From 87901e2961ef9bbeee9f3381b1763f97aa96ad8a Mon Sep 17 00:00:00 2001 From: S2kael Date: Mon, 22 Jul 2024 15:41:40 +0700 Subject: [PATCH 001/424] [MasterAccount] Init code --- .../src/background/KoniTypes.ts | 51 +- .../extension-base/src/background/types.ts | 84 +-- .../src/koni/background/cron.ts | 6 +- .../src/koni/background/handlers/Extension.ts | 417 ++--------- .../src/koni/background/handlers/State.ts | 50 +- .../src/koni/background/handlers/Tabs.ts | 10 +- .../src/koni/background/subscription.ts | 4 +- .../helpers/subscribe/index.ts | 3 +- .../src/services/balance-service/index.ts | 2 +- .../src/services/event-service/types.ts | 2 +- .../src/services/history-service/index.ts | 2 +- .../keyring-service/account-context.ts | 667 ++++++++++++++++++ .../src/services/keyring-service/index.ts | 171 +---- .../scripts/MigrateRemoveGenesisHash.ts | 2 +- .../handler/AuthRequestHandler.ts | 2 +- .../handler/SubstrateRequestHandler.ts | 3 +- .../src/services/request-service/index.ts | 5 +- .../src/services/request-service/types.ts | 3 +- .../src/services/transaction-service/index.ts | 3 +- .../src/stores/AccountGroupStore.ts | 12 + .../src/stores/CurrentAccountStore.ts | 2 +- .../src/stores/ModifyPairStore.ts | 12 + .../extension-base/src/types/account/index.ts | 4 + .../src/types/account/info/current.ts | 14 + .../src/types/account/info/group.ts | 26 + .../src/types/account/info/index.ts | 6 + .../src/types/account/info/keyring.ts | 124 ++++ packages/extension-base/src/types/index.ts | 1 + packages/extension-base/src/utils/account.ts | 20 +- packages/extension-base/src/utils/auth.ts | 16 + packages/extension-base/src/utils/index.ts | 4 +- .../extension-koni-ui/src/Popup/BuyTokens.tsx | 3 +- .../src/Popup/Confirmations/index.tsx | 3 +- .../parts/Detail/Evm/Transaction.tsx | 2 +- .../parts/Detail/Substrate/Extrinsic.tsx | 2 +- .../Confirmations/parts/Sign/Substrate.tsx | 3 +- .../variants/AuthorizeConfirmation.tsx | 3 +- .../variants/NotSupportConfirmation.tsx | 3 +- .../src/Popup/Home/History/index.tsx | 2 +- .../Keyring/ApplyMasterPassword/Done.tsx | 2 +- .../Keyring/ApplyMasterPassword/index.tsx | 2 +- .../src/Popup/Settings/AddressBook/index.tsx | 2 +- .../Security/ManageWebsiteAccess/Detail.tsx | 2 +- .../Popup/Transaction/helper/earning/base.ts | 3 +- .../Popup/Transaction/helper/staking/base.ts | 2 +- .../Transaction/variants/CancelUnstake.tsx | 3 +- .../Transaction/variants/ClaimReward.tsx | 3 +- .../Popup/Transaction/variants/SendFund.tsx | 2 +- .../src/Popup/Transaction/variants/Unbond.tsx | 3 +- .../Popup/Transaction/variants/Withdraw.tsx | 3 +- .../Popup/WalletConnect/ConnectionDetail.tsx | 2 +- .../Account/Info/AccountBriefInfo.tsx | 2 +- .../Account/Item/AccountItemWithName.tsx | 2 +- .../src/components/Field/AccountSelector.tsx | 2 +- .../src/components/Field/AddressInput.tsx | 2 +- .../parts/SelectAccount/ExportAllSelector.tsx | 2 +- .../Layout/parts/SelectAccount/index.tsx | 3 +- .../Modal/Account/DeriveAccountModal.tsx | 2 +- .../components/Modal/AccountSelectorModal.tsx | 2 +- .../Modal/AddressBook/AddressBookModal.tsx | 2 +- .../Modal/AddressBook/EditContactModal.tsx | 2 +- .../WalletConnect/Account/WCAccountInput.tsx | 2 +- .../WalletConnect/Account/WCAccountSelect.tsx | 2 +- .../WalletConnect/ConnectionItem.tsx | 2 +- .../src/hooks/account/useFormatAddress.ts | 2 +- .../hooks/account/useGetAccountByAddress.ts | 2 +- .../hooks/account/useIsMantaPayAvailable.ts | 2 +- .../src/hooks/account/usePreCheckAction.ts | 2 +- .../useGetChainSlugsByCurrentAccount.ts | 2 +- .../src/hooks/history/useHistorySelection.tsx | 2 +- .../common/useGetAccountInfoByAddress.ts | 2 +- .../home/useGetChainSlugsByAccountType.ts | 2 +- .../src/hooks/screen/home/useReceiveQR.ts | 2 +- .../hooks/screen/nft/useGetNftByAccount.ts | 2 +- .../useSelectWalletConnectAccount.ts | 3 +- .../src/messaging/accounts/create.ts | 4 - .../src/messaging/accounts/currentAccount.ts | 2 +- .../src/messaging/accounts/legacy.ts | 4 +- .../src/stores/base/AccountState.ts | 3 +- .../extension-koni-ui/src/stores/types.ts | 4 +- .../src/stores/utils/index.ts | 6 +- packages/extension-koni-ui/src/types/index.ts | 2 +- .../src/utils/account/account.ts | 3 +- .../src/utils/account/buildHierarchy.ts | 3 +- packages/extension-koni-ui/src/utils/index.ts | 3 +- .../src/utils/scanner/decoders.ts | 2 +- .../src/utils/walletConnect/index.ts | 2 +- .../extension-web-ui/src/Popup/BuyTokens.tsx | 3 +- .../src/Popup/Confirmations/index.tsx | 3 +- .../parts/Detail/Evm/Transaction.tsx | 2 +- .../parts/Detail/Substrate/Extrinsic.tsx | 2 +- .../Confirmations/parts/Sign/Substrate.tsx | 3 +- .../variants/AuthorizeConfirmation.tsx | 3 +- .../variants/NotSupportConfirmation.tsx | 3 +- .../extension-web-ui/src/Popup/CreateDone.tsx | 2 +- .../EarningPreview/EarningPreviewOptions.tsx | 3 +- .../EarningPreview/EarningPreviewPools.tsx | 3 +- .../src/Popup/Home/History/index.tsx | 2 +- .../Keyring/ApplyMasterPassword/Done.tsx | 2 +- .../Keyring/ApplyMasterPassword/index.tsx | 2 +- .../src/Popup/Settings/AddressBook/index.tsx | 2 +- .../Security/ManageWebsiteAccess/Detail.tsx | 2 +- .../Popup/Transaction/helper/earning/base.ts | 3 +- .../Popup/Transaction/helper/staking/base.ts | 2 +- .../Transaction/variants/CancelUnstake.tsx | 3 +- .../Transaction/variants/ClaimReward.tsx | 3 +- .../Popup/Transaction/variants/SendFund.tsx | 2 +- .../src/Popup/Transaction/variants/Unbond.tsx | 3 +- .../Popup/Transaction/variants/Withdraw.tsx | 3 +- .../Popup/WalletConnect/ConnectionDetail.tsx | 2 +- .../Account/Info/AccountBriefInfo.tsx | 2 +- .../Account/Item/AccountItemWithName.tsx | 2 +- .../src/components/Field/AccountSelector.tsx | 2 +- .../src/components/Field/AddressInput.tsx | 2 +- .../Layout/parts/SelectAccount/index.tsx | 3 +- .../Modal/Account/DeriveAccountModal.tsx | 2 +- .../components/Modal/AccountSelectorModal.tsx | 2 +- .../Modal/AddressBook/AddressBookModal.tsx | 2 +- .../Modal/AddressBook/EditContactModal.tsx | 2 +- .../WalletConnect/Account/WCAccountInput.tsx | 2 +- .../WalletConnect/Account/WCAccountSelect.tsx | 2 +- .../WalletConnect/ConnectionItem.tsx | 2 +- .../src/hooks/account/useFormatAddress.ts | 2 +- .../hooks/account/useGetAccountByAddress.ts | 2 +- .../hooks/account/useIsMantaPayAvailable.ts | 2 +- .../src/hooks/account/usePreCheckAction.ts | 2 +- .../useGetChainSlugsByCurrentAccount.ts | 2 +- .../src/hooks/history/useHistorySelection.tsx | 2 +- .../common/useGetAccountInfoByAddress.ts | 2 +- .../home/useGetChainSlugsByAccountType.ts | 2 +- .../src/hooks/screen/home/useReceiveQR.ts | 2 +- .../hooks/screen/nft/useGetNftByAccount.ts | 2 +- .../useSelectWalletConnectAccount.ts | 3 +- .../src/messaging/accounts/create.ts | 4 - .../src/messaging/accounts/currentAccount.ts | 2 +- .../src/messaging/accounts/legacy.ts | 4 +- .../src/stores/base/AccountState.ts | 3 +- packages/extension-web-ui/src/stores/types.ts | 4 +- .../src/stores/utils/index.ts | 6 +- packages/extension-web-ui/src/types/index.ts | 2 +- .../extension-web-ui/src/types/navigation.ts | 2 +- .../src/utils/account/account.ts | 3 +- .../src/utils/account/buildHierarchy.ts | 3 +- packages/extension-web-ui/src/utils/index.ts | 3 +- .../src/utils/scanner/decoders.ts | 2 +- .../src/utils/transaction/account.ts | 2 +- .../src/utils/walletConnect/index.ts | 2 +- 147 files changed, 1175 insertions(+), 839 deletions(-) create mode 100644 packages/extension-base/src/services/keyring-service/account-context.ts create mode 100644 packages/extension-base/src/stores/AccountGroupStore.ts create mode 100644 packages/extension-base/src/stores/ModifyPairStore.ts create mode 100644 packages/extension-base/src/types/account/index.ts create mode 100644 packages/extension-base/src/types/account/info/current.ts create mode 100644 packages/extension-base/src/types/account/info/group.ts create mode 100644 packages/extension-base/src/types/account/info/index.ts create mode 100644 packages/extension-base/src/types/account/info/keyring.ts create mode 100644 packages/extension-base/src/utils/auth.ts diff --git a/packages/extension-base/src/background/KoniTypes.ts b/packages/extension-base/src/background/KoniTypes.ts index 7001afc849..a7c7b3cc62 100644 --- a/packages/extension-base/src/background/KoniTypes.ts +++ b/packages/extension-base/src/background/KoniTypes.ts @@ -1,17 +1,21 @@ // Copyright 2019-2022 @polkadot/extension-koni authors & contributors // SPDX-License-Identifier: Apache-2.0 +import { ExtDef } from '@polkadot/types/extrinsic/signedExtensions/types'; +import { SignerResult } from '@polkadot/types/types/extrinsic'; +import { KeypairType } from '@polkadot/util-crypto/types'; +import { HexString } from '@polkadot/util/types'; import { _AssetRef, _AssetType, _ChainAsset, _ChainInfo, _FundStatus, _MultiChainAsset } from '@subwallet/chain-list/types'; import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError'; import { AuthUrls, Resolver } from '@subwallet/extension-base/background/handlers/State'; -import { AccountAuthType, AccountJson, AddressJson, AuthorizeRequest, ConfirmationRequestBase, RequestAccountList, RequestAccountSubscribe, RequestAccountUnsubscribe, RequestAuthorizeCancel, RequestAuthorizeReject, RequestAuthorizeSubscribe, RequestAuthorizeTab, RequestCurrentAccountAddress, ResponseAuthorizeList, ResponseJsonGetAccountInfo, SeedLengths } from '@subwallet/extension-base/background/types'; +import { AccountAuthType, AuthorizeRequest, ConfirmationRequestBase, RequestAccountList, RequestAccountSubscribe, RequestAccountUnsubscribe, RequestAuthorizeCancel, RequestAuthorizeReject, RequestAuthorizeSubscribe, RequestAuthorizeTab, RequestCurrentAccountAddress, ResponseAuthorizeList, ResponseJsonGetAccountInfo, SeedLengths } from '@subwallet/extension-base/background/types'; import { RequestOptimalTransferProcess } from '@subwallet/extension-base/services/balance-service/helpers'; import { _CHAIN_VALIDATION_ERROR } from '@subwallet/extension-base/services/chain-service/handler/types'; import { _ChainState, _EvmApi, _NetworkUpsertParams, _SubstrateApi, _ValidateCustomAssetRequest, _ValidateCustomAssetResponse, EnableChainParams, EnableMultiChainParams } from '@subwallet/extension-base/services/chain-service/types'; import { CrowdloanContributionsResponse } from '@subwallet/extension-base/services/subscan-service/types'; import { SWTransactionResponse, SWTransactionResult } from '@subwallet/extension-base/services/transaction-service/types'; import { WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; -import { BalanceJson, BuyServiceInfo, BuyTokenInfo, EarningRewardHistoryItem, EarningRewardJson, EarningStatus, HandleYieldStepParams, LeavePoolAdditionalData, NominationPoolInfo, OptimalYieldPath, OptimalYieldPathParams, RequestEarlyValidateYield, RequestGetYieldPoolTargets, RequestMetadataHash, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseEarlyValidateYield, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseShortenMetadata, StorageDataInterface, SubmitYieldStepData, TokenSpendingApprovalParams, UnlockDotTransactionNft, UnstakingStatus, ValidateYieldProcessParams, YieldPoolInfo, YieldPositionInfo, YieldValidationStatus } from '@subwallet/extension-base/types'; +import { AccountJson, AccountsWithCurrentAddress, AddressJson, BalanceJson, BuyServiceInfo, BuyTokenInfo, CurrentAccountInfo, EarningRewardHistoryItem, EarningRewardJson, EarningStatus, HandleYieldStepParams, LeavePoolAdditionalData, NominationPoolInfo, OptimalYieldPath, OptimalYieldPathParams, RequestEarlyValidateYield, RequestGetYieldPoolTargets, RequestMetadataHash, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseEarlyValidateYield, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseShortenMetadata, StorageDataInterface, SubmitYieldStepData, TokenSpendingApprovalParams, UnlockDotTransactionNft, UnstakingStatus, ValidateYieldProcessParams, YieldPoolInfo, YieldPositionInfo, YieldValidationStatus } from '@subwallet/extension-base/types'; import { CommonOptimalPath } from '@subwallet/extension-base/types/service-base'; import { SwapErrorType, SwapPair, SwapQuoteResponse, SwapRequest, SwapRequestResult, SwapSubmitParams, SwapTxData, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap'; import { InjectedAccount, InjectedAccountWithMeta, MetadataDefBase } from '@subwallet/extension-inject/types'; @@ -24,11 +28,6 @@ import Web3 from 'web3'; import { RequestArguments, TransactionConfig } from 'web3-core'; import { JsonRpcPayload, JsonRpcResponse } from 'web3-core-helpers'; -import { ExtDef } from '@polkadot/types/extrinsic/signedExtensions/types'; -import { SignerResult } from '@polkadot/types/types/extrinsic'; -import { HexString } from '@polkadot/util/types'; -import { KeypairType } from '@polkadot/util-crypto/types'; - import { TransactionWarning } from './warnings/TransactionWarning'; export enum RuntimeEnvironment { @@ -370,34 +369,10 @@ export interface NetWorkMetadataDef extends MetadataDefBase { apiStatus: NETWORK_STATUS; } -export type CurrentNetworkInfo = { - networkKey: string; - networkPrefix: number; - icon: string; - genesisHash: string; - isEthereum: boolean; - isReady?: boolean; // check if current network info is lifted from initial state -} - -// all Accounts and the address of the current Account -export interface AccountsWithCurrentAddress { - accounts: AccountJson[]; - currentAddress?: string; - currentGenesisHash?: string | null; - isShowBalance?: boolean; // Deprecated and move to setting - allAccountLogo?: string; // Deprecated and move to setting -} - export interface OptionInputAddress { options: KeyringOptions; } -export interface CurrentAccountInfo { - address: string; - currentGenesisHash: string | null; - allGenesisHash?: string; -} - export type LanguageType = 'en' | 'zh' | 'fr' @@ -962,16 +937,6 @@ export interface RequestAccountCreateExternalV2 { // Attach Ledger account -export interface RequestAccountCreateHardwareV2 { - accountIndex: number; - address: string; - addressOffset: number; - genesisHash: string; - hardwareType: string; - name: string; - isAllowed?: boolean; -} - export interface CreateHardwareAccountItem { accountIndex: number; address: string; @@ -983,6 +948,10 @@ export interface CreateHardwareAccountItem { isGeneric: boolean; } +export interface RequestAccountCreateHardwareV2 extends CreateHardwareAccountItem { + isAllowed?: boolean; +} + export interface RequestAccountCreateHardwareMultiple { accounts: CreateHardwareAccountItem[]; } diff --git a/packages/extension-base/src/background/types.ts b/packages/extension-base/src/background/types.ts index cd16de5a86..9a262eb0f4 100644 --- a/packages/extension-base/src/background/types.ts +++ b/packages/extension-base/src/background/types.ts @@ -4,14 +4,15 @@ /* eslint-disable no-use-before-define */ import type { InjectedAccount, InjectedMetadataKnown, MetadataDef, ProviderList, ProviderMeta } from '@subwallet/extension-inject/types'; -import type { KeyringPair, KeyringPair$Json, KeyringPair$Meta } from '@subwallet/keyring/types'; +import type { KeyringPair, KeyringPair$Json } from '@subwallet/keyring/types'; import type { KeyringPairs$Json } from '@subwallet/ui-keyring/types'; import type { JsonRpcResponse } from '@polkadot/rpc-provider/types'; import type { SignerPayloadJSON, SignerPayloadRaw } from '@polkadot/types/types'; import type { HexString } from '@polkadot/util/types'; import type { KeypairType } from '@polkadot/util-crypto/types'; -import { CurrentNetworkInfo, KoniRequestSignatures, NetworkJson } from '@subwallet/extension-base/background/KoniTypes'; +import { KoniRequestSignatures, NetworkJson } from '@subwallet/extension-base/background/KoniTypes'; +import { AccountJson } from '@subwallet/extension-base/types'; import { TypeRegistry } from '@polkadot/types'; @@ -32,78 +33,6 @@ type NullKeys = { [K in keyof T]: IsNull }[keyof T]; export type SeedLengths = 12 | 24; -export interface AbstractAddressJson extends KeyringPair$Meta { - address: string; - type?: KeypairType; - whenCreated?: number; - name?: string; -} - -/** - * @interface AccountJson - * @prop {number} [accountIndex] - Ledger's account index - * @prop {number} [addressOffset] - Ledger's address offset - * @prop {string[]} [availableGenesisHashes] - Ledger's availableGenesisHashes - * @prop {string|null} [genesisHash] - Ledger's genesisHash - * @prop {boolean} [isExternal] - Is external account - * @prop {boolean} [isHardware] - Is hardware account - * @prop {boolean} [isHidden] - Is hidden account - * @prop {boolean} [isInjected] - Is injected account - * @prop {boolean} [isGeneric] - Is generic account - * @prop {boolean} [isMasterAccount] - Is master account - account has seed - * @prop {boolean} [isMasterPassword] - Account has migrated with wallet password - * @prop {boolean} [isReadOnly] - Is readonly account - * @prop {boolean} [isReadOnly] - Is readonly account - * @prop {boolean} [isSubWallet] - Import from SubWallet - * @prop {boolean} [pendingMigrate] - Pending migrate password - * @prop {string|null} [originGenesisHash] - Ledger's originGenesisHash - * @prop {string} [source] - Account's source - * @prop {string} [suri] - Derivate path - * */ -export interface AccountJson extends AbstractAddressJson { - /** Ledger's account index */ - accountIndex?: number; - /** Ledger's address offset */ - addressOffset?: number; - /** Ledger's availableGenesisHashes */ - availableGenesisHashes?: string[]; - /** Ledger's genesisHash */ - genesisHash?: string | null; - /** Is external account */ - isExternal?: boolean; - /** Is hardware account */ - isHardware?: boolean; - /** Is hidden account */ - isHidden?: boolean; - /** Is injected account */ - isInjected?: boolean; - /** Is generic ledger account */ - isGeneric?: boolean; - /** Is master account - account has seed */ - isMasterAccount?: boolean; - /** Account has migrated with wallet password */ - isMasterPassword?: boolean; - /** Is readonly account */ - isReadOnly?: boolean; - /** Import from SubWallet */ - isSubWallet?: boolean; - /** Pending migrate password */ - pendingMigrate?: boolean; - /** Ledger's originGenesisHash */ - originGenesisHash?: string | null; - /** Parent's address */ - parentAddress?: string; - /** Account's source */ - source?: string; - /** Derivate path */ - suri?: string; -} - -export interface AddressJson extends AbstractAddressJson { - isRecent?: boolean; - recentChainSlugs?: string[]; -} - // all Accounts and the address of the current Account export interface AccountsWithCurrentAddress { accounts: AccountJson[]; @@ -133,11 +62,6 @@ export type CurrentAccContext = { setCurrentAccount: (account: AccountJson | null) => void; } -export type AccNetworkContext = { - network: CurrentNetworkInfo; - setNetwork: (network: CurrentNetworkInfo) => void; -} - export interface ConfirmationRequestBase { id: string; url: string; @@ -161,7 +85,6 @@ export interface SigningRequest extends ConfirmationRequestBase { export interface RequestSignatures extends KoniRequestSignatures { // private/internal requests, i.e. from a popup 'pri(ping)': [null, string]; - 'pri(accounts.create.external)': [RequestAccountCreateExternal, boolean]; 'pri(accounts.create.hardware)': [RequestAccountCreateHardware, boolean]; 'pri(accounts.create.suri)': [RequestAccountCreateSuri, boolean]; 'pri(accounts.edit)': [RequestAccountEdit, boolean]; @@ -172,6 +95,7 @@ export interface RequestSignatures extends KoniRequestSignatures { 'pri(accounts.tie)': [RequestAccountTie, boolean]; 'pri(accounts.subscribe)': [RequestAccountSubscribe, AccountJson[], AccountJson[]]; 'pri(accounts.validate)': [RequestAccountValidate, boolean]; + /** @deprecated */ 'pri(accounts.changePassword)': [RequestAccountChangePassword, boolean]; 'pri(authorize.approve)': [RequestAuthorizeApprove, boolean]; 'pri(authorize.list)': [null, ResponseAuthorizeList]; diff --git a/packages/extension-base/src/koni/background/cron.ts b/packages/extension-base/src/koni/background/cron.ts index 11fdd648e4..2549f9f6d7 100644 --- a/packages/extension-base/src/koni/background/cron.ts +++ b/packages/extension-base/src/koni/background/cron.ts @@ -78,7 +78,7 @@ export class KoniCron { await Promise.all([this.state.eventService.waitKeyringReady, this.state.eventService.waitAssetReady]); - const currentAccountInfo = this.state.keyringService.currentAccount; + const currentAccountInfo = this.state.keyringService.context.currentAccount; const commonReloadEvents: EventType[] = [ 'account.add', @@ -213,7 +213,7 @@ export class KoniCron { }; public async reloadNft () { - const address = this.state.keyringService.currentAccount.address; + const address = this.state.keyringService.context.currentAccount.address; const serviceInfo = this.state.getServiceInfo(); this.resetNft(address); @@ -226,7 +226,7 @@ export class KoniCron { } public async reloadStaking () { - const address = this.state.keyringService.currentAccount.address; + const address = this.state.keyringService.context.currentAccount.address; console.log('reload staking', address); diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index e3e102be25..bbcbf6d9db 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -7,10 +7,10 @@ import { _AssetRef, _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError'; import { withErrorLog } from '@subwallet/extension-base/background/handlers/helpers'; import { createSubscription } from '@subwallet/extension-base/background/handlers/subscriptions'; -import { AccountExternalError, AccountExternalErrorCode, AccountsWithCurrentAddress, AddressBookInfo, AmountData, AmountDataWithId, AssetSetting, AssetSettingUpdateReq, BasicTxErrorType, BondingOptionParams, BrowserConfirmationType, CampaignBanner, CampaignData, CampaignDataType, ChainType, CreateDeriveAccountInfo, CronReloadRequest, CrowdloanJson, CurrentAccountInfo, DeriveAccountInfo, ExternalRequestPromiseStatus, ExtrinsicType, KeyringState, MantaPayEnableMessage, MantaPayEnableParams, MantaPayEnableResponse, MantaPaySyncState, MetadataItem, NftCollection, NftJson, NftTransactionRequest, NftTransactionResponse, OptionInputAddress, PriceJson, RequestAccountBatchExportV2, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateSuriV2, RequestAccountCreateWithSecretKey, RequestAccountExportPrivateKey, RequestAccountMeta, RequestAddInjectedAccounts, RequestApproveConnectWalletSession, RequestApproveWalletConnectNotSupport, RequestAuthorization, RequestAuthorizationBlock, RequestAuthorizationPerAccount, RequestAuthorizationPerSite, RequestAuthorizeApproveV2, RequestBatchRestoreV2, RequestBondingSubmit, RequestCameraSettings, RequestCampaignBannerComplete, RequestChangeEnableChainPatrol, RequestChangeLanguage, RequestChangeMasterPassword, RequestChangePriceCurrency, RequestChangeShowBalance, RequestChangeShowZeroBalance, RequestChangeTimeAutoLock, RequestCheckPublicAndSecretKey, RequestConfirmationComplete, RequestConnectWalletConnect, RequestCrossChainTransfer, RequestCrowdloanContributions, RequestDeleteContactAccount, RequestDeriveCreateMultiple, RequestDeriveCreateV2, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestDisconnectWalletConnectSession, RequestEditContactAccount, RequestFindRawMetadata, RequestForgetSite, RequestFreeBalance, RequestGetDeriveAccounts, RequestGetTransaction, RequestJsonRestoreV2, RequestKeyringExportMnemonic, RequestMaxTransferable, RequestMigratePassword, RequestParseEvmContractInput, RequestParseTransactionSubstrate, RequestPassPhishingPage, RequestQrParseRLP, RequestQrSignEvm, RequestQrSignSubstrate, RequestRejectConnectWalletSession, RequestRejectExternalRequest, RequestRejectWalletConnectNotSupport, RequestRemoveInjectedAccounts, RequestResetWallet, RequestResolveExternalRequest, RequestSaveRecentAccount, RequestSeedCreateV2, RequestSeedValidateV2, RequestSettingsType, RequestSigningApprovePasswordV2, RequestStakePoolingBonding, RequestStakePoolingUnbonding, RequestSubscribeHistory, RequestSubstrateNftSubmitTransaction, RequestTransfer, RequestTuringCancelStakeCompound, RequestTuringStakeCompound, RequestUnbondingSubmit, RequestUnlockKeyring, RequestUnlockType, ResolveAddressToDomainRequest, ResolveDomainRequest, ResponseAccountBatchExportV2, ResponseAccountCreateSuriV2, ResponseAccountCreateWithSecretKey, ResponseAccountExportPrivateKey, ResponseAccountMeta, ResponseChangeMasterPassword, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseFindRawMetadata, ResponseGetDeriveAccounts, ResponseKeyringExportMnemonic, ResponseMigratePassword, ResponseParseEvmContractInput, ResponseParseTransactionSubstrate, ResponsePrivateKeyValidateV2, ResponseQrParseRLP, ResponseQrSignEvm, ResponseQrSignSubstrate, ResponseRejectExternalRequest, ResponseResetWallet, ResponseResolveExternalRequest, ResponseSeedCreateV2, ResponseSeedValidateV2, ResponseSubscribeHistory, ResponseUnlockKeyring, ShowCampaignPopupRequest, StakingJson, StakingRewardJson, StakingTxErrorType, StakingType, ThemeNames, TransactionHistoryItem, TransactionResponse, ValidateNetworkRequest, ValidateNetworkResponse, ValidatorInfo } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountAuthType, AccountJson, AuthorizeRequest, MessageTypes, MetadataRequest, RequestAccountChangePassword, RequestAccountCreateExternal, RequestAccountCreateHardware, RequestAccountCreateSuri, RequestAccountEdit, RequestAccountExport, RequestAccountForget, RequestAccountShow, RequestAccountTie, RequestAccountValidate, RequestAuthorizeCancel, RequestAuthorizeReject, RequestBatchRestore, RequestCurrentAccountAddress, RequestDeriveCreate, RequestDeriveValidate, RequestJsonRestore, RequestMetadataApprove, RequestMetadataReject, RequestSeedCreate, RequestSeedValidate, RequestSigningApproveSignature, RequestSigningCancel, RequestTypes, ResponseAccountExport, ResponseAuthorizeList, ResponseDeriveValidate, ResponseJsonGetAccountInfo, ResponseSeedCreate, ResponseSeedValidate, ResponseType, SigningRequest, WindowOpenParams } from '@subwallet/extension-base/background/types'; +import { AccountExternalError, AddressBookInfo, AmountData, AmountDataWithId, AssetSetting, AssetSettingUpdateReq, BasicTxErrorType, BondingOptionParams, BrowserConfirmationType, CampaignBanner, CampaignData, CampaignDataType, ChainType, CreateDeriveAccountInfo, CronReloadRequest, CrowdloanJson, DeriveAccountInfo, ExternalRequestPromiseStatus, ExtrinsicType, KeyringState, MantaPayEnableMessage, MantaPayEnableParams, MantaPayEnableResponse, MantaPaySyncState, MetadataItem, NftCollection, NftJson, NftTransactionRequest, NftTransactionResponse, OptionInputAddress, PriceJson, RequestAccountBatchExportV2, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateSuriV2, RequestAccountCreateWithSecretKey, RequestAccountExportPrivateKey, RequestAccountMeta, RequestAddInjectedAccounts, RequestApproveConnectWalletSession, RequestApproveWalletConnectNotSupport, RequestAuthorization, RequestAuthorizationBlock, RequestAuthorizationPerAccount, RequestAuthorizationPerSite, RequestAuthorizeApproveV2, RequestBatchRestoreV2, RequestBondingSubmit, RequestCameraSettings, RequestCampaignBannerComplete, RequestChangeEnableChainPatrol, RequestChangeLanguage, RequestChangeMasterPassword, RequestChangePriceCurrency, RequestChangeShowBalance, RequestChangeShowZeroBalance, RequestChangeTimeAutoLock, RequestCheckPublicAndSecretKey, RequestConfirmationComplete, RequestConnectWalletConnect, RequestCrossChainTransfer, RequestCrowdloanContributions, RequestDeleteContactAccount, RequestDeriveCreateMultiple, RequestDeriveCreateV2, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestDisconnectWalletConnectSession, RequestEditContactAccount, RequestFindRawMetadata, RequestForgetSite, RequestFreeBalance, RequestGetDeriveAccounts, RequestGetTransaction, RequestJsonRestoreV2, RequestKeyringExportMnemonic, RequestMaxTransferable, RequestMigratePassword, RequestParseEvmContractInput, RequestParseTransactionSubstrate, RequestPassPhishingPage, RequestQrParseRLP, RequestQrSignEvm, RequestQrSignSubstrate, RequestRejectConnectWalletSession, RequestRejectExternalRequest, RequestRejectWalletConnectNotSupport, RequestRemoveInjectedAccounts, RequestResetWallet, RequestResolveExternalRequest, RequestSaveRecentAccount, RequestSeedCreateV2, RequestSeedValidateV2, RequestSettingsType, RequestSigningApprovePasswordV2, RequestStakePoolingBonding, RequestStakePoolingUnbonding, RequestSubscribeHistory, RequestSubstrateNftSubmitTransaction, RequestTransfer, RequestTuringCancelStakeCompound, RequestTuringStakeCompound, RequestUnbondingSubmit, RequestUnlockKeyring, RequestUnlockType, ResolveAddressToDomainRequest, ResolveDomainRequest, ResponseAccountBatchExportV2, ResponseAccountCreateSuriV2, ResponseAccountCreateWithSecretKey, ResponseAccountExportPrivateKey, ResponseAccountMeta, ResponseChangeMasterPassword, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseFindRawMetadata, ResponseGetDeriveAccounts, ResponseKeyringExportMnemonic, ResponseMigratePassword, ResponseParseEvmContractInput, ResponseParseTransactionSubstrate, ResponsePrivateKeyValidateV2, ResponseQrParseRLP, ResponseQrSignEvm, ResponseQrSignSubstrate, ResponseRejectExternalRequest, ResponseResetWallet, ResponseResolveExternalRequest, ResponseSeedCreateV2, ResponseSeedValidateV2, ResponseSubscribeHistory, ResponseUnlockKeyring, ShowCampaignPopupRequest, StakingJson, StakingRewardJson, StakingTxErrorType, StakingType, ThemeNames, TransactionHistoryItem, TransactionResponse, ValidateNetworkRequest, ValidateNetworkResponse, ValidatorInfo } from '@subwallet/extension-base/background/KoniTypes'; +import { AccountAuthType, AuthorizeRequest, MessageTypes, MetadataRequest, RequestAccountChangePassword, RequestAccountCreateHardware, RequestAccountCreateSuri, RequestAccountEdit, RequestAccountExport, RequestAccountForget, RequestAccountShow, RequestAccountTie, RequestAccountValidate, RequestAuthorizeCancel, RequestAuthorizeReject, RequestBatchRestore, RequestCurrentAccountAddress, RequestDeriveCreate, RequestDeriveValidate, RequestJsonRestore, RequestMetadataApprove, RequestMetadataReject, RequestSeedCreate, RequestSeedValidate, RequestSigningApproveSignature, RequestSigningCancel, RequestTypes, ResponseAccountExport, ResponseAuthorizeList, ResponseDeriveValidate, ResponseJsonGetAccountInfo, ResponseSeedCreate, ResponseSeedValidate, ResponseType, SigningRequest, WindowOpenParams } from '@subwallet/extension-base/background/types'; import { TransactionWarning } from '@subwallet/extension-base/background/warnings/TransactionWarning'; -import { ALL_ACCOUNT_KEY, ALL_GENESIS_HASH, LATEST_SESSION, XCM_FEE_RATIO } from '@subwallet/extension-base/constants'; +import { ALL_ACCOUNT_KEY, LATEST_SESSION, XCM_FEE_RATIO } from '@subwallet/extension-base/constants'; import { additionalValidateTransfer, additionalValidateXcmTransfer, validateTransferRequest, validateXcmTransferRequest } from '@subwallet/extension-base/core/logic-validation/transfer'; import { _isSnowBridgeXcm } from '@subwallet/extension-base/core/substrate/xcm-parser'; import { ALLOWED_PATH } from '@subwallet/extension-base/defaults'; @@ -41,7 +41,7 @@ import { isProposalExpired, isSupportWalletConnectChain, isSupportWalletConnectN import { ResultApproveWalletConnectSession, WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; import { SWStorage } from '@subwallet/extension-base/storage'; import { AccountsStore } from '@subwallet/extension-base/stores'; -import { BalanceJson, BuyServiceInfo, BuyTokenInfo, EarningRewardJson, NominationPoolInfo, OptimalYieldPathParams, RequestEarlyValidateYield, RequestGetYieldPoolTargets, RequestMetadataHash, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseShortenMetadata, StorageDataInterface, TokenSpendingApprovalParams, ValidateYieldProcessParams, YieldPoolType } from '@subwallet/extension-base/types'; +import { AccountGroup, AccountJson, AccountsWithCurrentAddress, BalanceJson, BuyServiceInfo, BuyTokenInfo, CurrentAccountInfo, EarningRewardJson, NominationPoolInfo, OptimalYieldPathParams, RequestEarlyValidateYield, RequestGetYieldPoolTargets, RequestMetadataHash, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseShortenMetadata, StorageDataInterface, TokenSpendingApprovalParams, ValidateYieldProcessParams, YieldPoolType } from '@subwallet/extension-base/types'; import { CommonOptimalPath } from '@subwallet/extension-base/types/service-base'; import { SwapPair, SwapQuoteResponse, SwapRequest, SwapRequestResult, SwapSubmitParams, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap'; import { BN_ZERO, convertSubjectInfoToAddresses, createTransactionFromRLP, isSameAddress, MODULE_SUPPORT, reformatAddress, signatureToHex, Transaction as QrTransaction, uniqueStringArray } from '@subwallet/extension-base/utils'; @@ -58,7 +58,7 @@ import { SessionTypes } from '@walletconnect/types/dist/types/sign-client/sessio import { getSdkError } from '@walletconnect/utils'; import BigN from 'bignumber.js'; import { t } from 'i18next'; -import { Subject } from 'rxjs'; +import { combineLatest, Subject } from 'rxjs'; import { TransactionConfig } from 'web3-core'; import { SubmittableExtrinsic } from '@polkadot/api/types'; @@ -77,17 +77,10 @@ function getSuri (seed: string, type?: KeypairType): string { : seed; } -function transformAccounts (accounts: SubjectInfo): AccountJson[] { - return Object.values(accounts).map(({ json: { address, meta }, type }): AccountJson => ({ - address, - ...meta, - type - })); -} - -const ACCOUNT_ALL_JSON: AccountJson = { - address: ALL_ACCOUNT_KEY, - name: 'All' +const ACCOUNT_ALL_GROUP: AccountGroup = { + id: ALL_ACCOUNT_KEY, + name: 'All', + accounts: [] }; export const SEED_DEFAULT_LENGTH = 12; @@ -146,13 +139,6 @@ export default class KoniExtension { }); } - /// Clone from PolkadotJs - private accountsCreateExternal ({ address, genesisHash, name }: RequestAccountCreateExternal): boolean { - keyring.addExternal(address, { genesisHash, name }); - - return true; - } - private accountsCreateHardware ({ accountIndex, address, addressOffset, @@ -227,7 +213,7 @@ export default class KoniExtension { // FIXME This looks very much like what we have in Tabs private accountsSubscribe (id: string, port: chrome.runtime.Port): boolean { const cb = createSubscription<'pri(accounts.subscribe)'>(id, port); - const accountSubject = this.#koniState.keyringService.accountSubject; + const accountSubject = this.#koniState.keyringService.context.pairSubject; const subscription = accountSubject.subscribe((accounts: SubjectInfo): void => cb(transformAccounts(accounts)) ); @@ -489,32 +475,29 @@ export default class KoniExtension { await this.#koniState.eventService.waitAccountReady; await this.#koniState.eventService.waitInjectReady; - const currentAccount = keyringService.currentAccount; - const transformedAccounts = transformAccounts(keyringService.accounts); + const currentAccount = keyringService.context.currentAccount; + const accounts = keyringService.context.accounts; + const transformedAccounts = Object.values(accounts); const responseData: AccountsWithCurrentAddress = { - accounts: transformedAccounts?.length ? [{ ...ACCOUNT_ALL_JSON }, ...transformedAccounts] : [], - currentAddress: currentAccount?.address, - currentGenesisHash: currentAccount?.currentGenesisHash + accounts: transformedAccounts?.length ? [{ ...ACCOUNT_ALL_GROUP }, ...transformedAccounts] : [], + currentAddress: currentAccount?.address }; - const subscriptionAccounts = keyringService.accountSubject.subscribe((storedAccounts: SubjectInfo): void => { - const transformedAccounts = transformAccounts(storedAccounts); + const accountGroups = keyringService.context.accountSubject; + const currentAccountSubscribe = keyringService.context.currentAccountSubject; - responseData.accounts = transformedAccounts?.length ? [{ ...ACCOUNT_ALL_JSON }, ...transformedAccounts] : []; + const subscriptionAccountGroups = combineLatest({ accountGroups, currentAccount: currentAccountSubscribe }).subscribe(({ accountGroups, currentAccount }) => { + const transformedAccounts = Object.values(accountGroups); - cb(responseData); - }); - - const subscriptionCurrentAccount = keyringService.currentAccountSubject.subscribe((currentAccountData) => { - responseData.currentAddress = currentAccountData.address; - responseData.currentGenesisHash = currentAccountData.currentGenesisHash; + responseData.accounts = transformedAccounts?.length ? [{ ...ACCOUNT_ALL_GROUP }, ...transformedAccounts] : []; + responseData.currentAddress = currentAccount?.address; + console.log(responseData); cb(responseData); }); this.createUnsubscriptionHandle(id, () => { - subscriptionAccounts.unsubscribe(); - subscriptionCurrentAccount.unsubscribe(); + subscriptionAccountGroups.unsubscribe(); }); port.onDisconnect.addListener((): void => { @@ -547,7 +530,7 @@ export default class KoniExtension { const _cb = createSubscription<'pri(accounts.subscribeAddresses)'>(id, port); let old = ''; - const subscription = this.#koniState.keyringService.addressesSubject.subscribe((subjectInfo: SubjectInfo): void => { + const subscription = this.#koniState.keyringService.context.contactSubject.subscribe((subjectInfo: SubjectInfo): void => { const addresses = convertSubjectInfoToAddresses(subjectInfo); const _new = JSON.stringify(addresses); @@ -566,7 +549,7 @@ export default class KoniExtension { this.cancelSubscription(id); }); - const subjectInfo = this.#koniState.keyringService.addresses; + const subjectInfo = this.#koniState.keyringService.context.contacts; return { addresses: convertSubjectInfoToAddresses(subjectInfo) @@ -644,7 +627,7 @@ export default class KoniExtension { return new Promise((resolve, reject) => { this.#koniState.getAuthorize((rs: AuthUrls) => { - const addressList = Object.keys(keyringService.accounts); + const addressList = Object.keys(keyringService.context.pairs); const urlList = Object.keys(rs); if (Object.keys(rs[urlList[0]].isAllowedMap).toString() !== addressList.toString()) { @@ -781,7 +764,7 @@ export default class KoniExtension { } private getAccounts (): string[] { - const storedAccounts = this.#koniState.keyringService.accounts; + const storedAccounts = this.#koniState.keyringService.context.pairs; const transformedAccounts = transformAccounts(storedAccounts); return transformedAccounts.map((a) => a.address); @@ -1086,28 +1069,14 @@ export default class KoniExtension { } private _saveCurrentAccountAddress (address: string, callback?: (data: CurrentAccountInfo) => void) { - let accountInfo = this.#koniState.keyringService.currentAccount; + let accountInfo = this.#koniState.keyringService.context.currentAccount; if (!accountInfo) { accountInfo = { - address, - currentGenesisHash: ALL_GENESIS_HASH, - allGenesisHash: ALL_GENESIS_HASH || undefined + address }; } else { accountInfo.address = address; - - if (address !== ALL_ACCOUNT_KEY) { - try { - const currentKeyPair = keyring.getPair(address); - - accountInfo.currentGenesisHash = currentKeyPair?.meta.genesisHash as string || ALL_GENESIS_HASH; - } catch { - accountInfo.currentGenesisHash = ALL_GENESIS_HASH; - } - } else { - accountInfo.currentGenesisHash = accountInfo.allGenesisHash || ALL_GENESIS_HASH; - } } this.#koniState.setCurrentAccount(accountInfo, () => { @@ -1300,58 +1269,8 @@ export default class KoniExtension { }); } - private async accountsCreateSuriV2 ({ genesisHash, - isAllowed, - name, - password, - suri: _suri, - types }: RequestAccountCreateSuriV2): Promise { - const addressDict = {} as Record; - let changedAccount = false; - const hasMasterPassword = keyring.keyring.hasMasterPassword; - - if (!hasMasterPassword) { - if (!password) { - throw Error(t('The password of each account is needed to set up master password')); - } else { - keyring.changeMasterPassword(password); - this.#koniState.updateKeyringState(); - } - } - - const currentAccount = this.#koniState.keyringService.currentAccount; - const allGenesisHash = currentAccount?.allGenesisHash || undefined; - - types?.forEach((type) => { - const suri = getSuri(_suri, type); - const address = keyring.createFromUri(suri, {}, type).address; - - addressDict[type] = address; - const newAccountName = type === 'ethereum' ? `${name} - EVM` : name; - - keyring.addUri(suri, { genesisHash, name: newAccountName }, type); - this._addAddressToAuthList(address, isAllowed); - - if (!changedAccount) { - if (types.length === 1) { - this.#koniState.setCurrentAccount({ address, currentGenesisHash: genesisHash || null, allGenesisHash }); - } else { - this.#koniState.setCurrentAccount({ - address: ALL_ACCOUNT_KEY, - currentGenesisHash: allGenesisHash || null, - allGenesisHash - }, undefined, true); - } - - changedAccount = true; - } - }); - - await new Promise((resolve) => { - this.#koniState.addAccountRef(Object.values(addressDict), () => { - resolve(); - }); - }); + private async accountsCreateSuriV2 (request: RequestAccountCreateSuriV2): Promise { + const addressDict = await this.#koniState.keyringService.context.accountsCreateSuriV2(request); if (this.#alwaysLock) { this.keyringLock(); @@ -1385,10 +1304,10 @@ export default class KoniExtension { // Set current account to all account await new Promise((resolve) => { - const currentAccountInfo = this.#koniState.keyringService.currentAccount; + // const currentAccountInfo = this.#koniState.keyringService.context.currentAccount; this.#koniState.setCurrentAccount({ - currentGenesisHash: currentAccountInfo?.allGenesisHash || null, + // currentGenesisHash: currentAccountInfo?.allGenesisHash || null, address: ALL_ACCOUNT_KEY }, resolve); }); @@ -1458,9 +1377,9 @@ export default class KoniExtension { } private metamaskPrivateKeyValidateV2 ({ suri, types }: RequestSeedValidateV2): ResponsePrivateKeyValidateV2 { - const isValidSuri = suri.startsWith('0x'); + const isHex = suri.startsWith('0x'); - if (isValidSuri) { + if (isHex) { return this._checkValidatePrivateKey({ suri, types }); } else { return this._checkValidatePrivateKey({ suri: `0x${suri}`, types }, true); @@ -1539,7 +1458,7 @@ export default class KoniExtension { this._saveCurrentAccountAddress(ALL_ACCOUNT_KEY, () => { keyring.restoreAccounts(file, password); - this.#koniState.keyringService.removeNoneHardwareGenesisHash(); + this.#koniState.keyringService.context.removeNoneHardwareGenesisHash(); this._addAddressesToAuthList(addressList, isAllowed); }); @@ -2193,255 +2112,26 @@ export default class KoniExtension { return this.#koniState.setAccountTie(address, genesisHash); } - private async accountsCreateExternalV2 ({ address, - genesisHash, - isAllowed, - isEthereum, - isReadOnly, - name }: RequestAccountCreateExternalV2): Promise { - try { - let result: KeyringPair; - - try { - const exists = keyring.getPair(address); - - if (exists) { - if (exists.type === (isEthereum ? 'ethereum' : 'sr25519')) { - return [{ code: AccountExternalErrorCode.INVALID_ADDRESS, message: t('Account exists') }]; - } - } - } catch (e) { - - } - - if (isEthereum) { - const chainInfoMap = this.#koniState.getChainInfoMap(); - let _gen = ''; - - if (genesisHash) { - for (const network of Object.values(chainInfoMap)) { - if (_getEvmChainId(network) === parseInt(genesisHash)) { - // TODO: pure EVM chains do not have genesisHash - _gen = _getSubstrateGenesisHash(network); - } - } - } - - result = keyring.keyring.addFromAddress(address, { - name, - isExternal: true, - isReadOnly, - genesisHash: _gen - }, null, 'ethereum'); - - keyring.saveAccount(result); - } else { - result = keyring.addExternal(address, { genesisHash, name, isReadOnly }).pair; - } - - const _address = result.address; - - await new Promise((resolve) => { - this.#koniState.addAccountRef([_address], () => { - resolve(); - }); - }); - - await new Promise((resolve) => { - this._saveCurrentAccountAddress(_address, () => { - this._addAddressToAuthList(_address, isAllowed); - resolve(); - }); - }); - - return []; - } catch (e) { - return [{ code: AccountExternalErrorCode.KEYRING_ERROR, message: (e as Error).message }]; - } + private async accountsCreateExternalV2 (request: RequestAccountCreateExternalV2): Promise { + return this.#koniState.keyringService.context.accountsCreateExternalV2(request); } - private async accountsCreateHardwareV2 ({ accountIndex, - address, - addressOffset, - genesisHash, - hardwareType, - isAllowed, - name }: RequestAccountCreateHardwareV2): Promise { - const key = keyring.addHardware(address, hardwareType, { - accountIndex, - addressOffset, - genesisHash, - name, - originGenesisHash: genesisHash - }); - - const result = key.pair; - - const _address = result.address; - - await new Promise((resolve) => { - this.#koniState.addAccountRef([_address], () => { - resolve(); - }); - }); - - await new Promise((resolve) => { - this._saveCurrentAccountAddress(_address, () => { - this._addAddressToAuthList(_address, isAllowed || false); - resolve(); - }); - }); - - return true; + private async accountsCreateHardwareV2 (request: RequestAccountCreateHardwareV2): Promise { + return this.#koniState.keyringService.context.accountsCreateHardwareV2(request); } - private async accountsCreateHardwareMultiple ({ accounts }: RequestAccountCreateHardwareMultiple): Promise { - const addresses: string[] = []; - - if (!accounts.length) { - throw new Error(t("Can't find an account. Please try again")); - } - - const slugMap: Record = {}; - - for (const account of accounts) { - const { accountIndex, address, addressOffset, genesisHash, hardwareType, isEthereum, isGeneric, name } = account; - - let result: KeyringPair; - - const baseMeta: KeyringPair$Meta = { - name, - hardwareType, - accountIndex, - addressOffset, - genesisHash, - originGenesisHash: genesisHash, - isGeneric - }; - - if (isEthereum) { - result = keyring.keyring.addFromAddress(address, { - ...baseMeta, - isExternal: true, - isHardware: true - }, null, 'ethereum'); - - keyring.saveAccount(result); - slugMap.ethereum = 'ethereum'; - } else { - result = keyring.addHardware(address, hardwareType, { - ...baseMeta, - availableGenesisHashes: [genesisHash] - }).pair; - - const [slug] = this.#koniState.findNetworkKeyByGenesisHash(genesisHash); - - if (slug) { - slugMap[slug] = slug; - } - } - - const _address = result.address; - - addresses.push(_address); - - await new Promise((resolve) => { - this._addAddressToAuthList(_address, true); - resolve(); - }); - } - - const currentAccount = this.#koniState.keyringService.currentAccount; - const allGenesisHash = currentAccount?.allGenesisHash || undefined; - - if (addresses.length <= 1) { - this.#koniState.setCurrentAccount({ address: addresses[0], currentGenesisHash: null, allGenesisHash }); - } else { - this.#koniState.setCurrentAccount({ - address: ALL_ACCOUNT_KEY, - currentGenesisHash: allGenesisHash || null, - allGenesisHash - }); - } - - await new Promise((resolve) => { - this.#koniState.addAccountRef(addresses, () => { - resolve(); - }); - }); - - if (Object.keys(slugMap).length) { - this.enableChains({ chainSlugs: Object.keys(slugMap), enableTokens: true }).catch(console.error); - } - - return true; + private async accountsCreateHardwareMultiple (request: RequestAccountCreateHardwareMultiple): Promise { + return this.#koniState.keyringService.context.accountsCreateHardwareMultiple(request); } - private async accountsCreateWithSecret ({ isAllow, - isEthereum, - name, - publicKey, - secretKey }: RequestAccountCreateWithSecretKey): Promise { - try { - let keyringPair: KeyringPair | null = null; - - if (isEthereum) { - const _secret = hexStripPrefix(secretKey); - - if (_secret.length === 64) { - const suri = `0x${_secret}`; - const { phrase } = keyExtractSuri(suri); - - if (isHex(phrase) && isHex(phrase, 256)) { - const type: KeypairType = 'ethereum'; - - keyringPair = keyring.addUri(getSuri(suri, type), { name: name }, type).pair; - } - } - } else { - keyringPair = keyring.keyring.addFromPair({ - publicKey: hexToU8a(publicKey), - secretKey: hexToU8a(secretKey) - }, { name }); - keyring.addPair(keyringPair, true); - } - - if (!keyringPair) { - return { - success: false, - errors: [{ code: AccountExternalErrorCode.KEYRING_ERROR, message: t('Cannot create account') }] - }; - } - - const _address = keyringPair.address; - - await new Promise((resolve) => { - this.#koniState.addAccountRef([_address], () => { - resolve(); - }); - }); - - await new Promise((resolve) => { - this._saveCurrentAccountAddress(_address, () => { - this._addAddressToAuthList(_address, isAllow); - resolve(); - }); - }); + private async accountsCreateWithSecret (request: RequestAccountCreateWithSecretKey): Promise { + const result = await this.#koniState.keyringService.context.accountsCreateWithSecret(request); - if (this.#alwaysLock) { - this.keyringLock(); - } - - return { - errors: [], - success: true - }; - } catch (e) { - return { - success: false, - errors: [{ code: AccountExternalErrorCode.KEYRING_ERROR, message: (e as Error).message }] - }; + if (this.#alwaysLock) { + this.keyringLock(); } + + return result; } /// External account @@ -2931,7 +2621,7 @@ export default class KoniExtension { private keyringStateSubscribe (id: string, port: chrome.runtime.Port): KeyringState { const cb = createSubscription<'pri(keyring.subscribe)'>(id, port); - const keyringStateSubject = this.#koniState.keyringService.keyringStateSubject; + const keyringStateSubject = this.#koniState.keyringService.stateSubject; const subscription = keyringStateSubject.subscribe((value): void => cb(value) ); @@ -3271,7 +2961,7 @@ export default class KoniExtension { if (result.length === 1) { this._saveCurrentAccountAddress(result[0].address); } else { - this.#koniState.setCurrentAccount({ address: ALL_ACCOUNT_KEY, currentGenesisHash: null }); + this.#koniState.setCurrentAccount({ address: ALL_ACCOUNT_KEY }); } return true; @@ -3982,13 +3672,13 @@ export default class KoniExtension { /// Inject account private addInjects (request: RequestAddInjectedAccounts): boolean { - this.#koniState.keyringService.addInjectAccounts(request.accounts); + this.#koniState.keyringService.context.addInjectAccounts(request.accounts); return true; } private removeInjects (request: RequestRemoveInjectedAccounts): boolean { - this.#koniState.keyringService.removeInjectAccounts(request.addresses); + this.#koniState.keyringService.context.removeInjectAccounts(request.addresses); return true; } @@ -4465,9 +4155,6 @@ export default class KoniExtension { case 'pri(ping)': return 'pong'; /// Clone from PolkadotJs - case 'pri(accounts.create.external)': - return this.accountsCreateExternal(request as RequestAccountCreateExternal); - case 'pri(accounts.create.hardware)': return this.accountsCreateHardware(request as RequestAccountCreateHardware); diff --git a/packages/extension-base/src/koni/background/handlers/State.ts b/packages/extension-base/src/koni/background/handlers/State.ts index dfb61e2e2e..4fafeabe92 100644 --- a/packages/extension-base/src/koni/background/handlers/State.ts +++ b/packages/extension-base/src/koni/background/handlers/State.ts @@ -5,9 +5,9 @@ import { _AssetRef, _AssetType, _ChainAsset, _ChainInfo, _MultiChainAsset } from import { EvmProviderError } from '@subwallet/extension-base/background/errors/EvmProviderError'; import { withErrorLog } from '@subwallet/extension-base/background/handlers/helpers'; import { isSubscriptionRunning, unsubscribe } from '@subwallet/extension-base/background/handlers/subscriptions'; -import { AccountRefMap, AddTokenRequestExternal, AmountData, APIItemState, ApiMap, AuthRequestV2, BasicTxErrorType, ChainStakingMetadata, ChainType, ConfirmationsQueue, CrowdloanItem, CrowdloanJson, CurrencyType, CurrentAccountInfo, EvmProviderErrorType, EvmSendTransactionParams, EvmSendTransactionRequest, EvmSignatureRequest, ExternalRequestPromise, ExternalRequestPromiseStatus, ExtrinsicType, MantaAuthorizationContext, MantaPayConfig, MantaPaySyncState, NftCollection, NftItem, NftJson, NominatorMetadata, RequestAccountExportPrivateKey, RequestCheckPublicAndSecretKey, RequestConfirmationComplete, RequestCrowdloanContributions, RequestSettingsType, ResponseAccountExportPrivateKey, ResponseCheckPublicAndSecretKey, ServiceInfo, SingleModeJson, StakingItem, StakingJson, StakingRewardItem, StakingRewardJson, StakingType, UiSettings } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson, RequestAuthorizeTab, RequestRpcSend, RequestRpcSubscribe, RequestRpcUnsubscribe, RequestSign, ResponseRpcListProviders, ResponseSigning } from '@subwallet/extension-base/background/types'; -import { ALL_ACCOUNT_KEY, ALL_GENESIS_HASH, MANTA_PAY_BALANCE_INTERVAL, REMIND_EXPORT_ACCOUNT } from '@subwallet/extension-base/constants'; +import { AccountRefMap, AddTokenRequestExternal, AmountData, APIItemState, ApiMap, AuthRequestV2, BasicTxErrorType, ChainStakingMetadata, ChainType, ConfirmationsQueue, CrowdloanItem, CrowdloanJson, CurrencyType, EvmProviderErrorType, EvmSendTransactionParams, EvmSendTransactionRequest, EvmSignatureRequest, ExternalRequestPromise, ExternalRequestPromiseStatus, ExtrinsicType, MantaAuthorizationContext, MantaPayConfig, MantaPaySyncState, NftCollection, NftItem, NftJson, NominatorMetadata, RequestAccountExportPrivateKey, RequestCheckPublicAndSecretKey, RequestConfirmationComplete, RequestCrowdloanContributions, RequestSettingsType, ResponseAccountExportPrivateKey, ResponseCheckPublicAndSecretKey, ServiceInfo, SingleModeJson, StakingItem, StakingJson, StakingRewardItem, StakingRewardJson, StakingType, UiSettings } from '@subwallet/extension-base/background/KoniTypes'; +import { RequestAuthorizeTab, RequestRpcSend, RequestRpcSubscribe, RequestRpcUnsubscribe, RequestSign, ResponseRpcListProviders, ResponseSigning } from '@subwallet/extension-base/background/types'; +import { ALL_ACCOUNT_KEY, MANTA_PAY_BALANCE_INTERVAL, REMIND_EXPORT_ACCOUNT } from '@subwallet/extension-base/constants'; import { BalanceService } from '@subwallet/extension-base/services/balance-service'; import { ServiceStatus } from '@subwallet/extension-base/services/base/types'; import BuyService from '@subwallet/extension-base/services/buy-service'; @@ -38,7 +38,7 @@ import { TransactionEventResponse } from '@subwallet/extension-base/services/tra import WalletConnectService from '@subwallet/extension-base/services/wallet-connect-service'; import { SWStorage } from '@subwallet/extension-base/storage'; import AccountRefStore from '@subwallet/extension-base/stores/AccountRef'; -import { BalanceItem, BalanceMap, EvmFeeInfo, StorageDataInterface } from '@subwallet/extension-base/types'; +import { AccountJson, BalanceItem, BalanceMap, CurrentAccountInfo, EvmFeeInfo, StorageDataInterface } from '@subwallet/extension-base/types'; import { isAccountAll, stripUrl, targetIsWeb, wait } from '@subwallet/extension-base/utils'; import { isContractAddress, parseContractInput } from '@subwallet/extension-base/utils/eth/parseTransaction'; import { createPromiseHandler } from '@subwallet/extension-base/utils/promise'; @@ -151,7 +151,7 @@ export default class KoniState { this.eventService = new EventService(); this.dbService = new DatabaseService(this.eventService); - this.keyringService = new KeyringService(this.eventService); + this.keyringService = new KeyringService(this); this.notificationService = new NotificationService(); this.chainService = new ChainService(this.dbService, this.eventService); @@ -284,9 +284,9 @@ export default class KoniState { public generateDefaultBalanceMap (_addresses?: string[]): BalanceMap { const balanceMap: BalanceMap = {}; const activeChains = this.chainService.getActiveChainInfoMap(); - const isAllAccount = isAccountAll(this.keyringService.currentAccount.address); + const isAllAccount = isAccountAll(this.keyringService.context.currentAccount.address); - const addresses = _addresses || (isAllAccount ? Object.keys(this.keyringService.accounts) : [this.keyringService.currentAccount.address]); + const addresses = _addresses || (isAllAccount ? Object.keys(this.keyringService.context.pairs) : [this.keyringService.context.currentAccount.address]); addresses.forEach((address) => { const temp: Record = {}; @@ -415,7 +415,7 @@ export default class KoniState { } getAddressList (value = false): Record { - const addressList = Object.keys(this.keyringService.accounts); + const addressList = Object.keys(this.keyringService.context.pairs); return addressList.reduce((addressList, v) => ({ ...addressList, [v]: value }), {}); } @@ -651,29 +651,24 @@ export default class KoniState { } public setCurrentAccount (data: CurrentAccountInfo, callback?: () => void, preventOneAccount?: boolean): void { - const { address, currentGenesisHash } = data; + const { address } = data; const result: CurrentAccountInfo = { ...data }; if (address === ALL_ACCOUNT_KEY) { const pairs = keyring.getAccounts(); const pair = pairs[0]; - const pairGenesisHash = pair?.meta.genesisHash as string || ''; if (pairs.length > 1 || !pair) { - result.allGenesisHash = currentGenesisHash || undefined; + // Empty } else { if (!preventOneAccount) { result.address = pair.address; - result.currentGenesisHash = pairGenesisHash || ''; - result.allGenesisHash = pairGenesisHash || undefined; - } else { - result.allGenesisHash = currentGenesisHash || undefined; } } } - this.keyringService.setCurrentAccount(result); + this.keyringService.context.setCurrentAccount(result); callback && callback(); } @@ -686,11 +681,9 @@ export default class KoniState { keyring.saveAccountMeta(pair, { ...pair.meta, genesisHash }); } - const accountInfo = this.keyringService.currentAccount; + const accountInfo = this.keyringService.context.currentAccount; if (address === accountInfo.address) { - accountInfo.currentGenesisHash = genesisHash as string || ALL_GENESIS_HASH; - this.setCurrentAccount(accountInfo); } @@ -717,7 +710,7 @@ export default class KoniState { public async switchNetworkAccount (id: string, url: string, networkKey: string, changeAddress?: string): Promise { const chainInfo = this.chainService.getChainInfoByKey(networkKey); const chainState = this.chainService.getChainStateByKey(networkKey); - const { address, currentGenesisHash } = this.keyringService.currentAccount; + const { address } = this.keyringService.context.currentAccount; return this.requestService.addConfirmation(id, url, 'switchNetworkRequest', { networkKey, @@ -739,10 +732,9 @@ export default class KoniState { keyring.saveAccountMeta(pair, { ...pair.meta, genesisHash: _getSubstrateGenesisHash(chainInfo) }); } - if (address !== changeAddress || _getSubstrateGenesisHash(chainInfo) !== currentGenesisHash || isApproved) { + if (address !== changeAddress || isApproved) { this.setCurrentAccount({ - address: useAddress, - currentGenesisHash: _getSubstrateGenesisHash(chainInfo) + address: useAddress }); } } @@ -837,7 +829,7 @@ export default class KoniState { } public getAccountAddress (): string | null { - const address = this.keyringService.currentAccount.address; + const address = this.keyringService.context.currentAccount.address; if (address === '') { return null; @@ -916,7 +908,7 @@ export default class KoniState { } private updateCrowdloanStore (networkKey: string, item: CrowdloanItem) { - const currentAccountInfo = this.keyringService.currentAccount; + const currentAccountInfo = this.keyringService.context.currentAccount; this.dbService.updateCrowdloanStore(networkKey, currentAccountInfo.address, item).catch((e) => this.logger.warn(e)); } @@ -1137,7 +1129,7 @@ export default class KoniState { return { chainInfoMap: this.chainService.getChainInfoMap(), chainApiMap: this.getApiMap(), - currentAccountInfo: this.keyringService.currentAccount, + currentAccountInfo: this.keyringService.context.currentAccount, assetRegistry: this.chainService.getAssetRegistry(), chainStateMap: this.chainService.getChainStateMap() }; @@ -1715,7 +1707,7 @@ export default class KoniState { } }; - const subscription = this.keyringService.currentAccountSubject.subscribe(handleRemind); + const subscription = this.keyringService.context.currentAccountSubject.subscribe(handleRemind); } } @@ -1925,7 +1917,7 @@ export default class KoniState { } public async reloadNft () { - const currentAddress = this.keyringService.currentAccount.address; + const currentAddress = this.keyringService.context.currentAccount.address; await this.dbService.removeNftsByAddress(currentAddress); @@ -2121,7 +2113,7 @@ export default class KoniState { public subscribeMantaPayBalance () { let interval: NodeJS.Timer | undefined; - this.chainService?.mantaPay?.getMantaPayConfig(this.keyringService.currentAccount.address, _DEFAULT_MANTA_ZK_CHAIN) + this.chainService?.mantaPay?.getMantaPayConfig(this.keyringService.context.currentAccount.address, _DEFAULT_MANTA_ZK_CHAIN) .then((config: MantaPayConfig) => { if (config && config.enabled && config.isInitialSync) { this.getMantaZkBalance(); diff --git a/packages/extension-base/src/koni/background/handlers/Tabs.ts b/packages/extension-base/src/koni/background/handlers/Tabs.ts index 3081e040c0..cde206dd10 100644 --- a/packages/extension-base/src/koni/background/handlers/Tabs.ts +++ b/packages/extension-base/src/koni/background/handlers/Tabs.ts @@ -290,7 +290,7 @@ export default class KoniTabs { anyType }: RequestAccountList): Promise { const authInfo = await this.getAuthInfo(url); - return transformAccountsV2(this.#koniState.keyringService.accounts, anyType, authInfo, authInfo?.accountAuthType || accountAuthType); + return transformAccountsV2(this.#koniState.keyringService.context.pairs, anyType, authInfo, authInfo?.accountAuthType || accountAuthType); } private accountsSubscribeV2 (url: string, { accountAuthType }: RequestAccountSubscribe, id: string, port: chrome.runtime.Port): string { @@ -303,7 +303,7 @@ export default class KoniTabs { this.getAuthInfo(url, infos) .then((authInfo) => { const accountAuthType_ = authInfo?.accountAuthType || accountAuthType; - const accounts = this.#koniState.keyringService.accounts; + const accounts = this.#koniState.keyringService.context.pairs; return cb(transformAccountsV2(accounts, false, authInfo, accountAuthType_)); }) @@ -349,11 +349,11 @@ export default class KoniTabs { private async getEvmCurrentAccount (url: string): Promise { return await new Promise((resolve) => { this.getAuthInfo(url).then((authInfo) => { - const allAccounts = this.#koniState.keyringService.accounts; + const allAccounts = this.#koniState.keyringService.context.pairs; const accountList = transformAccountsV2(allAccounts, false, authInfo, 'evm').map((a) => a.address); let accounts: string[] = []; - const address = this.#koniState.keyringService.currentAccount.address; + const address = this.#koniState.keyringService.context.currentAccount.address; if (address === ALL_ACCOUNT_KEY || !address) { accounts = accountList; @@ -716,7 +716,7 @@ export default class KoniTabs { } }; - const accountListSubscription = this.#koniState.keyringService.currentAccountSubject + const accountListSubscription = this.#koniState.keyringService.context.currentAccountSubject .subscribe(() => { onCurrentAccountChanged().catch(console.error); }); diff --git a/packages/extension-base/src/koni/background/subscription.ts b/packages/extension-base/src/koni/background/subscription.ts index 6d61830395..0a531d4a26 100644 --- a/packages/extension-base/src/koni/background/subscription.ts +++ b/packages/extension-base/src/koni/background/subscription.ts @@ -66,7 +66,7 @@ export class KoniSubscription { async start () { await Promise.all([this.state.eventService.waitCryptoReady, this.state.eventService.waitKeyringReady, this.state.eventService.waitAssetReady]); - const currentAddress = this.state.keyringService.currentAccount?.address; + const currentAddress = this.state.keyringService.context.currentAccount?.address; if (currentAddress) { this.subscribeCrowdloans(currentAddress, this.state.getSubstrateApiMap()); @@ -155,7 +155,7 @@ export class KoniSubscription { } async reloadCrowdloan () { - const currentAddress = this.state.keyringService.currentAccount?.address; + const currentAddress = this.state.keyringService.context.currentAccount?.address; this.subscribeCrowdloans(currentAddress, this.state.getSubstrateApiMap()); diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts index 0035483662..7a01b209b9 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts @@ -3,10 +3,9 @@ import { _AssetType, _ChainAsset, _ChainInfo } from '@subwallet/chain-list/types'; import { APIItemState, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { _EvmApi, _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; import { _getSubstrateGenesisHash, _isChainEvmCompatible, _isPureEvmChain } from '@subwallet/extension-base/services/chain-service/utils'; -import { BalanceItem } from '@subwallet/extension-base/types'; +import { AccountJson, BalanceItem } from '@subwallet/extension-base/types'; import { categoryAddresses, filterAssetsByChainAndType } from '@subwallet/extension-base/utils'; import keyring from '@subwallet/ui-keyring'; diff --git a/packages/extension-base/src/services/balance-service/index.ts b/packages/extension-base/src/services/balance-service/index.ts index 63e234b5b8..8b5802103a 100644 --- a/packages/extension-base/src/services/balance-service/index.ts +++ b/packages/extension-base/src/services/balance-service/index.ts @@ -309,7 +309,7 @@ export class BalanceService implements StoppableServiceInterface { } addLazy('updateBalanceStore', () => { - const isAllAccount = isAccountAll(this.state.keyringService.currentAccount.address); + const isAllAccount = isAccountAll(this.state.keyringService.context.currentAccount.address); this.balanceMap.updateBalanceItems(this.balanceUpdateCache, isAllAccount); diff --git a/packages/extension-base/src/services/event-service/types.ts b/packages/extension-base/src/services/event-service/types.ts index 39636c9d4f..30a92ac8b1 100644 --- a/packages/extension-base/src/services/event-service/types.ts +++ b/packages/extension-base/src/services/event-service/types.ts @@ -1,8 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-base // SPDX-License-Identifier: Apache-2.0 -import { CurrentAccountInfo } from '@subwallet/extension-base/background/KoniTypes'; import { SWTransaction } from '@subwallet/extension-base/services/transaction-service/types'; +import { CurrentAccountInfo } from '@subwallet/extension-base/types'; export interface EventRegistry { 'general.sleep': [boolean]; diff --git a/packages/extension-base/src/services/history-service/index.ts b/packages/extension-base/src/services/history-service/index.ts index ba331e2d31..c952099f01 100644 --- a/packages/extension-base/src/services/history-service/index.ts +++ b/packages/extension-base/src/services/history-service/index.ts @@ -52,7 +52,7 @@ export class HistoryService implements StoppableServiceInterface, PersistDataSer const historyRecords = [] as TransactionHistoryItem[]; // Fill additional info - const accountMap = Object.entries(this.keyringService.accounts).reduce((map, [address, account]) => { + const accountMap = Object.entries(this.keyringService.context.pairs).reduce((map, [address, account]) => { map[address.toLowerCase()] = account.json.meta.name || address; return map; diff --git a/packages/extension-base/src/services/keyring-service/account-context.ts b/packages/extension-base/src/services/keyring-service/account-context.ts new file mode 100644 index 0000000000..062e64fc41 --- /dev/null +++ b/packages/extension-base/src/services/keyring-service/account-context.ts @@ -0,0 +1,667 @@ +// Copyright 2019-2022 @subwallet/extension-base +// SPDX-License-Identifier: Apache-2.0 + +import { AccountExternalError, AccountExternalErrorCode, AccountRefMap, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateSuriV2, RequestAccountCreateWithSecretKey, ResponseAccountCreateSuriV2, ResponseAccountCreateWithSecretKey } from '@subwallet/extension-base/background/KoniTypes'; +import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; +import { _getEvmChainId, _getSubstrateGenesisHash } from '@subwallet/extension-base/services/chain-service/utils'; +import { KeyringService } from '@subwallet/extension-base/services/keyring-service/index'; +import { CurrentAccountStore } from '@subwallet/extension-base/stores'; +import AccountGroupStore from '@subwallet/extension-base/stores/AccountGroupStore'; +import AccountRefStore from '@subwallet/extension-base/stores/AccountRef'; +import ModifyPairStore from '@subwallet/extension-base/stores/ModifyPairStore'; +import { AccountGroupData, AccountGroupMap, AccountGroupStoreData, AccountJson, CurrentAccountInfo, ModifyPairStoreData } from '@subwallet/extension-base/types'; +import { isAddressValidWithAuthType, transformAccount, transformAccounts } from '@subwallet/extension-base/utils'; +import { InjectedAccountWithMeta } from '@subwallet/extension-inject/types'; +import { KeyringPair, KeyringPair$Meta } from '@subwallet/keyring/types'; +import { keyring } from '@subwallet/ui-keyring'; +import { SubjectInfo } from '@subwallet/ui-keyring/observable/types'; +import { t } from 'i18next'; +import { BehaviorSubject, combineLatest } from 'rxjs'; + +import { hexStripPrefix, hexToU8a, isHex, stringShorten } from '@polkadot/util'; +import { keyExtractSuri } from '@polkadot/util-crypto'; +import { KeypairType } from '@polkadot/util-crypto/types'; + +const ETH_DERIVE_DEFAULT = '/m/44\'/60\'/0\'/0/0'; + +const getSuri = (seed: string, type?: KeypairType): string => type === 'ethereum' + ? `${seed}${ETH_DERIVE_DEFAULT}` + : seed; + +const CURRENT_ACCOUNT_KEY = 'CurrentAccountInfo'; +const MODIFY_PAIRS_KEY = 'ModifyPairs'; +const ACCOUNT_GROUPS_KEY = 'AccountGroups'; + +export class AccountContext { + // Current account + private readonly currentAccountStore = new CurrentAccountStore(); + public readonly currentAccountSubject = new BehaviorSubject({ address: '' }); + + // Account groups + private readonly accountGroupsStore = new AccountGroupStore(); + public readonly accountGroupsSubject = new BehaviorSubject({}); + + // Modify pairs + private readonly modifyPairsStore = new ModifyPairStore(); + public readonly modifyPairsSubject = new BehaviorSubject({}); + + // Observable of accounts, pairs and contacts + public readonly contactSubject = keyring.addresses.subject; + public readonly pairSubject = keyring.accounts.subject; + public readonly accountSubject = new BehaviorSubject({}); + + // Old from Polkadot-js + private readonly accountRefStore = new AccountRefStore(); + + // Save before account info to check if accounts changed (injected accounts) + private beforeAccount: SubjectInfo = this.pairSubject.value; + + private injected: boolean; + + constructor (private parent: KeyringService) { + this.injected = false; + + this.parent.state.eventService.waitCryptoReady + .then(() => { + // Load current account + this.currentAccountStore.get(CURRENT_ACCOUNT_KEY, (rs) => { + rs && this.currentAccountSubject.next(rs); + }); + // Load modify pairs + this.modifyPairsStore.get(MODIFY_PAIRS_KEY, (rs) => { + rs && this.modifyPairsSubject.next(rs); + }); + // Load account groups + this.accountGroupsStore.get(ACCOUNT_GROUPS_KEY, (rs) => { + rs && this.accountGroupsSubject.next(rs); + }); + this.subscribeAccounts().catch(console.error); + }) + .catch(console.error); + } + + private async subscribeAccounts () { + // Wait until account ready + await this.parent.state.eventService.waitAccountReady; + this.beforeAccount = { ...this.pairSubject.value }; + this.pairSubject.subscribe((subjectInfo) => { + // Check if accounts changed + const beforeAddresses = Object.keys(this.beforeAccount); + const afterAddresses = Object.keys(subjectInfo); + + if (beforeAddresses.length > afterAddresses.length) { + const removedAddresses = beforeAddresses.filter((address) => !afterAddresses.includes(address)); + + // Remove account + removedAddresses.forEach((address) => { + this.parent.state.eventService.emit('account.remove', address); + }); + } else if (beforeAddresses.length < afterAddresses.length) { + const addedAddresses = afterAddresses.filter((address) => !beforeAddresses.includes(address)); + + // Add account + addedAddresses.forEach((address) => { + this.parent.state.eventService.emit('account.add', address); + }); + } else { + // Handle case update later + } + + this.beforeAccount = { ...subjectInfo }; + }); + + const pairs = this.pairSubject.asObservable(); + const modifyPairs = this.modifyPairsSubject.asObservable(); + const accountGroups = this.accountGroupsSubject.asObservable(); + + combineLatest([pairs, modifyPairs, accountGroups]).subscribe(([pairs, modifyPairs, accountGroups]) => { + const result: AccountGroupMap = {}; + + for (const [address, pair] of Object.entries(pairs)) { + const modifyPair = modifyPairs[address]; + const account: AccountJson = transformAccount(pair); + + if (modifyPair && modifyPair.applied && modifyPair.accountGroupId) { + const accountGroup = accountGroups[modifyPair.accountGroupId]; + + if (accountGroup) { + if (!result[accountGroup.id]) { + result[accountGroup.id] = { ...accountGroup, accounts: [] }; + } + + result[accountGroup.id].accounts.push(account); + continue; + } + } + + result[address] = { id: address, name: account.name || account.address, accounts: [account] }; + } + + this.accountGroupsSubject.next(result); + }); + } + + get pairs (): SubjectInfo { + return this.pairSubject.value; + } + + get contacts (): SubjectInfo { + return this.contactSubject.value; + } + + get accounts (): AccountGroupMap { + return this.accountSubject.value; + } + + /* Current account */ + + get currentAccount (): CurrentAccountInfo { + return this.currentAccountSubject.value; + } + + setCurrentAccount (currentAccountData: CurrentAccountInfo) { + this.currentAccountSubject.next(currentAccountData); + this.parent.state.eventService.emit('account.updateCurrent', currentAccountData); + this.currentAccountStore.set(CURRENT_ACCOUNT_KEY, currentAccountData); + } + + public _setCurrentAccount (data: CurrentAccountInfo, callback?: () => void, preventOneAccount?: boolean): void { + const { address } = data; + + const result: CurrentAccountInfo = { ...data }; + + if (address === ALL_ACCOUNT_KEY) { + const pairs = keyring.getAccounts(); + const pair = pairs[0]; + + if (pairs.length > 1 || !pair) { + // Empty + } else { + if (!preventOneAccount) { + result.address = pair.address; + } + } + } + + this.setCurrentAccount(result); + callback && callback(); + } + + private _saveCurrentAccountAddress (address: string, callback?: (data: CurrentAccountInfo) => void) { + let accountInfo = this.currentAccount; + + if (!accountInfo) { + accountInfo = { + address + }; + } else { + accountInfo.address = address; + } + + this._setCurrentAccount(accountInfo, () => { + callback && callback(accountInfo); + }); + } + + /* Current account */ + + private _addAddressToAuthList (address: string, isAllowed: boolean): void { + this.parent.state.getAuthorize((value) => { + if (value && Object.keys(value).length) { + Object.keys(value).forEach((url) => { + if (isAddressValidWithAuthType(address, value[url].accountAuthType)) { + value[url].isAllowedMap[address] = isAllowed; + } + }); + + this.parent.state.setAuthorize(value); + } + }); + } + + /* Account groups */ + + /* Upsert account group */ + + private upsertAccountGroup (data: AccountGroupData, callback?: () => void) { + this.accountGroupsStore.get(ACCOUNT_GROUPS_KEY, (rs) => { + const accountGroups = rs || {}; + + accountGroups[data.id] = data; + this.accountGroupsSubject.next(accountGroups); + this.accountGroupsStore.set(ACCOUNT_GROUPS_KEY, accountGroups, callback); + }); + } + + /* Account group */ + + /* Add accounts from seed */ + public async accountsCreateSuriV2 (request: RequestAccountCreateSuriV2): Promise { + const { genesisHash, isAllowed, name, password, suri: _suri, types } = request; + const addressDict = {} as Record; + let changedAccount = false; + const hasMasterPassword = keyring.keyring.hasMasterPassword; + + if (!hasMasterPassword) { + if (!password) { + throw Error(t('The password of each account is needed to set up master password')); + } else { + keyring.changeMasterPassword(password); + this.parent.updateKeyringState(); + } + } + + // const currentAccount = this.#koniState.keyringService.context.currentAccount; + // const allGenesisHash = currentAccount?.allGenesisHash || undefined; + + types?.forEach((type) => { + const suri = getSuri(_suri, type); + const address = keyring.createFromUri(suri, {}, type).address; + + addressDict[type] = address; + const newAccountName = type === 'ethereum' ? `${name} - EVM` : name; + + keyring.addUri(suri, { genesisHash, name: newAccountName }, type); + this._addAddressToAuthList(address, isAllowed); + + if (!changedAccount) { + if (types.length === 1) { + this.setCurrentAccount({ address }); + } else { + this._setCurrentAccount({ address: ALL_ACCOUNT_KEY }, undefined, true); + } + + changedAccount = true; + } + }); + + await new Promise((resolve) => { + this.addAccountRef(Object.values(addressDict), () => { + resolve(); + }); + }); + + return addressDict; + } + + /* Add QR-signer, read-only */ + public async accountsCreateExternalV2 (request: RequestAccountCreateExternalV2): Promise { + const { address, genesisHash, isAllowed, isEthereum, isReadOnly, name } = request; + + try { + let result: KeyringPair; + + try { + const exists = keyring.getPair(address); + + if (exists) { + if (exists.type === (isEthereum ? 'ethereum' : 'sr25519')) { + return [{ code: AccountExternalErrorCode.INVALID_ADDRESS, message: t('Account exists') }]; + } + } + } catch (e) { + + } + + if (isEthereum) { + const chainInfoMap = this.parent.state.getChainInfoMap(); + let _gen = ''; + + if (genesisHash) { + for (const network of Object.values(chainInfoMap)) { + if (_getEvmChainId(network) === parseInt(genesisHash)) { + // TODO: pure EVM chains do not have genesisHash + _gen = _getSubstrateGenesisHash(network); + } + } + } + + result = keyring.keyring.addFromAddress(address, { + name, + isExternal: true, + isReadOnly, + genesisHash: _gen + }, null, 'ethereum'); + + keyring.saveAccount(result); + } else { + result = keyring.addExternal(address, { genesisHash, name, isReadOnly }).pair; + } + + const _address = result.address; + + await new Promise((resolve) => { + this.parent.state.addAccountRef([_address], () => { + resolve(); + }); + }); + + await new Promise((resolve) => { + this._saveCurrentAccountAddress(_address, () => { + this._addAddressToAuthList(_address, isAllowed); + resolve(); + }); + }); + + return []; + } catch (e) { + return [{ code: AccountExternalErrorCode.KEYRING_ERROR, message: (e as Error).message }]; + } + } + + /* Ledger */ + + /* For custom derive path */ + public async accountsCreateHardwareV2 (request: RequestAccountCreateHardwareV2): Promise { + const { accountIndex, address, addressOffset, genesisHash, hardwareType, isAllowed, name } = request; + const key = keyring.addHardware(address, hardwareType, { + accountIndex, + addressOffset, + genesisHash, + name, + originGenesisHash: genesisHash + }); + + const result = key.pair; + + const _address = result.address; + + await new Promise((resolve) => { + this.addAccountRef([_address], () => { + resolve(); + }); + }); + + await new Promise((resolve) => { + this._saveCurrentAccountAddress(_address, () => { + this._addAddressToAuthList(_address, isAllowed || false); + resolve(); + }); + }); + + return true; + } + + /* For multi select */ + public async accountsCreateHardwareMultiple ({ accounts }: RequestAccountCreateHardwareMultiple): Promise { + const addresses: string[] = []; + + if (!accounts.length) { + throw new Error(t("Can't find an account. Please try again")); + } + + const slugMap: Record = {}; + + for (const account of accounts) { + const { accountIndex, address, addressOffset, genesisHash, hardwareType, isEthereum, isGeneric, name } = account; + + let result: KeyringPair; + + const baseMeta: KeyringPair$Meta = { + name, + hardwareType, + accountIndex, + addressOffset, + genesisHash, + originGenesisHash: genesisHash, + isGeneric + }; + + if (isEthereum) { + result = keyring.keyring.addFromAddress(address, { + ...baseMeta, + isExternal: true, + isHardware: true + }, null, 'ethereum'); + + keyring.saveAccount(result); + slugMap.ethereum = 'ethereum'; + } else { + result = keyring.addHardware(address, hardwareType, { + ...baseMeta, + availableGenesisHashes: [genesisHash] + }).pair; + + const [slug] = this.parent.state.findNetworkKeyByGenesisHash(genesisHash); + + if (slug) { + slugMap[slug] = slug; + } + } + + const _address = result.address; + + addresses.push(_address); + + await new Promise((resolve) => { + this._addAddressToAuthList(_address, true); + resolve(); + }); + } + + // const currentAccount = this.#koniState.keyringService.context.currentAccount; + // const allGenesisHash = currentAccount?.allGenesisHash || undefined; + + if (addresses.length <= 1) { + this._setCurrentAccount({ address: addresses[0] }); + } else { + this._setCurrentAccount({ address: ALL_ACCOUNT_KEY }); + } + + await new Promise((resolve) => { + this.addAccountRef(addresses, () => { + resolve(); + }); + }); + + if (Object.keys(slugMap).length) { + for (const chainSlug of Object.keys(slugMap)) { + this.parent.state.enableChain(chainSlug, true).catch(console.error); + } + } + + return true; + } + + /* Ledger */ + + /* Add with secret and public key */ + + public async accountsCreateWithSecret (request: RequestAccountCreateWithSecretKey): Promise { + const { isAllow, isEthereum, name, publicKey, secretKey } = request; + + try { + let keyringPair: KeyringPair | null = null; + + if (isEthereum) { + const _secret = hexStripPrefix(secretKey); + + if (_secret.length === 64) { + const suri = `0x${_secret}`; + const { phrase } = keyExtractSuri(suri); + + if (isHex(phrase) && isHex(phrase, 256)) { + const type: KeypairType = 'ethereum'; + + keyringPair = keyring.addUri(getSuri(suri, type), { name: name }, type).pair; + } + } + } else { + keyringPair = keyring.keyring.addFromPair({ + publicKey: hexToU8a(publicKey), + secretKey: hexToU8a(secretKey) + }, { name }); + keyring.addPair(keyringPair, true); + } + + if (!keyringPair) { + return { + success: false, + errors: [{ code: AccountExternalErrorCode.KEYRING_ERROR, message: t('Cannot create account') }] + }; + } + + const _address = keyringPair.address; + + await new Promise((resolve) => { + this.addAccountRef([_address], () => { + resolve(); + }); + }); + + await new Promise((resolve) => { + this._saveCurrentAccountAddress(_address, () => { + this._addAddressToAuthList(_address, isAllow); + resolve(); + }); + }); + + return { + errors: [], + success: true + }; + } catch (e) { + return { + success: false, + errors: [{ code: AccountExternalErrorCode.KEYRING_ERROR, message: (e as Error).message }] + }; + } + } + + /* Inject */ + + public addInjectAccounts (accounts: InjectedAccountWithMeta[]) { + keyring.addInjects(accounts.map((account) => { + const name = account.meta.name || stringShorten(account.address); + + // TODO: Add if need + // name = name.concat(' (', account.meta.source, ')'); + + return { + ...account, + meta: { + ...account.meta, + name: name + } + }; + })); + + const currentAddress = this.currentAccountSubject.value.address; + const afterAccounts: Record = {}; + + Object.keys(this.pairs).forEach((adr) => { + afterAccounts[adr] = true; + }); + + accounts.forEach((value) => { + afterAccounts[value.address] = true; + }); + + if (Object.keys(afterAccounts).length === 1) { + this.currentAccountSubject.next({ address: Object.keys(afterAccounts)[0] }); + } else if (Object.keys(afterAccounts).indexOf(currentAddress) === -1) { + this.currentAccountSubject.next({ address: ALL_ACCOUNT_KEY }); + } + + if (!this.injected) { + this.parent.state.eventService.emit('inject.ready', true); + this.injected = true; + } + } + + public removeInjectAccounts (_addresses: string[]) { + const addresses = _addresses.map((address) => { + try { + return keyring.getPair(address).address; + } catch (error) { + return address; + } + }); + const currentAddress = this.currentAccountSubject.value.address; + const afterAccounts = Object.keys(this.pairs).filter((address) => (addresses.indexOf(address) < 0)); + + if (afterAccounts.length === 1) { + this.currentAccountSubject.next({ address: afterAccounts[0] }); + } else if (addresses.indexOf(currentAddress) === -1) { + this.currentAccountSubject.next({ address: ALL_ACCOUNT_KEY }); + } + + keyring.removeInjects(addresses); + } + + /* Inject */ + + /** + * @deprecated + * Account ref + * */ + + /** @deprecated */ + public getAccountRefMap (callback: (refMap: Record>) => void) { + const refMap: AccountRefMap = {}; + + this.accountRefStore.get('refList', (refList) => { + if (refList) { + refList.forEach((accRef) => { + accRef.forEach((acc) => { + refMap[acc] = [...accRef].filter((r) => !(r === acc)); + }); + }); + } + + callback(refMap); + }); + } + + /** @deprecated */ + public addAccountRef (addresses: string[], callback: () => void) { + this.accountRefStore.get('refList', (refList) => { + const newList = refList ? [...refList] : []; + + newList.push(addresses); + + this.accountRefStore.set('refList', newList, callback); + }); + } + + /** @deprecated */ + public removeAccountRef (address: string, callback: () => void) { + this.accountRefStore.get('refList', (refList) => { + if (refList) { + refList.forEach((accRef) => { + if (accRef.indexOf(address) > -1) { + accRef.splice(accRef.indexOf(address), 1); + } + + if (accRef.length < 2) { + refList.splice(refList.indexOf(accRef), 1); + } + }); + + this.accountRefStore.set('refList', refList, () => { + callback(); + }); + } else { + callback(); + } + }); + } + + /** + * Account ref + * */ + + /* Others */ + + removeNoneHardwareGenesisHash () { + const pairs = keyring.getPairs(); + + const needUpdatePairs = pairs.filter(({ meta: { genesisHash, isHardware } }) => !isHardware && genesisHash && genesisHash !== ''); + + needUpdatePairs.forEach((pair) => { + keyring.saveAccountMeta(pair, { ...pair.meta, genesisHash: '' }); + }); + } + + /* Others */ +} diff --git a/packages/extension-base/src/services/keyring-service/index.ts b/packages/extension-base/src/services/keyring-service/index.ts index 4a344259bf..00bd6bfb06 100644 --- a/packages/extension-base/src/services/keyring-service/index.ts +++ b/packages/extension-base/src/services/keyring-service/index.ts @@ -1,180 +1,53 @@ // Copyright 2019-2022 @subwallet/extension-base // SPDX-License-Identifier: Apache-2.0 -import { CurrentAccountInfo, KeyringState } from '@subwallet/extension-base/background/KoniTypes'; +import { KeyringState } from '@subwallet/extension-base/background/KoniTypes'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; -import { EventService } from '@subwallet/extension-base/services/event-service'; -import { CurrentAccountStore } from '@subwallet/extension-base/stores'; -import { InjectedAccountWithMeta } from '@subwallet/extension-inject/types'; +import KoniState from '@subwallet/extension-base/koni/background/handlers/State'; import { keyring } from '@subwallet/ui-keyring'; -import { SubjectInfo } from '@subwallet/ui-keyring/observable/types'; import { BehaviorSubject } from 'rxjs'; -import { stringShorten } from '@polkadot/util'; +import { AccountContext } from './account-context'; export class KeyringService { - private readonly currentAccountStore = new CurrentAccountStore(); - readonly currentAccountSubject = new BehaviorSubject({ address: '', currentGenesisHash: null }); - - readonly addressesSubject = keyring.addresses.subject; - public readonly accountSubject = keyring.accounts.subject; - private beforeAccount: SubjectInfo = this.accountSubject.value; - private injected: boolean; - - readonly keyringStateSubject = new BehaviorSubject({ + readonly stateSubject = new BehaviorSubject({ isReady: false, hasMasterPassword: false, isLocked: false }); - constructor (private eventService: EventService) { - this.injected = false; - this.eventService.waitCryptoReady.then(() => { - this.currentAccountStore.get('CurrentAccountInfo', (rs) => { - rs && this.currentAccountSubject.next(rs); - }); - this.subscribeAccounts().catch(console.error); - }).catch(console.error); - } - - private async subscribeAccounts () { - // Wait until account ready - await this.eventService.waitAccountReady; - - this.beforeAccount = { ...this.accountSubject.value }; - - this.accountSubject.subscribe((subjectInfo) => { - // Check if accounts changed - const beforeAddresses = Object.keys(this.beforeAccount); - const afterAddresses = Object.keys(subjectInfo); + readonly context: AccountContext; - if (beforeAddresses.length > afterAddresses.length) { - const removedAddresses = beforeAddresses.filter((address) => !afterAddresses.includes(address)); - - // Remove account - removedAddresses.forEach((address) => { - this.eventService.emit('account.remove', address); - }); - } else if (beforeAddresses.length < afterAddresses.length) { - const addedAddresses = afterAddresses.filter((address) => !beforeAddresses.includes(address)); - - // Add account - addedAddresses.forEach((address) => { - this.eventService.emit('account.add', address); - }); - } else { - // Handle case update later - } - - this.beforeAccount = { ...subjectInfo }; - }); + constructor (public state: KoniState) { + this.context = new AccountContext(this); } get keyringState () { - return this.keyringStateSubject.value; + return this.stateSubject.value; } updateKeyringState (isReady = true) { if (!this.keyringState.isReady && isReady) { - this.eventService.waitCryptoReady.then(() => { - this.eventService.emit('keyring.ready', true); - this.eventService.emit('account.ready', true); - }).catch(console.error); + this.state.eventService.waitCryptoReady + .then(() => { + this.state.eventService.emit('keyring.ready', true); + this.state.eventService.emit('account.ready', true); + }) + .catch(console.error); } - this.keyringStateSubject.next({ + this.stateSubject.next({ hasMasterPassword: !!keyring.keyring?.hasMasterPassword, isLocked: !!keyring.keyring?.isLocked, isReady: isReady }); } - get accounts (): SubjectInfo { - return this.accountSubject.value; - } - - get addresses (): SubjectInfo { - return this.addressesSubject.value; - } - - get currentAccount (): CurrentAccountInfo { - return this.currentAccountSubject.value; - } - - setCurrentAccount (currentAccountData: CurrentAccountInfo) { - this.currentAccountSubject.next(currentAccountData); - this.eventService.emit('account.updateCurrent', currentAccountData); - this.currentAccountStore.set('CurrentAccountInfo', currentAccountData); - } - public lock () { keyring.lockAll(); this.updateKeyringState(); } - /* Inject */ - - public addInjectAccounts (accounts: InjectedAccountWithMeta[]) { - keyring.addInjects(accounts.map((account) => { - const name = account.meta.name || stringShorten(account.address); - - // TODO: Add if need - // name = name.concat(' (', account.meta.source, ')'); - - return { - ...account, - meta: { - ...account.meta, - name: name - } - }; - })); - - const currentAddress = this.currentAccountSubject.value.address; - const afterAccounts: Record = {}; - - Object.keys(this.accounts).forEach((adr) => { - afterAccounts[adr] = true; - }); - - accounts.forEach((value) => { - afterAccounts[value.address] = true; - }); - - if (Object.keys(afterAccounts).length === 1) { - this.currentAccountSubject.next({ address: Object.keys(afterAccounts)[0], currentGenesisHash: null }); - } else if (Object.keys(afterAccounts).indexOf(currentAddress) === -1) { - this.currentAccountSubject.next({ address: ALL_ACCOUNT_KEY, currentGenesisHash: null }); - } - - if (!this.injected) { - this.eventService.emit('inject.ready', true); - this.injected = true; - } - } - - public removeInjectAccounts (_addresses: string[]) { - const addresses = _addresses.map((address) => { - try { - return keyring.getPair(address).address; - } catch (error) { - return address; - } - }); - const currentAddress = this.currentAccountSubject.value.address; - const afterAccounts = Object.keys(this.accounts).filter((address) => (addresses.indexOf(address) < 0)); - - if (afterAccounts.length === 1) { - this.currentAccountSubject.next({ address: afterAccounts[0], currentGenesisHash: null }); - } else if (addresses.indexOf(currentAddress) === -1) { - this.currentAccountSubject.next({ address: ALL_ACCOUNT_KEY, currentGenesisHash: null }); - } - - keyring.removeInjects(addresses); - } - - /* Inject */ - /* Reset */ async resetWallet (resetAll: boolean) { keyring.resetWallet(resetAll); @@ -184,19 +57,7 @@ export class KeyringService { }, 1500); }); this.updateKeyringState(); - this.currentAccountSubject.next({ address: ALL_ACCOUNT_KEY, currentGenesisHash: null }); + this.context.currentAccountSubject.next({ address: ALL_ACCOUNT_KEY }); } /* Reset */ - - /* Others */ - removeNoneHardwareGenesisHash () { - const pairs = keyring.getPairs(); - - const needUpdatePairs = pairs.filter(({ meta: { genesisHash, isHardware } }) => !isHardware && genesisHash && genesisHash !== ''); - - needUpdatePairs.forEach((pair) => { - keyring.saveAccountMeta(pair, { ...pair.meta, genesisHash: '' }); - }); - } - /* Others */ } diff --git a/packages/extension-base/src/services/migration-service/scripts/MigrateRemoveGenesisHash.ts b/packages/extension-base/src/services/migration-service/scripts/MigrateRemoveGenesisHash.ts index 86034e3f99..5753866a13 100644 --- a/packages/extension-base/src/services/migration-service/scripts/MigrateRemoveGenesisHash.ts +++ b/packages/extension-base/src/services/migration-service/scripts/MigrateRemoveGenesisHash.ts @@ -8,7 +8,7 @@ export default class MigrateRemoveGenesisHash extends BaseMigrationJob { try { return new Promise((resolve) => { try { - this.state.keyringService.removeNoneHardwareGenesisHash(); + this.state.keyringService.context.removeNoneHardwareGenesisHash(); } catch (e) { console.error(e); } diff --git a/packages/extension-base/src/services/request-service/handler/AuthRequestHandler.ts b/packages/extension-base/src/services/request-service/handler/AuthRequestHandler.ts index e6abfb7e28..27a0ea292a 100644 --- a/packages/extension-base/src/services/request-service/handler/AuthRequestHandler.ts +++ b/packages/extension-base/src/services/request-service/handler/AuthRequestHandler.ts @@ -58,7 +58,7 @@ export default class AuthRequestHandler { } private getAddressList (value = false): Record { - const addressList = Object.keys(this.keyringService.accounts); + const addressList = Object.keys(this.keyringService.context.pairs); return addressList.reduce((addressList, v) => ({ ...addressList, [v]: value }), {}); } diff --git a/packages/extension-base/src/services/request-service/handler/SubstrateRequestHandler.ts b/packages/extension-base/src/services/request-service/handler/SubstrateRequestHandler.ts index e6baf5ad31..732f0fbe87 100644 --- a/packages/extension-base/src/services/request-service/handler/SubstrateRequestHandler.ts +++ b/packages/extension-base/src/services/request-service/handler/SubstrateRequestHandler.ts @@ -2,9 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 import RequestExtrinsicSign from '@subwallet/extension-base/background/RequestExtrinsicSign'; -import { AccountJson, RequestSign, Resolver, ResponseSigning, SigningRequest } from '@subwallet/extension-base/background/types'; +import { RequestSign, Resolver, ResponseSigning, SigningRequest } from '@subwallet/extension-base/background/types'; import RequestService from '@subwallet/extension-base/services/request-service'; import { SignRequest } from '@subwallet/extension-base/services/request-service/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { getId } from '@subwallet/extension-base/utils/getId'; import { isInternalRequest } from '@subwallet/extension-base/utils/request'; import keyring from '@subwallet/ui-keyring'; diff --git a/packages/extension-base/src/services/request-service/index.ts b/packages/extension-base/src/services/request-service/index.ts index 660aa3674e..badb36e732 100644 --- a/packages/extension-base/src/services/request-service/index.ts +++ b/packages/extension-base/src/services/request-service/index.ts @@ -2,11 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 import { AuthRequestV2, ConfirmationDefinitions, ConfirmationsQueue, ConfirmationsQueueItemOptions, ConfirmationType, RequestConfirmationComplete } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountAuthType, AccountJson, AuthorizeRequest, MetadataRequest, RequestAuthorizeTab, RequestSign, ResponseSigning, SigningRequest } from '@subwallet/extension-base/background/types'; +import { AccountAuthType, AuthorizeRequest, MetadataRequest, RequestAuthorizeTab, RequestSign, ResponseSigning, SigningRequest } from '@subwallet/extension-base/background/types'; import { ChainService } from '@subwallet/extension-base/services/chain-service'; import { KeyringService } from '@subwallet/extension-base/services/keyring-service'; import SettingService from '@subwallet/extension-base/services/setting-service/SettingService'; import { WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { MetadataDef } from '@subwallet/extension-inject/types'; import { BehaviorSubject } from 'rxjs'; @@ -54,7 +55,7 @@ export default class RequestService { } getAddressList (value = false): Record { - const addressList = Object.keys(this.keyringService.accounts); + const addressList = Object.keys(this.keyringService.context.pairs); return addressList.reduce((addressList, v) => ({ ...addressList, [v]: value }), {}); } diff --git a/packages/extension-base/src/services/request-service/types.ts b/packages/extension-base/src/services/request-service/types.ts index 73a068744b..12048fb5d9 100644 --- a/packages/extension-base/src/services/request-service/types.ts +++ b/packages/extension-base/src/services/request-service/types.ts @@ -1,7 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-base authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountAuthType, AccountJson, RequestSign, Resolver, ResponseSigning } from '@subwallet/extension-base/background/types'; +import { AccountAuthType, RequestSign, Resolver, ResponseSigning } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { MetadataDef } from '@subwallet/extension-inject/types'; export interface SignRequest extends Resolver { diff --git a/packages/extension-base/src/services/transaction-service/index.ts b/packages/extension-base/src/services/transaction-service/index.ts index 6bf792b8c1..a73e720f3f 100644 --- a/packages/extension-base/src/services/transaction-service/index.ts +++ b/packages/extension-base/src/services/transaction-service/index.ts @@ -4,7 +4,6 @@ import { EvmProviderError } from '@subwallet/extension-base/background/errors/EvmProviderError'; import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError'; import { AmountData, BasicTxErrorType, ChainType, EvmProviderErrorType, EvmSendTransactionRequest, ExtrinsicStatus, ExtrinsicType, NotificationType, TransactionAdditionalInfo, TransactionDirection, TransactionHistoryItem } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; import { checkBalanceWithTransactionFee, checkSigningAccountForTransaction, checkSupportForTransaction, estimateFeeForTransaction } from '@subwallet/extension-base/core/logic-validation/transfer'; import KoniState from '@subwallet/extension-base/koni/background/handlers/State'; @@ -20,7 +19,7 @@ import { SWTransaction, SWTransactionInput, SWTransactionResponse, TransactionEm import { getExplorerLink, parseTransactionData } from '@subwallet/extension-base/services/transaction-service/utils'; import { isWalletConnectRequest } from '@subwallet/extension-base/services/wallet-connect-service/helpers'; import { Web3Transaction } from '@subwallet/extension-base/signers/types'; -import { LeavePoolAdditionalData, RequestStakePoolingBonding, RequestYieldStepSubmit, SpecialYieldPoolInfo, YieldPoolType } from '@subwallet/extension-base/types'; +import { AccountJson, LeavePoolAdditionalData, RequestStakePoolingBonding, RequestYieldStepSubmit, SpecialYieldPoolInfo, YieldPoolType } from '@subwallet/extension-base/types'; import { _isRuntimeUpdated, anyNumberToBN, reformatAddress } from '@subwallet/extension-base/utils'; import { mergeTransactionAndSignature } from '@subwallet/extension-base/utils/eth/mergeTransactionAndSignature'; import { isContractAddress, parseContractInput } from '@subwallet/extension-base/utils/eth/parseTransaction'; diff --git a/packages/extension-base/src/stores/AccountGroupStore.ts b/packages/extension-base/src/stores/AccountGroupStore.ts new file mode 100644 index 0000000000..4226157cac --- /dev/null +++ b/packages/extension-base/src/stores/AccountGroupStore.ts @@ -0,0 +1,12 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { EXTENSION_PREFIX } from '@subwallet/extension-base/defaults'; +import SubscribableStore from '@subwallet/extension-base/stores/SubscribableStore'; +import { AccountGroupStoreData } from '@subwallet/extension-base/types'; + +export default class AccountGroupStore extends SubscribableStore { + constructor () { + super(EXTENSION_PREFIX ? `${EXTENSION_PREFIX}pair_modify` : null); + } +} diff --git a/packages/extension-base/src/stores/CurrentAccountStore.ts b/packages/extension-base/src/stores/CurrentAccountStore.ts index 17589bb9f3..8fe05e8643 100644 --- a/packages/extension-base/src/stores/CurrentAccountStore.ts +++ b/packages/extension-base/src/stores/CurrentAccountStore.ts @@ -1,9 +1,9 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { CurrentAccountInfo } from '@subwallet/extension-base/background/KoniTypes'; import { EXTENSION_PREFIX } from '@subwallet/extension-base/defaults'; import SubscribableStore from '@subwallet/extension-base/stores/SubscribableStore'; +import { CurrentAccountInfo } from '@subwallet/extension-base/types'; export default class CurrentAccountStore extends SubscribableStore { constructor () { diff --git a/packages/extension-base/src/stores/ModifyPairStore.ts b/packages/extension-base/src/stores/ModifyPairStore.ts new file mode 100644 index 0000000000..a340641824 --- /dev/null +++ b/packages/extension-base/src/stores/ModifyPairStore.ts @@ -0,0 +1,12 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { EXTENSION_PREFIX } from '@subwallet/extension-base/defaults'; +import SubscribableStore from '@subwallet/extension-base/stores/SubscribableStore'; +import { ModifyPairStoreData } from '@subwallet/extension-base/types'; + +export default class ModifyPairStore extends SubscribableStore { + constructor () { + super(EXTENSION_PREFIX ? `${EXTENSION_PREFIX}group_account` : null); + } +} diff --git a/packages/extension-base/src/types/account/index.ts b/packages/extension-base/src/types/account/index.ts new file mode 100644 index 0000000000..c99a56190a --- /dev/null +++ b/packages/extension-base/src/types/account/index.ts @@ -0,0 +1,4 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export * from './info'; diff --git a/packages/extension-base/src/types/account/info/current.ts b/packages/extension-base/src/types/account/info/current.ts new file mode 100644 index 0000000000..a74e97ff10 --- /dev/null +++ b/packages/extension-base/src/types/account/info/current.ts @@ -0,0 +1,14 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { AccountGroup } from './group'; + +// all Accounts and the address of the current Account +export interface AccountsWithCurrentAddress { + accounts: AccountGroup[]; + currentAddress?: string; +} + +export interface CurrentAccountInfo { + address: string; +} diff --git a/packages/extension-base/src/types/account/info/group.ts b/packages/extension-base/src/types/account/info/group.ts new file mode 100644 index 0000000000..90fef36011 --- /dev/null +++ b/packages/extension-base/src/types/account/info/group.ts @@ -0,0 +1,26 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { AccountJson } from './keyring'; + +export interface AccountGroupData { + id: string; + name: string; +} + +export type AccountGroupStoreData = Record; + +export interface AccountGroup extends AccountGroupData { + accounts: AccountJson[]; +} + +export type AccountGroupMap = Record + +export interface ModifyPairData { + key: string; + applied: boolean; + migrated: boolean; + accountGroupId?: string; +} + +export type ModifyPairStoreData = Record; diff --git a/packages/extension-base/src/types/account/info/index.ts b/packages/extension-base/src/types/account/info/index.ts new file mode 100644 index 0000000000..ee95c76a28 --- /dev/null +++ b/packages/extension-base/src/types/account/info/index.ts @@ -0,0 +1,6 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export * from './current'; +export * from './group'; +export * from './keyring'; diff --git a/packages/extension-base/src/types/account/info/keyring.ts b/packages/extension-base/src/types/account/info/keyring.ts new file mode 100644 index 0000000000..8d74c001ab --- /dev/null +++ b/packages/extension-base/src/types/account/info/keyring.ts @@ -0,0 +1,124 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; +import type { KeyringPair$Meta } from '@subwallet/keyring/types'; +import type { KeypairType } from '@polkadot/util-crypto/types'; + +export interface AbstractAddressJson extends KeyringPair$Meta { + address: string; + type?: KeypairType; + whenCreated?: number; + name?: string; +} + +/** + * @interface AccountExternalData + * @prop {boolean} [isExternal] - Is external account + * @prop {boolean} [isHardware] - Is hardware account + * @prop {boolean} [isReadOnly] - Is readonly account + * @prop {boolean} [isHidden] - Is hidden account + * */ +export interface AccountExternalData { + /** Is external account */ + isExternal?: boolean; + /** Is hardware account */ + isHardware?: boolean; + /** Is readonly account */ + isReadOnly?: boolean; + /** Is hidden account */ + isHidden?: boolean; +} + +/** + * @interface AccountLedgerData + * @prop {boolean} [isGeneric] - Is generic account + * @prop {number} [accountIndex] - Ledger's account index + * @prop {number} [addressOffset] - Ledger's address offset + * @prop {string|null} [genesisHash] - Ledger's genesisHash + * @prop {string|null} [originGenesisHash] - Ledger's originGenesisHash + * @prop {string[]} [availableGenesisHashes] - Ledger's availableGenesisHashes + * */ +export interface AccountLedgerData { + /** Is generic ledger account */ + isGeneric?: boolean; + /** Ledger's account index */ + accountIndex?: number; + /** Ledger's address offset */ + addressOffset?: number; + /** Ledger's genesisHash */ + genesisHash?: string | null; + /** Ledger's originGenesisHash */ + originGenesisHash?: string | null; + /** Ledger's availableGenesisHashes */ + availableGenesisHashes?: string[]; +} + +/** + * @interface AccountInjectData + * @prop {boolean} [isInjected] - Is injected account + * @prop {string} [source] - Account's source + * */ +export interface AccountInjectData { + /** Is injected account */ + isInjected?: boolean; + /** Account's source */ + source?: string; +} + +/** + * @interface AccountDeriveData + * @prop {string} [parentAddress] - Parent's address + * @prop {string} [suri] - Derivate path + * */ +export interface AccountDeriveData { + /** Parent's address */ + parentAddress?: string; + /** Derivate path */ + suri?: string; +} + +/** + * Represents the actions associated with an account. + * @interface AccountActionData + * @prop {string[]} accountActions - A list of account-specific actions. These could be actions like 'derive', 'export', etc., that are applicable to the account. + * @prop {ExtrinsicType[]} transactionActions - A list of transaction types that the account can initiate. This is dependent on the blockchain's supported extrinsic types, such as 'transfer', 'bond', etc. + */ +export interface AccountActionData { + accountActions: string[]; + transactionActions: ExtrinsicType[]; +} + +/** + * @interface AccountJson + * @extends AbstractAddressJson + * @extends AccountLedgerData + * @extends AccountInjectData + * @extends AccountDeriveData + * @prop {boolean} [isExternal] - Is external account + * @prop {boolean} [isHidden] - Is hidden account + * @prop {boolean} [isInjected] - Is injected account + * @prop {boolean} [isGeneric] - Is generic account + * @prop {boolean} [isMasterAccount] - Is master account - account has seed + * @prop {boolean} [isMasterPassword] - Account has migrated with wallet password + * @prop {boolean} [isReadOnly] - Is readonly account + * @prop {boolean} [isSubWallet] - Import from SubWallet + * @prop {boolean} [pendingMigrate] - Pending migrate password + * @prop {string} [source] - Account's source + * @prop {string} [suri] - Derivate path + * */ +export interface AccountJson extends AbstractAddressJson, AccountExternalData, AccountLedgerData, AccountInjectData, AccountDeriveData, AccountActionData { + /** Is master account - account has seed */ + isMasterAccount?: boolean; + /** Account has migrated with wallet password */ + isMasterPassword?: boolean; + /** Import from SubWallet */ + isSubWallet?: boolean; + /** Pending migrate password */ + pendingMigrate?: boolean; +} + +export interface AddressJson extends AbstractAddressJson { + isRecent?: boolean; + recentChainSlugs?: string[]; +} diff --git a/packages/extension-base/src/types/index.ts b/packages/extension-base/src/types/index.ts index 7ba49ba379..85a3bb3c3a 100644 --- a/packages/extension-base/src/types/index.ts +++ b/packages/extension-base/src/types/index.ts @@ -12,6 +12,7 @@ export interface Message extends MessageEvent { } } +export * from './account'; export * from './balance'; export * from './buy'; export * from './campaigns'; diff --git a/packages/extension-base/src/utils/account.ts b/packages/extension-base/src/utils/account.ts index 9ce347edd8..003414e388 100644 --- a/packages/extension-base/src/utils/account.ts +++ b/packages/extension-base/src/utils/account.ts @@ -1,9 +1,10 @@ // Copyright 2019-2022 @subwallet/extension-base authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AddressJson } from '@subwallet/extension-base/background/types'; +import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; +import { AccountJson, AddressJson } from '@subwallet/extension-base/types'; import { reformatAddress } from '@subwallet/extension-base/utils/index'; -import { SubjectInfo } from '@subwallet/ui-keyring/observable/types'; +import { SingleAddress, SubjectInfo } from '@subwallet/ui-keyring/observable/types'; import { decodeAddress, encodeAddress, isAddress, isEthereumAddress } from '@polkadot/util-crypto'; @@ -26,3 +27,18 @@ export function quickFormatAddressToCompare (address?: string) { export const convertSubjectInfoToAddresses = (subjectInfo: SubjectInfo): AddressJson[] => { return Object.values(subjectInfo).map((info): AddressJson => ({ address: info.json.address, type: info.type, ...info.json.meta })); }; + +export const transformAccount = ({ json: { address, meta }, type }: SingleAddress): AccountJson => { + const accountActions: string[] = []; + const transactionActions: ExtrinsicType[] = []; + + return { + address, + ...meta, + type, + accountActions, + transactionActions + }; +}; + +export const transformAccounts = (accounts: SubjectInfo): AccountJson[] => Object.values(accounts).map(transformAccount); diff --git a/packages/extension-base/src/utils/auth.ts b/packages/extension-base/src/utils/auth.ts new file mode 100644 index 0000000000..2f421264fd --- /dev/null +++ b/packages/extension-base/src/utils/auth.ts @@ -0,0 +1,16 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { AccountAuthType } from '@subwallet/extension-base/background/types'; + +import { isEthereumAddress } from '@polkadot/util-crypto'; + +export const isAddressValidWithAuthType = (address: string, accountAuthType?: AccountAuthType): boolean => { + if (accountAuthType === 'substrate') { + return !isEthereumAddress(address); + } else if (accountAuthType === 'evm') { + return isEthereumAddress(address); + } + + return true; +}; diff --git a/packages/extension-base/src/utils/index.ts b/packages/extension-base/src/utils/index.ts index 1705fbaf6d..3d39d9f897 100644 --- a/packages/extension-base/src/utils/index.ts +++ b/packages/extension-base/src/utils/index.ts @@ -2,9 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 import { CrowdloanParaState, NetworkJson } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountAuthType, AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountAuthType } from '@subwallet/extension-base/background/types'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; import { getRandomIpfsGateway, SUBWALLET_IPFS } from '@subwallet/extension-base/koni/api/nft/config'; +import { AccountJson } from '@subwallet/extension-base/types'; import { t } from 'i18next'; import { assert, BN, hexToU8a, isHex } from '@polkadot/util'; @@ -425,6 +426,7 @@ export function wait (milliseconds: number) { export * from './account'; export * from './array'; export * from './asset'; +export * from './auth'; export * from './environment'; export * from './eth'; export * from './fetchEvmChainInfo'; diff --git a/packages/extension-koni-ui/src/Popup/BuyTokens.tsx b/packages/extension-koni-ui/src/Popup/BuyTokens.tsx index c21440f08b..2b633998b5 100644 --- a/packages/extension-koni-ui/src/Popup/BuyTokens.tsx +++ b/packages/extension-koni-ui/src/Popup/BuyTokens.tsx @@ -1,7 +1,8 @@ // Copyright 2019-2022 @polkadot/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson, Resolver } from '@subwallet/extension-base/background/types'; +import { Resolver } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { detectTranslate, isAccountAll } from '@subwallet/extension-base/utils'; import { baseServiceItems, Layout, PageWrapper, ServiceItem } from '@subwallet/extension-koni-ui/components'; import { AccountSelector } from '@subwallet/extension-koni-ui/components/Field/AccountSelector'; diff --git a/packages/extension-koni-ui/src/Popup/Confirmations/index.tsx b/packages/extension-koni-ui/src/Popup/Confirmations/index.tsx index c0abfdfe4c..2a6b00da27 100644 --- a/packages/extension-koni-ui/src/Popup/Confirmations/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Confirmations/index.tsx @@ -2,8 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 import { ConfirmationDefinitions, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson, AuthorizeRequest, MetadataRequest, SigningRequest } from '@subwallet/extension-base/background/types'; +import { AuthorizeRequest, MetadataRequest, SigningRequest } from '@subwallet/extension-base/background/types'; import { WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { detectTranslate } from '@subwallet/extension-base/utils'; import { AlertModal } from '@subwallet/extension-koni-ui/components'; import { isProductionMode, NEED_SIGN_CONFIRMATION } from '@subwallet/extension-koni-ui/constants'; diff --git a/packages/extension-koni-ui/src/Popup/Confirmations/parts/Detail/Evm/Transaction.tsx b/packages/extension-koni-ui/src/Popup/Confirmations/parts/Detail/Evm/Transaction.tsx index f5c12bc6ff..9c3456e933 100644 --- a/packages/extension-koni-ui/src/Popup/Confirmations/parts/Detail/Evm/Transaction.tsx +++ b/packages/extension-koni-ui/src/Popup/Confirmations/parts/Detail/Evm/Transaction.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { EvmSendTransactionRequest, EvmTransactionArg } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import MetaInfo from '@subwallet/extension-koni-ui/components/MetaInfo/MetaInfo'; import useGetAccountByAddress from '@subwallet/extension-koni-ui/hooks/account/useGetAccountByAddress'; import useGetChainInfoByChainId from '@subwallet/extension-koni-ui/hooks/chain/useGetChainInfoByChainId'; diff --git a/packages/extension-koni-ui/src/Popup/Confirmations/parts/Detail/Substrate/Extrinsic.tsx b/packages/extension-koni-ui/src/Popup/Confirmations/parts/Detail/Substrate/Extrinsic.tsx index 881d64d6f4..0830de0758 100644 --- a/packages/extension-koni-ui/src/Popup/Confirmations/parts/Detail/Substrate/Extrinsic.tsx +++ b/packages/extension-koni-ui/src/Popup/Confirmations/parts/Detail/Substrate/Extrinsic.tsx @@ -5,7 +5,7 @@ import type { Chain } from '@subwallet/extension-chains/types'; import type { Call, ExtrinsicEra, ExtrinsicPayload } from '@polkadot/types/interfaces'; import type { AnyJson, SignerPayloadJSON } from '@polkadot/types/types'; -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import MetaInfo from '@subwallet/extension-koni-ui/components/MetaInfo/MetaInfo'; import useGetChainInfoByGenesisHash from '@subwallet/extension-koni-ui/hooks/chain/useGetChainInfoByGenesisHash'; import useMetadata from '@subwallet/extension-koni-ui/hooks/transaction/confirmation/useMetadata'; diff --git a/packages/extension-koni-ui/src/Popup/Confirmations/parts/Sign/Substrate.tsx b/packages/extension-koni-ui/src/Popup/Confirmations/parts/Sign/Substrate.tsx index 85dfdf9d2e..4038e4c6f7 100644 --- a/packages/extension-koni-ui/src/Popup/Confirmations/parts/Sign/Substrate.tsx +++ b/packages/extension-koni-ui/src/Popup/Confirmations/parts/Sign/Substrate.tsx @@ -2,7 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 import { ExtrinsicType, NotificationType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson, RequestSign } from '@subwallet/extension-base/background/types'; +import { RequestSign } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { _isRuntimeUpdated, detectTranslate } from '@subwallet/extension-base/utils'; import { AlertBox, AlertModal } from '@subwallet/extension-koni-ui/components'; import { CONFIRMATION_QR_MODAL, NotNeedMigrationGens, SUBSTRATE_GENERIC_KEY } from '@subwallet/extension-koni-ui/constants'; diff --git a/packages/extension-koni-ui/src/Popup/Confirmations/variants/AuthorizeConfirmation.tsx b/packages/extension-koni-ui/src/Popup/Confirmations/variants/AuthorizeConfirmation.tsx index e34d55ae1e..6f13b71451 100644 --- a/packages/extension-koni-ui/src/Popup/Confirmations/variants/AuthorizeConfirmation.tsx +++ b/packages/extension-koni-ui/src/Popup/Confirmations/variants/AuthorizeConfirmation.tsx @@ -1,8 +1,9 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountAuthType, AccountJson, AuthorizeRequest } from '@subwallet/extension-base/background/types'; +import { AccountAuthType, AuthorizeRequest } from '@subwallet/extension-base/background/types'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; +import { AccountJson } from '@subwallet/extension-base/types'; import { AccountItemWithName, ConfirmationGeneralInfo } from '@subwallet/extension-koni-ui/components'; import { DEFAULT_ACCOUNT_TYPES, EVM_ACCOUNT_TYPE, SUBSTRATE_ACCOUNT_TYPE } from '@subwallet/extension-koni-ui/constants'; import { useSetSelectedAccountTypes } from '@subwallet/extension-koni-ui/hooks'; diff --git a/packages/extension-koni-ui/src/Popup/Confirmations/variants/NotSupportConfirmation.tsx b/packages/extension-koni-ui/src/Popup/Confirmations/variants/NotSupportConfirmation.tsx index d13dcb4d75..329fa50c6a 100644 --- a/packages/extension-koni-ui/src/Popup/Confirmations/variants/NotSupportConfirmation.tsx +++ b/packages/extension-koni-ui/src/Popup/Confirmations/variants/NotSupportConfirmation.tsx @@ -2,7 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 import { ConfirmationResult } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson, ConfirmationRequestBase } from '@subwallet/extension-base/background/types'; +import { ConfirmationRequestBase } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { detectTranslate } from '@subwallet/extension-base/utils'; import { AccountItemWithName, ConfirmationGeneralInfo } from '@subwallet/extension-koni-ui/components'; import { NEED_SIGN_CONFIRMATION } from '@subwallet/extension-koni-ui/constants'; diff --git a/packages/extension-koni-ui/src/Popup/Home/History/index.tsx b/packages/extension-koni-ui/src/Popup/Home/History/index.tsx index 30644b3634..fb356a18e2 100644 --- a/packages/extension-koni-ui/src/Popup/Home/History/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Home/History/index.tsx @@ -3,9 +3,9 @@ import { _ChainInfo } from '@subwallet/chain-list/types'; import { ExtrinsicStatus, ExtrinsicType, TransactionDirection, TransactionHistoryItem } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { YIELD_EXTRINSIC_TYPES } from '@subwallet/extension-base/koni/api/yield/helper/utils'; import { _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { AccountJson } from '@subwallet/extension-base/types'; import { quickFormatAddressToCompare } from '@subwallet/extension-base/utils'; import { AccountSelector, BasicInputEvent, ChainSelector, EmptyList, FilterModal, HistoryItem, Layout, PageWrapper } from '@subwallet/extension-koni-ui/components'; import { DEFAULT_SESSION_VALUE, HISTORY_DETAIL_MODAL, LATEST_SESSION, REMIND_BACKUP_SEED_PHRASE_MODAL } from '@subwallet/extension-koni-ui/constants'; diff --git a/packages/extension-koni-ui/src/Popup/Keyring/ApplyMasterPassword/Done.tsx b/packages/extension-koni-ui/src/Popup/Keyring/ApplyMasterPassword/Done.tsx index 6ee723c6d4..005fa33519 100644 --- a/packages/extension-koni-ui/src/Popup/Keyring/ApplyMasterPassword/Done.tsx +++ b/packages/extension-koni-ui/src/Popup/Keyring/ApplyMasterPassword/Done.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { detectTranslate } from '@subwallet/extension-base/utils'; import AccountItemWithName from '@subwallet/extension-koni-ui/components/Account/Item/AccountItemWithName'; import { ThemeProps } from '@subwallet/extension-koni-ui/types'; diff --git a/packages/extension-koni-ui/src/Popup/Keyring/ApplyMasterPassword/index.tsx b/packages/extension-koni-ui/src/Popup/Keyring/ApplyMasterPassword/index.tsx index 16131f7e78..fe9c77ef40 100644 --- a/packages/extension-koni-ui/src/Popup/Keyring/ApplyMasterPassword/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Keyring/ApplyMasterPassword/index.tsx @@ -1,8 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; +import { AccountJson } from '@subwallet/extension-base/types'; import { CloseIcon, Layout, PageWrapper } from '@subwallet/extension-koni-ui/components'; import { useDefaultNavigate, useDeleteAccount, useNotification } from '@subwallet/extension-koni-ui/hooks'; import useUnlockChecker from '@subwallet/extension-koni-ui/hooks/common/useUnlockChecker'; diff --git a/packages/extension-koni-ui/src/Popup/Settings/AddressBook/index.tsx b/packages/extension-koni-ui/src/Popup/Settings/AddressBook/index.tsx index 40a94297e6..bc863ead4e 100644 --- a/packages/extension-koni-ui/src/Popup/Settings/AddressBook/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Settings/AddressBook/index.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AddressJson } from '@subwallet/extension-base/background/types'; +import { AddressJson } from '@subwallet/extension-base/types'; import { AccountItemBase, AccountItemWithName, AddContactModal, BackIcon, EditContactModal, FilterModal, GeneralEmptyList, Layout, PageWrapper } from '@subwallet/extension-koni-ui/components'; import { ADD_ADDRESS_BOOK_MODAL, EDIT_ADDRESS_BOOK_MODAL } from '@subwallet/extension-koni-ui/constants'; import { useFilterModal, useFormatAddress, useSelector } from '@subwallet/extension-koni-ui/hooks'; diff --git a/packages/extension-koni-ui/src/Popup/Settings/Security/ManageWebsiteAccess/Detail.tsx b/packages/extension-koni-ui/src/Popup/Settings/Security/ManageWebsiteAccess/Detail.tsx index dc5a771a7f..1b865151fe 100644 --- a/packages/extension-koni-ui/src/Popup/Settings/Security/ManageWebsiteAccess/Detail.tsx +++ b/packages/extension-koni-ui/src/Popup/Settings/Security/ManageWebsiteAccess/Detail.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { AuthUrlInfo } from '@subwallet/extension-base/background/handlers/State'; -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { AccountItemWithName, EmptyList, Layout, PageWrapper } from '@subwallet/extension-koni-ui/components'; import { ActionItemType, ActionModal } from '@subwallet/extension-koni-ui/components/Modal/ActionModal'; import useDefaultNavigate from '@subwallet/extension-koni-ui/hooks/router/useDefaultNavigate'; diff --git a/packages/extension-koni-ui/src/Popup/Transaction/helper/earning/base.ts b/packages/extension-koni-ui/src/Popup/Transaction/helper/earning/base.ts index d59c7c6450..0651e6df3d 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/helper/earning/base.ts +++ b/packages/extension-koni-ui/src/Popup/Transaction/helper/earning/base.ts @@ -2,9 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 import { _ChainInfo } from '@subwallet/chain-list/types'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { _getSubstrateGenesisHash, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; -import { YieldPoolType } from '@subwallet/extension-base/types'; +import { AccountJson, YieldPoolType } from '@subwallet/extension-base/types'; import { isAccountAll } from '@subwallet/extension-base/utils'; import { ALL_KEY } from '@subwallet/extension-koni-ui/constants'; diff --git a/packages/extension-koni-ui/src/Popup/Transaction/helper/staking/base.ts b/packages/extension-koni-ui/src/Popup/Transaction/helper/staking/base.ts index b848b83c6b..3fda40000b 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/helper/staking/base.ts +++ b/packages/extension-koni-ui/src/Popup/Transaction/helper/staking/base.ts @@ -3,8 +3,8 @@ import { _ChainInfo } from '@subwallet/chain-list/types'; import { StakingType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { _getSubstrateGenesisHash, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { AccountJson } from '@subwallet/extension-base/types'; import { ALL_KEY } from '@subwallet/extension-koni-ui/constants/common'; import { isAccountAll } from '@subwallet/extension-koni-ui/utils'; diff --git a/packages/extension-koni-ui/src/Popup/Transaction/variants/CancelUnstake.tsx b/packages/extension-koni-ui/src/Popup/Transaction/variants/CancelUnstake.tsx index 47159501c3..54bfb2d5f7 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/variants/CancelUnstake.tsx +++ b/packages/extension-koni-ui/src/Popup/Transaction/variants/CancelUnstake.tsx @@ -3,8 +3,7 @@ import { _ChainInfo } from '@subwallet/chain-list/types'; import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; -import { YieldPoolType, YieldPositionInfo } from '@subwallet/extension-base/types'; +import { AccountJson, YieldPoolType, YieldPositionInfo } from '@subwallet/extension-base/types'; import { isSameAddress } from '@subwallet/extension-base/utils'; import { AccountSelector, CancelUnstakeSelector, HiddenInput } from '@subwallet/extension-koni-ui/components'; import { useHandleSubmitTransaction, useInitValidateTransaction, usePreCheckAction, useRestoreTransaction, useSelector, useTransactionContext, useWatchTransaction, useYieldPositionDetail } from '@subwallet/extension-koni-ui/hooks'; diff --git a/packages/extension-koni-ui/src/Popup/Transaction/variants/ClaimReward.tsx b/packages/extension-koni-ui/src/Popup/Transaction/variants/ClaimReward.tsx index 678f78feef..c68ba3429b 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/variants/ClaimReward.tsx +++ b/packages/extension-koni-ui/src/Popup/Transaction/variants/ClaimReward.tsx @@ -3,10 +3,9 @@ import { _ChainInfo } from '@subwallet/chain-list/types'; import { AmountData, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { _getSubstrateGenesisHash, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; import { _STAKING_CHAIN_GROUP } from '@subwallet/extension-base/services/earning-service/constants'; -import { EarningRewardItem, YieldPoolType, YieldPositionInfo } from '@subwallet/extension-base/types'; +import { AccountJson, EarningRewardItem, YieldPoolType, YieldPositionInfo } from '@subwallet/extension-base/types'; import { isSameAddress } from '@subwallet/extension-base/utils'; import { AccountSelector, HiddenInput, MetaInfo } from '@subwallet/extension-koni-ui/components'; import { BN_ZERO } from '@subwallet/extension-koni-ui/constants'; diff --git a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx index a6f9ba98a3..5a022af6b2 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx +++ b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx @@ -3,11 +3,11 @@ import { _AssetRef, _AssetType, _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet/chain-list/types'; import { AssetSetting, ExtrinsicType, NotificationType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { _getXcmUnstableWarning, _isXcmTransferUnstable } from '@subwallet/extension-base/core/substrate/xcm-parser'; import { getSnowBridgeGatewayContract } from '@subwallet/extension-base/koni/api/contract-handler/utils'; import { _getAssetDecimals, _getContractAddressOfToken, _getOriginChainOfAsset, _getTokenMinAmount, _isAssetFungibleToken, _isChainEvmCompatible, _isMantaZkAsset, _isNativeToken, _isTokenTransferredByEvm } from '@subwallet/extension-base/services/chain-service/utils'; import { SWTransactionResponse } from '@subwallet/extension-base/services/transaction-service/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { CommonStepType } from '@subwallet/extension-base/types/service-base'; import { detectTranslate, isSameAddress } from '@subwallet/extension-base/utils'; import { AccountSelector, AddressInput, AlertBox, AlertModal, AmountInput, ChainSelector, HiddenInput, TokenItemType, TokenSelector } from '@subwallet/extension-koni-ui/components'; diff --git a/packages/extension-koni-ui/src/Popup/Transaction/variants/Unbond.tsx b/packages/extension-koni-ui/src/Popup/Transaction/variants/Unbond.tsx index 486d5d13d1..91c6ed0074 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/variants/Unbond.tsx +++ b/packages/extension-koni-ui/src/Popup/Transaction/variants/Unbond.tsx @@ -3,10 +3,9 @@ import { _ChainInfo } from '@subwallet/chain-list/types'; import { AmountData, ExtrinsicType, NominationInfo } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { getValidatorLabel } from '@subwallet/extension-base/koni/api/staking/bonding/utils'; import { isActionFromValidator } from '@subwallet/extension-base/services/earning-service/utils'; -import { RequestYieldLeave, YieldPoolType, YieldPositionInfo } from '@subwallet/extension-base/types'; +import { AccountJson, RequestYieldLeave, YieldPoolType, YieldPositionInfo } from '@subwallet/extension-base/types'; import { AccountSelector, AlertBox, AmountInput, HiddenInput, InstructionItem, NominationSelector } from '@subwallet/extension-koni-ui/components'; import { BN_ZERO, UNSTAKE_ALERT_DATA } from '@subwallet/extension-koni-ui/constants'; import { useHandleSubmitTransaction, useInitValidateTransaction, usePreCheckAction, useRestoreTransaction, useSelector, useTransactionContext, useWatchTransaction, useYieldPositionDetail } from '@subwallet/extension-koni-ui/hooks'; diff --git a/packages/extension-koni-ui/src/Popup/Transaction/variants/Withdraw.tsx b/packages/extension-koni-ui/src/Popup/Transaction/variants/Withdraw.tsx index 924337b78a..34b2e53afc 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/variants/Withdraw.tsx +++ b/packages/extension-koni-ui/src/Popup/Transaction/variants/Withdraw.tsx @@ -3,10 +3,9 @@ import { _ChainInfo } from '@subwallet/chain-list/types'; import { AmountData, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { _STAKING_CHAIN_GROUP } from '@subwallet/extension-base/services/earning-service/constants'; import { getAstarWithdrawable } from '@subwallet/extension-base/services/earning-service/handlers/native-staking/astar'; -import { RequestYieldWithdrawal, UnstakingInfo, UnstakingStatus, YieldPoolType, YieldPositionInfo } from '@subwallet/extension-base/types'; +import { AccountJson, RequestYieldWithdrawal, UnstakingInfo, UnstakingStatus, YieldPoolType, YieldPositionInfo } from '@subwallet/extension-base/types'; import { isSameAddress } from '@subwallet/extension-base/utils'; import { AccountSelector, HiddenInput, MetaInfo } from '@subwallet/extension-koni-ui/components'; import { useGetChainAssetInfo, useHandleSubmitTransaction, useInitValidateTransaction, usePreCheckAction, useRestoreTransaction, useSelector, useTransactionContext, useWatchTransaction, useYieldPositionDetail } from '@subwallet/extension-koni-ui/hooks'; diff --git a/packages/extension-koni-ui/src/Popup/WalletConnect/ConnectionDetail.tsx b/packages/extension-koni-ui/src/Popup/WalletConnect/ConnectionDetail.tsx index c47bed23e1..b1778abe98 100644 --- a/packages/extension-koni-ui/src/Popup/WalletConnect/ConnectionDetail.tsx +++ b/packages/extension-koni-ui/src/Popup/WalletConnect/ConnectionDetail.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AbstractAddressJson, AccountJson } from '@subwallet/extension-base/background/types'; +import { AbstractAddressJson, AccountJson } from '@subwallet/extension-base/types'; import { stripUrl } from '@subwallet/extension-base/utils'; import { AccountItemWithName, EmptyList, GeneralEmptyList, Layout, MetaInfo, PageWrapper, WCNetworkAvatarGroup } from '@subwallet/extension-koni-ui/components'; import { DataContext } from '@subwallet/extension-koni-ui/contexts/DataContext'; diff --git a/packages/extension-koni-ui/src/components/Account/Info/AccountBriefInfo.tsx b/packages/extension-koni-ui/src/components/Account/Info/AccountBriefInfo.tsx index 6a1ddd9665..8d83eb82da 100644 --- a/packages/extension-koni-ui/src/components/Account/Info/AccountBriefInfo.tsx +++ b/packages/extension-koni-ui/src/components/Account/Info/AccountBriefInfo.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import AvatarGroup from '@subwallet/extension-koni-ui/components/Account/Info/AvatarGroup'; import useChainInfo from '@subwallet/extension-koni-ui/hooks/chain/useChainInfo'; import useTranslation from '@subwallet/extension-koni-ui/hooks/common/useTranslation'; diff --git a/packages/extension-koni-ui/src/components/Account/Item/AccountItemWithName.tsx b/packages/extension-koni-ui/src/components/Account/Item/AccountItemWithName.tsx index 12e2b026fb..f2c8f566b3 100644 --- a/packages/extension-koni-ui/src/components/Account/Item/AccountItemWithName.tsx +++ b/packages/extension-koni-ui/src/components/Account/Item/AccountItemWithName.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AbstractAddressJson } from '@subwallet/extension-base/background/types'; +import { AbstractAddressJson } from '@subwallet/extension-base/types'; import AvatarGroup from '@subwallet/extension-koni-ui/components/Account/Info/AvatarGroup'; import AccountItemBase, { AccountItemBaseProps } from '@subwallet/extension-koni-ui/components/Account/Item/AccountItemBase'; import { isAccountAll, toShort } from '@subwallet/extension-koni-ui/utils'; diff --git a/packages/extension-koni-ui/src/components/Field/AccountSelector.tsx b/packages/extension-koni-ui/src/components/Field/AccountSelector.tsx index a2d686b642..988f277054 100644 --- a/packages/extension-koni-ui/src/components/Field/AccountSelector.tsx +++ b/packages/extension-koni-ui/src/components/Field/AccountSelector.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { isAccountAll } from '@subwallet/extension-base/utils'; import { BasicInputWrapper } from '@subwallet/extension-koni-ui/components/Field/Base'; import { useFormatAddress, useSelectModalInputHelper, useSelector, useTranslation } from '@subwallet/extension-koni-ui/hooks'; diff --git a/packages/extension-koni-ui/src/components/Field/AddressInput.tsx b/packages/extension-koni-ui/src/components/Field/AddressInput.tsx index 2e97ec8e9c..9df3c1e045 100644 --- a/packages/extension-koni-ui/src/components/Field/AddressInput.tsx +++ b/packages/extension-koni-ui/src/components/Field/AddressInput.tsx @@ -1,8 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AbstractAddressJson } from '@subwallet/extension-base/background/types'; import { CHAINS_SUPPORTED_DOMAIN, isAzeroDomain } from '@subwallet/extension-base/koni/api/dotsama/domain'; +import { AbstractAddressJson } from '@subwallet/extension-base/types'; import { reformatAddress } from '@subwallet/extension-base/utils'; import { useForwardInputRef, useOpenQrScanner, useSelector, useTranslation } from '@subwallet/extension-koni-ui/hooks'; import { resolveAddressToDomain, resolveDomainToAddress, saveRecentAccount } from '@subwallet/extension-koni-ui/messaging'; diff --git a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/ExportAllSelector.tsx b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/ExportAllSelector.tsx index 5d3cea4baf..6c00c373a1 100644 --- a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/ExportAllSelector.tsx +++ b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/ExportAllSelector.tsx @@ -1,8 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; +import { AccountJson } from '@subwallet/extension-base/types'; import { AccountExportPasswordModal, AccountItemWithName, GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; import { BasicInputWrapper } from '@subwallet/extension-koni-ui/components/Field/Base'; import ExportAllSelectItem from '@subwallet/extension-koni-ui/components/Layout/parts/SelectAccount/ExportAllSelectItem'; diff --git a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/index.tsx b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/index.tsx index 753460eaed..867ef67c79 100644 --- a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/index.tsx +++ b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/index.tsx @@ -1,7 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson, CurrentAccountInfo } from '@subwallet/extension-base/background/types'; +import { CurrentAccountInfo } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import ExportAllSelector from '@subwallet/extension-koni-ui/components/Layout/parts/SelectAccount/ExportAllSelector'; import { SimpleQrModal } from '@subwallet/extension-koni-ui/components/Modal'; import { DISCONNECT_EXTENSION_MODAL, SELECT_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants'; diff --git a/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx b/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx index 28f79403af..af580e8897 100644 --- a/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @polkadot/extension-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { canDerive } from '@subwallet/extension-base/utils'; import AccountItemWithName from '@subwallet/extension-koni-ui/components/Account/Item/AccountItemWithName'; import BackIcon from '@subwallet/extension-koni-ui/components/Icon/BackIcon'; diff --git a/packages/extension-koni-ui/src/components/Modal/AccountSelectorModal.tsx b/packages/extension-koni-ui/src/components/Modal/AccountSelectorModal.tsx index d8a3df78da..3c8ed0930a 100644 --- a/packages/extension-koni-ui/src/components/Modal/AccountSelectorModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/AccountSelectorModal.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import AccountItemWithName from '@subwallet/extension-koni-ui/components/Account/Item/AccountItemWithName'; import useTranslation from '@subwallet/extension-koni-ui/hooks/common/useTranslation'; import { ThemeProps } from '@subwallet/extension-koni-ui/types'; diff --git a/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx b/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx index 0921251dd1..2d9997dc31 100644 --- a/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AbstractAddressJson, AccountJson } from '@subwallet/extension-base/background/types'; +import { AbstractAddressJson, AccountJson } from '@subwallet/extension-base/types'; import { BackIcon } from '@subwallet/extension-koni-ui/components'; import { useFilterModal, useFormatAddress, useGetChainInfoByGenesisHash, useSelector } from '@subwallet/extension-koni-ui/hooks'; import { ThemeProps } from '@subwallet/extension-koni-ui/types'; diff --git a/packages/extension-koni-ui/src/components/Modal/AddressBook/EditContactModal.tsx b/packages/extension-koni-ui/src/components/Modal/AddressBook/EditContactModal.tsx index 9c8522a916..e79d57d7e8 100644 --- a/packages/extension-koni-ui/src/components/Modal/AddressBook/EditContactModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/AddressBook/EditContactModal.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AddressJson } from '@subwallet/extension-base/background/types'; +import { AddressJson } from '@subwallet/extension-base/types'; import { Avatar } from '@subwallet/extension-koni-ui/components'; import { DELETE_ADDRESS_BOOK_MODAL, EDIT_ADDRESS_BOOK_MODAL } from '@subwallet/extension-koni-ui/constants'; import { useCopy, useNotification, useSelector } from '@subwallet/extension-koni-ui/hooks'; diff --git a/packages/extension-koni-ui/src/components/WalletConnect/Account/WCAccountInput.tsx b/packages/extension-koni-ui/src/components/WalletConnect/Account/WCAccountInput.tsx index 138d6f4901..aa21a42d84 100644 --- a/packages/extension-koni-ui/src/components/WalletConnect/Account/WCAccountInput.tsx +++ b/packages/extension-koni-ui/src/components/WalletConnect/Account/WCAccountInput.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { isSameAddress } from '@subwallet/extension-base/utils'; import { useTranslation } from '@subwallet/extension-koni-ui/hooks'; import { ThemeProps } from '@subwallet/extension-koni-ui/types'; diff --git a/packages/extension-koni-ui/src/components/WalletConnect/Account/WCAccountSelect.tsx b/packages/extension-koni-ui/src/components/WalletConnect/Account/WCAccountSelect.tsx index 76752c69d2..72f63111c3 100644 --- a/packages/extension-koni-ui/src/components/WalletConnect/Account/WCAccountSelect.tsx +++ b/packages/extension-koni-ui/src/components/WalletConnect/Account/WCAccountSelect.tsx @@ -1,8 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; +import { AccountJson } from '@subwallet/extension-base/types'; import { isSameAddress } from '@subwallet/extension-base/utils'; import { AccountItemWithName, AlertBox } from '@subwallet/extension-koni-ui/components'; import { useTranslation } from '@subwallet/extension-koni-ui/hooks'; diff --git a/packages/extension-koni-ui/src/components/WalletConnect/ConnectionItem.tsx b/packages/extension-koni-ui/src/components/WalletConnect/ConnectionItem.tsx index 5003ccab09..b99a2bacc0 100644 --- a/packages/extension-koni-ui/src/components/WalletConnect/ConnectionItem.tsx +++ b/packages/extension-koni-ui/src/components/WalletConnect/ConnectionItem.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AbstractAddressJson } from '@subwallet/extension-base/background/types'; +import { AbstractAddressJson } from '@subwallet/extension-base/types'; import { stripUrl } from '@subwallet/extension-base/utils'; import { useSelector } from '@subwallet/extension-koni-ui/hooks'; import { ThemeProps } from '@subwallet/extension-koni-ui/types'; diff --git a/packages/extension-koni-ui/src/hooks/account/useFormatAddress.ts b/packages/extension-koni-ui/src/hooks/account/useFormatAddress.ts index 9582cd5932..b48caedabd 100644 --- a/packages/extension-koni-ui/src/hooks/account/useFormatAddress.ts +++ b/packages/extension-koni-ui/src/hooks/account/useFormatAddress.ts @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AbstractAddressJson } from '@subwallet/extension-base/background/types'; +import { AbstractAddressJson } from '@subwallet/extension-base/types'; import { findNetworkJsonByGenesisHash, reformatAddress } from '@subwallet/extension-koni-ui/utils'; import { useCallback } from 'react'; diff --git a/packages/extension-koni-ui/src/hooks/account/useGetAccountByAddress.ts b/packages/extension-koni-ui/src/hooks/account/useGetAccountByAddress.ts index c6fe263465..eb0de299df 100644 --- a/packages/extension-koni-ui/src/hooks/account/useGetAccountByAddress.ts +++ b/packages/extension-koni-ui/src/hooks/account/useGetAccountByAddress.ts @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { RootState } from '@subwallet/extension-koni-ui/stores'; import { findAccountByAddress } from '@subwallet/extension-koni-ui/utils/account/account'; import { useMemo } from 'react'; diff --git a/packages/extension-koni-ui/src/hooks/account/useIsMantaPayAvailable.ts b/packages/extension-koni-ui/src/hooks/account/useIsMantaPayAvailable.ts index f0e4f64df6..487004d44a 100644 --- a/packages/extension-koni-ui/src/hooks/account/useIsMantaPayAvailable.ts +++ b/packages/extension-koni-ui/src/hooks/account/useIsMantaPayAvailable.ts @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { RootState } from '@subwallet/extension-koni-ui/stores'; import { useMemo } from 'react'; import { useSelector } from 'react-redux'; diff --git a/packages/extension-koni-ui/src/hooks/account/usePreCheckAction.ts b/packages/extension-koni-ui/src/hooks/account/usePreCheckAction.ts index e658f3cbaa..eab2382d76 100644 --- a/packages/extension-koni-ui/src/hooks/account/usePreCheckAction.ts +++ b/packages/extension-koni-ui/src/hooks/account/usePreCheckAction.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { detectTranslate } from '@subwallet/extension-base/utils'; import { ALL_STAKING_ACTIONS, isLedgerCapable, isProductionMode, ledgerIncompatible } from '@subwallet/extension-koni-ui/constants'; import { BLOCK_ACTION_LEDGER_NETWORKS, PredefinedLedgerNetwork } from '@subwallet/extension-koni-ui/constants/ledger'; diff --git a/packages/extension-koni-ui/src/hooks/common/useGetChainSlugsByCurrentAccount.ts b/packages/extension-koni-ui/src/hooks/common/useGetChainSlugsByCurrentAccount.ts index 9bad0e8642..202f0d9b26 100644 --- a/packages/extension-koni-ui/src/hooks/common/useGetChainSlugsByCurrentAccount.ts +++ b/packages/extension-koni-ui/src/hooks/common/useGetChainSlugsByCurrentAccount.ts @@ -4,8 +4,8 @@ import type { KeypairType } from '@polkadot/util-crypto/types'; import { _ChainInfo, _ChainStatus } from '@subwallet/chain-list/types'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { AccountJson } from '@subwallet/extension-base/types'; import { RootState } from '@subwallet/extension-koni-ui/stores'; import { AccountType } from '@subwallet/extension-koni-ui/types'; import { isAccountAll } from '@subwallet/extension-koni-ui/utils'; diff --git a/packages/extension-koni-ui/src/hooks/history/useHistorySelection.tsx b/packages/extension-koni-ui/src/hooks/history/useHistorySelection.tsx index 57e7b3f52b..a93543fec1 100644 --- a/packages/extension-koni-ui/src/hooks/history/useHistorySelection.tsx +++ b/packages/extension-koni-ui/src/hooks/history/useHistorySelection.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { useSelector } from '@subwallet/extension-koni-ui/hooks'; import { isAccountAll } from '@subwallet/extension-koni-ui/utils'; import { useEffect, useRef, useState } from 'react'; diff --git a/packages/extension-koni-ui/src/hooks/screen/common/useGetAccountInfoByAddress.ts b/packages/extension-koni-ui/src/hooks/screen/common/useGetAccountInfoByAddress.ts index 9eb75518e5..7452c9cef3 100644 --- a/packages/extension-koni-ui/src/hooks/screen/common/useGetAccountInfoByAddress.ts +++ b/packages/extension-koni-ui/src/hooks/screen/common/useGetAccountInfoByAddress.ts @@ -1,7 +1,7 @@ // Copyright 2019-2022 @polkadot/extension-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { reformatAddress } from '@subwallet/extension-base/utils'; import { RootState } from '@subwallet/extension-koni-ui/stores'; import { useSelector } from 'react-redux'; diff --git a/packages/extension-koni-ui/src/hooks/screen/home/useGetChainSlugsByAccountType.ts b/packages/extension-koni-ui/src/hooks/screen/home/useGetChainSlugsByAccountType.ts index 5f4f2ffc4b..aead762bd8 100644 --- a/packages/extension-koni-ui/src/hooks/screen/home/useGetChainSlugsByAccountType.ts +++ b/packages/extension-koni-ui/src/hooks/screen/home/useGetChainSlugsByAccountType.ts @@ -2,8 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 import { _ChainInfo } from '@subwallet/chain-list/types'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { AccountJson } from '@subwallet/extension-base/types'; import { RootState } from '@subwallet/extension-koni-ui/stores'; import { AccountType } from '@subwallet/extension-koni-ui/types'; import { isAccountAll } from '@subwallet/extension-koni-ui/utils'; diff --git a/packages/extension-koni-ui/src/hooks/screen/home/useReceiveQR.ts b/packages/extension-koni-ui/src/hooks/screen/home/useReceiveQR.ts index 009eb56d46..44c3e48d0b 100644 --- a/packages/extension-koni-ui/src/hooks/screen/home/useReceiveQR.ts +++ b/packages/extension-koni-ui/src/hooks/screen/home/useReceiveQR.ts @@ -3,9 +3,9 @@ import { _ChainAsset } from '@subwallet/chain-list/types'; import { MantaPayConfig } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { _MANTA_ZK_CHAIN_GROUP, _ZK_ASSET_PREFIX } from '@subwallet/extension-base/services/chain-service/constants'; import { _getMultiChainAsset, _isAssetFungibleToken, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { AccountJson } from '@subwallet/extension-base/types'; import { AccountSelectorModalId } from '@subwallet/extension-koni-ui/components/Modal/AccountSelectorModal'; import { RECEIVE_QR_MODAL, RECEIVE_TOKEN_SELECTOR_MODAL } from '@subwallet/extension-koni-ui/constants/modal'; import { useChainAssets } from '@subwallet/extension-koni-ui/hooks/assets'; diff --git a/packages/extension-koni-ui/src/hooks/screen/nft/useGetNftByAccount.ts b/packages/extension-koni-ui/src/hooks/screen/nft/useGetNftByAccount.ts index 21b1a91264..0468e03882 100644 --- a/packages/extension-koni-ui/src/hooks/screen/nft/useGetNftByAccount.ts +++ b/packages/extension-koni-ui/src/hooks/screen/nft/useGetNftByAccount.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { NftCollection, NftItem } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { isAccountAll } from '@subwallet/extension-base/utils'; import { RootState } from '@subwallet/extension-koni-ui/stores'; import reformatAddress from '@subwallet/extension-koni-ui/utils/account/reformatAddress'; diff --git a/packages/extension-koni-ui/src/hooks/wallet-connect/useSelectWalletConnectAccount.ts b/packages/extension-koni-ui/src/hooks/wallet-connect/useSelectWalletConnectAccount.ts index 314d346b98..02a877a808 100644 --- a/packages/extension-koni-ui/src/hooks/wallet-connect/useSelectWalletConnectAccount.ts +++ b/packages/extension-koni-ui/src/hooks/wallet-connect/useSelectWalletConnectAccount.ts @@ -1,9 +1,10 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountAuthType, AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountAuthType } from '@subwallet/extension-base/background/types'; import { WALLET_CONNECT_EIP155_NAMESPACE, WALLET_CONNECT_SUPPORT_NAMESPACES } from '@subwallet/extension-base/services/wallet-connect-service/constants'; import { isProposalExpired, isSupportWalletConnectChain, isSupportWalletConnectNamespace } from '@subwallet/extension-base/services/wallet-connect-service/helpers'; +import { AccountJson } from '@subwallet/extension-base/types'; import { isSameAddress, uniqueStringArray } from '@subwallet/extension-base/utils'; import { WalletConnectChainInfo } from '@subwallet/extension-koni-ui/types'; import { chainsToWalletConnectChainInfos, isAccountAll, reformatAddress } from '@subwallet/extension-koni-ui/utils'; diff --git a/packages/extension-koni-ui/src/messaging/accounts/create.ts b/packages/extension-koni-ui/src/messaging/accounts/create.ts index 7b417d941e..1af73d4d36 100644 --- a/packages/extension-koni-ui/src/messaging/accounts/create.ts +++ b/packages/extension-koni-ui/src/messaging/accounts/create.ts @@ -34,10 +34,6 @@ export async function createAccountWithSecret (request: RequestAccountCreateWith } // Qr, read-only -export async function createAccountExternal (name: string, address: string, genesisHash: string): Promise { - return sendMessage('pri(accounts.create.external)', { address, genesisHash, name }); -} - export async function createAccountExternalV2 (request: RequestAccountCreateExternalV2): Promise { return sendMessage('pri(accounts.create.externalV2)', request); } diff --git a/packages/extension-koni-ui/src/messaging/accounts/currentAccount.ts b/packages/extension-koni-ui/src/messaging/accounts/currentAccount.ts index 80126db928..58fd6f3879 100644 --- a/packages/extension-koni-ui/src/messaging/accounts/currentAccount.ts +++ b/packages/extension-koni-ui/src/messaging/accounts/currentAccount.ts @@ -1,8 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { CurrentAccountInfo } from '@subwallet/extension-base/background/KoniTypes'; import { RequestCurrentAccountAddress } from '@subwallet/extension-base/background/types'; +import { CurrentAccountInfo } from '@subwallet/extension-base/types'; import { sendMessage } from '@subwallet/extension-koni-ui/messaging/base'; export async function saveCurrentAccountAddress (data: RequestCurrentAccountAddress): Promise { diff --git a/packages/extension-koni-ui/src/messaging/accounts/legacy.ts b/packages/extension-koni-ui/src/messaging/accounts/legacy.ts index d96ed57b1c..de9e4e1fb4 100644 --- a/packages/extension-koni-ui/src/messaging/accounts/legacy.ts +++ b/packages/extension-koni-ui/src/messaging/accounts/legacy.ts @@ -1,8 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountsWithCurrentAddress, OptionInputAddress } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { OptionInputAddress } from '@subwallet/extension-base/background/KoniTypes'; +import { AccountJson, AccountsWithCurrentAddress } from '@subwallet/extension-base/types'; import { sendMessage } from '../base'; diff --git a/packages/extension-koni-ui/src/stores/base/AccountState.ts b/packages/extension-koni-ui/src/stores/base/AccountState.ts index 373c41de62..f27a2397ea 100644 --- a/packages/extension-koni-ui/src/stores/base/AccountState.ts +++ b/packages/extension-koni-ui/src/stores/base/AccountState.ts @@ -3,7 +3,8 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { AddressBookInfo, KeyringState } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson, AccountsContext } from '@subwallet/extension-base/background/types'; +import { AccountsContext } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { AccountState, ReduxStatus } from '@subwallet/extension-koni-ui/stores/types'; import { isAccountAll } from '@subwallet/extension-koni-ui/utils'; diff --git a/packages/extension-koni-ui/src/stores/types.ts b/packages/extension-koni-ui/src/stores/types.ts index 083d55a5cf..feb36322d7 100644 --- a/packages/extension-koni-ui/src/stores/types.ts +++ b/packages/extension-koni-ui/src/stores/types.ts @@ -4,11 +4,11 @@ import { _AssetRef, _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet/chain-list/types'; import { AuthUrlInfo } from '@subwallet/extension-base/background/handlers/State'; import { AddressBookState, AllLogoMap, AssetSetting, CampaignBanner, ChainStakingMetadata, ConfirmationDefinitions, ConfirmationsQueue, ConfirmationType, CrowdloanItem, KeyringState, LanguageType, MantaPayConfig, NftCollection, NftItem, NominatorMetadata, PriceJson, StakingItem, StakingRewardItem, TransactionHistoryItem, UiSettings, ValidatorInfo } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson, AccountsContext, AuthorizeRequest, MetadataRequest, SigningRequest } from '@subwallet/extension-base/background/types'; +import { AccountsContext, AuthorizeRequest, MetadataRequest, SigningRequest } from '@subwallet/extension-base/background/types'; import { _ChainApiStatus, _ChainState } from '@subwallet/extension-base/services/chain-service/types'; import { SWTransactionResult } from '@subwallet/extension-base/services/transaction-service/types'; import { WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; -import { BalanceMap, BuyServiceInfo, BuyTokenInfo, EarningRewardHistoryItem, EarningRewardItem, NominationPoolInfo, YieldPoolInfo, YieldPoolTarget, YieldPositionInfo } from '@subwallet/extension-base/types'; +import { AccountJson, BalanceMap, BuyServiceInfo, BuyTokenInfo, EarningRewardHistoryItem, EarningRewardItem, NominationPoolInfo, YieldPoolInfo, YieldPoolTarget, YieldPositionInfo } from '@subwallet/extension-base/types'; import { SwapPair } from '@subwallet/extension-base/types/swap'; import { MissionInfo } from '@subwallet/extension-koni-ui/types'; import { SessionTypes } from '@walletconnect/types'; diff --git a/packages/extension-koni-ui/src/stores/utils/index.ts b/packages/extension-koni-ui/src/stores/utils/index.ts index 4e2c7701a7..c9a4ab7537 100644 --- a/packages/extension-koni-ui/src/stores/utils/index.ts +++ b/packages/extension-koni-ui/src/stores/utils/index.ts @@ -3,12 +3,12 @@ import { _AssetRef, _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet/chain-list/types'; import { AuthUrls } from '@subwallet/extension-base/background/handlers/State'; -import { AccountsWithCurrentAddress, AddressBookInfo, AssetSetting, CampaignBanner, ChainStakingMetadata, ConfirmationsQueue, CrowdloanJson, KeyringState, MantaPayConfig, MantaPaySyncState, NftCollection, NftJson, NominatorMetadata, PriceJson, ShowCampaignPopupRequest, StakingJson, StakingRewardJson, TransactionHistoryItem, UiSettings } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson, AccountsContext, AuthorizeRequest, ConfirmationRequestBase, MetadataRequest, SigningRequest } from '@subwallet/extension-base/background/types'; +import { AddressBookInfo, AssetSetting, CampaignBanner, ChainStakingMetadata, ConfirmationsQueue, CrowdloanJson, KeyringState, MantaPayConfig, MantaPaySyncState, NftCollection, NftJson, NominatorMetadata, PriceJson, ShowCampaignPopupRequest, StakingJson, StakingRewardJson, TransactionHistoryItem, UiSettings } from '@subwallet/extension-base/background/KoniTypes'; +import { AccountsContext, AuthorizeRequest, ConfirmationRequestBase, MetadataRequest, SigningRequest } from '@subwallet/extension-base/background/types'; import { _ChainApiStatus, _ChainState } from '@subwallet/extension-base/services/chain-service/types'; import { SWTransactionResult } from '@subwallet/extension-base/services/transaction-service/types'; import { WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; -import { BalanceJson, BuyServiceInfo, BuyTokenInfo, EarningRewardHistoryItem, EarningRewardJson, YieldPoolInfo, YieldPositionInfo } from '@subwallet/extension-base/types'; +import { AccountJson, AccountsWithCurrentAddress, BalanceJson, BuyServiceInfo, BuyTokenInfo, EarningRewardHistoryItem, EarningRewardJson, YieldPoolInfo, YieldPositionInfo } from '@subwallet/extension-base/types'; import { SwapPair } from '@subwallet/extension-base/types/swap'; import { addLazy, canDerive, fetchStaticData } from '@subwallet/extension-base/utils'; import { lazySubscribeMessage } from '@subwallet/extension-koni-ui/messaging'; diff --git a/packages/extension-koni-ui/src/types/index.ts b/packages/extension-koni-ui/src/types/index.ts index a12549280f..96b693a6b2 100644 --- a/packages/extension-koni-ui/src/types/index.ts +++ b/packages/extension-koni-ui/src/types/index.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { NotificationType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { ButtonSchema } from '@subwallet/react-ui/es/button/button'; import { Icon as _PhosphorIcon, IconProps } from 'phosphor-react'; import React from 'react'; diff --git a/packages/extension-koni-ui/src/utils/account/account.ts b/packages/extension-koni-ui/src/utils/account/account.ts index e6905cb4ce..a6fd5f4700 100644 --- a/packages/extension-koni-ui/src/utils/account/account.ts +++ b/packages/extension-koni-ui/src/utils/account/account.ts @@ -3,9 +3,10 @@ import { _ChainInfo } from '@subwallet/chain-list/types'; import { NetworkJson } from '@subwallet/extension-base/background/KoniTypes'; -import { AbstractAddressJson, AccountAuthType, AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountAuthType } from '@subwallet/extension-base/background/types'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; import { _getChainSubstrateAddressPrefix, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { AbstractAddressJson, AccountJson } from '@subwallet/extension-base/types'; import { isAccountAll, uniqueStringArray } from '@subwallet/extension-base/utils'; import { DEFAULT_ACCOUNT_TYPES, EVM_ACCOUNT_TYPE, SUBSTRATE_ACCOUNT_TYPE } from '@subwallet/extension-koni-ui/constants'; import { MODE_CAN_SIGN } from '@subwallet/extension-koni-ui/constants/signing'; diff --git a/packages/extension-koni-ui/src/utils/account/buildHierarchy.ts b/packages/extension-koni-ui/src/utils/account/buildHierarchy.ts index 54e8be39f5..2a5402931a 100644 --- a/packages/extension-koni-ui/src/utils/account/buildHierarchy.ts +++ b/packages/extension-koni-ui/src/utils/account/buildHierarchy.ts @@ -1,8 +1,9 @@ // Copyright 2019-2022 @polkadot/extension-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import type { AccountJson, AccountWithChildren } from '@subwallet/extension-base/background/types'; +import type { AccountWithChildren } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { isAccountAll } from '@subwallet/extension-koni-ui/utils/account/accountAll'; import getNetworkMap from '../chain/getNetworkMap'; diff --git a/packages/extension-koni-ui/src/utils/index.ts b/packages/extension-koni-ui/src/utils/index.ts index 64b101517e..e0a991ba7a 100644 --- a/packages/extension-koni-ui/src/utils/index.ts +++ b/packages/extension-koni-ui/src/utils/index.ts @@ -4,9 +4,10 @@ import { ChainLogoMap } from '@subwallet/chain-list'; import { _ChainInfo } from '@subwallet/chain-list/types'; import { NetworkJson } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson, AccountWithChildren } from '@subwallet/extension-base/background/types'; +import { AccountWithChildren } from '@subwallet/extension-base/background/types'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; import { _getChainSubstrateAddressPrefix, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { AccountJson } from '@subwallet/extension-base/types'; import { Recoded } from '@subwallet/extension-koni-ui/types'; import { isAccountAll } from '@subwallet/extension-koni-ui/utils/account/accountAll'; import reformatAddress from '@subwallet/extension-koni-ui/utils/account/reformatAddress'; diff --git a/packages/extension-koni-ui/src/utils/scanner/decoders.ts b/packages/extension-koni-ui/src/utils/scanner/decoders.ts index 415177c4dd..95088eb93e 100644 --- a/packages/extension-koni-ui/src/utils/scanner/decoders.ts +++ b/packages/extension-koni-ui/src/utils/scanner/decoders.ts @@ -2,9 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 import { _ChainInfo } from '@subwallet/chain-list/types'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { _ChainState } from '@subwallet/extension-base/services/chain-service/types'; import { _isChainEnabled, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { AccountJson } from '@subwallet/extension-base/types'; import { createTransactionFromRLP } from '@subwallet/extension-base/utils/eth'; import { EthereumParsedData, ParsedData, SubstrateCompletedParsedData, SubstrateMultiParsedData } from '@subwallet/extension-koni-ui/types/scanner'; import { findAccountByAddress } from '@subwallet/extension-koni-ui/utils/account/account'; diff --git a/packages/extension-koni-ui/src/utils/walletConnect/index.ts b/packages/extension-koni-ui/src/utils/walletConnect/index.ts index e99cca7dd8..4c27212abd 100644 --- a/packages/extension-koni-ui/src/utils/walletConnect/index.ts +++ b/packages/extension-koni-ui/src/utils/walletConnect/index.ts @@ -2,9 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 import { _ChainInfo } from '@subwallet/chain-list/types'; -import { AbstractAddressJson, AccountJson } from '@subwallet/extension-base/background/types'; import { findChainInfoByChainId, findChainInfoByHalfGenesisHash } from '@subwallet/extension-base/services/chain-service/utils'; import { WALLET_CONNECT_EIP155_NAMESPACE, WALLET_CONNECT_POLKADOT_NAMESPACE } from '@subwallet/extension-base/services/wallet-connect-service/constants'; +import { AbstractAddressJson, AccountJson } from '@subwallet/extension-base/types'; import { WalletConnectChainInfo } from '@subwallet/extension-koni-ui/types'; import { SessionTypes } from '@walletconnect/types'; diff --git a/packages/extension-web-ui/src/Popup/BuyTokens.tsx b/packages/extension-web-ui/src/Popup/BuyTokens.tsx index 8f7ab98b53..4938baa080 100644 --- a/packages/extension-web-ui/src/Popup/BuyTokens.tsx +++ b/packages/extension-web-ui/src/Popup/BuyTokens.tsx @@ -1,7 +1,8 @@ // Copyright 2019-2022 @polkadot/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson, Resolver } from '@subwallet/extension-base/background/types'; +import { Resolver } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { detectTranslate, isAccountAll } from '@subwallet/extension-base/utils'; import { BaseModal, baseServiceItems, Layout, PageWrapper, ServiceItem } from '@subwallet/extension-web-ui/components'; import { AccountSelector } from '@subwallet/extension-web-ui/components/Field/AccountSelector'; diff --git a/packages/extension-web-ui/src/Popup/Confirmations/index.tsx b/packages/extension-web-ui/src/Popup/Confirmations/index.tsx index 1f1243bd22..4a9c09960d 100644 --- a/packages/extension-web-ui/src/Popup/Confirmations/index.tsx +++ b/packages/extension-web-ui/src/Popup/Confirmations/index.tsx @@ -2,8 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 import { ConfirmationDefinitions, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson, AuthorizeRequest, MetadataRequest, SigningRequest } from '@subwallet/extension-base/background/types'; +import { AuthorizeRequest, MetadataRequest, SigningRequest } from '@subwallet/extension-base/background/types'; import { WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { detectTranslate } from '@subwallet/extension-base/utils'; import { AlertModal } from '@subwallet/extension-web-ui/components'; import { isProductionMode, NEED_SIGN_CONFIRMATION } from '@subwallet/extension-web-ui/constants'; diff --git a/packages/extension-web-ui/src/Popup/Confirmations/parts/Detail/Evm/Transaction.tsx b/packages/extension-web-ui/src/Popup/Confirmations/parts/Detail/Evm/Transaction.tsx index ecb8917c49..2e55545cbd 100644 --- a/packages/extension-web-ui/src/Popup/Confirmations/parts/Detail/Evm/Transaction.tsx +++ b/packages/extension-web-ui/src/Popup/Confirmations/parts/Detail/Evm/Transaction.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { EvmSendTransactionRequest, EvmTransactionArg } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import MetaInfo from '@subwallet/extension-web-ui/components/MetaInfo/MetaInfo'; import useGetAccountByAddress from '@subwallet/extension-web-ui/hooks/account/useGetAccountByAddress'; import useGetChainInfoByChainId from '@subwallet/extension-web-ui/hooks/chain/useGetChainInfoByChainId'; diff --git a/packages/extension-web-ui/src/Popup/Confirmations/parts/Detail/Substrate/Extrinsic.tsx b/packages/extension-web-ui/src/Popup/Confirmations/parts/Detail/Substrate/Extrinsic.tsx index 16ed0aaed2..7ba2251114 100644 --- a/packages/extension-web-ui/src/Popup/Confirmations/parts/Detail/Substrate/Extrinsic.tsx +++ b/packages/extension-web-ui/src/Popup/Confirmations/parts/Detail/Substrate/Extrinsic.tsx @@ -5,7 +5,7 @@ import type { Chain } from '@subwallet/extension-chains/types'; import type { Call, ExtrinsicEra, ExtrinsicPayload } from '@polkadot/types/interfaces'; import type { AnyJson, SignerPayloadJSON } from '@polkadot/types/types'; -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import MetaInfo from '@subwallet/extension-web-ui/components/MetaInfo/MetaInfo'; import useGetChainInfoByGenesisHash from '@subwallet/extension-web-ui/hooks/chain/useGetChainInfoByGenesisHash'; import useMetadata from '@subwallet/extension-web-ui/hooks/transaction/confirmation/useMetadata'; diff --git a/packages/extension-web-ui/src/Popup/Confirmations/parts/Sign/Substrate.tsx b/packages/extension-web-ui/src/Popup/Confirmations/parts/Sign/Substrate.tsx index a25a4dfd0c..309d1424ee 100644 --- a/packages/extension-web-ui/src/Popup/Confirmations/parts/Sign/Substrate.tsx +++ b/packages/extension-web-ui/src/Popup/Confirmations/parts/Sign/Substrate.tsx @@ -2,7 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson, RequestSign } from '@subwallet/extension-base/background/types'; +import { RequestSign } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { _isRuntimeUpdated, detectTranslate } from '@subwallet/extension-base/utils'; import { AlertBox } from '@subwallet/extension-web-ui/components'; import { CONFIRMATION_QR_MODAL, NotNeedMigrationGens, SUBSTRATE_GENERIC_KEY } from '@subwallet/extension-web-ui/constants'; diff --git a/packages/extension-web-ui/src/Popup/Confirmations/variants/AuthorizeConfirmation.tsx b/packages/extension-web-ui/src/Popup/Confirmations/variants/AuthorizeConfirmation.tsx index 20107bfdbf..6de16678ff 100644 --- a/packages/extension-web-ui/src/Popup/Confirmations/variants/AuthorizeConfirmation.tsx +++ b/packages/extension-web-ui/src/Popup/Confirmations/variants/AuthorizeConfirmation.tsx @@ -1,8 +1,9 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountAuthType, AccountJson, AuthorizeRequest } from '@subwallet/extension-base/background/types'; +import { AccountAuthType, AuthorizeRequest } from '@subwallet/extension-base/background/types'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; +import { AccountJson } from '@subwallet/extension-base/types'; import { AccountItemWithName, ConfirmationGeneralInfo } from '@subwallet/extension-web-ui/components'; import { DEFAULT_ACCOUNT_TYPES, EVM_ACCOUNT_TYPE, SUBSTRATE_ACCOUNT_TYPE } from '@subwallet/extension-web-ui/constants'; import { useSetSelectedAccountTypes } from '@subwallet/extension-web-ui/hooks'; diff --git a/packages/extension-web-ui/src/Popup/Confirmations/variants/NotSupportConfirmation.tsx b/packages/extension-web-ui/src/Popup/Confirmations/variants/NotSupportConfirmation.tsx index e28268190b..2d0772977e 100644 --- a/packages/extension-web-ui/src/Popup/Confirmations/variants/NotSupportConfirmation.tsx +++ b/packages/extension-web-ui/src/Popup/Confirmations/variants/NotSupportConfirmation.tsx @@ -2,7 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 import { ConfirmationResult } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson, ConfirmationRequestBase } from '@subwallet/extension-base/background/types'; +import { ConfirmationRequestBase } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { detectTranslate } from '@subwallet/extension-base/utils'; import { AccountItemWithName, ConfirmationGeneralInfo } from '@subwallet/extension-web-ui/components'; import { NEED_SIGN_CONFIRMATION } from '@subwallet/extension-web-ui/constants'; diff --git a/packages/extension-web-ui/src/Popup/CreateDone.tsx b/packages/extension-web-ui/src/Popup/CreateDone.tsx index 22ade51a61..23adf051a8 100644 --- a/packages/extension-web-ui/src/Popup/CreateDone.tsx +++ b/packages/extension-web-ui/src/Popup/CreateDone.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { Layout, SocialButtonGroup } from '@subwallet/extension-web-ui/components'; import { CREATE_RETURN, DEFAULT_ROUTER_PATH } from '@subwallet/extension-web-ui/constants'; import { ScreenContext } from '@subwallet/extension-web-ui/contexts/ScreenContext'; diff --git a/packages/extension-web-ui/src/Popup/Home/Earning/EarningPreview/EarningPreviewOptions.tsx b/packages/extension-web-ui/src/Popup/Home/Earning/EarningPreview/EarningPreviewOptions.tsx index f12743e0b7..a9ef5e9098 100644 --- a/packages/extension-web-ui/src/Popup/Home/Earning/EarningPreview/EarningPreviewOptions.tsx +++ b/packages/extension-web-ui/src/Popup/Home/Earning/EarningPreview/EarningPreviewOptions.tsx @@ -3,10 +3,9 @@ import { _ChainInfo } from '@subwallet/chain-list/types'; import { NotificationType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { _getSubstrateGenesisHash, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; import { isLendingPool, isLiquidPool } from '@subwallet/extension-base/services/earning-service/utils'; -import { NominationPoolInfo, ValidatorInfo, YieldPoolInfo, YieldPoolTarget, YieldPoolType } from '@subwallet/extension-base/types'; +import { AccountJson, NominationPoolInfo, ValidatorInfo, YieldPoolInfo, YieldPoolTarget, YieldPoolType } from '@subwallet/extension-base/types'; import { EarningOptionDesktopItem, EarningOptionItem, EarningValidatorDetailRWModal, EmptyList, FilterModal, Layout, LoadingScreen } from '@subwallet/extension-web-ui/components'; import { ASTAR_PORTAL_URL, CREATE_RETURN, DEFAULT_EARN_PARAMS, DEFAULT_ROUTER_PATH, EARN_TRANSACTION, EVM_ACCOUNT_TYPE, SUBSTRATE_ACCOUNT_TYPE, VALIDATOR_DETAIL_RW_MODAL } from '@subwallet/extension-web-ui/constants'; import { ScreenContext } from '@subwallet/extension-web-ui/contexts/ScreenContext'; diff --git a/packages/extension-web-ui/src/Popup/Home/Earning/EarningPreview/EarningPreviewPools.tsx b/packages/extension-web-ui/src/Popup/Home/Earning/EarningPreview/EarningPreviewPools.tsx index 4f09a69831..b2bc224293 100644 --- a/packages/extension-web-ui/src/Popup/Home/Earning/EarningPreview/EarningPreviewPools.tsx +++ b/packages/extension-web-ui/src/Popup/Home/Earning/EarningPreview/EarningPreviewPools.tsx @@ -2,10 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 import { _ChainInfo } from '@subwallet/chain-list/types'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { _getSubstrateGenesisHash, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; import { isLendingPool, isLiquidPool } from '@subwallet/extension-base/services/earning-service/utils'; -import { YieldPoolInfo, YieldPoolType } from '@subwallet/extension-base/types'; +import { AccountJson, YieldPoolInfo, YieldPoolType } from '@subwallet/extension-base/types'; import { EarningPoolItem, EmptyList, FilterModal, Layout } from '@subwallet/extension-web-ui/components'; import { CREATE_RETURN, DEFAULT_EARN_PARAMS, DEFAULT_ROUTER_PATH, EARN_TRANSACTION, EARNING_INSTRUCTION_MODAL, EVM_ACCOUNT_TYPE, SUBSTRATE_ACCOUNT_TYPE } from '@subwallet/extension-web-ui/constants'; import { ScreenContext } from '@subwallet/extension-web-ui/contexts/ScreenContext'; diff --git a/packages/extension-web-ui/src/Popup/Home/History/index.tsx b/packages/extension-web-ui/src/Popup/Home/History/index.tsx index 5705ab1b53..721fb4878c 100644 --- a/packages/extension-web-ui/src/Popup/Home/History/index.tsx +++ b/packages/extension-web-ui/src/Popup/Home/History/index.tsx @@ -3,9 +3,9 @@ import { _ChainInfo } from '@subwallet/chain-list/types'; import { ExtrinsicStatus, ExtrinsicType, TransactionDirection, TransactionHistoryItem } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { YIELD_EXTRINSIC_TYPES } from '@subwallet/extension-base/koni/api/yield/helper/utils'; import { _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { AccountJson } from '@subwallet/extension-base/types'; import { quickFormatAddressToCompare } from '@subwallet/extension-base/utils'; import { AccountSelector, BasicInputEvent, ChainSelector, FilterModal, HistoryItem, Layout, PageWrapper } from '@subwallet/extension-web-ui/components'; import { FilterTabItemType, FilterTabs } from '@subwallet/extension-web-ui/components/FilterTabs'; diff --git a/packages/extension-web-ui/src/Popup/Keyring/ApplyMasterPassword/Done.tsx b/packages/extension-web-ui/src/Popup/Keyring/ApplyMasterPassword/Done.tsx index d547148d30..dc562f2b89 100644 --- a/packages/extension-web-ui/src/Popup/Keyring/ApplyMasterPassword/Done.tsx +++ b/packages/extension-web-ui/src/Popup/Keyring/ApplyMasterPassword/Done.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { detectTranslate } from '@subwallet/extension-base/utils'; import AccountItemWithName from '@subwallet/extension-web-ui/components/Account/Item/AccountItemWithName'; import { ThemeProps } from '@subwallet/extension-web-ui/types'; diff --git a/packages/extension-web-ui/src/Popup/Keyring/ApplyMasterPassword/index.tsx b/packages/extension-web-ui/src/Popup/Keyring/ApplyMasterPassword/index.tsx index 4fcfa1f2f1..bae26af84b 100644 --- a/packages/extension-web-ui/src/Popup/Keyring/ApplyMasterPassword/index.tsx +++ b/packages/extension-web-ui/src/Popup/Keyring/ApplyMasterPassword/index.tsx @@ -1,8 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; +import { AccountJson } from '@subwallet/extension-base/types'; import { CloseIcon, Layout, PageWrapper } from '@subwallet/extension-web-ui/components'; import { ScreenContext } from '@subwallet/extension-web-ui/contexts/ScreenContext'; import { useDefaultNavigate, useDeleteAccount, useNotification } from '@subwallet/extension-web-ui/hooks'; diff --git a/packages/extension-web-ui/src/Popup/Settings/AddressBook/index.tsx b/packages/extension-web-ui/src/Popup/Settings/AddressBook/index.tsx index 1c38fcfdae..21801321c5 100644 --- a/packages/extension-web-ui/src/Popup/Settings/AddressBook/index.tsx +++ b/packages/extension-web-ui/src/Popup/Settings/AddressBook/index.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AddressJson } from '@subwallet/extension-base/background/types'; +import { AddressJson } from '@subwallet/extension-base/types'; import { AccountItemBase, AccountItemWithName, AddContactModal, BackIcon, EditContactModal, FilterModal, GeneralEmptyList, Layout, PageWrapper } from '@subwallet/extension-web-ui/components'; import { ADD_ADDRESS_BOOK_MODAL, EDIT_ADDRESS_BOOK_MODAL } from '@subwallet/extension-web-ui/constants'; import { ScreenContext } from '@subwallet/extension-web-ui/contexts/ScreenContext'; diff --git a/packages/extension-web-ui/src/Popup/Settings/Security/ManageWebsiteAccess/Detail.tsx b/packages/extension-web-ui/src/Popup/Settings/Security/ManageWebsiteAccess/Detail.tsx index 1a19630ce9..4eea62da44 100644 --- a/packages/extension-web-ui/src/Popup/Settings/Security/ManageWebsiteAccess/Detail.tsx +++ b/packages/extension-web-ui/src/Popup/Settings/Security/ManageWebsiteAccess/Detail.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { AuthUrlInfo } from '@subwallet/extension-base/background/handlers/State'; -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { AccountItemWithName, EmptyList, Layout, PageWrapper } from '@subwallet/extension-web-ui/components'; import { ActionItemType, ActionModal } from '@subwallet/extension-web-ui/components/Modal/ActionModal'; import useDefaultNavigate from '@subwallet/extension-web-ui/hooks/router/useDefaultNavigate'; diff --git a/packages/extension-web-ui/src/Popup/Transaction/helper/earning/base.ts b/packages/extension-web-ui/src/Popup/Transaction/helper/earning/base.ts index 301e228f60..3fbf5d3f0b 100644 --- a/packages/extension-web-ui/src/Popup/Transaction/helper/earning/base.ts +++ b/packages/extension-web-ui/src/Popup/Transaction/helper/earning/base.ts @@ -2,9 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 import { _ChainInfo } from '@subwallet/chain-list/types'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { _getSubstrateGenesisHash, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; -import { YieldPoolType } from '@subwallet/extension-base/types'; +import { AccountJson, YieldPoolType } from '@subwallet/extension-base/types'; import { isAccountAll } from '@subwallet/extension-base/utils'; import { ALL_KEY } from '@subwallet/extension-web-ui/constants'; diff --git a/packages/extension-web-ui/src/Popup/Transaction/helper/staking/base.ts b/packages/extension-web-ui/src/Popup/Transaction/helper/staking/base.ts index a440517b70..0f3b915b12 100644 --- a/packages/extension-web-ui/src/Popup/Transaction/helper/staking/base.ts +++ b/packages/extension-web-ui/src/Popup/Transaction/helper/staking/base.ts @@ -3,8 +3,8 @@ import { _ChainInfo } from '@subwallet/chain-list/types'; import { StakingType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { _getSubstrateGenesisHash, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { AccountJson } from '@subwallet/extension-base/types'; import { ALL_KEY } from '@subwallet/extension-web-ui/constants/common'; import { isAccountAll } from '@subwallet/extension-web-ui/utils'; diff --git a/packages/extension-web-ui/src/Popup/Transaction/variants/CancelUnstake.tsx b/packages/extension-web-ui/src/Popup/Transaction/variants/CancelUnstake.tsx index e7650ee52a..09e4e0df68 100644 --- a/packages/extension-web-ui/src/Popup/Transaction/variants/CancelUnstake.tsx +++ b/packages/extension-web-ui/src/Popup/Transaction/variants/CancelUnstake.tsx @@ -3,8 +3,7 @@ import { _ChainInfo } from '@subwallet/chain-list/types'; import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; -import { YieldPoolType, YieldPositionInfo } from '@subwallet/extension-base/types'; +import { AccountJson, YieldPoolType, YieldPositionInfo } from '@subwallet/extension-base/types'; import { isSameAddress } from '@subwallet/extension-base/utils'; import { AccountSelector, CancelUnstakeSelector, HiddenInput } from '@subwallet/extension-web-ui/components'; import { ScreenContext } from '@subwallet/extension-web-ui/contexts/ScreenContext'; diff --git a/packages/extension-web-ui/src/Popup/Transaction/variants/ClaimReward.tsx b/packages/extension-web-ui/src/Popup/Transaction/variants/ClaimReward.tsx index 85d4e13f92..0b126851e8 100644 --- a/packages/extension-web-ui/src/Popup/Transaction/variants/ClaimReward.tsx +++ b/packages/extension-web-ui/src/Popup/Transaction/variants/ClaimReward.tsx @@ -3,10 +3,9 @@ import { _ChainInfo } from '@subwallet/chain-list/types'; import { AmountData, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { _getSubstrateGenesisHash, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; import { _STAKING_CHAIN_GROUP } from '@subwallet/extension-base/services/earning-service/constants'; -import { EarningRewardItem, YieldPoolType, YieldPositionInfo } from '@subwallet/extension-base/types'; +import { AccountJson, EarningRewardItem, YieldPoolType, YieldPositionInfo } from '@subwallet/extension-base/types'; import { isSameAddress } from '@subwallet/extension-base/utils'; import { AccountSelector, HiddenInput, MetaInfo } from '@subwallet/extension-web-ui/components'; import { BN_ZERO } from '@subwallet/extension-web-ui/constants'; diff --git a/packages/extension-web-ui/src/Popup/Transaction/variants/SendFund.tsx b/packages/extension-web-ui/src/Popup/Transaction/variants/SendFund.tsx index b57b5312e6..dc0f6cfae6 100644 --- a/packages/extension-web-ui/src/Popup/Transaction/variants/SendFund.tsx +++ b/packages/extension-web-ui/src/Popup/Transaction/variants/SendFund.tsx @@ -3,11 +3,11 @@ import { _AssetRef, _AssetType, _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet/chain-list/types'; import { AssetSetting, ExtrinsicType, NotificationType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { _getXcmUnstableWarning, _isXcmTransferUnstable } from '@subwallet/extension-base/core/substrate/xcm-parser'; import { getSnowBridgeGatewayContract } from '@subwallet/extension-base/koni/api/contract-handler/utils'; import { _getAssetDecimals, _getContractAddressOfToken, _getOriginChainOfAsset, _getTokenMinAmount, _isAssetFungibleToken, _isChainEvmCompatible, _isMantaZkAsset, _isNativeToken, _isTokenTransferredByEvm } from '@subwallet/extension-base/services/chain-service/utils'; import { SWTransactionResponse } from '@subwallet/extension-base/services/transaction-service/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { CommonStepType } from '@subwallet/extension-base/types/service-base'; import { detectTranslate, isSameAddress } from '@subwallet/extension-base/utils'; import { AlertBox, AlertModal, HiddenInput } from '@subwallet/extension-web-ui/components'; diff --git a/packages/extension-web-ui/src/Popup/Transaction/variants/Unbond.tsx b/packages/extension-web-ui/src/Popup/Transaction/variants/Unbond.tsx index 03eb8fba00..67621abd65 100644 --- a/packages/extension-web-ui/src/Popup/Transaction/variants/Unbond.tsx +++ b/packages/extension-web-ui/src/Popup/Transaction/variants/Unbond.tsx @@ -3,10 +3,9 @@ import { _ChainInfo } from '@subwallet/chain-list/types'; import { AmountData, ExtrinsicType, NominationInfo } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { getValidatorLabel } from '@subwallet/extension-base/koni/api/staking/bonding/utils'; import { isActionFromValidator } from '@subwallet/extension-base/services/earning-service/utils'; -import { RequestYieldLeave, YieldPoolType, YieldPositionInfo } from '@subwallet/extension-base/types'; +import { AccountJson, RequestYieldLeave, YieldPoolType, YieldPositionInfo } from '@subwallet/extension-base/types'; import { AccountSelector, AlertBox, AmountInput, HiddenInput, InstructionItem, NominationSelector } from '@subwallet/extension-web-ui/components'; import { BN_ZERO, UNSTAKE_ALERT_DATA } from '@subwallet/extension-web-ui/constants'; import { useHandleSubmitTransaction, useInitValidateTransaction, usePreCheckAction, useRestoreTransaction, useSelector, useTransactionContext, useWatchTransaction, useYieldPositionDetail } from '@subwallet/extension-web-ui/hooks'; diff --git a/packages/extension-web-ui/src/Popup/Transaction/variants/Withdraw.tsx b/packages/extension-web-ui/src/Popup/Transaction/variants/Withdraw.tsx index cbd7df2a8b..6fd7552f1a 100644 --- a/packages/extension-web-ui/src/Popup/Transaction/variants/Withdraw.tsx +++ b/packages/extension-web-ui/src/Popup/Transaction/variants/Withdraw.tsx @@ -3,10 +3,9 @@ import { _ChainInfo } from '@subwallet/chain-list/types'; import { AmountData, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { _STAKING_CHAIN_GROUP } from '@subwallet/extension-base/services/earning-service/constants'; import { getAstarWithdrawable } from '@subwallet/extension-base/services/earning-service/handlers/native-staking/astar'; -import { RequestYieldWithdrawal, UnstakingInfo, UnstakingStatus, YieldPoolType, YieldPositionInfo } from '@subwallet/extension-base/types'; +import { AccountJson, RequestYieldWithdrawal, UnstakingInfo, UnstakingStatus, YieldPoolType, YieldPositionInfo } from '@subwallet/extension-base/types'; import { isSameAddress } from '@subwallet/extension-base/utils'; import { AccountSelector, HiddenInput, MetaInfo } from '@subwallet/extension-web-ui/components'; import { ScreenContext } from '@subwallet/extension-web-ui/contexts/ScreenContext'; diff --git a/packages/extension-web-ui/src/Popup/WalletConnect/ConnectionDetail.tsx b/packages/extension-web-ui/src/Popup/WalletConnect/ConnectionDetail.tsx index 111ea32106..91d91eeb46 100644 --- a/packages/extension-web-ui/src/Popup/WalletConnect/ConnectionDetail.tsx +++ b/packages/extension-web-ui/src/Popup/WalletConnect/ConnectionDetail.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AbstractAddressJson, AccountJson } from '@subwallet/extension-base/background/types'; +import { AbstractAddressJson, AccountJson } from '@subwallet/extension-base/types'; import { stripUrl } from '@subwallet/extension-base/utils'; import { AccountItemWithName, EmptyList, GeneralEmptyList, Layout, MetaInfo, PageWrapper, WCNetworkAvatarGroup } from '@subwallet/extension-web-ui/components'; import { BaseModal } from '@subwallet/extension-web-ui/components/Modal/BaseModal'; diff --git a/packages/extension-web-ui/src/components/Account/Info/AccountBriefInfo.tsx b/packages/extension-web-ui/src/components/Account/Info/AccountBriefInfo.tsx index 6da1d6a415..c4b560e5c3 100644 --- a/packages/extension-web-ui/src/components/Account/Info/AccountBriefInfo.tsx +++ b/packages/extension-web-ui/src/components/Account/Info/AccountBriefInfo.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { Avatar } from '@subwallet/extension-web-ui/components'; import AvatarGroup from '@subwallet/extension-web-ui/components/Account/Info/AvatarGroup'; import useChainInfo from '@subwallet/extension-web-ui/hooks/chain/useChainInfo'; diff --git a/packages/extension-web-ui/src/components/Account/Item/AccountItemWithName.tsx b/packages/extension-web-ui/src/components/Account/Item/AccountItemWithName.tsx index ab6dde66b8..f2de1895c8 100644 --- a/packages/extension-web-ui/src/components/Account/Item/AccountItemWithName.tsx +++ b/packages/extension-web-ui/src/components/Account/Item/AccountItemWithName.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AbstractAddressJson } from '@subwallet/extension-base/background/types'; +import { AbstractAddressJson } from '@subwallet/extension-base/types'; import AvatarGroup from '@subwallet/extension-web-ui/components/Account/Info/AvatarGroup'; import AccountItemBase, { AccountItemBaseProps } from '@subwallet/extension-web-ui/components/Account/Item/AccountItemBase'; import { isAccountAll, toShort } from '@subwallet/extension-web-ui/utils'; diff --git a/packages/extension-web-ui/src/components/Field/AccountSelector.tsx b/packages/extension-web-ui/src/components/Field/AccountSelector.tsx index a86e92dd8d..25b5377113 100644 --- a/packages/extension-web-ui/src/components/Field/AccountSelector.tsx +++ b/packages/extension-web-ui/src/components/Field/AccountSelector.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { isAccountAll } from '@subwallet/extension-base/utils'; import { BasicInputWrapper } from '@subwallet/extension-web-ui/components/Field/Base'; import { BaseSelectModal } from '@subwallet/extension-web-ui/components/Modal/BaseSelectModal'; diff --git a/packages/extension-web-ui/src/components/Field/AddressInput.tsx b/packages/extension-web-ui/src/components/Field/AddressInput.tsx index ce8f33f45b..dc5ced9861 100644 --- a/packages/extension-web-ui/src/components/Field/AddressInput.tsx +++ b/packages/extension-web-ui/src/components/Field/AddressInput.tsx @@ -1,8 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AbstractAddressJson } from '@subwallet/extension-base/background/types'; import { CHAINS_SUPPORTED_DOMAIN, isAzeroDomain } from '@subwallet/extension-base/koni/api/dotsama/domain'; +import { AbstractAddressJson } from '@subwallet/extension-base/types'; import { reformatAddress } from '@subwallet/extension-base/utils'; import { ScreenContext } from '@subwallet/extension-web-ui/contexts/ScreenContext'; import { useForwardInputRef, useOpenQrScanner, useSelector, useTranslation } from '@subwallet/extension-web-ui/hooks'; diff --git a/packages/extension-web-ui/src/components/Layout/parts/SelectAccount/index.tsx b/packages/extension-web-ui/src/components/Layout/parts/SelectAccount/index.tsx index 398056d35b..e34c4cd5a1 100644 --- a/packages/extension-web-ui/src/components/Layout/parts/SelectAccount/index.tsx +++ b/packages/extension-web-ui/src/components/Layout/parts/SelectAccount/index.tsx @@ -1,7 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson, CurrentAccountInfo } from '@subwallet/extension-base/background/types'; +import { CurrentAccountInfo } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { BaseSelectModal, SimpleQrModal } from '@subwallet/extension-web-ui/components/Modal'; import { DISCONNECT_EXTENSION_MODAL, SELECT_ACCOUNT_MODAL } from '@subwallet/extension-web-ui/constants'; import { useDefaultNavigate, useGetCurrentAuth, useGetCurrentTab, useGoBackSelectAccount, useIsPopup, useTranslation } from '@subwallet/extension-web-ui/hooks'; diff --git a/packages/extension-web-ui/src/components/Modal/Account/DeriveAccountModal.tsx b/packages/extension-web-ui/src/components/Modal/Account/DeriveAccountModal.tsx index f8c8eb79c9..b3dc2a693b 100644 --- a/packages/extension-web-ui/src/components/Modal/Account/DeriveAccountModal.tsx +++ b/packages/extension-web-ui/src/components/Modal/Account/DeriveAccountModal.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @polkadot/extension-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { canDerive } from '@subwallet/extension-base/utils'; import AccountItemWithName from '@subwallet/extension-web-ui/components/Account/Item/AccountItemWithName'; import BackIcon from '@subwallet/extension-web-ui/components/Icon/BackIcon'; diff --git a/packages/extension-web-ui/src/components/Modal/AccountSelectorModal.tsx b/packages/extension-web-ui/src/components/Modal/AccountSelectorModal.tsx index 0698d5888a..bc36e4d7d0 100644 --- a/packages/extension-web-ui/src/components/Modal/AccountSelectorModal.tsx +++ b/packages/extension-web-ui/src/components/Modal/AccountSelectorModal.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import AccountItemWithName from '@subwallet/extension-web-ui/components/Account/Item/AccountItemWithName'; import useTranslation from '@subwallet/extension-web-ui/hooks/common/useTranslation'; import { ThemeProps } from '@subwallet/extension-web-ui/types'; diff --git a/packages/extension-web-ui/src/components/Modal/AddressBook/AddressBookModal.tsx b/packages/extension-web-ui/src/components/Modal/AddressBook/AddressBookModal.tsx index 356c5e4ef9..25380c07a2 100644 --- a/packages/extension-web-ui/src/components/Modal/AddressBook/AddressBookModal.tsx +++ b/packages/extension-web-ui/src/components/Modal/AddressBook/AddressBookModal.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AbstractAddressJson, AccountJson } from '@subwallet/extension-base/background/types'; +import { AbstractAddressJson, AccountJson } from '@subwallet/extension-base/types'; import { BackIcon } from '@subwallet/extension-web-ui/components'; import { BaseModal } from '@subwallet/extension-web-ui/components/Modal/BaseModal'; import { useFilterModal, useFormatAddress, useGetChainInfoByGenesisHash, useSelector } from '@subwallet/extension-web-ui/hooks'; diff --git a/packages/extension-web-ui/src/components/Modal/AddressBook/EditContactModal.tsx b/packages/extension-web-ui/src/components/Modal/AddressBook/EditContactModal.tsx index 19fa1233e4..8c97440f75 100644 --- a/packages/extension-web-ui/src/components/Modal/AddressBook/EditContactModal.tsx +++ b/packages/extension-web-ui/src/components/Modal/AddressBook/EditContactModal.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AddressJson } from '@subwallet/extension-base/background/types'; +import { AddressJson } from '@subwallet/extension-base/types'; import { Avatar } from '@subwallet/extension-web-ui/components'; import { BaseModal } from '@subwallet/extension-web-ui/components/Modal/BaseModal'; import { DELETE_ADDRESS_BOOK_MODAL, EDIT_ADDRESS_BOOK_MODAL } from '@subwallet/extension-web-ui/constants'; diff --git a/packages/extension-web-ui/src/components/WalletConnect/Account/WCAccountInput.tsx b/packages/extension-web-ui/src/components/WalletConnect/Account/WCAccountInput.tsx index 3a38d55c03..226ec96e60 100644 --- a/packages/extension-web-ui/src/components/WalletConnect/Account/WCAccountInput.tsx +++ b/packages/extension-web-ui/src/components/WalletConnect/Account/WCAccountInput.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { isSameAddress } from '@subwallet/extension-base/utils'; import { useTranslation } from '@subwallet/extension-web-ui/hooks'; import { ThemeProps } from '@subwallet/extension-web-ui/types'; diff --git a/packages/extension-web-ui/src/components/WalletConnect/Account/WCAccountSelect.tsx b/packages/extension-web-ui/src/components/WalletConnect/Account/WCAccountSelect.tsx index 163db48d76..7a4122c020 100644 --- a/packages/extension-web-ui/src/components/WalletConnect/Account/WCAccountSelect.tsx +++ b/packages/extension-web-ui/src/components/WalletConnect/Account/WCAccountSelect.tsx @@ -1,8 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; +import { AccountJson } from '@subwallet/extension-base/types'; import { isSameAddress } from '@subwallet/extension-base/utils'; import { AccountItemWithName, AlertBox } from '@subwallet/extension-web-ui/components'; import { BaseModal } from '@subwallet/extension-web-ui/components/Modal/BaseModal'; diff --git a/packages/extension-web-ui/src/components/WalletConnect/ConnectionItem.tsx b/packages/extension-web-ui/src/components/WalletConnect/ConnectionItem.tsx index 2a527919d2..7988b48412 100644 --- a/packages/extension-web-ui/src/components/WalletConnect/ConnectionItem.tsx +++ b/packages/extension-web-ui/src/components/WalletConnect/ConnectionItem.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AbstractAddressJson } from '@subwallet/extension-base/background/types'; +import { AbstractAddressJson } from '@subwallet/extension-base/types'; import { stripUrl } from '@subwallet/extension-base/utils'; import { useSelector } from '@subwallet/extension-web-ui/hooks'; import { ThemeProps } from '@subwallet/extension-web-ui/types'; diff --git a/packages/extension-web-ui/src/hooks/account/useFormatAddress.ts b/packages/extension-web-ui/src/hooks/account/useFormatAddress.ts index 0ce55a3be8..840ab9a765 100644 --- a/packages/extension-web-ui/src/hooks/account/useFormatAddress.ts +++ b/packages/extension-web-ui/src/hooks/account/useFormatAddress.ts @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AbstractAddressJson } from '@subwallet/extension-base/background/types'; +import { AbstractAddressJson } from '@subwallet/extension-base/types'; import { findNetworkJsonByGenesisHash, reformatAddress } from '@subwallet/extension-web-ui/utils'; import { useCallback } from 'react'; diff --git a/packages/extension-web-ui/src/hooks/account/useGetAccountByAddress.ts b/packages/extension-web-ui/src/hooks/account/useGetAccountByAddress.ts index 625148209c..61badaf368 100644 --- a/packages/extension-web-ui/src/hooks/account/useGetAccountByAddress.ts +++ b/packages/extension-web-ui/src/hooks/account/useGetAccountByAddress.ts @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { RootState } from '@subwallet/extension-web-ui/stores'; import { findAccountByAddress } from '@subwallet/extension-web-ui/utils/account/account'; import { useMemo } from 'react'; diff --git a/packages/extension-web-ui/src/hooks/account/useIsMantaPayAvailable.ts b/packages/extension-web-ui/src/hooks/account/useIsMantaPayAvailable.ts index ce1bbd888d..3f73feec56 100644 --- a/packages/extension-web-ui/src/hooks/account/useIsMantaPayAvailable.ts +++ b/packages/extension-web-ui/src/hooks/account/useIsMantaPayAvailable.ts @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { RootState } from '@subwallet/extension-web-ui/stores'; import { useMemo } from 'react'; import { useSelector } from 'react-redux'; diff --git a/packages/extension-web-ui/src/hooks/account/usePreCheckAction.ts b/packages/extension-web-ui/src/hooks/account/usePreCheckAction.ts index e54e7c585b..7c442b5358 100644 --- a/packages/extension-web-ui/src/hooks/account/usePreCheckAction.ts +++ b/packages/extension-web-ui/src/hooks/account/usePreCheckAction.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { detectTranslate } from '@subwallet/extension-base/utils'; import { ALL_STAKING_ACTIONS, isLedgerCapable, isProductionMode, ledgerIncompatible } from '@subwallet/extension-web-ui/constants'; import { BLOCK_ACTION_LEDGER_NETWORKS, PredefinedLedgerNetwork } from '@subwallet/extension-web-ui/constants/ledger'; diff --git a/packages/extension-web-ui/src/hooks/common/useGetChainSlugsByCurrentAccount.ts b/packages/extension-web-ui/src/hooks/common/useGetChainSlugsByCurrentAccount.ts index 74e7968cbc..6327aeef9f 100644 --- a/packages/extension-web-ui/src/hooks/common/useGetChainSlugsByCurrentAccount.ts +++ b/packages/extension-web-ui/src/hooks/common/useGetChainSlugsByCurrentAccount.ts @@ -4,8 +4,8 @@ import type { KeypairType } from '@polkadot/util-crypto/types'; import { _ChainInfo, _ChainStatus } from '@subwallet/chain-list/types'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { AccountJson } from '@subwallet/extension-base/types'; import { RootState } from '@subwallet/extension-web-ui/stores'; import { AccountType } from '@subwallet/extension-web-ui/types'; import { isAccountAll } from '@subwallet/extension-web-ui/utils'; diff --git a/packages/extension-web-ui/src/hooks/history/useHistorySelection.tsx b/packages/extension-web-ui/src/hooks/history/useHistorySelection.tsx index 24727b4d1c..6df43181a2 100644 --- a/packages/extension-web-ui/src/hooks/history/useHistorySelection.tsx +++ b/packages/extension-web-ui/src/hooks/history/useHistorySelection.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { useSelector } from '@subwallet/extension-web-ui/hooks'; import { isAccountAll } from '@subwallet/extension-web-ui/utils'; import { useEffect, useRef, useState } from 'react'; diff --git a/packages/extension-web-ui/src/hooks/screen/common/useGetAccountInfoByAddress.ts b/packages/extension-web-ui/src/hooks/screen/common/useGetAccountInfoByAddress.ts index f566687cda..0cb8861c2a 100644 --- a/packages/extension-web-ui/src/hooks/screen/common/useGetAccountInfoByAddress.ts +++ b/packages/extension-web-ui/src/hooks/screen/common/useGetAccountInfoByAddress.ts @@ -1,7 +1,7 @@ // Copyright 2019-2022 @polkadot/extension-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { reformatAddress } from '@subwallet/extension-base/utils'; import { RootState } from '@subwallet/extension-web-ui/stores'; import { useSelector } from 'react-redux'; diff --git a/packages/extension-web-ui/src/hooks/screen/home/useGetChainSlugsByAccountType.ts b/packages/extension-web-ui/src/hooks/screen/home/useGetChainSlugsByAccountType.ts index 7a406f8c3c..23d4aa1e00 100644 --- a/packages/extension-web-ui/src/hooks/screen/home/useGetChainSlugsByAccountType.ts +++ b/packages/extension-web-ui/src/hooks/screen/home/useGetChainSlugsByAccountType.ts @@ -2,8 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 import { _ChainInfo } from '@subwallet/chain-list/types'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { AccountJson } from '@subwallet/extension-base/types'; import { RootState } from '@subwallet/extension-web-ui/stores'; import { AccountType } from '@subwallet/extension-web-ui/types'; import { isAccountAll } from '@subwallet/extension-web-ui/utils'; diff --git a/packages/extension-web-ui/src/hooks/screen/home/useReceiveQR.ts b/packages/extension-web-ui/src/hooks/screen/home/useReceiveQR.ts index 5cb8e3e621..fbc0a0c32c 100644 --- a/packages/extension-web-ui/src/hooks/screen/home/useReceiveQR.ts +++ b/packages/extension-web-ui/src/hooks/screen/home/useReceiveQR.ts @@ -3,9 +3,9 @@ import { _ChainAsset } from '@subwallet/chain-list/types'; import { MantaPayConfig } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { _MANTA_ZK_CHAIN_GROUP, _ZK_ASSET_PREFIX } from '@subwallet/extension-base/services/chain-service/constants'; import { _getMultiChainAsset, _isAssetFungibleToken, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { AccountJson } from '@subwallet/extension-base/types'; import { AccountSelectorModalId } from '@subwallet/extension-web-ui/components/Modal/AccountSelectorModal'; import { RECEIVE_QR_MODAL, RECEIVE_TOKEN_SELECTOR_MODAL } from '@subwallet/extension-web-ui/constants/modal'; import { useChainAssets } from '@subwallet/extension-web-ui/hooks/assets'; diff --git a/packages/extension-web-ui/src/hooks/screen/nft/useGetNftByAccount.ts b/packages/extension-web-ui/src/hooks/screen/nft/useGetNftByAccount.ts index 55df52b3b5..7949c9eaec 100644 --- a/packages/extension-web-ui/src/hooks/screen/nft/useGetNftByAccount.ts +++ b/packages/extension-web-ui/src/hooks/screen/nft/useGetNftByAccount.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { NftCollection, NftItem } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { isAccountAll } from '@subwallet/extension-base/utils'; import { RootState } from '@subwallet/extension-web-ui/stores'; import reformatAddress from '@subwallet/extension-web-ui/utils/account/reformatAddress'; diff --git a/packages/extension-web-ui/src/hooks/wallet-connect/useSelectWalletConnectAccount.ts b/packages/extension-web-ui/src/hooks/wallet-connect/useSelectWalletConnectAccount.ts index ae89384fe8..6869107410 100644 --- a/packages/extension-web-ui/src/hooks/wallet-connect/useSelectWalletConnectAccount.ts +++ b/packages/extension-web-ui/src/hooks/wallet-connect/useSelectWalletConnectAccount.ts @@ -1,9 +1,10 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountAuthType, AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountAuthType } from '@subwallet/extension-base/background/types'; import { WALLET_CONNECT_EIP155_NAMESPACE, WALLET_CONNECT_SUPPORT_NAMESPACES } from '@subwallet/extension-base/services/wallet-connect-service/constants'; import { isProposalExpired, isSupportWalletConnectChain, isSupportWalletConnectNamespace } from '@subwallet/extension-base/services/wallet-connect-service/helpers'; +import { AccountJson } from '@subwallet/extension-base/types'; import { isSameAddress, uniqueStringArray } from '@subwallet/extension-base/utils'; import { WalletConnectChainInfo } from '@subwallet/extension-web-ui/types'; import { chainsToWalletConnectChainInfos, isAccountAll, reformatAddress } from '@subwallet/extension-web-ui/utils'; diff --git a/packages/extension-web-ui/src/messaging/accounts/create.ts b/packages/extension-web-ui/src/messaging/accounts/create.ts index ec3c87020e..40cff9c9e4 100644 --- a/packages/extension-web-ui/src/messaging/accounts/create.ts +++ b/packages/extension-web-ui/src/messaging/accounts/create.ts @@ -34,10 +34,6 @@ export async function createAccountWithSecret (request: RequestAccountCreateWith } // Qr, read-only -export async function createAccountExternal (name: string, address: string, genesisHash: string): Promise { - return sendMessage('pri(accounts.create.external)', { address, genesisHash, name }); -} - export async function createAccountExternalV2 (request: RequestAccountCreateExternalV2): Promise { return sendMessage('pri(accounts.create.externalV2)', request); } diff --git a/packages/extension-web-ui/src/messaging/accounts/currentAccount.ts b/packages/extension-web-ui/src/messaging/accounts/currentAccount.ts index b761a664ab..31a9ecd889 100644 --- a/packages/extension-web-ui/src/messaging/accounts/currentAccount.ts +++ b/packages/extension-web-ui/src/messaging/accounts/currentAccount.ts @@ -1,8 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { CurrentAccountInfo } from '@subwallet/extension-base/background/KoniTypes'; import { RequestCurrentAccountAddress } from '@subwallet/extension-base/background/types'; +import { CurrentAccountInfo } from '@subwallet/extension-base/types'; import { sendMessage } from '@subwallet/extension-web-ui/messaging/base'; export async function saveCurrentAccountAddress (data: RequestCurrentAccountAddress): Promise { diff --git a/packages/extension-web-ui/src/messaging/accounts/legacy.ts b/packages/extension-web-ui/src/messaging/accounts/legacy.ts index ad1d1abe98..97d0684da7 100644 --- a/packages/extension-web-ui/src/messaging/accounts/legacy.ts +++ b/packages/extension-web-ui/src/messaging/accounts/legacy.ts @@ -1,8 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountsWithCurrentAddress, OptionInputAddress } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { OptionInputAddress } from '@subwallet/extension-base/background/KoniTypes'; +import { AccountJson, AccountsWithCurrentAddress } from '@subwallet/extension-base/types'; import { sendMessage } from '../base'; diff --git a/packages/extension-web-ui/src/stores/base/AccountState.ts b/packages/extension-web-ui/src/stores/base/AccountState.ts index 8d6d3efb53..d5acd89c2e 100644 --- a/packages/extension-web-ui/src/stores/base/AccountState.ts +++ b/packages/extension-web-ui/src/stores/base/AccountState.ts @@ -3,7 +3,8 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { AddressBookInfo, KeyringState } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson, AccountsContext } from '@subwallet/extension-base/background/types'; +import { AccountsContext } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { AccountState, ReduxStatus } from '@subwallet/extension-web-ui/stores/types'; import { isAccountAll, isNoAccount } from '@subwallet/extension-web-ui/utils'; diff --git a/packages/extension-web-ui/src/stores/types.ts b/packages/extension-web-ui/src/stores/types.ts index 99f8c22672..b548c24e93 100644 --- a/packages/extension-web-ui/src/stores/types.ts +++ b/packages/extension-web-ui/src/stores/types.ts @@ -4,11 +4,11 @@ import { _AssetRef, _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet/chain-list/types'; import { AuthUrlInfo } from '@subwallet/extension-base/background/handlers/State'; import { AddressBookState, AllLogoMap, AssetSetting, CampaignBanner, ChainStakingMetadata, ConfirmationDefinitions, ConfirmationsQueue, ConfirmationType, CrowdloanItem, KeyringState, LanguageType, MantaPayConfig, NftCollection, NftItem, NominatorMetadata, PriceJson, StakingItem, StakingRewardItem, TransactionHistoryItem, UiSettings, ValidatorInfo } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson, AccountsContext, AuthorizeRequest, MetadataRequest, SigningRequest } from '@subwallet/extension-base/background/types'; +import { AccountsContext, AuthorizeRequest, MetadataRequest, SigningRequest } from '@subwallet/extension-base/background/types'; import { _ChainApiStatus, _ChainState } from '@subwallet/extension-base/services/chain-service/types'; import { SWTransactionResult } from '@subwallet/extension-base/services/transaction-service/types'; import { WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; -import { BalanceMap, BuyServiceInfo, BuyTokenInfo, EarningRewardHistoryItem, EarningRewardItem, NominationPoolInfo, YieldPoolInfo, YieldPoolTarget, YieldPositionInfo } from '@subwallet/extension-base/types'; +import { AccountJson, BalanceMap, BuyServiceInfo, BuyTokenInfo, EarningRewardHistoryItem, EarningRewardItem, NominationPoolInfo, YieldPoolInfo, YieldPoolTarget, YieldPositionInfo } from '@subwallet/extension-base/types'; import { SwapPair } from '@subwallet/extension-base/types/swap'; import { DAppCategory, DAppInfo } from '@subwallet/extension-web-ui/types/dapp'; import { MissionInfo } from '@subwallet/extension-web-ui/types/missionPool'; diff --git a/packages/extension-web-ui/src/stores/utils/index.ts b/packages/extension-web-ui/src/stores/utils/index.ts index 97aa6e0f42..3499e76791 100644 --- a/packages/extension-web-ui/src/stores/utils/index.ts +++ b/packages/extension-web-ui/src/stores/utils/index.ts @@ -3,12 +3,12 @@ import { _AssetRef, _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet/chain-list/types'; import { AuthUrls } from '@subwallet/extension-base/background/handlers/State'; -import { AccountsWithCurrentAddress, AddressBookInfo, AssetSetting, CampaignBanner, ChainStakingMetadata, ConfirmationsQueue, CrowdloanJson, KeyringState, MantaPayConfig, MantaPaySyncState, NftCollection, NftJson, NominatorMetadata, PriceJson, StakingJson, StakingRewardJson, TransactionHistoryItem, UiSettings } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson, AccountsContext, AuthorizeRequest, ConfirmationRequestBase, MetadataRequest, SigningRequest } from '@subwallet/extension-base/background/types'; +import { AddressBookInfo, AssetSetting, CampaignBanner, ChainStakingMetadata, ConfirmationsQueue, CrowdloanJson, KeyringState, MantaPayConfig, MantaPaySyncState, NftCollection, NftJson, NominatorMetadata, PriceJson, StakingJson, StakingRewardJson, TransactionHistoryItem, UiSettings } from '@subwallet/extension-base/background/KoniTypes'; +import { AccountsContext, AuthorizeRequest, ConfirmationRequestBase, MetadataRequest, SigningRequest } from '@subwallet/extension-base/background/types'; import { _ChainApiStatus, _ChainState } from '@subwallet/extension-base/services/chain-service/types'; import { SWTransactionResult } from '@subwallet/extension-base/services/transaction-service/types'; import { WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; -import { BalanceJson, BuyServiceInfo, BuyTokenInfo, EarningRewardHistoryItem, EarningRewardJson, YieldPoolInfo, YieldPositionInfo } from '@subwallet/extension-base/types'; +import { AccountJson, AccountsWithCurrentAddress, BalanceJson, BuyServiceInfo, BuyTokenInfo, EarningRewardHistoryItem, EarningRewardJson, YieldPoolInfo, YieldPositionInfo } from '@subwallet/extension-base/types'; import { SwapPair } from '@subwallet/extension-base/types/swap'; import { addLazy, canDerive, fetchStaticData, isEmptyObject } from '@subwallet/extension-base/utils'; import { lazySubscribeMessage } from '@subwallet/extension-web-ui/messaging'; diff --git a/packages/extension-web-ui/src/types/index.ts b/packages/extension-web-ui/src/types/index.ts index 00c6b53846..3d9df0ab8d 100644 --- a/packages/extension-web-ui/src/types/index.ts +++ b/packages/extension-web-ui/src/types/index.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { NotificationType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { ButtonSchema } from '@subwallet/react-ui/es/button/button'; import { Icon as _PhosphorIcon, IconProps } from 'phosphor-react'; import React from 'react'; diff --git a/packages/extension-web-ui/src/types/navigation.ts b/packages/extension-web-ui/src/types/navigation.ts index 29a7e42fbe..6e8b8e9e20 100644 --- a/packages/extension-web-ui/src/types/navigation.ts +++ b/packages/extension-web-ui/src/types/navigation.ts @@ -1,7 +1,7 @@ // Copyright 2019-2022 @polkadot/extension-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { EarningEntryView } from '@subwallet/extension-web-ui/types/earning'; export type CreateDoneParam = { diff --git a/packages/extension-web-ui/src/utils/account/account.ts b/packages/extension-web-ui/src/utils/account/account.ts index eb6b566ead..a83cd646cf 100644 --- a/packages/extension-web-ui/src/utils/account/account.ts +++ b/packages/extension-web-ui/src/utils/account/account.ts @@ -3,9 +3,10 @@ import { _ChainInfo } from '@subwallet/chain-list/types'; import { NetworkJson } from '@subwallet/extension-base/background/KoniTypes'; -import { AbstractAddressJson, AccountAuthType, AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountAuthType } from '@subwallet/extension-base/background/types'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; import { _getChainSubstrateAddressPrefix, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { AbstractAddressJson, AccountJson } from '@subwallet/extension-base/types'; import { isAccountAll, uniqueStringArray } from '@subwallet/extension-base/utils'; import { DEFAULT_ACCOUNT_TYPES, EVM_ACCOUNT_TYPE, SUBSTRATE_ACCOUNT_TYPE } from '@subwallet/extension-web-ui/constants'; import { MODE_CAN_SIGN } from '@subwallet/extension-web-ui/constants/signing'; diff --git a/packages/extension-web-ui/src/utils/account/buildHierarchy.ts b/packages/extension-web-ui/src/utils/account/buildHierarchy.ts index 5474a3e8aa..86da91a04d 100644 --- a/packages/extension-web-ui/src/utils/account/buildHierarchy.ts +++ b/packages/extension-web-ui/src/utils/account/buildHierarchy.ts @@ -1,8 +1,9 @@ // Copyright 2019-2022 @polkadot/extension-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import type { AccountJson, AccountWithChildren } from '@subwallet/extension-base/background/types'; +import type { AccountWithChildren } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { isAccountAll } from '@subwallet/extension-web-ui/utils/account/accountAll'; import getNetworkMap from '../chain/getNetworkMap'; diff --git a/packages/extension-web-ui/src/utils/index.ts b/packages/extension-web-ui/src/utils/index.ts index 65620f4461..8e68152314 100644 --- a/packages/extension-web-ui/src/utils/index.ts +++ b/packages/extension-web-ui/src/utils/index.ts @@ -4,9 +4,10 @@ import { ChainLogoMap } from '@subwallet/chain-list'; import { _ChainInfo } from '@subwallet/chain-list/types'; import { NetworkJson } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson, AccountWithChildren } from '@subwallet/extension-base/background/types'; +import { AccountWithChildren } from '@subwallet/extension-base/background/types'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; import { _getChainSubstrateAddressPrefix, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { AccountJson } from '@subwallet/extension-base/types'; import { Recoded } from '@subwallet/extension-web-ui/types'; import { isAccountAll } from '@subwallet/extension-web-ui/utils/account/accountAll'; import reformatAddress from '@subwallet/extension-web-ui/utils/account/reformatAddress'; diff --git a/packages/extension-web-ui/src/utils/scanner/decoders.ts b/packages/extension-web-ui/src/utils/scanner/decoders.ts index 58275fae84..8c4c154bc9 100644 --- a/packages/extension-web-ui/src/utils/scanner/decoders.ts +++ b/packages/extension-web-ui/src/utils/scanner/decoders.ts @@ -2,9 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 import { _ChainInfo } from '@subwallet/chain-list/types'; -import { AccountJson } from '@subwallet/extension-base/background/types'; import { _ChainState } from '@subwallet/extension-base/services/chain-service/types'; import { _isChainEnabled, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { AccountJson } from '@subwallet/extension-base/types'; import { createTransactionFromRLP } from '@subwallet/extension-base/utils/eth'; import { EthereumParsedData, ParsedData, SubstrateCompletedParsedData, SubstrateMultiParsedData } from '@subwallet/extension-web-ui/types/scanner'; import { findAccountByAddress } from '@subwallet/extension-web-ui/utils/account/account'; diff --git a/packages/extension-web-ui/src/utils/transaction/account.ts b/packages/extension-web-ui/src/utils/transaction/account.ts index 88128b04eb..6351fbb522 100644 --- a/packages/extension-web-ui/src/utils/transaction/account.ts +++ b/packages/extension-web-ui/src/utils/transaction/account.ts @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from '@subwallet/extension-base/background/types'; +import { AccountJson } from '@subwallet/extension-base/types'; import { isAccountAll } from '@subwallet/extension-web-ui/utils'; export const transactionDefaultFilterAccount = (account: AccountJson): boolean => !(isAccountAll(account.address) || account.isReadOnly); diff --git a/packages/extension-web-ui/src/utils/walletConnect/index.ts b/packages/extension-web-ui/src/utils/walletConnect/index.ts index c2c5966786..8c70c6f7f3 100644 --- a/packages/extension-web-ui/src/utils/walletConnect/index.ts +++ b/packages/extension-web-ui/src/utils/walletConnect/index.ts @@ -2,9 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 import { _ChainInfo } from '@subwallet/chain-list/types'; -import { AbstractAddressJson, AccountJson } from '@subwallet/extension-base/background/types'; import { findChainInfoByChainId, findChainInfoByHalfGenesisHash } from '@subwallet/extension-base/services/chain-service/utils'; import { WALLET_CONNECT_EIP155_NAMESPACE, WALLET_CONNECT_POLKADOT_NAMESPACE } from '@subwallet/extension-base/services/wallet-connect-service/constants'; +import { AbstractAddressJson, AccountJson } from '@subwallet/extension-base/types'; import { WalletConnectChainInfo } from '@subwallet/extension-web-ui/types'; import { SessionTypes } from '@walletconnect/types'; From 3aa6a5cb6413ef29a4c4f10bbd225dc05e47b9f6 Mon Sep 17 00:00:00 2001 From: S2kael Date: Mon, 22 Jul 2024 16:23:24 +0700 Subject: [PATCH 002/424] [MasterAccount] Change from `AccountGroup` to `AccountProxy` --- .../src/koni/background/handlers/Extension.ts | 4 +- .../keyring-service/account-context.ts | 48 +++++++++++-------- ...ountGroupStore.ts => AccountProxyStore.ts} | 6 +-- .../src/stores/ModifyPairStore.ts | 2 +- .../src/types/account/info/current.ts | 4 +- .../src/types/account/info/index.ts | 2 +- .../types/account/info/{group.ts => proxy.ts} | 10 ++-- 7 files changed, 41 insertions(+), 35 deletions(-) rename packages/extension-base/src/stores/{AccountGroupStore.ts => AccountProxyStore.ts} (57%) rename packages/extension-base/src/types/account/info/{group.ts => proxy.ts} (61%) diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index bbcbf6d9db..76505f53da 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -41,7 +41,7 @@ import { isProposalExpired, isSupportWalletConnectChain, isSupportWalletConnectN import { ResultApproveWalletConnectSession, WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; import { SWStorage } from '@subwallet/extension-base/storage'; import { AccountsStore } from '@subwallet/extension-base/stores'; -import { AccountGroup, AccountJson, AccountsWithCurrentAddress, BalanceJson, BuyServiceInfo, BuyTokenInfo, CurrentAccountInfo, EarningRewardJson, NominationPoolInfo, OptimalYieldPathParams, RequestEarlyValidateYield, RequestGetYieldPoolTargets, RequestMetadataHash, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseShortenMetadata, StorageDataInterface, TokenSpendingApprovalParams, ValidateYieldProcessParams, YieldPoolType } from '@subwallet/extension-base/types'; +import { AccountProxy, AccountJson, AccountsWithCurrentAddress, BalanceJson, BuyServiceInfo, BuyTokenInfo, CurrentAccountInfo, EarningRewardJson, NominationPoolInfo, OptimalYieldPathParams, RequestEarlyValidateYield, RequestGetYieldPoolTargets, RequestMetadataHash, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseShortenMetadata, StorageDataInterface, TokenSpendingApprovalParams, ValidateYieldProcessParams, YieldPoolType } from '@subwallet/extension-base/types'; import { CommonOptimalPath } from '@subwallet/extension-base/types/service-base'; import { SwapPair, SwapQuoteResponse, SwapRequest, SwapRequestResult, SwapSubmitParams, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap'; import { BN_ZERO, convertSubjectInfoToAddresses, createTransactionFromRLP, isSameAddress, MODULE_SUPPORT, reformatAddress, signatureToHex, Transaction as QrTransaction, uniqueStringArray } from '@subwallet/extension-base/utils'; @@ -77,7 +77,7 @@ function getSuri (seed: string, type?: KeypairType): string { : seed; } -const ACCOUNT_ALL_GROUP: AccountGroup = { +const ACCOUNT_ALL_GROUP: AccountProxy = { id: ALL_ACCOUNT_KEY, name: 'All', accounts: [] diff --git a/packages/extension-base/src/services/keyring-service/account-context.ts b/packages/extension-base/src/services/keyring-service/account-context.ts index 062e64fc41..1b0bb3c9ce 100644 --- a/packages/extension-base/src/services/keyring-service/account-context.ts +++ b/packages/extension-base/src/services/keyring-service/account-context.ts @@ -6,11 +6,11 @@ import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; import { _getEvmChainId, _getSubstrateGenesisHash } from '@subwallet/extension-base/services/chain-service/utils'; import { KeyringService } from '@subwallet/extension-base/services/keyring-service/index'; import { CurrentAccountStore } from '@subwallet/extension-base/stores'; -import AccountGroupStore from '@subwallet/extension-base/stores/AccountGroupStore'; +import AccountProxyStore from '@subwallet/extension-base/stores/AccountProxyStore'; import AccountRefStore from '@subwallet/extension-base/stores/AccountRef'; import ModifyPairStore from '@subwallet/extension-base/stores/ModifyPairStore'; -import { AccountGroupData, AccountGroupMap, AccountGroupStoreData, AccountJson, CurrentAccountInfo, ModifyPairStoreData } from '@subwallet/extension-base/types'; -import { isAddressValidWithAuthType, transformAccount, transformAccounts } from '@subwallet/extension-base/utils'; +import { AccountJson, AccountProxyData, AccountProxyMap, AccountProxyStoreData, CurrentAccountInfo, ModifyPairStoreData } from '@subwallet/extension-base/types'; +import { isAddressValidWithAuthType, transformAccount } from '@subwallet/extension-base/utils'; import { InjectedAccountWithMeta } from '@subwallet/extension-inject/types'; import { KeyringPair, KeyringPair$Meta } from '@subwallet/keyring/types'; import { keyring } from '@subwallet/ui-keyring'; @@ -19,7 +19,7 @@ import { t } from 'i18next'; import { BehaviorSubject, combineLatest } from 'rxjs'; import { hexStripPrefix, hexToU8a, isHex, stringShorten } from '@polkadot/util'; -import { keyExtractSuri } from '@polkadot/util-crypto'; +import { keyExtractSuri, mnemonicToEntropy } from '@polkadot/util-crypto'; import { KeypairType } from '@polkadot/util-crypto/types'; const ETH_DERIVE_DEFAULT = '/m/44\'/60\'/0\'/0/0'; @@ -30,7 +30,7 @@ const getSuri = (seed: string, type?: KeypairType): string => type === 'ethereum const CURRENT_ACCOUNT_KEY = 'CurrentAccountInfo'; const MODIFY_PAIRS_KEY = 'ModifyPairs'; -const ACCOUNT_GROUPS_KEY = 'AccountGroups'; +const ACCOUNT_PROXIES_KEY = 'AccountProxies'; export class AccountContext { // Current account @@ -38,8 +38,8 @@ export class AccountContext { public readonly currentAccountSubject = new BehaviorSubject({ address: '' }); // Account groups - private readonly accountGroupsStore = new AccountGroupStore(); - public readonly accountGroupsSubject = new BehaviorSubject({}); + private readonly accountProxiesStore = new AccountProxyStore(); + public readonly accountProxiesSubject = new BehaviorSubject({}); // Modify pairs private readonly modifyPairsStore = new ModifyPairStore(); @@ -48,7 +48,7 @@ export class AccountContext { // Observable of accounts, pairs and contacts public readonly contactSubject = keyring.addresses.subject; public readonly pairSubject = keyring.accounts.subject; - public readonly accountSubject = new BehaviorSubject({}); + public readonly accountSubject = new BehaviorSubject({}); // Old from Polkadot-js private readonly accountRefStore = new AccountRefStore(); @@ -71,9 +71,9 @@ export class AccountContext { this.modifyPairsStore.get(MODIFY_PAIRS_KEY, (rs) => { rs && this.modifyPairsSubject.next(rs); }); - // Load account groups - this.accountGroupsStore.get(ACCOUNT_GROUPS_KEY, (rs) => { - rs && this.accountGroupsSubject.next(rs); + // Load account proxies + this.accountProxiesStore.get(ACCOUNT_PROXIES_KEY, (rs) => { + rs && this.accountProxiesSubject.next(rs); }); this.subscribeAccounts().catch(console.error); }) @@ -112,17 +112,17 @@ export class AccountContext { const pairs = this.pairSubject.asObservable(); const modifyPairs = this.modifyPairsSubject.asObservable(); - const accountGroups = this.accountGroupsSubject.asObservable(); + const accountGroups = this.accountProxiesSubject.asObservable(); combineLatest([pairs, modifyPairs, accountGroups]).subscribe(([pairs, modifyPairs, accountGroups]) => { - const result: AccountGroupMap = {}; + const result: AccountProxyMap = {}; for (const [address, pair] of Object.entries(pairs)) { const modifyPair = modifyPairs[address]; const account: AccountJson = transformAccount(pair); - if (modifyPair && modifyPair.applied && modifyPair.accountGroupId) { - const accountGroup = accountGroups[modifyPair.accountGroupId]; + if (modifyPair && modifyPair.applied && modifyPair.accountProxyId) { + const accountGroup = accountGroups[modifyPair.accountProxyId]; if (accountGroup) { if (!result[accountGroup.id]) { @@ -137,7 +137,7 @@ export class AccountContext { result[address] = { id: address, name: account.name || account.address, accounts: [account] }; } - this.accountGroupsSubject.next(result); + this.accountProxiesSubject.next(result); }); } @@ -149,7 +149,7 @@ export class AccountContext { return this.contactSubject.value; } - get accounts (): AccountGroupMap { + get accounts (): AccountProxyMap { return this.accountSubject.value; } @@ -223,16 +223,20 @@ export class AccountContext { /* Upsert account group */ - private upsertAccountGroup (data: AccountGroupData, callback?: () => void) { - this.accountGroupsStore.get(ACCOUNT_GROUPS_KEY, (rs) => { + private upsertAccountProxy (data: AccountProxyData, callback?: () => void) { + this.accountProxiesStore.get(ACCOUNT_PROXIES_KEY, (rs) => { const accountGroups = rs || {}; accountGroups[data.id] = data; - this.accountGroupsSubject.next(accountGroups); - this.accountGroupsStore.set(ACCOUNT_GROUPS_KEY, accountGroups, callback); + this.accountProxiesSubject.next(accountGroups); + this.accountProxiesStore.set(ACCOUNT_PROXIES_KEY, accountGroups, callback); }); } + // private createAccountGroupId (_suri: string) { + // bcrypt. + // } + /* Account group */ /* Add accounts from seed */ @@ -254,6 +258,8 @@ export class AccountContext { // const currentAccount = this.#koniState.keyringService.context.currentAccount; // const allGenesisHash = currentAccount?.allGenesisHash || undefined; + const entropy = mnemonicToEntropy(_suri); + types?.forEach((type) => { const suri = getSuri(_suri, type); const address = keyring.createFromUri(suri, {}, type).address; diff --git a/packages/extension-base/src/stores/AccountGroupStore.ts b/packages/extension-base/src/stores/AccountProxyStore.ts similarity index 57% rename from packages/extension-base/src/stores/AccountGroupStore.ts rename to packages/extension-base/src/stores/AccountProxyStore.ts index 4226157cac..5502331011 100644 --- a/packages/extension-base/src/stores/AccountGroupStore.ts +++ b/packages/extension-base/src/stores/AccountProxyStore.ts @@ -3,10 +3,10 @@ import { EXTENSION_PREFIX } from '@subwallet/extension-base/defaults'; import SubscribableStore from '@subwallet/extension-base/stores/SubscribableStore'; -import { AccountGroupStoreData } from '@subwallet/extension-base/types'; +import { AccountProxyStoreData } from '@subwallet/extension-base/types'; -export default class AccountGroupStore extends SubscribableStore { +export default class AccountProxyStore extends SubscribableStore { constructor () { - super(EXTENSION_PREFIX ? `${EXTENSION_PREFIX}pair_modify` : null); + super(EXTENSION_PREFIX ? `${EXTENSION_PREFIX}account_proxy` : null); } } diff --git a/packages/extension-base/src/stores/ModifyPairStore.ts b/packages/extension-base/src/stores/ModifyPairStore.ts index a340641824..31525fcee0 100644 --- a/packages/extension-base/src/stores/ModifyPairStore.ts +++ b/packages/extension-base/src/stores/ModifyPairStore.ts @@ -7,6 +7,6 @@ import { ModifyPairStoreData } from '@subwallet/extension-base/types'; export default class ModifyPairStore extends SubscribableStore { constructor () { - super(EXTENSION_PREFIX ? `${EXTENSION_PREFIX}group_account` : null); + super(EXTENSION_PREFIX ? `${EXTENSION_PREFIX}pair_modify` : null); } } diff --git a/packages/extension-base/src/types/account/info/current.ts b/packages/extension-base/src/types/account/info/current.ts index a74e97ff10..832de05bf5 100644 --- a/packages/extension-base/src/types/account/info/current.ts +++ b/packages/extension-base/src/types/account/info/current.ts @@ -1,11 +1,11 @@ // Copyright 2019-2022 @subwallet/extension-base authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountGroup } from './group'; +import { AccountProxy } from './group'; // all Accounts and the address of the current Account export interface AccountsWithCurrentAddress { - accounts: AccountGroup[]; + accounts: AccountProxy[]; currentAddress?: string; } diff --git a/packages/extension-base/src/types/account/info/index.ts b/packages/extension-base/src/types/account/info/index.ts index ee95c76a28..5b587c56d4 100644 --- a/packages/extension-base/src/types/account/info/index.ts +++ b/packages/extension-base/src/types/account/info/index.ts @@ -2,5 +2,5 @@ // SPDX-License-Identifier: Apache-2.0 export * from './current'; -export * from './group'; export * from './keyring'; +export * from './proxy'; diff --git a/packages/extension-base/src/types/account/info/group.ts b/packages/extension-base/src/types/account/info/proxy.ts similarity index 61% rename from packages/extension-base/src/types/account/info/group.ts rename to packages/extension-base/src/types/account/info/proxy.ts index 90fef36011..ed88ddb056 100644 --- a/packages/extension-base/src/types/account/info/group.ts +++ b/packages/extension-base/src/types/account/info/proxy.ts @@ -3,24 +3,24 @@ import { AccountJson } from './keyring'; -export interface AccountGroupData { +export interface AccountProxyData { id: string; name: string; } -export type AccountGroupStoreData = Record; +export type AccountProxyStoreData = Record; -export interface AccountGroup extends AccountGroupData { +export interface AccountProxy extends AccountProxyData { accounts: AccountJson[]; } -export type AccountGroupMap = Record +export type AccountProxyMap = Record export interface ModifyPairData { key: string; applied: boolean; migrated: boolean; - accountGroupId?: string; + accountProxyId?: string; } export type ModifyPairStoreData = Record; From c38fa1eecceac455b0332a89fe5eb94b6b13b0e0 Mon Sep 17 00:00:00 2001 From: S2kael Date: Mon, 22 Jul 2024 18:05:22 +0700 Subject: [PATCH 003/424] [MasterAccount] Update create account with seed --- .../src/background/KoniTypes.ts | 1 - .../src/koni/background/handlers/Extension.ts | 8 +- .../keyring-service/account-context.ts | 75 ++++++++++++++++--- .../src/types/account/info/proxy.ts | 1 - 4 files changed, 67 insertions(+), 18 deletions(-) diff --git a/packages/extension-base/src/background/KoniTypes.ts b/packages/extension-base/src/background/KoniTypes.ts index a7c7b3cc62..d43eeea07e 100644 --- a/packages/extension-base/src/background/KoniTypes.ts +++ b/packages/extension-base/src/background/KoniTypes.ts @@ -829,7 +829,6 @@ export type ResponseSeedValidateV2 = ResponseSeedCreateV2 export interface RequestAccountCreateSuriV2 { name: string; - genesisHash?: string | null; password?: string; suri: string; types?: Array; diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index 76505f53da..668a3509ed 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -31,7 +31,7 @@ import { createTransferExtrinsic, getTransferMockTxFee } from '@subwallet/extens import { createSnowBridgeExtrinsic, createXcmExtrinsic, getXcmMockTxFee } from '@subwallet/extension-base/services/balance-service/transfer/xcm'; import { _API_OPTIONS_CHAIN_GROUP, _DEFAULT_MANTA_ZK_CHAIN, _MANTA_ZK_CHAIN_GROUP, _ZK_ASSET_PREFIX } from '@subwallet/extension-base/services/chain-service/constants'; import { _ChainApiStatus, _ChainConnectionStatus, _ChainState, _NetworkUpsertParams, _ValidateCustomAssetRequest, _ValidateCustomAssetResponse, EnableChainParams, EnableMultiChainParams } from '@subwallet/extension-base/services/chain-service/types'; -import { _getAssetDecimals, _getAssetSymbol, _getChainNativeTokenBasicInfo, _getContractAddressOfToken, _getEvmChainId, _getSubstrateGenesisHash, _isAssetSmartContractNft, _isChainEvmCompatible, _isCustomAsset, _isLocalToken, _isMantaZkAsset, _isNativeToken, _isPureEvmChain, _isTokenEvmSmartContract, _isTokenTransferredByEvm } from '@subwallet/extension-base/services/chain-service/utils'; +import { _getAssetDecimals, _getAssetSymbol, _getChainNativeTokenBasicInfo, _getContractAddressOfToken, _getEvmChainId, _isAssetSmartContractNft, _isChainEvmCompatible, _isCustomAsset, _isLocalToken, _isMantaZkAsset, _isNativeToken, _isPureEvmChain, _isTokenEvmSmartContract, _isTokenTransferredByEvm } from '@subwallet/extension-base/services/chain-service/utils'; import { EXTENSION_REQUEST_URL } from '@subwallet/extension-base/services/request-service/constants'; import { AuthUrls } from '@subwallet/extension-base/services/request-service/types'; import { DEFAULT_AUTO_LOCK_TIME } from '@subwallet/extension-base/services/setting-service/constants'; @@ -41,10 +41,10 @@ import { isProposalExpired, isSupportWalletConnectChain, isSupportWalletConnectN import { ResultApproveWalletConnectSession, WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; import { SWStorage } from '@subwallet/extension-base/storage'; import { AccountsStore } from '@subwallet/extension-base/stores'; -import { AccountProxy, AccountJson, AccountsWithCurrentAddress, BalanceJson, BuyServiceInfo, BuyTokenInfo, CurrentAccountInfo, EarningRewardJson, NominationPoolInfo, OptimalYieldPathParams, RequestEarlyValidateYield, RequestGetYieldPoolTargets, RequestMetadataHash, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseShortenMetadata, StorageDataInterface, TokenSpendingApprovalParams, ValidateYieldProcessParams, YieldPoolType } from '@subwallet/extension-base/types'; +import { AccountProxy, AccountsWithCurrentAddress, BalanceJson, BuyServiceInfo, BuyTokenInfo, CurrentAccountInfo, EarningRewardJson, NominationPoolInfo, OptimalYieldPathParams, RequestEarlyValidateYield, RequestGetYieldPoolTargets, RequestMetadataHash, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseShortenMetadata, StorageDataInterface, TokenSpendingApprovalParams, ValidateYieldProcessParams, YieldPoolType } from '@subwallet/extension-base/types'; import { CommonOptimalPath } from '@subwallet/extension-base/types/service-base'; import { SwapPair, SwapQuoteResponse, SwapRequest, SwapRequestResult, SwapSubmitParams, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap'; -import { BN_ZERO, convertSubjectInfoToAddresses, createTransactionFromRLP, isSameAddress, MODULE_SUPPORT, reformatAddress, signatureToHex, Transaction as QrTransaction, uniqueStringArray } from '@subwallet/extension-base/utils'; +import { BN_ZERO, convertSubjectInfoToAddresses, createTransactionFromRLP, isSameAddress, MODULE_SUPPORT, reformatAddress, signatureToHex, Transaction as QrTransaction, transformAccounts, uniqueStringArray } from '@subwallet/extension-base/utils'; import { parseContractInput, parseEvmRlp } from '@subwallet/extension-base/utils/eth/parseTransaction'; import { metadataExpand } from '@subwallet/extension-chains'; import { MetadataDef } from '@subwallet/extension-inject/types'; @@ -492,7 +492,7 @@ export default class KoniExtension { responseData.accounts = transformedAccounts?.length ? [{ ...ACCOUNT_ALL_GROUP }, ...transformedAccounts] : []; responseData.currentAddress = currentAccount?.address; - console.log(responseData); + console.log('subscriptionAccountGroups', responseData); cb(responseData); }); diff --git a/packages/extension-base/src/services/keyring-service/account-context.ts b/packages/extension-base/src/services/keyring-service/account-context.ts index 1b0bb3c9ce..b74190478d 100644 --- a/packages/extension-base/src/services/keyring-service/account-context.ts +++ b/packages/extension-base/src/services/keyring-service/account-context.ts @@ -19,7 +19,8 @@ import { t } from 'i18next'; import { BehaviorSubject, combineLatest } from 'rxjs'; import { hexStripPrefix, hexToU8a, isHex, stringShorten } from '@polkadot/util'; -import { keyExtractSuri, mnemonicToEntropy } from '@polkadot/util-crypto'; +import { blake2AsHex, keyExtractSuri, mnemonicToEntropy } from '@polkadot/util-crypto'; +import { validateMnemonic } from '@polkadot/util-crypto/mnemonic/bip39'; import { KeypairType } from '@polkadot/util-crypto/types'; const ETH_DERIVE_DEFAULT = '/m/44\'/60\'/0\'/0/0'; @@ -121,7 +122,7 @@ export class AccountContext { const modifyPair = modifyPairs[address]; const account: AccountJson = transformAccount(pair); - if (modifyPair && modifyPair.applied && modifyPair.accountProxyId) { + if (modifyPair && modifyPair.accountProxyId) { const accountGroup = accountGroups[modifyPair.accountProxyId]; if (accountGroup) { @@ -233,15 +234,32 @@ export class AccountContext { }); } - // private createAccountGroupId (_suri: string) { - // bcrypt. - // } + private createAccountGroupId (_suri: string) { + if (validateMnemonic(_suri)) { + const entropy = mnemonicToEntropy(_suri); + + return blake2AsHex(entropy, 256); + } else { + return blake2AsHex(_suri, 256); + } + } /* Account group */ + /* Modify pairs */ + + /* Upsert modify pairs */ + + private upsertModifyPairs (data: ModifyPairStoreData) { + this.modifyPairsStore.set(MODIFY_PAIRS_KEY, data); + this.modifyPairsSubject.next(data); + } + + /* Modify pairs */ + /* Add accounts from seed */ public async accountsCreateSuriV2 (request: RequestAccountCreateSuriV2): Promise { - const { genesisHash, isAllowed, name, password, suri: _suri, types } = request; + const { isAllowed, name, password, suri: _suri, types } = request; const addressDict = {} as Record; let changedAccount = false; const hasMasterPassword = keyring.keyring.hasMasterPassword; @@ -255,23 +273,50 @@ export class AccountContext { } } + if (!types || !types.length) { + throw Error(t('Please choose at least one account type')); + } + // const currentAccount = this.#koniState.keyringService.context.currentAccount; // const allGenesisHash = currentAccount?.allGenesisHash || undefined; - const entropy = mnemonicToEntropy(_suri); + const multiChain = types.length > 1; + const proxyId = multiChain ? this.createAccountGroupId(_suri) : ''; + const modifiedPairs = this.modifyPairsSubject.value; - types?.forEach((type) => { + types.forEach((type) => { const suri = getSuri(_suri, type); - const address = keyring.createFromUri(suri, {}, type).address; + const newAccountName = (() => { + if (!proxyId) { + return name; + } + + let network = ''; + + switch (type) { + case 'sr25519': + case 'ed25519': + case 'ecdsa': + network = 'Substrate'; + break; + case 'ethereum': + network = 'EVM'; + break; + } + + return network ? [name, network].join(' - ') : name; + })(); + const rs = keyring.addUri(suri, { name: newAccountName }, type); + const address = rs.pair.address; + + modifiedPairs[address] = { accountProxyId: proxyId || address, migrated: true, key: address }; addressDict[type] = address; - const newAccountName = type === 'ethereum' ? `${name} - EVM` : name; - keyring.addUri(suri, { genesisHash, name: newAccountName }, type); this._addAddressToAuthList(address, isAllowed); if (!changedAccount) { - if (types.length === 1) { + if (!multiChain) { this.setCurrentAccount({ address }); } else { this._setCurrentAccount({ address: ALL_ACCOUNT_KEY }, undefined, true); @@ -281,6 +326,12 @@ export class AccountContext { } }); + if (proxyId) { + this.upsertAccountProxy({ id: proxyId, name }); + } + + this.upsertModifyPairs(modifiedPairs); + await new Promise((resolve) => { this.addAccountRef(Object.values(addressDict), () => { resolve(); diff --git a/packages/extension-base/src/types/account/info/proxy.ts b/packages/extension-base/src/types/account/info/proxy.ts index ed88ddb056..de231713fa 100644 --- a/packages/extension-base/src/types/account/info/proxy.ts +++ b/packages/extension-base/src/types/account/info/proxy.ts @@ -18,7 +18,6 @@ export type AccountProxyMap = Record export interface ModifyPairData { key: string; - applied: boolean; migrated: boolean; accountProxyId?: string; } From 9d007dbb707c81eb2b30cdc5ed5251c3a0080b4b Mon Sep 17 00:00:00 2001 From: S2kael Date: Tue, 23 Jul 2024 14:33:23 +0700 Subject: [PATCH 004/424] [MasterAccount] Fix error missing subscribe data --- .../src/koni/background/handlers/Extension.ts | 1 - .../keyring-service/account-context.ts | 2 +- .../src/types/account/info/proxy.ts | 23 +++++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index 668a3509ed..e4ce291c27 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -492,7 +492,6 @@ export default class KoniExtension { responseData.accounts = transformedAccounts?.length ? [{ ...ACCOUNT_ALL_GROUP }, ...transformedAccounts] : []; responseData.currentAddress = currentAccount?.address; - console.log('subscriptionAccountGroups', responseData); cb(responseData); }); diff --git a/packages/extension-base/src/services/keyring-service/account-context.ts b/packages/extension-base/src/services/keyring-service/account-context.ts index b74190478d..3f82bde5f4 100644 --- a/packages/extension-base/src/services/keyring-service/account-context.ts +++ b/packages/extension-base/src/services/keyring-service/account-context.ts @@ -138,7 +138,7 @@ export class AccountContext { result[address] = { id: address, name: account.name || account.address, accounts: [account] }; } - this.accountProxiesSubject.next(result); + this.accountSubject.next(result); }); } diff --git a/packages/extension-base/src/types/account/info/proxy.ts b/packages/extension-base/src/types/account/info/proxy.ts index de231713fa..5cc0277340 100644 --- a/packages/extension-base/src/types/account/info/proxy.ts +++ b/packages/extension-base/src/types/account/info/proxy.ts @@ -3,13 +3,36 @@ import { AccountJson } from './keyring'; +/** + * Represents the basic data structure for an account proxy. + * + * @interface AccountProxyData + * @prop {string} id - The unique identifier for the proxy account. + * @prop {string} name - The name of the proxy account. + * @prop {string} [parentId] - The identifier of the parent account proxy, from which it is derived. + * @prop {string} [suri] - Derivate path. + */ export interface AccountProxyData { id: string; name: string; + parentId?: string; + suri?: string; } +/** + * Represents a mapping of unique identifiers to account proxy data. + * This type is used to store and manage account proxy information efficiently, + * allowing for quick access and manipulation of proxy account details. + * + * @typedef {Record} AccountProxyStoreData + */ export type AccountProxyStoreData = Record; +/** + * @interface AccountProxy + * @extends AccountProxyData - Inherits properties from AccountProxyData. + * @prop {AccountJson[]} accounts - An array of `AccountJson` objects representing the accounts associated with this proxy. + */ export interface AccountProxy extends AccountProxyData { accounts: AccountJson[]; } From 55aefd28c0772cc0c7bd20e56d680719c7d21595 Mon Sep 17 00:00:00 2001 From: S2kael Date: Wed, 24 Jul 2024 09:39:26 +0700 Subject: [PATCH 005/424] [MasterAccount] Update interface --- .../src/koni/background/handlers/Extension.ts | 6 +- .../src/koni/background/handlers/Tabs.ts | 6 +- .../keyring-service/account-context.ts | 67 ++++++++++++++----- .../src/types/account/info/keyring.ts | 59 +++++++++++----- .../src/types/account/info/proxy.ts | 12 ++++ packages/extension-base/src/utils/account.ts | 59 +++++++++++++++- 6 files changed, 168 insertions(+), 41 deletions(-) diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index e4ce291c27..bc4eb04f87 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -41,7 +41,7 @@ import { isProposalExpired, isSupportWalletConnectChain, isSupportWalletConnectN import { ResultApproveWalletConnectSession, WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; import { SWStorage } from '@subwallet/extension-base/storage'; import { AccountsStore } from '@subwallet/extension-base/stores'; -import { AccountProxy, AccountsWithCurrentAddress, BalanceJson, BuyServiceInfo, BuyTokenInfo, CurrentAccountInfo, EarningRewardJson, NominationPoolInfo, OptimalYieldPathParams, RequestEarlyValidateYield, RequestGetYieldPoolTargets, RequestMetadataHash, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseShortenMetadata, StorageDataInterface, TokenSpendingApprovalParams, ValidateYieldProcessParams, YieldPoolType } from '@subwallet/extension-base/types'; +import { AccountProxy, AccountProxyType, AccountsWithCurrentAddress, BalanceJson, BuyServiceInfo, BuyTokenInfo, CurrentAccountInfo, EarningRewardJson, NominationPoolInfo, OptimalYieldPathParams, RequestEarlyValidateYield, RequestGetYieldPoolTargets, RequestMetadataHash, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseShortenMetadata, StorageDataInterface, TokenSpendingApprovalParams, ValidateYieldProcessParams, YieldPoolType } from '@subwallet/extension-base/types'; import { CommonOptimalPath } from '@subwallet/extension-base/types/service-base'; import { SwapPair, SwapQuoteResponse, SwapRequest, SwapRequestResult, SwapSubmitParams, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap'; import { BN_ZERO, convertSubjectInfoToAddresses, createTransactionFromRLP, isSameAddress, MODULE_SUPPORT, reformatAddress, signatureToHex, Transaction as QrTransaction, transformAccounts, uniqueStringArray } from '@subwallet/extension-base/utils'; @@ -80,7 +80,8 @@ function getSuri (seed: string, type?: KeypairType): string { const ACCOUNT_ALL_GROUP: AccountProxy = { id: ALL_ACCOUNT_KEY, name: 'All', - accounts: [] + accounts: [], + accountType: AccountProxyType.ALL_ACCOUNT }; export const SEED_DEFAULT_LENGTH = 12; @@ -492,6 +493,7 @@ export default class KoniExtension { responseData.accounts = transformedAccounts?.length ? [{ ...ACCOUNT_ALL_GROUP }, ...transformedAccounts] : []; responseData.currentAddress = currentAccount?.address; + console.debug('subscriptionAccountGroups', responseData); cb(responseData); }); diff --git a/packages/extension-base/src/koni/background/handlers/Tabs.ts b/packages/extension-base/src/koni/background/handlers/Tabs.ts index cde206dd10..e6b1c2d46a 100644 --- a/packages/extension-base/src/koni/background/handlers/Tabs.ts +++ b/packages/extension-base/src/koni/background/handlers/Tabs.ts @@ -20,7 +20,7 @@ import { _NetworkUpsertParams } from '@subwallet/extension-base/services/chain-s import { _generateCustomProviderKey } from '@subwallet/extension-base/services/chain-service/utils'; import { AuthUrls } from '@subwallet/extension-base/services/request-service/types'; import { DEFAULT_CHAIN_PATROL_ENABLE } from '@subwallet/extension-base/services/setting-service/constants'; -import { canDerive, getEVMChainInfo, stripUrl } from '@subwallet/extension-base/utils'; +import { canDerive, getEVMChainInfo, stripUrl, transformAccountFromPair } from '@subwallet/extension-base/utils'; import { InjectedMetadataKnown, MetadataDef, ProviderMeta } from '@subwallet/extension-inject/types'; import { KeyringPair } from '@subwallet/keyring/types'; import keyring from '@subwallet/ui-keyring'; @@ -149,7 +149,7 @@ export default class KoniTabs { throw new Error('Account {{address}} not in allowed list'.replace('{{address}}', address)); } - return this.#koniState.sign(url, new RequestBytesSign(request), { address, ...pair.meta }); + return this.#koniState.sign(url, new RequestBytesSign(request), transformAccountFromPair(pair)); } private async extrinsicSign (url: string, request: SignerPayloadJSON): Promise { @@ -161,7 +161,7 @@ export default class KoniTabs { throw new Error('Account {{address}} not in allowed list'.replace('{{address}}', address)); } - return this.#koniState.sign(url, new RequestExtrinsicSign(request), { address, ...pair.meta }); + return this.#koniState.sign(url, new RequestExtrinsicSign(request), transformAccountFromPair(pair)); } private metadataProvide (url: string, request: MetadataDef): Promise { diff --git a/packages/extension-base/src/services/keyring-service/account-context.ts b/packages/extension-base/src/services/keyring-service/account-context.ts index 3f82bde5f4..081739b156 100644 --- a/packages/extension-base/src/services/keyring-service/account-context.ts +++ b/packages/extension-base/src/services/keyring-service/account-context.ts @@ -9,7 +9,7 @@ import { CurrentAccountStore } from '@subwallet/extension-base/stores'; import AccountProxyStore from '@subwallet/extension-base/stores/AccountProxyStore'; import AccountRefStore from '@subwallet/extension-base/stores/AccountRef'; import ModifyPairStore from '@subwallet/extension-base/stores/ModifyPairStore'; -import { AccountJson, AccountProxyData, AccountProxyMap, AccountProxyStoreData, CurrentAccountInfo, ModifyPairStoreData } from '@subwallet/extension-base/types'; +import { AccountJson, AccountProxy, AccountProxyData, AccountProxyMap, AccountProxyStoreData, AccountProxyType, CurrentAccountInfo, ModifyPairStoreData } from '@subwallet/extension-base/types'; import { isAddressValidWithAuthType, transformAccount } from '@subwallet/extension-base/utils'; import { InjectedAccountWithMeta } from '@subwallet/extension-inject/types'; import { KeyringPair, KeyringPair$Meta } from '@subwallet/keyring/types'; @@ -116,7 +116,7 @@ export class AccountContext { const accountGroups = this.accountProxiesSubject.asObservable(); combineLatest([pairs, modifyPairs, accountGroups]).subscribe(([pairs, modifyPairs, accountGroups]) => { - const result: AccountProxyMap = {}; + const temp: Record> = {}; for (const [address, pair] of Object.entries(pairs)) { const modifyPair = modifyPairs[address]; @@ -126,18 +126,47 @@ export class AccountContext { const accountGroup = accountGroups[modifyPair.accountProxyId]; if (accountGroup) { - if (!result[accountGroup.id]) { - result[accountGroup.id] = { ...accountGroup, accounts: [] }; + if (!temp[accountGroup.id]) { + temp[accountGroup.id] = { ...accountGroup, accounts: [] }; } - result[accountGroup.id].accounts.push(account); + temp[accountGroup.id].accounts.push(account); continue; } } - result[address] = { id: address, name: account.name || account.address, accounts: [account] }; + temp[address] = { id: address, name: account.name || account.address, accounts: [account] }; } + const result: AccountProxyMap = Object.fromEntries( + Object.entries(temp) + .map(([key, value]): [string, AccountProxy] => { + let accountType: AccountProxyType = AccountProxyType.UNKNOWN; + + if (value.accounts.length > 1) { + accountType = AccountProxyType.MULTI; + } else if (value.accounts.length === 1) { + const account = value.accounts[0]; + + if (account.isInjected) { + accountType = AccountProxyType.INJECTED; + } else if (account.isExternal) { + if (account.isHardware) { + accountType = AccountProxyType.LEDGER; + } else if (account.isReadOnly) { + accountType = AccountProxyType.READ_ONLY; + } else { + accountType = AccountProxyType.QR; + } + } else { + accountType = AccountProxyType.SINGLE; + } + } + + return [key, { ...value, accountType }]; + }) + ); + this.accountSubject.next(result); }); } @@ -282,8 +311,25 @@ export class AccountContext { const multiChain = types.length > 1; const proxyId = multiChain ? this.createAccountGroupId(_suri) : ''; + + // Upsert account group first, to avoid combine latest have no account group data. + if (proxyId) { + this.upsertAccountProxy({ id: proxyId, name }); + } + const modifiedPairs = this.modifyPairsSubject.value; + types.forEach((type) => { + const suri = getSuri(_suri, type); + const pair = keyring.createFromUri(suri, {}, type); + const address = pair.address; + + modifiedPairs[address] = { accountProxyId: proxyId || address, migrated: true, key: address }; + }); + + // Upsert modify pair before add account to keyring + this.upsertModifyPairs(modifiedPairs); + types.forEach((type) => { const suri = getSuri(_suri, type); const newAccountName = (() => { @@ -309,10 +355,7 @@ export class AccountContext { const rs = keyring.addUri(suri, { name: newAccountName }, type); const address = rs.pair.address; - modifiedPairs[address] = { accountProxyId: proxyId || address, migrated: true, key: address }; - addressDict[type] = address; - this._addAddressToAuthList(address, isAllowed); if (!changedAccount) { @@ -326,12 +369,6 @@ export class AccountContext { } }); - if (proxyId) { - this.upsertAccountProxy({ id: proxyId, name }); - } - - this.upsertModifyPairs(modifiedPairs); - await new Promise((resolve) => { this.addAccountRef(Object.values(addressDict), () => { resolve(); diff --git a/packages/extension-base/src/types/account/info/keyring.ts b/packages/extension-base/src/types/account/info/keyring.ts index 8d74c001ab..aa5f17e735 100644 --- a/packages/extension-base/src/types/account/info/keyring.ts +++ b/packages/extension-base/src/types/account/info/keyring.ts @@ -1,10 +1,11 @@ // Copyright 2019-2022 @subwallet/extension-base authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; import type { KeyringPair$Meta } from '@subwallet/keyring/types'; import type { KeypairType } from '@polkadot/util-crypto/types'; +import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; + export interface AbstractAddressJson extends KeyringPair$Meta { address: string; type?: KeypairType; @@ -14,12 +15,18 @@ export interface AbstractAddressJson extends KeyringPair$Meta { /** * @interface AccountExternalData + * @prop {boolean} [isMasterAccount] - Is master account - account has seed + * @prop {boolean} [isMasterPassword] - Account has migrated with wallet password * @prop {boolean} [isExternal] - Is external account * @prop {boolean} [isHardware] - Is hardware account * @prop {boolean} [isReadOnly] - Is readonly account * @prop {boolean} [isHidden] - Is hidden account * */ export interface AccountExternalData { + /** Is master account - account has seed */ + isMasterAccount?: boolean; + /** Account has migrated with wallet password */ + isMasterPassword?: boolean; /** Is external account */ isExternal?: boolean; /** Is hardware account */ @@ -78,40 +85,56 @@ export interface AccountDeriveData { suri?: string; } +/** + * Represents the comprehensive metadata associated with an account, combining various aspects of account data. + * This interface extends from multiple specific metadata interfaces to provide a unified view of an account's metadata. + * It includes external, ledger, injected, and derived account data, offering a detailed perspective on the account's characteristics and origins. + * + * @interface AccountMetadataData + * Represents the comprehensive metadata associated with an account. This interface aggregates various aspects of account data to provide a unified view of an account's metadata. It extends from multiple specific metadata interfaces, each covering a different dimension of account information. + * + * @interface AccountMetadataData + * @extends AccountExternalData - Includes data about whether the account is external, hardware, readonly, or hidden. + * @extends AccountLedgerData - Contains information specific to Ledger hardware wallets, such as account index and genesis hash. + * @extends AccountExternalData - Includes data about the account's external status, hardware wallet status, read-only status, and hidden status. + * @extends AccountInjectData - Covers data related to injected accounts, including the source of the injection. + * @extends AccountDeriveData - Holds information about derived accounts, including the parent address and derivation path (suri). + */ +export interface AccountMetadataData extends AccountExternalData, AccountLedgerData, AccountInjectData, AccountDeriveData {} + +export enum AccountSignMode { + PASSWORD = 'password', + QR = 'qr', + LEGACY_LEDGER = 'legacy-ledger', + GENERIC_LEDGER = 'generic-ledger', + READ_ONLY = 'readonly', + ALL_ACCOUNT = 'all', + INJECTED = 'injected', + UNKNOWN = 'unknown' +} + /** * Represents the actions associated with an account. * @interface AccountActionData * @prop {string[]} accountActions - A list of account-specific actions. These could be actions like 'derive', 'export', etc., that are applicable to the account. * @prop {ExtrinsicType[]} transactionActions - A list of transaction types that the account can initiate. This is dependent on the blockchain's supported extrinsic types, such as 'transfer', 'bond', etc. + * @prop {AccountSignMode} signMode - Account sign mode */ export interface AccountActionData { accountActions: string[]; transactionActions: ExtrinsicType[]; + signMode: AccountSignMode; } /** * @interface AccountJson * @extends AbstractAddressJson - * @extends AccountLedgerData - * @extends AccountInjectData - * @extends AccountDeriveData - * @prop {boolean} [isExternal] - Is external account - * @prop {boolean} [isHidden] - Is hidden account - * @prop {boolean} [isInjected] - Is injected account - * @prop {boolean} [isGeneric] - Is generic account - * @prop {boolean} [isMasterAccount] - Is master account - account has seed - * @prop {boolean} [isMasterPassword] - Account has migrated with wallet password - * @prop {boolean} [isReadOnly] - Is readonly account + * @extends AccountMetadataData + * @extends AccountActionData * @prop {boolean} [isSubWallet] - Import from SubWallet * @prop {boolean} [pendingMigrate] - Pending migrate password - * @prop {string} [source] - Account's source - * @prop {string} [suri] - Derivate path * */ -export interface AccountJson extends AbstractAddressJson, AccountExternalData, AccountLedgerData, AccountInjectData, AccountDeriveData, AccountActionData { - /** Is master account - account has seed */ - isMasterAccount?: boolean; - /** Account has migrated with wallet password */ - isMasterPassword?: boolean; +export interface AccountJson extends AbstractAddressJson, AccountMetadataData, AccountActionData { /** Import from SubWallet */ isSubWallet?: boolean; /** Pending migrate password */ diff --git a/packages/extension-base/src/types/account/info/proxy.ts b/packages/extension-base/src/types/account/info/proxy.ts index 5cc0277340..b5ab797ea6 100644 --- a/packages/extension-base/src/types/account/info/proxy.ts +++ b/packages/extension-base/src/types/account/info/proxy.ts @@ -28,6 +28,17 @@ export interface AccountProxyData { */ export type AccountProxyStoreData = Record; +export enum AccountProxyType { + ALL_ACCOUNT = 'all', + SINGLE = 'single-chain', + MULTI = 'multi-chain', + QR = 'qr', + LEDGER = 'ledger', + READ_ONLY = 'readonly', + INJECTED = 'injected', + UNKNOWN = 'unknown' +} + /** * @interface AccountProxy * @extends AccountProxyData - Inherits properties from AccountProxyData. @@ -35,6 +46,7 @@ export type AccountProxyStoreData = Record; */ export interface AccountProxy extends AccountProxyData { accounts: AccountJson[]; + accountType: AccountProxyType; } export type AccountProxyMap = Record diff --git a/packages/extension-base/src/utils/account.ts b/packages/extension-base/src/utils/account.ts index 003414e388..9b895f19ca 100644 --- a/packages/extension-base/src/utils/account.ts +++ b/packages/extension-base/src/utils/account.ts @@ -2,8 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountJson, AddressJson } from '@subwallet/extension-base/types'; +import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; +import { AccountJson, AccountMetadataData, AccountSignMode, AddressJson } from '@subwallet/extension-base/types'; import { reformatAddress } from '@subwallet/extension-base/utils/index'; +import { KeyringPair, KeyringPair$Meta } from '@subwallet/keyring/types'; import { SingleAddress, SubjectInfo } from '@subwallet/ui-keyring/observable/types'; import { decodeAddress, encodeAddress, isAddress, isEthereumAddress } from '@polkadot/util-crypto'; @@ -28,16 +30,67 @@ export const convertSubjectInfoToAddresses = (subjectInfo: SubjectInfo): Address return Object.values(subjectInfo).map((info): AddressJson => ({ address: info.json.address, type: info.type, ...info.json.meta })); }; -export const transformAccount = ({ json: { address, meta }, type }: SingleAddress): AccountJson => { +export const getAccountSignMode = (address: string, _meta?: KeyringPair$Meta): AccountSignMode => { + const meta = _meta as AccountMetadataData; + + if (!address) { + return AccountSignMode.UNKNOWN; + } else { + if (address === ALL_ACCOUNT_KEY) { + return AccountSignMode.ALL_ACCOUNT; + } else { + if (meta.isInjected) { + return AccountSignMode.INJECTED; + } + + if (meta.isExternal) { + if (meta.isHardware) { + if (meta.isGeneric) { + return AccountSignMode.GENERIC_LEDGER; + } else { + return AccountSignMode.LEGACY_LEDGER; + } + } else if (meta.isReadOnly) { + return AccountSignMode.READ_ONLY; + } else { + return AccountSignMode.QR; + } + } else { + return AccountSignMode.PASSWORD; + } + } + } +}; + +export const transformAccount = (account: SingleAddress): AccountJson => { + const { json: { address, meta }, type } = account; + const accountActions: string[] = []; + const transactionActions: ExtrinsicType[] = []; + const signMode = getAccountSignMode(address, meta); + + return { + address, + ...meta, + type, + accountActions, + transactionActions, + signMode + }; +}; + +export const transformAccountFromPair = (account: KeyringPair): AccountJson => { + const { address, meta, type } = account; const accountActions: string[] = []; const transactionActions: ExtrinsicType[] = []; + const signMode = getAccountSignMode(address, meta); return { address, ...meta, type, accountActions, - transactionActions + transactionActions, + signMode }; }; From fa2ffc25f61030aaff319f60502261dcafd1ccab Mon Sep 17 00:00:00 2001 From: S2kael Date: Thu, 25 Jul 2024 18:48:59 +0700 Subject: [PATCH 006/424] [MasterAccount] Update create/import/edit/forget account logic --- .../src/background/KoniTypes.ts | 84 +-- .../extension-base/src/background/types.ts | 13 - .../src/koni/background/handlers/Extension.ts | 477 ++------------ .../src/koni/background/handlers/State.ts | 6 +- .../src/koni/background/handlers/Tabs.ts | 6 +- .../keyring-service/account-context.ts | 604 +++++++++++++++--- packages/extension-base/src/stores/index.ts | 5 +- .../src/types/account/action/add.ts | 14 + .../src/types/account/action/derive.ts | 52 ++ .../src/types/account/action/edit.ts | 12 + .../src/types/account/action/index.ts | 5 + .../extension-base/src/types/account/index.ts | 1 + .../src/types/account/info/current.ts | 4 +- .../src/utils/account/common.ts | 44 ++ .../src/utils/account/derive.ts | 99 +++ .../extension-base/src/utils/account/index.ts | 6 + .../{account.ts => account/transform.ts} | 46 +- packages/extension-base/src/utils/auth.ts | 22 + .../src/Popup/Debugger/DebuggerAPI.tsx | 8 +- .../src/messaging/accounts/create.ts | 3 +- .../src/messaging/accounts/currentAccount.ts | 2 +- .../src/messaging/accounts/derive.ts | 2 +- .../src/messaging/accounts/edit.ts | 4 +- .../src/messaging/accounts/json.ts | 4 +- .../src/messaging/accounts/legacy.ts | 2 +- .../src/messaging/qr-signer/index.ts | 6 +- .../src/stores/utils/index.ts | 8 +- .../extension-koni-ui/src/types/derive.ts | 2 +- .../src/Popup/Debugger/DebuggerAPI.tsx | 8 +- .../src/messaging/accounts/create.ts | 3 +- .../src/messaging/accounts/currentAccount.ts | 2 +- .../src/messaging/accounts/derive.ts | 2 +- .../src/messaging/accounts/json.ts | 4 +- .../src/messaging/accounts/legacy.ts | 2 +- .../src/messaging/qr-signer/index.ts | 6 +- .../src/stores/utils/index.ts | 8 +- packages/extension-web-ui/src/types/derive.ts | 2 +- 37 files changed, 894 insertions(+), 684 deletions(-) create mode 100644 packages/extension-base/src/types/account/action/add.ts create mode 100644 packages/extension-base/src/types/account/action/derive.ts create mode 100644 packages/extension-base/src/types/account/action/edit.ts create mode 100644 packages/extension-base/src/types/account/action/index.ts create mode 100644 packages/extension-base/src/utils/account/common.ts create mode 100644 packages/extension-base/src/utils/account/derive.ts create mode 100644 packages/extension-base/src/utils/account/index.ts rename packages/extension-base/src/utils/{account.ts => account/transform.ts} (52%) diff --git a/packages/extension-base/src/background/KoniTypes.ts b/packages/extension-base/src/background/KoniTypes.ts index d43eeea07e..f8d420e51e 100644 --- a/packages/extension-base/src/background/KoniTypes.ts +++ b/packages/extension-base/src/background/KoniTypes.ts @@ -1,10 +1,6 @@ // Copyright 2019-2022 @polkadot/extension-koni authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { ExtDef } from '@polkadot/types/extrinsic/signedExtensions/types'; -import { SignerResult } from '@polkadot/types/types/extrinsic'; -import { KeypairType } from '@polkadot/util-crypto/types'; -import { HexString } from '@polkadot/util/types'; import { _AssetRef, _AssetType, _ChainAsset, _ChainInfo, _FundStatus, _MultiChainAsset } from '@subwallet/chain-list/types'; import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError'; import { AuthUrls, Resolver } from '@subwallet/extension-base/background/handlers/State'; @@ -15,7 +11,8 @@ import { _ChainState, _EvmApi, _NetworkUpsertParams, _SubstrateApi, _ValidateCus import { CrowdloanContributionsResponse } from '@subwallet/extension-base/services/subscan-service/types'; import { SWTransactionResponse, SWTransactionResult } from '@subwallet/extension-base/services/transaction-service/types'; import { WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; -import { AccountJson, AccountsWithCurrentAddress, AddressJson, BalanceJson, BuyServiceInfo, BuyTokenInfo, CurrentAccountInfo, EarningRewardHistoryItem, EarningRewardJson, EarningStatus, HandleYieldStepParams, LeavePoolAdditionalData, NominationPoolInfo, OptimalYieldPath, OptimalYieldPathParams, RequestEarlyValidateYield, RequestGetYieldPoolTargets, RequestMetadataHash, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseEarlyValidateYield, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseShortenMetadata, StorageDataInterface, SubmitYieldStepData, TokenSpendingApprovalParams, UnlockDotTransactionNft, UnstakingStatus, ValidateYieldProcessParams, YieldPoolInfo, YieldPositionInfo, YieldValidationStatus } from '@subwallet/extension-base/types'; +import { AccountJson, AccountsWithCurrentAddress, AddressJson, BalanceJson, BuyServiceInfo, BuyTokenInfo, CurrentAccountInfo, EarningRewardHistoryItem, EarningRewardJson, EarningStatus, HandleYieldStepParams, LeavePoolAdditionalData, NominationPoolInfo, OptimalYieldPath, OptimalYieldPathParams, RequestAccountCreateSuriV2, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestEarlyValidateYield, RequestGetDeriveAccounts, RequestGetYieldPoolTargets, RequestMetadataHash, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseAccountCreateSuriV2, ResponseDeriveValidateV2, ResponseEarlyValidateYield, ResponseGetDeriveAccounts, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseShortenMetadata, StorageDataInterface, SubmitYieldStepData, TokenSpendingApprovalParams, UnlockDotTransactionNft, UnstakingStatus, ValidateYieldProcessParams, YieldPoolInfo, YieldPositionInfo, YieldValidationStatus } from '@subwallet/extension-base/types'; +import { RequestAccountProxyEdit, RequestAccountProxyForget } from '@subwallet/extension-base/types/account/action/edit'; import { CommonOptimalPath } from '@subwallet/extension-base/types/service-base'; import { SwapErrorType, SwapPair, SwapQuoteResponse, SwapRequest, SwapRequestResult, SwapSubmitParams, SwapTxData, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap'; import { InjectedAccount, InjectedAccountWithMeta, MetadataDefBase } from '@subwallet/extension-inject/types'; @@ -28,6 +25,11 @@ import Web3 from 'web3'; import { RequestArguments, TransactionConfig } from 'web3-core'; import { JsonRpcPayload, JsonRpcResponse } from 'web3-core-helpers'; +import { ExtDef } from '@polkadot/types/extrinsic/signedExtensions/types'; +import { SignerResult } from '@polkadot/types/types/extrinsic'; +import { HexString } from '@polkadot/util/types'; +import { KeypairType } from '@polkadot/util-crypto/types'; + import { TransactionWarning } from './warnings/TransactionWarning'; export enum RuntimeEnvironment { @@ -827,63 +829,8 @@ export type ResponseSeedValidateV2 = ResponseSeedCreateV2 // Create account with suri -export interface RequestAccountCreateSuriV2 { - name: string; - password?: string; - suri: string; - types?: Array; - isAllowed: boolean; -} - -export type ResponseAccountCreateSuriV2 = Record - // Create derive account -export interface RequestDeriveCreateV2 { - name: string; - genesisHash?: string | null; - suri: string; - parentAddress: string; - isAllowed: boolean; -} - -export interface CreateDeriveAccountInfo { - name: string; - suri: string; -} - -export interface RequestDeriveCreateV3 { - address: string; -} - -export interface RequestDeriveCreateMultiple { - parentAddress: string; - isAllowed: boolean; - items: CreateDeriveAccountInfo[]; -} - -export interface DeriveAccountInfo { - address: string; - suri: string; -} - -export interface RequestDeriveValidateV2 { - suri: string; - parentAddress: string; -} - -export type ResponseDeriveValidateV2 = DeriveAccountInfo; - -export interface RequestGetDeriveAccounts { - page: number; - limit: number; - parentAddress: string; -} - -export interface ResponseGetDeriveAccounts { - result: DeriveAccountInfo[]; -} - // Restore account with json file (single account) export interface RequestJsonRestoreV2 { @@ -2138,22 +2085,21 @@ export interface KoniRequestSignatures { 'pri(accounts.inject.add)': [RequestAddInjectedAccounts, boolean]; 'pri(accounts.inject.remove)': [RequestRemoveInjectedAccounts, boolean]; - // Derive - 'pri(derivation.createV2)': [RequestDeriveCreateV2, boolean]; // Substrate - // Restore by json - 'pri(json.restoreV2)': [RequestJsonRestoreV2, void]; - 'pri(json.batchRestoreV2)': [RequestBatchRestoreV2, void]; + 'pri(accounts.json.restoreV2)': [RequestJsonRestoreV2, void]; + 'pri(accounts.json.batchRestoreV2)': [RequestBatchRestoreV2, void]; // Export account 'pri(accounts.batchExportV2)': [RequestAccountBatchExportV2, ResponseAccountBatchExportV2]; 'pri(accounts.exportPrivateKey)': [RequestAccountExportPrivateKey, ResponseAccountExportPrivateKey]; // Current account - 'pri(accounts.subscribeWithCurrentAddress)': [RequestAccountSubscribe, AccountsWithCurrentAddress, AccountsWithCurrentAddress]; - 'pri(accounts.updateCurrentAddress)': [string, boolean]; // old - 'pri(currentAccount.saveAddress)': [RequestCurrentAccountAddress, CurrentAccountInfo]; - 'pri(accounts.get.meta)': [RequestAccountMeta, ResponseAccountMeta]; + 'pri(accounts.subscribeWithCurrentProxy)': [RequestAccountSubscribe, AccountsWithCurrentAddress, AccountsWithCurrentAddress]; + 'pri(accounts.saveCurrentProxy)': [RequestCurrentAccountAddress, CurrentAccountInfo]; + + // Edit account + 'pri(accounts.edit)': [RequestAccountProxyEdit, boolean]; + 'pri(accounts.forget)': [RequestAccountProxyForget, boolean]; // Address book 'pri(accounts.saveRecent)': [RequestSaveRecentAccount, KeyringAddress]; diff --git a/packages/extension-base/src/background/types.ts b/packages/extension-base/src/background/types.ts index 9a262eb0f4..fb79a033f8 100644 --- a/packages/extension-base/src/background/types.ts +++ b/packages/extension-base/src/background/types.ts @@ -87,10 +87,8 @@ export interface RequestSignatures extends KoniRequestSignatures { 'pri(ping)': [null, string]; 'pri(accounts.create.hardware)': [RequestAccountCreateHardware, boolean]; 'pri(accounts.create.suri)': [RequestAccountCreateSuri, boolean]; - 'pri(accounts.edit)': [RequestAccountEdit, boolean]; 'pri(accounts.export)': [RequestAccountExport, ResponseAccountExport]; 'pri(accounts.batchExport)': [RequestAccountBatchExport, ResponseAccountsExport] - 'pri(accounts.forget)': [RequestAccountForget, boolean]; 'pri(accounts.show)': [RequestAccountShow, boolean]; 'pri(accounts.tie)': [RequestAccountTie, boolean]; 'pri(accounts.subscribe)': [RequestAccountSubscribe, AccountJson[], AccountJson[]]; @@ -224,17 +222,6 @@ export interface RequestAccountChangePassword { newPass: string; } -export interface RequestAccountEdit { - address: string; - genesisHash?: string | null; - name: string; -} - -export interface RequestAccountForget { - address: string; - lockAfter: boolean; -} - export interface RequestAccountShow { address: string; isShowing: boolean; diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index bc4eb04f87..ca36a60ca5 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -7,8 +7,8 @@ import { _AssetRef, _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError'; import { withErrorLog } from '@subwallet/extension-base/background/handlers/helpers'; import { createSubscription } from '@subwallet/extension-base/background/handlers/subscriptions'; -import { AccountExternalError, AddressBookInfo, AmountData, AmountDataWithId, AssetSetting, AssetSettingUpdateReq, BasicTxErrorType, BondingOptionParams, BrowserConfirmationType, CampaignBanner, CampaignData, CampaignDataType, ChainType, CreateDeriveAccountInfo, CronReloadRequest, CrowdloanJson, DeriveAccountInfo, ExternalRequestPromiseStatus, ExtrinsicType, KeyringState, MantaPayEnableMessage, MantaPayEnableParams, MantaPayEnableResponse, MantaPaySyncState, MetadataItem, NftCollection, NftJson, NftTransactionRequest, NftTransactionResponse, OptionInputAddress, PriceJson, RequestAccountBatchExportV2, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateSuriV2, RequestAccountCreateWithSecretKey, RequestAccountExportPrivateKey, RequestAccountMeta, RequestAddInjectedAccounts, RequestApproveConnectWalletSession, RequestApproveWalletConnectNotSupport, RequestAuthorization, RequestAuthorizationBlock, RequestAuthorizationPerAccount, RequestAuthorizationPerSite, RequestAuthorizeApproveV2, RequestBatchRestoreV2, RequestBondingSubmit, RequestCameraSettings, RequestCampaignBannerComplete, RequestChangeEnableChainPatrol, RequestChangeLanguage, RequestChangeMasterPassword, RequestChangePriceCurrency, RequestChangeShowBalance, RequestChangeShowZeroBalance, RequestChangeTimeAutoLock, RequestCheckPublicAndSecretKey, RequestConfirmationComplete, RequestConnectWalletConnect, RequestCrossChainTransfer, RequestCrowdloanContributions, RequestDeleteContactAccount, RequestDeriveCreateMultiple, RequestDeriveCreateV2, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestDisconnectWalletConnectSession, RequestEditContactAccount, RequestFindRawMetadata, RequestForgetSite, RequestFreeBalance, RequestGetDeriveAccounts, RequestGetTransaction, RequestJsonRestoreV2, RequestKeyringExportMnemonic, RequestMaxTransferable, RequestMigratePassword, RequestParseEvmContractInput, RequestParseTransactionSubstrate, RequestPassPhishingPage, RequestQrParseRLP, RequestQrSignEvm, RequestQrSignSubstrate, RequestRejectConnectWalletSession, RequestRejectExternalRequest, RequestRejectWalletConnectNotSupport, RequestRemoveInjectedAccounts, RequestResetWallet, RequestResolveExternalRequest, RequestSaveRecentAccount, RequestSeedCreateV2, RequestSeedValidateV2, RequestSettingsType, RequestSigningApprovePasswordV2, RequestStakePoolingBonding, RequestStakePoolingUnbonding, RequestSubscribeHistory, RequestSubstrateNftSubmitTransaction, RequestTransfer, RequestTuringCancelStakeCompound, RequestTuringStakeCompound, RequestUnbondingSubmit, RequestUnlockKeyring, RequestUnlockType, ResolveAddressToDomainRequest, ResolveDomainRequest, ResponseAccountBatchExportV2, ResponseAccountCreateSuriV2, ResponseAccountCreateWithSecretKey, ResponseAccountExportPrivateKey, ResponseAccountMeta, ResponseChangeMasterPassword, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseFindRawMetadata, ResponseGetDeriveAccounts, ResponseKeyringExportMnemonic, ResponseMigratePassword, ResponseParseEvmContractInput, ResponseParseTransactionSubstrate, ResponsePrivateKeyValidateV2, ResponseQrParseRLP, ResponseQrSignEvm, ResponseQrSignSubstrate, ResponseRejectExternalRequest, ResponseResetWallet, ResponseResolveExternalRequest, ResponseSeedCreateV2, ResponseSeedValidateV2, ResponseSubscribeHistory, ResponseUnlockKeyring, ShowCampaignPopupRequest, StakingJson, StakingRewardJson, StakingTxErrorType, StakingType, ThemeNames, TransactionHistoryItem, TransactionResponse, ValidateNetworkRequest, ValidateNetworkResponse, ValidatorInfo } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountAuthType, AuthorizeRequest, MessageTypes, MetadataRequest, RequestAccountChangePassword, RequestAccountCreateHardware, RequestAccountCreateSuri, RequestAccountEdit, RequestAccountExport, RequestAccountForget, RequestAccountShow, RequestAccountTie, RequestAccountValidate, RequestAuthorizeCancel, RequestAuthorizeReject, RequestBatchRestore, RequestCurrentAccountAddress, RequestDeriveCreate, RequestDeriveValidate, RequestJsonRestore, RequestMetadataApprove, RequestMetadataReject, RequestSeedCreate, RequestSeedValidate, RequestSigningApproveSignature, RequestSigningCancel, RequestTypes, ResponseAccountExport, ResponseAuthorizeList, ResponseDeriveValidate, ResponseJsonGetAccountInfo, ResponseSeedCreate, ResponseSeedValidate, ResponseType, SigningRequest, WindowOpenParams } from '@subwallet/extension-base/background/types'; +import { AccountExternalError, AddressBookInfo, AmountData, AmountDataWithId, AssetSetting, AssetSettingUpdateReq, BasicTxErrorType, BondingOptionParams, BrowserConfirmationType, CampaignBanner, CampaignData, CampaignDataType, ChainType, CronReloadRequest, CrowdloanJson, ExternalRequestPromiseStatus, ExtrinsicType, KeyringState, MantaPayEnableMessage, MantaPayEnableParams, MantaPayEnableResponse, MantaPaySyncState, MetadataItem, NftCollection, NftJson, NftTransactionRequest, NftTransactionResponse, OptionInputAddress, PriceJson, RequestAccountBatchExportV2, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateWithSecretKey, RequestAccountExportPrivateKey, RequestAddInjectedAccounts, RequestApproveConnectWalletSession, RequestApproveWalletConnectNotSupport, RequestAuthorization, RequestAuthorizationBlock, RequestAuthorizationPerAccount, RequestAuthorizationPerSite, RequestAuthorizeApproveV2, RequestBatchRestoreV2, RequestBondingSubmit, RequestCameraSettings, RequestCampaignBannerComplete, RequestChangeEnableChainPatrol, RequestChangeLanguage, RequestChangeMasterPassword, RequestChangePriceCurrency, RequestChangeShowBalance, RequestChangeShowZeroBalance, RequestChangeTimeAutoLock, RequestCheckPublicAndSecretKey, RequestConfirmationComplete, RequestConnectWalletConnect, RequestCrossChainTransfer, RequestCrowdloanContributions, RequestDeleteContactAccount, RequestDisconnectWalletConnectSession, RequestEditContactAccount, RequestFindRawMetadata, RequestForgetSite, RequestFreeBalance, RequestGetTransaction, RequestJsonRestoreV2, RequestKeyringExportMnemonic, RequestMaxTransferable, RequestMigratePassword, RequestParseEvmContractInput, RequestParseTransactionSubstrate, RequestPassPhishingPage, RequestQrParseRLP, RequestQrSignEvm, RequestQrSignSubstrate, RequestRejectConnectWalletSession, RequestRejectExternalRequest, RequestRejectWalletConnectNotSupport, RequestRemoveInjectedAccounts, RequestResetWallet, RequestResolveExternalRequest, RequestSaveRecentAccount, RequestSeedCreateV2, RequestSeedValidateV2, RequestSettingsType, RequestSigningApprovePasswordV2, RequestStakePoolingBonding, RequestStakePoolingUnbonding, RequestSubscribeHistory, RequestSubstrateNftSubmitTransaction, RequestTransfer, RequestTuringCancelStakeCompound, RequestTuringStakeCompound, RequestUnbondingSubmit, RequestUnlockKeyring, RequestUnlockType, ResolveAddressToDomainRequest, ResolveDomainRequest, ResponseAccountBatchExportV2, ResponseAccountCreateWithSecretKey, ResponseAccountExportPrivateKey, ResponseChangeMasterPassword, ResponseCheckPublicAndSecretKey, ResponseFindRawMetadata, ResponseKeyringExportMnemonic, ResponseMigratePassword, ResponseParseEvmContractInput, ResponseParseTransactionSubstrate, ResponsePrivateKeyValidateV2, ResponseQrParseRLP, ResponseQrSignEvm, ResponseQrSignSubstrate, ResponseRejectExternalRequest, ResponseResetWallet, ResponseResolveExternalRequest, ResponseSeedCreateV2, ResponseSeedValidateV2, ResponseSubscribeHistory, ResponseUnlockKeyring, ShowCampaignPopupRequest, StakingJson, StakingRewardJson, StakingTxErrorType, StakingType, ThemeNames, TransactionHistoryItem, TransactionResponse, ValidateNetworkRequest, ValidateNetworkResponse, ValidatorInfo } from '@subwallet/extension-base/background/KoniTypes'; +import { AccountAuthType, AuthorizeRequest, MessageTypes, MetadataRequest, RequestAccountChangePassword, RequestAccountCreateHardware, RequestAccountCreateSuri, RequestAccountExport, RequestAccountShow, RequestAccountTie, RequestAccountValidate, RequestAuthorizeCancel, RequestAuthorizeReject, RequestBatchRestore, RequestCurrentAccountAddress, RequestDeriveCreate, RequestDeriveValidate, RequestJsonRestore, RequestMetadataApprove, RequestMetadataReject, RequestSeedCreate, RequestSeedValidate, RequestSigningApproveSignature, RequestSigningCancel, RequestTypes, ResponseAccountExport, ResponseAuthorizeList, ResponseDeriveValidate, ResponseJsonGetAccountInfo, ResponseSeedCreate, ResponseSeedValidate, ResponseType, SigningRequest, WindowOpenParams } from '@subwallet/extension-base/background/types'; import { TransactionWarning } from '@subwallet/extension-base/background/warnings/TransactionWarning'; import { ALL_ACCOUNT_KEY, LATEST_SESSION, XCM_FEE_RATIO } from '@subwallet/extension-base/constants'; import { additionalValidateTransfer, additionalValidateXcmTransfer, validateTransferRequest, validateXcmTransferRequest } from '@subwallet/extension-base/core/logic-validation/transfer'; @@ -41,14 +41,14 @@ import { isProposalExpired, isSupportWalletConnectChain, isSupportWalletConnectN import { ResultApproveWalletConnectSession, WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; import { SWStorage } from '@subwallet/extension-base/storage'; import { AccountsStore } from '@subwallet/extension-base/stores'; -import { AccountProxy, AccountProxyType, AccountsWithCurrentAddress, BalanceJson, BuyServiceInfo, BuyTokenInfo, CurrentAccountInfo, EarningRewardJson, NominationPoolInfo, OptimalYieldPathParams, RequestEarlyValidateYield, RequestGetYieldPoolTargets, RequestMetadataHash, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseShortenMetadata, StorageDataInterface, TokenSpendingApprovalParams, ValidateYieldProcessParams, YieldPoolType } from '@subwallet/extension-base/types'; +import { AccountProxy, AccountProxyType, AccountsWithCurrentAddress, BalanceJson, BuyServiceInfo, BuyTokenInfo, EarningRewardJson, NominationPoolInfo, OptimalYieldPathParams, RequestAccountCreateSuriV2, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestEarlyValidateYield, RequestGetDeriveAccounts, RequestGetYieldPoolTargets, RequestMetadataHash, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseAccountCreateSuriV2, ResponseDeriveValidateV2, ResponseGetDeriveAccounts, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseShortenMetadata, StorageDataInterface, TokenSpendingApprovalParams, ValidateYieldProcessParams, YieldPoolType } from '@subwallet/extension-base/types'; +import { RequestAccountProxyEdit, RequestAccountProxyForget } from '@subwallet/extension-base/types/account/action/edit'; import { CommonOptimalPath } from '@subwallet/extension-base/types/service-base'; import { SwapPair, SwapQuoteResponse, SwapRequest, SwapRequestResult, SwapSubmitParams, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap'; -import { BN_ZERO, convertSubjectInfoToAddresses, createTransactionFromRLP, isSameAddress, MODULE_SUPPORT, reformatAddress, signatureToHex, Transaction as QrTransaction, transformAccounts, uniqueStringArray } from '@subwallet/extension-base/utils'; +import { BN_ZERO, createTransactionFromRLP, isSameAddress, MODULE_SUPPORT, reformatAddress, signatureToHex, Transaction as QrTransaction, transformAccounts, uniqueStringArray } from '@subwallet/extension-base/utils'; import { parseContractInput, parseEvmRlp } from '@subwallet/extension-base/utils/eth/parseTransaction'; import { metadataExpand } from '@subwallet/extension-chains'; import { MetadataDef } from '@subwallet/extension-inject/types'; -import { createPair } from '@subwallet/keyring'; import { KeyringPair, KeyringPair$Json, KeyringPair$Meta } from '@subwallet/keyring/types'; import { keyring } from '@subwallet/ui-keyring'; import { SubjectInfo } from '@subwallet/ui-keyring/observable/types'; @@ -65,9 +65,9 @@ import { SubmittableExtrinsic } from '@polkadot/api/types'; import { Metadata, TypeRegistry } from '@polkadot/types'; import { ChainProperties } from '@polkadot/types/interfaces'; import { Registry, SignerPayloadJSON, SignerPayloadRaw } from '@polkadot/types/types'; -import { assert, hexStripPrefix, hexToU8a, isAscii, isHex, u8aToHex, u8aToString } from '@polkadot/util'; -import { base64Decode, decodeAddress, isAddress, isEthereumAddress, jsonDecrypt, keyExtractSuri, mnemonicGenerate, mnemonicValidate } from '@polkadot/util-crypto'; -import { EncryptedJson, KeypairType, Prefix } from '@polkadot/util-crypto/types'; +import { assert, hexStripPrefix, hexToU8a, isAscii, isHex, u8aToHex } from '@polkadot/util'; +import { decodeAddress, isAddress, isEthereumAddress, keyExtractSuri, mnemonicGenerate, mnemonicValidate } from '@polkadot/util-crypto'; +import { KeypairType } from '@polkadot/util-crypto/types'; const ETH_DERIVE_DEFAULT = '/m/44\'/60\'/0\'/0/0'; @@ -177,14 +177,8 @@ export default class KoniExtension { return true; } - private accountsEdit ({ address, name }: RequestAccountEdit): boolean { - const pair = keyring.getPair(address); - - assert(pair, t('Unable to find account')); - - keyring.saveAccountMeta(pair, { ...pair.meta, name }); - - return true; + private accountsEdit (request: RequestAccountProxyEdit): boolean { + return this.#koniState.keyringService.context.accountsEdit(request); } private accountsExport ({ address, password }: RequestAccountExport): ResponseAccountExport { @@ -452,14 +446,6 @@ export default class KoniExtension { this.#koniState.createUnsubscriptionHandle(id, unsubscribe); } - public decodeAddress = (key: string | Uint8Array, ignoreChecksum?: boolean, ss58Format?: Prefix): Uint8Array => { - return keyring.decodeAddress(key, ignoreChecksum, ss58Format); - }; - - public encodeAddress = (key: string | Uint8Array, ss58Format?: Prefix): string => { - return keyring.encodeAddress(key, ss58Format); - }; - private accountExportPrivateKey ({ address, password }: RequestAccountExportPrivateKey): ResponseAccountExportPrivateKey { return this.#koniState.accountExportPrivateKey({ address, password }); @@ -470,7 +456,7 @@ export default class KoniExtension { } private async accountsGetAllWithCurrentAddress (id: string, port: chrome.runtime.Port): Promise { - const cb = createSubscription<'pri(accounts.subscribeWithCurrentAddress)'>(id, port); + const cb = createSubscription<'pri(accounts.subscribeWithCurrentProxy)'>(id, port); const keyringService = this.#koniState.keyringService; await this.#koniState.eventService.waitAccountReady; @@ -481,7 +467,7 @@ export default class KoniExtension { const transformedAccounts = Object.values(accounts); const responseData: AccountsWithCurrentAddress = { accounts: transformedAccounts?.length ? [{ ...ACCOUNT_ALL_GROUP }, ...transformedAccounts] : [], - currentAddress: currentAccount?.address + currentAccountProxy: currentAccount?.address }; const accountGroups = keyringService.context.accountSubject; @@ -491,7 +477,7 @@ export default class KoniExtension { const transformedAccounts = Object.values(accountGroups); responseData.accounts = transformedAccounts?.length ? [{ ...ACCOUNT_ALL_GROUP }, ...transformedAccounts] : []; - responseData.currentAddress = currentAccount?.address; + responseData.currentAccountProxy = currentAccount?.address; console.debug('subscriptionAccountGroups', responseData); cb(responseData); @@ -532,7 +518,7 @@ export default class KoniExtension { let old = ''; const subscription = this.#koniState.keyringService.context.contactSubject.subscribe((subjectInfo: SubjectInfo): void => { - const addresses = convertSubjectInfoToAddresses(subjectInfo); + const addresses = transformAccounts(subjectInfo); const _new = JSON.stringify(addresses); if (old !== _new) { @@ -553,7 +539,7 @@ export default class KoniExtension { const subjectInfo = this.#koniState.keyringService.context.contacts; return { - addresses: convertSubjectInfoToAddresses(subjectInfo) + addresses: transformAccounts(subjectInfo) }; } @@ -1069,32 +1055,10 @@ export default class KoniExtension { return await this.#koniState.getAuthList(); } - private _saveCurrentAccountAddress (address: string, callback?: (data: CurrentAccountInfo) => void) { - let accountInfo = this.#koniState.keyringService.context.currentAccount; - - if (!accountInfo) { - accountInfo = { - address - }; - } else { - accountInfo.address = address; - } - - this.#koniState.setCurrentAccount(accountInfo, () => { - callback && callback(accountInfo); - }); - } - - private updateCurrentAccountAddress (address: string): boolean { - this._saveCurrentAccountAddress(address); - - return true; - } - - private async saveCurrentAccountAddress (data: RequestCurrentAccountAddress): Promise { - return new Promise((resolve) => { - this._saveCurrentAccountAddress(data.address, (currentInfo) => { - resolve(currentInfo); + private async saveCurrentAccountAddress (data: RequestCurrentAccountAddress): Promise { + return new Promise((resolve) => { + this.#koniState.keyringService.context._setCurrentAccount({ address: data.address }, () => { + resolve(true); }); }); } @@ -1206,72 +1170,8 @@ export default class KoniExtension { return this.getCrowdloan(true); } - private validatePassword (json: KeyringPair$Json, password: string): boolean { - const cryptoType = Array.isArray(json.encoding.content) ? json.encoding.content[1] : 'ed25519'; - const encType = Array.isArray(json.encoding.type) ? json.encoding.type : [json.encoding.type]; - const pair = createPair( - { toSS58: this.encodeAddress, type: cryptoType as KeypairType }, - { publicKey: this.decodeAddress(json.address, true) }, - json.meta, - isHex(json.encoded) ? hexToU8a(json.encoded) : base64Decode(json.encoded), - encType - ); - - // unlock then lock (locking cleans secretKey, so needs to be last) - try { - pair.decodePkcs8(password); - pair.lock(); - - return true; - } catch (e) { - console.error(e); - - return false; - } - } - - private validatedAccountsPassword (json: EncryptedJson, password: string): boolean { - try { - u8aToString(jsonDecrypt(json, password)); - - return true; - } catch (e) { - return false; - } - } - - private _addAddressToAuthList (address: string, isAllowed: boolean): void { - this.#koniState.getAuthorize((value) => { - if (value && Object.keys(value).length) { - Object.keys(value).forEach((url) => { - if (this.isAddressValidWithAuthType(address, value[url].accountAuthType)) { - value[url].isAllowedMap[address] = isAllowed; - } - }); - - this.#koniState.setAuthorize(value); - } - }); - } - - private _addAddressesToAuthList (addresses: string[], isAllowed: boolean): void { - this.#koniState.getAuthorize((value) => { - if (value && Object.keys(value).length) { - Object.keys(value).forEach((url) => { - addresses.forEach((address) => { - if (this.isAddressValidWithAuthType(address, value[url].accountAuthType)) { - value[url].isAllowedMap[address] = isAllowed; - } - }); - });/**/ - - this.#koniState.setAuthorize(value); - } - }); - } - - private async accountsCreateSuriV2 (request: RequestAccountCreateSuriV2): Promise { - const addressDict = await this.#koniState.keyringService.context.accountsCreateSuriV2(request); + private accountsCreateSuriV2 (request: RequestAccountCreateSuriV2): ResponseAccountCreateSuriV2 { + const addressDict = this.#koniState.keyringService.context.accountsCreateSuriV2(request); if (this.#alwaysLock) { this.keyringLock(); @@ -1280,20 +1180,17 @@ export default class KoniExtension { return addressDict; } - private async accountsForgetOverride ({ address, lockAfter }: RequestAccountForget): Promise { - keyring.forgetAccount(address); - await new Promise((resolve) => { - this.#koniState.removeAccountRef(address, () => { - resolve(); - }); - }); + private async accountsForgetOverride (request: RequestAccountProxyForget): Promise { + const addresses = await this.#koniState.keyringService.context.accountProxyForget(request); // Remove from auth list await new Promise((resolve) => { this.#koniState.getAuthorize((value) => { if (value && Object.keys(value).length) { Object.keys(value).forEach((url) => { - delete value[url].isAllowedMap[address]; + for (const address of addresses) { + delete value[url].isAllowedMap[address]; + } }); this.#koniState.setAuthorize(value, resolve); @@ -1303,19 +1200,11 @@ export default class KoniExtension { }); }); - // Set current account to all account - await new Promise((resolve) => { - // const currentAccountInfo = this.#koniState.keyringService.context.currentAccount; - - this.#koniState.setCurrentAccount({ - // currentGenesisHash: currentAccountInfo?.allGenesisHash || null, - address: ALL_ACCOUNT_KEY - }, resolve); - }); - - await this.#koniState.disableMantaPay(address); + for (const address of addresses) { + await this.#koniState.disableMantaPay(address); + } - if (lockAfter) { + if (request.lockAfter) { this.checkLockAfterMigrate(); } @@ -1387,91 +1276,16 @@ export default class KoniExtension { } } - private deriveV2 (parentAddress: string, suri: string, metadata: KeyringPair$Meta): KeyringPair { - const parentPair = keyring.getPair(parentAddress); - - if (parentPair.isLocked) { - keyring.unlockPair(parentPair.address); - } + private jsonRestoreV2 (request: RequestJsonRestoreV2): void { + this.#koniState.keyringService.context.jsonRestoreV2(request); - try { - return parentPair.derive(suri, metadata); - } catch (err) { - throw new Error(t('"{{suri}}" is not a valid derivation path', { replace: { suri } })); - } - } - - private derivationCreateV2 ({ genesisHash, - isAllowed, - name, - parentAddress, - suri }: RequestDeriveCreateV2): boolean { - const childPair = this.deriveV2(parentAddress, suri, { - genesisHash, - name, - parentAddress, - suri - }); - - const address = childPair.address; - - this._saveCurrentAccountAddress(address, () => { - keyring.addPair(childPair, true); - this._addAddressToAuthList(address, isAllowed); - }); - - return true; - } - - private jsonRestoreV2 ({ address, file, isAllowed, password, withMasterPassword }: RequestJsonRestoreV2): void { - const isPasswordValidated = this.validatePassword(file, password); - - if (isPasswordValidated) { - try { - this._saveCurrentAccountAddress(address, () => { - const newAccount = keyring.restoreAccount(file, password, withMasterPassword); - - // genesisHash is not used in SubWallet => reset it to empty string - if (newAccount.meta?.genesisHash && newAccount.meta?.genesisHash !== '') { - keyring.saveAccountMeta(newAccount, { ...newAccount.meta, genesisHash: '' }); - } - - this._addAddressToAuthList(address, isAllowed); - }); - - if (this.#alwaysLock) { - this.keyringLock(); - } - } catch (error) { - throw new Error((error as Error).message); - } - } else { - throw new Error(t('Wrong password')); + if (this.#alwaysLock) { + this.keyringLock(); } } - private batchRestoreV2 ({ accountsInfo, file, isAllowed, password }: RequestBatchRestoreV2): void { - const addressList: string[] = accountsInfo.map((acc) => acc.address); - const isPasswordValidated = this.validatedAccountsPassword(file, password); - - if (isPasswordValidated) { - try { - this._saveCurrentAccountAddress(ALL_ACCOUNT_KEY, () => { - keyring.restoreAccounts(file, password); - - this.#koniState.keyringService.context.removeNoneHardwareGenesisHash(); - this._addAddressesToAuthList(addressList, isAllowed); - }); - - // if (this.#alwaysLock) { - // this.keyringLock(); - // } - } catch (error) { - throw new Error((error as Error).message); - } - } else { - throw new Error(t('Wrong password')); - } + private batchRestoreV2 (request: RequestBatchRestoreV2): void { + this.#koniState.keyringService.context.batchRestoreV2(request); } private async batchExportV2 ({ addresses, password }: RequestAccountBatchExportV2): Promise { @@ -2099,16 +1913,6 @@ export default class KoniExtension { return true; } - private getAccountMeta ({ address }: RequestAccountMeta): ResponseAccountMeta { - const pair = keyring.getPair(address); - - assert(pair, t('Unable to find account')); - - return { - meta: pair.meta - }; - } - private accountsTie2 ({ address, genesisHash }: RequestAccountTie): boolean { return this.#koniState.setAccountTie(address, genesisHash); } @@ -2902,186 +2706,26 @@ export default class KoniExtension { /// Derive account - private derivationCreateMultiple ({ isAllowed, items, parentAddress }: RequestDeriveCreateMultiple): boolean { - const parentPair = keyring.getPair(parentAddress); - const isEvm = parentPair.type === 'ethereum'; - - if (parentPair.isLocked) { - keyring.unlockPair(parentPair.address); - } - - const createChild = ({ name, suri }: CreateDeriveAccountInfo): KeyringPair => { - const meta: KeyringPair$Meta = { - name: name, - parentAddress - }; - - if (isEvm) { - let index = 0; - - try { - const reg = /^\d+$/; - const path = suri.split('//')[1]; - - if (reg.test(path)) { - index = parseInt(path); - } - } catch (e) { - - } - - if (!index) { - throw Error(t('Invalid derive path')); - } - - meta.suri = `//${index}`; - - return parentPair.deriveEvm(index, meta); - } else { - meta.suri = suri; - - return parentPair.derive(suri, meta); - } - }; - - const result: KeyringPair[] = []; - - for (const item of items) { - try { - const childPair = createChild(item); - const address = childPair.address; - - keyring.addPair(childPair, true); - this._addAddressToAuthList(address, isAllowed); - result.push(childPair); - } catch (e) { - console.log(e); - } - } - - if (result.length === 1) { - this._saveCurrentAccountAddress(result[0].address); - } else { - this.#koniState.setCurrentAccount({ address: ALL_ACCOUNT_KEY }); - } - - return true; + private derivationCreateMultiple (request: RequestDeriveCreateMultiple): boolean { + return this.#koniState.keyringService.context.derivationCreateMultiple(request); } - private derivationCreateV3 ({ address: parentAddress }: RequestDeriveCreateV3): boolean { - const parentPair = keyring.getPair(parentAddress); - const isEvm = parentPair.type === 'ethereum'; - - if (parentPair.isLocked) { - keyring.unlockPair(parentPair.address); - } - - const pairs = keyring.getPairs(); - const children = pairs.filter((p) => p.meta.parentAddress === parentAddress); - const name = `Account ${pairs.length}`; - - let index = isEvm ? 1 : 0; - let valid = false; - - do { - const exist = children.find((p) => p.meta.suri === `//${index}`); - - if (exist) { - index++; - } else { - valid = true; - } - } while (!valid); - - const meta = { - name, - parentAddress, - suri: `//${index}` - }; - const childPair = isEvm ? parentPair.deriveEvm(index, meta) : parentPair.derive(meta.suri, meta); - const address = childPair.address; - - this._saveCurrentAccountAddress(address, () => { - keyring.addPair(childPair, true); - this._addAddressToAuthList(address, true); - }); + private derivationCreateV3 (request: RequestDeriveCreateV3): boolean { + const rs = this.#koniState.keyringService.context.derivationCreateV3(request); if (this.#alwaysLock) { this.keyringLock(); } - return true; + return rs; } - private validateDerivePath ({ parentAddress, suri }: RequestDeriveValidateV2): ResponseDeriveValidateV2 { - const parentPair = keyring.getPair(parentAddress); - const isEvm = parentPair.type === 'ethereum'; - - if (parentPair.isLocked) { - keyring.unlockPair(parentPair.address); - } - - const meta: KeyringPair$Meta = { - parentAddress - }; - - let childPair: KeyringPair; - - if (isEvm) { - let index = 0; - - try { - const reg = /^\d+$/; - const path = suri.split('//')[1]; - - if (reg.test(path)) { - index = parseInt(path); - } - } catch (e) { - - } - - if (!index) { - throw Error(t('Invalid derive path')); - } - - meta.suri = `//${index}`; - - childPair = parentPair.deriveEvm(index, meta); - } else { - meta.suri = suri; - childPair = parentPair.derive(suri, meta); - } - - return { - address: childPair.address, - suri: meta.suri as string - }; + private validateDerivePath (request: RequestDeriveValidateV2): ResponseDeriveValidateV2 { + return this.#koniState.keyringService.context.validateDerivePath(request); } - private getListDeriveAccounts ({ limit, page, parentAddress }: RequestGetDeriveAccounts): ResponseGetDeriveAccounts { - const parentPair = keyring.getPair(parentAddress); - const isEvm = parentPair.type === 'ethereum'; - - if (parentPair.isLocked) { - keyring.unlockPair(parentPair.address); - } - - const start = (page - 1) * limit + (isEvm ? 1 : 0); - const end = start + limit; - - const result: DeriveAccountInfo[] = []; - - for (let i = start; i < end; i++) { - const suri = `//${i}`; - const pair = isEvm ? parentPair.deriveEvm(i, {}) : parentPair.derive(suri, {}); - - result.push({ address: pair.address, suri: suri }); - } - - return { - result: result - }; + private getListDeriveAccounts (request: RequestGetDeriveAccounts): ResponseGetDeriveAccounts { + return this.#koniState.keyringService.context.getListDeriveAccounts(request); } // ChainService ------------------------------------------------- @@ -4295,14 +3939,6 @@ export default class KoniExtension { return this.getCrowdloanContributions(request as RequestCrowdloanContributions); case 'pri(crowdloan.getSubscription)': return this.subscribeCrowdloan(id, port); - case 'pri(derivation.createV2)': - return this.derivationCreateV2(request as RequestDeriveCreateV2); - case 'pri(accounts.batchExportV2)': - return this.batchExportV2(request as RequestAccountBatchExportV2); - case 'pri(json.restoreV2)': - return this.jsonRestoreV2(request as RequestJsonRestoreV2); - case 'pri(json.batchRestoreV2)': - return this.batchRestoreV2(request as RequestBatchRestoreV2); case 'pri(nft.getNft)': return await this.getNft(); case 'pri(nft.getSubscription)': @@ -4378,7 +4014,7 @@ export default class KoniExtension { /* Account management */ // Add account case 'pri(accounts.create.suriV2)': - return await this.accountsCreateSuriV2(request as RequestAccountCreateSuriV2); + return this.accountsCreateSuriV2(request as RequestAccountCreateSuriV2); case 'pri(accounts.create.externalV2)': return await this.accountsCreateExternalV2(request as RequestAccountCreateExternalV2); case 'pri(accounts.create.hardwareV2)': @@ -4387,12 +4023,16 @@ export default class KoniExtension { return await this.accountsCreateHardwareMultiple(request as RequestAccountCreateHardwareMultiple); case 'pri(accounts.create.withSecret)': return await this.accountsCreateWithSecret(request as RequestAccountCreateWithSecretKey); + case 'pri(accounts.json.restoreV2)': + return this.jsonRestoreV2(request as RequestJsonRestoreV2); + case 'pri(accounts.json.batchRestoreV2)': + return this.batchRestoreV2(request as RequestBatchRestoreV2); case 'pri(seed.createV2)': return this.seedCreateV2(request as RequestSeedCreateV2); // Remove account case 'pri(accounts.forget)': - return await this.accountsForgetOverride(request as RequestAccountForget); + return await this.accountsForgetOverride(request as RequestAccountProxyForget); // Validate account case 'pri(seed.validateV2)': @@ -4405,22 +4045,22 @@ export default class KoniExtension { // Export account case 'pri(accounts.exportPrivateKey)': return this.accountExportPrivateKey(request as RequestAccountExportPrivateKey); + case 'pri(accounts.batchExportV2)': + return this.batchExportV2(request as RequestAccountBatchExportV2); // Subscribe account - case 'pri(accounts.subscribeWithCurrentAddress)': + case 'pri(accounts.subscribeWithCurrentProxy)': return await this.accountsGetAllWithCurrentAddress(id, port); case 'pri(accounts.subscribeAccountsInputAddress)': return this.accountsGetAll(id, port); // Save current account - case 'pri(currentAccount.saveAddress)': + case 'pri(accounts.saveCurrentProxy)': return await this.saveCurrentAccountAddress(request as RequestCurrentAccountAddress); - case 'pri(accounts.updateCurrentAddress)': - return this.updateCurrentAccountAddress(request as string); // Edit account case 'pri(accounts.edit)': - return this.accountsEdit(request as RequestAccountEdit); + return this.accountsEdit(request as RequestAccountProxyEdit); // Save contact address case 'pri(accounts.saveRecent)': @@ -4491,8 +4131,6 @@ export default class KoniExtension { case 'pri(transfer.getMaxTransferable)': return this.getMaxTransferable(request as RequestMaxTransferable); - case 'pri(transfer.subscribeMaxTransferable)': - return this.getMaxTransferable(request as RequestMaxTransferable); case 'pri(freeBalance.get)': return this.getAddressTransferableBalance(request as RequestFreeBalance); case 'pri(freeBalance.subscribe)': @@ -4502,9 +4140,6 @@ export default class KoniExtension { case 'pri(chainService.recoverSubstrateApi)': return this.recoverDotSamaApi(request as string); - case 'pri(accounts.get.meta)': - return this.getAccountMeta(request as RequestAccountMeta); - /// Send NFT case 'pri(evmNft.submitTransaction)': return this.evmNftSubmitTransaction(request as NftTransactionRequest); diff --git a/packages/extension-base/src/koni/background/handlers/State.ts b/packages/extension-base/src/koni/background/handlers/State.ts index 4fafeabe92..022e3804f5 100644 --- a/packages/extension-base/src/koni/background/handlers/State.ts +++ b/packages/extension-base/src/koni/background/handlers/State.ts @@ -39,7 +39,7 @@ import WalletConnectService from '@subwallet/extension-base/services/wallet-conn import { SWStorage } from '@subwallet/extension-base/storage'; import AccountRefStore from '@subwallet/extension-base/stores/AccountRef'; import { AccountJson, BalanceItem, BalanceMap, CurrentAccountInfo, EvmFeeInfo, StorageDataInterface } from '@subwallet/extension-base/types'; -import { isAccountAll, stripUrl, targetIsWeb, wait } from '@subwallet/extension-base/utils'; +import { isAccountAll, pairToAccount, stripUrl, targetIsWeb, wait } from '@subwallet/extension-base/utils'; import { isContractAddress, parseContractInput } from '@subwallet/extension-base/utils/eth/parseTransaction'; import { createPromiseHandler } from '@subwallet/extension-base/utils/promise'; import { MetadataDef, ProviderMeta } from '@subwallet/extension-inject/types'; @@ -1361,7 +1361,7 @@ export default class KoniState { throw new EvmProviderError(EvmProviderErrorType.INVALID_PARAMS, t('Unable to find account')); } - const account: AccountJson = { address: pair.address, ...pair.meta }; + const account: AccountJson = pairToAccount(pair); let hashPayload = ''; let canSign = false; @@ -1549,7 +1549,7 @@ export default class KoniState { throw new EvmProviderError(EvmProviderErrorType.INVALID_PARAMS, t('Unable to find account')); } - const account: AccountJson = { address: pair.address, ...pair.meta }; + const account: AccountJson = pairToAccount(pair); // Validate balance const balance = new BN(await web3.eth.getBalance(fromAddress) || 0); diff --git a/packages/extension-base/src/koni/background/handlers/Tabs.ts b/packages/extension-base/src/koni/background/handlers/Tabs.ts index e6b1c2d46a..e3d62dc538 100644 --- a/packages/extension-base/src/koni/background/handlers/Tabs.ts +++ b/packages/extension-base/src/koni/background/handlers/Tabs.ts @@ -20,7 +20,7 @@ import { _NetworkUpsertParams } from '@subwallet/extension-base/services/chain-s import { _generateCustomProviderKey } from '@subwallet/extension-base/services/chain-service/utils'; import { AuthUrls } from '@subwallet/extension-base/services/request-service/types'; import { DEFAULT_CHAIN_PATROL_ENABLE } from '@subwallet/extension-base/services/setting-service/constants'; -import { canDerive, getEVMChainInfo, stripUrl, transformAccountFromPair } from '@subwallet/extension-base/utils'; +import { canDerive, getEVMChainInfo, stripUrl, singleAddressToAccount } from '@subwallet/extension-base/utils'; import { InjectedMetadataKnown, MetadataDef, ProviderMeta } from '@subwallet/extension-inject/types'; import { KeyringPair } from '@subwallet/keyring/types'; import keyring from '@subwallet/ui-keyring'; @@ -149,7 +149,7 @@ export default class KoniTabs { throw new Error('Account {{address}} not in allowed list'.replace('{{address}}', address)); } - return this.#koniState.sign(url, new RequestBytesSign(request), transformAccountFromPair(pair)); + return this.#koniState.sign(url, new RequestBytesSign(request), singleAddressToAccount(pair)); } private async extrinsicSign (url: string, request: SignerPayloadJSON): Promise { @@ -161,7 +161,7 @@ export default class KoniTabs { throw new Error('Account {{address}} not in allowed list'.replace('{{address}}', address)); } - return this.#koniState.sign(url, new RequestExtrinsicSign(request), transformAccountFromPair(pair)); + return this.#koniState.sign(url, new RequestExtrinsicSign(request), singleAddressToAccount(pair)); } private metadataProvide (url: string, request: MetadataDef): Promise { diff --git a/packages/extension-base/src/services/keyring-service/account-context.ts b/packages/extension-base/src/services/keyring-service/account-context.ts index 081739b156..7eb0b21fdd 100644 --- a/packages/extension-base/src/services/keyring-service/account-context.ts +++ b/packages/extension-base/src/services/keyring-service/account-context.ts @@ -1,27 +1,26 @@ // Copyright 2019-2022 @subwallet/extension-base // SPDX-License-Identifier: Apache-2.0 -import { AccountExternalError, AccountExternalErrorCode, AccountRefMap, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateSuriV2, RequestAccountCreateWithSecretKey, ResponseAccountCreateSuriV2, ResponseAccountCreateWithSecretKey } from '@subwallet/extension-base/background/KoniTypes'; +import { AccountExternalError, AccountExternalErrorCode, AccountRefMap, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateWithSecretKey, RequestBatchRestoreV2, RequestJsonRestoreV2, ResponseAccountCreateWithSecretKey } from '@subwallet/extension-base/background/KoniTypes'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; import { _getEvmChainId, _getSubstrateGenesisHash } from '@subwallet/extension-base/services/chain-service/utils'; import { KeyringService } from '@subwallet/extension-base/services/keyring-service/index'; -import { CurrentAccountStore } from '@subwallet/extension-base/stores'; -import AccountProxyStore from '@subwallet/extension-base/stores/AccountProxyStore'; -import AccountRefStore from '@subwallet/extension-base/stores/AccountRef'; -import ModifyPairStore from '@subwallet/extension-base/stores/ModifyPairStore'; -import { AccountJson, AccountProxy, AccountProxyData, AccountProxyMap, AccountProxyStoreData, AccountProxyType, CurrentAccountInfo, ModifyPairStoreData } from '@subwallet/extension-base/types'; -import { isAddressValidWithAuthType, transformAccount } from '@subwallet/extension-base/utils'; +import { AccountProxyStore, AccountRefStore, CurrentAccountStore, ModifyPairStore } from '@subwallet/extension-base/stores'; +import { AccountJson, AccountProxy, AccountProxyData, AccountProxyMap, AccountProxyStoreData, AccountProxyType, CreateDeriveAccountInfo, CurrentAccountInfo, DeriveAccountInfo, ModifyPairStoreData, RequestAccountCreateSuriV2, RequestDeriveAccountProxy, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestGetDeriveAccounts, ResponseAccountCreateSuriV2, ResponseDeriveValidateV2, ResponseGetDeriveAccounts } from '@subwallet/extension-base/types'; +import { RequestAccountProxyEdit, RequestAccountProxyForget } from '@subwallet/extension-base/types/account/action/edit'; +import { isAddressValidWithAuthType, modifyAccountName, singleAddressToAccount } from '@subwallet/extension-base/utils'; import { InjectedAccountWithMeta } from '@subwallet/extension-inject/types'; -import { KeyringPair, KeyringPair$Meta } from '@subwallet/keyring/types'; +import { createPair } from '@subwallet/keyring'; +import { KeyringPair, KeyringPair$Json, KeyringPair$Meta } from '@subwallet/keyring/types'; import { keyring } from '@subwallet/ui-keyring'; import { SubjectInfo } from '@subwallet/ui-keyring/observable/types'; import { t } from 'i18next'; import { BehaviorSubject, combineLatest } from 'rxjs'; -import { hexStripPrefix, hexToU8a, isHex, stringShorten } from '@polkadot/util'; -import { blake2AsHex, keyExtractSuri, mnemonicToEntropy } from '@polkadot/util-crypto'; +import { assert, hexStripPrefix, hexToU8a, isHex, stringShorten, u8aToHex, u8aToString } from '@polkadot/util'; +import { base64Decode, blake2AsHex, jsonDecrypt, keyExtractSuri, mnemonicToEntropy } from '@polkadot/util-crypto'; import { validateMnemonic } from '@polkadot/util-crypto/mnemonic/bip39'; -import { KeypairType } from '@polkadot/util-crypto/types'; +import { EncryptedJson, KeypairType, Prefix } from '@polkadot/util-crypto/types'; const ETH_DERIVE_DEFAULT = '/m/44\'/60\'/0\'/0/0'; @@ -120,7 +119,7 @@ export class AccountContext { for (const [address, pair] of Object.entries(pairs)) { const modifyPair = modifyPairs[address]; - const account: AccountJson = transformAccount(pair); + const account: AccountJson = singleAddressToAccount(pair); if (modifyPair && modifyPair.accountProxyId) { const accountGroup = accountGroups[modifyPair.accountProxyId]; @@ -197,7 +196,6 @@ export class AccountContext { public _setCurrentAccount (data: CurrentAccountInfo, callback?: () => void, preventOneAccount?: boolean): void { const { address } = data; - const result: CurrentAccountInfo = { ...data }; if (address === ALL_ACCOUNT_KEY) { @@ -235,13 +233,17 @@ export class AccountContext { /* Current account */ - private _addAddressToAuthList (address: string, isAllowed: boolean): void { + /* Auth address */ + + private _addAddressesToAuthList (addresses: string[], isAllowed: boolean): void { this.parent.state.getAuthorize((value) => { if (value && Object.keys(value).length) { Object.keys(value).forEach((url) => { - if (isAddressValidWithAuthType(address, value[url].accountAuthType)) { - value[url].isAllowedMap[address] = isAllowed; - } + addresses.forEach((address) => { + if (isAddressValidWithAuthType(address, value[url].accountAuthType)) { + value[url].isAllowedMap[address] = isAllowed; + } + }); }); this.parent.state.setAuthorize(value); @@ -249,10 +251,15 @@ export class AccountContext { }); } + private _addAddressToAuthList (address: string, isAllowed: boolean): void { + this._addAddressesToAuthList([address], isAllowed); + } + + /* Auth address */ + /* Account groups */ /* Upsert account group */ - private upsertAccountProxy (data: AccountProxyData, callback?: () => void) { this.accountProxiesStore.get(ACCOUNT_PROXIES_KEY, (rs) => { const accountGroups = rs || {}; @@ -263,14 +270,36 @@ export class AccountContext { }); } - private createAccountGroupId (_suri: string) { + /* Delete account group */ + private deleteAccountProxy (key: string, callback?: () => void) { + this.accountProxiesStore.get(ACCOUNT_PROXIES_KEY, (rs) => { + const accountGroups = rs || {}; + + delete accountGroups[key]; + this.accountProxiesSubject.next(accountGroups); + this.accountProxiesStore.set(ACCOUNT_PROXIES_KEY, accountGroups, callback); + }); + } + + /* Create group id */ + private createAccountGroupId (_suri: string, derivationPath?: string) { + let data: string = _suri; + if (validateMnemonic(_suri)) { const entropy = mnemonicToEntropy(_suri); - return blake2AsHex(entropy, 256); - } else { - return blake2AsHex(_suri, 256); + data = u8aToHex(entropy); + + if (derivationPath) { + data = blake2AsHex(data, 256); + } + } + + if (derivationPath) { + data = hexStripPrefix(data).concat(derivationPath); } + + return blake2AsHex(data, 256); } /* Account group */ @@ -278,7 +307,6 @@ export class AccountContext { /* Modify pairs */ /* Upsert modify pairs */ - private upsertModifyPairs (data: ModifyPairStoreData) { this.modifyPairsStore.set(MODIFY_PAIRS_KEY, data); this.modifyPairsSubject.next(data); @@ -286,8 +314,76 @@ export class AccountContext { /* Modify pairs */ + /* Modify accounts */ + + public accountsEdit ({ name, proxyId }: RequestAccountProxyEdit): boolean { + const accountProxies = this.accountProxiesSubject.value; + const modifyPairs = this.modifyPairsSubject.value; + + if (!accountProxies[proxyId]) { + const pair = keyring.getPair(proxyId); + + assert(pair, t('Unable to find account')); + + keyring.saveAccountMeta(pair, { ...pair.meta, name }); + } else { + const accountGroup = accountProxies[proxyId]; + const addresses = Object.keys(modifyPairs).filter((address) => modifyPairs[address].accountProxyId === proxyId); + + accountGroup.name = name; + this.upsertAccountProxy(accountGroup); + + for (const address of addresses) { + const pair = keyring.getPair(address); + + assert(pair, t('Unable to find account')); + + const _name = modifyAccountName(pair.type, name, true); + + keyring.saveAccountMeta(pair, { ...pair.meta, name: _name }); + } + } + + return true; + } + + public async accountProxyForget ({ proxyId }: RequestAccountProxyForget): Promise { + const accountProxies = this.accountProxiesSubject.value; + const modifyPairs = this.modifyPairsSubject.value; + + let addresses: string[]; + + if (!accountProxies[proxyId]) { + addresses = [proxyId]; + } else { + addresses = Object.keys(modifyPairs).filter((address) => modifyPairs[address].accountProxyId === proxyId); + + this.deleteAccountProxy(proxyId); + } + + for (const address of addresses) { + delete modifyPairs[address]; + } + + this.upsertModifyPairs(modifyPairs); + + for (const address of addresses) { + keyring.forgetAccount(address); + } + + await Promise.all(addresses.map((address) => new Promise((resolve) => this.removeAccountRef(address, resolve)))); + + await new Promise((resolve) => { + this._setCurrentAccount({ address: ALL_ACCOUNT_KEY }, resolve); + }); + + return addresses; + } + + /* Modify accounts */ + /* Add accounts from seed */ - public async accountsCreateSuriV2 (request: RequestAccountCreateSuriV2): Promise { + public accountsCreateSuriV2 (request: RequestAccountCreateSuriV2): ResponseAccountCreateSuriV2 { const { isAllowed, name, password, suri: _suri, types } = request; const addressDict = {} as Record; let changedAccount = false; @@ -325,6 +421,7 @@ export class AccountContext { const address = pair.address; modifiedPairs[address] = { accountProxyId: proxyId || address, migrated: true, key: address }; + addressDict[type] = address; }); // Upsert modify pair before add account to keyring @@ -332,55 +429,29 @@ export class AccountContext { types.forEach((type) => { const suri = getSuri(_suri, type); - const newAccountName = (() => { - if (!proxyId) { - return name; - } - - let network = ''; - - switch (type) { - case 'sr25519': - case 'ed25519': - case 'ecdsa': - network = 'Substrate'; - break; - case 'ethereum': - network = 'EVM'; - break; - } - - return network ? [name, network].join(' - ') : name; - })(); + const newAccountName = modifyAccountName(type, name, !!proxyId); const rs = keyring.addUri(suri, { name: newAccountName }, type); const address = rs.pair.address; - addressDict[type] = address; this._addAddressToAuthList(address, isAllowed); if (!changedAccount) { - if (!multiChain) { + if (!proxyId) { this.setCurrentAccount({ address }); } else { - this._setCurrentAccount({ address: ALL_ACCOUNT_KEY }, undefined, true); + this._setCurrentAccount({ address: proxyId }, undefined, true); } changedAccount = true; } }); - await new Promise((resolve) => { - this.addAccountRef(Object.values(addressDict), () => { - resolve(); - }); - }); - return addressDict; } /* Add QR-signer, read-only */ public async accountsCreateExternalV2 (request: RequestAccountCreateExternalV2): Promise { - const { address, genesisHash, isAllowed, isEthereum, isReadOnly, name } = request; + const { address, isAllowed, isEthereum, isReadOnly, name } = request; try { let result: KeyringPair; @@ -398,37 +469,24 @@ export class AccountContext { } if (isEthereum) { - const chainInfoMap = this.parent.state.getChainInfoMap(); - let _gen = ''; - - if (genesisHash) { - for (const network of Object.values(chainInfoMap)) { - if (_getEvmChainId(network) === parseInt(genesisHash)) { - // TODO: pure EVM chains do not have genesisHash - _gen = _getSubstrateGenesisHash(network); - } - } - } - result = keyring.keyring.addFromAddress(address, { name, isExternal: true, isReadOnly, - genesisHash: _gen + genesisHash: '' }, null, 'ethereum'); keyring.saveAccount(result); } else { - result = keyring.addExternal(address, { genesisHash, name, isReadOnly }).pair; + result = keyring.addExternal(address, { genesisHash: '', name, isReadOnly }).pair; } const _address = result.address; + const modifiedPairs = this.modifyPairsSubject.value; - await new Promise((resolve) => { - this.parent.state.addAccountRef([_address], () => { - resolve(); - }); - }); + modifiedPairs[_address] = { migrated: true, key: _address }; + + this.upsertModifyPairs(modifiedPairs); await new Promise((resolve) => { this._saveCurrentAccountAddress(_address, () => { @@ -459,12 +517,11 @@ export class AccountContext { const result = key.pair; const _address = result.address; + const modifiedPairs = this.modifyPairsSubject.value; - await new Promise((resolve) => { - this.addAccountRef([_address], () => { - resolve(); - }); - }); + modifiedPairs[_address] = { migrated: true, key: _address }; + + this.upsertModifyPairs(modifiedPairs); await new Promise((resolve) => { this._saveCurrentAccountAddress(_address, () => { @@ -485,6 +542,7 @@ export class AccountContext { } const slugMap: Record = {}; + const modifiedPairs = this.modifyPairsSubject.value; for (const account of accounts) { const { accountIndex, address, addressOffset, genesisHash, hardwareType, isEthereum, isGeneric, name } = account; @@ -525,6 +583,7 @@ export class AccountContext { const _address = result.address; + modifiedPairs[_address] = { migrated: true, key: _address }; addresses.push(_address); await new Promise((resolve) => { @@ -536,18 +595,14 @@ export class AccountContext { // const currentAccount = this.#koniState.keyringService.context.currentAccount; // const allGenesisHash = currentAccount?.allGenesisHash || undefined; + this.upsertModifyPairs(modifiedPairs); + if (addresses.length <= 1) { this._setCurrentAccount({ address: addresses[0] }); } else { this._setCurrentAccount({ address: ALL_ACCOUNT_KEY }); } - await new Promise((resolve) => { - this.addAccountRef(addresses, () => { - resolve(); - }); - }); - if (Object.keys(slugMap).length) { for (const chainSlug of Object.keys(slugMap)) { this.parent.state.enableChain(chainSlug, true).catch(console.error); @@ -559,8 +614,96 @@ export class AccountContext { /* Ledger */ - /* Add with secret and public key */ + /* JSON */ + + public decodeAddress = (key: string | Uint8Array, ignoreChecksum?: boolean, ss58Format?: Prefix): Uint8Array => { + return keyring.decodeAddress(key, ignoreChecksum, ss58Format); + }; + public encodeAddress = (key: string | Uint8Array, ss58Format?: Prefix): string => { + return keyring.encodeAddress(key, ss58Format); + }; + + private validatePassword (json: KeyringPair$Json, password: string): boolean { + const cryptoType = Array.isArray(json.encoding.content) ? json.encoding.content[1] : 'ed25519'; + const encType = Array.isArray(json.encoding.type) ? json.encoding.type : [json.encoding.type]; + const pair = createPair( + { toSS58: this.encodeAddress, type: cryptoType as KeypairType }, + { publicKey: this.decodeAddress(json.address, true) }, + json.meta, + isHex(json.encoded) ? hexToU8a(json.encoded) : base64Decode(json.encoded), + encType + ); + + // unlock then lock (locking cleans secretKey, so needs to be last) + try { + pair.decodePkcs8(password); + pair.lock(); + + return true; + } catch (e) { + console.error(e); + + return false; + } + } + + public jsonRestoreV2 ({ address, file, isAllowed, password, withMasterPassword }: RequestJsonRestoreV2): void { + const isPasswordValidated = this.validatePassword(file, password); + + if (isPasswordValidated) { + try { + this._saveCurrentAccountAddress(address, () => { + const newAccount = keyring.restoreAccount(file, password, withMasterPassword); + + // genesisHash is not used in SubWallet => reset it to empty string, if it is not hardware wallet + if (!newAccount.meta?.isHardware && newAccount.meta?.genesisHash !== '') { + keyring.saveAccountMeta(newAccount, { ...newAccount.meta, genesisHash: '' }); + } + + this._addAddressToAuthList(address, isAllowed); + }); + } catch (error) { + throw new Error((error as Error).message); + } + } else { + throw new Error(t('Wrong password')); + } + } + + private validatedAccountsPassword (json: EncryptedJson, password: string): boolean { + try { + u8aToString(jsonDecrypt(json, password)); + + return true; + } catch (e) { + return false; + } + } + + public batchRestoreV2 ({ accountsInfo, file, isAllowed, password }: RequestBatchRestoreV2): void { + const addressList: string[] = accountsInfo.map((acc) => acc.address); + const isPasswordValidated = this.validatedAccountsPassword(file, password); + + if (isPasswordValidated) { + try { + this._saveCurrentAccountAddress(ALL_ACCOUNT_KEY, () => { + keyring.restoreAccounts(file, password); + + this.removeNoneHardwareGenesisHash(); + this._addAddressesToAuthList(addressList, isAllowed); + }); + } catch (error) { + throw new Error((error as Error).message); + } + } else { + throw new Error(t('Wrong password')); + } + } + + /* JSON */ + + /* Add with secret and public key */ public async accountsCreateWithSecret (request: RequestAccountCreateWithSecretKey): Promise { const { isAllow, isEthereum, name, publicKey, secretKey } = request; @@ -596,12 +739,11 @@ export class AccountContext { } const _address = keyringPair.address; + const modifiedPairs = this.modifyPairsSubject.value; - await new Promise((resolve) => { - this.addAccountRef([_address], () => { - resolve(); - }); - }); + modifiedPairs[_address] = { migrated: true, key: _address }; + + this.upsertModifyPairs(modifiedPairs); await new Promise((resolve) => { this._saveCurrentAccountAddress(_address, () => { @@ -622,6 +764,288 @@ export class AccountContext { } } + /* Derive */ + + /* Derive multi account */ + public derivationCreateMultiple ({ isAllowed, items, parentAddress }: RequestDeriveCreateMultiple): boolean { + const parentPair = keyring.getPair(parentAddress); + const isEvm = parentPair.type === 'ethereum'; + + if (parentPair.isLocked) { + keyring.unlockPair(parentPair.address); + } + + const createChild = ({ name, suri }: CreateDeriveAccountInfo): KeyringPair => { + const meta: KeyringPair$Meta = { + name: name, + parentAddress + }; + + if (isEvm) { + let index = 0; + + try { + const reg = /^\d+$/; + const path = suri.split('//')[1]; + + if (reg.test(path)) { + index = parseInt(path); + } + } catch (e) { + + } + + if (!index) { + throw Error(t('Invalid derive path')); + } + + meta.suri = `//${index}`; + + return parentPair.deriveEvm(index, meta); + } else { + meta.suri = suri; + + return parentPair.derive(suri, meta); + } + }; + + const result: KeyringPair[] = []; + + for (const item of items) { + try { + const childPair = createChild(item); + const address = childPair.address; + + keyring.addPair(childPair, true); + this._addAddressToAuthList(address, isAllowed); + result.push(childPair); + } catch (e) { + console.log(e); + } + } + + if (result.length === 1) { + this._saveCurrentAccountAddress(result[0].address); + } else { + this._setCurrentAccount({ address: ALL_ACCOUNT_KEY }); + } + + return true; + } + + /* Auto create derive account */ + public derivationCreateV3 ({ address: parentAddress }: RequestDeriveCreateV3): boolean { + const parentPair = keyring.getPair(parentAddress); + const isEvm = parentPair.type === 'ethereum'; + + if (parentPair.isLocked) { + keyring.unlockPair(parentPair.address); + } + + const pairs = keyring.getPairs(); + const children = pairs.filter((p) => p.meta.parentAddress === parentAddress); + const name = `Account ${pairs.length}`; + + let index = isEvm ? 1 : 0; + let valid = false; + + do { + const exist = children.find((p) => p.meta.suri === `//${index}`); + + if (exist) { + index++; + } else { + valid = true; + } + } while (!valid); + + const meta = { + name, + parentAddress, + suri: `//${index}` + }; + const childPair = isEvm ? parentPair.deriveEvm(index, meta) : parentPair.derive(meta.suri, meta); + const address = childPair.address; + + this._saveCurrentAccountAddress(address, () => { + keyring.addPair(childPair, true); + this._addAddressToAuthList(address, true); + }); + + return true; + } + + /* Validate derivation path */ + public validateDerivePath ({ parentAddress, suri }: RequestDeriveValidateV2): ResponseDeriveValidateV2 { + const parentPair = keyring.getPair(parentAddress); + const isEvm = parentPair.type === 'ethereum'; + + if (parentPair.isLocked) { + keyring.unlockPair(parentPair.address); + } + + const meta: KeyringPair$Meta = { + parentAddress + }; + + let childPair: KeyringPair; + + if (isEvm) { + let index = 0; + + try { + const reg = /^\d+$/; + const path = suri.split('//')[1]; + + if (reg.test(path)) { + index = parseInt(path); + } + } catch (e) { + + } + + if (!index) { + throw Error(t('Invalid derive path')); + } + + meta.suri = `//${index}`; + + childPair = parentPair.deriveEvm(index, meta); + } else { + meta.suri = suri; + childPair = parentPair.derive(suri, meta); + } + + return { + address: childPair.address, + suri: meta.suri as string + }; + } + + /* Get a derivation account list */ + public getListDeriveAccounts ({ limit, page, parentAddress }: RequestGetDeriveAccounts): ResponseGetDeriveAccounts { + const parentPair = keyring.getPair(parentAddress); + const isEvm = parentPair.type === 'ethereum'; + + if (parentPair.isLocked) { + keyring.unlockPair(parentPair.address); + } + + const start = (page - 1) * limit + (isEvm ? 1 : 0); + const end = start + limit; + + const result: DeriveAccountInfo[] = []; + + for (let i = start; i < end; i++) { + const suri = `//${i}`; + const pair = isEvm ? parentPair.deriveEvm(i, {}) : parentPair.derive(suri, {}); + + result.push({ address: pair.address, suri: suri }); + } + + return { + result: result + }; + } + + /** + * Derive account proxy + * @todo: finish this method + * */ + public derivationAccountProxyCreate ({ proxyId, suri }: RequestDeriveAccountProxy): boolean { + const pairs = keyring.getPairs(); + + const newProxyName = 'Account 1'; + // const modifyPairs = this.modifyPairsSubject.value; + const accountProxies = this.accountProxiesSubject.value; + + if (!accountProxies[proxyId]) { + const parentAddress = proxyId; + const parentPair = keyring.getPair(parentAddress); + const isEvm = parentPair.type === 'ethereum'; + + if (!parentPair) { + throw Error(t('Cannot find account')); + } + + const pairs = keyring.getPairs(); + const children = pairs.filter((p) => p.meta.parentAddress === parentAddress); + const name = `Account ${pairs.length}`; + + let index = isEvm ? 1 : 0; + let valid = false; + + do { + const exist = children.find((p) => p.meta.suri === `//${index}`); + + if (exist) { + index++; + } else { + valid = true; + } + } while (!valid); + + const meta = { + name, + parentAddress, + suri: `//${index}` + }; + const childPair = isEvm ? parentPair.deriveEvm(index, meta) : parentPair.derive(meta.suri, meta); + const address = childPair.address; + + this._saveCurrentAccountAddress(address, () => { + keyring.addPair(childPair, true); + this._addAddressToAuthList(address, true); + }); + + return true; + } else { + // Empty + } + + pairs.forEach((pair) => { + if (pair.meta.proxyId !== proxyId) { + return; + } + + const isEvm = pair.type === 'ethereum'; + + if (pair.isLocked) { + keyring.unlockPair(pair.address); + } + + const children = pairs.filter((p) => p.meta.parentAddress === pair.address); + + let index = 1; + let valid = false; + + do { + const exist = children.find((p) => p.meta.suri === `//${index}`); + + if (exist) { + index++; + } else { + valid = true; + } + } while (!valid); + + const meta = { + name: newProxyName, + parentAddress: pair.address, + suri: `//${index}` + }; + + // todo: will update logic if support more type + const childPair = isEvm ? pair.deriveEvm(index, meta) : pair.derive(index.toString(), meta); + + keyring.addPair(childPair, true); + }); + + return true; + } + + /* Derive */ + /* Inject */ public addInjectAccounts (accounts: InjectedAccountWithMeta[]) { diff --git a/packages/extension-base/src/stores/index.ts b/packages/extension-base/src/stores/index.ts index b4dd5d6e77..7cb938abb5 100644 --- a/packages/extension-base/src/stores/index.ts +++ b/packages/extension-base/src/stores/index.ts @@ -1,7 +1,10 @@ // Copyright 2019-2022 @polkadot/extension-base authors & contributors // SPDX-License-Identifier: Apache-2.0 +export { default as AccountProxyStore } from './AccountProxyStore'; +export { default as AccountRefStore } from './AccountRef'; export { default as AccountsStore } from './Accounts'; -export { default as MetadataStore } from './Metadata'; export { default as CurrentAccountStore } from './CurrentAccountStore'; export { default as CurrentCurrencyStore } from './CurrentCurrencyStore'; +export { default as MetadataStore } from './Metadata'; +export { default as ModifyPairStore } from './ModifyPairStore'; diff --git a/packages/extension-base/src/types/account/action/add.ts b/packages/extension-base/src/types/account/action/add.ts new file mode 100644 index 0000000000..06013ce86d --- /dev/null +++ b/packages/extension-base/src/types/account/action/add.ts @@ -0,0 +1,14 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { KeypairType } from '@polkadot/util-crypto/types'; + +export interface RequestAccountCreateSuriV2 { + name: string; + password?: string; + suri: string; + types?: Array; + isAllowed: boolean; +} + +export type ResponseAccountCreateSuriV2 = Record diff --git a/packages/extension-base/src/types/account/action/derive.ts b/packages/extension-base/src/types/account/action/derive.ts new file mode 100644 index 0000000000..49509d02c9 --- /dev/null +++ b/packages/extension-base/src/types/account/action/derive.ts @@ -0,0 +1,52 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export interface RequestDeriveCreateV2 { + name: string; + genesisHash?: string | null; + suri: string; + parentAddress: string; + isAllowed: boolean; +} + +export interface CreateDeriveAccountInfo { + name: string; + suri: string; +} + +export interface RequestDeriveCreateV3 { + address: string; +} + +export interface RequestDeriveCreateMultiple { + parentAddress: string; + isAllowed: boolean; + items: CreateDeriveAccountInfo[]; +} + +export interface DeriveAccountInfo { + address: string; + suri: string; +} + +export interface RequestDeriveValidateV2 { + suri: string; + parentAddress: string; +} + +export type ResponseDeriveValidateV2 = DeriveAccountInfo; + +export interface RequestGetDeriveAccounts { + page: number; + limit: number; + parentAddress: string; +} + +export interface ResponseGetDeriveAccounts { + result: DeriveAccountInfo[]; +} + +export interface RequestDeriveAccountProxy { + proxyId: string; + suri?: string; +} diff --git a/packages/extension-base/src/types/account/action/edit.ts b/packages/extension-base/src/types/account/action/edit.ts new file mode 100644 index 0000000000..5a0d737145 --- /dev/null +++ b/packages/extension-base/src/types/account/action/edit.ts @@ -0,0 +1,12 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export interface RequestAccountProxyEdit { + proxyId: string; + name: string; +} + +export interface RequestAccountProxyForget { + proxyId: string; + lockAfter: boolean; +} diff --git a/packages/extension-base/src/types/account/action/index.ts b/packages/extension-base/src/types/account/action/index.ts new file mode 100644 index 0000000000..b5e2eb5397 --- /dev/null +++ b/packages/extension-base/src/types/account/action/index.ts @@ -0,0 +1,5 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export * from './add'; +export * from './derive'; diff --git a/packages/extension-base/src/types/account/index.ts b/packages/extension-base/src/types/account/index.ts index c99a56190a..a4f6f137f5 100644 --- a/packages/extension-base/src/types/account/index.ts +++ b/packages/extension-base/src/types/account/index.ts @@ -1,4 +1,5 @@ // Copyright 2019-2022 @subwallet/extension-base authors & contributors // SPDX-License-Identifier: Apache-2.0 +export * from './action'; export * from './info'; diff --git a/packages/extension-base/src/types/account/info/current.ts b/packages/extension-base/src/types/account/info/current.ts index 832de05bf5..0d3818b0c6 100644 --- a/packages/extension-base/src/types/account/info/current.ts +++ b/packages/extension-base/src/types/account/info/current.ts @@ -1,12 +1,12 @@ // Copyright 2019-2022 @subwallet/extension-base authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountProxy } from './group'; +import { AccountProxy } from './proxy'; // all Accounts and the address of the current Account export interface AccountsWithCurrentAddress { accounts: AccountProxy[]; - currentAddress?: string; + currentAccountProxy?: string; } export interface CurrentAccountInfo { diff --git a/packages/extension-base/src/utils/account/common.ts b/packages/extension-base/src/utils/account/common.ts new file mode 100644 index 0000000000..aa838329b9 --- /dev/null +++ b/packages/extension-base/src/utils/account/common.ts @@ -0,0 +1,44 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { KeypairType } from '@polkadot/util-crypto/types'; +import { reformatAddress } from '@subwallet/extension-base/utils'; + +import { decodeAddress, encodeAddress, isAddress, isEthereumAddress } from '@polkadot/util-crypto'; + +export const simpleAddress = (address: string): string => { + if (isEthereumAddress(address)) { + return address; + } + + return encodeAddress(decodeAddress(address)); +}; + +export function quickFormatAddressToCompare (address?: string) { + if (!isAddress(address)) { + return address; + } + + return reformatAddress(address, 42).toLowerCase(); +} + +export const modifyAccountName = (type: KeypairType, name: string, modify: boolean) => { + if (!modify) { + return name; + } + + let network = ''; + + switch (type) { + case 'sr25519': + case 'ed25519': + case 'ecdsa': + network = 'Substrate'; + break; + case 'ethereum': + network = 'EVM'; + break; + } + + return network ? [name, network].join(' - ') : name; +}; diff --git a/packages/extension-base/src/utils/account/derive.ts b/packages/extension-base/src/utils/account/derive.ts new file mode 100644 index 0000000000..a4c95a90c9 --- /dev/null +++ b/packages/extension-base/src/utils/account/derive.ts @@ -0,0 +1,99 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { KeyringPair, KeyringPair$Meta } from '@subwallet/keyring/types'; +import { keyring } from '@subwallet/ui-keyring'; +import { t } from 'i18next'; + +import { assert } from '@polkadot/util'; +import { KeypairType } from '@polkadot/util-crypto/types'; + +interface DeriveInfo { + suri?: string; + deriveIndex?: number; +} + +interface NextDerivePair { + address: string; + deriveIndex: number; + meta: KeyringPair$Meta; +} + +const SUBSTRATE_TYPE: KeypairType[] = ['ed25519', 'sr25519', 'ecdsa']; + +export const getDerivationInfo = (pair: KeyringPair): DeriveInfo => { + const isSubstrate = SUBSTRATE_TYPE.includes(pair.type); + + const suri = pair.meta.suri as string; + + if (suri) { + if (/^\/\/\d+$/.test(suri)) { + const _deriveIndex = parseInt(suri.replace('//', ''), 10); + const deriveIndex = isSubstrate ? _deriveIndex : _deriveIndex - 1; + + return { suri, deriveIndex }; + } else { + return { suri }; + } + } else { + return {}; + } +}; + +export const findNextDerivePair = (parentAddress: string): NextDerivePair => { + const parentPair = keyring.getPair(parentAddress); + + assert(parentPair, t('Unable to find account')); + + const isEvm = parentPair.type === 'ethereum'; + + if (parentPair.isLocked) { + keyring.unlockPair(parentPair.address); + } + + const pairs = keyring.getPairs(); + const children = pairs.filter((p) => p.meta.parentAddress === parentAddress); + const childrenMetadata = children.map(getDerivationInfo).sort((a, b) => { + if (a.deriveIndex !== undefined && b.deriveIndex !== undefined) { + return a.deriveIndex - b.deriveIndex; + } else { + if (a.deriveIndex === undefined && b.deriveIndex === undefined) { + return 0; + } else { + return a.deriveIndex === undefined ? -1 : 1; + } + } + }); + + let valid = false; + let index = 0; + + for (const { deriveIndex, suri } of childrenMetadata) { + if (!suri || deriveIndex === undefined) { + valid = false; + break; + } + + if (deriveIndex === index) { + index++; + } else { + break; + } + } + + assert(valid, t('Unable to find next derive path')); + + const meta = { + parentAddress, + suri: `//${index}` + }; + + const childPair = isEvm ? parentPair.deriveEvm(index, meta) : parentPair.derive(meta.suri, meta); + const address = childPair.address; + + return { + address, + deriveIndex: index, + meta + }; +}; diff --git a/packages/extension-base/src/utils/account/index.ts b/packages/extension-base/src/utils/account/index.ts new file mode 100644 index 0000000000..947472213d --- /dev/null +++ b/packages/extension-base/src/utils/account/index.ts @@ -0,0 +1,6 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export * from './common'; +export * from './derive'; +export * from './transform'; diff --git a/packages/extension-base/src/utils/account.ts b/packages/extension-base/src/utils/account/transform.ts similarity index 52% rename from packages/extension-base/src/utils/account.ts rename to packages/extension-base/src/utils/account/transform.ts index 9b895f19ca..0c8266be6d 100644 --- a/packages/extension-base/src/utils/account.ts +++ b/packages/extension-base/src/utils/account/transform.ts @@ -3,32 +3,11 @@ import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; -import { AccountJson, AccountMetadataData, AccountSignMode, AddressJson } from '@subwallet/extension-base/types'; -import { reformatAddress } from '@subwallet/extension-base/utils/index'; +import { AccountJson, AccountMetadataData, AccountSignMode } from '@subwallet/extension-base/types'; import { KeyringPair, KeyringPair$Meta } from '@subwallet/keyring/types'; import { SingleAddress, SubjectInfo } from '@subwallet/ui-keyring/observable/types'; -import { decodeAddress, encodeAddress, isAddress, isEthereumAddress } from '@polkadot/util-crypto'; - -export const simpleAddress = (address: string): string => { - if (isEthereumAddress(address)) { - return address; - } - - return encodeAddress(decodeAddress(address)); -}; - -export function quickFormatAddressToCompare (address?: string) { - if (!isAddress(address)) { - return address; - } - - return reformatAddress(address, 42).toLowerCase(); -} - -export const convertSubjectInfoToAddresses = (subjectInfo: SubjectInfo): AddressJson[] => { - return Object.values(subjectInfo).map((info): AddressJson => ({ address: info.json.address, type: info.type, ...info.json.meta })); -}; +import { KeypairType } from '@polkadot/util-crypto/types'; export const getAccountSignMode = (address: string, _meta?: KeyringPair$Meta): AccountSignMode => { const meta = _meta as AccountMetadataData; @@ -62,8 +41,7 @@ export const getAccountSignMode = (address: string, _meta?: KeyringPair$Meta): A } }; -export const transformAccount = (account: SingleAddress): AccountJson => { - const { json: { address, meta }, type } = account; +export const transformAccount = (address: string, type?: KeypairType, meta?: KeyringPair$Meta): AccountJson => { const accountActions: string[] = []; const transactionActions: ExtrinsicType[] = []; const signMode = getAccountSignMode(address, meta); @@ -78,20 +56,8 @@ export const transformAccount = (account: SingleAddress): AccountJson => { }; }; -export const transformAccountFromPair = (account: KeyringPair): AccountJson => { - const { address, meta, type } = account; - const accountActions: string[] = []; - const transactionActions: ExtrinsicType[] = []; - const signMode = getAccountSignMode(address, meta); +export const singleAddressToAccount = ({ json: { address, meta }, type }: SingleAddress): AccountJson => transformAccount(address, type, meta); - return { - address, - ...meta, - type, - accountActions, - transactionActions, - signMode - }; -}; +export const pairToAccount = ({ address, meta, type }: KeyringPair): AccountJson => transformAccount(address, type, meta); -export const transformAccounts = (accounts: SubjectInfo): AccountJson[] => Object.values(accounts).map(transformAccount); +export const transformAccounts = (accounts: SubjectInfo): AccountJson[] => Object.values(accounts).map(singleAddressToAccount); diff --git a/packages/extension-base/src/utils/auth.ts b/packages/extension-base/src/utils/auth.ts index 2f421264fd..6d77f711de 100644 --- a/packages/extension-base/src/utils/auth.ts +++ b/packages/extension-base/src/utils/auth.ts @@ -14,3 +14,25 @@ export const isAddressValidWithAuthType = (address: string, accountAuthType?: Ac return true; }; + +// export const isAddressValidWithAuthType = (address: string, accountAuthType?: AccountAuthType): boolean => { +// const keypairType = getKeypairTypeByAddress(address); +// +// if (!['ethereum', 'bitcoin-84', 'bitcoin-86', 'bittest-84', 'bittest-86'].includes(keypairType)) { +// return false; +// } +// +// if (accountAuthType === 'both') { +// return true; +// } +// +// if (accountAuthType === 'evm') { +// return keypairType === 'ethereum'; +// } +// +// if (accountAuthType === 'bitcoin') { +// return ['bitcoin-86', 'bittest-86', 'bitcoin-84', 'bittest-84'].includes(keypairType); +// } +// +// return false; +// }; diff --git a/packages/extension-koni-ui/src/Popup/Debugger/DebuggerAPI.tsx b/packages/extension-koni-ui/src/Popup/Debugger/DebuggerAPI.tsx index 75dc2056c3..5905c22e75 100644 --- a/packages/extension-koni-ui/src/Popup/Debugger/DebuggerAPI.tsx +++ b/packages/extension-koni-ui/src/Popup/Debugger/DebuggerAPI.tsx @@ -21,7 +21,7 @@ const API_LIST = [ // 'pri(accounts.edit)', // 'pri(accounts.show)', - // 'pri(currentAccount.saveAddress)', + // 'pri(accounts.saveCurrentProxy)', // 'pri(settings.changeBalancesVisibility)', // 'pri(settings.saveAccountAllLogo)', // 'pri(settings.saveTheme)', @@ -58,7 +58,7 @@ const API_LIST = [ // 'pri(authorize.cancelV2)', // 'pri(metadata.reject)', // 'pri(accounts.subscribe)', - // 'pri(accounts.subscribeWithCurrentAddress)', + // 'pri(accounts.subscribeWithCurrentProxy)', // 'pri(accounts.subscribeAccountsInputAddress)', // 'pri(accounts.saveRecent)', // 'pri(accounts.triggerSubscription)', @@ -86,8 +86,8 @@ const API_LIST = [ // 'pri(json.account.info)', // 'pri(json.restore)', // 'pri(json.batchRestore)', - // 'pri(json.restoreV2)', - // 'pri(json.batchRestoreV2)', + // 'pri(accounts.json.restoreV2)', + // 'pri(accounts.json.batchRestoreV2)', // 'pri(settings.notification)', // 'pri(price.getPrice)', // 'pri(price.getSubscription)', diff --git a/packages/extension-koni-ui/src/messaging/accounts/create.ts b/packages/extension-koni-ui/src/messaging/accounts/create.ts index 1af73d4d36..2679fe858e 100644 --- a/packages/extension-koni-ui/src/messaging/accounts/create.ts +++ b/packages/extension-koni-ui/src/messaging/accounts/create.ts @@ -1,8 +1,9 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountExternalError, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateSuriV2, RequestAccountCreateWithSecretKey, ResponseAccountCreateSuriV2, ResponseAccountCreateWithSecretKey, ResponseSeedCreateV2 } from '@subwallet/extension-base/background/KoniTypes'; +import { AccountExternalError, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateWithSecretKey, ResponseAccountCreateWithSecretKey, ResponseSeedCreateV2 } from '@subwallet/extension-base/background/KoniTypes'; import { SeedLengths } from '@subwallet/extension-base/background/types'; +import { RequestAccountCreateSuriV2, ResponseAccountCreateSuriV2 } from '@subwallet/extension-base/types'; import { sendMessage } from '@subwallet/extension-koni-ui/messaging/base'; import { KeypairType } from '@polkadot/util-crypto/types'; diff --git a/packages/extension-koni-ui/src/messaging/accounts/currentAccount.ts b/packages/extension-koni-ui/src/messaging/accounts/currentAccount.ts index 58fd6f3879..783d0bbb54 100644 --- a/packages/extension-koni-ui/src/messaging/accounts/currentAccount.ts +++ b/packages/extension-koni-ui/src/messaging/accounts/currentAccount.ts @@ -6,5 +6,5 @@ import { CurrentAccountInfo } from '@subwallet/extension-base/types'; import { sendMessage } from '@subwallet/extension-koni-ui/messaging/base'; export async function saveCurrentAccountAddress (data: RequestCurrentAccountAddress): Promise { - return sendMessage('pri(currentAccount.saveAddress)', data); + return sendMessage('pri(accounts.saveCurrentProxy)', data); } diff --git a/packages/extension-koni-ui/src/messaging/accounts/derive.ts b/packages/extension-koni-ui/src/messaging/accounts/derive.ts index 8aa4a643a5..49d400be5d 100644 --- a/packages/extension-koni-ui/src/messaging/accounts/derive.ts +++ b/packages/extension-koni-ui/src/messaging/accounts/derive.ts @@ -1,8 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestGetDeriveAccounts, ResponseDeriveValidateV2, ResponseGetDeriveAccounts } from '@subwallet/extension-base/background/KoniTypes'; import { ResponseDeriveValidate } from '@subwallet/extension-base/background/types'; +import { RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestGetDeriveAccounts, ResponseDeriveValidateV2, ResponseGetDeriveAccounts } from '@subwallet/extension-base/types'; import { sendMessage } from '../base'; diff --git a/packages/extension-koni-ui/src/messaging/accounts/edit.ts b/packages/extension-koni-ui/src/messaging/accounts/edit.ts index fad58a6638..5d4faf0ba5 100644 --- a/packages/extension-koni-ui/src/messaging/accounts/edit.ts +++ b/packages/extension-koni-ui/src/messaging/accounts/edit.ts @@ -4,9 +4,9 @@ import { sendMessage } from '../base'; export async function editAccount (address: string, name: string): Promise { - return sendMessage('pri(accounts.edit)', { address, name }); + return sendMessage('pri(accounts.edit)', { proxyId: address, name }); } export async function forgetAccount (address: string, lockAfter = false): Promise { - return sendMessage('pri(accounts.forget)', { address, lockAfter }); + return sendMessage('pri(accounts.forget)', { proxyId: address, lockAfter }); } diff --git a/packages/extension-koni-ui/src/messaging/accounts/json.ts b/packages/extension-koni-ui/src/messaging/accounts/json.ts index 6fdc6986f8..df57ad48d0 100644 --- a/packages/extension-koni-ui/src/messaging/accounts/json.ts +++ b/packages/extension-koni-ui/src/messaging/accounts/json.ts @@ -21,9 +21,9 @@ export async function batchRestore (file: KeyringPairs$Json, password: string, a } export async function jsonRestoreV2 (request: RequestJsonRestoreV2): Promise { - return sendMessage('pri(json.restoreV2)', request); + return sendMessage('pri(accounts.json.restoreV2)', request); } export async function batchRestoreV2 (file: KeyringPairs$Json, password: string, accountsInfo: ResponseJsonGetAccountInfo[], isAllowed: boolean): Promise { - return sendMessage('pri(json.batchRestoreV2)', { file, password, accountsInfo, isAllowed }); + return sendMessage('pri(accounts.json.batchRestoreV2)', { file, password, accountsInfo, isAllowed }); } diff --git a/packages/extension-koni-ui/src/messaging/accounts/legacy.ts b/packages/extension-koni-ui/src/messaging/accounts/legacy.ts index de9e4e1fb4..a0ee7a7dfe 100644 --- a/packages/extension-koni-ui/src/messaging/accounts/legacy.ts +++ b/packages/extension-koni-ui/src/messaging/accounts/legacy.ts @@ -23,7 +23,7 @@ export async function subscribeAccounts (cb: (accounts: AccountJson[]) => void): } export async function subscribeAccountsWithCurrentAddress (cb: (data: AccountsWithCurrentAddress) => void): Promise { - return sendMessage('pri(accounts.subscribeWithCurrentAddress)', {}, cb); + return sendMessage('pri(accounts.subscribeWithCurrentProxy)', {}, cb); } export async function subscribeAccountsInputAddress (cb: (data: OptionInputAddress) => void): Promise { diff --git a/packages/extension-koni-ui/src/messaging/qr-signer/index.ts b/packages/extension-koni-ui/src/messaging/qr-signer/index.ts index 69c7acb30b..2d0575324b 100644 --- a/packages/extension-koni-ui/src/messaging/qr-signer/index.ts +++ b/packages/extension-koni-ui/src/messaging/qr-signer/index.ts @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { RequestAccountMeta, RequestParseTransactionSubstrate, RequestQrSignEvm, RequestQrSignSubstrate, ResponseAccountIsLocked, ResponseAccountMeta, ResponseParseTransactionSubstrate, ResponseQrParseRLP, ResponseQrSignEvm, ResponseQrSignSubstrate } from '@subwallet/extension-base/background/KoniTypes'; +import { RequestParseTransactionSubstrate, RequestQrSignEvm, RequestQrSignSubstrate, ResponseAccountIsLocked, ResponseParseTransactionSubstrate, ResponseQrParseRLP, ResponseQrSignEvm, ResponseQrSignSubstrate } from '@subwallet/extension-base/background/KoniTypes'; import { sendMessage } from '../base'; @@ -24,7 +24,3 @@ export async function parseSubstrateTransaction (request: RequestParseTransactio export async function parseEVMTransaction (data: string): Promise { return sendMessage('pri(qr.transaction.parse.evm)', { data }); } - -export async function getAccountMeta (request: RequestAccountMeta): Promise { - return sendMessage('pri(accounts.get.meta)', request); -} diff --git a/packages/extension-koni-ui/src/stores/utils/index.ts b/packages/extension-koni-ui/src/stores/utils/index.ts index c9a4ab7537..bebc876028 100644 --- a/packages/extension-koni-ui/src/stores/utils/index.ts +++ b/packages/extension-koni-ui/src/stores/utils/index.ts @@ -26,7 +26,7 @@ export const updateAccountData = (data: AccountsWithCurrentAddress) => { const accounts = data.accounts; accounts.forEach((accountJson) => { - if (accountJson.address === data.currentAddress) { + if (accountJson.address === data.currentAccountProxy) { currentAccountJson = accountJson; } }); @@ -86,7 +86,7 @@ export const updateAccountsContext = (data: AccountsContext) => { store.dispatch({ type: 'accountState/updateAccountsContext', payload: data }); }; -export const subscribeAccountsData = lazySubscribeMessage('pri(accounts.subscribeWithCurrentAddress)', {}, updateAccountData, updateAccountData); +export const subscribeAccountsData = lazySubscribeMessage('pri(accounts.subscribeWithCurrentProxy)', {}, updateAccountData, updateAccountData); export const updateKeyringState = (data: KeyringState) => { store.dispatch({ type: 'accountState/updateKeyringState', payload: data }); @@ -178,7 +178,7 @@ export const subscribeAssetLogoMaps = lazySubscribeMessage('pri(settings.logo.as // store.dispatch({ type: 'accountState/updateCurrentAccount', payload: data }); // }; // -// export const subscribeAppSettings = lazySubscribeMessage('pri(accounts.subscribeWithCurrentAddress)', {}, updateCurrentAccountState, updateCurrentAccountState); +// export const subscribeAppSettings = lazySubscribeMessage('pri(accounts.subscribeWithCurrentProxy)', {}, updateCurrentAccountState, updateCurrentAccountState); // export const updateAuthUrls = (data: AuthUrls) => { store.dispatch({ type: 'settings/updateAuthUrls', payload: data }); @@ -190,7 +190,7 @@ export const subscribeAuthUrls = lazySubscribeMessage('pri(authorize.subscribe)' // store.dispatch({ type: 'accountState/updateCurrentAccount', payload: data }); // }; // -// export const subscribeMediaAllowance = lazySubscribeMessage('pri(accounts.subscribeWithCurrentAddress)', {}, updateCurrentAccountState, updateCurrentAccountState); +// export const subscribeMediaAllowance = lazySubscribeMessage('pri(accounts.subscribeWithCurrentProxy)', {}, updateCurrentAccountState, updateCurrentAccountState); export const updateChainInfoMap = (data: Record) => { store.dispatch({ type: 'chainStore/updateChainInfoMap', payload: data }); diff --git a/packages/extension-koni-ui/src/types/derive.ts b/packages/extension-koni-ui/src/types/derive.ts index eaf4daf4d9..34639853f6 100644 --- a/packages/extension-koni-ui/src/types/derive.ts +++ b/packages/extension-koni-ui/src/types/derive.ts @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { CreateDeriveAccountInfo } from '@subwallet/extension-base/background/KoniTypes'; +import { CreateDeriveAccountInfo } from '@subwallet/extension-base/types'; export interface DeriveAccount extends CreateDeriveAccountInfo{ address: string; diff --git a/packages/extension-web-ui/src/Popup/Debugger/DebuggerAPI.tsx b/packages/extension-web-ui/src/Popup/Debugger/DebuggerAPI.tsx index ce581dbbc5..898613c358 100644 --- a/packages/extension-web-ui/src/Popup/Debugger/DebuggerAPI.tsx +++ b/packages/extension-web-ui/src/Popup/Debugger/DebuggerAPI.tsx @@ -22,7 +22,7 @@ const API_LIST = [ // 'pri(accounts.edit)', // 'pri(accounts.show)', - // 'pri(currentAccount.saveAddress)', + // 'pri(accounts.saveCurrentProxy)', // 'pri(settings.changeBalancesVisibility)', // 'pri(settings.saveAccountAllLogo)', // 'pri(settings.saveTheme)', @@ -59,7 +59,7 @@ const API_LIST = [ // 'pri(authorize.cancelV2)', // 'pri(metadata.reject)', // 'pri(accounts.subscribe)', - // 'pri(accounts.subscribeWithCurrentAddress)', + // 'pri(accounts.subscribeWithCurrentProxy)', // 'pri(accounts.subscribeAccountsInputAddress)', // 'pri(accounts.saveRecent)', // 'pri(accounts.triggerSubscription)', @@ -87,8 +87,8 @@ const API_LIST = [ // 'pri(json.account.info)', // 'pri(json.restore)', // 'pri(json.batchRestore)', - // 'pri(json.restoreV2)', - // 'pri(json.batchRestoreV2)', + // 'pri(accounts.json.restoreV2)', + // 'pri(accounts.json.batchRestoreV2)', // 'pri(settings.notification)', // 'pri(price.getPrice)', // 'pri(price.getSubscription)', diff --git a/packages/extension-web-ui/src/messaging/accounts/create.ts b/packages/extension-web-ui/src/messaging/accounts/create.ts index 40cff9c9e4..a615043984 100644 --- a/packages/extension-web-ui/src/messaging/accounts/create.ts +++ b/packages/extension-web-ui/src/messaging/accounts/create.ts @@ -1,8 +1,9 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountExternalError, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateSuriV2, RequestAccountCreateWithSecretKey, ResponseAccountCreateSuriV2, ResponseAccountCreateWithSecretKey, ResponseSeedCreateV2 } from '@subwallet/extension-base/background/KoniTypes'; +import { AccountExternalError, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateWithSecretKey, ResponseAccountCreateWithSecretKey, ResponseSeedCreateV2 } from '@subwallet/extension-base/background/KoniTypes'; import { SeedLengths } from '@subwallet/extension-base/background/types'; +import { RequestAccountCreateSuriV2, ResponseAccountCreateSuriV2 } from '@subwallet/extension-base/types'; import { sendMessage } from '@subwallet/extension-web-ui/messaging/base'; import { KeypairType } from '@polkadot/util-crypto/types'; diff --git a/packages/extension-web-ui/src/messaging/accounts/currentAccount.ts b/packages/extension-web-ui/src/messaging/accounts/currentAccount.ts index 31a9ecd889..70eade9f35 100644 --- a/packages/extension-web-ui/src/messaging/accounts/currentAccount.ts +++ b/packages/extension-web-ui/src/messaging/accounts/currentAccount.ts @@ -6,5 +6,5 @@ import { CurrentAccountInfo } from '@subwallet/extension-base/types'; import { sendMessage } from '@subwallet/extension-web-ui/messaging/base'; export async function saveCurrentAccountAddress (data: RequestCurrentAccountAddress): Promise { - return sendMessage('pri(currentAccount.saveAddress)', data); + return sendMessage('pri(accounts.saveCurrentProxy)', data); } diff --git a/packages/extension-web-ui/src/messaging/accounts/derive.ts b/packages/extension-web-ui/src/messaging/accounts/derive.ts index dd95ab56f5..9346fd78d1 100644 --- a/packages/extension-web-ui/src/messaging/accounts/derive.ts +++ b/packages/extension-web-ui/src/messaging/accounts/derive.ts @@ -1,8 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestGetDeriveAccounts, ResponseDeriveValidateV2, ResponseGetDeriveAccounts } from '@subwallet/extension-base/background/KoniTypes'; import { ResponseDeriveValidate } from '@subwallet/extension-base/background/types'; +import { RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestGetDeriveAccounts, ResponseDeriveValidateV2, ResponseGetDeriveAccounts } from '@subwallet/extension-base/types'; import { sendMessage } from '../base'; diff --git a/packages/extension-web-ui/src/messaging/accounts/json.ts b/packages/extension-web-ui/src/messaging/accounts/json.ts index 25fe2eef76..7638962118 100644 --- a/packages/extension-web-ui/src/messaging/accounts/json.ts +++ b/packages/extension-web-ui/src/messaging/accounts/json.ts @@ -21,9 +21,9 @@ export async function batchRestore (file: KeyringPairs$Json, password: string, a } export async function jsonRestoreV2 (request: RequestJsonRestoreV2): Promise { - return sendMessage('pri(json.restoreV2)', request); + return sendMessage('pri(accounts.json.restoreV2)', request); } export async function batchRestoreV2 (file: KeyringPairs$Json, password: string, accountsInfo: ResponseJsonGetAccountInfo[], isAllowed: boolean): Promise { - return sendMessage('pri(json.batchRestoreV2)', { file, password, accountsInfo, isAllowed }); + return sendMessage('pri(accounts.json.batchRestoreV2)', { file, password, accountsInfo, isAllowed }); } diff --git a/packages/extension-web-ui/src/messaging/accounts/legacy.ts b/packages/extension-web-ui/src/messaging/accounts/legacy.ts index 97d0684da7..82abaa5db9 100644 --- a/packages/extension-web-ui/src/messaging/accounts/legacy.ts +++ b/packages/extension-web-ui/src/messaging/accounts/legacy.ts @@ -23,7 +23,7 @@ export async function subscribeAccounts (cb: (accounts: AccountJson[]) => void): } export async function subscribeAccountsWithCurrentAddress (cb: (data: AccountsWithCurrentAddress) => void): Promise { - return sendMessage('pri(accounts.subscribeWithCurrentAddress)', {}, cb); + return sendMessage('pri(accounts.subscribeWithCurrentProxy)', {}, cb); } export async function subscribeAccountsInputAddress (cb: (data: OptionInputAddress) => void): Promise { diff --git a/packages/extension-web-ui/src/messaging/qr-signer/index.ts b/packages/extension-web-ui/src/messaging/qr-signer/index.ts index 0881b2f6af..db107f2146 100644 --- a/packages/extension-web-ui/src/messaging/qr-signer/index.ts +++ b/packages/extension-web-ui/src/messaging/qr-signer/index.ts @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { RequestAccountMeta, RequestParseTransactionSubstrate, RequestQrSignEvm, RequestQrSignSubstrate, ResponseAccountIsLocked, ResponseAccountMeta, ResponseParseTransactionSubstrate, ResponseQrParseRLP, ResponseQrSignEvm, ResponseQrSignSubstrate } from '@subwallet/extension-base/background/KoniTypes'; +import { RequestParseTransactionSubstrate, RequestQrSignEvm, RequestQrSignSubstrate, ResponseAccountIsLocked, ResponseParseTransactionSubstrate, ResponseQrParseRLP, ResponseQrSignEvm, ResponseQrSignSubstrate } from '@subwallet/extension-base/background/KoniTypes'; import { sendMessage } from '../base'; @@ -24,7 +24,3 @@ export async function parseSubstrateTransaction (request: RequestParseTransactio export async function parseEVMTransaction (data: string): Promise { return sendMessage('pri(qr.transaction.parse.evm)', { data }); } - -export async function getAccountMeta (request: RequestAccountMeta): Promise { - return sendMessage('pri(accounts.get.meta)', request); -} diff --git a/packages/extension-web-ui/src/stores/utils/index.ts b/packages/extension-web-ui/src/stores/utils/index.ts index 3499e76791..f66f4d116b 100644 --- a/packages/extension-web-ui/src/stores/utils/index.ts +++ b/packages/extension-web-ui/src/stores/utils/index.ts @@ -27,7 +27,7 @@ export const updateAccountData = (data: AccountsWithCurrentAddress) => { const accounts = data.accounts; accounts.forEach((accountJson) => { - if (accountJson.address === data.currentAddress) { + if (accountJson.address === data.currentAccountProxy) { currentAccountJson = accountJson; } }); @@ -53,7 +53,7 @@ export const updateAccountsContext = (data: AccountsContext) => { }, 300, 2400); }; -export const subscribeAccountsData = lazySubscribeMessage('pri(accounts.subscribeWithCurrentAddress)', {}, updateAccountData, updateAccountData); +export const subscribeAccountsData = lazySubscribeMessage('pri(accounts.subscribeWithCurrentProxy)', {}, updateAccountData, updateAccountData); export const updateKeyringState = (data: KeyringState) => { addLazy('updateKeyringState', () => { @@ -147,7 +147,7 @@ export const subscribeAssetLogoMaps = lazySubscribeMessage('pri(settings.logo.as // store.dispatch({ type: 'accountState/updateCurrentAccount', payload: data }); // }; // -// export const subscribeAppSettings = lazySubscribeMessage('pri(accounts.subscribeWithCurrentAddress)', {}, updateCurrentAccountState, updateCurrentAccountState); +// export const subscribeAppSettings = lazySubscribeMessage('pri(accounts.subscribeWithCurrentProxy)', {}, updateCurrentAccountState, updateCurrentAccountState); // export const updateAuthUrls = (data: AuthUrls) => { store.dispatch({ type: 'settings/updateAuthUrls', payload: data }); @@ -159,7 +159,7 @@ export const subscribeAuthUrls = lazySubscribeMessage('pri(authorize.subscribe)' // store.dispatch({ type: 'accountState/updateCurrentAccount', payload: data }); // }; // -// export const subscribeMediaAllowance = lazySubscribeMessage('pri(accounts.subscribeWithCurrentAddress)', {}, updateCurrentAccountState, updateCurrentAccountState); +// export const subscribeMediaAllowance = lazySubscribeMessage('pri(accounts.subscribeWithCurrentProxy)', {}, updateCurrentAccountState, updateCurrentAccountState); export const updateChainInfoMap = (data: Record) => { store.dispatch({ type: 'chainStore/updateChainInfoMap', payload: data }); diff --git a/packages/extension-web-ui/src/types/derive.ts b/packages/extension-web-ui/src/types/derive.ts index ad0efed1c0..79bebc0bd7 100644 --- a/packages/extension-web-ui/src/types/derive.ts +++ b/packages/extension-web-ui/src/types/derive.ts @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { CreateDeriveAccountInfo } from '@subwallet/extension-base/background/KoniTypes'; +import { CreateDeriveAccountInfo } from '@subwallet/extension-base/types'; export interface DeriveAccount extends CreateDeriveAccountInfo{ address: string; From 46175ee59b5f5735c7d858751e6a21f56a1b2e4b Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Thu, 25 Jul 2024 18:11:15 +0700 Subject: [PATCH 007/424] [Issue-3384] feat: handle Ton chain-service & balance-service --- package.json | 5 +- .../helpers/subscribe/index.ts | 18 ++- .../balance-service/helpers/subscribe/ton.ts | 68 ++++++++++ .../helpers/subscribe/ton/utils.ts | 3 + .../src/services/balance-service/index.ts | 6 +- .../services/chain-service/handler/TonApi.ts | 121 ++++++++++++++++++ .../chain-service/handler/TonChainHandler.ts | 49 +++++++ .../src/services/chain-service/index.ts | 9 ++ .../src/services/chain-service/types.ts | 6 + .../src/services/chain-service/utils/index.ts | 8 +- .../extension-base/src/types/balance/index.ts | 6 +- yarn.lock | 118 +++++++++++++++-- 12 files changed, 398 insertions(+), 19 deletions(-) create mode 100644 packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts create mode 100644 packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts create mode 100644 packages/extension-base/src/services/chain-service/handler/TonApi.ts create mode 100644 packages/extension-base/src/services/chain-service/handler/TonChainHandler.ts diff --git a/package.json b/package.json index cb3934e200..a34b968c2f 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,9 @@ "webapp:watch": "cd packages/webapp && yarn webpack-dev-server --config webpack.config.cjs --mode development" }, "dependencies": { + "@ton/core": "^0.56.3", + "@ton/crypto": "^3.2.0", + "@ton/ton": "^14.0.0", "@types/node": "^17.0.10", "dexie": "^3.2.2", "loglevel": "^1.8.1", @@ -103,7 +106,7 @@ "@polkadot/types-support": "^12.0.2", "@polkadot/util": "^12.6.2", "@polkadot/util-crypto": "^12.6.2", - "@subwallet/chain-list": "0.2.78", + "@subwallet/chain-list": "/Users/truongnguyen/Workspace/SubWallet-ChainList/packages/chain-list/build", "@subwallet/keyring": "^0.1.5", "@subwallet/react-ui": "5.1.2-b79", "@subwallet/ui-keyring": "^0.1.5", diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts index 0035483662..9c5033031e 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts @@ -4,8 +4,9 @@ import { _AssetType, _ChainAsset, _ChainInfo } from '@subwallet/chain-list/types'; import { APIItemState, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; import { AccountJson } from '@subwallet/extension-base/background/types'; -import { _EvmApi, _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; -import { _getSubstrateGenesisHash, _isChainEvmCompatible, _isPureEvmChain } from '@subwallet/extension-base/services/chain-service/utils'; +import { subscribeTonBalance } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton'; +import { _EvmApi, _SubstrateApi, _TonApi } from '@subwallet/extension-base/services/chain-service/types'; +import { _getSubstrateGenesisHash, _isChainEvmCompatible, _isPureEvmChain, _isPureTonChain } from '@subwallet/extension-base/services/chain-service/utils'; import { BalanceItem } from '@subwallet/extension-base/types'; import { categoryAddresses, filterAssetsByChainAndType } from '@subwallet/extension-base/utils'; import keyring from '@subwallet/ui-keyring'; @@ -91,6 +92,7 @@ export function subscribeBalance ( _chainInfoMap: Record, substrateApiMap: Record, evmApiMap: Record, + tonApiMap: Record, callback: (rs: BalanceItem[]) => void, extrinsicType?: ExtrinsicType ) { @@ -134,6 +136,18 @@ export function subscribeBalance ( }); } + const tonApi = tonApiMap[chainSlug]; + + if (_isPureTonChain(chainInfo)) { + return subscribeTonBalance({ + addresses: useAddresses, + assetMap: chainAssetMap, + callback, + chainInfo, + tonApi + }); + } + const substrateApi = await substrateApiMap[chainSlug].isReady; return subscribeSubstrateBalance(useAddresses, chainInfo, chainAssetMap, substrateApi, evmApi, callback, extrinsicType); diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts new file mode 100644 index 0000000000..6dbcd2c2e0 --- /dev/null +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts @@ -0,0 +1,68 @@ +// Copyright 2019-2022 @subwallet/extension-base +// SPDX-License-Identifier: Apache-2.0 + +import { _AssetType } from '@subwallet/chain-list/types'; +import { APIItemState } from '@subwallet/extension-base/background/KoniTypes'; +import { ASTAR_REFRESH_BALANCE_INTERVAL } from '@subwallet/extension-base/constants'; +import { _TonApi } from '@subwallet/extension-base/services/chain-service/types'; +import { BalanceItem, SubscribeTonPalletBalance } from '@subwallet/extension-base/types'; +import { filterAssetsByChainAndType } from '@subwallet/extension-base/utils'; +import { Address } from '@ton/core'; + +// todo: export subscribeJettonBalance + +async function getTonBalance (addresses: string[], tonApi: _TonApi): Promise { + return await Promise.all(addresses.map(async (address) => { + try { + const tonAddress = Address.parse(address); + + return await tonApi.api.getBalance(tonAddress); + } catch (e) { + return 0n; + } + })); +} + +export function subscribeTonBalance (params: SubscribeTonPalletBalance) { + const { addresses, assetMap, callback, chainInfo, tonApi } = params; + const chain = chainInfo.slug; + const nativeTokenInfo = filterAssetsByChainAndType(assetMap, chain, [_AssetType.NATIVE]); + const nativeTokenSlug = Object.values(nativeTokenInfo)[0]?.slug || ''; + + function getBalance () { + getTonBalance(addresses, tonApi) + .then((balances) => { + return balances.map((balance, index): BalanceItem => { + return { + address: addresses[index], + tokenSlug: nativeTokenSlug, + state: APIItemState.READY, + free: balance.toString(), + locked: '0' + }; + }); + }) + .catch((e) => { + console.error(`Error on get native balance with token ${nativeTokenSlug}`, e); + + return addresses.map((address): BalanceItem => { + return { + address: address, + tokenSlug: nativeTokenSlug, + state: APIItemState.READY, + free: '0', + locked: '0' + }; + }); + }) + .then((items) => callback(items)) + .catch(console.error); + } + + getBalance(); + const interval = setInterval(getBalance, ASTAR_REFRESH_BALANCE_INTERVAL); + + return () => { + clearInterval(interval); + }; +} diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts new file mode 100644 index 0000000000..ed1530690a --- /dev/null +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts @@ -0,0 +1,3 @@ +// Copyright 2019-2022 @subwallet/extension-base +// SPDX-License-Identifier: Apache-2.0 + diff --git a/packages/extension-base/src/services/balance-service/index.ts b/packages/extension-base/src/services/balance-service/index.ts index 63e234b5b8..6c3b30a322 100644 --- a/packages/extension-base/src/services/balance-service/index.ts +++ b/packages/extension-base/src/services/balance-service/index.ts @@ -209,10 +209,11 @@ export class BalanceService implements StoppableServiceInterface { const chainInfoMap = this.state.chainService.getChainInfoMap(); const evmApiMap = this.state.chainService.getEvmApiMap(); const substrateApiMap = this.state.chainService.getSubstrateApiMap(); + const tonApiMap = this.state.chainService.getTonApiMap(); let unsub = noop; - unsub = subscribeBalance([address], [chain], [tSlug], assetMap, chainInfoMap, substrateApiMap, evmApiMap, (result) => { + unsub = subscribeBalance([address], [chain], [tSlug], assetMap, chainInfoMap, substrateApiMap, evmApiMap, tonApiMap, (result) => { const rs = result[0]; if (rs.tokenSlug === tSlug) { @@ -360,6 +361,7 @@ export class BalanceService implements StoppableServiceInterface { const chainInfoMap = this.state.chainService.getChainInfoMap(); const evmApiMap = this.state.chainService.getEvmApiMap(); const substrateApiMap = this.state.chainService.getSubstrateApiMap(); + const tonApiMap = this.state.chainService.getTonApiMap(); const activeChainSlugs = Object.keys(this.state.getActiveChainInfoMap()); const assetState = this.state.chainService.subscribeAssetSettings().value; @@ -369,7 +371,7 @@ export class BalanceService implements StoppableServiceInterface { }) .map((asset) => asset.slug); - const unsub = subscribeBalance(addresses, activeChainSlugs, assets, assetMap, chainInfoMap, substrateApiMap, evmApiMap, (result) => { + const unsub = subscribeBalance(addresses, activeChainSlugs, assets, assetMap, chainInfoMap, substrateApiMap, evmApiMap, tonApiMap, (result) => { !cancel && this.setBalanceItem(result); }, ExtrinsicType.TRANSFER_BALANCE); diff --git a/packages/extension-base/src/services/chain-service/handler/TonApi.ts b/packages/extension-base/src/services/chain-service/handler/TonApi.ts new file mode 100644 index 0000000000..66abce369b --- /dev/null +++ b/packages/extension-base/src/services/chain-service/handler/TonApi.ts @@ -0,0 +1,121 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { _ApiOptions } from '@subwallet/extension-base/services/chain-service/handler/types'; +import { _ChainConnectionStatus, _TonApi } from '@subwallet/extension-base/services/chain-service/types'; +import { createPromiseHandler, PromiseHandler } from '@subwallet/extension-base/utils'; +import { TonClient } from '@ton/ton'; +import { BehaviorSubject } from 'rxjs'; + +export class TonApi implements _TonApi { + chainSlug: string; + api: TonClient; + apiUrl: string; + apiError?: string; + apiRetry = 0; + public readonly isApiConnectedSubject = new BehaviorSubject(false); + public readonly connectionStatusSubject = new BehaviorSubject(_ChainConnectionStatus.DISCONNECTED); + isApiReady = false; + isApiReadyOnce = false; + isReadyHandler: PromiseHandler<_TonApi>; + + providerName: string; + + constructor (chainSlug: string, apiUrl: string, { providerName }: _ApiOptions) { + this.chainSlug = chainSlug; + this.apiUrl = apiUrl; + this.providerName = providerName || 'unknown'; + this.api = this.createProvider(apiUrl); + this.isReadyHandler = createPromiseHandler<_TonApi>(); + + this.connect(); + } + + get isApiConnected (): boolean { + return this.isApiConnectedSubject.getValue(); + } + + get connectionStatus (): _ChainConnectionStatus { + return this.connectionStatusSubject.getValue(); + } + + private updateConnectionStatus (status: _ChainConnectionStatus): void { + const isConnected = status === _ChainConnectionStatus.CONNECTED; + + if (isConnected !== this.isApiConnectedSubject.value) { + this.isApiConnectedSubject.next(isConnected); + } + + if (status !== this.connectionStatusSubject.value) { + this.connectionStatusSubject.next(status); + } + } + + get isReady (): Promise<_TonApi> { + return this.isReadyHandler.promise; + } + + async updateApiUrl (apiUrl: string) { + if (this.apiUrl === apiUrl) { + return; + } + + await this.disconnect(); + + // Create new provider and api + this.apiUrl = apiUrl; + this.api = new TonClient({ endpoint: this.apiUrl }); + } + + async recoverConnect () { + await this.disconnect(); + this.connect(); + // alibaba + } + + private createProvider (apiUrl: string) { // alibaba + return new TonClient({ endpoint: apiUrl }); + } + + connect (): void { + // alibaba. + // There isn't a persistent network connection underlying TonClient. Cant check connection status. + this.isApiReadyOnce = true; + this.onConnect(); + } + + async disconnect () { + this.onDisconnect(); + this.updateConnectionStatus(_ChainConnectionStatus.DISCONNECTED); + + return Promise.resolve(); + } + + destroy () { + // Todo: implement this in the future + return this.disconnect(); + } + + onConnect (): void { + if (!this.isApiConnected) { + console.log(`Connected to ${this.chainSlug} at ${this.apiUrl}`); + this.isApiReady = true; + + if (this.isApiReadyOnce) { + this.isReadyHandler.resolve(this); + } + } + + this.updateConnectionStatus(_ChainConnectionStatus.CONNECTED); + } + + onDisconnect (): void { + this.updateConnectionStatus(_ChainConnectionStatus.DISCONNECTED); + + if (this.isApiConnected) { + console.warn(`Disconnected from ${this.chainSlug} of ${this.apiUrl} (TON)`); + this.isApiReady = false; + this.isReadyHandler = createPromiseHandler<_TonApi>(); + } + } +} diff --git a/packages/extension-base/src/services/chain-service/handler/TonChainHandler.ts b/packages/extension-base/src/services/chain-service/handler/TonChainHandler.ts new file mode 100644 index 0000000000..d722154034 --- /dev/null +++ b/packages/extension-base/src/services/chain-service/handler/TonChainHandler.ts @@ -0,0 +1,49 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { ChainService } from '@subwallet/extension-base/services/chain-service'; +import { AbstractChainHandler } from '@subwallet/extension-base/services/chain-service/handler/AbstractChainHandler'; +import { TonApi } from '@subwallet/extension-base/services/chain-service/handler/TonApi'; + +import { logger as createLogger } from '@polkadot/util/logger'; +import { Logger } from '@polkadot/util/types'; + +export class TonChainHandler extends AbstractChainHandler { + private tonApiMap: Record = {}; + private logger: Logger; + + constructor (parent?: ChainService) { + super(parent); + this.logger = createLogger('ton-chain-handler'); + } + + public getTonApiMap () { + return this.tonApiMap; + } + + public getTonApiByChain (chain: string) { + return this.tonApiMap[chain]; + } + + public getApiByChain (chain: string) { + return this.getTonApiByChain(chain); + } + + public setTonApi (chain: string, tonApi: TonApi) { + this.tonApiMap[chain] = tonApi; + } + + public initApi () { + + } + + public recoverApi (chain: string) { + const existed = this.getTonApiByChain(chain); + + if (existed && !existed.isApiReadyOnce) { + console.log(`Reconnect ${existed.providerName || existed.chainSlug} at ${existed.apiUrl}`); + + return existed.recoverConnect(); + } + } +} diff --git a/packages/extension-base/src/services/chain-service/index.ts b/packages/extension-base/src/services/chain-service/index.ts index 054eb4b4c3..c379df2a3a 100644 --- a/packages/extension-base/src/services/chain-service/index.ts +++ b/packages/extension-base/src/services/chain-service/index.ts @@ -8,6 +8,7 @@ import { _DEFAULT_ACTIVE_CHAINS, _ZK_ASSET_PREFIX, LATEST_CHAIN_DATA_FETCHING_IN import { EvmChainHandler } from '@subwallet/extension-base/services/chain-service/handler/EvmChainHandler'; import { MantaPrivateHandler } from '@subwallet/extension-base/services/chain-service/handler/manta/MantaPrivateHandler'; import { SubstrateChainHandler } from '@subwallet/extension-base/services/chain-service/handler/SubstrateChainHandler'; +import { TonChainHandler } from '@subwallet/extension-base/services/chain-service/handler/TonChainHandler'; import { _CHAIN_VALIDATION_ERROR } from '@subwallet/extension-base/services/chain-service/handler/types'; import { _ChainApiStatus, _ChainConnectionStatus, _ChainState, _CUSTOM_PREFIX, _DataMap, _EvmApi, _NetworkUpsertParams, _NFT_CONTRACT_STANDARDS, _SMART_CONTRACT_STANDARDS, _SmartContractTokenInfo, _SubstrateApi, _ValidateCustomAssetRequest, _ValidateCustomAssetResponse } from '@subwallet/extension-base/services/chain-service/types'; import { _isAssetAutoEnable, _isAssetCanPayTxFee, _isAssetFungibleToken, _isChainEnabled, _isCustomAsset, _isCustomChain, _isCustomProvider, _isEqualContractAddress, _isEqualSmartContractAsset, _isMantaZkAsset, _isPureEvmChain, _isPureSubstrateChain, _parseAssetRefKey, fetchPatchData, randomizeProvider, updateLatestChainInfo } from '@subwallet/extension-base/services/chain-service/utils'; @@ -86,6 +87,7 @@ export class ChainService { private substrateChainHandler: SubstrateChainHandler; private evmChainHandler: EvmChainHandler; + private tonChainHandler: TonChainHandler; private mantaChainHandler: MantaPrivateHandler | undefined; refreshLatestChainDataTimeOut: NodeJS.Timer | undefined; @@ -130,6 +132,7 @@ export class ChainService { this.substrateChainHandler = new SubstrateChainHandler(this); this.evmChainHandler = new EvmChainHandler(this); + this.tonChainHandler = new TonChainHandler(this); this.logger = createLogger('chain-service'); } @@ -175,6 +178,10 @@ export class ChainService { return this.substrateChainHandler.getSubstrateApiMap(); } + public getTonApiMap () { + return this.tonChainHandler.getTonApiMap(); + } + public getSubstrateApi (slug: string) { return this.substrateChainHandler.getSubstrateApiByChain(slug); } @@ -1228,6 +1235,7 @@ export class ChainService { evmInfo: storedChainInfo.evmInfo, substrateInfo: storedChainInfo.substrateInfo, bitcoinInfo: storedChainInfo.bitcoinInfo ?? null, + tonInfo: storedChainInfo.tonInfo ?? null, isTestnet: storedChainInfo.isTestnet, chainStatus: storedChainInfo.chainStatus, icon: storedChainInfo.icon, @@ -1473,6 +1481,7 @@ export class ChainService { substrateInfo, evmInfo, bitcoinInfo: null, + tonInfo: null, isTestnet: false, chainStatus: _ChainStatus.ACTIVE, icon: '', // Todo: Allow update with custom chain, diff --git a/packages/extension-base/src/services/chain-service/types.ts b/packages/extension-base/src/services/chain-service/types.ts index 8e49996842..47baba4389 100644 --- a/packages/extension-base/src/services/chain-service/types.ts +++ b/packages/extension-base/src/services/chain-service/types.ts @@ -12,6 +12,7 @@ import { ApiPromise } from '@polkadot/api'; import { SubmittableExtrinsicFunction } from '@polkadot/api/promise/types'; import { ChainProperties, ChainType } from '@polkadot/types/interfaces'; import { Registry } from '@polkadot/types/types'; +import {TonClient} from "@ton/ton"; export interface _DataMap { chainInfoMap: Record, @@ -105,6 +106,11 @@ export interface _EvmApi extends _ChainBaseApi { isReady: Promise<_EvmApi>; } +export interface _TonApi extends _ChainBaseApi { + api: TonClient; + isReady: Promise<_TonApi>; +} + export type _NetworkUpsertParams = { mode: 'update' | 'insert', chainEditInfo: { diff --git a/packages/extension-base/src/services/chain-service/utils/index.ts b/packages/extension-base/src/services/chain-service/utils/index.ts index 1c473b5800..29f6bc619d 100644 --- a/packages/extension-base/src/services/chain-service/utils/index.ts +++ b/packages/extension-base/src/services/chain-service/utils/index.ts @@ -61,11 +61,15 @@ export function _isEqualSmartContractAsset (asset1: _ChainAsset, asset2: _ChainA } export function _isPureEvmChain (chainInfo: _ChainInfo) { - return (chainInfo.evmInfo !== null && chainInfo.substrateInfo === null); + return (chainInfo.evmInfo !== null && chainInfo.substrateInfo === null && chainInfo.tonInfo === null); } export function _isPureSubstrateChain (chainInfo: _ChainInfo) { - return (chainInfo.evmInfo === null && chainInfo.substrateInfo !== null); + return (chainInfo.evmInfo === null && chainInfo.substrateInfo !== null && chainInfo.tonInfo === null); +} + +export function _isPureTonChain (chainInfo: _ChainInfo) { + return (chainInfo.evmInfo === null && chainInfo.substrateInfo === null && chainInfo.tonInfo !== null); } export function _getOriginChainOfAsset (assetSlug: string) { diff --git a/packages/extension-base/src/types/balance/index.ts b/packages/extension-base/src/types/balance/index.ts index aeb456ba6a..1cb7ef0166 100644 --- a/packages/extension-base/src/types/balance/index.ts +++ b/packages/extension-base/src/types/balance/index.ts @@ -3,7 +3,7 @@ import { _ChainAsset, _ChainInfo } from '@subwallet/chain-list/types'; import { _BalanceMetadata, APIItemState, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; -import { _EvmApi } from '@subwallet/extension-base/services/chain-service/types'; +import { _EvmApi, _TonApi } from '@subwallet/extension-base/services/chain-service/types'; import { ApiPromise } from '@polkadot/api'; import { BN } from '@polkadot/util'; @@ -65,3 +65,7 @@ export interface SubscribeSubstratePalletBalance extends SubscribeBasePalletBala export interface SubscribeEvmPalletBalance extends SubscribeBasePalletBalance { evmApi: _EvmApi; } + +export interface SubscribeTonPalletBalance extends SubscribeBasePalletBalance { + tonApi: _TonApi; +} diff --git a/yarn.lock b/yarn.lock index 1de7f151a9..9268dd6e15 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6050,14 +6050,14 @@ __metadata: languageName: node linkType: hard -"@subwallet/chain-list@npm:0.2.78": - version: 0.2.78 - resolution: "@subwallet/chain-list@npm:0.2.78" +"@subwallet/chain-list@file:/Users/truongnguyen/Workspace/SubWallet-ChainList/packages/chain-list/build::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.2.79-beta.0 + resolution: "@subwallet/chain-list@file:/Users/truongnguyen/Workspace/SubWallet-ChainList/packages/chain-list/build#/Users/truongnguyen/Workspace/SubWallet-ChainList/packages/chain-list/build::hash=06e6dc&locator=root-workspace-0b6124%40workspace%3A." dependencies: "@polkadot/dev": 0.67.167 "@polkadot/util": ^12.5.1 eventemitter3: ^5.0.1 - checksum: 396de6972f065be1b75fd5ef349e61ebe18c5cfb10da54f634a78ba19c7841459f255c8e05175f267dcf5c3883d63c96d4f3ab5576652f331acb969b620c8fc5 + checksum: 65bf980da5abc85881df37f8fffbc40f557369b8f26f3b937a1149ccb5aecdd32e93a8e6d23dd5df87baf410496fd912eaabdba13ff9c80549ff24d9a9b82913 languageName: node linkType: hard @@ -6779,6 +6779,53 @@ __metadata: languageName: node linkType: hard +"@ton/core@npm:^0.56.3": + version: 0.56.3 + resolution: "@ton/core@npm:0.56.3" + dependencies: + symbol.inspect: 1.0.1 + peerDependencies: + "@ton/crypto": ">=3.2.0" + checksum: bb0d2e444b832a64933f0a98e1f681f609d90b0085f5a138f0d066e47d7c4005f288455aea8c48d669e704ea803dd8e7e3e5a07dcdeb1d7dab57e1b01126f34b + languageName: node + linkType: hard + +"@ton/crypto-primitives@npm:2.0.0": + version: 2.0.0 + resolution: "@ton/crypto-primitives@npm:2.0.0" + dependencies: + jssha: 3.2.0 + checksum: 1a686b04dc1430792341339f0ddc1e2f5effd94d31ae118baf2c510e074201495801787b2ca881a6ceb587f89212eb081ec9e3979d374d9c9004c6c4b61fc591 + languageName: node + linkType: hard + +"@ton/crypto@npm:^3.2.0": + version: 3.2.0 + resolution: "@ton/crypto@npm:3.2.0" + dependencies: + "@ton/crypto-primitives": 2.0.0 + jssha: 3.2.0 + tweetnacl: 1.0.3 + checksum: 0851fad506796573ec6079c1f36d3d07f4070abb90a4a2f3e621f6b2b2c6725c13096a5afdabb24611aa2a063ba335dcbc742e98a3c1cd0bbf3645ae55c1a8c6 + languageName: node + linkType: hard + +"@ton/ton@npm:^14.0.0": + version: 14.0.0 + resolution: "@ton/ton@npm:14.0.0" + dependencies: + axios: ^1.6.7 + dataloader: ^2.0.0 + symbol.inspect: 1.0.1 + teslabot: ^1.3.0 + zod: ^3.21.4 + peerDependencies: + "@ton/core": ">=0.56.0" + "@ton/crypto": ">=3.2.0" + checksum: b0be725460cf12a5c4ef9e71a1a04b93759d1fb917d410ba2249c1bec6bdbc826b8b77a1ae5d4cdb2f7a02ec5d73136c3556f81ab62260649f7203ed77708aea + languageName: node + linkType: hard + "@tootallnate/once@npm:1": version: 1.1.2 resolution: "@tootallnate/once@npm:1.1.2" @@ -9653,6 +9700,17 @@ __metadata: languageName: node linkType: hard +"axios@npm:^1.6.7": + version: 1.7.2 + resolution: "axios@npm:1.7.2" + dependencies: + follow-redirects: ^1.15.6 + form-data: ^4.0.0 + proxy-from-env: ^1.1.0 + checksum: e457e2b0ab748504621f6fa6609074ac08c824bf0881592209dfa15098ece7e88495300e02cd22ba50b3468fd712fe687e629dcb03d6a3f6a51989727405aedf + languageName: node + linkType: hard + "axios@npm:^1.6.8": version: 1.6.8 resolution: "axios@npm:1.6.8" @@ -12229,6 +12287,13 @@ __metadata: languageName: node linkType: hard +"dataloader@npm:^2.0.0": + version: 2.2.2 + resolution: "dataloader@npm:2.2.2" + checksum: 4dabd247089c29f194e94d5434d504f99156c5c214a03463c20f3f17f40398d7e179edee69a27c16e315519ac8739042a810090087ae26449a0e685156a02c65 + languageName: node + linkType: hard + "dayjs@npm:^1.11.1": version: 1.11.7 resolution: "dayjs@npm:1.11.7" @@ -18907,6 +18972,13 @@ __metadata: languageName: node linkType: hard +"jssha@npm:3.2.0": + version: 3.2.0 + resolution: "jssha@npm:3.2.0" + checksum: 2adb8a9a57a79360379e843c0548e240d072c2ef12aef39ef6a784315686bd6f65501e9353fdd2f3a604f64af07e7eab04a0ed92b221cdfea97d671d7b8e14f4 + languageName: node + linkType: hard + "jsx-ast-utils@npm:^2.4.1 || ^3.0.0": version: 3.3.3 resolution: "jsx-ast-utils@npm:3.3.3" @@ -24569,6 +24641,9 @@ __metadata: "@babel/cli": ^7.19.3 "@babel/core": ^7.19.3 "@polkadot/dev": ^0.65.23 + "@ton/core": ^0.56.3 + "@ton/crypto": ^3.2.0 + "@ton/ton": ^14.0.0 "@types/jest": ^29.5.0 "@types/node": ^17.0.10 axios: ^1.6.2 @@ -25932,6 +26007,13 @@ __metadata: languageName: node linkType: hard +"symbol.inspect@npm:1.0.1": + version: 1.0.1 + resolution: "symbol.inspect@npm:1.0.1" + checksum: 47fa8d38d0bc5d04c06df2f71bba1a723ee0e015ca042c47b29c11f107877dd1a2e2d2154c9ef5eec11e92e4165d126c844f06d05da80e477581c8f284f05fdf + languageName: node + linkType: hard + "system-architecture@npm:^0.1.0": version: 0.1.0 resolution: "system-architecture@npm:0.1.0" @@ -26089,6 +26171,13 @@ __metadata: languageName: node linkType: hard +"teslabot@npm:^1.3.0": + version: 1.5.0 + resolution: "teslabot@npm:1.5.0" + checksum: 1494f83b9070f3d0882c7ce089a69ea46f0f30ee24c14036880ed5f49882cd80ff47f1c5543c9c973d250596896640130c16b221e84be296474a02f65e7187d0 + languageName: node + linkType: hard + "test-exclude@npm:^6.0.0": version: 6.0.0 resolution: "test-exclude@npm:6.0.0" @@ -26458,6 +26547,13 @@ __metadata: languageName: node linkType: hard +"tweetnacl@npm:1.0.3, tweetnacl@npm:^1.0.3": + version: 1.0.3 + resolution: "tweetnacl@npm:1.0.3" + checksum: e4a57cac188f0c53f24c7a33279e223618a2bfb5fea426231991652a13247bea06b081fd745d71291fcae0f4428d29beba1b984b1f1ce6f66b06a6d1ab90645c + languageName: node + linkType: hard + "tweetnacl@npm:^0.14.3, tweetnacl@npm:~0.14.0": version: 0.14.5 resolution: "tweetnacl@npm:0.14.5" @@ -26465,13 +26561,6 @@ __metadata: languageName: node linkType: hard -"tweetnacl@npm:^1.0.3": - version: 1.0.3 - resolution: "tweetnacl@npm:1.0.3" - checksum: e4a57cac188f0c53f24c7a33279e223618a2bfb5fea426231991652a13247bea06b081fd745d71291fcae0f4428d29beba1b984b1f1ce6f66b06a6d1ab90645c - languageName: node - linkType: hard - "type-check@npm:^0.4.0, type-check@npm:~0.4.0": version: 0.4.0 resolution: "type-check@npm:0.4.0" @@ -28515,6 +28604,13 @@ __metadata: languageName: node linkType: hard +"zod@npm:^3.21.4": + version: 3.23.8 + resolution: "zod@npm:3.23.8" + checksum: 15949ff82118f59c893dacd9d3c766d02b6fa2e71cf474d5aa888570c469dbf5446ac5ad562bb035bf7ac9650da94f290655c194f4a6de3e766f43febd432c5c + languageName: node + linkType: hard + "zwitch@npm:^2.0.0": version: 2.0.4 resolution: "zwitch@npm:2.0.4" From 4636de45ef2f1d50217626e16f104ce912f3787a Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Fri, 26 Jul 2024 11:02:16 +0700 Subject: [PATCH 008/424] [Issue-3384] feat: update ton chain-service --- .../services/chain-service/handler/TonApi.ts | 5 +- .../chain-service/handler/TonChainHandler.ts | 58 ++++++++++++++++--- .../src/services/chain-service/index.ts | 35 ++++++++--- 3 files changed, 80 insertions(+), 18 deletions(-) diff --git a/packages/extension-base/src/services/chain-service/handler/TonApi.ts b/packages/extension-base/src/services/chain-service/handler/TonApi.ts index 66abce369b..71c1571db9 100644 --- a/packages/extension-base/src/services/chain-service/handler/TonApi.ts +++ b/packages/extension-base/src/services/chain-service/handler/TonApi.ts @@ -78,9 +78,10 @@ export class TonApi implements _TonApi { } connect (): void { + this.updateConnectionStatus(_ChainConnectionStatus.CONNECTING); // alibaba. // There isn't a persistent network connection underlying TonClient. Cant check connection status. - this.isApiReadyOnce = true; + // this.isApiReadyOnce = true; this.onConnect(); } @@ -113,7 +114,7 @@ export class TonApi implements _TonApi { this.updateConnectionStatus(_ChainConnectionStatus.DISCONNECTED); if (this.isApiConnected) { - console.warn(`Disconnected from ${this.chainSlug} of ${this.apiUrl} (TON)`); + console.warn(`Disconnected from ${this.chainSlug} of ${this.apiUrl}`); this.isApiReady = false; this.isReadyHandler = createPromiseHandler<_TonApi>(); } diff --git a/packages/extension-base/src/services/chain-service/handler/TonChainHandler.ts b/packages/extension-base/src/services/chain-service/handler/TonChainHandler.ts index d722154034..7921cf7d7e 100644 --- a/packages/extension-base/src/services/chain-service/handler/TonChainHandler.ts +++ b/packages/extension-base/src/services/chain-service/handler/TonChainHandler.ts @@ -4,17 +4,14 @@ import { ChainService } from '@subwallet/extension-base/services/chain-service'; import { AbstractChainHandler } from '@subwallet/extension-base/services/chain-service/handler/AbstractChainHandler'; import { TonApi } from '@subwallet/extension-base/services/chain-service/handler/TonApi'; - -import { logger as createLogger } from '@polkadot/util/logger'; -import { Logger } from '@polkadot/util/types'; +import { _ApiOptions } from '@subwallet/extension-base/services/chain-service/handler/types'; export class TonChainHandler extends AbstractChainHandler { private tonApiMap: Record = {}; - private logger: Logger; + // eslint-disable-next-line no-useless-constructor constructor (parent?: ChainService) { super(parent); - this.logger = createLogger('ton-chain-handler'); } public getTonApiMap () { @@ -33,11 +30,28 @@ export class TonChainHandler extends AbstractChainHandler { this.tonApiMap[chain] = tonApi; } - public initApi () { + public async initApi (chainSlug: string, apiUrl: string, { onUpdateStatus, providerName }: Omit<_ApiOptions, 'metadata'> = {}) { + const existed = this.getTonApiByChain(chainSlug); + + if (existed) { + existed.connect(); + + if (apiUrl !== existed.apiUrl) { + existed.updateApiUrl(apiUrl).catch(console.error); + } + + return existed; + } + + const apiObject = new TonApi(chainSlug, apiUrl, { providerName }); + + apiObject.connectionStatusSubject.subscribe(this.handleConnection.bind(this, chainSlug)); + apiObject.connectionStatusSubject.subscribe(onUpdateStatus); + return Promise.resolve(apiObject); } - public recoverApi (chain: string) { + public async recoverApi (chain: string): Promise { const existed = this.getTonApiByChain(chain); if (existed && !existed.isApiReadyOnce) { @@ -46,4 +60,34 @@ export class TonChainHandler extends AbstractChainHandler { return existed.recoverConnect(); } } + + destroyTonApi (chain: string) { + const tonApi = this.getApiByChain(chain); + + tonApi?.destroy().catch(console.error); + } + + async sleep () { + this.isSleeping = true; + this.cancelAllRecover(); + + await Promise.all(Object.values(this.getTonApiMap()).map((tonApi) => { + return tonApi.disconnect().catch(console.error); + })); + + return Promise.resolve(); + } + + wakeUp () { + this.isSleeping = false; + const activeChains = this.parent?.getActiveChains() || []; + + for (const chain of activeChains) { + const tonApi = this.getTonApiByChain(chain); + + tonApi?.connect(); + } + + return Promise.resolve(); + } } diff --git a/packages/extension-base/src/services/chain-service/index.ts b/packages/extension-base/src/services/chain-service/index.ts index c379df2a3a..0118166252 100644 --- a/packages/extension-base/src/services/chain-service/index.ts +++ b/packages/extension-base/src/services/chain-service/index.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { AssetLogoMap, AssetRefMap, ChainAssetMap, ChainInfoMap, ChainLogoMap, MultiChainAssetMap } from '@subwallet/chain-list'; -import { _AssetRef, _AssetRefPath, _AssetType, _ChainAsset, _ChainInfo, _ChainStatus, _EvmInfo, _MultiChainAsset, _SubstrateChainType, _SubstrateInfo } from '@subwallet/chain-list/types'; +import { _AssetRef, _AssetRefPath, _AssetType, _ChainAsset, _ChainInfo, _ChainStatus, _EvmInfo, _MultiChainAsset, _SubstrateChainType, _SubstrateInfo, _TonInfo } from '@subwallet/chain-list/types'; import { AssetSetting, ValidateNetworkResponse } from '@subwallet/extension-base/background/KoniTypes'; import { _DEFAULT_ACTIVE_CHAINS, _ZK_ASSET_PREFIX, LATEST_CHAIN_DATA_FETCHING_INTERVAL } from '@subwallet/extension-base/services/chain-service/constants'; import { EvmChainHandler } from '@subwallet/extension-base/services/chain-service/handler/EvmChainHandler'; @@ -174,16 +174,20 @@ export class ChainService { return this.evmChainHandler.getEvmApiMap(); } + public getSubstrateApi (slug: string) { + return this.substrateChainHandler.getSubstrateApiByChain(slug); + } + public getSubstrateApiMap () { return this.substrateChainHandler.getSubstrateApiMap(); } - public getTonApiMap () { - return this.tonChainHandler.getTonApiMap(); + public getTonApi (slug: string) { + return this.tonChainHandler.getTonApiByChain(slug); } - public getSubstrateApi (slug: string) { - return this.substrateChainHandler.getSubstrateApiByChain(slug); + public getTonApiMap () { + return this.tonChainHandler.getTonApiMap(); } public getChainCurrentProviderByKey (slug: string) { @@ -914,6 +918,12 @@ export class ChainService { this.evmChainHandler.setEvmApi(chainInfo.slug, chainApi); } + + if (chainInfo.tonInfo !== null && chainInfo.tonInfo !== undefined) { + const chainApi = await this.tonChainHandler.initApi(chainInfo.slug, endpoint, { providerName, onUpdateStatus }); + + this.tonChainHandler.setTonApi(chainInfo.slug, chainApi); + } } private destroyApiForChain (chainInfo: _ChainInfo) { @@ -924,6 +934,10 @@ export class ChainService { if (chainInfo.evmInfo !== null) { this.evmChainHandler.destroyEvmApi(chainInfo.slug); } + + if (chainInfo.tonInfo !== null) { + this.evmChainHandler.destroyEvmApi(chainInfo.slug); + } } public async enableChain (chainSlug: string) { @@ -1235,7 +1249,7 @@ export class ChainService { evmInfo: storedChainInfo.evmInfo, substrateInfo: storedChainInfo.substrateInfo, bitcoinInfo: storedChainInfo.bitcoinInfo ?? null, - tonInfo: storedChainInfo.tonInfo ?? null, + tonInfo: storedChainInfo.tonInfo, isTestnet: storedChainInfo.isTestnet, chainStatus: storedChainInfo.chainStatus, icon: storedChainInfo.icon, @@ -1443,6 +1457,7 @@ export class ChainService { let substrateInfo: _SubstrateInfo | null = null; let evmInfo: _EvmInfo | null = null; + const tonInfo: _TonInfo | null = null; if (params.chainSpec.genesisHash !== '') { substrateInfo = { @@ -1481,7 +1496,7 @@ export class ChainService { substrateInfo, evmInfo, bitcoinInfo: null, - tonInfo: null, + tonInfo, isTestnet: false, chainStatus: _ChainStatus.ACTIVE, icon: '', // Todo: Allow update with custom chain, @@ -1811,7 +1826,8 @@ export class ChainService { public async stopAllChainApis () { await Promise.all([ this.substrateChainHandler.sleep(), - this.evmChainHandler.sleep() + this.evmChainHandler.sleep(), + this.tonChainHandler.sleep() ]); this.stopCheckLatestChainData(); @@ -1820,7 +1836,8 @@ export class ChainService { public async resumeAllChainApis () { await Promise.all([ this.substrateChainHandler.wakeUp(), - this.evmChainHandler.wakeUp() + this.evmChainHandler.wakeUp(), + this.tonChainHandler.wakeUp() ]); this.checkLatestData(); From 2919daa8bcc480a452ab34376a835904fa16b892 Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Fri, 26 Jul 2024 12:35:51 +0700 Subject: [PATCH 009/424] [Issue-3384] test: test Ton balance --- .../src/services/balance-service/helpers/subscribe/index.ts | 2 +- .../src/services/balance-service/helpers/subscribe/ton.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts index 9c5033031e..784acaeeed 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts @@ -140,7 +140,7 @@ export function subscribeBalance ( if (_isPureTonChain(chainInfo)) { return subscribeTonBalance({ - addresses: useAddresses, + addresses: ['EQChB2eMoFG4ThuEsZ6ehlBPKJXOjNxlR5B7qKZNGIv256Da'], assetMap: chainAssetMap, callback, chainInfo, diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts index 6dbcd2c2e0..bab91ced79 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts @@ -9,7 +9,7 @@ import { BalanceItem, SubscribeTonPalletBalance } from '@subwallet/extension-bas import { filterAssetsByChainAndType } from '@subwallet/extension-base/utils'; import { Address } from '@ton/core'; -// todo: export subscribeJettonBalance +// todo: export subscribeJettonBalance (later) async function getTonBalance (addresses: string[], tonApi: _TonApi): Promise { return await Promise.all(addresses.map(async (address) => { @@ -34,7 +34,7 @@ export function subscribeTonBalance (params: SubscribeTonPalletBalance) { .then((balances) => { return balances.map((balance, index): BalanceItem => { return { - address: addresses[index], + address: 'UQChB2eMoFG4ThuEsZ6ehlBPKJXOjNxlR5B7qKZNGIv25_0f', tokenSlug: nativeTokenSlug, state: APIItemState.READY, free: balance.toString(), From 002a2c31e763610a1fa0854a3e74c04cbaa863f9 Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Fri, 26 Jul 2024 15:26:57 +0700 Subject: [PATCH 010/424] [Issue-3384] fix: fix some minor bugs --- .../src/services/balance-service/helpers/subscribe/ton.ts | 2 +- .../src/services/chain-service/handler/TonApi.ts | 2 ++ .../src/services/chain-service/handler/TonChainHandler.ts | 2 +- .../extension-base/src/services/chain-service/index.ts | 8 +++++++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts index bab91ced79..971566e045 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts @@ -34,7 +34,7 @@ export function subscribeTonBalance (params: SubscribeTonPalletBalance) { .then((balances) => { return balances.map((balance, index): BalanceItem => { return { - address: 'UQChB2eMoFG4ThuEsZ6ehlBPKJXOjNxlR5B7qKZNGIv25_0f', + address: '5HpbHTE8NKRHffnDwUDE7VR1ZtRSK1xWT4NrbvkSv54Fvqxx', // fake address tokenSlug: nativeTokenSlug, state: APIItemState.READY, free: balance.toString(), diff --git a/packages/extension-base/src/services/chain-service/handler/TonApi.ts b/packages/extension-base/src/services/chain-service/handler/TonApi.ts index 71c1571db9..5b82e6810f 100644 --- a/packages/extension-base/src/services/chain-service/handler/TonApi.ts +++ b/packages/extension-base/src/services/chain-service/handler/TonApi.ts @@ -70,6 +70,8 @@ export class TonApi implements _TonApi { async recoverConnect () { await this.disconnect(); this.connect(); + + await this.isReadyHandler.promise; // alibaba } diff --git a/packages/extension-base/src/services/chain-service/handler/TonChainHandler.ts b/packages/extension-base/src/services/chain-service/handler/TonChainHandler.ts index 7921cf7d7e..b5aebbf2e7 100644 --- a/packages/extension-base/src/services/chain-service/handler/TonChainHandler.ts +++ b/packages/extension-base/src/services/chain-service/handler/TonChainHandler.ts @@ -62,7 +62,7 @@ export class TonChainHandler extends AbstractChainHandler { } destroyTonApi (chain: string) { - const tonApi = this.getApiByChain(chain); + const tonApi = this.getTonApiByChain(chain); tonApi?.destroy().catch(console.error); } diff --git a/packages/extension-base/src/services/chain-service/index.ts b/packages/extension-base/src/services/chain-service/index.ts index 0118166252..ca28ed0d75 100644 --- a/packages/extension-base/src/services/chain-service/index.ts +++ b/packages/extension-base/src/services/chain-service/index.ts @@ -936,7 +936,7 @@ export class ChainService { } if (chainInfo.tonInfo !== null) { - this.evmChainHandler.destroyEvmApi(chainInfo.slug); + this.tonChainHandler.destroyTonApi(chainInfo.slug); } } @@ -1617,6 +1617,8 @@ export class ChainService { // TODO: EVM chain might have WS provider if (provider.startsWith('http')) { + // todo: handle validate ton provider + // HTTP provider is EVM by default api = await this.evmChainHandler.initApi('custom', provider); } else { @@ -1823,6 +1825,10 @@ export class ChainService { this.evmChainHandler.recoverApi(slug).catch(console.error); } + public refreshTonApi (slug: string) { // alibaba + this.tonChainHandler.recoverApi(slug).catch(console.error); + } + public async stopAllChainApis () { await Promise.all([ this.substrateChainHandler.sleep(), From aab724e44608f5b9573c3c7af9723adfcc3ce940 Mon Sep 17 00:00:00 2001 From: S2kael Date: Fri, 26 Jul 2024 12:03:58 +0700 Subject: [PATCH 011/424] [MasterAccount] Update keyring lib (install local) --- package.json | 4 +- .../src/koni/background/handlers/Extension.ts | 6 +- .../src/koni/background/handlers/Tabs.ts | 6 +- .../helpers/subscribe/index.ts | 8 +- .../keyring-service/account-context.ts | 17 +- .../handler/EvmRequestHandler.ts | 4 +- .../handler/SubstrateRequestHandler.ts | 3 +- .../src/services/transaction-service/index.ts | 4 +- .../handler/PolkadotRequestHandler.ts | 7 +- .../src/types/account/info/keyring.ts | 3 +- .../src/utils/account/common.ts | 2 +- .../src/utils/account/derive.ts | 5 +- .../src/utils/account/transform.ts | 4 +- .../extension-base/src/utils/canDerive.ts | 2 +- packages/extension-base/src/utils/index.ts | 8 +- packages/extension-inject/src/types.ts | 2 +- .../useGetChainSlugsByCurrentAccount.ts | 2 +- .../src/messaging/accounts/derive.ts | 4 - packages/extension-koni-ui/src/utils/index.ts | 10 +- .../src/messaging/accounts/derive.ts | 4 - .../src/messaging/accounts/edit.ts | 4 +- yarn.lock | 483 +++++++++++++++++- 22 files changed, 508 insertions(+), 84 deletions(-) diff --git a/package.json b/package.json index cfb63c93de..3066bd99a7 100644 --- a/package.json +++ b/package.json @@ -104,9 +104,9 @@ "@polkadot/util": "^12.6.2", "@polkadot/util-crypto": "^12.6.2", "@subwallet/chain-list": "0.2.75", - "@subwallet/keyring": "^0.1.5", + "@subwallet/keyring": "file:../SubWallet-Base/packages/keyring/build/", "@subwallet/react-ui": "5.1.2-b79", - "@subwallet/ui-keyring": "^0.1.5", + "@subwallet/ui-keyring": "file:../SubWallet-Base/packages/ui-keyring/build/", "@zondax/ledger-substrate": "0.44.2", "babel-core": "^7.0.0-bridge.0", "babel-jest": "^29.3.1", diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index ca36a60ca5..c9635384d3 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -408,7 +408,7 @@ export default class KoniExtension { } try { - return parentPair.derive(suri, metadata); + return parentPair.substrate.derive(suri, metadata); } catch (err) { throw new Error(t('"{{suri}}" is not a valid derivation path', { replace: { suri } })); } @@ -2095,7 +2095,7 @@ export default class KoniExtension { data = `0x${message}`; } - signed = await pair.evmSigner.signMessage(data, 'personal_sign'); + signed = await pair.evm.signMessage(data, 'personal_sign'); } else { const tx: QrTransaction | null = createTransactionFromRLP(message); @@ -2121,7 +2121,7 @@ export default class KoniExtension { // @ts-ignore const transaction = new LegacyTransaction(txObject, { common }); - const signedTranaction = LegacyTransaction.fromSerializedTx(hexToU8a(pair.evmSigner.signTransaction(transaction))); + const signedTranaction = LegacyTransaction.fromSerializedTx(hexToU8a(pair.evm.signTransaction(transaction))); signed = signatureToHex({ r: signedTranaction.r?.toString(16) || '', diff --git a/packages/extension-base/src/koni/background/handlers/Tabs.ts b/packages/extension-base/src/koni/background/handlers/Tabs.ts index e3d62dc538..5dfc109e7b 100644 --- a/packages/extension-base/src/koni/background/handlers/Tabs.ts +++ b/packages/extension-base/src/koni/background/handlers/Tabs.ts @@ -20,7 +20,7 @@ import { _NetworkUpsertParams } from '@subwallet/extension-base/services/chain-s import { _generateCustomProviderKey } from '@subwallet/extension-base/services/chain-service/utils'; import { AuthUrls } from '@subwallet/extension-base/services/request-service/types'; import { DEFAULT_CHAIN_PATROL_ENABLE } from '@subwallet/extension-base/services/setting-service/constants'; -import { canDerive, getEVMChainInfo, stripUrl, singleAddressToAccount } from '@subwallet/extension-base/utils'; +import { canDerive, getEVMChainInfo, pairToAccount, stripUrl } from '@subwallet/extension-base/utils'; import { InjectedMetadataKnown, MetadataDef, ProviderMeta } from '@subwallet/extension-inject/types'; import { KeyringPair } from '@subwallet/keyring/types'; import keyring from '@subwallet/ui-keyring'; @@ -149,7 +149,7 @@ export default class KoniTabs { throw new Error('Account {{address}} not in allowed list'.replace('{{address}}', address)); } - return this.#koniState.sign(url, new RequestBytesSign(request), singleAddressToAccount(pair)); + return this.#koniState.sign(url, new RequestBytesSign(request), pairToAccount(pair)); } private async extrinsicSign (url: string, request: SignerPayloadJSON): Promise { @@ -161,7 +161,7 @@ export default class KoniTabs { throw new Error('Account {{address}} not in allowed list'.replace('{{address}}', address)); } - return this.#koniState.sign(url, new RequestExtrinsicSign(request), singleAddressToAccount(pair)); + return this.#koniState.sign(url, new RequestExtrinsicSign(request), pairToAccount(pair)); } private metadataProvide (url: string, request: MetadataDef): Promise { diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts index 7a01b209b9..2c536f1fcb 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts @@ -6,7 +6,7 @@ import { APIItemState, ExtrinsicType } from '@subwallet/extension-base/backgroun import { _EvmApi, _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; import { _getSubstrateGenesisHash, _isChainEvmCompatible, _isPureEvmChain } from '@subwallet/extension-base/services/chain-service/utils'; import { AccountJson, BalanceItem } from '@subwallet/extension-base/types'; -import { categoryAddresses, filterAssetsByChainAndType } from '@subwallet/extension-base/utils'; +import { categoryAddresses, filterAssetsByChainAndType, pairToAccount } from '@subwallet/extension-base/utils'; import keyring from '@subwallet/ui-keyring'; import { subscribeEVMBalance } from './evm'; @@ -26,11 +26,7 @@ export const getAccountJsonByAddress = (address: string): AccountJson | null => const pair = keyring.getPair(address); if (pair) { - return { - address: pair.address, - type: pair.type, - ...pair.meta - }; + return pairToAccount(pair); } else { return null; } diff --git a/packages/extension-base/src/services/keyring-service/account-context.ts b/packages/extension-base/src/services/keyring-service/account-context.ts index 7eb0b21fdd..3ae949715f 100644 --- a/packages/extension-base/src/services/keyring-service/account-context.ts +++ b/packages/extension-base/src/services/keyring-service/account-context.ts @@ -3,7 +3,6 @@ import { AccountExternalError, AccountExternalErrorCode, AccountRefMap, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateWithSecretKey, RequestBatchRestoreV2, RequestJsonRestoreV2, ResponseAccountCreateWithSecretKey } from '@subwallet/extension-base/background/KoniTypes'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; -import { _getEvmChainId, _getSubstrateGenesisHash } from '@subwallet/extension-base/services/chain-service/utils'; import { KeyringService } from '@subwallet/extension-base/services/keyring-service/index'; import { AccountProxyStore, AccountRefStore, CurrentAccountStore, ModifyPairStore } from '@subwallet/extension-base/stores'; import { AccountJson, AccountProxy, AccountProxyData, AccountProxyMap, AccountProxyStoreData, AccountProxyType, CreateDeriveAccountInfo, CurrentAccountInfo, DeriveAccountInfo, ModifyPairStoreData, RequestAccountCreateSuriV2, RequestDeriveAccountProxy, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestGetDeriveAccounts, ResponseAccountCreateSuriV2, ResponseDeriveValidateV2, ResponseGetDeriveAccounts } from '@subwallet/extension-base/types'; @@ -801,11 +800,11 @@ export class AccountContext { meta.suri = `//${index}`; - return parentPair.deriveEvm(index, meta); + return parentPair.evm.derive(index, meta); } else { meta.suri = suri; - return parentPair.derive(suri, meta); + return parentPair.substrate.derive(suri, meta); } }; @@ -864,7 +863,7 @@ export class AccountContext { parentAddress, suri: `//${index}` }; - const childPair = isEvm ? parentPair.deriveEvm(index, meta) : parentPair.derive(meta.suri, meta); + const childPair = isEvm ? parentPair.evm.derive(index, meta) : parentPair.substrate.derive(meta.suri, meta); const address = childPair.address; this._saveCurrentAccountAddress(address, () => { @@ -910,10 +909,10 @@ export class AccountContext { meta.suri = `//${index}`; - childPair = parentPair.deriveEvm(index, meta); + childPair = parentPair.evm.derive(index, meta); } else { meta.suri = suri; - childPair = parentPair.derive(suri, meta); + childPair = parentPair.substrate.derive(suri, meta); } return { @@ -938,7 +937,7 @@ export class AccountContext { for (let i = start; i < end; i++) { const suri = `//${i}`; - const pair = isEvm ? parentPair.deriveEvm(i, {}) : parentPair.derive(suri, {}); + const pair = isEvm ? parentPair.evm.derive(i, {}) : parentPair.substrate.derive(suri, {}); result.push({ address: pair.address, suri: suri }); } @@ -990,7 +989,7 @@ export class AccountContext { parentAddress, suri: `//${index}` }; - const childPair = isEvm ? parentPair.deriveEvm(index, meta) : parentPair.derive(meta.suri, meta); + const childPair = isEvm ? parentPair.evm.derive(index, meta) : parentPair.substrate.derive(meta.suri, meta); const address = childPair.address; this._saveCurrentAccountAddress(address, () => { @@ -1036,7 +1035,7 @@ export class AccountContext { }; // todo: will update logic if support more type - const childPair = isEvm ? pair.deriveEvm(index, meta) : pair.derive(index.toString(), meta); + const childPair = isEvm ? pair.evm.derive(index, meta) : pair.substrate.derive(index.toString(), meta); keyring.addPair(childPair, true); }); diff --git a/packages/extension-base/src/services/request-service/handler/EvmRequestHandler.ts b/packages/extension-base/src/services/request-service/handler/EvmRequestHandler.ts index 11291d6cd5..2493d04fd3 100644 --- a/packages/extension-base/src/services/request-service/handler/EvmRequestHandler.ts +++ b/packages/extension-base/src/services/request-service/handler/EvmRequestHandler.ts @@ -160,7 +160,7 @@ export default class EvmRequestHandler { case 'eth_signTypedData_v1': case 'eth_signTypedData_v3': case 'eth_signTypedData_v4': - return await pair.evmSigner.signMessage(payload, type); + return await pair.evm.signMessage(payload, type); default: throw new EvmProviderError(EvmProviderErrorType.INVALID_PARAMS, t('Unsupported action')); } @@ -230,7 +230,7 @@ export default class EvmRequestHandler { keyring.unlockPair(pair.address); } - return pair.evmSigner.signTransaction(tx); + return pair.evm.signTransaction(tx); } private async decorateResult (t: T, request: ConfirmationDefinitions[T][0], result: ConfirmationDefinitions[T][1]) { diff --git a/packages/extension-base/src/services/request-service/handler/SubstrateRequestHandler.ts b/packages/extension-base/src/services/request-service/handler/SubstrateRequestHandler.ts index 732f0fbe87..39c2995fa7 100644 --- a/packages/extension-base/src/services/request-service/handler/SubstrateRequestHandler.ts +++ b/packages/extension-base/src/services/request-service/handler/SubstrateRequestHandler.ts @@ -6,6 +6,7 @@ import { RequestSign, Resolver, ResponseSigning, SigningRequest } from '@subwall import RequestService from '@subwallet/extension-base/services/request-service'; import { SignRequest } from '@subwallet/extension-base/services/request-service/types'; import { AccountJson } from '@subwallet/extension-base/types'; +import { pairToAccount } from '@subwallet/extension-base/utils'; import { getId } from '@subwallet/extension-base/utils/getId'; import { isInternalRequest } from '@subwallet/extension-base/utils/request'; import keyring from '@subwallet/ui-keyring'; @@ -95,7 +96,7 @@ export default class SubstrateRequestHandler { return new Promise((resolve, reject): void => { const pair = keyring.getPair(address); - const account: AccountJson = { address: pair.address, ...pair.meta }; + const account: AccountJson = pairToAccount(pair); this.#substrateRequests[id] = { ...this.signComplete(id, resolve, reject), diff --git a/packages/extension-base/src/services/transaction-service/index.ts b/packages/extension-base/src/services/transaction-service/index.ts index a73e720f3f..2ba1ef18d1 100644 --- a/packages/extension-base/src/services/transaction-service/index.ts +++ b/packages/extension-base/src/services/transaction-service/index.ts @@ -20,7 +20,7 @@ import { getExplorerLink, parseTransactionData } from '@subwallet/extension-base import { isWalletConnectRequest } from '@subwallet/extension-base/services/wallet-connect-service/helpers'; import { Web3Transaction } from '@subwallet/extension-base/signers/types'; import { AccountJson, LeavePoolAdditionalData, RequestStakePoolingBonding, RequestYieldStepSubmit, SpecialYieldPoolInfo, YieldPoolType } from '@subwallet/extension-base/types'; -import { _isRuntimeUpdated, anyNumberToBN, reformatAddress } from '@subwallet/extension-base/utils'; +import { _isRuntimeUpdated, anyNumberToBN, pairToAccount, reformatAddress } from '@subwallet/extension-base/utils'; import { mergeTransactionAndSignature } from '@subwallet/extension-base/utils/eth/mergeTransactionAndSignature'; import { isContractAddress, parseContractInput } from '@subwallet/extension-base/utils/eth/parseTransaction'; import { BN_ZERO } from '@subwallet/extension-base/utils/number'; @@ -840,7 +840,7 @@ export default class TransactionService { const chainInfo = this.state.chainService.getChainInfoByKey(chain); const accountPair = keyring.getPair(address); - const account: AccountJson = { address, ...accountPair.meta }; + const account: AccountJson = pairToAccount(accountPair); if (!payload.account) { payload.account = account; diff --git a/packages/extension-base/src/services/wallet-connect-service/handler/PolkadotRequestHandler.ts b/packages/extension-base/src/services/wallet-connect-service/handler/PolkadotRequestHandler.ts index 17f7273c75..bb5b30fa0f 100644 --- a/packages/extension-base/src/services/wallet-connect-service/handler/PolkadotRequestHandler.ts +++ b/packages/extension-base/src/services/wallet-connect-service/handler/PolkadotRequestHandler.ts @@ -8,7 +8,7 @@ import RequestService from '@subwallet/extension-base/services/request-service'; import WalletConnectService from '@subwallet/extension-base/services/wallet-connect-service'; import { getWCId, parseRequestParams } from '@subwallet/extension-base/services/wallet-connect-service/helpers'; import { POLKADOT_SIGNING_METHODS } from '@subwallet/extension-base/services/wallet-connect-service/types'; -import { isSameAddress } from '@subwallet/extension-base/utils'; +import { isSameAddress, pairToAccount } from '@subwallet/extension-base/utils'; import keyring from '@subwallet/ui-keyring'; import { SignClientTypes } from '@walletconnect/types'; import { getSdkError } from '@walletconnect/utils'; @@ -59,7 +59,7 @@ export default class PolkadotRequestHandler { const address = pair.address; this.#requestService - .sign(url, new RequestBytesSign({ address: address, data: param.message, type: 'bytes' }), { address, ...pair.meta }, getWCId(id)) + .sign(url, new RequestBytesSign({ address: address, data: param.message, type: 'bytes' }), pairToAccount(pair), getWCId(id)) .then(async ({ signature }) => { await this.#walletConnectService.responseRequest({ topic: topic, @@ -75,10 +75,9 @@ export default class PolkadotRequestHandler { this.#checkAccount(param.address, sessionAccounts); const pair = keyring.getPair(param.address); - const address = pair.address; this.#requestService - .sign(url, new RequestExtrinsicSign(param.transactionPayload), { address, ...pair.meta }, getWCId(id)) + .sign(url, new RequestExtrinsicSign(param.transactionPayload), pairToAccount(pair), getWCId(id)) .then(async ({ signature }) => { await this.#walletConnectService.responseRequest({ topic: topic, diff --git a/packages/extension-base/src/types/account/info/keyring.ts b/packages/extension-base/src/types/account/info/keyring.ts index aa5f17e735..84394a6ad7 100644 --- a/packages/extension-base/src/types/account/info/keyring.ts +++ b/packages/extension-base/src/types/account/info/keyring.ts @@ -1,8 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-base authors & contributors // SPDX-License-Identifier: Apache-2.0 -import type { KeyringPair$Meta } from '@subwallet/keyring/types'; -import type { KeypairType } from '@polkadot/util-crypto/types'; +import type { KeypairType, KeyringPair$Meta } from '@subwallet/keyring/types'; import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; diff --git a/packages/extension-base/src/utils/account/common.ts b/packages/extension-base/src/utils/account/common.ts index aa838329b9..857b1cd9e4 100644 --- a/packages/extension-base/src/utils/account/common.ts +++ b/packages/extension-base/src/utils/account/common.ts @@ -1,8 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-base authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { KeypairType } from '@polkadot/util-crypto/types'; import { reformatAddress } from '@subwallet/extension-base/utils'; +import { KeypairType } from '@subwallet/keyring/types'; import { decodeAddress, encodeAddress, isAddress, isEthereumAddress } from '@polkadot/util-crypto'; diff --git a/packages/extension-base/src/utils/account/derive.ts b/packages/extension-base/src/utils/account/derive.ts index a4c95a90c9..f1ab793e63 100644 --- a/packages/extension-base/src/utils/account/derive.ts +++ b/packages/extension-base/src/utils/account/derive.ts @@ -1,12 +1,11 @@ // Copyright 2019-2022 @subwallet/extension-base authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { KeyringPair, KeyringPair$Meta } from '@subwallet/keyring/types'; +import { KeypairType, KeyringPair, KeyringPair$Meta } from '@subwallet/keyring/types'; import { keyring } from '@subwallet/ui-keyring'; import { t } from 'i18next'; import { assert } from '@polkadot/util'; -import { KeypairType } from '@polkadot/util-crypto/types'; interface DeriveInfo { suri?: string; @@ -88,7 +87,7 @@ export const findNextDerivePair = (parentAddress: string): NextDerivePair => { suri: `//${index}` }; - const childPair = isEvm ? parentPair.deriveEvm(index, meta) : parentPair.derive(meta.suri, meta); + const childPair = isEvm ? parentPair.evm.derive(index, meta) : parentPair.substrate.derive(meta.suri, meta); const address = childPair.address; return { diff --git a/packages/extension-base/src/utils/account/transform.ts b/packages/extension-base/src/utils/account/transform.ts index 0c8266be6d..0e39f028ab 100644 --- a/packages/extension-base/src/utils/account/transform.ts +++ b/packages/extension-base/src/utils/account/transform.ts @@ -4,11 +4,9 @@ import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; import { AccountJson, AccountMetadataData, AccountSignMode } from '@subwallet/extension-base/types'; -import { KeyringPair, KeyringPair$Meta } from '@subwallet/keyring/types'; +import { KeypairType, KeyringPair, KeyringPair$Meta } from '@subwallet/keyring/types'; import { SingleAddress, SubjectInfo } from '@subwallet/ui-keyring/observable/types'; -import { KeypairType } from '@polkadot/util-crypto/types'; - export const getAccountSignMode = (address: string, _meta?: KeyringPair$Meta): AccountSignMode => { const meta = _meta as AccountMetadataData; diff --git a/packages/extension-base/src/utils/canDerive.ts b/packages/extension-base/src/utils/canDerive.ts index 0a64ba2d47..434ce62e0d 100644 --- a/packages/extension-base/src/utils/canDerive.ts +++ b/packages/extension-base/src/utils/canDerive.ts @@ -1,7 +1,7 @@ // Copyright 2019-2022 @polkadot/extension authors & contributors // SPDX-License-Identifier: Apache-2.0 -import type { KeypairType } from '@polkadot/util-crypto/types'; +import type { KeypairType } from '@subwallet/keyring/types'; export function canDerive (type?: KeypairType): boolean { return !!type && ['ed25519', 'sr25519', 'ecdsa', 'ethereum'].includes(type); diff --git a/packages/extension-base/src/utils/index.ts b/packages/extension-base/src/utils/index.ts index 3d39d9f897..ed81c5637d 100644 --- a/packages/extension-base/src/utils/index.ts +++ b/packages/extension-base/src/utils/index.ts @@ -6,10 +6,12 @@ import { AccountAuthType } from '@subwallet/extension-base/background/types'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; import { getRandomIpfsGateway, SUBWALLET_IPFS } from '@subwallet/extension-base/koni/api/nft/config'; import { AccountJson } from '@subwallet/extension-base/types'; +import { decodeAddress, encodeAddress, getKeypairTypeByAddress } from '@subwallet/keyring'; +import { KeypairType } from '@subwallet/keyring/types'; import { t } from 'i18next'; import { assert, BN, hexToU8a, isHex } from '@polkadot/util'; -import { decodeAddress, encodeAddress, ethereumEncode, isEthereumAddress } from '@polkadot/util-crypto'; +import { ethereumEncode, isEthereumAddress } from '@polkadot/util-crypto'; export { canDerive } from './canDerive'; export * from './mv3'; @@ -44,11 +46,13 @@ export function reformatAddress (address: string, networkPrefix = 42, isEthereum return ethereumEncode(publicKey); } + const type: KeypairType = getKeypairTypeByAddress(address); + if (networkPrefix < 0) { return address; } - return encodeAddress(publicKey, networkPrefix); + return encodeAddress(publicKey, networkPrefix, type); } catch (e) { console.warn('Get error while reformat address', address, e); diff --git a/packages/extension-inject/src/types.ts b/packages/extension-inject/src/types.ts index 3c70abee27..035270308a 100644 --- a/packages/extension-inject/src/types.ts +++ b/packages/extension-inject/src/types.ts @@ -1,10 +1,10 @@ // Copyright 2019-2022 @polkadot/extension-inject authors & contributors // SPDX-License-Identifier: Apache-2.0 +import type { KeypairType } from '@subwallet/keyring/types'; import type { Signer as InjectedSigner } from '@polkadot/api/types'; import type { ProviderInterface } from '@polkadot/rpc-provider/types'; import type { ExtDef } from '@polkadot/types/extrinsic/signedExtensions/types'; -import type { KeypairType } from '@polkadot/util-crypto/types'; // eslint-disable-next-line no-undef type This = typeof globalThis; diff --git a/packages/extension-koni-ui/src/hooks/common/useGetChainSlugsByCurrentAccount.ts b/packages/extension-koni-ui/src/hooks/common/useGetChainSlugsByCurrentAccount.ts index 202f0d9b26..13fffb1b9f 100644 --- a/packages/extension-koni-ui/src/hooks/common/useGetChainSlugsByCurrentAccount.ts +++ b/packages/extension-koni-ui/src/hooks/common/useGetChainSlugsByCurrentAccount.ts @@ -1,7 +1,7 @@ // Copyright 2019-2022 @polkadot/extension-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import type { KeypairType } from '@polkadot/util-crypto/types'; +import type { KeypairType } from '@subwallet/keyring/types'; import { _ChainInfo, _ChainStatus } from '@subwallet/chain-list/types'; import { _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; diff --git a/packages/extension-koni-ui/src/messaging/accounts/derive.ts b/packages/extension-koni-ui/src/messaging/accounts/derive.ts index 49d400be5d..d33a522a5a 100644 --- a/packages/extension-koni-ui/src/messaging/accounts/derive.ts +++ b/packages/extension-koni-ui/src/messaging/accounts/derive.ts @@ -29,7 +29,3 @@ export async function validateDerivationPath (parentAddress: string, suri: strin export async function deriveAccount (parentAddress: string, suri: string, parentPassword: string, name: string, password: string, genesisHash: string | null): Promise { return sendMessage('pri(derivation.create)', { genesisHash, name, parentAddress, parentPassword, password, suri }); } - -export async function deriveAccountV2 (parentAddress: string, suri: string, parentPassword: string, name: string, password: string, genesisHash: string | null, isAllowed: boolean): Promise { - return sendMessage('pri(derivation.createV2)', { genesisHash, name, parentAddress, suri, isAllowed }); -} diff --git a/packages/extension-koni-ui/src/utils/index.ts b/packages/extension-koni-ui/src/utils/index.ts index e0a991ba7a..a7ccc4e0b3 100644 --- a/packages/extension-koni-ui/src/utils/index.ts +++ b/packages/extension-koni-ui/src/utils/index.ts @@ -7,12 +7,13 @@ import { NetworkJson } from '@subwallet/extension-base/background/KoniTypes'; import { AccountWithChildren } from '@subwallet/extension-base/background/types'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; import { _getChainSubstrateAddressPrefix, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; -import { AccountJson } from '@subwallet/extension-base/types'; +import { AccountJson, AccountSignMode } from '@subwallet/extension-base/types'; import { Recoded } from '@subwallet/extension-koni-ui/types'; import { isAccountAll } from '@subwallet/extension-koni-ui/utils/account/accountAll'; import reformatAddress from '@subwallet/extension-koni-ui/utils/account/reformatAddress'; +import { decodeAddress } from '@subwallet/keyring'; -import { decodeAddress, isEthereumAddress } from '@polkadot/util-crypto'; +import { isEthereumAddress } from '@polkadot/util-crypto'; import { KeypairType } from '@polkadot/util-crypto/types'; import { findAccountByAddress } from './account/account'; @@ -43,7 +44,10 @@ export const defaultRecoded: Recoded = { account: null, formatted: null, prefix: export const accountAllRecoded: Recoded = { account: { - address: ALL_ACCOUNT_KEY + address: ALL_ACCOUNT_KEY, + accountActions: [], + transactionActions: [], + signMode: AccountSignMode.ALL_ACCOUNT }, formatted: ALL_ACCOUNT_KEY, prefix: 42, diff --git a/packages/extension-web-ui/src/messaging/accounts/derive.ts b/packages/extension-web-ui/src/messaging/accounts/derive.ts index 9346fd78d1..c576fa8ed8 100644 --- a/packages/extension-web-ui/src/messaging/accounts/derive.ts +++ b/packages/extension-web-ui/src/messaging/accounts/derive.ts @@ -29,7 +29,3 @@ export async function validateDerivationPath (parentAddress: string, suri: strin export async function deriveAccount (parentAddress: string, suri: string, parentPassword: string, name: string, password: string, genesisHash: string | null): Promise { return sendMessage('pri(derivation.create)', { genesisHash, name, parentAddress, parentPassword, password, suri }); } - -export async function deriveAccountV2 (parentAddress: string, suri: string, parentPassword: string, name: string, password: string, genesisHash: string | null, isAllowed: boolean): Promise { - return sendMessage('pri(derivation.createV2)', { genesisHash, name, parentAddress, suri, isAllowed }); -} diff --git a/packages/extension-web-ui/src/messaging/accounts/edit.ts b/packages/extension-web-ui/src/messaging/accounts/edit.ts index 7c49a7d49b..6bcf6d2b25 100644 --- a/packages/extension-web-ui/src/messaging/accounts/edit.ts +++ b/packages/extension-web-ui/src/messaging/accounts/edit.ts @@ -4,9 +4,9 @@ import { sendMessage } from '../base'; export async function editAccount (address: string, name: string): Promise { - return sendMessage('pri(accounts.edit)', { address, name }); + return sendMessage('pri(accounts.edit)', { proxyId: address, name }); } export async function forgetAccount (address: string, lockAfter = false): Promise { - return sendMessage('pri(accounts.forget)', { address, lockAfter }); + return sendMessage('pri(accounts.forget)', { proxyId: address, lockAfter }); } diff --git a/yarn.lock b/yarn.lock index 8b650037d3..d9b37823b0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1705,7 +1705,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.10.4, @babel/runtime@npm:^7.10.5, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.14.5, @babel/runtime@npm:^7.17.2, @babel/runtime@npm:^7.17.9, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": +"@babel/runtime@npm:^7.10.4, @babel/runtime@npm:^7.10.5, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.14.5, @babel/runtime@npm:^7.17.2, @babel/runtime@npm:^7.17.9, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": version: 7.20.1 resolution: "@babel/runtime@npm:7.20.1" dependencies: @@ -1723,6 +1723,15 @@ __metadata: languageName: node linkType: hard +"@babel/runtime@npm:^7.20.1": + version: 7.24.8 + resolution: "@babel/runtime@npm:7.24.8" + dependencies: + regenerator-runtime: ^0.14.0 + checksum: 6b1e4230580f67a807ad054720812bbefbb024cc2adc1159d050acbb764c4c81c7ac5f7a042c48f578987c5edc2453c71039268df059058e9501fa6023d764b0 + languageName: node + linkType: hard + "@babel/runtime@npm:^7.23.2": version: 7.23.9 resolution: "@babel/runtime@npm:7.23.9" @@ -1828,6 +1837,16 @@ __metadata: languageName: node linkType: hard +"@bitcoinerlab/secp256k1@npm:^1.1.1": + version: 1.1.1 + resolution: "@bitcoinerlab/secp256k1@npm:1.1.1" + dependencies: + "@noble/hashes": ^1.1.5 + "@noble/secp256k1": ^1.7.1 + checksum: 01f23cb05553ceb3783513b9c79b3303289bf55cd694150967b15ce60a35821cad68794ae958088cbe6b8a2b02c9294ebff78fd6b53d6fd78662eeda7bc742f1 + languageName: node + linkType: hard + "@chainflip/sdk@npm:^1.3.0": version: 1.3.0 resolution: "@chainflip/sdk@npm:1.3.0" @@ -2137,6 +2156,15 @@ __metadata: languageName: node linkType: hard +"@ethereumjs/rlp@npm:^5.0.2": + version: 5.0.2 + resolution: "@ethereumjs/rlp@npm:5.0.2" + bin: + rlp: bin/rlp.cjs + checksum: b569061ddb1f4cf56a82f7a677c735ba37f9e94e2bbaf567404beb9e2da7aa1f595e72fc12a17c61f7aec67fd5448443efe542967c685a2fe0ffc435793dcbab + languageName: node + linkType: hard + "@ethereumjs/tx@npm:3.3.2": version: 3.3.2 resolution: "@ethereumjs/tx@npm:3.3.2" @@ -2147,7 +2175,19 @@ __metadata: languageName: node linkType: hard -"@ethereumjs/tx@npm:^5.0.0, @ethereumjs/tx@npm:^5.1.0": +"@ethereumjs/tx@npm:^5.0.0": + version: 5.3.0 + resolution: "@ethereumjs/tx@npm:5.3.0" + dependencies: + "@ethereumjs/common": ^4.3.0 + "@ethereumjs/rlp": ^5.0.2 + "@ethereumjs/util": ^9.0.3 + ethereum-cryptography: ^2.1.3 + checksum: 1fa6ef7a5eea7605ca065ab4df5446bdbf17a368267b60cdbb315cfcd78ac82dc689ba020093ae3d42940ad196bfffbfa705fd51f30a277c6eb60b04432db743 + languageName: node + linkType: hard + +"@ethereumjs/tx@npm:^5.1.0": version: 5.1.0 resolution: "@ethereumjs/tx@npm:5.1.0" dependencies: @@ -2179,6 +2219,16 @@ __metadata: languageName: node linkType: hard +"@ethereumjs/util@npm:^9.0.3": + version: 9.0.3 + resolution: "@ethereumjs/util@npm:9.0.3" + dependencies: + "@ethereumjs/rlp": ^5.0.2 + ethereum-cryptography: ^2.1.3 + checksum: 231dae61268c84d514a6c992a770559bb94a21c753c02287d08781cbeae01a6e5b5479af9f0d3d412d532fda6e9b1eeb746e617a68b738907a4a8ee4e24d79a6 + languageName: node + linkType: hard + "@ethersproject/abi@npm:^5.5.0, @ethersproject/abi@npm:^5.6.3, @ethersproject/abi@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/abi@npm:5.7.0" @@ -3711,6 +3761,15 @@ __metadata: languageName: node linkType: hard +"@noble/curves@npm:1.4.2, @noble/curves@npm:~1.4.0": + version: 1.4.2 + resolution: "@noble/curves@npm:1.4.2" + dependencies: + "@noble/hashes": 1.4.0 + checksum: c475a83c4263e2c970eaba728895b9b5d67e0ca880651e9c6e3efdc5f6a4f07ceb5b043bf71c399fc80fada0b8706e69d0772bffdd7b9de2483b988973a34cba + languageName: node + linkType: hard + "@noble/hashes@npm:1.1.2": version: 1.1.2 resolution: "@noble/hashes@npm:1.1.2" @@ -3732,6 +3791,13 @@ __metadata: languageName: node linkType: hard +"@noble/hashes@npm:1.4.0, @noble/hashes@npm:^1.1.5, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:~1.4.0": + version: 1.4.0 + resolution: "@noble/hashes@npm:1.4.0" + checksum: 8ba816ae26c90764b8c42493eea383716396096c5f7ba6bea559993194f49d80a73c081f315f4c367e51bd2d5891700bcdfa816b421d24ab45b41cb03e4f3342 + languageName: node + linkType: hard + "@noble/hashes@npm:^1.2.0": version: 1.3.0 resolution: "@noble/hashes@npm:1.3.0" @@ -3739,14 +3805,7 @@ __metadata: languageName: node linkType: hard -"@noble/hashes@npm:^1.3.1": - version: 1.4.0 - resolution: "@noble/hashes@npm:1.4.0" - checksum: 8ba816ae26c90764b8c42493eea383716396096c5f7ba6bea559993194f49d80a73c081f315f4c367e51bd2d5891700bcdfa816b421d24ab45b41cb03e4f3342 - languageName: node - linkType: hard - -"@noble/secp256k1@npm:1.7.1": +"@noble/secp256k1@npm:1.7.1, @noble/secp256k1@npm:^1.7.1": version: 1.7.1 resolution: "@noble/secp256k1@npm:1.7.1" checksum: d2301f1f7690368d8409a3152450458f27e54df47e3f917292de3de82c298770890c2de7c967d237eff9c95b70af485389a9695f73eb05a43e2bd562d18b18cb @@ -5601,6 +5660,13 @@ __metadata: languageName: node linkType: hard +"@scure/base@npm:~1.1.6": + version: 1.1.7 + resolution: "@scure/base@npm:1.1.7" + checksum: d9084be9a2f27971df1684af9e40bb750e86f549345e1bb3227fb61673c0c83569c92c1cb0a4ddccb32650b39d3cd3c145603b926ba751c9bc60c27317549b20 + languageName: node + linkType: hard + "@scure/bip32@npm:1.3.3": version: 1.3.3 resolution: "@scure/bip32@npm:1.3.3" @@ -5612,6 +5678,17 @@ __metadata: languageName: node linkType: hard +"@scure/bip32@npm:1.4.0": + version: 1.4.0 + resolution: "@scure/bip32@npm:1.4.0" + dependencies: + "@noble/curves": ~1.4.0 + "@noble/hashes": ~1.4.0 + "@scure/base": ~1.1.6 + checksum: eff491651cbf2bea8784936de75af5fc020fc1bbb9bcb26b2cfeefbd1fb2440ebfaf30c0733ca11c0ae1e272a2ef4c3c34ba5c9fb3e1091c3285a4272045b0c6 + languageName: node + linkType: hard + "@scure/bip39@npm:1.2.2": version: 1.2.2 resolution: "@scure/bip39@npm:1.2.2" @@ -5622,6 +5699,16 @@ __metadata: languageName: node linkType: hard +"@scure/bip39@npm:1.3.0": + version: 1.3.0 + resolution: "@scure/bip39@npm:1.3.0" + dependencies: + "@noble/hashes": ~1.4.0 + "@scure/base": ~1.1.6 + checksum: dbb0b27df753eb6c6380010b25cc9a9ea31f9cb08864fc51e69e5880ff7e2b8f85b72caea1f1f28af165e83b72c48dd38617e43fc632779d025b50ba32ea759e + languageName: node + linkType: hard + "@semantic-ui-react/event-stack@npm:^3.1.3": version: 3.1.3 resolution: "@semantic-ui-react/event-stack@npm:3.1.3" @@ -6385,19 +6472,29 @@ __metadata: languageName: unknown linkType: soft -"@subwallet/keyring@npm:^0.1.5": +"@subwallet/keyring@file:../SubWallet-Base/packages/keyring/build/::locator=root-workspace-0b6124%40workspace%3A.": version: 0.1.5 - resolution: "@subwallet/keyring@npm:0.1.5" + resolution: "@subwallet/keyring@file:../SubWallet-Base/packages/keyring/build/#../SubWallet-Base/packages/keyring/build/::hash=6b6f81&locator=root-workspace-0b6124%40workspace%3A." dependencies: "@ethereumjs/tx": ^5.0.0 "@polkadot/util": ^12.2.1 "@polkadot/util-crypto": ^12.2.1 + "@ton/core": ^0.56.3 + "@ton/crypto": ^3.2.0 + "@ton/crypto-primitives": ^2.0.0 + "@ton/ton": ^13.11.2 bcryptjs: ^2.4.3 + bignumber.js: ^9.1.2 + bip322-js: ^2.0.0 + bitcoinjs-lib: ^6.1.5 + bitcoinjs-message: ^2.2.0 + ecpair: ^2.1.0 eth-simple-keyring: ^4.2.0 eventemitter3: ^4.0.7 rxjs: ^7.5.6 + tiny-secp256k1: ^2.2.3 tslib: ^2.6.2 - checksum: 24282ab64bb78c41f957052dd664f17c2d20e16cbce50670a6cb771635f84b98c14c6b1174d3f6eb42fb9bda275a1525b818102c6ace56de5fbd391574153cda + checksum: 25e91849d921a3bb7fe4b0c3b3d866f05ba73b97729961aba19287ab8c168584af90a9c9924ec8e146804373ed49e2689f6b63e42706ac4d6fd09aa98b1f67c2 languageName: node linkType: hard @@ -6479,9 +6576,9 @@ __metadata: languageName: node linkType: hard -"@subwallet/ui-keyring@npm:^0.1.5": +"@subwallet/ui-keyring@file:../SubWallet-Base/packages/ui-keyring/build/::locator=root-workspace-0b6124%40workspace%3A.": version: 0.1.5 - resolution: "@subwallet/ui-keyring@npm:0.1.5" + resolution: "@subwallet/ui-keyring@file:../SubWallet-Base/packages/ui-keyring/build/#../SubWallet-Base/packages/ui-keyring/build/::hash=49ace5&locator=root-workspace-0b6124%40workspace%3A." dependencies: "@babel/runtime": ^7.20.1 "@polkadot/ui-settings": 2.9.14 @@ -6491,7 +6588,7 @@ __metadata: mkdirp: ^1.0.4 rxjs: ^7.5.7 store: ^2.0.12 - checksum: db100686fae694ed7298a2cc99b371f35003559f0c7b77cd5a9cd22fa453f5c1397e3882c92168777417b66045bccc371012641c810ebc735d781c39083fc38f + checksum: 7e29c84602f0c6d004929707079e74ce7aeed2cdf3d4b6e73a32debb06dbbba517c713243839d43a43d82bce6225b39c3fb660e26d9542c42c71269ff71c4746 languageName: node linkType: hard @@ -6724,6 +6821,53 @@ __metadata: languageName: node linkType: hard +"@ton/core@npm:^0.56.3": + version: 0.56.3 + resolution: "@ton/core@npm:0.56.3" + dependencies: + symbol.inspect: 1.0.1 + peerDependencies: + "@ton/crypto": ">=3.2.0" + checksum: bb0d2e444b832a64933f0a98e1f681f609d90b0085f5a138f0d066e47d7c4005f288455aea8c48d669e704ea803dd8e7e3e5a07dcdeb1d7dab57e1b01126f34b + languageName: node + linkType: hard + +"@ton/crypto-primitives@npm:2.0.0, @ton/crypto-primitives@npm:^2.0.0": + version: 2.0.0 + resolution: "@ton/crypto-primitives@npm:2.0.0" + dependencies: + jssha: 3.2.0 + checksum: 1a686b04dc1430792341339f0ddc1e2f5effd94d31ae118baf2c510e074201495801787b2ca881a6ceb587f89212eb081ec9e3979d374d9c9004c6c4b61fc591 + languageName: node + linkType: hard + +"@ton/crypto@npm:^3.2.0": + version: 3.2.0 + resolution: "@ton/crypto@npm:3.2.0" + dependencies: + "@ton/crypto-primitives": 2.0.0 + jssha: 3.2.0 + tweetnacl: 1.0.3 + checksum: 0851fad506796573ec6079c1f36d3d07f4070abb90a4a2f3e621f6b2b2c6725c13096a5afdabb24611aa2a063ba335dcbc742e98a3c1cd0bbf3645ae55c1a8c6 + languageName: node + linkType: hard + +"@ton/ton@npm:^13.11.2": + version: 13.11.2 + resolution: "@ton/ton@npm:13.11.2" + dependencies: + axios: ^1.6.7 + dataloader: ^2.0.0 + symbol.inspect: 1.0.1 + teslabot: ^1.3.0 + zod: ^3.21.4 + peerDependencies: + "@ton/core": ">=0.56.0" + "@ton/crypto": ">=3.2.0" + checksum: d017339a5a4d358eb80207f0afb3e1cc05a4edb157229b974f0bf5d397ad8b1ef7edb2c89c119bab3d6a3829fb6336b5b665665060e2a9c139b1998476c3431e + languageName: node + linkType: hard + "@tootallnate/once@npm:1": version: 1.1.2 resolution: "@tootallnate/once@npm:1.1.2" @@ -9598,6 +9742,17 @@ __metadata: languageName: node linkType: hard +"axios@npm:^1.6.7": + version: 1.7.2 + resolution: "axios@npm:1.7.2" + dependencies: + follow-redirects: ^1.15.6 + form-data: ^4.0.0 + proxy-from-env: ^1.1.0 + checksum: e457e2b0ab748504621f6fa6609074ac08c824bf0881592209dfa15098ece7e88495300e02cd22ba50b3468fd712fe687e629dcb03d6a3f6a51989727405aedf + languageName: node + linkType: hard + "axios@npm:^1.6.8": version: 1.6.8 resolution: "axios@npm:1.6.8" @@ -10377,6 +10532,13 @@ __metadata: languageName: node linkType: hard +"base-x@npm:^4.0.0": + version: 4.0.0 + resolution: "base-x@npm:4.0.0" + checksum: b25db9e07eb1998472a20557c7f00c797dc0595f79df95155ab74274e7fa98b9f2659b3ee547ac8773666b7f69540656793aeb97ad2b1ceccdb6fa5faaf69ac0 + languageName: node + linkType: hard + "base64-js@npm:^1.3.1": version: 1.5.1 resolution: "base64-js@npm:1.5.1" @@ -10407,6 +10569,20 @@ __metadata: languageName: node linkType: hard +"bech32@npm:^1.1.3": + version: 1.1.4 + resolution: "bech32@npm:1.1.4" + checksum: 0e98db619191548390d6f09ff68b0253ba7ae6a55db93dfdbb070ba234c1fd3308c0606fbcc95fad50437227b10011e2698b89f0181f6e7f845c499bd14d0f4b + languageName: node + linkType: hard + +"bech32@npm:^2.0.0": + version: 2.0.0 + resolution: "bech32@npm:2.0.0" + checksum: fa15acb270b59aa496734a01f9155677b478987b773bf701f465858bf1606c6a970085babd43d71ce61895f1baa594cb41a2cd1394bd2c6698f03cc2d811300e + languageName: node + linkType: hard + "before-after-hook@npm:^2.2.0": version: 2.2.3 resolution: "before-after-hook@npm:2.2.3" @@ -10458,6 +10634,28 @@ __metadata: languageName: node linkType: hard +"bip174@npm:^2.1.1": + version: 2.1.1 + resolution: "bip174@npm:2.1.1" + checksum: bc5b99e7d1acd9484aec117dc4d931a8b6d3a77ffb84e9672a9e8be2e41c22a3d41b4dad307cbe84091c6a30ee2ceaf8e1b3036b91201d4767d0772485ecb225 + languageName: node + linkType: hard + +"bip322-js@npm:^2.0.0": + version: 2.0.0 + resolution: "bip322-js@npm:2.0.0" + dependencies: + "@bitcoinerlab/secp256k1": ^1.1.1 + bitcoinjs-lib: ^6.1.5 + bitcoinjs-message: ^2.2.0 + ecpair: ^2.1.0 + elliptic: ^6.5.5 + fast-sha256: ^1.3.0 + secp256k1: ^5.0.0 + checksum: faaaa457251724513ec0510398bb5620775a29f8accb6bfb316bcfe9feee20f76e48cea945836d8b630dbc423d36fee8dd81399575f3f6ab46541e66c7b9c228 + languageName: node + linkType: hard + "bip39@npm:^3.1.0": version: 3.1.0 resolution: "bip39@npm:3.1.0" @@ -10467,6 +10665,43 @@ __metadata: languageName: node linkType: hard +"bip66@npm:^1.1.5": + version: 1.1.5 + resolution: "bip66@npm:1.1.5" + dependencies: + safe-buffer: ^5.0.1 + checksum: 956cff6e51d7206571ef8ce875bc5fa61b5c181589790b9155799b7edcae4b20dbb3eed43b188ff3eec27cdbe98e0b7e0ec9f1cb2e4f5370c119028b248ad859 + languageName: node + linkType: hard + +"bitcoinjs-lib@npm:^6.1.5": + version: 6.1.6 + resolution: "bitcoinjs-lib@npm:6.1.6" + dependencies: + "@noble/hashes": ^1.2.0 + bech32: ^2.0.0 + bip174: ^2.1.1 + bs58check: ^3.0.1 + typeforce: ^1.11.3 + varuint-bitcoin: ^1.1.2 + checksum: 04370cf6991c8343eb749fbeeff357e45b7c92e28272c4c731b6c3a45d3e67bfca90db96175cdca0479f84f17bf91aa02b3d113b7c80d73dd5494f431e140574 + languageName: node + linkType: hard + +"bitcoinjs-message@npm:^2.2.0": + version: 2.2.0 + resolution: "bitcoinjs-message@npm:2.2.0" + dependencies: + bech32: ^1.1.3 + bs58check: ^2.1.2 + buffer-equals: ^1.0.3 + create-hash: ^1.1.2 + secp256k1: ^3.0.1 + varuint-bitcoin: ^1.0.1 + checksum: 2b851d7b976487118f34507739aabf5bca4b3c14ba997f46b932c71a83104a66a9476a808688a319e3a772c026d65381939852f091affc9dbae0f174eb6b03a1 + languageName: node + linkType: hard + "bl@npm:^4.0.3, bl@npm:^4.1.0": version: 4.1.0 resolution: "bl@npm:4.1.0" @@ -10661,7 +10896,7 @@ __metadata: languageName: node linkType: hard -"browserify-aes@npm:^1.0.0, browserify-aes@npm:^1.0.4, browserify-aes@npm:^1.2.0": +"browserify-aes@npm:^1.0.0, browserify-aes@npm:^1.0.4, browserify-aes@npm:^1.0.6, browserify-aes@npm:^1.2.0": version: 1.2.0 resolution: "browserify-aes@npm:1.2.0" dependencies: @@ -10781,7 +11016,16 @@ __metadata: languageName: node linkType: hard -"bs58check@npm:^2.1.2": +"bs58@npm:^5.0.0": + version: 5.0.0 + resolution: "bs58@npm:5.0.0" + dependencies: + base-x: ^4.0.0 + checksum: 2475cb0684e07077521aac718e604a13e0f891d58cff923d437a2f7e9e28703ab39fce9f84c7c703ab369815a675f11e3bd394d38643bfe8969fbe42e6833d45 + languageName: node + linkType: hard + +"bs58check@npm:<3.0.0, bs58check@npm:^2.1.2": version: 2.1.2 resolution: "bs58check@npm:2.1.2" dependencies: @@ -10792,6 +11036,16 @@ __metadata: languageName: node linkType: hard +"bs58check@npm:^3.0.1": + version: 3.0.1 + resolution: "bs58check@npm:3.0.1" + dependencies: + "@noble/hashes": ^1.2.0 + bs58: ^5.0.0 + checksum: dbbecc7a09f3836e821149266c864c4bbd545539cea43c35f23f4c3c46b54c86c52b65d224b9ea2e916fa6d93bd2ce9fac5b6c6bfcf19621a9c209a5602f71c8 + languageName: node + linkType: hard + "bser@npm:2.1.1": version: 2.1.1 resolution: "bser@npm:2.1.1" @@ -10817,6 +11071,13 @@ __metadata: languageName: node linkType: hard +"buffer-equals@npm:^1.0.3": + version: 1.0.4 + resolution: "buffer-equals@npm:1.0.4" + checksum: 392a2f82acdaad46392aec7ce54a8ff0b2a650b5802ccb0c77072050bbc7fd4e101f38460c7e88cdc7e130421882977f595d5c1a3d3343611562ecf7c684a70f + languageName: node + linkType: hard + "buffer-from@npm:^1.0.0": version: 1.1.2 resolution: "buffer-from@npm:1.1.2" @@ -12174,6 +12435,13 @@ __metadata: languageName: node linkType: hard +"dataloader@npm:^2.0.0": + version: 2.2.2 + resolution: "dataloader@npm:2.2.2" + checksum: 4dabd247089c29f194e94d5434d504f99156c5c214a03463c20f3f17f40398d7e179edee69a27c16e315519ac8739042a810090087ae26449a0e685156a02c65 + languageName: node + linkType: hard + "dayjs@npm:^1.11.1": version: 1.11.7 resolution: "dayjs@npm:1.11.7" @@ -12875,6 +13143,17 @@ __metadata: languageName: node linkType: hard +"drbg.js@npm:^1.0.1": + version: 1.0.1 + resolution: "drbg.js@npm:1.0.1" + dependencies: + browserify-aes: ^1.0.6 + create-hash: ^1.1.2 + create-hmac: ^1.1.4 + checksum: f8df5cdd4fb792e548d6187cbc446fbd0afd8f1ef7fa486e1c286c2adee55a687183ce48ab178e9f24965c2deabb6e2ba7a7ee2d675264b951356480eb042476 + languageName: node + linkType: hard + "duplexer3@npm:^0.1.4": version: 0.1.5 resolution: "duplexer3@npm:0.1.5" @@ -12923,6 +13202,17 @@ __metadata: languageName: node linkType: hard +"ecpair@npm:^2.1.0": + version: 2.1.0 + resolution: "ecpair@npm:2.1.0" + dependencies: + randombytes: ^2.1.0 + typeforce: ^1.18.0 + wif: ^2.0.6 + checksum: 924a776808f91d2fdd33a7033f84e3bbfe668ae98c0b9764c7b923e018accd8de57012bf20e419e0a5ef73ec3ec3738a654e71abe12f537b2fd7bcf02b93659f + languageName: node + linkType: hard + "ee-first@npm:1.1.1": version: 1.1.1 resolution: "ee-first@npm:1.1.1" @@ -12968,6 +13258,21 @@ __metadata: languageName: node linkType: hard +"elliptic@npm:^6.5.5": + version: 6.5.6 + resolution: "elliptic@npm:6.5.6" + dependencies: + bn.js: ^4.11.9 + brorand: ^1.1.0 + hash.js: ^1.0.0 + hmac-drbg: ^1.0.1 + inherits: ^2.0.4 + minimalistic-assert: ^1.0.1 + minimalistic-crypto-utils: ^1.0.1 + checksum: 213d778ccfe99ec8f0f871b1cc96a10ac3763d9175215d0a9dc026f291e5f50fea6f635e4e47b4506f9ada25aeb703bd807d8737b880dbb24d092a3001c6d97d + languageName: node + linkType: hard + "email-addresses@npm:^3.0.1": version: 3.1.0 resolution: "email-addresses@npm:3.1.0" @@ -13965,6 +14270,18 @@ __metadata: languageName: node linkType: hard +"ethereum-cryptography@npm:^2.1.3": + version: 2.2.1 + resolution: "ethereum-cryptography@npm:2.2.1" + dependencies: + "@noble/curves": 1.4.2 + "@noble/hashes": 1.4.0 + "@scure/bip32": 1.4.0 + "@scure/bip39": 1.3.0 + checksum: 1466e4c417b315a6ac67f95088b769fafac8902b495aada3c6375d827e5a7882f9e0eea5f5451600d2250283d9198b8a3d4d996e374e07a80a324e29136f25c6 + languageName: node + linkType: hard + "ethereumjs-abi@npm:^0.6.8": version: 0.6.8 resolution: "ethereumjs-abi@npm:0.6.8" @@ -18852,6 +19169,13 @@ __metadata: languageName: node linkType: hard +"jssha@npm:3.2.0": + version: 3.2.0 + resolution: "jssha@npm:3.2.0" + checksum: 2adb8a9a57a79360379e843c0548e240d072c2ef12aef39ef6a784315686bd6f65501e9353fdd2f3a604f64af07e7eab04a0ed92b221cdfea97d671d7b8e14f4 + languageName: node + linkType: hard + "jsx-ast-utils@npm:^2.4.1 || ^3.0.0": version: 3.3.3 resolution: "jsx-ast-utils@npm:3.3.3" @@ -20676,6 +21000,15 @@ __metadata: languageName: node linkType: hard +"nan@npm:^2.14.0": + version: 2.20.0 + resolution: "nan@npm:2.20.0" + dependencies: + node-gyp: latest + checksum: eb09286e6c238a3582db4d88c875db73e9b5ab35f60306090acd2f3acae21696c9b653368b4a0e32abcef64ee304a923d6223acaddd16169e5eaaf5c508fb533 + languageName: node + linkType: hard + "nano-json-stream-parser@npm:^0.1.2": version: 0.1.2 resolution: "nano-json-stream-parser@npm:0.1.2" @@ -20835,6 +21168,15 @@ __metadata: languageName: node linkType: hard +"node-addon-api@npm:^5.0.0": + version: 5.1.0 + resolution: "node-addon-api@npm:5.1.0" + dependencies: + node-gyp: latest + checksum: 2508bd2d2981945406243a7bd31362fc7af8b70b8b4d65f869c61731800058fb818cc2fd36c8eac714ddd0e568cc85becf5e165cebbdf7b5024d5151bbc75ea1 + languageName: node + linkType: hard + "node-addon-api@npm:^6.0.0": version: 6.1.0 resolution: "node-addon-api@npm:6.1.0" @@ -24793,6 +25135,23 @@ __metadata: languageName: node linkType: hard +"secp256k1@npm:^3.0.1": + version: 3.8.0 + resolution: "secp256k1@npm:3.8.0" + dependencies: + bindings: ^1.5.0 + bip66: ^1.1.5 + bn.js: ^4.11.8 + create-hash: ^1.2.0 + drbg.js: ^1.0.1 + elliptic: ^6.5.2 + nan: ^2.14.0 + node-gyp: latest + safe-buffer: ^5.1.2 + checksum: 37aaae687a8de9b7bc733ab26bc89c4302b9c681d69d71d531842d99d3af9301a4e30dbe40122793ec64b7a08b8fee8d2330397b7b2dd3a7e404ed259a458089 + languageName: node + linkType: hard + "secp256k1@npm:^4.0.1": version: 4.0.3 resolution: "secp256k1@npm:4.0.3" @@ -24805,6 +25164,18 @@ __metadata: languageName: node linkType: hard +"secp256k1@npm:^5.0.0": + version: 5.0.0 + resolution: "secp256k1@npm:5.0.0" + dependencies: + elliptic: ^6.5.4 + node-addon-api: ^5.0.0 + node-gyp: latest + node-gyp-build: ^4.2.0 + checksum: a0719dff4687c38d385b5e0b7e811c51a4ea24893128be9d097aee99f879eb0ea52582590deb15a49da627a3db23c6b028ad5c9c6ac1fca92ce760153b8cf21c + languageName: node + linkType: hard + "select-hose@npm:^2.0.0": version: 2.0.0 resolution: "select-hose@npm:2.0.0" @@ -25877,6 +26248,13 @@ __metadata: languageName: node linkType: hard +"symbol.inspect@npm:1.0.1": + version: 1.0.1 + resolution: "symbol.inspect@npm:1.0.1" + checksum: 47fa8d38d0bc5d04c06df2f71bba1a723ee0e015ca042c47b29c11f107877dd1a2e2d2154c9ef5eec11e92e4165d126c844f06d05da80e477581c8f284f05fdf + languageName: node + linkType: hard + "system-architecture@npm:^0.1.0": version: 0.1.0 resolution: "system-architecture@npm:0.1.0" @@ -26034,6 +26412,13 @@ __metadata: languageName: node linkType: hard +"teslabot@npm:^1.3.0": + version: 1.5.0 + resolution: "teslabot@npm:1.5.0" + checksum: 1494f83b9070f3d0882c7ce089a69ea46f0f30ee24c14036880ed5f49882cd80ff47f1c5543c9c973d250596896640130c16b221e84be296474a02f65e7187d0 + languageName: node + linkType: hard + "test-exclude@npm:^6.0.0": version: 6.0.0 resolution: "test-exclude@npm:6.0.0" @@ -26164,6 +26549,15 @@ __metadata: languageName: node linkType: hard +"tiny-secp256k1@npm:^2.2.3": + version: 2.2.3 + resolution: "tiny-secp256k1@npm:2.2.3" + dependencies: + uint8array-tools: 0.0.7 + checksum: f7a74a1fceacab39d268907cd84798d3a07f3de2e00ba2557a043316ef45298d9acc96fb1614d72c728c3e512ecfef985b0fbd43b7fdb789fd9901df983e3e44 + languageName: node + linkType: hard + "tmp@npm:^0.0.33": version: 0.0.33 resolution: "tmp@npm:0.0.33" @@ -26403,6 +26797,13 @@ __metadata: languageName: node linkType: hard +"tweetnacl@npm:1.0.3, tweetnacl@npm:^1.0.3": + version: 1.0.3 + resolution: "tweetnacl@npm:1.0.3" + checksum: e4a57cac188f0c53f24c7a33279e223618a2bfb5fea426231991652a13247bea06b081fd745d71291fcae0f4428d29beba1b984b1f1ce6f66b06a6d1ab90645c + languageName: node + linkType: hard + "tweetnacl@npm:^0.14.3, tweetnacl@npm:~0.14.0": version: 0.14.5 resolution: "tweetnacl@npm:0.14.5" @@ -26410,13 +26811,6 @@ __metadata: languageName: node linkType: hard -"tweetnacl@npm:^1.0.3": - version: 1.0.3 - resolution: "tweetnacl@npm:1.0.3" - checksum: e4a57cac188f0c53f24c7a33279e223618a2bfb5fea426231991652a13247bea06b081fd745d71291fcae0f4428d29beba1b984b1f1ce6f66b06a6d1ab90645c - languageName: node - linkType: hard - "type-check@npm:^0.4.0, type-check@npm:~0.4.0": version: 0.4.0 resolution: "type-check@npm:0.4.0" @@ -26503,6 +26897,13 @@ __metadata: languageName: node linkType: hard +"typeforce@npm:^1.11.3, typeforce@npm:^1.18.0": + version: 1.18.0 + resolution: "typeforce@npm:1.18.0" + checksum: e3b21e27e76cb05f32285bef7c30a29760e79c622cfe4aa3c179ce49d1c7895b7154c8deedb9fe4599b1fd0428d35860d43e0776da1c04861168f3ad7ed99c70 + languageName: node + linkType: hard + "typescript@npm:^4.8.4": version: 4.8.4 resolution: "typescript@npm:4.8.4" @@ -26530,6 +26931,13 @@ __metadata: languageName: node linkType: hard +"uint8array-tools@npm:0.0.7": + version: 0.0.7 + resolution: "uint8array-tools@npm:0.0.7" + checksum: 6ffc45c7d2136757d63c6e556eb8345f908948618a9de37c805fec1249d989c265187b3fbef6cffc4ce5129083204829025b3c58800a0f24c8548e243d42ba13 + languageName: node + linkType: hard + "uint8arrays@npm:3.1.0": version: 3.1.0 resolution: "uint8arrays@npm:3.1.0" @@ -27145,6 +27553,15 @@ __metadata: languageName: node linkType: hard +"varuint-bitcoin@npm:^1.0.1, varuint-bitcoin@npm:^1.1.2": + version: 1.1.2 + resolution: "varuint-bitcoin@npm:1.1.2" + dependencies: + safe-buffer: ^5.1.1 + checksum: 1c900bf08f2408ae33a6094dc5d809bdb6673eaf6039062d88c230155873e51e29c760053611f93ccd024854d04ebd92ed95c744720e94a79ca4e1150fcce071 + languageName: node + linkType: hard + "vary@npm:^1, vary@npm:~1.1.2": version: 1.1.2 resolution: "vary@npm:1.1.2" @@ -28123,6 +28540,15 @@ __metadata: languageName: node linkType: hard +"wif@npm:^2.0.6": + version: 2.0.6 + resolution: "wif@npm:2.0.6" + dependencies: + bs58check: <3.0.0 + checksum: 8c3147ef98d56f394d66f0477f699fba7fc18dd0d1c2c5d0f8408be41acffed589fa82447d80eae5afc9a3cbd943bc3eebb337b9f114955adeaad02a244f4f9a + languageName: node + linkType: hard + "wildcard@npm:^2.0.0": version: 2.0.0 resolution: "wildcard@npm:2.0.0" @@ -28460,6 +28886,13 @@ __metadata: languageName: node linkType: hard +"zod@npm:^3.21.4": + version: 3.23.8 + resolution: "zod@npm:3.23.8" + checksum: 15949ff82118f59c893dacd9d3c766d02b6fa2e71cf474d5aa888570c469dbf5446ac5ad562bb035bf7ac9650da94f290655c194f4a6de3e766f43febd432c5c + languageName: node + linkType: hard + "zwitch@npm:^2.0.0": version: 2.0.4 resolution: "zwitch@npm:2.0.4" From a1afe9bbe91d9481a8213a33f0a807677722d3fb Mon Sep 17 00:00:00 2001 From: S2kael Date: Mon, 29 Jul 2024 10:21:26 +0700 Subject: [PATCH 012/424] [MasterAccount] Update some interface for Ton --- .../src/background/KoniTypes.ts | 1 - .../src/services/balance-service/index.ts | 21 ++++++--- .../keyring-service/account-context.ts | 43 ++++++++++--------- .../src/types/account/action/add.ts | 2 +- .../src/types/account/info/keyring.ts | 4 +- .../src/utils/account/common.ts | 4 ++ yarn.lock | 4 +- 7 files changed, 45 insertions(+), 34 deletions(-) diff --git a/packages/extension-base/src/background/KoniTypes.ts b/packages/extension-base/src/background/KoniTypes.ts index f8d420e51e..c41137f4f6 100644 --- a/packages/extension-base/src/background/KoniTypes.ts +++ b/packages/extension-base/src/background/KoniTypes.ts @@ -876,7 +876,6 @@ export interface RequestAccountCreateExternalV2 { address: string; genesisHash?: string | null; name: string; - isEthereum: boolean; isAllowed: boolean; isReadOnly: boolean; } diff --git a/packages/extension-base/src/services/balance-service/index.ts b/packages/extension-base/src/services/balance-service/index.ts index 8b5802103a..22c6df33b9 100644 --- a/packages/extension-base/src/services/balance-service/index.ts +++ b/packages/extension-base/src/services/balance-service/index.ts @@ -14,6 +14,8 @@ import DetectAccountBalanceStore from '@subwallet/extension-base/stores/DetectAc import { BalanceItem, BalanceJson } from '@subwallet/extension-base/types'; import { CommonOptimalPath } from '@subwallet/extension-base/types/service-base'; import { addLazy, createPromiseHandler, isAccountAll, PromiseHandler, waitTimeout } from '@subwallet/extension-base/utils'; +import { getKeypairTypeByAddress } from '@subwallet/keyring'; +import { EthereumKeypairTypes, SubstrateKeypairTypes } from '@subwallet/keyring/types'; import keyring from '@subwallet/ui-keyring'; import { t } from 'i18next'; import { BehaviorSubject } from 'rxjs'; @@ -404,12 +406,19 @@ export class BalanceService implements StoppableServiceInterface { this.setBalanceDetectCache(addresses); const assetMap = this.state.chainService.getAssetRegistry(); const promiseList = addresses.map((address) => { - return this.state.subscanService.getMultiChainBalance(address) - .catch((e) => { - console.error(e); - - return null; - }); + const type = getKeypairTypeByAddress(address); + const typeValid = [...SubstrateKeypairTypes, ...EthereumKeypairTypes].includes(type); + + if (typeValid) { + return this.state.subscanService.getMultiChainBalance(address) + .catch((e) => { + console.error(e); + + return null; + }); + } else { + return null; + } }); const needEnableChains: string[] = []; diff --git a/packages/extension-base/src/services/keyring-service/account-context.ts b/packages/extension-base/src/services/keyring-service/account-context.ts index 3ae949715f..64616154c3 100644 --- a/packages/extension-base/src/services/keyring-service/account-context.ts +++ b/packages/extension-base/src/services/keyring-service/account-context.ts @@ -9,8 +9,8 @@ import { AccountJson, AccountProxy, AccountProxyData, AccountProxyMap, AccountPr import { RequestAccountProxyEdit, RequestAccountProxyForget } from '@subwallet/extension-base/types/account/action/edit'; import { isAddressValidWithAuthType, modifyAccountName, singleAddressToAccount } from '@subwallet/extension-base/utils'; import { InjectedAccountWithMeta } from '@subwallet/extension-inject/types'; -import { createPair } from '@subwallet/keyring'; -import { KeyringPair, KeyringPair$Json, KeyringPair$Meta } from '@subwallet/keyring/types'; +import { createPair, getDerivePath, getKeypairTypeByAddress } from '@subwallet/keyring'; +import { BitcoinKeypairTypes, KeypairType, KeyringPair, KeyringPair$Json, KeyringPair$Meta, TonKeypairTypes } from '@subwallet/keyring/types'; import { keyring } from '@subwallet/ui-keyring'; import { SubjectInfo } from '@subwallet/ui-keyring/observable/types'; import { t } from 'i18next'; @@ -19,13 +19,13 @@ import { BehaviorSubject, combineLatest } from 'rxjs'; import { assert, hexStripPrefix, hexToU8a, isHex, stringShorten, u8aToHex, u8aToString } from '@polkadot/util'; import { base64Decode, blake2AsHex, jsonDecrypt, keyExtractSuri, mnemonicToEntropy } from '@polkadot/util-crypto'; import { validateMnemonic } from '@polkadot/util-crypto/mnemonic/bip39'; -import { EncryptedJson, KeypairType, Prefix } from '@polkadot/util-crypto/types'; +import { EncryptedJson, Prefix } from '@polkadot/util-crypto/types'; -const ETH_DERIVE_DEFAULT = '/m/44\'/60\'/0\'/0/0'; +function getSuri (seed: string, type?: KeypairType): string { + const extraPath = type ? getDerivePath(type)(0) : ''; -const getSuri = (seed: string, type?: KeypairType): string => type === 'ethereum' - ? `${seed}${ETH_DERIVE_DEFAULT}` - : seed; + return seed + (extraPath ? '/' + extraPath : ''); +} const CURRENT_ACCOUNT_KEY = 'CurrentAccountInfo'; const MODIFY_PAIRS_KEY = 'ModifyPairs'; @@ -450,16 +450,15 @@ export class AccountContext { /* Add QR-signer, read-only */ public async accountsCreateExternalV2 (request: RequestAccountCreateExternalV2): Promise { - const { address, isAllowed, isEthereum, isReadOnly, name } = request; + const { address, isAllowed, isReadOnly, name } = request; + const type = getKeypairTypeByAddress(address); try { - let result: KeyringPair; - try { const exists = keyring.getPair(address); if (exists) { - if (exists.type === (isEthereum ? 'ethereum' : 'sr25519')) { + if (exists.type === type) { return [{ code: AccountExternalErrorCode.INVALID_ADDRESS, message: t('Account exists') }]; } } @@ -467,19 +466,21 @@ export class AccountContext { } - if (isEthereum) { - result = keyring.keyring.addFromAddress(address, { - name, - isExternal: true, - isReadOnly, - genesisHash: '' - }, null, 'ethereum'); + const meta: KeyringPair$Meta = { + name, + isExternal: true, + isReadOnly, + genesisHash: '' + }; - keyring.saveAccount(result); - } else { - result = keyring.addExternal(address, { genesisHash: '', name, isReadOnly }).pair; + if ([...BitcoinKeypairTypes, ...TonKeypairTypes].includes(type)) { + meta.noPublicKey = true; } + const result = keyring.keyring.addFromAddress(address, meta, null, type); + + keyring.saveAccount(result); + const _address = result.address; const modifiedPairs = this.modifyPairsSubject.value; diff --git a/packages/extension-base/src/types/account/action/add.ts b/packages/extension-base/src/types/account/action/add.ts index 06013ce86d..466e056de5 100644 --- a/packages/extension-base/src/types/account/action/add.ts +++ b/packages/extension-base/src/types/account/action/add.ts @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-base authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { KeypairType } from '@polkadot/util-crypto/types'; +import { KeypairType } from '@subwallet/keyring/types'; export interface RequestAccountCreateSuriV2 { name: string; diff --git a/packages/extension-base/src/types/account/info/keyring.ts b/packages/extension-base/src/types/account/info/keyring.ts index 84394a6ad7..ef427cb463 100644 --- a/packages/extension-base/src/types/account/info/keyring.ts +++ b/packages/extension-base/src/types/account/info/keyring.ts @@ -92,10 +92,8 @@ export interface AccountDeriveData { * @interface AccountMetadataData * Represents the comprehensive metadata associated with an account. This interface aggregates various aspects of account data to provide a unified view of an account's metadata. It extends from multiple specific metadata interfaces, each covering a different dimension of account information. * - * @interface AccountMetadataData - * @extends AccountExternalData - Includes data about whether the account is external, hardware, readonly, or hidden. - * @extends AccountLedgerData - Contains information specific to Ledger hardware wallets, such as account index and genesis hash. * @extends AccountExternalData - Includes data about the account's external status, hardware wallet status, read-only status, and hidden status. + * @extends AccountLedgerData - Contains information specific to Ledger hardware wallets, such as account index and genesis hash. * @extends AccountInjectData - Covers data related to injected accounts, including the source of the injection. * @extends AccountDeriveData - Holds information about derived accounts, including the parent address and derivation path (suri). */ diff --git a/packages/extension-base/src/utils/account/common.ts b/packages/extension-base/src/utils/account/common.ts index 857b1cd9e4..dfd9641d83 100644 --- a/packages/extension-base/src/utils/account/common.ts +++ b/packages/extension-base/src/utils/account/common.ts @@ -38,6 +38,10 @@ export const modifyAccountName = (type: KeypairType, name: string, modify: boole case 'ethereum': network = 'EVM'; break; + case 'ton': + case 'ton-special': + network = 'Ton'; + break; } return network ? [name, network].join(' - ') : name; diff --git a/yarn.lock b/yarn.lock index d9b37823b0..5b3cb15e08 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6474,7 +6474,7 @@ __metadata: "@subwallet/keyring@file:../SubWallet-Base/packages/keyring/build/::locator=root-workspace-0b6124%40workspace%3A.": version: 0.1.5 - resolution: "@subwallet/keyring@file:../SubWallet-Base/packages/keyring/build/#../SubWallet-Base/packages/keyring/build/::hash=6b6f81&locator=root-workspace-0b6124%40workspace%3A." + resolution: "@subwallet/keyring@file:../SubWallet-Base/packages/keyring/build/#../SubWallet-Base/packages/keyring/build/::hash=102d08&locator=root-workspace-0b6124%40workspace%3A." dependencies: "@ethereumjs/tx": ^5.0.0 "@polkadot/util": ^12.2.1 @@ -6494,7 +6494,7 @@ __metadata: rxjs: ^7.5.6 tiny-secp256k1: ^2.2.3 tslib: ^2.6.2 - checksum: 25e91849d921a3bb7fe4b0c3b3d866f05ba73b97729961aba19287ab8c168584af90a9c9924ec8e146804373ed49e2689f6b63e42706ac4d6fd09aa98b1f67c2 + checksum: a4663767a3c5524facdd214905fad26c379900712f3e12f37ac495869019292ed2af2ae6503a3c90a6d7f302882cf9248a61415988e86740cc078a9741a2504a languageName: node linkType: hard From a849322b01df34d54c0c335a06cbb7d874750927 Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Mon, 29 Jul 2024 15:33:50 +0700 Subject: [PATCH 013/424] [Issue-3394] feat: Support showing Jetton balance --- .../balance-service/helpers/subscribe/ton.ts | 58 ++++++++++++++++++- .../helpers/subscribe/ton/utils.ts | 29 ++++++++++ yarn.lock | 4 +- 3 files changed, 87 insertions(+), 4 deletions(-) diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts index 971566e045..6db6b547fa 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts @@ -3,13 +3,65 @@ import { _AssetType } from '@subwallet/chain-list/types'; import { APIItemState } from '@subwallet/extension-base/background/KoniTypes'; -import { ASTAR_REFRESH_BALANCE_INTERVAL } from '@subwallet/extension-base/constants'; +import { ASTAR_REFRESH_BALANCE_INTERVAL, SUB_TOKEN_REFRESH_BALANCE_INTERVAL } from '@subwallet/extension-base/constants'; +import { getJettonMasterContract, getJettonWalletContract } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/utils'; import { _TonApi } from '@subwallet/extension-base/services/chain-service/types'; +import { _getContractAddressOfToken } from '@subwallet/extension-base/services/chain-service/utils'; import { BalanceItem, SubscribeTonPalletBalance } from '@subwallet/extension-base/types'; import { filterAssetsByChainAndType } from '@subwallet/extension-base/utils'; import { Address } from '@ton/core'; +import { JettonMaster, OpenedContract } from '@ton/ton'; -// todo: export subscribeJettonBalance (later) +export function subscribeJettonBalanceInterval ({ addresses, assetMap, callback, chainInfo, tonApi }: SubscribeTonPalletBalance): () => void { + const chain = chainInfo.slug; + const tokenList = filterAssetsByChainAndType(assetMap, chain, [_AssetType.TEP74]); + const jettonMasterContractMap = {} as Record>; + + Object.entries(tokenList).forEach(([slug, tokenInfo]) => { + jettonMasterContractMap[slug] = getJettonMasterContract(tonApi, _getContractAddressOfToken(tokenInfo)); + }); + + const getJettonBalances = () => { + Object.values(tokenList).map(async (tokenInfo) => { + try { + const masterContract = jettonMasterContractMap[tokenInfo.slug]; + const balances = await Promise.all(addresses.map(async (address): Promise => { + try { + const jettonWalletContract = await getJettonWalletContract(masterContract, tonApi, address); + + return await jettonWalletContract.getBalance(); + } catch (e) { + console.error(`Error on get balance of account ${address} for token ${tokenInfo.slug}`, e); + + return 0n; + } + })); + + const items: BalanceItem[] = balances.map((balance, index): BalanceItem => { + return { + address: '5HpbHTE8NKRHffnDwUDE7VR1ZtRSK1xWT4NrbvkSv54Fvqxx', // fake address + tokenSlug: tokenInfo.slug, + free: balance.toString(), + locked: '0', + state: APIItemState.READY + }; + }); + + callback(items); + } catch (err) { + console.log(tokenInfo.slug, err); + } + }); + }; + + getJettonBalances(); + + const interval = setInterval(getJettonBalances, SUB_TOKEN_REFRESH_BALANCE_INTERVAL); + + return () => { + clearInterval(interval); + }; +} async function getTonBalance (addresses: string[], tonApi: _TonApi): Promise { return await Promise.all(addresses.map(async (address) => { @@ -61,8 +113,10 @@ export function subscribeTonBalance (params: SubscribeTonPalletBalance) { getBalance(); const interval = setInterval(getBalance, ASTAR_REFRESH_BALANCE_INTERVAL); + const unsub2 = subscribeJettonBalanceInterval(params); return () => { clearInterval(interval); + unsub2 && unsub2(); }; } diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts index ed1530690a..eb6149d3d1 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts @@ -1,3 +1,32 @@ // Copyright 2019-2022 @subwallet/extension-base // SPDX-License-Identifier: Apache-2.0 +// import { getHttpEndpoint } from '@orbs-network/ton-access'; +import { _TonApi } from '@subwallet/extension-base/services/chain-service/types'; +import { Address } from '@ton/core'; +import { JettonMaster, JettonWallet, OpenedContract } from '@ton/ton'; + +export function getJettonMasterContract (tonApi: _TonApi, contractAddress: string) { + const masterAddress = Address.parse(contractAddress); + + return tonApi.api.open(JettonMaster.create(masterAddress)); +} + +export async function getJettonWalletContract (jettonMasterContract: OpenedContract, tonApi: _TonApi, ownerAddress: string) { + const walletAddress = Address.parse(ownerAddress); + const jettonWalletAddress = await jettonMasterContract.getWalletAddress(walletAddress); + + return tonApi.api.open(JettonWallet.create(jettonWalletAddress)); +} + +// export async function getTonClient (isTestnet = false) { +// if (isTestnet) { +// const endpoint = await getHttpEndpoint({ network: 'testnet' }); +// +// return new TonClient({ endpoint }); +// } +// +// const endpoint = await getHttpEndpoint(); +// +// return new TonClient({ endpoint }); +// } diff --git a/yarn.lock b/yarn.lock index 9268dd6e15..dacd5ebc52 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6052,12 +6052,12 @@ __metadata: "@subwallet/chain-list@file:/Users/truongnguyen/Workspace/SubWallet-ChainList/packages/chain-list/build::locator=root-workspace-0b6124%40workspace%3A.": version: 0.2.79-beta.0 - resolution: "@subwallet/chain-list@file:/Users/truongnguyen/Workspace/SubWallet-ChainList/packages/chain-list/build#/Users/truongnguyen/Workspace/SubWallet-ChainList/packages/chain-list/build::hash=06e6dc&locator=root-workspace-0b6124%40workspace%3A." + resolution: "@subwallet/chain-list@file:/Users/truongnguyen/Workspace/SubWallet-ChainList/packages/chain-list/build#/Users/truongnguyen/Workspace/SubWallet-ChainList/packages/chain-list/build::hash=b001f9&locator=root-workspace-0b6124%40workspace%3A." dependencies: "@polkadot/dev": 0.67.167 "@polkadot/util": ^12.5.1 eventemitter3: ^5.0.1 - checksum: 65bf980da5abc85881df37f8fffbc40f557369b8f26f3b937a1149ccb5aecdd32e93a8e6d23dd5df87baf410496fd912eaabdba13ff9c80549ff24d9a9b82913 + checksum: 098c6808c7dfdead9810556011208796cd90e0032f43ac50dcb29cddd28b872b26f3e9eeaea71b25f79611fa1b508532bb53fc708bef2bb25aef9fad522b0211 languageName: node linkType: hard From f6902715decf69978e8d85e4f2b8f1ebbe125978 Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Mon, 29 Jul 2024 15:38:21 +0700 Subject: [PATCH 014/424] [Issue-3394] test: manually sleep for passing api rate limit --- .../services/balance-service/helpers/subscribe/ton.ts | 4 +++- .../balance-service/helpers/subscribe/ton/utils.ts | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts index 6db6b547fa..712812191d 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts @@ -4,7 +4,7 @@ import { _AssetType } from '@subwallet/chain-list/types'; import { APIItemState } from '@subwallet/extension-base/background/KoniTypes'; import { ASTAR_REFRESH_BALANCE_INTERVAL, SUB_TOKEN_REFRESH_BALANCE_INTERVAL } from '@subwallet/extension-base/constants'; -import { getJettonMasterContract, getJettonWalletContract } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/utils'; +import { getJettonMasterContract, getJettonWalletContract, sleep } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/utils'; import { _TonApi } from '@subwallet/extension-base/services/chain-service/types'; import { _getContractAddressOfToken } from '@subwallet/extension-base/services/chain-service/utils'; import { BalanceItem, SubscribeTonPalletBalance } from '@subwallet/extension-base/types'; @@ -29,6 +29,8 @@ export function subscribeJettonBalanceInterval ({ addresses, assetMap, callback, try { const jettonWalletContract = await getJettonWalletContract(masterContract, tonApi, address); + await sleep(1500); + return await jettonWalletContract.getBalance(); } catch (e) { console.error(`Error on get balance of account ${address} for token ${tokenInfo.slug}`, e); diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts index eb6149d3d1..9fb2c5a287 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts @@ -13,9 +13,14 @@ export function getJettonMasterContract (tonApi: _TonApi, contractAddress: strin } export async function getJettonWalletContract (jettonMasterContract: OpenedContract, tonApi: _TonApi, ownerAddress: string) { + await sleep(1500); const walletAddress = Address.parse(ownerAddress); + + await sleep(1500); const jettonWalletAddress = await jettonMasterContract.getWalletAddress(walletAddress); + await sleep(1500); + return tonApi.api.open(JettonWallet.create(jettonWalletAddress)); } @@ -30,3 +35,7 @@ export async function getJettonWalletContract (jettonMasterContract: OpenedContr // // return new TonClient({ endpoint }); // } + +export function sleep (ms: number) { // alibaba for test + return new Promise((resolve) => setTimeout(resolve, ms)); +} From 9041bcf6cc52576e84b25cf5ec69a04e30432db8 Mon Sep 17 00:00:00 2001 From: S2kael Date: Mon, 29 Jul 2024 20:22:04 +0700 Subject: [PATCH 015/424] [MasterAccount] Add export mnemonic by proxy Id and support with Ton's mnemonic --- package.json | 1 + .../src/background/KoniTypes.ts | 60 ++----- .../extension-base/src/background/types.ts | 34 +--- .../src/koni/background/handlers/Extension.ts | 147 ++++-------------- .../src/koni/background/handlers/State.ts | 4 +- .../keyring-service/account-context.ts | 143 ++++++++++++++++- .../src/types/account/action/add.ts | 14 -- .../src/types/account/action/add/index.ts | 6 + .../src/types/account/action/add/metamask.ts | 20 +++ .../src/types/account/action/add/mnemonic.ts | 88 +++++++++++ .../src/types/account/action/add/substrate.ts | 13 ++ .../src/types/account/action/export.ts | 11 ++ .../src/types/account/action/index.ts | 2 + .../src/Popup/Account/NewSeedPhrase.tsx | 2 +- .../src/Popup/Debugger/DebuggerAPI.tsx | 8 +- .../src/messaging/accounts/create.ts | 15 +- .../src/messaging/accounts/export.ts | 4 +- .../src/messaging/accounts/validate.ts | 18 +-- .../src/Popup/Account/NewSeedPhrase.tsx | 2 +- .../src/Popup/Debugger/DebuggerAPI.tsx | 8 +- .../Modal/Account/SeedPhraseModal.tsx | 2 +- .../src/messaging/accounts/create.ts | 20 +-- .../src/messaging/accounts/export.ts | 2 +- .../src/messaging/accounts/validate.ts | 18 +-- yarn.lock | 96 +----------- 25 files changed, 355 insertions(+), 383 deletions(-) delete mode 100644 packages/extension-base/src/types/account/action/add.ts create mode 100644 packages/extension-base/src/types/account/action/add/index.ts create mode 100644 packages/extension-base/src/types/account/action/add/metamask.ts create mode 100644 packages/extension-base/src/types/account/action/add/mnemonic.ts create mode 100644 packages/extension-base/src/types/account/action/add/substrate.ts create mode 100644 packages/extension-base/src/types/account/action/export.ts diff --git a/package.json b/package.json index 31d945b19b..77d31ee737 100644 --- a/package.json +++ b/package.json @@ -84,6 +84,7 @@ }, "resolutions": { "@ethereumjs/common": "^4.1.0", + "@ethereumjs/tx": "^5.1.0", "@google/model-viewer": "3.1.1", "@ledgerhq/hw-app-eth": "6.33.4", "@ledgerhq/hw-transport": "6.30.3", diff --git a/packages/extension-base/src/background/KoniTypes.ts b/packages/extension-base/src/background/KoniTypes.ts index c41137f4f6..7ed7484b72 100644 --- a/packages/extension-base/src/background/KoniTypes.ts +++ b/packages/extension-base/src/background/KoniTypes.ts @@ -4,14 +4,14 @@ import { _AssetRef, _AssetType, _ChainAsset, _ChainInfo, _FundStatus, _MultiChainAsset } from '@subwallet/chain-list/types'; import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError'; import { AuthUrls, Resolver } from '@subwallet/extension-base/background/handlers/State'; -import { AccountAuthType, AuthorizeRequest, ConfirmationRequestBase, RequestAccountList, RequestAccountSubscribe, RequestAccountUnsubscribe, RequestAuthorizeCancel, RequestAuthorizeReject, RequestAuthorizeSubscribe, RequestAuthorizeTab, RequestCurrentAccountAddress, ResponseAuthorizeList, ResponseJsonGetAccountInfo, SeedLengths } from '@subwallet/extension-base/background/types'; +import { AccountAuthType, AuthorizeRequest, ConfirmationRequestBase, RequestAccountList, RequestAccountSubscribe, RequestAccountUnsubscribe, RequestAuthorizeCancel, RequestAuthorizeReject, RequestAuthorizeSubscribe, RequestAuthorizeTab, RequestCurrentAccountAddress, ResponseAuthorizeList, ResponseJsonGetAccountInfo } from '@subwallet/extension-base/background/types'; import { RequestOptimalTransferProcess } from '@subwallet/extension-base/services/balance-service/helpers'; import { _CHAIN_VALIDATION_ERROR } from '@subwallet/extension-base/services/chain-service/handler/types'; import { _ChainState, _EvmApi, _NetworkUpsertParams, _SubstrateApi, _ValidateCustomAssetRequest, _ValidateCustomAssetResponse, EnableChainParams, EnableMultiChainParams } from '@subwallet/extension-base/services/chain-service/types'; import { CrowdloanContributionsResponse } from '@subwallet/extension-base/services/subscan-service/types'; import { SWTransactionResponse, SWTransactionResult } from '@subwallet/extension-base/services/transaction-service/types'; import { WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; -import { AccountJson, AccountsWithCurrentAddress, AddressJson, BalanceJson, BuyServiceInfo, BuyTokenInfo, CurrentAccountInfo, EarningRewardHistoryItem, EarningRewardJson, EarningStatus, HandleYieldStepParams, LeavePoolAdditionalData, NominationPoolInfo, OptimalYieldPath, OptimalYieldPathParams, RequestAccountCreateSuriV2, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestEarlyValidateYield, RequestGetDeriveAccounts, RequestGetYieldPoolTargets, RequestMetadataHash, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseAccountCreateSuriV2, ResponseDeriveValidateV2, ResponseEarlyValidateYield, ResponseGetDeriveAccounts, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseShortenMetadata, StorageDataInterface, SubmitYieldStepData, TokenSpendingApprovalParams, UnlockDotTransactionNft, UnstakingStatus, ValidateYieldProcessParams, YieldPoolInfo, YieldPositionInfo, YieldValidationStatus } from '@subwallet/extension-base/types'; +import { AccountJson, AccountsWithCurrentAddress, AddressJson, BalanceJson, BuyServiceInfo, BuyTokenInfo, CurrentAccountInfo, EarningRewardHistoryItem, EarningRewardJson, EarningStatus, HandleYieldStepParams, LeavePoolAdditionalData, NominationPoolInfo, OptimalYieldPath, OptimalYieldPathParams, RequestAccountCreateSuriV2, RequestCheckPublicAndSecretKey, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestEarlyValidateYield, RequestExportAccountProxyMnemonic, RequestGetDeriveAccounts, RequestGetYieldPoolTargets, RequestMetadataHash, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseAccountCreateSuriV2, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseEarlyValidateYield, ResponseExportAccountProxyMnemonic, ResponseGetDeriveAccounts, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2, ResponseShortenMetadata, StorageDataInterface, SubmitYieldStepData, TokenSpendingApprovalParams, UnlockDotTransactionNft, UnstakingStatus, ValidateYieldProcessParams, YieldPoolInfo, YieldPositionInfo, YieldValidationStatus } from '@subwallet/extension-base/types'; import { RequestAccountProxyEdit, RequestAccountProxyForget } from '@subwallet/extension-base/types/account/action/edit'; import { CommonOptimalPath } from '@subwallet/extension-base/types/service-base'; import { SwapErrorType, SwapPair, SwapQuoteResponse, SwapRequest, SwapRequestResult, SwapSubmitParams, SwapTxData, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap'; @@ -28,7 +28,6 @@ import { JsonRpcPayload, JsonRpcResponse } from 'web3-core-helpers'; import { ExtDef } from '@polkadot/types/extrinsic/signedExtensions/types'; import { SignerResult } from '@polkadot/types/types/extrinsic'; import { HexString } from '@polkadot/util/types'; -import { KeypairType } from '@polkadot/util-crypto/types'; import { TransactionWarning } from './warnings/TransactionWarning'; @@ -794,41 +793,6 @@ export interface ResponseAccountBatchExportV2 { // Get account info with private key -export interface RequestCheckPublicAndSecretKey { - secretKey: string; - publicKey: string; -} - -export interface ResponseCheckPublicAndSecretKey { - address: string; - isValid: boolean; - isEthereum: boolean; -} - -// Create seed phase - -export interface RequestSeedCreateV2 { - length?: SeedLengths; - seed?: string; - types?: Array; -} - -export interface ResponseSeedCreateV2 { - seed: string, - addressMap: Record -} - -// Get account info with suri - -export interface RequestSeedValidateV2 { - suri: string; - types?: Array; -} - -export type ResponseSeedValidateV2 = ResponseSeedCreateV2 - -// Create account with suri - // Create derive account // Restore account with json file (single account) @@ -850,13 +814,6 @@ export interface RequestBatchRestoreV2 { isAllowed: boolean; } -// Restore account with privateKey - -export interface ResponsePrivateKeyValidateV2 { - addressMap: Record, - autoAddPrefix: boolean -} - // External account export enum AccountExternalErrorCode { @@ -2068,12 +2025,12 @@ export interface KoniRequestSignatures { /* Account management */ // Validate - 'pri(seed.validateV2)': [RequestSeedValidateV2, ResponseSeedValidateV2]; - 'pri(privateKey.validateV2)': [RequestSeedValidateV2, ResponsePrivateKeyValidateV2]; - 'pri(accounts.checkPublicAndSecretKey)': [RequestCheckPublicAndSecretKey, ResponseCheckPublicAndSecretKey]; + 'pri(accounts.validate.seed)': [RequestMnemonicValidateV2, ResponseMnemonicValidateV2]; + 'pri(accounts.validate.metamask.privateKey)': [RequestPrivateKeyValidateV2, ResponsePrivateKeyValidateV2]; + 'pri(accounts.validate.substrate.publicAndPrivateKey)': [RequestCheckPublicAndSecretKey, ResponseCheckPublicAndSecretKey]; // Create account - 'pri(seed.createV2)': [RequestSeedCreateV2, ResponseSeedCreateV2]; + 'pri(seed.createV2)': [RequestMnemonicCreateV2, ResponseMnemonicCreateV2]; 'pri(accounts.create.suriV2)': [RequestAccountCreateSuriV2, ResponseAccountCreateSuriV2]; 'pri(accounts.create.externalV2)': [RequestAccountCreateExternalV2, AccountExternalError[]]; 'pri(accounts.create.hardwareV2)': [RequestAccountCreateHardwareV2, boolean]; @@ -2089,8 +2046,9 @@ export interface KoniRequestSignatures { 'pri(accounts.json.batchRestoreV2)': [RequestBatchRestoreV2, void]; // Export account - 'pri(accounts.batchExportV2)': [RequestAccountBatchExportV2, ResponseAccountBatchExportV2]; - 'pri(accounts.exportPrivateKey)': [RequestAccountExportPrivateKey, ResponseAccountExportPrivateKey]; + 'pri(accounts.export.json.batch)': [RequestAccountBatchExportV2, ResponseAccountBatchExportV2]; + 'pri(accounts.export.privateKey)': [RequestAccountExportPrivateKey, ResponseAccountExportPrivateKey]; + 'pri(accounts.export.mnemonic)': [RequestExportAccountProxyMnemonic, ResponseExportAccountProxyMnemonic]; // Current account 'pri(accounts.subscribeWithCurrentProxy)': [RequestAccountSubscribe, AccountsWithCurrentAddress, AccountsWithCurrentAddress]; diff --git a/packages/extension-base/src/background/types.ts b/packages/extension-base/src/background/types.ts index fb79a033f8..42487d319f 100644 --- a/packages/extension-base/src/background/types.ts +++ b/packages/extension-base/src/background/types.ts @@ -47,7 +47,7 @@ export type AccountWithChildren = AccountJson & { children?: AccountWithChildren[]; } -export interface FindAccountFunction{ +export interface FindAccountFunction { (networkMap: Record, address: string, genesisHash?: string): AccountJson | undefined; } @@ -86,7 +86,6 @@ export interface RequestSignatures extends KoniRequestSignatures { // private/internal requests, i.e. from a popup 'pri(ping)': [null, string]; 'pri(accounts.create.hardware)': [RequestAccountCreateHardware, boolean]; - 'pri(accounts.create.suri)': [RequestAccountCreateSuri, boolean]; 'pri(accounts.export)': [RequestAccountExport, ResponseAccountExport]; 'pri(accounts.batchExport)': [RequestAccountBatchExport, ResponseAccountsExport] 'pri(accounts.show)': [RequestAccountShow, boolean]; @@ -111,8 +110,6 @@ export interface RequestSignatures extends KoniRequestSignatures { 'pri(metadata.reject)': [RequestMetadataReject, boolean]; 'pri(metadata.requests)': [RequestMetadataSubscribe, MetadataRequest[], MetadataRequest[]]; 'pri(metadata.list)': [null, MetadataDef[]]; - 'pri(seed.create)': [RequestSeedCreate, ResponseSeedCreate]; - 'pri(seed.validate)': [RequestSeedValidate, ResponseSeedValidate]; 'pri(settings.notification)': [string, boolean]; 'pri(signing.approve.password)': [RequestSigningApprovePassword, boolean]; 'pri(signing.approve.signature)': [RequestSigningApproveSignature, boolean]; @@ -199,14 +196,6 @@ export interface RequestAccountCreateExternal { name: string; } -export interface RequestAccountCreateSuri { - name: string; - genesisHash?: string | null; - password: string; - suri: string; - type?: KeypairType; -} - export interface RequestAccountCreateHardware { accountIndex: number; address: string; @@ -317,17 +306,6 @@ export interface ResponseSigningIsLocked { export type RequestSigningSubscribe = null; -export interface RequestSeedCreate { - length?: SeedLengths; - seed?: string; - type?: KeypairType; -} - -export interface RequestSeedValidate { - suri: string; - type?: KeypairType; -} - // Responses export type ResponseTypes = { @@ -371,16 +349,6 @@ export interface ResponseDeriveValidate { suri: string; } -export interface ResponseSeedCreate { - address: string; - seed: string; -} - -export interface ResponseSeedValidate { - address: string; - suri: string; -} - export interface ResponseAccountExport { exportedJson: KeyringPair$Json; } diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index c9635384d3..77f665c196 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -7,8 +7,8 @@ import { _AssetRef, _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError'; import { withErrorLog } from '@subwallet/extension-base/background/handlers/helpers'; import { createSubscription } from '@subwallet/extension-base/background/handlers/subscriptions'; -import { AccountExternalError, AddressBookInfo, AmountData, AmountDataWithId, AssetSetting, AssetSettingUpdateReq, BasicTxErrorType, BondingOptionParams, BrowserConfirmationType, CampaignBanner, CampaignData, CampaignDataType, ChainType, CronReloadRequest, CrowdloanJson, ExternalRequestPromiseStatus, ExtrinsicType, KeyringState, MantaPayEnableMessage, MantaPayEnableParams, MantaPayEnableResponse, MantaPaySyncState, MetadataItem, NftCollection, NftJson, NftTransactionRequest, NftTransactionResponse, OptionInputAddress, PriceJson, RequestAccountBatchExportV2, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateWithSecretKey, RequestAccountExportPrivateKey, RequestAddInjectedAccounts, RequestApproveConnectWalletSession, RequestApproveWalletConnectNotSupport, RequestAuthorization, RequestAuthorizationBlock, RequestAuthorizationPerAccount, RequestAuthorizationPerSite, RequestAuthorizeApproveV2, RequestBatchRestoreV2, RequestBondingSubmit, RequestCameraSettings, RequestCampaignBannerComplete, RequestChangeEnableChainPatrol, RequestChangeLanguage, RequestChangeMasterPassword, RequestChangePriceCurrency, RequestChangeShowBalance, RequestChangeShowZeroBalance, RequestChangeTimeAutoLock, RequestCheckPublicAndSecretKey, RequestConfirmationComplete, RequestConnectWalletConnect, RequestCrossChainTransfer, RequestCrowdloanContributions, RequestDeleteContactAccount, RequestDisconnectWalletConnectSession, RequestEditContactAccount, RequestFindRawMetadata, RequestForgetSite, RequestFreeBalance, RequestGetTransaction, RequestJsonRestoreV2, RequestKeyringExportMnemonic, RequestMaxTransferable, RequestMigratePassword, RequestParseEvmContractInput, RequestParseTransactionSubstrate, RequestPassPhishingPage, RequestQrParseRLP, RequestQrSignEvm, RequestQrSignSubstrate, RequestRejectConnectWalletSession, RequestRejectExternalRequest, RequestRejectWalletConnectNotSupport, RequestRemoveInjectedAccounts, RequestResetWallet, RequestResolveExternalRequest, RequestSaveRecentAccount, RequestSeedCreateV2, RequestSeedValidateV2, RequestSettingsType, RequestSigningApprovePasswordV2, RequestStakePoolingBonding, RequestStakePoolingUnbonding, RequestSubscribeHistory, RequestSubstrateNftSubmitTransaction, RequestTransfer, RequestTuringCancelStakeCompound, RequestTuringStakeCompound, RequestUnbondingSubmit, RequestUnlockKeyring, RequestUnlockType, ResolveAddressToDomainRequest, ResolveDomainRequest, ResponseAccountBatchExportV2, ResponseAccountCreateWithSecretKey, ResponseAccountExportPrivateKey, ResponseChangeMasterPassword, ResponseCheckPublicAndSecretKey, ResponseFindRawMetadata, ResponseKeyringExportMnemonic, ResponseMigratePassword, ResponseParseEvmContractInput, ResponseParseTransactionSubstrate, ResponsePrivateKeyValidateV2, ResponseQrParseRLP, ResponseQrSignEvm, ResponseQrSignSubstrate, ResponseRejectExternalRequest, ResponseResetWallet, ResponseResolveExternalRequest, ResponseSeedCreateV2, ResponseSeedValidateV2, ResponseSubscribeHistory, ResponseUnlockKeyring, ShowCampaignPopupRequest, StakingJson, StakingRewardJson, StakingTxErrorType, StakingType, ThemeNames, TransactionHistoryItem, TransactionResponse, ValidateNetworkRequest, ValidateNetworkResponse, ValidatorInfo } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountAuthType, AuthorizeRequest, MessageTypes, MetadataRequest, RequestAccountChangePassword, RequestAccountCreateHardware, RequestAccountCreateSuri, RequestAccountExport, RequestAccountShow, RequestAccountTie, RequestAccountValidate, RequestAuthorizeCancel, RequestAuthorizeReject, RequestBatchRestore, RequestCurrentAccountAddress, RequestDeriveCreate, RequestDeriveValidate, RequestJsonRestore, RequestMetadataApprove, RequestMetadataReject, RequestSeedCreate, RequestSeedValidate, RequestSigningApproveSignature, RequestSigningCancel, RequestTypes, ResponseAccountExport, ResponseAuthorizeList, ResponseDeriveValidate, ResponseJsonGetAccountInfo, ResponseSeedCreate, ResponseSeedValidate, ResponseType, SigningRequest, WindowOpenParams } from '@subwallet/extension-base/background/types'; +import { AccountExternalError, AddressBookInfo, AmountData, AmountDataWithId, AssetSetting, AssetSettingUpdateReq, BasicTxErrorType, BondingOptionParams, BrowserConfirmationType, CampaignBanner, CampaignData, CampaignDataType, ChainType, CronReloadRequest, CrowdloanJson, ExternalRequestPromiseStatus, ExtrinsicType, KeyringState, MantaPayEnableMessage, MantaPayEnableParams, MantaPayEnableResponse, MantaPaySyncState, MetadataItem, NftCollection, NftJson, NftTransactionRequest, NftTransactionResponse, OptionInputAddress, PriceJson, RequestAccountBatchExportV2, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateWithSecretKey, RequestAccountExportPrivateKey, RequestAddInjectedAccounts, RequestApproveConnectWalletSession, RequestApproveWalletConnectNotSupport, RequestAuthorization, RequestAuthorizationBlock, RequestAuthorizationPerAccount, RequestAuthorizationPerSite, RequestAuthorizeApproveV2, RequestBatchRestoreV2, RequestBondingSubmit, RequestCameraSettings, RequestCampaignBannerComplete, RequestChangeEnableChainPatrol, RequestChangeLanguage, RequestChangeMasterPassword, RequestChangePriceCurrency, RequestChangeShowBalance, RequestChangeShowZeroBalance, RequestChangeTimeAutoLock, RequestConfirmationComplete, RequestConnectWalletConnect, RequestCrossChainTransfer, RequestCrowdloanContributions, RequestDeleteContactAccount, RequestDisconnectWalletConnectSession, RequestEditContactAccount, RequestFindRawMetadata, RequestForgetSite, RequestFreeBalance, RequestGetTransaction, RequestJsonRestoreV2, RequestKeyringExportMnemonic, RequestMaxTransferable, RequestMigratePassword, RequestParseEvmContractInput, RequestParseTransactionSubstrate, RequestPassPhishingPage, RequestQrParseRLP, RequestQrSignEvm, RequestQrSignSubstrate, RequestRejectConnectWalletSession, RequestRejectExternalRequest, RequestRejectWalletConnectNotSupport, RequestRemoveInjectedAccounts, RequestResetWallet, RequestResolveExternalRequest, RequestSaveRecentAccount, RequestSettingsType, RequestSigningApprovePasswordV2, RequestStakePoolingBonding, RequestStakePoolingUnbonding, RequestSubscribeHistory, RequestSubstrateNftSubmitTransaction, RequestTransfer, RequestTuringCancelStakeCompound, RequestTuringStakeCompound, RequestUnbondingSubmit, RequestUnlockKeyring, RequestUnlockType, ResolveAddressToDomainRequest, ResolveDomainRequest, ResponseAccountBatchExportV2, ResponseAccountCreateWithSecretKey, ResponseAccountExportPrivateKey, ResponseChangeMasterPassword, ResponseFindRawMetadata, ResponseKeyringExportMnemonic, ResponseMigratePassword, ResponseParseEvmContractInput, ResponseParseTransactionSubstrate, ResponseQrParseRLP, ResponseQrSignEvm, ResponseQrSignSubstrate, ResponseRejectExternalRequest, ResponseResetWallet, ResponseResolveExternalRequest, ResponseSubscribeHistory, ResponseUnlockKeyring, ShowCampaignPopupRequest, StakingJson, StakingRewardJson, StakingTxErrorType, StakingType, ThemeNames, TransactionHistoryItem, TransactionResponse, ValidateNetworkRequest, ValidateNetworkResponse, ValidatorInfo } from '@subwallet/extension-base/background/KoniTypes'; +import { AccountAuthType, AuthorizeRequest, MessageTypes, MetadataRequest, RequestAccountChangePassword, RequestAccountCreateHardware, RequestAccountExport, RequestAccountShow, RequestAccountTie, RequestAccountValidate, RequestAuthorizeCancel, RequestAuthorizeReject, RequestBatchRestore, RequestCurrentAccountAddress, RequestDeriveCreate, RequestDeriveValidate, RequestJsonRestore, RequestMetadataApprove, RequestMetadataReject, RequestSigningApproveSignature, RequestSigningCancel, RequestTypes, ResponseAccountExport, ResponseAuthorizeList, ResponseDeriveValidate, ResponseJsonGetAccountInfo, ResponseType, SigningRequest, WindowOpenParams } from '@subwallet/extension-base/background/types'; import { TransactionWarning } from '@subwallet/extension-base/background/warnings/TransactionWarning'; import { ALL_ACCOUNT_KEY, LATEST_SESSION, XCM_FEE_RATIO } from '@subwallet/extension-base/constants'; import { additionalValidateTransfer, additionalValidateXcmTransfer, validateTransferRequest, validateXcmTransferRequest } from '@subwallet/extension-base/core/logic-validation/transfer'; @@ -41,7 +41,9 @@ import { isProposalExpired, isSupportWalletConnectChain, isSupportWalletConnectN import { ResultApproveWalletConnectSession, WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; import { SWStorage } from '@subwallet/extension-base/storage'; import { AccountsStore } from '@subwallet/extension-base/stores'; -import { AccountProxy, AccountProxyType, AccountsWithCurrentAddress, BalanceJson, BuyServiceInfo, BuyTokenInfo, EarningRewardJson, NominationPoolInfo, OptimalYieldPathParams, RequestAccountCreateSuriV2, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestEarlyValidateYield, RequestGetDeriveAccounts, RequestGetYieldPoolTargets, RequestMetadataHash, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseAccountCreateSuriV2, ResponseDeriveValidateV2, ResponseGetDeriveAccounts, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseShortenMetadata, StorageDataInterface, TokenSpendingApprovalParams, ValidateYieldProcessParams, YieldPoolType } from '@subwallet/extension-base/types'; +import { + AccountProxy, AccountProxyType, AccountsWithCurrentAddress, BalanceJson, BuyServiceInfo, BuyTokenInfo, EarningRewardJson, NominationPoolInfo, OptimalYieldPathParams, RequestAccountCreateSuriV2, RequestCheckPublicAndSecretKey, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestEarlyValidateYield, RequestExportAccountProxyMnemonic, RequestGetDeriveAccounts, RequestGetYieldPoolTargets, RequestMetadataHash, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseAccountCreateSuriV2, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseExportAccountProxyMnemonic, ResponseGetDeriveAccounts, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2, ResponseShortenMetadata, StorageDataInterface, TokenSpendingApprovalParams, ValidateYieldProcessParams, YieldPoolType +} from '@subwallet/extension-base/types'; import { RequestAccountProxyEdit, RequestAccountProxyForget } from '@subwallet/extension-base/types/account/action/edit'; import { CommonOptimalPath } from '@subwallet/extension-base/types/service-base'; import { SwapPair, SwapQuoteResponse, SwapRequest, SwapRequestResult, SwapSubmitParams, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap'; @@ -66,16 +68,7 @@ import { Metadata, TypeRegistry } from '@polkadot/types'; import { ChainProperties } from '@polkadot/types/interfaces'; import { Registry, SignerPayloadJSON, SignerPayloadRaw } from '@polkadot/types/types'; import { assert, hexStripPrefix, hexToU8a, isAscii, isHex, u8aToHex } from '@polkadot/util'; -import { decodeAddress, isAddress, isEthereumAddress, keyExtractSuri, mnemonicGenerate, mnemonicValidate } from '@polkadot/util-crypto'; -import { KeypairType } from '@polkadot/util-crypto/types'; - -const ETH_DERIVE_DEFAULT = '/m/44\'/60\'/0\'/0/0'; - -function getSuri (seed: string, type?: KeypairType): string { - return type === 'ethereum' - ? `${seed}${ETH_DERIVE_DEFAULT}` - : seed; -} +import { decodeAddress, isAddress, isEthereumAddress } from '@polkadot/util-crypto'; const ACCOUNT_ALL_GROUP: AccountProxy = { id: ALL_ACCOUNT_KEY, @@ -151,12 +144,6 @@ export default class KoniExtension { return true; } - private accountsCreateSuri ({ genesisHash, name, suri, type }: RequestAccountCreateSuri): boolean { - keyring.addUri(getSuri(suri, type), { genesisHash, name }, type); - - return true; - } - private accountsChangePassword ({ address, newPass, oldPass }: RequestAccountChangePassword): boolean { const pair = keyring.getPair(address); @@ -301,32 +288,6 @@ export default class KoniExtension { } } - private seedCreate ({ length = SEED_DEFAULT_LENGTH, seed: _seed, type }: RequestSeedCreate): ResponseSeedCreate { - const seed = _seed || mnemonicGenerate(length); - - return { - address: keyring.createFromUri(getSuri(seed, type), {}, type).address, - seed - }; - } - - private seedValidate ({ suri, type }: RequestSeedValidate): ResponseSeedValidate { - const { phrase } = keyExtractSuri(suri); - - if (isHex(phrase)) { - assert(isHex(phrase, 256), t('Invalid seed phrase. Please try again.')); - } else { - // sadly isHex detects as string, so we need a cast here - assert(SEED_LENGTHS.includes((phrase).split(' ').length), t('Seed phrase needs to contain {{x}} words', { replace: { x: SEED_LENGTHS.join(', ') } })); - assert(mnemonicValidate(phrase), t('Invalid seed phrase. Please try again.')); - } - - return { - address: keyring.createFromUri(getSuri(suri, type), {}, type).address, - suri - }; - } - // TODO: move to request service private signingApproveSignature ({ id, signature, signedTransaction }: RequestSigningApproveSignature): boolean { const queued = this.#koniState.getSignRequest(id); @@ -1211,69 +1172,16 @@ export default class KoniExtension { return true; } - private seedCreateV2 ({ length = SEED_DEFAULT_LENGTH, - seed: _seed, - types }: RequestSeedCreateV2): ResponseSeedCreateV2 { - const seed = _seed || mnemonicGenerate(length); - const rs = { seed: seed, addressMap: {} } as ResponseSeedCreateV2; - - types?.forEach((type) => { - rs.addressMap[type] = keyring.createFromUri(getSuri(seed, type), {}, type).address; - }); - - return rs; + private seedCreateV2 (request: RequestMnemonicCreateV2): ResponseMnemonicCreateV2 { + return this.#koniState.keyringService.context.mnemonicCreateV2(request); } - private seedValidateV2 ({ suri, types }: RequestSeedValidateV2): ResponseSeedValidateV2 { - const { phrase } = keyExtractSuri(suri); - - if (isHex(phrase)) { - assert(isHex(phrase, 256), t('Invalid seed phrase. Please try again.')); - } else { - // sadly isHex detects as string, so we need a cast here - assert(SEED_LENGTHS.includes((phrase).split(' ').length), t('Seed phrase needs to contain {{x}} words', { replace: { x: SEED_LENGTHS.join(', ') } })); - assert(mnemonicValidate(phrase), t('Invalid seed phrase. Please try again.')); - } - - const rs = { seed: suri, addressMap: {} } as ResponseSeedValidateV2; - - types && types.forEach((type) => { - rs.addressMap[type] = keyring.createFromUri(getSuri(suri, type), {}, type).address; - }); - - return rs; + private seedValidateV2 (request: RequestMnemonicValidateV2): ResponseMnemonicValidateV2 { + return this.#koniState.keyringService.context.mnemonicValidateV2(request); } - private _checkValidatePrivateKey ({ suri, - types }: RequestSeedValidateV2, autoAddPrefix = false): ResponsePrivateKeyValidateV2 { - const { phrase } = keyExtractSuri(suri); - const rs = { autoAddPrefix: autoAddPrefix, addressMap: {} } as ResponsePrivateKeyValidateV2; - - types && types.forEach((type) => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - rs.addressMap[type] = ''; - }); - - if (isHex(phrase) && isHex(phrase, 256)) { - types && types.forEach((type) => { - rs.addressMap[type] = keyring.createFromUri(getSuri(suri, type), {}, type).address; - }); - } else { - rs.autoAddPrefix = false; - assert(false, t('Invalid private key. Please try again.')); - } - - return rs; - } - - private metamaskPrivateKeyValidateV2 ({ suri, types }: RequestSeedValidateV2): ResponsePrivateKeyValidateV2 { - const isHex = suri.startsWith('0x'); - - if (isHex) { - return this._checkValidatePrivateKey({ suri, types }); - } else { - return this._checkValidatePrivateKey({ suri: `0x${suri}`, types }, true); - } + private metamaskPrivateKeyValidateV2 (request: RequestPrivateKeyValidateV2): ResponsePrivateKeyValidateV2 { + return this.#koniState.keyringService.context.metamaskPrivateKeyValidateV2(request); } private jsonRestoreV2 (request: RequestJsonRestoreV2): void { @@ -1308,6 +1216,10 @@ export default class KoniExtension { } } + private exportAccountProxyMnemonic (request: RequestExportAccountProxyMnemonic): ResponseExportAccountProxyMnemonic { + return this.#koniState.keyringService.context.exportAccountProxyMnemonic(request); + } + private getNftCollection (): Promise { return this.#koniState.getNftCollection(); } @@ -3803,9 +3715,6 @@ export default class KoniExtension { case 'pri(accounts.create.hardware)': return this.accountsCreateHardware(request as RequestAccountCreateHardware); - case 'pri(accounts.create.suri)': - return this.accountsCreateSuri(request as RequestAccountCreateSuri); - case 'pri(accounts.changePassword)': return this.accountsChangePassword(request as RequestAccountChangePassword); @@ -3851,12 +3760,6 @@ export default class KoniExtension { case 'pri(json.account.info)': return this.jsonGetAccountInfo(request as KeyringPair$Json); - case 'pri(seed.create)': - return this.seedCreate(request as RequestSeedCreate); - - case 'pri(seed.validate)': - return this.seedValidate(request as RequestSeedValidate); - case 'pri(signing.approve.signature)': return this.signingApproveSignature(request as RequestSigningApproveSignature); @@ -4028,25 +3931,27 @@ export default class KoniExtension { case 'pri(accounts.json.batchRestoreV2)': return this.batchRestoreV2(request as RequestBatchRestoreV2); case 'pri(seed.createV2)': - return this.seedCreateV2(request as RequestSeedCreateV2); + return this.seedCreateV2(request as RequestMnemonicCreateV2); // Remove account case 'pri(accounts.forget)': return await this.accountsForgetOverride(request as RequestAccountProxyForget); // Validate account - case 'pri(seed.validateV2)': - return this.seedValidateV2(request as RequestSeedValidateV2); - case 'pri(privateKey.validateV2)': - return this.metamaskPrivateKeyValidateV2(request as RequestSeedValidateV2); - case 'pri(accounts.checkPublicAndSecretKey)': + case 'pri(accounts.validate.seed)': + return this.seedValidateV2(request as RequestMnemonicValidateV2); + case 'pri(accounts.validate.metamask.privateKey)': + return this.metamaskPrivateKeyValidateV2(request as RequestPrivateKeyValidateV2); + case 'pri(accounts.validate.substrate.publicAndPrivateKey)': return this.checkPublicAndSecretKey(request as RequestCheckPublicAndSecretKey); // Export account - case 'pri(accounts.exportPrivateKey)': + case 'pri(accounts.export.privateKey)': return this.accountExportPrivateKey(request as RequestAccountExportPrivateKey); - case 'pri(accounts.batchExportV2)': + case 'pri(accounts.export.json.batch)': return this.batchExportV2(request as RequestAccountBatchExportV2); + case 'pri(accounts.export.mnemonic)': + return this.exportAccountProxyMnemonic(request as RequestExportAccountProxyMnemonic); // Subscribe account case 'pri(accounts.subscribeWithCurrentProxy)': diff --git a/packages/extension-base/src/koni/background/handlers/State.ts b/packages/extension-base/src/koni/background/handlers/State.ts index 022e3804f5..bc856b119b 100644 --- a/packages/extension-base/src/koni/background/handlers/State.ts +++ b/packages/extension-base/src/koni/background/handlers/State.ts @@ -5,7 +5,7 @@ import { _AssetRef, _AssetType, _ChainAsset, _ChainInfo, _MultiChainAsset } from import { EvmProviderError } from '@subwallet/extension-base/background/errors/EvmProviderError'; import { withErrorLog } from '@subwallet/extension-base/background/handlers/helpers'; import { isSubscriptionRunning, unsubscribe } from '@subwallet/extension-base/background/handlers/subscriptions'; -import { AccountRefMap, AddTokenRequestExternal, AmountData, APIItemState, ApiMap, AuthRequestV2, BasicTxErrorType, ChainStakingMetadata, ChainType, ConfirmationsQueue, CrowdloanItem, CrowdloanJson, CurrencyType, EvmProviderErrorType, EvmSendTransactionParams, EvmSendTransactionRequest, EvmSignatureRequest, ExternalRequestPromise, ExternalRequestPromiseStatus, ExtrinsicType, MantaAuthorizationContext, MantaPayConfig, MantaPaySyncState, NftCollection, NftItem, NftJson, NominatorMetadata, RequestAccountExportPrivateKey, RequestCheckPublicAndSecretKey, RequestConfirmationComplete, RequestCrowdloanContributions, RequestSettingsType, ResponseAccountExportPrivateKey, ResponseCheckPublicAndSecretKey, ServiceInfo, SingleModeJson, StakingItem, StakingJson, StakingRewardItem, StakingRewardJson, StakingType, UiSettings } from '@subwallet/extension-base/background/KoniTypes'; +import { AccountRefMap, AddTokenRequestExternal, AmountData, APIItemState, ApiMap, AuthRequestV2, BasicTxErrorType, ChainStakingMetadata, ChainType, ConfirmationsQueue, CrowdloanItem, CrowdloanJson, CurrencyType, EvmProviderErrorType, EvmSendTransactionParams, EvmSendTransactionRequest, EvmSignatureRequest, ExternalRequestPromise, ExternalRequestPromiseStatus, ExtrinsicType, MantaAuthorizationContext, MantaPayConfig, MantaPaySyncState, NftCollection, NftItem, NftJson, NominatorMetadata, RequestAccountExportPrivateKey, RequestConfirmationComplete, RequestCrowdloanContributions, RequestSettingsType, ResponseAccountExportPrivateKey, ServiceInfo, SingleModeJson, StakingItem, StakingJson, StakingRewardItem, StakingRewardJson, StakingType, UiSettings } from '@subwallet/extension-base/background/KoniTypes'; import { RequestAuthorizeTab, RequestRpcSend, RequestRpcSubscribe, RequestRpcUnsubscribe, RequestSign, ResponseRpcListProviders, ResponseSigning } from '@subwallet/extension-base/background/types'; import { ALL_ACCOUNT_KEY, MANTA_PAY_BALANCE_INTERVAL, REMIND_EXPORT_ACCOUNT } from '@subwallet/extension-base/constants'; import { BalanceService } from '@subwallet/extension-base/services/balance-service'; @@ -38,7 +38,7 @@ import { TransactionEventResponse } from '@subwallet/extension-base/services/tra import WalletConnectService from '@subwallet/extension-base/services/wallet-connect-service'; import { SWStorage } from '@subwallet/extension-base/storage'; import AccountRefStore from '@subwallet/extension-base/stores/AccountRef'; -import { AccountJson, BalanceItem, BalanceMap, CurrentAccountInfo, EvmFeeInfo, StorageDataInterface } from '@subwallet/extension-base/types'; +import { AccountJson, BalanceItem, BalanceMap, CurrentAccountInfo, EvmFeeInfo, RequestCheckPublicAndSecretKey, ResponseCheckPublicAndSecretKey, StorageDataInterface } from '@subwallet/extension-base/types'; import { isAccountAll, pairToAccount, stripUrl, targetIsWeb, wait } from '@subwallet/extension-base/utils'; import { isContractAddress, parseContractInput } from '@subwallet/extension-base/utils/eth/parseTransaction'; import { createPromiseHandler } from '@subwallet/extension-base/utils/promise'; diff --git a/packages/extension-base/src/services/keyring-service/account-context.ts b/packages/extension-base/src/services/keyring-service/account-context.ts index 64616154c3..073bab59a6 100644 --- a/packages/extension-base/src/services/keyring-service/account-context.ts +++ b/packages/extension-base/src/services/keyring-service/account-context.ts @@ -3,21 +3,23 @@ import { AccountExternalError, AccountExternalErrorCode, AccountRefMap, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateWithSecretKey, RequestBatchRestoreV2, RequestJsonRestoreV2, ResponseAccountCreateWithSecretKey } from '@subwallet/extension-base/background/KoniTypes'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; +import { SEED_DEFAULT_LENGTH, SEED_LENGTHS } from '@subwallet/extension-base/koni/background/handlers/Extension'; import { KeyringService } from '@subwallet/extension-base/services/keyring-service/index'; import { AccountProxyStore, AccountRefStore, CurrentAccountStore, ModifyPairStore } from '@subwallet/extension-base/stores'; -import { AccountJson, AccountProxy, AccountProxyData, AccountProxyMap, AccountProxyStoreData, AccountProxyType, CreateDeriveAccountInfo, CurrentAccountInfo, DeriveAccountInfo, ModifyPairStoreData, RequestAccountCreateSuriV2, RequestDeriveAccountProxy, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestGetDeriveAccounts, ResponseAccountCreateSuriV2, ResponseDeriveValidateV2, ResponseGetDeriveAccounts } from '@subwallet/extension-base/types'; +import { AccountJson, AccountProxy, AccountProxyData, AccountProxyMap, AccountProxyStoreData, AccountProxyType, CreateDeriveAccountInfo, CurrentAccountInfo, DeriveAccountInfo, MnemonicType, ModifyPairStoreData, RequestAccountCreateSuriV2, RequestDeriveAccountProxy, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestExportAccountProxyMnemonic, RequestGetDeriveAccounts, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, ResponseAccountCreateSuriV2, ResponseDeriveValidateV2, ResponseExportAccountProxyMnemonic, ResponseGetDeriveAccounts, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2 } from '@subwallet/extension-base/types'; import { RequestAccountProxyEdit, RequestAccountProxyForget } from '@subwallet/extension-base/types/account/action/edit'; import { isAddressValidWithAuthType, modifyAccountName, singleAddressToAccount } from '@subwallet/extension-base/utils'; import { InjectedAccountWithMeta } from '@subwallet/extension-inject/types'; import { createPair, getDerivePath, getKeypairTypeByAddress } from '@subwallet/keyring'; import { BitcoinKeypairTypes, KeypairType, KeyringPair, KeyringPair$Json, KeyringPair$Meta, TonKeypairTypes } from '@subwallet/keyring/types'; +import { tonMnemonicValidate } from '@subwallet/keyring/utils'; import { keyring } from '@subwallet/ui-keyring'; import { SubjectInfo } from '@subwallet/ui-keyring/observable/types'; import { t } from 'i18next'; import { BehaviorSubject, combineLatest } from 'rxjs'; import { assert, hexStripPrefix, hexToU8a, isHex, stringShorten, u8aToHex, u8aToString } from '@polkadot/util'; -import { base64Decode, blake2AsHex, jsonDecrypt, keyExtractSuri, mnemonicToEntropy } from '@polkadot/util-crypto'; +import { base64Decode, blake2AsHex, jsonDecrypt, keyExtractSuri, mnemonicGenerate, mnemonicToEntropy, mnemonicValidate } from '@polkadot/util-crypto'; import { validateMnemonic } from '@polkadot/util-crypto/mnemonic/bip39'; import { EncryptedJson, Prefix } from '@polkadot/util-crypto/types'; @@ -31,6 +33,10 @@ const CURRENT_ACCOUNT_KEY = 'CurrentAccountInfo'; const MODIFY_PAIRS_KEY = 'ModifyPairs'; const ACCOUNT_PROXIES_KEY = 'AccountProxies'; +/** + * @class AccountContext + * @note Can convert multiple states into one state and split functions into related handlers + * */ export class AccountContext { // Current account private readonly currentAccountStore = new CurrentAccountStore(); @@ -381,7 +387,61 @@ export class AccountContext { /* Modify accounts */ - /* Add accounts from seed */ + /* Create with mnemonic */ + + /* Create seed */ + public mnemonicCreateV2 ({ length = SEED_DEFAULT_LENGTH, mnemonic: _seed, type = 'general' }: RequestMnemonicCreateV2): ResponseMnemonicCreateV2 { + const seed = _seed || mnemonicGenerate(length); + // At this point, only 'general' type will be accepted + const types: KeypairType[] = type === 'general' ? ['sr25519', 'ethereum', 'ton'] : ['ton-special']; + const rs = { mnemonic: seed, addressMap: {} } as ResponseMnemonicCreateV2; + + types?.forEach((type) => { + rs.addressMap[type] = keyring.createFromUri(getSuri(seed, type), {}, type).address; + }); + + return rs; + } + + /* Validate seed */ + public mnemonicValidateV2 ({ mnemonic }: RequestMnemonicValidateV2): ResponseMnemonicValidateV2 { + const { phrase } = keyExtractSuri(mnemonic); + let mnemonicTypes: MnemonicType = 'general'; + let pairTypes: KeypairType[] = []; + + if (isHex(phrase)) { + assert(isHex(phrase, 256), t('Invalid seed phrase. Please try again.')); + } else { + // sadly isHex detects as string, so we need a cast here + assert(SEED_LENGTHS.includes((phrase).split(' ').length), t('Seed phrase needs to contain {{x}} words', { replace: { x: SEED_LENGTHS.join(', ') } })); + + try { + assert(mnemonicValidate(phrase), t('Invalid seed phrase. Please try again.')); + + mnemonicTypes = 'general'; + pairTypes = ['sr25519', 'ethereum', 'ton']; + } catch (e) { + assert(tonMnemonicValidate(phrase), t('Invalid seed phrase. Please try again.')); + mnemonicTypes = 'ton'; + pairTypes = ['ton-special']; + } + } + + const rs: ResponseMnemonicValidateV2 = { + mnemonic, + addressMap: {} as Record, + mnemonicTypes, + pairTypes + }; + + pairTypes.forEach((type) => { + rs.addressMap[type] = keyring.createFromUri(getSuri(mnemonic, type), {}, type).address; + }); + + return rs; + } + + /* Add accounts from mnemonic */ public accountsCreateSuriV2 (request: RequestAccountCreateSuriV2): ResponseAccountCreateSuriV2 { const { isAllowed, name, password, suri: _suri, types } = request; const addressDict = {} as Record; @@ -448,6 +508,8 @@ export class AccountContext { return addressDict; } + /* Create with mnemonic */ + /* Add QR-signer, read-only */ public async accountsCreateExternalV2 (request: RequestAccountCreateExternalV2): Promise { const { address, isAllowed, isReadOnly, name } = request; @@ -501,6 +563,40 @@ export class AccountContext { } } + /* Import ethereum account with the private key */ + public _checkValidatePrivateKey ({ privateKey }: RequestPrivateKeyValidateV2, autoAddPrefix = false): ResponsePrivateKeyValidateV2 { + const { phrase } = keyExtractSuri(privateKey); + const rs = { autoAddPrefix: autoAddPrefix, addressMap: {} } as ResponsePrivateKeyValidateV2; + const types: KeypairType[] = ['ethereum']; + + types.forEach((type) => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + rs.addressMap[type] = ''; + }); + + if (isHex(phrase) && isHex(phrase, 256)) { + types && types.forEach((type) => { + rs.addressMap[type] = keyring.createFromUri(getSuri(privateKey, type), {}, type).address; + }); + } else { + rs.autoAddPrefix = false; + assert(false, t('Invalid private key. Please try again.')); + } + + return rs; + } + + public metamaskPrivateKeyValidateV2 ({ privateKey }: RequestPrivateKeyValidateV2): ResponsePrivateKeyValidateV2 { + const isHex = privateKey.startsWith('0x'); + + if (isHex) { + return this._checkValidatePrivateKey({ privateKey }); + } else { + return this._checkValidatePrivateKey({ privateKey: `0x${privateKey}` }, true); + } + } + /* Import ethereum account with the private key */ + /* Ledger */ /* For custom derive path */ @@ -1046,6 +1142,47 @@ export class AccountContext { /* Derive */ + /* Export */ + + /* Export mnemonic */ + public exportAccountProxyMnemonic ({ password, proxyId }: RequestExportAccountProxyMnemonic): ResponseExportAccountProxyMnemonic { + const accountProxies = this.accountProxiesSubject.value; + const modifyPairs = this.modifyPairsSubject.value; + + if (!accountProxies[proxyId]) { + const pair = keyring.getPair(proxyId); + + assert(pair, t('Unable to find account')); + + const result = pair.exportMnemonic(password); + + return { result }; + } else { + const accountGroup = accountProxies[proxyId]; + const addresses = Object.keys(modifyPairs).filter((address) => modifyPairs[address].accountProxyId === proxyId); + + this.upsertAccountProxy(accountGroup); + + let pair: KeyringPair | undefined; + + for (const address of addresses) { + pair = keyring.getPair(address); + + if (pair && pair.haveEntropy) { + break; + } + } + + assert(pair, t('Unable to find account')); + + const result = pair.exportMnemonic(password) || ''; + + return { result }; + } + } + + /* Export */ + /* Inject */ public addInjectAccounts (accounts: InjectedAccountWithMeta[]) { diff --git a/packages/extension-base/src/types/account/action/add.ts b/packages/extension-base/src/types/account/action/add.ts deleted file mode 100644 index 466e056de5..0000000000 --- a/packages/extension-base/src/types/account/action/add.ts +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2019-2022 @subwallet/extension-base authors & contributors -// SPDX-License-Identifier: Apache-2.0 - -import { KeypairType } from '@subwallet/keyring/types'; - -export interface RequestAccountCreateSuriV2 { - name: string; - password?: string; - suri: string; - types?: Array; - isAllowed: boolean; -} - -export type ResponseAccountCreateSuriV2 = Record diff --git a/packages/extension-base/src/types/account/action/add/index.ts b/packages/extension-base/src/types/account/action/add/index.ts new file mode 100644 index 0000000000..0e36a5c494 --- /dev/null +++ b/packages/extension-base/src/types/account/action/add/index.ts @@ -0,0 +1,6 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export * from './metamask'; +export * from './mnemonic'; +export * from './substrate'; diff --git a/packages/extension-base/src/types/account/action/add/metamask.ts b/packages/extension-base/src/types/account/action/add/metamask.ts new file mode 100644 index 0000000000..b99cc8149e --- /dev/null +++ b/packages/extension-base/src/types/account/action/add/metamask.ts @@ -0,0 +1,20 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { KeypairType } from '@subwallet/keyring/types'; + +export interface RequestPrivateKeyValidateV2 { + privateKey: string; +} + +/** + * @interface ResponsePrivateKeyValidateV2 + * @description Represents the response for validating a private key. + * + * @property {Record} addressMap - A map of key pair types to their corresponding addresses. + * @property {boolean} autoAddPrefix - Indicates if the prefix should be automatically added. + */ +export interface ResponsePrivateKeyValidateV2 { + addressMap: Record, + autoAddPrefix: boolean +} diff --git a/packages/extension-base/src/types/account/action/add/mnemonic.ts b/packages/extension-base/src/types/account/action/add/mnemonic.ts new file mode 100644 index 0000000000..29570d4597 --- /dev/null +++ b/packages/extension-base/src/types/account/action/add/mnemonic.ts @@ -0,0 +1,88 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { SeedLengths } from '@subwallet/extension-base/background/types'; +import { KeypairType } from '@subwallet/keyring/types'; + +export type MnemonicType = 'general' | 'ton'; + +/** + * @interface RequestMnemonicCreateV2 + * @description Represents a request to create a new mnemonic phrase. + * + * @property {SeedLengths} [length] - The desired length of the mnemonic phrase. + * @property {string} [mnemonic] - An optional predefined mnemonic phrase. + * If provided, this mnemonic will be used instead of generating a new one. + * @property {MnemonicType} [type] - The type of mnemonic to create. + */ +export interface RequestMnemonicCreateV2 { + length?: SeedLengths; + mnemonic?: string; + type?: MnemonicType; +} + +/** + * @interface ResponseMnemonicCreateV2 + * @description Represents the response for creating a new mnemonic phrase. + * + * @property {string} mnemonic - The generated mnemonic phrase. + * @property {Array} pairTypes - The types of key pairs associated with the mnemonic. + * @property {Record} addressMap - A map of key pair types to their corresponding addresses. + */ +export interface ResponseMnemonicCreateV2 { + mnemonic: string; + pairTypes: Array; + addressMap: Record; +} + +/** + * @interface RequestMnemonicValidateV2 + * @description Represents a request to validate a mnemonic phrase. + * + * @property {string} mnemonic - The mnemonic seed to validate. + */ +export interface RequestMnemonicValidateV2 { + mnemonic: string; +} + +/** + * @interface ResponseMnemonicValidateV2 + * @description Represents the response for validating a mnemonic phrase. + * + * @property {string} mnemonic - The mnemonic phrase that was validated. + * @property {MnemonicType} mnemonicTypes - The type of the mnemonic phrase. + * @property {Array} pairTypes - The types of key pairs associated with the mnemonic. + * @property {Record} addressMap - A map of key pair types to their corresponding addresses. + */ +export interface ResponseMnemonicValidateV2 { + mnemonic: string; + mnemonicTypes: MnemonicType; + pairTypes: Array; + addressMap: Record; +} + +/** + * @interface RequestAccountCreateSuriV2 + * @description Represents a request to create an account from a mnemonic phrase. + * + * @property {string} name - The name of the account. + * @property {string} [password] - An optional password for the account. + * @property {string} suri - The mnemonic phrase or derivation path. + * @property {Array} [types] - The types of key pairs to create. Optional. + * @property {boolean} isAllowed - Indicates if the account creation is allowed. + */ +export interface RequestAccountCreateSuriV2 { + name: string; + password?: string; + suri: string; + types?: Array; + isAllowed: boolean; +} + +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 +/** + * @typedef {Record} ResponseAccountCreateSuriV2 + * @description Represents the response for creating an account from a mnemonic phrase. + */ +export type ResponseAccountCreateSuriV2 = Record; diff --git a/packages/extension-base/src/types/account/action/add/substrate.ts b/packages/extension-base/src/types/account/action/add/substrate.ts new file mode 100644 index 0000000000..0d27980e42 --- /dev/null +++ b/packages/extension-base/src/types/account/action/add/substrate.ts @@ -0,0 +1,13 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export interface RequestCheckPublicAndSecretKey { + secretKey: string; + publicKey: string; +} + +export interface ResponseCheckPublicAndSecretKey { + address: string; + isValid: boolean; + isEthereum: boolean; +} diff --git a/packages/extension-base/src/types/account/action/export.ts b/packages/extension-base/src/types/account/action/export.ts new file mode 100644 index 0000000000..815570f7c2 --- /dev/null +++ b/packages/extension-base/src/types/account/action/export.ts @@ -0,0 +1,11 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export interface RequestExportAccountProxyMnemonic { + proxyId: string; + password: string; +} + +export interface ResponseExportAccountProxyMnemonic { + result: string; +} diff --git a/packages/extension-base/src/types/account/action/index.ts b/packages/extension-base/src/types/account/action/index.ts index b5e2eb5397..1d9830fbfc 100644 --- a/packages/extension-base/src/types/account/action/index.ts +++ b/packages/extension-base/src/types/account/action/index.ts @@ -3,3 +3,5 @@ export * from './add'; export * from './derive'; +export * from './edit'; +export * from './export'; diff --git a/packages/extension-koni-ui/src/Popup/Account/NewSeedPhrase.tsx b/packages/extension-koni-ui/src/Popup/Account/NewSeedPhrase.tsx index 7f42a92b00..9aa01868f7 100644 --- a/packages/extension-koni-ui/src/Popup/Account/NewSeedPhrase.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/NewSeedPhrase.tsx @@ -111,7 +111,7 @@ const Component: React.FC = ({ className }: Props) => { useEffect(() => { createSeedV2(undefined, undefined, DEFAULT_ACCOUNT_TYPES) .then((response): void => { - const phrase = response.seed; + const phrase = response.mnemonic; setSeedPhrase(phrase); }) diff --git a/packages/extension-koni-ui/src/Popup/Debugger/DebuggerAPI.tsx b/packages/extension-koni-ui/src/Popup/Debugger/DebuggerAPI.tsx index 5905c22e75..b362c2baa6 100644 --- a/packages/extension-koni-ui/src/Popup/Debugger/DebuggerAPI.tsx +++ b/packages/extension-koni-ui/src/Popup/Debugger/DebuggerAPI.tsx @@ -28,9 +28,9 @@ const API_LIST = [ // 'pri(settings.subscribe)', // 'pri(accounts.tie)', // 'pri(accounts.export)', - // 'pri(accounts.exportPrivateKey)', + // 'pri(accounts.export.privateKey)', // 'pri(accounts.batchExport)', - // 'pri(accounts.checkPublicAndSecretKey)', + // 'pri(accounts.validate.substrate.publicAndPrivateKey)', // 'pri(accounts.validate)', // 'pri(accounts.forget)', // 'pri(authorize.approve)', @@ -77,8 +77,8 @@ const API_LIST = [ // 'pri(metadata.requests)', // 'pri(signing.requests)', // 'pri(seed.validate)', - // 'pri(seed.validateV2)', - // 'pri(privateKey.validateV2)', + // 'pri(accounts.validate.seed)', + // 'pri(accounts.validate.metamask.privateKey)', // 'pri(derivation.validate)', // 'pri(derivation.create)', // 'pri(derivation.createV2)', diff --git a/packages/extension-koni-ui/src/messaging/accounts/create.ts b/packages/extension-koni-ui/src/messaging/accounts/create.ts index 2679fe858e..fa5ee7be58 100644 --- a/packages/extension-koni-ui/src/messaging/accounts/create.ts +++ b/packages/extension-koni-ui/src/messaging/accounts/create.ts @@ -1,29 +1,20 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountExternalError, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateWithSecretKey, ResponseAccountCreateWithSecretKey, ResponseSeedCreateV2 } from '@subwallet/extension-base/background/KoniTypes'; +import { AccountExternalError, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateWithSecretKey, ResponseAccountCreateWithSecretKey } from '@subwallet/extension-base/background/KoniTypes'; import { SeedLengths } from '@subwallet/extension-base/background/types'; -import { RequestAccountCreateSuriV2, ResponseAccountCreateSuriV2 } from '@subwallet/extension-base/types'; +import { RequestAccountCreateSuriV2, ResponseAccountCreateSuriV2, ResponseMnemonicCreateV2 } from '@subwallet/extension-base/types'; import { sendMessage } from '@subwallet/extension-koni-ui/messaging/base'; import { KeypairType } from '@polkadot/util-crypto/types'; // Create seed -export async function createSeed (length?: SeedLengths, seed?: string, type?: KeypairType): Promise<{ address: string; seed: string }> { - return sendMessage('pri(seed.create)', { length, seed, type }); -} - -export async function createSeedV2 (length?: SeedLengths, seed?: string, types?: Array): Promise { +export async function createSeedV2 (length?: SeedLengths, seed?: string, types?: Array): Promise { return sendMessage('pri(seed.createV2)', { length, seed, types }); } /// Suri: seed or private key for evm - -export async function createAccountSuri (name: string, password: string, suri: string, type?: KeypairType, genesisHash?: string): Promise { - return sendMessage('pri(accounts.create.suri)', { genesisHash, name, password, suri, type }); -} - export async function createAccountSuriV2 (request: RequestAccountCreateSuriV2): Promise { return sendMessage('pri(accounts.create.suriV2)', request); } diff --git a/packages/extension-koni-ui/src/messaging/accounts/export.ts b/packages/extension-koni-ui/src/messaging/accounts/export.ts index ea4a13796b..8fec1f1ccf 100644 --- a/packages/extension-koni-ui/src/messaging/accounts/export.ts +++ b/packages/extension-koni-ui/src/messaging/accounts/export.ts @@ -12,9 +12,9 @@ export async function exportAccount (address: string, password: string): Promise } export async function exportAccountPrivateKey (address: string, password: string): Promise { - return sendMessage('pri(accounts.exportPrivateKey)', { address, password }); + return sendMessage('pri(accounts.export.privateKey)', { address, password }); } export async function exportAccountsV2 (request: RequestAccountBatchExportV2): Promise<{ exportedJson: KeyringPairs$Json }> { - return sendMessage('pri(accounts.batchExportV2)', request); + return sendMessage('pri(accounts.export.json.batch)', request); } diff --git a/packages/extension-koni-ui/src/messaging/accounts/validate.ts b/packages/extension-koni-ui/src/messaging/accounts/validate.ts index 5a4458a7a5..c7e63cf408 100644 --- a/packages/extension-koni-ui/src/messaging/accounts/validate.ts +++ b/packages/extension-koni-ui/src/messaging/accounts/validate.ts @@ -1,23 +1,17 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { ResponseCheckPublicAndSecretKey, ResponsePrivateKeyValidateV2, ResponseSeedValidateV2 } from '@subwallet/extension-base/background/KoniTypes'; +import { ResponseCheckPublicAndSecretKey, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2 } from '@subwallet/extension-base/types'; import { sendMessage } from '@subwallet/extension-koni-ui/messaging/base'; -import { KeypairType } from '@polkadot/util-crypto/types'; - export async function checkPublicAndPrivateKey (publicKey: string, secretKey: string): Promise { - return sendMessage('pri(accounts.checkPublicAndSecretKey)', { publicKey, secretKey }); -} - -export async function validateSeed (suri: string, type?: KeypairType): Promise<{ address: string; suri: string }> { - return sendMessage('pri(seed.validate)', { suri, type }); + return sendMessage('pri(accounts.validate.substrate.publicAndPrivateKey)', { publicKey, secretKey }); } -export async function validateSeedV2 (suri: string, types: Array): Promise { - return sendMessage('pri(seed.validateV2)', { suri, types }); +export async function validateSeedV2 (mnemonic: string): Promise { + return sendMessage('pri(accounts.validate.seed)', { mnemonic }); } -export async function validateMetamaskPrivateKeyV2 (suri: string, types: Array): Promise { - return sendMessage('pri(privateKey.validateV2)', { suri, types }); +export async function validateMetamaskPrivateKeyV2 (privateKey: string): Promise { + return sendMessage('pri(accounts.validate.metamask.privateKey)', { privateKey }); } diff --git a/packages/extension-web-ui/src/Popup/Account/NewSeedPhrase.tsx b/packages/extension-web-ui/src/Popup/Account/NewSeedPhrase.tsx index 8311c34c2e..f7e3762e93 100644 --- a/packages/extension-web-ui/src/Popup/Account/NewSeedPhrase.tsx +++ b/packages/extension-web-ui/src/Popup/Account/NewSeedPhrase.tsx @@ -148,7 +148,7 @@ const Component: React.FC = ({ className }: Props) => { useEffect(() => { createSeedV2(undefined, undefined, DEFAULT_ACCOUNT_TYPES) .then((response): void => { - const phrase = response.seed; + const phrase = response.mnemonic; setSeedPhrase(phrase); }) diff --git a/packages/extension-web-ui/src/Popup/Debugger/DebuggerAPI.tsx b/packages/extension-web-ui/src/Popup/Debugger/DebuggerAPI.tsx index 898613c358..bf54467635 100644 --- a/packages/extension-web-ui/src/Popup/Debugger/DebuggerAPI.tsx +++ b/packages/extension-web-ui/src/Popup/Debugger/DebuggerAPI.tsx @@ -29,9 +29,9 @@ const API_LIST = [ // 'pri(settings.subscribe)', // 'pri(accounts.tie)', // 'pri(accounts.export)', - // 'pri(accounts.exportPrivateKey)', + // 'pri(accounts.export.privateKey)', // 'pri(accounts.batchExport)', - // 'pri(accounts.checkPublicAndSecretKey)', + // 'pri(accounts.validate.substrate.publicAndPrivateKey)', // 'pri(accounts.validate)', // 'pri(accounts.forget)', // 'pri(authorize.approve)', @@ -78,8 +78,8 @@ const API_LIST = [ // 'pri(metadata.requests)', // 'pri(signing.requests)', // 'pri(seed.validate)', - // 'pri(seed.validateV2)', - // 'pri(privateKey.validateV2)', + // 'pri(accounts.validate.seed)', + // 'pri(accounts.validate.metamask.privateKey)', // 'pri(derivation.validate)', // 'pri(derivation.create)', // 'pri(derivation.createV2)', diff --git a/packages/extension-web-ui/src/components/Modal/Account/SeedPhraseModal.tsx b/packages/extension-web-ui/src/components/Modal/Account/SeedPhraseModal.tsx index d53f225306..cfca151a39 100644 --- a/packages/extension-web-ui/src/components/Modal/Account/SeedPhraseModal.tsx +++ b/packages/extension-web-ui/src/components/Modal/Account/SeedPhraseModal.tsx @@ -45,7 +45,7 @@ const Component: React.FC = ({ className, modalId, onBack, onSubmitSucces useEffect(() => { createSeedV2(undefined, undefined, [SUBSTRATE_ACCOUNT_TYPE, EVM_ACCOUNT_TYPE]) .then((response): void => { - const phrase = response.seed; + const phrase = response.mnemonic; setSeedPhrase(phrase); }) diff --git a/packages/extension-web-ui/src/messaging/accounts/create.ts b/packages/extension-web-ui/src/messaging/accounts/create.ts index a615043984..597aac94cf 100644 --- a/packages/extension-web-ui/src/messaging/accounts/create.ts +++ b/packages/extension-web-ui/src/messaging/accounts/create.ts @@ -1,29 +1,17 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountExternalError, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateWithSecretKey, ResponseAccountCreateWithSecretKey, ResponseSeedCreateV2 } from '@subwallet/extension-base/background/KoniTypes'; +import { AccountExternalError, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateWithSecretKey, ResponseAccountCreateWithSecretKey } from '@subwallet/extension-base/background/KoniTypes'; import { SeedLengths } from '@subwallet/extension-base/background/types'; -import { RequestAccountCreateSuriV2, ResponseAccountCreateSuriV2 } from '@subwallet/extension-base/types'; +import { MnemonicType, RequestAccountCreateSuriV2, ResponseAccountCreateSuriV2, ResponseMnemonicCreateV2 } from '@subwallet/extension-base/types'; import { sendMessage } from '@subwallet/extension-web-ui/messaging/base'; -import { KeypairType } from '@polkadot/util-crypto/types'; - // Create seed - -export async function createSeed (length?: SeedLengths, seed?: string, type?: KeypairType): Promise<{ address: string; seed: string }> { - return sendMessage('pri(seed.create)', { length, seed, type }); -} - -export async function createSeedV2 (length?: SeedLengths, seed?: string, types?: Array): Promise { - return sendMessage('pri(seed.createV2)', { length, seed, types }); +export async function createSeedV2 (length?: SeedLengths, mnemonic?: string, type?: MnemonicType): Promise { + return sendMessage('pri(seed.createV2)', { length, mnemonic, type }); } /// Suri: seed or private key for evm - -export async function createAccountSuri (name: string, password: string, suri: string, type?: KeypairType, genesisHash?: string): Promise { - return sendMessage('pri(accounts.create.suri)', { genesisHash, name, password, suri, type }); -} - export async function createAccountSuriV2 (request: RequestAccountCreateSuriV2): Promise { return sendMessage('pri(accounts.create.suriV2)', request); } diff --git a/packages/extension-web-ui/src/messaging/accounts/export.ts b/packages/extension-web-ui/src/messaging/accounts/export.ts index 65797a3900..aa1b57ab01 100644 --- a/packages/extension-web-ui/src/messaging/accounts/export.ts +++ b/packages/extension-web-ui/src/messaging/accounts/export.ts @@ -12,7 +12,7 @@ export async function exportAccount (address: string, password: string): Promise } export async function exportAccountPrivateKey (address: string, password: string): Promise { - return sendMessage('pri(accounts.exportPrivateKey)', { address, password }); + return sendMessage('pri(accounts.export.privateKey)', { address, password }); } export async function exportAccounts (addresses: string[], password: string): Promise<{ exportedJson: KeyringPairs$Json }> { diff --git a/packages/extension-web-ui/src/messaging/accounts/validate.ts b/packages/extension-web-ui/src/messaging/accounts/validate.ts index 2469813e30..389f28eeb7 100644 --- a/packages/extension-web-ui/src/messaging/accounts/validate.ts +++ b/packages/extension-web-ui/src/messaging/accounts/validate.ts @@ -1,23 +1,17 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { ResponseCheckPublicAndSecretKey, ResponsePrivateKeyValidateV2, ResponseSeedValidateV2 } from '@subwallet/extension-base/background/KoniTypes'; +import { ResponseCheckPublicAndSecretKey, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2 } from '@subwallet/extension-base/types'; import { sendMessage } from '@subwallet/extension-web-ui/messaging/base'; -import { KeypairType } from '@polkadot/util-crypto/types'; - export async function checkPublicAndPrivateKey (publicKey: string, secretKey: string): Promise { - return sendMessage('pri(accounts.checkPublicAndSecretKey)', { publicKey, secretKey }); -} - -export async function validateSeed (suri: string, type?: KeypairType): Promise<{ address: string; suri: string }> { - return sendMessage('pri(seed.validate)', { suri, type }); + return sendMessage('pri(accounts.validate.substrate.publicAndPrivateKey)', { publicKey, secretKey }); } -export async function validateSeedV2 (suri: string, types: Array): Promise { - return sendMessage('pri(seed.validateV2)', { suri, types }); +export async function validateSeedV2 (mnemonic: string): Promise { + return sendMessage('pri(accounts.validate.seed)', { mnemonic }); } -export async function validateMetamaskPrivateKeyV2 (suri: string, types: Array): Promise { - return sendMessage('pri(privateKey.validateV2)', { suri, types }); +export async function validateMetamaskPrivateKeyV2 (privateKey: string): Promise { + return sendMessage('pri(accounts.validate.metamask.privateKey)', { privateKey }); } diff --git a/yarn.lock b/yarn.lock index 338a976981..0e440a4928 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2156,37 +2156,6 @@ __metadata: languageName: node linkType: hard -"@ethereumjs/rlp@npm:^5.0.2": - version: 5.0.2 - resolution: "@ethereumjs/rlp@npm:5.0.2" - bin: - rlp: bin/rlp.cjs - checksum: b569061ddb1f4cf56a82f7a677c735ba37f9e94e2bbaf567404beb9e2da7aa1f595e72fc12a17c61f7aec67fd5448443efe542967c685a2fe0ffc435793dcbab - languageName: node - linkType: hard - -"@ethereumjs/tx@npm:3.3.2": - version: 3.3.2 - resolution: "@ethereumjs/tx@npm:3.3.2" - dependencies: - "@ethereumjs/common": ^2.5.0 - ethereumjs-util: ^7.1.2 - checksum: e18c871fa223fcb23af1c3dde0ff9c82c91e962556fd531e1c75df63afb3941dd71e3def733d8c442a80224c6dcefb256f169cc286176e6ffb33c19349189c53 - languageName: node - linkType: hard - -"@ethereumjs/tx@npm:^5.0.0": - version: 5.3.0 - resolution: "@ethereumjs/tx@npm:5.3.0" - dependencies: - "@ethereumjs/common": ^4.3.0 - "@ethereumjs/rlp": ^5.0.2 - "@ethereumjs/util": ^9.0.3 - ethereum-cryptography: ^2.1.3 - checksum: 1fa6ef7a5eea7605ca065ab4df5446bdbf17a368267b60cdbb315cfcd78ac82dc689ba020093ae3d42940ad196bfffbfa705fd51f30a277c6eb60b04432db743 - languageName: node - linkType: hard - "@ethereumjs/tx@npm:^5.1.0": version: 5.1.0 resolution: "@ethereumjs/tx@npm:5.1.0" @@ -2219,16 +2188,6 @@ __metadata: languageName: node linkType: hard -"@ethereumjs/util@npm:^9.0.3": - version: 9.0.3 - resolution: "@ethereumjs/util@npm:9.0.3" - dependencies: - "@ethereumjs/rlp": ^5.0.2 - ethereum-cryptography: ^2.1.3 - checksum: 231dae61268c84d514a6c992a770559bb94a21c753c02287d08781cbeae01a6e5b5479af9f0d3d412d532fda6e9b1eeb746e617a68b738907a4a8ee4e24d79a6 - languageName: node - linkType: hard - "@ethersproject/abi@npm:^5.5.0, @ethersproject/abi@npm:^5.6.3, @ethersproject/abi@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/abi@npm:5.7.0" @@ -3761,15 +3720,6 @@ __metadata: languageName: node linkType: hard -"@noble/curves@npm:1.4.2, @noble/curves@npm:~1.4.0": - version: 1.4.2 - resolution: "@noble/curves@npm:1.4.2" - dependencies: - "@noble/hashes": 1.4.0 - checksum: c475a83c4263e2c970eaba728895b9b5d67e0ca880651e9c6e3efdc5f6a4f07ceb5b043bf71c399fc80fada0b8706e69d0772bffdd7b9de2483b988973a34cba - languageName: node - linkType: hard - "@noble/hashes@npm:1.1.2": version: 1.1.2 resolution: "@noble/hashes@npm:1.1.2" @@ -3791,7 +3741,7 @@ __metadata: languageName: node linkType: hard -"@noble/hashes@npm:1.4.0, @noble/hashes@npm:^1.1.5, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:~1.4.0": +"@noble/hashes@npm:^1.1.5, @noble/hashes@npm:^1.3.1": version: 1.4.0 resolution: "@noble/hashes@npm:1.4.0" checksum: 8ba816ae26c90764b8c42493eea383716396096c5f7ba6bea559993194f49d80a73c081f315f4c367e51bd2d5891700bcdfa816b421d24ab45b41cb03e4f3342 @@ -5715,13 +5665,6 @@ __metadata: languageName: node linkType: hard -"@scure/base@npm:~1.1.6": - version: 1.1.7 - resolution: "@scure/base@npm:1.1.7" - checksum: d9084be9a2f27971df1684af9e40bb750e86f549345e1bb3227fb61673c0c83569c92c1cb0a4ddccb32650b39d3cd3c145603b926ba751c9bc60c27317549b20 - languageName: node - linkType: hard - "@scure/bip32@npm:1.3.3": version: 1.3.3 resolution: "@scure/bip32@npm:1.3.3" @@ -5733,17 +5676,6 @@ __metadata: languageName: node linkType: hard -"@scure/bip32@npm:1.4.0": - version: 1.4.0 - resolution: "@scure/bip32@npm:1.4.0" - dependencies: - "@noble/curves": ~1.4.0 - "@noble/hashes": ~1.4.0 - "@scure/base": ~1.1.6 - checksum: eff491651cbf2bea8784936de75af5fc020fc1bbb9bcb26b2cfeefbd1fb2440ebfaf30c0733ca11c0ae1e272a2ef4c3c34ba5c9fb3e1091c3285a4272045b0c6 - languageName: node - linkType: hard - "@scure/bip39@npm:1.2.2": version: 1.2.2 resolution: "@scure/bip39@npm:1.2.2" @@ -5754,16 +5686,6 @@ __metadata: languageName: node linkType: hard -"@scure/bip39@npm:1.3.0": - version: 1.3.0 - resolution: "@scure/bip39@npm:1.3.0" - dependencies: - "@noble/hashes": ~1.4.0 - "@scure/base": ~1.1.6 - checksum: dbb0b27df753eb6c6380010b25cc9a9ea31f9cb08864fc51e69e5880ff7e2b8f85b72caea1f1f28af165e83b72c48dd38617e43fc632779d025b50ba32ea759e - languageName: node - linkType: hard - "@semantic-ui-react/event-stack@npm:^3.1.3": version: 3.1.3 resolution: "@semantic-ui-react/event-stack@npm:3.1.3" @@ -6529,7 +6451,7 @@ __metadata: "@subwallet/keyring@file:../SubWallet-Base/packages/keyring/build/::locator=root-workspace-0b6124%40workspace%3A.": version: 0.1.5 - resolution: "@subwallet/keyring@file:../SubWallet-Base/packages/keyring/build/#../SubWallet-Base/packages/keyring/build/::hash=102d08&locator=root-workspace-0b6124%40workspace%3A." + resolution: "@subwallet/keyring@file:../SubWallet-Base/packages/keyring/build/#../SubWallet-Base/packages/keyring/build/::hash=daaa5f&locator=root-workspace-0b6124%40workspace%3A." dependencies: "@ethereumjs/tx": ^5.0.0 "@polkadot/util": ^12.2.1 @@ -6549,7 +6471,7 @@ __metadata: rxjs: ^7.5.6 tiny-secp256k1: ^2.2.3 tslib: ^2.6.2 - checksum: a4663767a3c5524facdd214905fad26c379900712f3e12f37ac495869019292ed2af2ae6503a3c90a6d7f302882cf9248a61415988e86740cc078a9741a2504a + checksum: 408116ccd35266d235ea4b4637a234e104819f2c349ce28663cd0132b56381d829e60bb205f6c9377013cec15d0c4ac31e894202198e88a43f1c7b326ef83b25 languageName: node linkType: hard @@ -14325,18 +14247,6 @@ __metadata: languageName: node linkType: hard -"ethereum-cryptography@npm:^2.1.3": - version: 2.2.1 - resolution: "ethereum-cryptography@npm:2.2.1" - dependencies: - "@noble/curves": 1.4.2 - "@noble/hashes": 1.4.0 - "@scure/bip32": 1.4.0 - "@scure/bip39": 1.3.0 - checksum: 1466e4c417b315a6ac67f95088b769fafac8902b495aada3c6375d827e5a7882f9e0eea5f5451600d2250283d9198b8a3d4d996e374e07a80a324e29136f25c6 - languageName: node - linkType: hard - "ethereumjs-abi@npm:^0.6.8": version: 0.6.8 resolution: "ethereumjs-abi@npm:0.6.8" From 5a34d2493356fb2211bdfa82c35134936b1f4210 Mon Sep 17 00:00:00 2001 From: lw Date: Tue, 30 Jul 2024 12:36:51 +0700 Subject: [PATCH 016/424] [MasterAccount] Update UI for select account modal --- .../src/Popup/Settings/MissionPool/index.tsx | 7 +- .../AccountProxy/AccountProxyAvatar.tsx | 62 ++++ .../AccountProxy/AccountProxyAvatarGroup.tsx | 130 +++++++ .../AccountProxy/AccountProxyBriefInfo.tsx | 70 ++++ .../AccountProxy/AccountProxyItem.tsx | 107 ++++++ .../AccountProxySelectorAllItem.tsx | 100 ++++++ .../AccountProxy/AccountProxySelectorItem.tsx | 326 +++++++++++++++++ .../src/components/AccountProxy/index.ts | 9 + .../SelectAccount/AccountSelectorModal.tsx | 332 ++++++++++++++++++ .../Layout/parts/SelectAccount/index.tsx | 231 ++---------- .../Modal/ReceiveModal/ReceiveQrModal.tsx | 2 + .../src/components/Search/index.tsx | 5 +- .../extension-koni-ui/src/components/index.ts | 1 + .../src/stores/base/AccountState.ts | 27 +- .../extension-koni-ui/src/stores/types.ts | 5 +- .../src/stores/utils/index.ts | 34 +- 16 files changed, 1218 insertions(+), 230 deletions(-) create mode 100644 packages/extension-koni-ui/src/components/AccountProxy/AccountProxyAvatar.tsx create mode 100644 packages/extension-koni-ui/src/components/AccountProxy/AccountProxyAvatarGroup.tsx create mode 100644 packages/extension-koni-ui/src/components/AccountProxy/AccountProxyBriefInfo.tsx create mode 100644 packages/extension-koni-ui/src/components/AccountProxy/AccountProxyItem.tsx create mode 100644 packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorAllItem.tsx create mode 100644 packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx create mode 100644 packages/extension-koni-ui/src/components/AccountProxy/index.ts create mode 100644 packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx diff --git a/packages/extension-koni-ui/src/Popup/Settings/MissionPool/index.tsx b/packages/extension-koni-ui/src/Popup/Settings/MissionPool/index.tsx index eb13aa5b46..104c356b0d 100644 --- a/packages/extension-koni-ui/src/Popup/Settings/MissionPool/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Settings/MissionPool/index.tsx @@ -270,10 +270,9 @@ const MissionPool = styled(Component)(({ theme: { token } }: Props) => { paddingRight: token.padding }, '.__search-item': { - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - paddingTop: token.paddingXS + paddingTop: token.paddingXS, + paddingLeft: token.padding, + paddingRight: token.padding }, '.__tool-area': { display: 'flex', diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxyAvatar.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxyAvatar.tsx new file mode 100644 index 0000000000..eb80ff580d --- /dev/null +++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxyAvatar.tsx @@ -0,0 +1,62 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { Theme, ThemeProps } from '@subwallet/extension-koni-ui/types'; +import Avatar from 'boring-avatars'; +import CN from 'classnames'; +import React from 'react'; +import styled, { useTheme } from 'styled-components'; + +type Props = ThemeProps & { + value?: string | null, + size?: number +} + +const Component: React.FC = (props: Props) => { + const { className, size = 40, value } = props; + const { logoMap } = useTheme() as Theme; + + return ( +
+ { + value + ? ( + + ) + : ( + logo + ) + } +
+ ); +}; + +const AccountAvatar = styled(Component)(({ theme: { token } }: Props) => { + return { + borderColor: token.colorPrimary, + borderRadius: '100%', + borderStyle: 'solid', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + + svg: { + borderRadius: '100%' + } + }; +}); + +export default AccountAvatar; diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxyAvatarGroup.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxyAvatarGroup.tsx new file mode 100644 index 0000000000..77cb2d554a --- /dev/null +++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxyAvatarGroup.tsx @@ -0,0 +1,130 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { RootState } from '@subwallet/extension-koni-ui/stores'; +import { ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { isAccountAll } from '@subwallet/extension-koni-ui/utils'; +import CN from 'classnames'; +import React, { useMemo } from 'react'; +import { useSelector } from 'react-redux'; +import styled from 'styled-components'; + +import AccountProxyAvatar from './AccountProxyAvatar'; + +export interface BasicAccountProxyInfo { + id: string; + name?: string; +} + +interface Props extends ThemeProps { + accountProxies?: BasicAccountProxyInfo[]; +} + +const sizeAva = { + default: 20, + large: 24 +}; + +const Component: React.FC = ({ accountProxies: _accountProxies, className }: Props) => { + const accountProxies = useSelector((state: RootState) => state.accountState.accountProxies); + const noAllAccountProxy: BasicAccountProxyInfo[] = useMemo((): BasicAccountProxyInfo[] => { + return (_accountProxies || accountProxies).filter((ap) => !isAccountAll(ap.id)); + }, [_accountProxies, accountProxies]); + + const showCount: number = useMemo((): number => { + return noAllAccountProxy.length > 2 ? 3 : 2; + }, [noAllAccountProxy]); + + const countMore: number = useMemo((): number => { + return noAllAccountProxy.length - 3; + }, [noAllAccountProxy]); + + return ( +
+
0 })}> + { + noAllAccountProxy.slice(0, 3).map((ap, index) => { + return ( +
0 + } + )} + key={ap.id} + > + +
+ ); + }) + } + { + countMore > 0 && ( +
+{countMore}
+ ) + } +
+
+ ); +}; + +const AccountProxyAvatarGroup = styled(Component)(({ theme }: Props) => { + const { token } = theme; + + return { + position: 'relative', + width: 'fit-content', + + '.content-container': { + display: 'flex', + flexDirection: 'row', + + '.avatar-content': { + marginLeft: -8 + }, + + '&.ml-strong': { + '.avatar-content': { + marginLeft: -10 + } + } + }, + + '.avatar-content:first-child': { + marginLeft: '0 !important', + opacity: 0.5 + }, + + '.avatar-content:last-child': { + opacity: 1 + }, + + '.avatar-blur': { + svg: { + opacity: 0.5 + } + }, + + '.cont-more': { + fontSize: token.sizeXS, + lineHeight: `${token.size}px`, + position: 'absolute', + width: token.sizeMD, + height: token.sizeMD, + right: 0, + top: 0, + fontWeight: 700, + color: token.colorTextBase, + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center' + } + }; +}); + +export default AccountProxyAvatarGroup; diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxyBriefInfo.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxyBriefInfo.tsx new file mode 100644 index 0000000000..65c1962f83 --- /dev/null +++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxyBriefInfo.tsx @@ -0,0 +1,70 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { AccountProxy } from '@subwallet/extension-base/types'; +import useTranslation from '@subwallet/extension-koni-ui/hooks/common/useTranslation'; +import { ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { isAccountAll } from '@subwallet/extension-koni-ui/utils'; +import { Typography } from '@subwallet/react-ui'; +import React, { useMemo } from 'react'; +import styled from 'styled-components'; + +import AccountProxyAvatar from './AccountProxyAvatar'; +import AccountProxyAvatarGroup from './AccountProxyAvatarGroup'; + +interface Props extends ThemeProps { + accountProxy: AccountProxy; +} + +const Component: React.FC = ({ accountProxy, className }: Props) => { + const { t } = useTranslation(); + const isAll = useMemo((): boolean => isAccountAll(accountProxy.id), [accountProxy.id]); + + return ( +
+ {isAll && } + {!isAll && ( + + )} + + { isAll ? t('All accounts') : accountProxy.name} + +
+ ); +}; + +const AccountProxyBriefInfo = styled(Component)(({ theme: { token } }: Props) => { + return { + display: 'flex', + flexDirection: 'row', + gap: token.sizeXS, + alignItems: 'center', + overflow: 'hidden', + + '&.mr': { + marginRight: -1 + }, + + '.account-name': { + fontWeight: token.headingFontWeight, + fontSize: token.fontSizeHeading5, + lineHeight: token.lineHeightHeading5, + color: token.colorTextBase + }, + + '.account-address': { + fontSize: token.fontSizeHeading6, + lineHeight: token.lineHeightHeading6, + color: token.colorTextDescription, + 'white-space': 'nowrap' + } + }; +}); + +export default AccountProxyBriefInfo; diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxyItem.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxyItem.tsx new file mode 100644 index 0000000000..2042870831 --- /dev/null +++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxyItem.tsx @@ -0,0 +1,107 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { AccountProxy } from '@subwallet/extension-base/types'; +import { Theme } from '@subwallet/extension-koni-ui/themes'; +import { ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { Icon } from '@subwallet/react-ui'; +import CN from 'classnames'; +import { CheckCircle } from 'phosphor-react'; +import React, { Context, useContext } from 'react'; +import styled, { ThemeContext } from 'styled-components'; + +import AccountProxyAvatar from './AccountProxyAvatar'; + +type Props = ThemeProps & { + accountProxy: AccountProxy; + isSelected?: boolean; + showUnselectIcon?: boolean; + renderRightPart?: (checkedIconNode: React.ReactNode) => React.ReactNode; + rightPartNode?: React.ReactNode; + leftPartNode?: React.ReactNode; + onClick?: VoidFunction; + accountProxyName?: string; +}; + +function Component (props: Props): React.ReactElement { + const { accountProxy, accountProxyName, className, isSelected, leftPartNode, onClick, renderRightPart, rightPartNode, showUnselectIcon } = props; + const token = useContext(ThemeContext as Context).token; + + const checkedIconNode = ((showUnselectIcon || isSelected) && ( +
+ +
+ )); + + return ( +
+
+ { + leftPartNode || ( + + ) + } +
+
+ {accountProxyName || accountProxy.name} +
+
+ {rightPartNode || (renderRightPart ? renderRightPart(checkedIconNode) : checkedIconNode)} +
+
+ ); +} + +const AccountProxyItem = styled(Component)(({ theme }) => { + const { token } = theme as Theme; + + return { + background: token.colorBgSecondary, + padding: token.paddingSM, + paddingRight: token.paddingXXS, + borderRadius: token.borderRadiusLG, + alignItems: 'center', + display: 'flex', + cursor: 'pointer', + transition: `background ${token.motionDurationMid} ease-in-out`, + gap: token.sizeSM, + + '.__item-middle-part': { + flex: 1, + textAlign: 'left' + }, + + '.__item-right-part': { + display: 'flex' + }, + + '.__checked-icon-wrapper': { + display: 'flex', + justifyContent: 'center', + minWidth: 40 + }, + + '&:hover': { + background: token.colorBgInput, + '.__item-actions-overlay': { + opacity: 0 + }, + '.-show-on-hover': { + opacity: 1 + } + } + }; +}); + +export default AccountProxyItem; diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorAllItem.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorAllItem.tsx new file mode 100644 index 0000000000..6b1eaf7bf8 --- /dev/null +++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorAllItem.tsx @@ -0,0 +1,100 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { useTranslation } from '@subwallet/extension-koni-ui/hooks'; +import { Theme } from '@subwallet/extension-koni-ui/themes'; +import { ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { Icon } from '@subwallet/react-ui'; +import CN from 'classnames'; +import { CheckCircle } from 'phosphor-react'; +import React, { Context, useContext } from 'react'; +import styled, { ThemeContext } from 'styled-components'; + +import AccountProxyAvatarGroup from './AccountProxyAvatarGroup'; + +type Props = ThemeProps & { + isSelected?: boolean; + onClick?: VoidFunction +}; + +function Component (props: Props): React.ReactElement { + const { className, isSelected, onClick } = props; + const { t } = useTranslation(); + + const token = useContext(ThemeContext as Context).token; + + return ( +
+
+ +
+
+ {t('All accounts')} +
+
+ {isSelected && ( +
+ +
+ )} +
+
+ ); +} + +const AccountProxySelectorAllItem = styled(Component)(({ theme }) => { + const { token } = theme as Theme; + + return { + height: 52, + background: token.colorBgSecondary, + padding: token.paddingSM, + paddingRight: token.paddingXXS, + borderRadius: token.borderRadiusLG, + alignItems: 'center', + display: 'flex', + cursor: 'pointer', + transition: `background ${token.motionDurationMid} ease-in-out`, + gap: token.sizeXS, + + '.__item-left-part': { + + }, + + '.__item-middle-part': { + flex: 1, + fontSize: token.fontSizeLG, + color: token.colorTextLight1, + lineHeight: token.lineHeightLG, + textOverflow: 'ellipsis', + overflow: 'hidden', + 'white-space': 'nowrap' + }, + + '.__checked-icon-wrapper': { + display: 'flex', + justifyContent: 'center', + minWidth: 40 + }, + + '&:hover': { + background: token.colorBgInput, + '.__item-actions-overlay': { + opacity: 0 + }, + '.-show-on-hover': { + opacity: 1 + } + } + }; +}); + +export default AccountProxySelectorAllItem; diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx new file mode 100644 index 0000000000..a7247c975e --- /dev/null +++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx @@ -0,0 +1,326 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { AccountProxy, AccountProxyType } from '@subwallet/extension-base/types'; +import { useTranslation } from '@subwallet/extension-koni-ui/hooks'; +import { Theme } from '@subwallet/extension-koni-ui/themes'; +import { PhosphorIcon, ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { Button, Icon } from '@subwallet/react-ui'; +import CN from 'classnames'; +import { CheckCircle, Copy, Eye, GitCommit, GitMerge, Needle, PencilSimpleLine, QrCode, Question, Strategy, Swatches } from 'phosphor-react'; +import { IconWeight } from 'phosphor-react/src/lib'; +import React, { Context, useContext } from 'react'; +import styled, { ThemeContext } from 'styled-components'; + +import AccountProxyAvatar from './AccountProxyAvatar'; + +type Props = ThemeProps & { + className?: string; + isSelected?: boolean; + accountProxy: AccountProxy; + onClick?: VoidFunction; + onClickCopyButton?: VoidFunction; + onClickDeriveButton?: VoidFunction; + onClickMoreButton?: VoidFunction; + showDeriveButton?: boolean; +} + +// @ts-ignore +type AccountProxyTypeIcon = { + className?: string; + value: PhosphorIcon | React.ReactNode, + weight?: IconWeight +} + +function Component (props: Props): React.ReactElement { + const { accountProxy, + isSelected, + onClick, + onClickCopyButton, + onClickDeriveButton, + onClickMoreButton, showDeriveButton } = props; + + const token = useContext(ThemeContext as Context).token; + + const { t } = useTranslation(); + + const _onClickDeriveButton: React.MouseEventHandler = React.useCallback((event) => { + event.stopPropagation(); + onClickDeriveButton?.(); + }, [onClickDeriveButton]); + + const _onClickCopyButton: React.MouseEventHandler = React.useCallback((event) => { + event.stopPropagation(); + onClickCopyButton?.(); + }, [onClickCopyButton]); + + const _onClickMoreButton: React.MouseEventHandler = React.useCallback((event) => { + event.stopPropagation(); + onClickMoreButton?.(); + }, [onClickMoreButton]); + + const accountProxyTypeIconProps = (() => { + if (accountProxy.accountType === AccountProxyType.MULTI) { + return { + className: '-is-multi', + value: Strategy, + weight: 'fill' + }; + } + + if (accountProxy.accountType === AccountProxyType.SINGLE) { + return { + className: '-is-single', + value: GitCommit, + weight: 'fill' + }; + } + + if (accountProxy.accountType === AccountProxyType.QR) { + return { + value: QrCode, + weight: 'fill' + }; + } + + if (accountProxy.accountType === AccountProxyType.READ_ONLY) { + return { + value: Eye, + weight: 'fill' + }; + } + + if (accountProxy.accountType === AccountProxyType.LEDGER) { + return { + value: Swatches, + weight: 'fill' + }; + } + + if (accountProxy.accountType === AccountProxyType.INJECTED) { + return { + value: Needle, + weight: 'fill' + }; + } + + if (accountProxy.accountType === AccountProxyType.UNKNOWN) { + return { + value: Question, + weight: 'fill' + }; + } + + return null; + })(); + + return ( + <> +
+
+
+ + + { + !!accountProxyTypeIconProps && ( +
+ +
+ ) + } +
+
+
+
{accountProxy.name}
+
{accountProxy.name}
+
+
+
+ { + showDeriveButton && ( +
+
+ {isSelected && ( +
+
+
+ + ); +} + +const AccountProxySelectorItem = styled(Component)(({ theme }) => { + const { token } = theme as Theme; + + return { + background: token.colorBgSecondary, + paddingLeft: token.paddingSM, + paddingRight: token.paddingXXS, + paddingTop: token.paddingXS, + paddingBottom: token.paddingXS, + borderRadius: token.borderRadiusLG, + alignItems: 'center', + display: 'flex', + flexDirection: 'row', + cursor: 'pointer', + transition: `background ${token.motionDurationMid} ease-in-out`, + + '.__item-left-part': { + paddingRight: token.paddingSM + }, + '.__item-avatar-wrapper': { + position: 'relative' + }, + '.__item-avatar-icon': { + color: token.colorWhite, + width: 16, + height: 16, + position: 'absolute', + right: 0, + bottom: 0, + backgroundColor: 'rgba(0, 0, 0, 0.65)', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + borderRadius: '100%', + + '&.-is-multi': { + color: token.colorSuccess + }, + + '&.-is-single': { + color: token['blue-9'] + }, + + '&.-is-derived': { + color: token.colorWarning + } + }, + '.__item-center-part': { + display: 'flex', + flexDirection: 'column', + overflow: 'hidden', + flex: 1 + }, + '.__item-name': { + fontSize: token.fontSize, + color: token.colorTextLight1, + lineHeight: token.lineHeight, + textOverflow: 'ellipsis', + overflow: 'hidden', + 'white-space': 'nowrap' + }, + '.__item-networks': { + fontSize: token.fontSizeSM, + color: token.colorTextLight4, + lineHeight: '18px' + }, + '.__item-address': { + fontSize: token.fontSizeSM, + color: token.colorTextLight4, + lineHeight: token.lineHeightSM, + textOverflow: 'ellipsis', + overflow: 'hidden', + 'white-space': 'nowrap' + }, + '.__item-right-part': { + marginLeft: 'auto', + display: 'flex', + alignItems: 'center', + justifyContent: 'flex-end', + minWidth: 120, + position: 'relative' + }, + '.__item-actions-overlay': { + display: 'flex', + flexDirection: 'row', + pointerEvents: 'none', + position: 'absolute', + inset: 0, + opacity: 1, + alignItems: 'center', + justifyContent: 'flex-end', + marginRight: 40, + transition: `opacity ${token.motionDurationMid} ease-in-out` + }, + '.-show-on-hover': { + opacity: 0, + transition: `opacity ${token.motionDurationMid} ease-in-out` + }, + '&:hover': { + background: token.colorBgInput, + '.__item-actions-overlay': { + opacity: 0 + }, + '.-show-on-hover': { + opacity: 1 + } + } + }; +}); + +export default AccountProxySelectorItem; diff --git a/packages/extension-koni-ui/src/components/AccountProxy/index.ts b/packages/extension-koni-ui/src/components/AccountProxy/index.ts new file mode 100644 index 0000000000..3c9311b72a --- /dev/null +++ b/packages/extension-koni-ui/src/components/AccountProxy/index.ts @@ -0,0 +1,9 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export { default as AccountProxySelectorItem } from './AccountProxySelectorItem'; +export { default as AccountProxyBriefInfo } from './AccountProxyBriefInfo'; +export { default as AccountProxySelectorAllItem } from './AccountProxySelectorAllItem'; +export { default as AccountProxyItem } from './AccountProxyItem'; +export { default as AccountProxyAvatar } from './AccountProxyAvatar'; +export { default as AccountProxyAvatarGroup } from './AccountProxyAvatarGroup'; diff --git a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx new file mode 100644 index 0000000000..c477f8944a --- /dev/null +++ b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx @@ -0,0 +1,332 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import type { ButtonProps } from '@subwallet/react-ui/es/button/button'; + +import { CurrentAccountInfo } from '@subwallet/extension-base/background/types'; +import { AccountProxy, AccountProxyType } from '@subwallet/extension-base/types'; +import { AccountProxySelectorAllItem, AccountProxySelectorItem, GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; +import SelectAccountFooter from '@subwallet/extension-koni-ui/components/Layout/parts/SelectAccount/Footer'; +import Search from '@subwallet/extension-koni-ui/components/Search'; +import { SELECT_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants/modal'; +import { useDefaultNavigate, useSetSessionLatest } from '@subwallet/extension-koni-ui/hooks'; +import useTranslation from '@subwallet/extension-koni-ui/hooks/common/useTranslation'; +import { saveCurrentAccountAddress } from '@subwallet/extension-koni-ui/messaging'; +import { RootState } from '@subwallet/extension-koni-ui/stores'; +import { Theme } from '@subwallet/extension-koni-ui/themes'; +import { ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { isAccountAll } from '@subwallet/extension-koni-ui/utils'; +import { Icon, ModalContext, SwList, SwModal, Tooltip } from '@subwallet/react-ui'; +import CN from 'classnames'; +import { Circle, Export } from 'phosphor-react'; +import React, { useCallback, useContext, useMemo, useState } from 'react'; +import { useSelector } from 'react-redux'; +import { useLocation, useNavigate } from 'react-router-dom'; +import styled, { useTheme } from 'styled-components'; + +type ListItemGroupLabel = { + id: string; + groupLabel: string; +} + +type ListItem = AccountProxy | ListItemGroupLabel; + +type Props = ThemeProps + +const renderEmpty = () => ; + +const modalId = SELECT_ACCOUNT_MODAL; + +const Component: React.FC = ({ className }: Props) => { + const location = useLocation(); + const { t } = useTranslation(); + const { inactiveModal } = useContext(ModalContext); + const [searchValue, setSearchValue] = useState(''); + const { token } = useTheme() as Theme; + const { goHome } = useDefaultNavigate(); + const navigate = useNavigate(); + const { setStateSelectAccount } = useSetSessionLatest(); + + const accountProxies = useSelector((state: RootState) => state.accountState.accountProxies); + const currentAccountProxy = useSelector((state: RootState) => state.accountState.currentAccountProxy); + + const listItems = useMemo(() => { + let accountAll: AccountProxy | undefined; + const result: ListItem[] = []; + const masterAccounts: ListItem[] = []; + const qrSignerAccounts: ListItem[] = []; + const watchOnlyAccounts: ListItem[] = []; + const ledgerAccounts: ListItem[] = []; + const injectedAccounts: ListItem[] = []; + const unknownAccounts: ListItem[] = []; + + accountProxies.forEach((ap) => { + if (searchValue) { + if (!ap.name.toLowerCase().includes(searchValue.toLowerCase())) { + return; + } + } else if (isAccountAll(ap.id) || ap.accountType === AccountProxyType.ALL_ACCOUNT) { + accountAll = ap; + + return; + } + + if (ap.accountType === AccountProxyType.SINGLE || ap.accountType === AccountProxyType.MULTI) { + masterAccounts.push(ap); + } else if (ap.accountType === AccountProxyType.QR) { + qrSignerAccounts.push(ap); + } else if (ap.accountType === AccountProxyType.READ_ONLY) { + watchOnlyAccounts.push(ap); + } else if (ap.accountType === AccountProxyType.LEDGER) { + ledgerAccounts.push(ap); + } else if (ap.accountType === AccountProxyType.INJECTED) { + injectedAccounts.push(ap); + } else if (ap.accountType === AccountProxyType.UNKNOWN) { + unknownAccounts.push(ap); + } + }); + + if (masterAccounts.length) { + result.push(...masterAccounts); + } + + if (qrSignerAccounts.length) { + qrSignerAccounts.unshift({ + id: 'qr', + groupLabel: t('QR signer account') + }); + + result.push(...qrSignerAccounts); + } + + if (watchOnlyAccounts.length) { + watchOnlyAccounts.unshift({ + id: 'watch-only', + groupLabel: t('Watch-only account') + }); + + result.push(...watchOnlyAccounts); + } + + if (ledgerAccounts.length) { + ledgerAccounts.unshift({ + id: 'ledger', + groupLabel: t('Ledger account') + }); + + result.push(...ledgerAccounts); + } + + if (injectedAccounts.length) { + injectedAccounts.unshift({ + id: 'injected', + groupLabel: t('Injected account') + }); + + result.push(...ledgerAccounts); + } + + if (unknownAccounts.length) { + unknownAccounts.unshift({ + id: 'unknown', + groupLabel: t('Unknown account') + }); + + result.push(...unknownAccounts); + } + + if (result.length && accountAll) { + result.unshift(accountAll); + } + + return result; + }, [accountProxies, searchValue, t]); + + const hasSearchValue = !!searchValue; + + const showAllAccount = useMemo(() => { + return !hasSearchValue && accountProxies.filter(({ id }) => !isAccountAll(id)).length > 1; + }, [hasSearchValue, accountProxies]); + + const onSelect = useCallback((accountProxy: AccountProxy) => { + return () => { + const targetAccountProxy = accountProxies.find((ap) => ap.id === accountProxy.id); + + if (targetAccountProxy) { + const accountInfo = { + address: targetAccountProxy.id + } as CurrentAccountInfo; + + saveCurrentAccountAddress(accountInfo).then(() => { + const pathName = location.pathname; + const locationPaths = location.pathname.split('/'); + + if (locationPaths) { + if (locationPaths[1] === 'home') { + if (locationPaths.length >= 3) { + if (pathName.startsWith('/home/nfts')) { + navigate('/home/nfts/collections'); + } else if (pathName.startsWith('/home/tokens/detail')) { + navigate('/home/tokens'); + } else { + navigate(`/home/${locationPaths[2]}`); + } + } + } else { + goHome(); + } + } + }).catch((e) => { + console.error('Failed to switch account', e); + }); + } else { + console.error('Failed to switch account'); + } + + inactiveModal(modalId); + }; + }, [accountProxies, inactiveModal, location.pathname, navigate, goHome]); + + const renderItem = useCallback((item: ListItem): React.ReactNode => { + if ((item as ListItemGroupLabel).groupLabel) { + return ( +
+ {(item as ListItemGroupLabel).groupLabel} +
+ ); + } + + const currentAccountIsAll = isAccountAll(item.id); + + if (currentAccountIsAll) { + if (showAllAccount) { + return ( + + ); + } else { + return null; + } + } + + return ( + + ); + }, [onSelect, currentAccountProxy?.id, showAllAccount]); + + const handleSearch = useCallback((value: string) => { + setSearchValue(value); + }, []); + + const _onCancel = useCallback(() => { + inactiveModal(modalId); + setSearchValue(''); + setStateSelectAccount(true); + }, [inactiveModal, setStateSelectAccount]); + + const rightIconProps = useMemo((): ButtonProps => { + return ({ + icon: ( + + ), + children: ( + +
+ +
+
+ ), + size: 'xs', + type: 'ghost', + tooltipPlacement: 'topLeft' + }); + }, [t, token.colorHighlight]); + + return ( + } + id={modalId} + onCancel={_onCancel} + rightIconProps={rightIconProps} + title={t('Select account')} + > + ('Account name')} + searchValue={searchValue} + /> + + + ); +}; + +export const AccountSelectorModal = styled(Component)(({ theme: { token } }: Props) => { + return { + '.ant-sw-modal-content': { + height: '100vh' + }, + + '.ant-sw-modal-body': { + overflow: 'auto', + display: 'flex', + flex: 1, + flexDirection: 'column' + }, + + '.list-item-group-label': { + textTransform: 'uppercase', + fontSize: 11, + lineHeight: '18px', + fontWeight: token.headingFontWeight, + color: token.colorTextLight3 + }, + + '.__search-box': { + marginBottom: token.marginXS + }, + + '.__list-container': { + flex: 1, + overflow: 'auto', + + '> div + div': { + marginTop: token.marginXS + } + } + }; +}); diff --git a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/index.tsx b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/index.tsx index 867ef67c79..f544e9b7df 100644 --- a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/index.tsx +++ b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/index.tsx @@ -1,31 +1,25 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { CurrentAccountInfo } from '@subwallet/extension-base/background/types'; import { AccountJson } from '@subwallet/extension-base/types'; -import ExportAllSelector from '@subwallet/extension-koni-ui/components/Layout/parts/SelectAccount/ExportAllSelector'; -import { SimpleQrModal } from '@subwallet/extension-koni-ui/components/Modal'; -import { DISCONNECT_EXTENSION_MODAL, SELECT_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants'; -import { useDefaultNavigate, useGetCurrentAuth, useGetCurrentTab, useGoBackSelectAccount, useIsPopup, useSetSessionLatest, useTranslation } from '@subwallet/extension-koni-ui/hooks'; -import { saveCurrentAccountAddress } from '@subwallet/extension-koni-ui/messaging'; +import { AccountProxyBriefInfo } from '@subwallet/extension-koni-ui/components'; +import { AccountSelectorModal } from '@subwallet/extension-koni-ui/components/Layout/parts/SelectAccount/AccountSelectorModal'; +import { SELECT_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants'; +import { useGetCurrentAuth, useGetCurrentTab, useIsPopup, useTranslation } from '@subwallet/extension-koni-ui/hooks'; import { RootState } from '@subwallet/extension-koni-ui/stores'; import { Theme } from '@subwallet/extension-koni-ui/themes'; import { ThemeProps } from '@subwallet/extension-koni-ui/types'; -import { findAccountByAddress, funcSortByName, isAccountAll, searchAccountFunction } from '@subwallet/extension-koni-ui/utils'; -import { BackgroundIcon, ButtonProps, Icon, ModalContext, SelectModal, Tooltip } from '@subwallet/react-ui'; +import { funcSortByName, isAccountAll } from '@subwallet/extension-koni-ui/utils'; +import { BackgroundIcon, ModalContext, Tooltip } from '@subwallet/react-ui'; import CN from 'classnames'; -import { Circle, Export, Plug, Plugs, PlugsConnected } from 'phosphor-react'; +import { Plug, Plugs, PlugsConnected } from 'phosphor-react'; import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'; import { useSelector } from 'react-redux'; -import { useLocation, useNavigate } from 'react-router-dom'; -import styled, { useTheme } from 'styled-components'; +import styled from 'styled-components'; import { isEthereumAddress } from '@polkadot/util-crypto'; -import { AccountBriefInfo, AccountCardItem, AccountItemWithName } from '../../../Account'; -import { GeneralEmptyList } from '../../../EmptyList'; import { ConnectWebsiteModal } from '../ConnectWebsiteModal'; -import SelectAccountFooter from '../SelectAccount/Footer'; interface Props extends ThemeProps { id?: string @@ -49,21 +43,13 @@ const iconMap = { const ConnectWebsiteId = 'connectWebsiteId'; -const renderEmpty = () => ; - const modalId = SELECT_ACCOUNT_MODAL; -const simpleQrModalId = 'simple-qr-modal-id'; -const multiExportAccountModalId = 'multi-export-account-selector'; -function Component ({ className, id }: Props): React.ReactElement { +function Component ({ className }: Props): React.ReactElement { const { t } = useTranslation(); const { activeModal, inactiveModal } = useContext(ModalContext); - const navigate = useNavigate(); - const location = useLocation(); - const { goHome } = useDefaultNavigate(); - const { setStateSelectAccount } = useSetSessionLatest(); - const { accounts: _accounts, currentAccount, isAllAccount } = useSelector((state: RootState) => state.accountState); + const { accounts: _accounts, currentAccount, currentAccountProxy, isAllAccount } = useSelector((state: RootState) => state.accountState); const [connected, setConnected] = useState(0); const [canConnect, setCanConnect] = useState(0); @@ -72,8 +58,6 @@ function Component ({ className, id }: Props): React.ReactElement { const isCurrentTabFetched = !!currentTab; const currentAuth = useGetCurrentAuth(); const isPopup = useIsPopup(); - const { token } = useTheme() as Theme; - const [selectedQrAddress, setSelectedQrAddress] = useState(); const accounts = useMemo((): AccountJson[] => { const result = [..._accounts].sort(funcSortByName); @@ -106,110 +90,6 @@ function Component ({ className, id }: Props): React.ReactElement { return accounts.filter(({ address }) => !isAccountAll(address)); }, [accounts]); - const showAllAccount = useMemo(() => { - return noAllAccounts.length > 1; - }, [noAllAccounts]); - - const _onSelect = useCallback((address: string) => { - if (address) { - const accountByAddress = findAccountByAddress(accounts, address); - - if (accountByAddress) { - const accountInfo = { - address: address - } as CurrentAccountInfo; - - saveCurrentAccountAddress(accountInfo).then(() => { - const pathName = location.pathname; - const locationPaths = location.pathname.split('/'); - - if (locationPaths) { - if (locationPaths[1] === 'home') { - if (locationPaths.length >= 3) { - if (pathName.startsWith('/home/nfts')) { - navigate('/home/nfts/collections'); - } else if (pathName.startsWith('/home/tokens/detail')) { - navigate('/home/tokens'); - } else { - navigate(`/home/${locationPaths[2]}`); - } - } - } else { - goHome(); - } - } - }).catch((e) => { - console.error('Failed to switch account', e); - }); - } else { - console.error('Failed to switch account'); - } - } - }, [accounts, location.pathname, navigate, goHome]); - - const onClickDetailAccount = useCallback((address: string) => { - return () => { - inactiveModal(modalId); - setTimeout(() => { - navigate(`/accounts/detail/${address}`); - }, 100); - }; - }, [inactiveModal, navigate]); - - const openDisconnectExtensionModal = useCallback(() => { - activeModal(DISCONNECT_EXTENSION_MODAL); - }, [activeModal]); - - const onClickItemQrButton = useCallback((address: string) => { - setSelectedQrAddress(address); - activeModal(simpleQrModalId); - }, [activeModal]); - - const onQrModalBack = useGoBackSelectAccount(simpleQrModalId); - - const renderItem = useCallback((item: AccountJson, _selected: boolean): React.ReactNode => { - const currentAccountIsAll = isAccountAll(item.address); - - if (currentAccountIsAll) { - if (showAllAccount) { - return ( - - ); - } else { - return null; - } - } - - const isInjected = !!item.isInjected; - - return ( - - ); - }, [className, onClickDetailAccount, openDisconnectExtensionModal, onClickItemQrButton, showAllAccount]); - - const renderSelectedItem = useCallback((item: AccountJson): React.ReactNode => { - return ( -
- -
- ); - }, []); - useEffect(() => { if (currentAuth) { if (!currentAuth.isAllowed) { @@ -310,48 +190,24 @@ function Component ({ className, id }: Props): React.ReactElement { inactiveModal(ConnectWebsiteId); }, [inactiveModal]); - const exportAllAccounts = useCallback(() => { - activeModal(multiExportAccountModalId); + const onOpenSelectAccountModal = useCallback(() => { + activeModal(modalId); }, [activeModal]); - const onCloseSelectAccountModal = useCallback(() => { - inactiveModal(modalId); - setStateSelectAccount(true); - }, [inactiveModal, setStateSelectAccount]); - - const rightButton = useMemo((): ButtonProps => { - return ({ - icon: ( - - ), - children: ( - -
- -
-
- ), - onClick: exportAllAccounts, - size: 'xs', - type: 'ghost', - tooltipPlacement: 'topLeft' - }); - }, [exportAllAccounts, t, token.colorHighlight]); + const selectedAccountNode = (() => { + if (!currentAccountProxy) { + return null; + } + + return ( +
+ +
+ ); + })(); return (
@@ -376,29 +232,9 @@ function Component ({ className, id }: Props): React.ReactElement { )} - } - id={modalId} - ignoreScrollbarMethod='padding' - inputWidth={'100%'} - itemKey='address' - items={accounts} - onCancel={onCloseSelectAccountModal} - onSelect={_onSelect} - renderItem={renderItem} - renderSelected={renderSelectedItem} - renderWhenEmpty={renderEmpty} - rightIconProps={rightButton} - searchFunction={searchAccountFunction} - searchMinCharactersCount={2} - searchPlaceholder={t('Account name')} - selected={currentAccount?.address || ''} - shape='round' - size='small' - title={t('Select account')} - /> + {selectedAccountNode} + + { onCancel={onCloseConnectWebsiteModal} url={currentTab?.url || ''} /> - - -
); } diff --git a/packages/extension-koni-ui/src/components/Modal/ReceiveModal/ReceiveQrModal.tsx b/packages/extension-koni-ui/src/components/Modal/ReceiveModal/ReceiveQrModal.tsx index 56a158b5c6..1933d29eff 100644 --- a/packages/extension-koni-ui/src/components/Modal/ReceiveModal/ReceiveQrModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/ReceiveModal/ReceiveQrModal.tsx @@ -25,6 +25,8 @@ interface Props extends ThemeProps { const modalId = RECEIVE_QR_MODAL; +// todo: merge with simple QR modal + const Component: React.FC = ({ address, className, selectedNetwork }: Props) => { const { t } = useTranslation(); const { inactiveModal } = useContext(ModalContext); diff --git a/packages/extension-koni-ui/src/components/Search/index.tsx b/packages/extension-koni-ui/src/components/Search/index.tsx index 3798c00538..9107899211 100644 --- a/packages/extension-koni-ui/src/components/Search/index.tsx +++ b/packages/extension-koni-ui/src/components/Search/index.tsx @@ -60,10 +60,7 @@ const Component: React.FC = ({ actionBtnIcon, const Search = styled(Component)(({ theme: { token } }: Props) => { return { - '.__search-input': { - width: 360, - height: 48 - } + }; }); diff --git a/packages/extension-koni-ui/src/components/index.ts b/packages/extension-koni-ui/src/components/index.ts index 4e7be502b6..3ea854c13c 100644 --- a/packages/extension-koni-ui/src/components/index.ts +++ b/packages/extension-koni-ui/src/components/index.ts @@ -17,6 +17,7 @@ export { default as NetworkTag } from './NetworkTag'; export * from '../contexts'; export * from './Common'; export * from './Account'; +export * from './AccountProxy'; export * from './Avatar'; export * from './Confirmation'; export * from './EmptyList'; diff --git a/packages/extension-koni-ui/src/stores/base/AccountState.ts b/packages/extension-koni-ui/src/stores/base/AccountState.ts index f27a2397ea..42f826dbdb 100644 --- a/packages/extension-koni-ui/src/stores/base/AccountState.ts +++ b/packages/extension-koni-ui/src/stores/base/AccountState.ts @@ -4,7 +4,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { AddressBookInfo, KeyringState } from '@subwallet/extension-base/background/KoniTypes'; import { AccountsContext } from '@subwallet/extension-base/background/types'; -import { AccountJson } from '@subwallet/extension-base/types'; +import { AccountJson, AccountProxy } from '@subwallet/extension-base/types'; import { AccountState, ReduxStatus } from '@subwallet/extension-koni-ui/stores/types'; import { isAccountAll } from '@subwallet/extension-koni-ui/utils'; @@ -13,6 +13,9 @@ const initialState: AccountState = { currentAccount: null, isAllAccount: false, + currentAccountProxy: null, + accountProxies: [], + // KeyringState isReady: false, hasMasterPassword: false, @@ -41,6 +44,7 @@ const accountStateSlice = createSlice({ reduxStatus: ReduxStatus.READY }; }, + // deprecated updateAccountsContext (state, action: PayloadAction) { const payload = action.payload; @@ -50,6 +54,7 @@ const accountStateSlice = createSlice({ reduxStatus: ReduxStatus.READY }; }, + // deprecated updateCurrentAccount (state, action: PayloadAction) { const payload = action.payload; @@ -60,6 +65,26 @@ const accountStateSlice = createSlice({ reduxStatus: ReduxStatus.READY }; }, + updateCurrentAccountProxy (state, action: PayloadAction) { + const payload = action.payload; + + return { + ...state, + currentAccountProxy: payload, + isAllAccount: isAccountAll(payload?.id), + reduxStatus: ReduxStatus.READY + }; + }, + updateAccountProxies (state, action: PayloadAction) { + const payload = action.payload; + + return { + ...state, + accounts: payload.reduce((accounts, ap) => [...accounts, ...ap.accounts], [] as AccountJson[]), + accountProxies: payload, + reduxStatus: ReduxStatus.READY + }; + }, updateAddressBook (state, action: PayloadAction) { const { addresses } = action.payload; diff --git a/packages/extension-koni-ui/src/stores/types.ts b/packages/extension-koni-ui/src/stores/types.ts index feb36322d7..d51a33b222 100644 --- a/packages/extension-koni-ui/src/stores/types.ts +++ b/packages/extension-koni-ui/src/stores/types.ts @@ -8,7 +8,7 @@ import { AccountsContext, AuthorizeRequest, MetadataRequest, SigningRequest } fr import { _ChainApiStatus, _ChainState } from '@subwallet/extension-base/services/chain-service/types'; import { SWTransactionResult } from '@subwallet/extension-base/services/transaction-service/types'; import { WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; -import { AccountJson, BalanceMap, BuyServiceInfo, BuyTokenInfo, EarningRewardHistoryItem, EarningRewardItem, NominationPoolInfo, YieldPoolInfo, YieldPoolTarget, YieldPositionInfo } from '@subwallet/extension-base/types'; +import { AccountJson, AccountProxy, BalanceMap, BuyServiceInfo, BuyTokenInfo, EarningRewardHistoryItem, EarningRewardItem, NominationPoolInfo, YieldPoolInfo, YieldPoolTarget, YieldPositionInfo } from '@subwallet/extension-base/types'; import { SwapPair } from '@subwallet/extension-base/types/swap'; import { MissionInfo } from '@subwallet/extension-koni-ui/types'; import { SessionTypes } from '@walletconnect/types'; @@ -91,7 +91,8 @@ export interface AppSettings extends LocalUiSettings, UiSettings, Omit { + store.dispatch({ type: 'accountState/updateCurrentAccountProxy', payload: accountProxy }); +}; + +export const updateAccountProxies = (data: AccountProxy[]) => { + store.dispatch({ type: 'accountState/updateAccountProxies', payload: data }); +}; + export const updateAccountData = (data: AccountsWithCurrentAddress) => { - let currentAccountJson: AccountJson = data.accounts[0]; - const accounts = data.accounts; + let currentAccountProxy: AccountProxy = data.accounts[0]; + const accountProxies = data.accounts; - accounts.forEach((accountJson) => { - if (accountJson.address === data.currentAccountProxy) { - currentAccountJson = accountJson; + accountProxies.forEach((ap) => { + if (ap.id === data.currentAccountProxy) { + currentAccountProxy = ap; } }); - const hierarchy = buildHierarchy(accounts); - const master = hierarchy.find(({ isExternal, type }) => !isExternal && canDerive(type)); - - updateCurrentAccountState(currentAccountJson); - updateAccountsContext({ - accounts, - hierarchy, - master - } as AccountsContext); + updateCurrentAccountProxy(currentAccountProxy); + updateAccountProxies(accountProxies); }; export const updateMissionPoolStore = (missions: MissionInfo[]) => { From db3fc52dcc27c4f867862979300d8ebe02fa52c0 Mon Sep 17 00:00:00 2001 From: S2kael Date: Tue, 30 Jul 2024 17:07:57 +0700 Subject: [PATCH 017/424] [Issue-3396] Add network info to account --- .../src/types/account/info/keyring.ts | 9 +++++++++ .../src/types/account/info/proxy.ts | 11 ++++++++--- .../src/utils/account/transform.ts | 16 +++++++++++++--- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/packages/extension-base/src/types/account/info/keyring.ts b/packages/extension-base/src/types/account/info/keyring.ts index ef427cb463..57dfa0436a 100644 --- a/packages/extension-base/src/types/account/info/keyring.ts +++ b/packages/extension-base/src/types/account/info/keyring.ts @@ -110,14 +110,23 @@ export enum AccountSignMode { UNKNOWN = 'unknown' } +export enum AccountNetworkType { + SUBSTRATE = 'substrate', + ETHEREUM = 'ethereum', + BITCOIN = 'bitcoin', + TON = 'ton' +} + /** * Represents the actions associated with an account. * @interface AccountActionData + * @prop {AccountNetworkType} networkType - The network type will account used on * @prop {string[]} accountActions - A list of account-specific actions. These could be actions like 'derive', 'export', etc., that are applicable to the account. * @prop {ExtrinsicType[]} transactionActions - A list of transaction types that the account can initiate. This is dependent on the blockchain's supported extrinsic types, such as 'transfer', 'bond', etc. * @prop {AccountSignMode} signMode - Account sign mode */ export interface AccountActionData { + networkType: AccountNetworkType; accountActions: string[]; transactionActions: ExtrinsicType[]; signMode: AccountSignMode; diff --git a/packages/extension-base/src/types/account/info/proxy.ts b/packages/extension-base/src/types/account/info/proxy.ts index b5ab797ea6..dc2e1067d6 100644 --- a/packages/extension-base/src/types/account/info/proxy.ts +++ b/packages/extension-base/src/types/account/info/proxy.ts @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-base authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountJson } from './keyring'; +import { AccountJson, AccountNetworkType } from './keyring'; /** * Represents the basic data structure for an account proxy. @@ -30,8 +30,8 @@ export type AccountProxyStoreData = Record; export enum AccountProxyType { ALL_ACCOUNT = 'all', - SINGLE = 'single-chain', - MULTI = 'multi-chain', + SOLO = 'solo', + UNIFIED = 'unified', QR = 'qr', LEDGER = 'ledger', READ_ONLY = 'readonly', @@ -42,11 +42,16 @@ export enum AccountProxyType { /** * @interface AccountProxy * @extends AccountProxyData - Inherits properties from AccountProxyData. + * @description Represents an account proxy, which includes additional details and associated accounts. + * * @prop {AccountJson[]} accounts - An array of `AccountJson` objects representing the accounts associated with this proxy. + * @prop {AccountProxyType} accountType - The type of the account proxy. + * @prop {AccountNetworkType[]} networkTypes - An array of network types associated with this proxy. */ export interface AccountProxy extends AccountProxyData { accounts: AccountJson[]; accountType: AccountProxyType; + networkTypes: AccountNetworkType[]; } export type AccountProxyMap = Record diff --git a/packages/extension-base/src/utils/account/transform.ts b/packages/extension-base/src/utils/account/transform.ts index 0e39f028ab..8a9b875db6 100644 --- a/packages/extension-base/src/utils/account/transform.ts +++ b/packages/extension-base/src/utils/account/transform.ts @@ -3,8 +3,8 @@ import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; -import { AccountJson, AccountMetadataData, AccountSignMode } from '@subwallet/extension-base/types'; -import { KeypairType, KeyringPair, KeyringPair$Meta } from '@subwallet/keyring/types'; +import { AccountJson, AccountMetadataData, AccountNetworkType, AccountSignMode } from '@subwallet/extension-base/types'; +import { BitcoinKeypairTypes, EthereumKeypairTypes, KeypairType, KeyringPair, KeyringPair$Meta, TonKeypairTypes } from '@subwallet/keyring/types'; import { SingleAddress, SubjectInfo } from '@subwallet/ui-keyring/observable/types'; export const getAccountSignMode = (address: string, _meta?: KeyringPair$Meta): AccountSignMode => { @@ -43,6 +43,15 @@ export const transformAccount = (address: string, type?: KeypairType, meta?: Key const accountActions: string[] = []; const transactionActions: ExtrinsicType[] = []; const signMode = getAccountSignMode(address, meta); + const networkType: AccountNetworkType = type + ? EthereumKeypairTypes.includes(type) + ? AccountNetworkType.ETHEREUM + : TonKeypairTypes.includes(type) + ? AccountNetworkType.TON + : BitcoinKeypairTypes.includes(type) + ? AccountNetworkType.BITCOIN + : AccountNetworkType.SUBSTRATE + : AccountNetworkType.SUBSTRATE; return { address, @@ -50,7 +59,8 @@ export const transformAccount = (address: string, type?: KeypairType, meta?: Key type, accountActions, transactionActions, - signMode + signMode, + networkType }; }; From 8804dc902db50ce904982477641778a79999d86c Mon Sep 17 00:00:00 2001 From: lw Date: Tue, 30 Jul 2024 19:18:56 +0700 Subject: [PATCH 018/424] [MasterAccount] Update code related to account type change --- .../AccountProxy/AccountProxySelectorItem.tsx | 12 ++++++------ .../parts/SelectAccount/AccountSelectorModal.tsx | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx index a7247c975e..4f050a54fb 100644 --- a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx +++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx @@ -60,17 +60,17 @@ function Component (props: Props): React.ReactElement { }, [onClickMoreButton]); const accountProxyTypeIconProps = (() => { - if (accountProxy.accountType === AccountProxyType.MULTI) { + if (accountProxy.accountType === AccountProxyType.UNIFIED) { return { - className: '-is-multi', + className: '-is-unified', value: Strategy, weight: 'fill' }; } - if (accountProxy.accountType === AccountProxyType.SINGLE) { + if (accountProxy.accountType === AccountProxyType.SOLO) { return { - className: '-is-single', + className: '-is-solo', value: GitCommit, weight: 'fill' }; @@ -248,11 +248,11 @@ const AccountProxySelectorItem = styled(Component)(({ theme }) => { justifyContent: 'center', borderRadius: '100%', - '&.-is-multi': { + '&.-is-unified': { color: token.colorSuccess }, - '&.-is-single': { + '&.-is-solo': { color: token['blue-9'] }, diff --git a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx index c477f8944a..705cb1fdce 100644 --- a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx +++ b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx @@ -71,7 +71,7 @@ const Component: React.FC = ({ className }: Props) => { return; } - if (ap.accountType === AccountProxyType.SINGLE || ap.accountType === AccountProxyType.MULTI) { + if (ap.accountType === AccountProxyType.SOLO || ap.accountType === AccountProxyType.UNIFIED) { masterAccounts.push(ap); } else if (ap.accountType === AccountProxyType.QR) { qrSignerAccounts.push(ap); From 6fddc10abdc52231fbb68d6ca67001c165480d2b Mon Sep 17 00:00:00 2001 From: S2kael Date: Tue, 30 Jul 2024 20:08:09 +0700 Subject: [PATCH 019/424] [Issue-3396] Update balance service --- .../src/koni/api/dotsama/crowdloan.ts | 2 +- .../extension-base/src/koni/api/nft/index.ts | 10 +- .../src/koni/api/staking/index.ts | 2 +- .../src/koni/background/cron.ts | 12 +- .../src/koni/background/handlers/Extension.ts | 11 +- .../src/koni/background/handlers/State.ts | 64 +++-------- .../src/koni/background/handlers/Tabs.ts | 2 +- .../src/koni/background/subscription.ts | 10 +- .../balance-service/BalanceMapImpl.ts | 63 ++++++++--- .../helpers/subscribe/index.ts | 19 ++-- .../src/services/balance-service/index.ts | 6 +- .../src/services/chain-service/utils/index.ts | 9 ++ .../src/services/earning-service/service.ts | 14 +-- .../keyring-service/account-context.ts | 106 +++++++++++++----- .../src/services/keyring-service/index.ts | 2 +- .../src/types/account/info/current.ts | 4 +- packages/extension-base/src/utils/index.ts | 26 +++-- 17 files changed, 222 insertions(+), 140 deletions(-) diff --git a/packages/extension-base/src/koni/api/dotsama/crowdloan.ts b/packages/extension-base/src/koni/api/dotsama/crowdloan.ts index 30f979a1fb..f41a0bbe3b 100644 --- a/packages/extension-base/src/koni/api/dotsama/crowdloan.ts +++ b/packages/extension-base/src/koni/api/dotsama/crowdloan.ts @@ -178,7 +178,7 @@ export async function subscribeCrowdloan (addresses: string[], substrateApiMap: const now = Date.now(); const polkadotAPI = await substrateApiMap[COMMON_CHAIN_SLUGS.POLKADOT].isReady; const kusamaAPI = await substrateApiMap[COMMON_CHAIN_SLUGS.KUSAMA].isReady; - const substrateAddresses = categoryAddresses(addresses)[0]; + const substrateAddresses = categoryAddresses(addresses).substrate; const hexAddresses = substrateAddresses.map((address) => { return registry.createType('AccountId', address).toHex(); }); diff --git a/packages/extension-base/src/koni/api/nft/index.ts b/packages/extension-base/src/koni/api/nft/index.ts index 3a6b29b5ed..fcc779d05e 100644 --- a/packages/extension-base/src/koni/api/nft/index.ts +++ b/packages/extension-base/src/koni/api/nft/index.ts @@ -24,7 +24,7 @@ import { categoryAddresses, targetIsWeb } from '@subwallet/extension-base/utils' import AssetHubNftsPalletApi from './assethub_nft'; function createSubstrateNftApi (chain: string, substrateApi: _SubstrateApi | null, addresses: string[]): BaseNftApi[] | null { - const [substrateAddresses, evmAddresses] = categoryAddresses(addresses); + const { evm: evmAddresses, substrate: substrateAddresses } = categoryAddresses(addresses); if (_NFT_CHAIN_GROUP.acala.includes(chain)) { return [new AcalaNftApi(substrateApi, substrateAddresses, chain)]; @@ -52,13 +52,13 @@ function createSubstrateNftApi (chain: string, substrateApi: _SubstrateApi | nul } function createWasmNftApi (chain: string, apiProps: _SubstrateApi | null, addresses: string[]): BaseNftApi | null { - const [substrateAddresses] = categoryAddresses(addresses); + const substrateAddresses = categoryAddresses(addresses).substrate; return new WasmNftApi(apiProps, substrateAddresses, chain); } function createWeb3NftApi (chain: string, evmApi: _EvmApi | null, addresses: string[]): BaseNftApi | null { - const [, evmAddresses] = categoryAddresses(addresses); + const evmAddresses = categoryAddresses(addresses).evm; return new EvmNftApi(evmApi, evmAddresses, chain); } @@ -100,7 +100,7 @@ export class NftHandler { setAddresses (addresses: string[]) { this.addresses = addresses; - const [substrateAddresses, evmAddresses] = categoryAddresses(addresses); + const { evm: evmAddresses, substrate: substrateAddresses } = categoryAddresses(addresses); for (const handler of this.handlers) { const useAddresses = handler.isEthereum ? evmAddresses : substrateAddresses; @@ -131,7 +131,7 @@ export class NftHandler { try { if (this.needSetupApi) { // setup connections for first time use this.handlers = []; - const [substrateAddresses, evmAddresses] = categoryAddresses(this.addresses); + const { evm: evmAddresses, substrate: substrateAddresses } = categoryAddresses(this.addresses); Object.entries(this.chainInfoMap).forEach(([chain, chainInfo]) => { if (_isChainSupportNativeNft(chainInfo)) { diff --git a/packages/extension-base/src/koni/api/staking/index.ts b/packages/extension-base/src/koni/api/staking/index.ts index c3a345ac65..4055d1f65d 100644 --- a/packages/extension-base/src/koni/api/staking/index.ts +++ b/packages/extension-base/src/koni/api/staking/index.ts @@ -19,7 +19,7 @@ interface PromiseMapping { export function stakingOnChainApi (addresses: string[], substrateApiMap: Record, chainInfoMap: Record, stakingCallback: (networkKey: string, rs: StakingItem) => void, nominatorStateCallback: (nominatorMetadata: NominatorMetadata) => void) { const filteredApiMap: PromiseMapping[] = []; - const [substrateAddresses, evmAddresses] = categoryAddresses(addresses); + const { evm: evmAddresses, substrate: substrateAddresses } = categoryAddresses(addresses); Object.entries(chainInfoMap).forEach(([networkKey, chainInfo]) => { if (_PURE_EVM_CHAINS.indexOf(networkKey) < 0 && _isChainSupportSubstrateStaking(chainInfo)) { diff --git a/packages/extension-base/src/koni/background/cron.ts b/packages/extension-base/src/koni/background/cron.ts index 2549f9f6d7..38e52c5810 100644 --- a/packages/extension-base/src/koni/background/cron.ts +++ b/packages/extension-base/src/koni/background/cron.ts @@ -110,7 +110,7 @@ export class KoniCron { return; } - const address = serviceInfo.currentAccountInfo?.address; + const address = serviceInfo.currentAccountInfo?.proxyId; if (!address) { return; @@ -146,13 +146,13 @@ export class KoniCron { this.addCron('fetchPoolInfo', this.fetchPoolInfo, CRON_REFRESH_CHAIN_STAKING_METADATA); - if (!currentAccountInfo?.address) { + if (!currentAccountInfo?.proxyId) { return; } if (Object.keys(this.state.getSubstrateApiMap()).length !== 0 || Object.keys(this.state.getEvmApiMap()).length !== 0) { - this.resetNft(currentAccountInfo.address); - this.addCron('refreshNft', this.refreshNft(currentAccountInfo.address, this.state.getApiMap(), this.state.getSmartContractNfts(), this.state.getActiveChainInfoMap()), CRON_REFRESH_NFT_INTERVAL); + this.resetNft(currentAccountInfo.proxyId); + this.addCron('refreshNft', this.refreshNft(currentAccountInfo.proxyId, this.state.getApiMap(), this.state.getSmartContractNfts(), this.state.getActiveChainInfoMap()), CRON_REFRESH_NFT_INTERVAL); // this.addCron('refreshStakingReward', this.refreshStakingReward(currentAccountInfo.address), CRON_REFRESH_STAKING_REWARD_INTERVAL); this.addCron('syncMantaPay', this.syncMantaPay, CRON_SYNC_MANTA_PAY); } @@ -213,7 +213,7 @@ export class KoniCron { }; public async reloadNft () { - const address = this.state.keyringService.context.currentAccount.address; + const address = this.state.keyringService.context.currentAccount.proxyId; const serviceInfo = this.state.getServiceInfo(); this.resetNft(address); @@ -226,7 +226,7 @@ export class KoniCron { } public async reloadStaking () { - const address = this.state.keyringService.context.currentAccount.address; + const address = this.state.keyringService.context.currentAccount.proxyId; console.log('reload staking', address); diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index 77f665c196..1661feda6f 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -41,9 +41,7 @@ import { isProposalExpired, isSupportWalletConnectChain, isSupportWalletConnectN import { ResultApproveWalletConnectSession, WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; import { SWStorage } from '@subwallet/extension-base/storage'; import { AccountsStore } from '@subwallet/extension-base/stores'; -import { - AccountProxy, AccountProxyType, AccountsWithCurrentAddress, BalanceJson, BuyServiceInfo, BuyTokenInfo, EarningRewardJson, NominationPoolInfo, OptimalYieldPathParams, RequestAccountCreateSuriV2, RequestCheckPublicAndSecretKey, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestEarlyValidateYield, RequestExportAccountProxyMnemonic, RequestGetDeriveAccounts, RequestGetYieldPoolTargets, RequestMetadataHash, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseAccountCreateSuriV2, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseExportAccountProxyMnemonic, ResponseGetDeriveAccounts, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2, ResponseShortenMetadata, StorageDataInterface, TokenSpendingApprovalParams, ValidateYieldProcessParams, YieldPoolType -} from '@subwallet/extension-base/types'; +import { AccountProxy, AccountProxyType, AccountsWithCurrentAddress, BalanceJson, BuyServiceInfo, BuyTokenInfo, EarningRewardJson, NominationPoolInfo, OptimalYieldPathParams, RequestAccountCreateSuriV2, RequestCheckPublicAndSecretKey, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestEarlyValidateYield, RequestExportAccountProxyMnemonic, RequestGetDeriveAccounts, RequestGetYieldPoolTargets, RequestMetadataHash, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseAccountCreateSuriV2, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseExportAccountProxyMnemonic, ResponseGetDeriveAccounts, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2, ResponseShortenMetadata, StorageDataInterface, TokenSpendingApprovalParams, ValidateYieldProcessParams, YieldPoolType } from '@subwallet/extension-base/types'; import { RequestAccountProxyEdit, RequestAccountProxyForget } from '@subwallet/extension-base/types/account/action/edit'; import { CommonOptimalPath } from '@subwallet/extension-base/types/service-base'; import { SwapPair, SwapQuoteResponse, SwapRequest, SwapRequestResult, SwapSubmitParams, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap'; @@ -74,7 +72,8 @@ const ACCOUNT_ALL_GROUP: AccountProxy = { id: ALL_ACCOUNT_KEY, name: 'All', accounts: [], - accountType: AccountProxyType.ALL_ACCOUNT + accountType: AccountProxyType.ALL_ACCOUNT, + networkTypes: [] }; export const SEED_DEFAULT_LENGTH = 12; @@ -438,7 +437,7 @@ export default class KoniExtension { const transformedAccounts = Object.values(accountGroups); responseData.accounts = transformedAccounts?.length ? [{ ...ACCOUNT_ALL_GROUP }, ...transformedAccounts] : []; - responseData.currentAccountProxy = currentAccount?.address; + responseData.currentAccountProxy = currentAccount?.proxyId; console.debug('subscriptionAccountGroups', responseData); cb(responseData); @@ -1018,7 +1017,7 @@ export default class KoniExtension { private async saveCurrentAccountAddress (data: RequestCurrentAccountAddress): Promise { return new Promise((resolve) => { - this.#koniState.keyringService.context._setCurrentAccount({ address: data.address }, () => { + this.#koniState.keyringService.context._setCurrentAccount({ proxyId: data.address }, () => { resolve(true); }); }); diff --git a/packages/extension-base/src/koni/background/handlers/State.ts b/packages/extension-base/src/koni/background/handlers/State.ts index bc856b119b..360d4bda83 100644 --- a/packages/extension-base/src/koni/background/handlers/State.ts +++ b/packages/extension-base/src/koni/background/handlers/State.ts @@ -284,9 +284,9 @@ export default class KoniState { public generateDefaultBalanceMap (_addresses?: string[]): BalanceMap { const balanceMap: BalanceMap = {}; const activeChains = this.chainService.getActiveChainInfoMap(); - const isAllAccount = isAccountAll(this.keyringService.context.currentAccount.address); + const isAllAccount = isAccountAll(this.keyringService.context.currentAccount.proxyId); - const addresses = _addresses || (isAllAccount ? Object.keys(this.keyringService.context.pairs) : [this.keyringService.context.currentAccount.address]); + const addresses = _addresses || (isAllAccount ? Object.keys(this.keyringService.context.pairs) : [this.keyringService.context.currentAccount.proxyId]); addresses.forEach((address) => { const temp: Record = {}; @@ -450,7 +450,7 @@ export default class KoniState { } public async getStaking (): Promise { - const addresses = this.getDecodedAddresses(); + const addresses = this.keyringService.context.getDecodedAddresses(); const stakings = await this.dbService.getStakings(addresses, this.activeChainSlugs); @@ -527,7 +527,7 @@ export default class KoniState { total: 0 })).catch((e) => this.logger.warn(e)); - const addresses = this.getDecodedAddresses(newAddress); + const addresses = this.keyringService.context.getDecodedAddresses(newAddress); this.dbService.subscribeNft(addresses, this.activeChainSlugs, (nfts) => { this.nftSubject.next({ @@ -552,7 +552,7 @@ export default class KoniState { } public async getNft (): Promise { - const addresses = this.getDecodedAddresses(); + const addresses = this.keyringService.context.getDecodedAddresses(); if (!addresses.length) { return; @@ -651,11 +651,11 @@ export default class KoniState { } public setCurrentAccount (data: CurrentAccountInfo, callback?: () => void, preventOneAccount?: boolean): void { - const { address } = data; + const { proxyId } = data; const result: CurrentAccountInfo = { ...data }; - if (address === ALL_ACCOUNT_KEY) { + if (proxyId === ALL_ACCOUNT_KEY) { const pairs = keyring.getAccounts(); const pair = pairs[0]; @@ -663,7 +663,7 @@ export default class KoniState { // Empty } else { if (!preventOneAccount) { - result.address = pair.address; + result.proxyId = pair.address; } } } @@ -683,7 +683,7 @@ export default class KoniState { const accountInfo = this.keyringService.context.currentAccount; - if (address === accountInfo.address) { + if (address === accountInfo.proxyId) { this.setCurrentAccount(accountInfo); } @@ -710,7 +710,7 @@ export default class KoniState { public async switchNetworkAccount (id: string, url: string, networkKey: string, changeAddress?: string): Promise { const chainInfo = this.chainService.getChainInfoByKey(networkKey); const chainState = this.chainService.getChainStateByKey(networkKey); - const { address } = this.keyringService.context.currentAccount; + const { proxyId } = this.keyringService.context.currentAccount; return this.requestService.addConfirmation(id, url, 'switchNetworkRequest', { networkKey, @@ -718,7 +718,7 @@ export default class KoniState { }, { address: changeAddress }) .then(({ isApproved }) => { if (isApproved) { - const useAddress = changeAddress || address; + const useAddress = changeAddress || proxyId; if (chainInfo && !_isChainEnabled(chainState)) { this.enableChain(networkKey).catch(console.error); @@ -732,9 +732,9 @@ export default class KoniState { keyring.saveAccountMeta(pair, { ...pair.meta, genesisHash: _getSubstrateGenesisHash(chainInfo) }); } - if (address !== changeAddress || isApproved) { + if (proxyId !== changeAddress || isApproved) { this.setCurrentAccount({ - address: useAddress + proxyId: useAddress }); } } @@ -828,34 +828,6 @@ export default class KoniState { return this.settingService.getSubject(); } - public getAccountAddress (): string | null { - const address = this.keyringService.context.currentAccount.address; - - if (address === '') { - return null; - } - - return address; - } - - public getDecodedAddresses (address?: string): string[] { - let checkingAddress: string | null | undefined = address; - - if (!address) { - checkingAddress = this.getAccountAddress(); - } - - if (!checkingAddress) { - return []; - } - - if (checkingAddress === ALL_ACCOUNT_KEY) { - return this.getAllAddresses(); - } - - return [checkingAddress]; - } - public getAllAddresses (): string[] { return keyring.getAccounts().map((account) => account.address); } @@ -875,7 +847,7 @@ export default class KoniState { }) .catch((e) => this.logger.warn(e)); - const addresses = this.getDecodedAddresses(newAddress); + const addresses = this.keyringService.context.getDecodedAddresses(newAddress); this.dbService.subscribeStaking(addresses, this.activeChainSlugs, (stakings) => { this.stakingSubject.next({ @@ -910,7 +882,7 @@ export default class KoniState { private updateCrowdloanStore (networkKey: string, item: CrowdloanItem) { const currentAccountInfo = this.keyringService.context.currentAccount; - this.dbService.updateCrowdloanStore(networkKey, currentAccountInfo.address, item).catch((e) => this.logger.warn(e)); + this.dbService.updateCrowdloanStore(networkKey, currentAccountInfo.proxyId, item).catch((e) => this.logger.warn(e)); } public subscribeCrowdloan () { @@ -1692,7 +1664,7 @@ export default class KoniState { if (!remindStatus || !remindStatus.includes('done')) { const handleRemind = (account: CurrentAccountInfo) => { - if (account.address !== '') { + if (account.proxyId !== '') { // Open remind tab const url = `${chrome.runtime.getURL('index.html')}#/remind-export-account`; @@ -1917,7 +1889,7 @@ export default class KoniState { } public async reloadNft () { - const currentAddress = this.keyringService.context.currentAccount.address; + const currentAddress = this.keyringService.context.currentAccount.proxyId; await this.dbService.removeNftsByAddress(currentAddress); @@ -2113,7 +2085,7 @@ export default class KoniState { public subscribeMantaPayBalance () { let interval: NodeJS.Timer | undefined; - this.chainService?.mantaPay?.getMantaPayConfig(this.keyringService.context.currentAccount.address, _DEFAULT_MANTA_ZK_CHAIN) + this.chainService?.mantaPay?.getMantaPayConfig(this.keyringService.context.currentAccount.proxyId, _DEFAULT_MANTA_ZK_CHAIN) .then((config: MantaPayConfig) => { if (config && config.enabled && config.isInitialSync) { this.getMantaZkBalance(); diff --git a/packages/extension-base/src/koni/background/handlers/Tabs.ts b/packages/extension-base/src/koni/background/handlers/Tabs.ts index 5dfc109e7b..31c366d792 100644 --- a/packages/extension-base/src/koni/background/handlers/Tabs.ts +++ b/packages/extension-base/src/koni/background/handlers/Tabs.ts @@ -353,7 +353,7 @@ export default class KoniTabs { const accountList = transformAccountsV2(allAccounts, false, authInfo, 'evm').map((a) => a.address); let accounts: string[] = []; - const address = this.#koniState.keyringService.context.currentAccount.address; + const address = this.#koniState.keyringService.context.currentAccount.proxyId; if (address === ALL_ACCOUNT_KEY || !address) { accounts = accountList; diff --git a/packages/extension-base/src/koni/background/subscription.ts b/packages/extension-base/src/koni/background/subscription.ts index 0a531d4a26..c42c0cf6c0 100644 --- a/packages/extension-base/src/koni/background/subscription.ts +++ b/packages/extension-base/src/koni/background/subscription.ts @@ -66,7 +66,7 @@ export class KoniSubscription { async start () { await Promise.all([this.state.eventService.waitCryptoReady, this.state.eventService.waitKeyringReady, this.state.eventService.waitAssetReady]); - const currentAddress = this.state.keyringService.context.currentAccount?.address; + const currentAddress = this.state.keyringService.context.currentAccount?.proxyId; if (currentAddress) { this.subscribeCrowdloans(currentAddress, this.state.getSubstrateApiMap()); @@ -80,7 +80,7 @@ export class KoniSubscription { return; } - const address = serviceInfo.currentAccountInfo?.address; + const address = serviceInfo.currentAccountInfo?.proxyId; if (!address) { return; @@ -104,7 +104,7 @@ export class KoniSubscription { } subscribeCrowdloans (address: string, substrateApiMap: Record, onlyRunOnFirstTime?: boolean) { - const addresses = this.state.getDecodedAddresses(address); + const addresses = this.state.keyringService.context.getDecodedAddresses(address); if (!addresses.length) { return; @@ -132,7 +132,7 @@ export class KoniSubscription { } subscribeNft (address: string, substrateApiMap: Record, evmApiMap: Record, smartContractNfts: _ChainAsset[], chainInfoMap: Record) { - const addresses = this.state.getDecodedAddresses(address); + const addresses = this.state.keyringService.context.getDecodedAddresses(address); if (!addresses.length) { return; @@ -155,7 +155,7 @@ export class KoniSubscription { } async reloadCrowdloan () { - const currentAddress = this.state.keyringService.context.currentAccount?.address; + const currentAddress = this.state.keyringService.context.currentAccount?.proxyId; this.subscribeCrowdloans(currentAddress, this.state.getSubstrateApiMap()); diff --git a/packages/extension-base/src/services/balance-service/BalanceMapImpl.ts b/packages/extension-base/src/services/balance-service/BalanceMapImpl.ts index bdbd454e09..d9d99e1fa3 100644 --- a/packages/extension-base/src/services/balance-service/BalanceMapImpl.ts +++ b/packages/extension-base/src/services/balance-service/BalanceMapImpl.ts @@ -2,7 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; -import { BalanceInfo, BalanceItem, BalanceMap } from '@subwallet/extension-base/types'; +import KoniState from '@subwallet/extension-base/koni/background/handlers/State'; +import { AccountProxyType, BalanceInfo, BalanceItem, BalanceMap } from '@subwallet/extension-base/types'; import { isAccountAll } from '@subwallet/extension-base/utils'; import { BehaviorSubject } from 'rxjs'; @@ -11,7 +12,7 @@ import { groupBalance } from './helpers'; export class BalanceMapImpl { private _mapSubject: BehaviorSubject; - constructor (private _map: BalanceMap = {}) { + constructor (private state: KoniState, private _map: BalanceMap = {}) { this._mapSubject = new BehaviorSubject(_map); } @@ -74,26 +75,60 @@ export class BalanceMapImpl { } public computeAllAccountBalance () { - const allAccountBalanceInfo: BalanceInfo = {}; - const allAccountBalance: Record = {}; + const compoundMap: Record> = {}; + const accountProxies = this.state.keyringService.context.accounts; + const unifiedAccountsMap = Object.values(accountProxies) + .filter((value) => value.accountType === AccountProxyType.UNIFIED) + .reduce>((rs, value) => { + rs[value.id] = value.accounts.map((account) => account.address); + + return rs; + }, {}); + const revertUnifiedAccountsMap = Object.entries(unifiedAccountsMap) + .reduce>((rs, [proxyId, accounts]) => { + for (const account of accounts) { + rs[account] = proxyId; + } + + return rs; + }, {}); + + const proxyIds = Object.keys(unifiedAccountsMap); Object.keys(this._map) - .filter((a) => !isAccountAll(a)) + .filter((a) => !isAccountAll(a) && !proxyIds.includes(a)) .forEach((address) => { - Object.keys(this._map[address]).forEach((tokenSlug) => { - if (!allAccountBalance[tokenSlug]) { - allAccountBalance[tokenSlug] = []; - } + const addItemToMap = (key: string) => { + const unifiedAccountBalance = compoundMap[key] || {}; - allAccountBalance[tokenSlug].push(this._map[address][tokenSlug]); - }); + Object.keys(this._map[address]).forEach((tokenSlug) => { + if (!unifiedAccountBalance[tokenSlug]) { + unifiedAccountBalance[tokenSlug] = []; + } + + unifiedAccountBalance[tokenSlug].push(this._map[address][tokenSlug]); + }); + + compoundMap[key] = unifiedAccountBalance; + }; + + addItemToMap(ALL_ACCOUNT_KEY); + const proxyId = revertUnifiedAccountsMap[address]; + + proxyId && addItemToMap(proxyId); + }); + + Object.entries(compoundMap).forEach(([compoundKey, balanceMap]) => { + const rs: BalanceInfo = {}; + + Object.entries(balanceMap).forEach(([tokenSlug, balanceItems]) => { + rs[tokenSlug] = groupBalance(balanceItems, tokenSlug, tokenSlug); }); - Object.entries(allAccountBalance).forEach(([tokenSlug, balanceItems]) => { - allAccountBalanceInfo[tokenSlug] = groupBalance(balanceItems, ALL_ACCOUNT_KEY, tokenSlug); + this._map[compoundKey] = rs; }); - this._map[ALL_ACCOUNT_KEY] = allAccountBalanceInfo; + console.debug('balanceMap', this._map); } // Remove balance items buy address or tokenSlug diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts index 2c536f1fcb..2a212142f7 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts @@ -4,7 +4,7 @@ import { _AssetType, _ChainAsset, _ChainInfo } from '@subwallet/chain-list/types'; import { APIItemState, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; import { _EvmApi, _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; -import { _getSubstrateGenesisHash, _isChainEvmCompatible, _isPureEvmChain } from '@subwallet/extension-base/services/chain-service/utils'; +import { _getSubstrateGenesisHash, _isChainBitcoinCompatible, _isChainEvmCompatible, _isChainTonCompatible, _isPureEvmChain } from '@subwallet/extension-base/services/chain-service/utils'; import { AccountJson, BalanceItem } from '@subwallet/extension-base/types'; import { categoryAddresses, filterAssetsByChainAndType, pairToAccount } from '@subwallet/extension-base/utils'; import keyring from '@subwallet/ui-keyring'; @@ -39,16 +39,19 @@ export const getAccountJsonByAddress = (address: string): AccountJson | null => /** Filter addresses to subscribe by chain info */ const filterAddress = (addresses: string[], chainInfo: _ChainInfo): [string[], string[]] => { - const isEvmChain = _isChainEvmCompatible(chainInfo); - const [substrateAddresses, evmAddresses] = categoryAddresses(addresses); - - if (isEvmChain) { - return [evmAddresses, substrateAddresses]; + const { bitcoin, evm, substrate, ton } = categoryAddresses(addresses); + + if (_isChainEvmCompatible(chainInfo)) { + return [evm, [...bitcoin, ...substrate, ...ton]]; + } else if (_isChainBitcoinCompatible(chainInfo)) { + return [bitcoin, [...evm, ...substrate, ...ton]]; + } else if (_isChainTonCompatible(chainInfo)) { + return [ton, [...bitcoin, ...evm, ...substrate]]; } else { const fetchList: string[] = []; const unfetchList: string[] = []; - substrateAddresses.forEach((address) => { + substrate.forEach((address) => { const account = getAccountJsonByAddress(address); if (account) { @@ -73,7 +76,7 @@ const filterAddress = (addresses: string[], chainInfo: _ChainInfo): [string[], s } }); - return [fetchList, [...unfetchList, ...evmAddresses]]; + return [fetchList, [...unfetchList, ...bitcoin, ...evm, ...ton]]; } }; diff --git a/packages/extension-base/src/services/balance-service/index.ts b/packages/extension-base/src/services/balance-service/index.ts index 22c6df33b9..169d2f1f86 100644 --- a/packages/extension-base/src/services/balance-service/index.ts +++ b/packages/extension-base/src/services/balance-service/index.ts @@ -51,7 +51,7 @@ export class BalanceService implements StoppableServiceInterface { */ constructor (state: KoniState) { this.state = state; - this.balanceMap = new BalanceMapImpl(); + this.balanceMap = new BalanceMapImpl(state); } /** Init service */ @@ -311,7 +311,7 @@ export class BalanceService implements StoppableServiceInterface { } addLazy('updateBalanceStore', () => { - const isAllAccount = isAccountAll(this.state.keyringService.context.currentAccount.address); + const isAllAccount = isAccountAll(this.state.keyringService.context.currentAccount.proxyId); this.balanceMap.updateBalanceItems(this.balanceUpdateCache, isAllAccount); @@ -348,7 +348,7 @@ export class BalanceService implements StoppableServiceInterface { await Promise.all([this.state.eventService.waitKeyringReady, this.state.eventService.waitChainReady]); this.runUnsubscribeBalances(); - const addresses = this.state.getDecodedAddresses(); + const addresses = this.state.keyringService.context.getDecodedAddresses(); if (!addresses.length) { return; diff --git a/packages/extension-base/src/services/chain-service/utils/index.ts b/packages/extension-base/src/services/chain-service/utils/index.ts index 1c473b5800..a3674bcf9e 100644 --- a/packages/extension-base/src/services/chain-service/utils/index.ts +++ b/packages/extension-base/src/services/chain-service/utils/index.ts @@ -138,6 +138,15 @@ export function _isChainEvmCompatible (chainInfo: _ChainInfo) { return !!chainInfo.evmInfo; } +export function _isChainBitcoinCompatible (chainInfo: _ChainInfo) { + return !!chainInfo.bitcoinInfo; +} + +export function _isChainTonCompatible (chainInfo: _ChainInfo) { + // TODO: Add TON chain info + return false; +} + export function _isNativeToken (tokenInfo: _ChainAsset) { return tokenInfo.assetType === _AssetType.NATIVE; } diff --git a/packages/extension-base/src/services/earning-service/service.ts b/packages/extension-base/src/services/earning-service/service.ts index 28cc60b7b3..5b14e66b31 100644 --- a/packages/extension-base/src/services/earning-service/service.ts +++ b/packages/extension-base/src/services/earning-service/service.ts @@ -473,7 +473,7 @@ export default class EarningService implements StoppableServiceInterface, Persis await this.eventService.waitChainReady; - const [substrateAddresses, evmAddresses] = categoryAddresses(addresses); + const { evm: evmAddresses, substrate: substrateAddresses } = categoryAddresses(addresses); const activeChains = this.state.activeChainSlugs; const unsubList: Array = []; @@ -533,7 +533,7 @@ export default class EarningService implements StoppableServiceInterface, Persis await this.eventService.waitChainReady; await this.eventService.waitKeyringReady; - const addresses = this.state.getDecodedAddresses(); + const addresses = this.state.keyringService.context.getDecodedAddresses(); const existedYieldPosition = await this.dbService.getYieldNominationPoolPosition(addresses, this.state.activeChainSlugs); @@ -608,7 +608,7 @@ export default class EarningService implements StoppableServiceInterface, Persis await this.eventService.waitKeyringReady; this.runUnsubscribePoolsPosition(); - const addresses = this.state.getDecodedAddresses(); + const addresses = this.state.keyringService.context.getDecodedAddresses(); this.subscribePoolPositions(addresses, (data) => { this.updateYieldPosition(data); @@ -657,7 +657,7 @@ export default class EarningService implements StoppableServiceInterface, Persis await this.eventService.waitChainReady; - const [substrateAddresses, evmAddresses] = categoryAddresses(addresses); + const { evm: evmAddresses, substrate: substrateAddresses } = categoryAddresses(addresses); const activeChains = this.state.activeChainSlugs; const unsubList: Array = []; @@ -697,7 +697,7 @@ export default class EarningService implements StoppableServiceInterface, Persis earningsRewardInterval: NodeJS.Timer | undefined; runSubscribeStakingRewardInterval () { - const addresses = this.state.getDecodedAddresses(); + const addresses = this.state.keyringService.context.getDecodedAddresses(); if (!addresses.length) { return; @@ -725,7 +725,7 @@ export default class EarningService implements StoppableServiceInterface, Persis await this.eventService.waitChainReady; - const [substrateAddresses, evmAddresses] = categoryAddresses(addresses); + const { evm: evmAddresses, substrate: substrateAddresses } = categoryAddresses(addresses); const activeChains = this.state.activeChainSlugs; const unsubList: Array = []; @@ -785,7 +785,7 @@ export default class EarningService implements StoppableServiceInterface, Persis runSubscribeEarningRewardHistoryInterval () { this.runUnsubscribeEarningRewardHistoryInterval(); - const addresses = this.state.getDecodedAddresses(); + const addresses = this.state.keyringService.context.getDecodedAddresses(); if (!addresses.length) { return; diff --git a/packages/extension-base/src/services/keyring-service/account-context.ts b/packages/extension-base/src/services/keyring-service/account-context.ts index 073bab59a6..1291ebb576 100644 --- a/packages/extension-base/src/services/keyring-service/account-context.ts +++ b/packages/extension-base/src/services/keyring-service/account-context.ts @@ -6,7 +6,7 @@ import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; import { SEED_DEFAULT_LENGTH, SEED_LENGTHS } from '@subwallet/extension-base/koni/background/handlers/Extension'; import { KeyringService } from '@subwallet/extension-base/services/keyring-service/index'; import { AccountProxyStore, AccountRefStore, CurrentAccountStore, ModifyPairStore } from '@subwallet/extension-base/stores'; -import { AccountJson, AccountProxy, AccountProxyData, AccountProxyMap, AccountProxyStoreData, AccountProxyType, CreateDeriveAccountInfo, CurrentAccountInfo, DeriveAccountInfo, MnemonicType, ModifyPairStoreData, RequestAccountCreateSuriV2, RequestDeriveAccountProxy, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestExportAccountProxyMnemonic, RequestGetDeriveAccounts, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, ResponseAccountCreateSuriV2, ResponseDeriveValidateV2, ResponseExportAccountProxyMnemonic, ResponseGetDeriveAccounts, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2 } from '@subwallet/extension-base/types'; +import { AccountJson, AccountNetworkType, AccountProxy, AccountProxyData, AccountProxyMap, AccountProxyStoreData, AccountProxyType, CreateDeriveAccountInfo, CurrentAccountInfo, DeriveAccountInfo, MnemonicType, ModifyPairStoreData, RequestAccountCreateSuriV2, RequestDeriveAccountProxy, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestExportAccountProxyMnemonic, RequestGetDeriveAccounts, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, ResponseAccountCreateSuriV2, ResponseDeriveValidateV2, ResponseExportAccountProxyMnemonic, ResponseGetDeriveAccounts, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2 } from '@subwallet/extension-base/types'; import { RequestAccountProxyEdit, RequestAccountProxyForget } from '@subwallet/extension-base/types/account/action/edit'; import { isAddressValidWithAuthType, modifyAccountName, singleAddressToAccount } from '@subwallet/extension-base/utils'; import { InjectedAccountWithMeta } from '@subwallet/extension-inject/types'; @@ -40,7 +40,7 @@ const ACCOUNT_PROXIES_KEY = 'AccountProxies'; export class AccountContext { // Current account private readonly currentAccountStore = new CurrentAccountStore(); - public readonly currentAccountSubject = new BehaviorSubject({ address: '' }); + public readonly currentAccountSubject = new BehaviorSubject({ proxyId: '' }); // Account groups private readonly accountProxiesStore = new AccountProxyStore(); @@ -70,7 +70,9 @@ export class AccountContext { .then(() => { // Load current account this.currentAccountStore.get(CURRENT_ACCOUNT_KEY, (rs) => { - rs && this.currentAccountSubject.next(rs); + const data: CurrentAccountInfo = rs ? { proxyId: rs.proxyId || rs.address || '' } : { proxyId: '' }; + + this.currentAccountSubject.next(data); }); // Load modify pairs this.modifyPairsStore.get(MODIFY_PAIRS_KEY, (rs) => { @@ -131,7 +133,7 @@ export class AccountContext { if (accountGroup) { if (!temp[accountGroup.id]) { - temp[accountGroup.id] = { ...accountGroup, accounts: [] }; + temp[accountGroup.id] = { ...accountGroup, accounts: [], networkTypes: [] }; } temp[accountGroup.id].accounts.push(account); @@ -139,19 +141,23 @@ export class AccountContext { } } - temp[address] = { id: address, name: account.name || account.address, accounts: [account] }; + temp[address] = { id: address, name: account.name || account.address, accounts: [account], networkTypes: [account.networkType] }; } const result: AccountProxyMap = Object.fromEntries( Object.entries(temp) .map(([key, value]): [string, AccountProxy] => { let accountType: AccountProxyType = AccountProxyType.UNKNOWN; + let networkTypes: AccountNetworkType[] = []; if (value.accounts.length > 1) { - accountType = AccountProxyType.MULTI; + accountType = AccountProxyType.UNIFIED; + networkTypes = Array.from(value.accounts.reduce>((rs, account) => rs.add(account.networkType), new Set())); } else if (value.accounts.length === 1) { const account = value.accounts[0]; + networkTypes = [account.networkType]; + if (account.isInjected) { accountType = AccountProxyType.INJECTED; } else if (account.isExternal) { @@ -163,11 +169,11 @@ export class AccountContext { accountType = AccountProxyType.QR; } } else { - accountType = AccountProxyType.SINGLE; + accountType = AccountProxyType.SOLO; } } - return [key, { ...value, accountType }]; + return [key, { ...value, accountType, networkTypes }]; }) ); @@ -200,10 +206,10 @@ export class AccountContext { } public _setCurrentAccount (data: CurrentAccountInfo, callback?: () => void, preventOneAccount?: boolean): void { - const { address } = data; + const { proxyId } = data; const result: CurrentAccountInfo = { ...data }; - if (address === ALL_ACCOUNT_KEY) { + if (proxyId === ALL_ACCOUNT_KEY) { const pairs = keyring.getAccounts(); const pair = pairs[0]; @@ -211,7 +217,7 @@ export class AccountContext { // Empty } else { if (!preventOneAccount) { - result.address = pair.address; + result.proxyId = pair.address; } } } @@ -225,10 +231,10 @@ export class AccountContext { if (!accountInfo) { accountInfo = { - address + proxyId: address }; } else { - accountInfo.address = address; + accountInfo.proxyId = address; } this._setCurrentAccount(accountInfo, () => { @@ -379,7 +385,7 @@ export class AccountContext { await Promise.all(addresses.map((address) => new Promise((resolve) => this.removeAccountRef(address, resolve)))); await new Promise((resolve) => { - this._setCurrentAccount({ address: ALL_ACCOUNT_KEY }, resolve); + this._setCurrentAccount({ proxyId: ALL_ACCOUNT_KEY }, resolve); }); return addresses; @@ -387,6 +393,53 @@ export class AccountContext { /* Modify accounts */ + /* Get address for another service */ + + public getAllAddresses (): string[] { + return keyring.getAccounts().map((account) => account.address); + } + + public getProxyId (): string | null { + const proxyId = this.currentAccount.proxyId; + + if (proxyId === '') { + return null; + } + + return proxyId; + } + + public getDecodedAddresses (accountProxy?: string): string[] { + let proxyId: string | null | undefined = accountProxy; + + if (!accountProxy) { + proxyId = this.getProxyId(); + } + + if (!proxyId) { + return []; + } + + if (proxyId === ALL_ACCOUNT_KEY) { + return this.getAllAddresses(); + } + + const accountProxies = this.accountProxiesSubject.value; + const modifyPairs = this.modifyPairsSubject.value; + + if (!accountProxies[proxyId]) { + const pair = keyring.getPair(proxyId); + + assert(pair, t('Unable to find account')); + + return [pair.address]; + } else { + return Object.keys(modifyPairs).filter((address) => modifyPairs[address].accountProxyId === proxyId); + } + } + + /* Get address for another service */ + /* Create with mnemonic */ /* Create seed */ @@ -496,9 +549,9 @@ export class AccountContext { if (!changedAccount) { if (!proxyId) { - this.setCurrentAccount({ address }); + this.setCurrentAccount({ proxyId: address }); } else { - this._setCurrentAccount({ address: proxyId }, undefined, true); + this._setCurrentAccount({ proxyId: proxyId }, undefined, true); } changedAccount = true; @@ -694,9 +747,9 @@ export class AccountContext { this.upsertModifyPairs(modifiedPairs); if (addresses.length <= 1) { - this._setCurrentAccount({ address: addresses[0] }); + this._setCurrentAccount({ proxyId: addresses[0] }); } else { - this._setCurrentAccount({ address: ALL_ACCOUNT_KEY }); + this._setCurrentAccount({ proxyId: ALL_ACCOUNT_KEY }); } if (Object.keys(slugMap).length) { @@ -923,7 +976,7 @@ export class AccountContext { if (result.length === 1) { this._saveCurrentAccountAddress(result[0].address); } else { - this._setCurrentAccount({ address: ALL_ACCOUNT_KEY }); + this._setCurrentAccount({ proxyId: ALL_ACCOUNT_KEY }); } return true; @@ -1158,11 +1211,8 @@ export class AccountContext { return { result }; } else { - const accountGroup = accountProxies[proxyId]; const addresses = Object.keys(modifyPairs).filter((address) => modifyPairs[address].accountProxyId === proxyId); - this.upsertAccountProxy(accountGroup); - let pair: KeyringPair | undefined; for (const address of addresses) { @@ -1201,7 +1251,7 @@ export class AccountContext { }; })); - const currentAddress = this.currentAccountSubject.value.address; + const currentAddress = this.currentAccountSubject.value.proxyId; const afterAccounts: Record = {}; Object.keys(this.pairs).forEach((adr) => { @@ -1213,9 +1263,9 @@ export class AccountContext { }); if (Object.keys(afterAccounts).length === 1) { - this.currentAccountSubject.next({ address: Object.keys(afterAccounts)[0] }); + this.currentAccountSubject.next({ proxyId: Object.keys(afterAccounts)[0] }); } else if (Object.keys(afterAccounts).indexOf(currentAddress) === -1) { - this.currentAccountSubject.next({ address: ALL_ACCOUNT_KEY }); + this.currentAccountSubject.next({ proxyId: ALL_ACCOUNT_KEY }); } if (!this.injected) { @@ -1232,13 +1282,13 @@ export class AccountContext { return address; } }); - const currentAddress = this.currentAccountSubject.value.address; + const currentAddress = this.currentAccountSubject.value.proxyId; const afterAccounts = Object.keys(this.pairs).filter((address) => (addresses.indexOf(address) < 0)); if (afterAccounts.length === 1) { - this.currentAccountSubject.next({ address: afterAccounts[0] }); + this.currentAccountSubject.next({ proxyId: afterAccounts[0] }); } else if (addresses.indexOf(currentAddress) === -1) { - this.currentAccountSubject.next({ address: ALL_ACCOUNT_KEY }); + this.currentAccountSubject.next({ proxyId: ALL_ACCOUNT_KEY }); } keyring.removeInjects(addresses); diff --git a/packages/extension-base/src/services/keyring-service/index.ts b/packages/extension-base/src/services/keyring-service/index.ts index 00bd6bfb06..4c4393dbfc 100644 --- a/packages/extension-base/src/services/keyring-service/index.ts +++ b/packages/extension-base/src/services/keyring-service/index.ts @@ -57,7 +57,7 @@ export class KeyringService { }, 1500); }); this.updateKeyringState(); - this.context.currentAccountSubject.next({ address: ALL_ACCOUNT_KEY }); + this.context.currentAccountSubject.next({ proxyId: ALL_ACCOUNT_KEY }); } /* Reset */ } diff --git a/packages/extension-base/src/types/account/info/current.ts b/packages/extension-base/src/types/account/info/current.ts index 0d3818b0c6..41ee50f247 100644 --- a/packages/extension-base/src/types/account/info/current.ts +++ b/packages/extension-base/src/types/account/info/current.ts @@ -10,5 +10,7 @@ export interface AccountsWithCurrentAddress { } export interface CurrentAccountInfo { - address: string; + proxyId: string; + /** @deprecated */ + address?: string; } diff --git a/packages/extension-base/src/utils/index.ts b/packages/extension-base/src/utils/index.ts index ed81c5637d..fa01e3767f 100644 --- a/packages/extension-base/src/utils/index.ts +++ b/packages/extension-base/src/utils/index.ts @@ -6,8 +6,9 @@ import { AccountAuthType } from '@subwallet/extension-base/background/types'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; import { getRandomIpfsGateway, SUBWALLET_IPFS } from '@subwallet/extension-base/koni/api/nft/config'; import { AccountJson } from '@subwallet/extension-base/types'; -import { decodeAddress, encodeAddress, getKeypairTypeByAddress } from '@subwallet/keyring'; +import { decodeAddress, encodeAddress, getKeypairTypeByAddress, isBitcoinAddress } from '@subwallet/keyring'; import { KeypairType } from '@subwallet/keyring/types'; +import { isTonAddress } from '@subwallet/keyring/utils'; import { t } from 'i18next'; import { assert, BN, hexToU8a, isHex } from '@polkadot/util'; @@ -72,19 +73,30 @@ export function filterAddressByNetworkKey (addresses: string[], networkKey: stri } } -export function categoryAddresses (addresses: string[]) { - const substrateAddresses: string[] = []; - const evmAddresses: string[] = []; +export function categoryAddresses (addresses: string[]): { substrate: string[], evm: string[], ton: string[], bitcoin: string[] } { + const substrate: string[] = []; + const evm: string[] = []; + const ton: string[] = []; + const bitcoin: string[] = []; addresses.forEach((address) => { if (isEthereumAddress(address)) { - evmAddresses.push(address); + evm.push(address); + } else if (isTonAddress(address)) { + ton.push(address); + } else if (isBitcoinAddress(address) !== 'unknown') { + bitcoin.push(address); } else { - substrateAddresses.push(address); + substrate.push(address); } }); - return [substrateAddresses, evmAddresses]; + return { + bitcoin, + evm, + substrate, + ton + }; } export function categoryNetworks (networks: NetworkJson[]) { From bb63a99667bab78e59c41c1d1d1b644f30e23c8f Mon Sep 17 00:00:00 2001 From: lw Date: Wed, 31 Jul 2024 11:17:45 +0700 Subject: [PATCH 020/424] [MasterAccount] Update UI for account detail --- .../src/Popup/Account/AccountDetail.tsx | 825 ------------------ .../AccountDetail/AccountAddressList.tsx | 60 ++ .../AccountDetail/DerivedAccountList.tsx | 60 ++ .../src/Popup/Account/AccountDetail/index.tsx | 351 ++++++++ .../extension-koni-ui/src/Popup/router.tsx | 2 +- .../src/components/Layout/base/Base.tsx | 8 +- .../SelectAccount/AccountSelectorModal.tsx | 12 +- .../Layout/parts/SelectAccount/index.tsx | 3 +- .../src/hooks/account/index.ts | 1 + .../hooks/account/useGetAccountProxyById.ts | 17 + .../src/messaging/accounts/edit.ts | 4 +- 11 files changed, 507 insertions(+), 836 deletions(-) delete mode 100644 packages/extension-koni-ui/src/Popup/Account/AccountDetail.tsx create mode 100644 packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx create mode 100644 packages/extension-koni-ui/src/Popup/Account/AccountDetail/DerivedAccountList.tsx create mode 100644 packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx create mode 100644 packages/extension-koni-ui/src/hooks/account/useGetAccountProxyById.ts diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail.tsx deleted file mode 100644 index ea6da5c111..0000000000 --- a/packages/extension-koni-ui/src/Popup/Account/AccountDetail.tsx +++ /dev/null @@ -1,825 +0,0 @@ -// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors -// SPDX-License-Identifier: Apache-2.0 - -import { MantaPayEnableMessage } from '@subwallet/extension-base/background/KoniTypes'; -import { detectTranslate } from '@subwallet/extension-base/utils'; -import { CloseIcon, Layout, PageWrapper, ZkModeFooter } from '@subwallet/extension-koni-ui/components'; -import AccountAvatar from '@subwallet/extension-koni-ui/components/Account/AccountAvatar'; -import { DataContext } from '@subwallet/extension-koni-ui/contexts/DataContext'; -import useDeleteAccount from '@subwallet/extension-koni-ui/hooks/account/useDeleteAccount'; -import useGetAccountByAddress from '@subwallet/extension-koni-ui/hooks/account/useGetAccountByAddress'; -import useGetAccountSignModeByAddress from '@subwallet/extension-koni-ui/hooks/account/useGetAccountSignModeByAddress'; -import { useGetMantaPayConfig } from '@subwallet/extension-koni-ui/hooks/account/useGetMantaPayConfig'; -import useNotification from '@subwallet/extension-koni-ui/hooks/common/useNotification'; -import useUnlockChecker from '@subwallet/extension-koni-ui/hooks/common/useUnlockChecker'; -import useDefaultNavigate from '@subwallet/extension-koni-ui/hooks/router/useDefaultNavigate'; -import { deriveAccountV3, disableMantaPay, editAccount, enableMantaPay, forgetAccount, windowOpen } from '@subwallet/extension-koni-ui/messaging'; -import { RootState } from '@subwallet/extension-koni-ui/stores'; -import { PhosphorIcon, Theme, ThemeProps } from '@subwallet/extension-koni-ui/types'; -import { AccountSignMode } from '@subwallet/extension-koni-ui/types/account'; -import { FormCallbacks, FormFieldData } from '@subwallet/extension-koni-ui/types/form'; -import { toShort } from '@subwallet/extension-koni-ui/utils'; -import { copyToClipboard } from '@subwallet/extension-koni-ui/utils/common/dom'; -import { convertFieldToObject } from '@subwallet/extension-koni-ui/utils/form/form'; -import { BackgroundIcon, Button, Field, Form, Icon, Input, ModalContext, SettingItem, SwAlert, Switch, SwModal } from '@subwallet/react-ui'; -import CN from 'classnames'; -import { CircleNotch, CopySimple, Export, Eye, FloppyDiskBack, GitMerge, QrCode, ShieldCheck, Swatches, Trash, User, Wallet, Warning } from 'phosphor-react'; -import React, { useCallback, useContext, useEffect, useMemo, useReducer, useRef, useState } from 'react'; -import { useTranslation } from 'react-i18next'; -import { useSelector } from 'react-redux'; -import { useNavigate, useParams, useSearchParams } from 'react-router-dom'; -import styled, { useTheme } from 'styled-components'; - -import useIsPopup from '../../hooks/dom/useIsPopup'; - -type Props = ThemeProps; - -enum FormFieldName { - NAME = 'name' -} - -enum ActionType { - EXPORT = 'export', - DERIVE = 'derive', - DELETE = 'delete' -} - -interface DetailFormState { - [FormFieldName.NAME]: string; -} - -interface MantaPayState { - shouldShowConfirmation: boolean, - loading: boolean, - error?: string -} - -const DEFAULT_MANTA_PAY_STATE: MantaPayState = { - shouldShowConfirmation: true, - loading: false -}; - -export enum MantaPayReducerActionType { - INIT = 'INIT', - SET_SHOULD_SHOW_CONFIRMATION = 'SET_SHOULD_SHOW_CONFIRMATION', - CONFIRM_ENABLE = 'CONFIRM_ENABLE', - REJECT_ENABLE = 'REJECT_ENABLE', - SYNC_FAIL = 'SYNC_FAIL', - SET_LOADING = 'SET_LOADING', - SET_ERROR_MESSAGE = 'SET_ERROR_MESSAGE' -} - -interface MantaPayReducerAction { - type: MantaPayReducerActionType, - payload: unknown -} - -export const mantaPayReducer = (state: MantaPayState, action: MantaPayReducerAction): MantaPayState => { - const { payload, type } = action; - - switch (type) { - case MantaPayReducerActionType.INIT: - return DEFAULT_MANTA_PAY_STATE; - case MantaPayReducerActionType.SET_SHOULD_SHOW_CONFIRMATION: - return { - ...state, - shouldShowConfirmation: payload as boolean - }; - case MantaPayReducerActionType.CONFIRM_ENABLE: - return { - ...state, - shouldShowConfirmation: false, - loading: false - }; - case MantaPayReducerActionType.REJECT_ENABLE: - return { - ...state, - shouldShowConfirmation: false - }; - case MantaPayReducerActionType.SYNC_FAIL: - return { - ...state, - shouldShowConfirmation: false - }; - case MantaPayReducerActionType.SET_LOADING: - return { - ...state, - loading: payload as boolean - }; - case MantaPayReducerActionType.SET_ERROR_MESSAGE: - return { - ...state, - error: payload as string, - loading: false - }; - default: - throw new Error("Can't handle action"); - } -}; - -const zkModeConfirmationId = 'zkModeConfirmation'; - -function getZkErrorMessage (error: MantaPayEnableMessage) { - if (error === MantaPayEnableMessage.WRONG_PASSWORD) { - return detectTranslate('Wrong password'); - } else if (error === MantaPayEnableMessage.CHAIN_DISCONNECTED) { - return detectTranslate('Network is disconnected'); - } - - return detectTranslate('Some errors occurred. Please try again later'); -} - -const Component: React.FC = (props: Props) => { - const { className } = props; - - const { t } = useTranslation(); - const navigate = useNavigate(); - const { goHome } = useDefaultNavigate(); - const [searchParams] = useSearchParams(); - const notify = useNotification(); - const { token } = useTheme() as Theme; - const { accountAddress } = useParams(); - const { activeModal, inactiveModal } = useContext(ModalContext); - const dataContext = useContext(DataContext); - - const enableMantaPayConfirm = searchParams.get('enableMantaPayConfirm') === 'true'; - const isPopup = useIsPopup(); - - const [form] = Form.useForm(); - - const account = useGetAccountByAddress(accountAddress); - const deleteAccountAction = useDeleteAccount(); - - const saveTimeOutRef = useRef(); - - const [deleting, setDeleting] = useState(false); - const [deriving, setDeriving] = useState(false); - const [saving, setSaving] = useState(false); - const checkUnlock = useUnlockChecker(); - - const signMode = useGetAccountSignModeByAddress(accountAddress); - - const mantaPayConfig = useGetMantaPayConfig(accountAddress || ''); - const isZkModeEnabled = useMemo(() => { - return !!mantaPayConfig && mantaPayConfig.enabled; - }, [mantaPayConfig]); - const zkModeSyncState = useSelector((state: RootState) => state.mantaPay); - const [mantaPayState, dispatchMantaPayState] = useReducer(mantaPayReducer, DEFAULT_MANTA_PAY_STATE); - - const handleEnableMantaPay = useCallback(() => { - activeModal(zkModeConfirmationId); - }, [activeModal]); - - useEffect(() => { - if (enableMantaPayConfirm && !isZkModeEnabled && !zkModeSyncState.isSyncing) { - handleEnableMantaPay(); - } - }, [enableMantaPayConfirm, handleEnableMantaPay, isZkModeEnabled, zkModeSyncState.isSyncing]); - - const canDerive = useMemo((): boolean => { - if (account) { - if (account.isExternal) { - return false; - } else { - if (account.type === 'ethereum') { - return !!account.isMasterAccount; - } else { - return true; - } - } - } else { - return false; - } - }, [account]); - - // const isZkModeAvailable = useIsMantaPayAvailable(account); - const isZkModeAvailable = false; - - const walletNamePrefixIcon = useMemo((): PhosphorIcon => { - switch (signMode) { - case AccountSignMode.LEGACY_LEDGER: - case AccountSignMode.GENERIC_LEDGER: - return Swatches; - case AccountSignMode.QR: - return QrCode; - case AccountSignMode.READ_ONLY: - return Eye; - case AccountSignMode.INJECTED: - return Wallet; - default: - return User; - } - }, [signMode]); - - const onDelete = useCallback(() => { - if (account?.address) { - deleteAccountAction() - .then(() => { - setDeleting(true); - forgetAccount(account.address) - .then(() => { - goHome(); - }) - .catch((e: Error) => { - notify({ - message: e.message, - type: 'error' - }); - }) - .finally(() => { - setDeleting(false); - }); - }) - .catch((e: Error) => { - if (e) { - notify({ - message: e.message, - type: 'error' - }); - } - }); - } - }, [account?.address, deleteAccountAction, notify, goHome]); - - const onDerive = useCallback(() => { - if (!account?.address) { - return; - } - - checkUnlock().then(() => { - setDeriving(true); - - setTimeout(() => { - deriveAccountV3({ - address: account.address - }).then(() => { - goHome(); - }).catch((e: Error) => { - notify({ - message: e.message, - type: 'error' - }); - }).finally(() => { - setDeriving(false); - }); - }, 500); - }).catch(() => { - // User cancel unlock - }); - }, [account?.address, checkUnlock, goHome, notify]); - - const onExport = useCallback(() => { - if (account?.address) { - navigate(`/accounts/export/${account.address}`); - } - }, [account?.address, navigate]); - - const onCopyAddress = useCallback(() => { - copyToClipboard(account?.address || ''); - notify({ - message: t('Copied to clipboard') - }); - }, [account?.address, notify, t]); - - const onUpdate: FormCallbacks['onFieldsChange'] = useCallback((changedFields: FormFieldData[], allFields: FormFieldData[]) => { - const changeMap = convertFieldToObject(changedFields); - - if (changeMap[FormFieldName.NAME]) { - clearTimeout(saveTimeOutRef.current); - setSaving(true); - saveTimeOutRef.current = setTimeout(() => { - form.submit(); - }, 1000); - } - }, [form]); - - const onSubmit: FormCallbacks['onFinish'] = useCallback((values: DetailFormState) => { - clearTimeout(saveTimeOutRef.current); - const name = values[FormFieldName.NAME]; - - if (!account || name === account.name) { - setSaving(false); - - return; - } - - const address = account.address; - - if (!address) { - setSaving(false); - - return; - } - - editAccount(account.address, name.trim()) - .catch(console.error) - .finally(() => { - setSaving(false); - }); - }, [account]); - - useEffect(() => { - if (!account) { - goHome(); - } - }, [account, goHome, navigate]); - - const onSwitchMantaPay = useCallback((checked: boolean, event: React.MouseEvent) => { - if (checked) { - if (isPopup) { - windowOpen({ - allowedPath: '/accounts/detail', - subPath: account ? `/${account.address}` : undefined, - params: { - enableMantaPayConfirm: 'true' - } - }) - .catch(console.warn); - } else { - handleEnableMantaPay(); - } - } else { - if (!zkModeSyncState.isSyncing) { - disableMantaPay(account?.address as string) - .then((result) => { - if (result) { - dispatchMantaPayState({ type: MantaPayReducerActionType.INIT, payload: undefined }); - notify({ - message: t('ZK assets are hidden as ZK mode is disabled'), - type: 'success', - duration: 3 - }); - } else { - notify({ - message: t('Something went wrong'), - type: 'error' - }); - } - }) - .catch(() => { - notify({ - message: t('Something went wrong'), - type: 'error' - }); - }); - } else { - notify({ - message: t('ZK mode is syncing'), - type: 'warning' - }); - } - } - }, [account, handleEnableMantaPay, isPopup, notify, t, zkModeSyncState.isSyncing]); - - const onCloseZkModeConfirmation = useCallback(() => { - if (!mantaPayState.loading) { - dispatchMantaPayState({ type: MantaPayReducerActionType.REJECT_ENABLE, payload: undefined }); - inactiveModal(zkModeConfirmationId); - } - }, [inactiveModal, mantaPayState.loading]); - - const onOkZkModeConfirmation = useCallback((password: string) => { - dispatchMantaPayState({ type: MantaPayReducerActionType.SET_LOADING, payload: true }); - setTimeout(() => { - enableMantaPay({ address: account?.address as string, password }) - .then((result) => { - if (result.success) { - inactiveModal(zkModeConfirmationId); - dispatchMantaPayState({ type: MantaPayReducerActionType.CONFIRM_ENABLE, payload: undefined }); - } else { - if (result.message !== MantaPayEnableMessage.WRONG_PASSWORD) { - notify({ - type: 'error', - message: t(getZkErrorMessage(result.message)) - }); - } - - dispatchMantaPayState({ type: MantaPayReducerActionType.SET_ERROR_MESSAGE, payload: t(getZkErrorMessage(result.message)) }); - } - }) - .catch((e) => { - console.error(e); - - dispatchMantaPayState({ type: MantaPayReducerActionType.SYNC_FAIL, payload: undefined }); - }); - }, 1000); - }, [account?.address, inactiveModal, notify, t]); - - if (!account) { - return null; - } - - return ( - - { zkModeSyncState.isSyncing &&
} - - , - onClick: goHome, - disabled: deriving || zkModeSyncState.isSyncing - } - ]} - title={t('Account details')} - > -
- {/*
*/} - {/* */} - {/*
*/} -
- value.trim(), - required: true - } - ]} - statusHelpAsTooltip={true} - > - - )} - suffix={( - - )} - /> - -
-
- - )} - suffix={( -
- - { - zkModeSyncState.isSyncing && ( - - ) - } - - { - isZkModeAvailable && ( - - )} - name={t('Zk mode')} - rightItem={( - - )} - />) - } -
- -
- - -
- - - )} - id={zkModeConfirmationId} - maskClosable={false} - title={t('Enable ZK mode?')} - wrapClassName={className} - > -
-
- -
{t('ZK mode requires data synchronization')}
-
- -
- {t('Using the app is not advised until synchronization finishes. First-time synchronization can take up to 45 minutes or longer. Proceed?')} -
-
-
-
- - ); -}; - -const AccountDetail = styled(Component)(({ theme: { token } }: Props) => { - return { - '.account-detail-form': { - marginTop: token.margin - }, - - '.ant-sw-screen-layout-body': { - display: 'flex', - flexDirection: 'column' - }, - - '.zk-mask': { - width: '100%', - height: '100%', - zIndex: 3, - position: 'absolute', - backgroundColor: token.colorBgMask - }, - - '.body-container': { - overflow: 'scroll', - flex: 1, - padding: `0 ${token.padding}px`, - '--wallet-name-icon-bg-color': token['geekblue-6'], - '--wallet-name-icon-color': token.colorWhite, - - '.ant-background-icon': { - width: token.sizeMD, - height: token.sizeMD, - - '.user-name-icon': { - span: { - height: token.sizeSM, - width: token.sizeSM - } - } - }, - - '.account-qr': { - marginTop: token.margin, - marginBottom: token.marginLG, - display: 'flex', - flexDirection: 'row', - justifyContent: 'center' - }, - - '.account-field': { - marginBottom: token.marginXS, - - '.single-icon-only': { - color: token['gray-4'] - }, - - '.ant-input-label': { - marginBottom: token.marginXS - 2 - }, - - '.ant-input-suffix': { - marginRight: 0, - marginLeft: token.marginXS - }, - - '.ant-btn': { - height: 'auto', - marginRight: -(token.marginSM - 2) - } - }, - - '.mb-lg': { - marginBottom: token.marginLG - }, - - '.account-button': { - marginBottom: token.marginXS, - gap: token.sizeXS, - color: token.colorTextLight1, - - '&:disabled': { - color: token.colorTextLight1, - opacity: 0.4 - } - }, - - [`.action-type-${ActionType.DERIVE}`]: { - '--icon-bg-color': token['magenta-7'] - }, - - [`.action-type-${ActionType.EXPORT}`]: { - '--icon-bg-color': token['green-6'] - }, - - [`.action-type-${ActionType.DELETE}`]: { - '--icon-bg-color': token['colorError-6'], - color: token['colorError-6'], - - '.ant-background-icon': { - color: token.colorTextLight1 - }, - - '&:disabled': { - color: token['colorError-6'], - - '.ant-background-icon': { - color: token.colorTextLight1 - } - } - } - }, - - '.account-name-input': { - '.loading': { - color: token['gray-5'], - animation: 'spinner-loading 1s infinite linear' - } - }, - - '.zk-alert-area': { - position: 'relative', - zIndex: 4, - marginTop: token.margin, - marginBottom: token.marginXS - }, - - '.zk-setting': { - position: 'relative', - zIndex: 4, - marginBottom: token.marginXS, - gap: token.sizeXS, - color: token.colorTextLight1, - - '.ant-web3-block .ant-web3-block-right-item': { - marginRight: 0 - } - }, - - '.zk-sync-margin': { - marginTop: token.margin - }, - - '.zk_confirmation_modal__footer': { - display: 'flex', - justifyContent: 'center' - }, - - '.footer__button': { - flexGrow: 1 - }, - - '.zk-warning__title': { - display: 'flex', - flexDirection: 'row', - gap: '8px', - justifyContent: 'center', - fontSize: token.size, - lineHeight: token.lineHeight - }, - - '.zk-warning__title-text': { - color: token.colorWarning, - fontWeight: token.headingFontWeight - }, - - '.zk-warning__subtitle': { - display: 'flex', - justifyContent: 'center', - textAlign: 'justify', - marginTop: token.marginMD, - paddingLeft: token.padding, - paddingRight: token.padding, - fontWeight: token.bodyFontWeight, - color: token.colorTextTertiary - }, - - '.account-detail___action-footer': { - backgroundColor: token.colorBgDefault, - position: 'sticky', - bottom: 0, - left: 0, - width: '100%', - display: 'flex', - gap: token.marginSM, - padding: token.padding, - paddingBottom: '33px', - - button: { - flex: 2 - }, - - 'button:nth-child(1)': { - flex: 1 - } - } - }; -}); - -export default AccountDetail; diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx new file mode 100644 index 0000000000..f498b4fa2c --- /dev/null +++ b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx @@ -0,0 +1,60 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; +import { useTranslation } from '@subwallet/extension-koni-ui/hooks'; +import { ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { SwList } from '@subwallet/react-ui'; +import React, { useCallback, useMemo } from 'react'; +import styled from 'styled-components'; + +type Props = ThemeProps; + +type ItemType = string; + +function Component ({ className }: Props) { + const { t } = useTranslation(); + const items: ItemType[] = useMemo(() => { + return []; + }, []); + + const renderItem = useCallback( + (item: ItemType) => { + return ( +
+ +
+ ); + }, + [] + ); + + const emptyList = useCallback(() => { + return ; + }, []); + + const searchFunction = useCallback( + (item: ItemType, searchText: string) => { + return true; + }, + [] + ); + + return ( + ('Enter network name')} + showActionBtn + /> + ); +} + +export const AccountAddressList = styled(Component)(({ theme: { token } }: Props) => ({ + +})); diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/DerivedAccountList.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/DerivedAccountList.tsx new file mode 100644 index 0000000000..c486a61fe7 --- /dev/null +++ b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/DerivedAccountList.tsx @@ -0,0 +1,60 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; +import { useTranslation } from '@subwallet/extension-koni-ui/hooks'; +import { ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { SwList } from '@subwallet/react-ui'; +import React, { useCallback, useMemo } from 'react'; +import styled from 'styled-components'; + +type Props = ThemeProps; + +type ItemType = string; + +function Component ({ className }: Props) { + const { t } = useTranslation(); + const items: ItemType[] = useMemo(() => { + return []; + }, []); + + const renderItem = useCallback( + (item: ItemType) => { + return ( +
+ +
+ ); + }, + [] + ); + + const emptyList = useCallback(() => { + return ; + }, []); + + const searchFunction = useCallback( + (item: ItemType, searchText: string) => { + return true; + }, + [] + ); + + return ( + ('Enter network name')} + showActionBtn + /> + ); +} + +export const DerivedAccountList = styled(Component)(({ theme: { token } }: Props) => ({ + +})); diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx new file mode 100644 index 0000000000..ad21682328 --- /dev/null +++ b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx @@ -0,0 +1,351 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { CloseIcon, Layout, PageWrapper } from '@subwallet/extension-koni-ui/components'; +import { FilterTabItemType, FilterTabs } from '@subwallet/extension-koni-ui/components/FilterTabs'; +import { useGetAccountProxyById } from '@subwallet/extension-koni-ui/hooks'; +import useNotification from '@subwallet/extension-koni-ui/hooks/common/useNotification'; +import useDefaultNavigate from '@subwallet/extension-koni-ui/hooks/router/useDefaultNavigate'; +import { editAccount } from '@subwallet/extension-koni-ui/messaging'; +import { ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { FormCallbacks, FormFieldData } from '@subwallet/extension-koni-ui/types/form'; +import { convertFieldToObject } from '@subwallet/extension-koni-ui/utils/form/form'; +import { Button, Form, Icon, Input } from '@subwallet/react-ui'; +import CN from 'classnames'; +import { CircleNotch, Export, FloppyDiskBack, GitMerge, Trash } from 'phosphor-react'; +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useNavigate, useParams } from 'react-router-dom'; +import styled from 'styled-components'; + +import { AccountAddressList } from './AccountAddressList'; +import { DerivedAccountList } from './DerivedAccountList'; + +type Props = ThemeProps; + +enum FormFieldName { + NAME = 'name' +} + +// @ts-ignore +enum ActionType { + EXPORT = 'export', + DERIVE = 'derive', + DELETE = 'delete' +} + +enum FilterTabType { + ACCOUNT_ADDRESS = 'account-address', + DERIVED_ACCOUNT = 'derived-account', +} + +interface DetailFormState { + [FormFieldName.NAME]: string; +} + +const showDerivedAccounts = false; + +const Component: React.FC = (props: Props) => { + const { className } = props; + + const { t } = useTranslation(); + const navigate = useNavigate(); + const { goHome } = useDefaultNavigate(); + const notify = useNotification(); + const { accountProxyId } = useParams(); + + const [selectedFilterTab, setSelectedFilterTab] = useState(FilterTabType.ACCOUNT_ADDRESS); + + const [form] = Form.useForm(); + + const accountProxy = useGetAccountProxyById(accountProxyId); + + const saveTimeOutRef = useRef(); + + // @ts-ignore + const [deleting, setDeleting] = useState(false); + // @ts-ignore + const [deriving, setDeriving] = useState(false); + const [saving, setSaving] = useState(false); + + const filterTabItems = useMemo(() => { + const result = [ + { + label: t('Account address'), + value: FilterTabType.ACCOUNT_ADDRESS + } + ]; + + if (showDerivedAccounts) { + result.push({ + label: t('Derived account'), + value: FilterTabType.DERIVED_ACCOUNT + }); + } + + return result; + }, [t]); + + const onSelectFilterTab = useCallback((value: string) => { + setSelectedFilterTab(value); + }, []); + + const onDelete = useCallback(() => { + // + }, []); + + const onDerive = useCallback(() => { + // + }, []); + + const onExport = useCallback(() => { + // + }, []); + + // @ts-ignore + const onCopyAddress = useCallback(() => { + notify({ + message: t('Copied to clipboard') + }); + }, [notify, t]); + + const onUpdate: FormCallbacks['onFieldsChange'] = useCallback((changedFields: FormFieldData[], allFields: FormFieldData[]) => { + const changeMap = convertFieldToObject(changedFields); + + if (changeMap[FormFieldName.NAME]) { + clearTimeout(saveTimeOutRef.current); + setSaving(true); + saveTimeOutRef.current = setTimeout(() => { + form.submit(); + }, 1000); + } + }, [form]); + + const onSubmit: FormCallbacks['onFinish'] = useCallback((values: DetailFormState) => { + clearTimeout(saveTimeOutRef.current); + const name = values[FormFieldName.NAME]; + + if (!accountProxy || name === accountProxy.name) { + setSaving(false); + + return; + } + + const accountProxyId = accountProxy.id; + + if (!accountProxyId) { + setSaving(false); + + return; + } + + editAccount(accountProxyId, name.trim()) + .catch(console.error) + .finally(() => { + setSaving(false); + }); + }, [accountProxy]); + + const footerNode = (() => { + return <> + + + ; + })(); + + useEffect(() => { + if (!accountProxy) { + goHome(); + } + }, [accountProxy, goHome, navigate]); + + if (!accountProxy) { + return null; + } + + return ( + + , + onClick: goHome, + disabled: false + } + ]} + title={t('Account details')} + > +
+ value.trim(), + required: true + } + ]} + statusHelpAsTooltip={true} + > + + )} + /> + +
+ + +
+ { + selectedFilterTab === FilterTabType.ACCOUNT_ADDRESS && ( + + ) + } + { + selectedFilterTab === FilterTabType.DERIVED_ACCOUNT && ( + + ) + } +
+
+
+ ); +}; + +const AccountDetail = styled(Component)(({ theme: { token } }: Props) => { + return { + '.ant-sw-screen-layout-body': { + display: 'flex', + overflow: 'hidden', + flexDirection: 'column' + }, + + '.ant-sw-screen-layout-footer': { + paddingTop: token.paddingSM, + paddingBottom: 24 + }, + + '.ant-sw-screen-layout-footer-content': { + display: 'flex', + gap: token.sizeSM + }, + + '.account-detail-form': { + paddingTop: token.padding, + paddingLeft: token.padding, + paddingRight: token.padding + }, + + '.account-detail-form .ant-form-item': { + marginBottom: 0 + }, + + '.account-name-input .ant-input-suffix .anticon': { + minWidth: 40, + justifyContent: 'center' + }, + + '.list-container': { + flex: 1, + overflow: 'hidden' + }, + + '.ant-sw-list-section': { + height: '100%' + }, + + '.ant-sw-list': { + paddingBottom: 0 + }, + + '.filter-tabs-container': { + gap: 0, + paddingLeft: token.paddingXXS, + paddingRight: token.paddingXXS, + + '.__tab-item:after': { + display: 'none' + }, + + '.__tab-item-label': { + padding: token.paddingSM, + lineHeight: '20px', + fontSize: '11px', + textTransform: 'uppercase' + } + } + }; +}); + +export default AccountDetail; diff --git a/packages/extension-koni-ui/src/Popup/router.tsx b/packages/extension-koni-ui/src/Popup/router.tsx index 6e1a1f1883..f9d7670a6a 100644 --- a/packages/extension-koni-ui/src/Popup/router.tsx +++ b/packages/extension-koni-ui/src/Popup/router.tsx @@ -270,7 +270,7 @@ export const router = createHashRouter([ ConnectPolkadotVault.generateRouterObject('connect-polkadot-vault'), ConnectKeystone.generateRouterObject('connect-keystone'), ConnectLedger.generateRouterObject('connect-ledger'), - AccountDetail.generateRouterObject('detail/:accountAddress'), + AccountDetail.generateRouterObject('detail/:accountProxyId'), AccountExport.generateRouterObject('export/:accountAddress'), ExportAllDone.generateRouterObject('export-all-done') ] diff --git a/packages/extension-koni-ui/src/components/Layout/base/Base.tsx b/packages/extension-koni-ui/src/components/Layout/base/Base.tsx index 1dce214d05..97b4b406b1 100644 --- a/packages/extension-koni-ui/src/components/Layout/base/Base.tsx +++ b/packages/extension-koni-ui/src/components/Layout/base/Base.tsx @@ -20,20 +20,17 @@ import { useLocation, useNavigate } from 'react-router-dom'; import styled from 'styled-components'; import { useLocalStorage } from 'usehooks-ts'; -import Footer from '../parts/Footer'; - export interface LayoutBaseProps extends Omit< SwScreenLayoutProps, -'tabBarItems' | 'footer' | 'headerContent' | 'selectedTabBarItem' +'tabBarItems' | 'headerContent' | 'selectedTabBarItem' >, ThemeProps { children: React.ReactNode | React.ReactNode[]; - showFooter?: boolean; isDisableHeader?: boolean; } type TabBarItem = Omit & { url: string }; const specialLanguages: Array = ['ja', 'ru']; -const Component = ({ children, className, headerIcons, isDisableHeader, onBack, showFooter, ...props }: LayoutBaseProps) => { +const Component = ({ children, className, headerIcons, isDisableHeader, onBack, ...props }: LayoutBaseProps) => { const navigate = useNavigate(); const { goHome } = useDefaultNavigate(); const { pathname } = useLocation(); @@ -146,7 +143,6 @@ const Component = ({ children, className, headerIcons, isDisableHeader, onBack, } headerContent={props.showHeader && } headerIcons={headerIcons} onBack={onBack || defaultOnBack} diff --git a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx index 705cb1fdce..8556c99cc5 100644 --- a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx +++ b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx @@ -187,6 +187,15 @@ const Component: React.FC = ({ className }: Props) => { }; }, [accountProxies, inactiveModal, location.pathname, navigate, goHome]); + const onViewAccountDetail = useCallback((accountProxy: AccountProxy) => { + return () => { + inactiveModal(modalId); + setTimeout(() => { + navigate(`/accounts/detail/${accountProxy.id}`); + }, 100); + }; + }, [inactiveModal, navigate]); + const renderItem = useCallback((item: ListItem): React.ReactNode => { if ((item as ListItemGroupLabel).groupLabel) { return ( @@ -223,9 +232,10 @@ const Component: React.FC = ({ className }: Props) => { isSelected={item.id === currentAccountProxy?.id} key={item.id} onClick={onSelect(item as AccountProxy)} + onClickMoreButton={onViewAccountDetail(item as AccountProxy)} /> ); - }, [onSelect, currentAccountProxy?.id, showAllAccount]); + }, [currentAccountProxy?.id, onSelect, onViewAccountDetail, showAllAccount]); const handleSearch = useCallback((value: string) => { setSearchValue(value); diff --git a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/index.tsx b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/index.tsx index f544e9b7df..0ddd9fd87e 100644 --- a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/index.tsx +++ b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/index.tsx @@ -347,7 +347,8 @@ const SelectAccount = styled(Component)(({ theme }) => { display: 'flex', flexDirection: 'row', alignItems: 'center', - gap: 8 + gap: 8, + cursor: 'pointer' }, '.connect-icon': { diff --git a/packages/extension-koni-ui/src/hooks/account/index.ts b/packages/extension-koni-ui/src/hooks/account/index.ts index 6dfad4d131..abd6aa00f8 100644 --- a/packages/extension-koni-ui/src/hooks/account/index.ts +++ b/packages/extension-koni-ui/src/hooks/account/index.ts @@ -16,6 +16,7 @@ export { default as useHandleMantaPaySync } from './useHandleMantaPaySync'; export { default as useIsReadOnlyAccount } from './useIsReadOnlyAccount'; export { default as usePreCheckAction } from './usePreCheckAction'; export { default as useSetSelectedAccountTypes } from './useSetSelectedAccountTypes'; +export { default as useGetAccountProxyById } from './useGetAccountProxyById'; export * from './useGetMantaPayConfig'; export * from './useGetZkAddress'; diff --git a/packages/extension-koni-ui/src/hooks/account/useGetAccountProxyById.ts b/packages/extension-koni-ui/src/hooks/account/useGetAccountProxyById.ts new file mode 100644 index 0000000000..cbc3855ed1 --- /dev/null +++ b/packages/extension-koni-ui/src/hooks/account/useGetAccountProxyById.ts @@ -0,0 +1,17 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { AccountProxy } from '@subwallet/extension-base/types'; +import { RootState } from '@subwallet/extension-koni-ui/stores'; +import { useMemo } from 'react'; +import { useSelector } from 'react-redux'; + +const useGetAccountProxyById = (id?: string): AccountProxy | null => { + const accountProxies = useSelector((state: RootState) => state.accountState.accountProxies); + + return useMemo((): AccountProxy | null => { + return accountProxies.find((ap) => ap.id === id) || null; + }, [accountProxies, id]); +}; + +export default useGetAccountProxyById; diff --git a/packages/extension-koni-ui/src/messaging/accounts/edit.ts b/packages/extension-koni-ui/src/messaging/accounts/edit.ts index 5d4faf0ba5..798ffa81b5 100644 --- a/packages/extension-koni-ui/src/messaging/accounts/edit.ts +++ b/packages/extension-koni-ui/src/messaging/accounts/edit.ts @@ -3,8 +3,8 @@ import { sendMessage } from '../base'; -export async function editAccount (address: string, name: string): Promise { - return sendMessage('pri(accounts.edit)', { proxyId: address, name }); +export async function editAccount (proxyId: string, name: string): Promise { + return sendMessage('pri(accounts.edit)', { proxyId, name }); } export async function forgetAccount (address: string, lockAfter = false): Promise { From 08566d3f1c42e9d7cf650fc31d5516eb5e766df3 Mon Sep 17 00:00:00 2001 From: lw Date: Wed, 31 Jul 2024 11:33:38 +0700 Subject: [PATCH 021/424] [MasterAccount] Update AccountProxySelectorItem --- .../AccountProxy/AccountProxySelectorItem.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx index 4f050a54fb..812dd3e773 100644 --- a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx +++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx @@ -167,7 +167,6 @@ function Component (props: Props): React.ReactElement { ) }
{accountProxy.name}
-
{accountProxy.name}
+
+ { + accountProxy.networkTypes.map((nt) => { + return ( + Network type + ); + }) + } +
@@ -276,10 +298,20 @@ const AccountProxySelectorItem = styled(Component)(({ theme }) => { overflow: 'hidden', 'white-space': 'nowrap' }, - '.__item-networks': { - fontSize: token.fontSizeSM, - color: token.colorTextLight4, - lineHeight: '18px' + '.__item-network-types': { + display: 'flex', + paddingTop: 2 + }, + '.__item-network-type-item': { + display: 'block', + boxShadow: '-4px 0px 4px 0px rgba(0, 0, 0, 0.40)', + width: token.size, + height: token.size, + borderRadius: '100%', + marginLeft: -token.marginXXS + }, + '.__item-network-type-item:first-of-type': { + marginLeft: 0 }, '.__item-address': { fontSize: token.fontSizeSM, diff --git a/packages/extension-koni/public/images/projects/ton.png b/packages/extension-koni/public/images/projects/ton.png new file mode 100644 index 0000000000000000000000000000000000000000..be62055abbe55d7ecc8da69e8f633c0cd50bdecc GIT binary patch literal 3882 zcmV+_57qFAP)005u}1^@s6i_d2*00009a7bBm000ZH z000ZH0U9_EasU7T0drDELIAGL9O(c600d`2O+f$vv5yP*p~+%g-v%?}IXAr@sG4Ktun0WA6{r z_d?&oC!qAb($9s|&zp7q*&1+sw+;(u8sG^6Tw?uh8J>>^ASWvN7aeGE%|I-qT(PCiJ~^BFl-Y>whl_^X8r~H{rsmI#`H3 z0{ryf6%b=pkm9UPT~%T_^Z*nkicyPFy{^G0KiLEeFjs(>PIso~^e5DUgE$ULTv7y8-|rLSOG@qc6v!qE*62Ykt;B{y)wvI^WX#+MLoH$|B3(@iy3S* zlrRXQv0mv0i_Zl_0Hujr@Wq2A7y!jaKuozWr!VVA^T4>shEBB_9s9VpXc;1!u+#foN%!CJV)qp zf9YDJg`DIU;LA7I<705IOl8mc$VEN@e(^|qLTU~eCT1Q!yPs>di#`VY^kD@`a0?iw z9o3wr))>+vAm;j#x&{o>30!(5jt6N1#KHm)0WeHQM4-omq$RuTDVS3)lNCZL&K?0d z^)gwBYd``MZ5 z83lU_5H}GqOfE_nd)YGG1<28l=?9F0xc9pY-37?ekLj1V@xamFKJq(jkE$H~m;$Iq z8`O@VO9Tw(fnkaO`~DpDt&Xp*KQ6<|-N(Q%MbO2P=^O!fcDU4vDUL3ak+IG{Fm@hg zYYV}fgW29}GL2U{th}`6ceFPdxzhgf;S_9m`Ylfin46h|v!}Q9@n z^367E{Octc3AS9u&Fv{VFDbhg%S$tik$xbge4_o8lBE%NVZM1&EFCSJ+GM`a=%O6eyLkBNd<3xzF zVLWalMeC<~9ag~*=7I?pU!No*G-}v_XT79o6`&MVFaW%2FaPQdVEP9|xbzEyE@aW# zCAU33zYhj*QO|UF%vT(XKR*^t}%rOoG7@fT)0vItE{TAOl228OmePl=!#BpGx zwU`3|N@+x2KXa~Bx2T>TH)t$aswR&PjOY+5CY+meUK^@ZZtK;6K`%?q=pjMY8Kr5T zCt?1lQ*h|Ywu3c#S*sJ;n7#*1U|Z_kFZ zEQVvd%fHM%S$qHOF)#vkaI9|X5()ztF*xy{q={jP&s47b^98JYyPf&{6;lK#%(E?SA&z<3-PF12OthR*Z})SQTOh?_vQ8IRl1pbL&;+_oDbHHiS#ygpInoLAkgG zjtbA2ySg^llbz&O^n0tvgj0T@QKxrX5IBkQwo zf)8Nyqpp|Zijk3o&9a21FfIZjI2NS%RyZE=p^WR=Z{H%lA0wZ!D@L-U1-R$OmwS>W5Kwb-@R5HIJ}_PE;#X6CjQ?I9j!g%1&9&w`dz=xX}q8=634eIri%{|N()da zqXmdu`uj7|gakKcyJX9t?Lso0wc%`}?Q#hDmW(!u7!HnOR`1XT)2^7)d2E++fBipL zfeKGbR3TUZ+A@@KEmzEGs_AUB?Q)p1HKX;&mdRmG+ic6=MMQ~yc!8R2yBtR1KoBee zuWpJh6PeQ%+cN7_+Um~gcZS<8?Fcy|Ayg;9BJ$WWHby~etsh1|Beq-;vCc5V2zZq+ z!$a{I)f*)vWYgIO+oc0mI<|{MTL$;f+GI{+TRKYg!=Z^Cw##9pNwt7kLGe*-nf2-k zumQYKu!8{w+a@0SD2ryn?YL^oP)%pcY?oGq#R9}AxKN`RuBMyQRMXi;+oc_=SM6~^ zLa}8q3R3pb4jZcJj1v#ryF*xCHgf6fXQcNp8QN(dTM|>FpRE&*G}a3c7v5J1{+Frd zG_@u1rLSrGW=zG2!a1yaqu4U0nbTC$86)5IdiD}ElW{_T)bf4P%xSvmZ1=r`82)JH*3H<(B3y?5M+euz^7%wx-p(wxp?yI9)~ z@CamdnzchvyDD7%^=P7C9@E(c+oc`c7yJYqg4$I9$AP2R&`#YrWo&nY{-`^7)Ht=P z!mu~AqwRtlr?O)8dT$S$6kr}(W|-zQ#de9eBDgj2NaLgc5o%Y3VVToZ(|I+j`f>I& zfQAGi?}DRH#)89&f|TfIMR$XKP~j72BOpTUsxas%NR58Bmf2I#0t}s+1-C=#sxas% zNQr)U5RZ$tOB)U6e86_7T@?n^+=v?e=4)GT6;Rrh&p%zwW~tE9TfEP~H!80hfOx`F+5ufAhy+^Zf zrm=Tep}GeiLG7wQje^06Qs!b)?#*u=Y7fTj3}kK{QNu?W1hUDAj!vj1WMj*r*DW2jvf`o*>G2DzBp zNkzbglMUajn0BaL74qU@cY_?%(F4Q>2h%m-ZyH9ZT@~`;Vs`^FDc2?C7x+67Nmv+g z6|&d1OADfwJUS4d@;d?|)UFCt9PMsEC#AJi1Z>uTA$L{Cia%xc84zIy0b)^t;~SK+ zFbG@5_3j2l>gfWQ)-@xcZURH@s?ZB>t6e&w!rSSmtpW^H4VZ|c#)8gwH=v@RmVVkQ zz%f|^CW6{k;VAqov+sd=T}wYb+=pWA;bS~P37Dvy{?^AQbGPfj?gmw!`KGDEAKy8X zexXC%kopRk2x?b_cD(3rK%>_FLI(kg8Zi4%4@FF1+ob~v4oz|o3vg=uIxzcCyDA`F zbvK|ewS7oihXsg*2^|T3 zuXcRzvB?cy6=?;__i-(^+juZ}57U7T=@;oNz$gv#Y`C37VA$T{wtkFYR7AT4D``IX z^J7lEo!RJ=evvNScQ9nC^T4!#0%LoHh-zLv>Ra6%*3Tc^&_7)ThRM$%^EplT4XivF zVfsb8SlzzeJp!&jF2m05U0#}Fa?&;WA>AWjJQ-O9hRH*Z=!f)PW#=f!70ocvgmYQnnq7bwepJ(6c|yYUAY6q{ z-pRbhmv$P<(qyEK`1fCcvnNj937M=>(?UBi4M6f_@$qreYCZ0)|PW znk$sln~?u-+_eWAAOsgHFvy0U_2$Zq`A_7VnppI`qZSjP$9>zmGh%)L;&?D@o&%ng z_)J}=-dXCnFHQgF)30p>AWGV#h5#6!h{f0EK}Y=y5MdGeMj_%uiaC`z>a3+d5T|4J z!Et{<;zNo%792m&^+p|TUFIY?pZfEVmvbJcJfN_UVd%u7B@f9eT z!3Yrf^kD@`a1D4|Xgl?2^((FgD4gO_a69OVV@l=%28#(-wa53tpu~p^E&`_cQb)s( zqoFlKO@zeqAcdDO904Y*J)GBnBaRINV9Y~_Mzp3ofU(|D3|D{&EJU+F;bFR+dVZy! zRgFB1Mt}({#LVT{)cGX$8h zezy!e({uU}M#i(i6o&!Pt`lYnFwMRgRaHku6k`BPcJ?Eks70;O3=&-$a|PHA8rwo> zF@`9}_kji3N-Q`X|j))$lWm=%hr sq5sZCZ2ZdjaU?K(FPjZpqgft)0MY(I{361?djJ3c07*qoM6N<$g2zBaA^-pY literal 0 HcmV?d00001 From 3a3b39d72a907ca90e8fb8beb01023152452abb4 Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Wed, 31 Jul 2024 15:45:16 +0700 Subject: [PATCH 023/424] [Issue-3384] refactor: hide tonApi api object --- .../balance-service/helpers/subscribe/ton.ts | 2 +- .../balance-service/helpers/subscribe/ton/utils.ts | 4 ++-- .../src/services/chain-service/handler/TonApi.ts | 12 ++++++++++-- .../src/services/chain-service/types.ts | 9 ++++++--- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts index 712812191d..c8692bdbb2 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts @@ -70,7 +70,7 @@ async function getTonBalance (addresses: string[], tonApi: _TonApi): Promise, tonApi: _TonApi, ownerAddress: string) { @@ -21,7 +21,7 @@ export async function getJettonWalletContract (jettonMasterContract: OpenedContr await sleep(1500); - return tonApi.api.open(JettonWallet.create(jettonWalletAddress)); + return tonApi.open(JettonWallet.create(jettonWalletAddress)); } // export async function getTonClient (isTestnet = false) { diff --git a/packages/extension-base/src/services/chain-service/handler/TonApi.ts b/packages/extension-base/src/services/chain-service/handler/TonApi.ts index 5b82e6810f..5bd81ff17d 100644 --- a/packages/extension-base/src/services/chain-service/handler/TonApi.ts +++ b/packages/extension-base/src/services/chain-service/handler/TonApi.ts @@ -4,12 +4,12 @@ import { _ApiOptions } from '@subwallet/extension-base/services/chain-service/handler/types'; import { _ChainConnectionStatus, _TonApi } from '@subwallet/extension-base/services/chain-service/types'; import { createPromiseHandler, PromiseHandler } from '@subwallet/extension-base/utils'; -import { TonClient } from '@ton/ton'; +import { Address, Contract, OpenedContract, TonClient } from '@ton/ton'; import { BehaviorSubject } from 'rxjs'; export class TonApi implements _TonApi { chainSlug: string; - api: TonClient; + private api: TonClient; apiUrl: string; apiError?: string; apiRetry = 0; @@ -121,4 +121,12 @@ export class TonApi implements _TonApi { this.isReadyHandler = createPromiseHandler<_TonApi>(); } } + + async getBalance (address: Address): Promise { + return await this.api.getBalance(address); + } + + open (src: T): OpenedContract { + return this.api.open(src); + } } diff --git a/packages/extension-base/src/services/chain-service/types.ts b/packages/extension-base/src/services/chain-service/types.ts index 47baba4389..443dc01060 100644 --- a/packages/extension-base/src/services/chain-service/types.ts +++ b/packages/extension-base/src/services/chain-service/types.ts @@ -5,6 +5,7 @@ import { _AssetRef, _AssetType, _ChainAsset, _ChainInfo, _CrowdloanFund } from '@subwallet/chain-list/types'; import { _CHAIN_VALIDATION_ERROR } from '@subwallet/extension-base/services/chain-service/handler/types'; +import { Address, Contract, OpenedContract } from '@ton/ton'; import { BehaviorSubject } from 'rxjs'; import Web3 from 'web3'; @@ -12,7 +13,6 @@ import { ApiPromise } from '@polkadot/api'; import { SubmittableExtrinsicFunction } from '@polkadot/api/promise/types'; import { ChainProperties, ChainType } from '@polkadot/types/interfaces'; import { Registry } from '@polkadot/types/types'; -import {TonClient} from "@ton/ton"; export interface _DataMap { chainInfoMap: Record, @@ -106,11 +106,14 @@ export interface _EvmApi extends _ChainBaseApi { isReady: Promise<_EvmApi>; } -export interface _TonApi extends _ChainBaseApi { - api: TonClient; +export interface _TonApi extends _ChainBaseApi, _TonUtilsApi { isReady: Promise<_TonApi>; } +export interface _TonUtilsApi { + getBalance (address: Address): Promise; + open(src: T): OpenedContract; +} export type _NetworkUpsertParams = { mode: 'update' | 'insert', chainEditInfo: { From f4853913155dacd3caf9a3193c48e560c8f34a76 Mon Sep 17 00:00:00 2001 From: lw Date: Wed, 31 Jul 2024 16:14:20 +0700 Subject: [PATCH 024/424] [MasterAccount] Update AccountNetworkAddressItem --- .../AccountNetworkAddressItem.tsx | 150 ++++++++++++++++++ .../src/components/AccountProxy/index.ts | 1 + .../extension-koni-ui/src/components/index.ts | 1 + .../extension-koni-ui/src/types/account.ts | 6 + 4 files changed, 158 insertions(+) create mode 100644 packages/extension-koni-ui/src/components/AccountProxy/AccountNetworkAddressItem.tsx diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountNetworkAddressItem.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountNetworkAddressItem.tsx new file mode 100644 index 0000000000..761989fa85 --- /dev/null +++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountNetworkAddressItem.tsx @@ -0,0 +1,150 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { AccountNetworkAddress, ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { toShort } from '@subwallet/extension-koni-ui/utils'; +import { Button, Icon, Logo } from '@subwallet/react-ui'; +import CN from 'classnames'; +import { Copy, QrCode } from 'phosphor-react'; +import React from 'react'; +import styled from 'styled-components'; + +type Props = ThemeProps & { + item: AccountNetworkAddress; + onClickCopyButton?: VoidFunction; + onClickQrButton?: VoidFunction; +} + +function Component (props: Props): React.ReactElement { + const { className, + item, + onClickCopyButton, onClickQrButton } = props; + + const _onClickCopyButton: React.MouseEventHandler = React.useCallback((event) => { + event.stopPropagation(); + onClickCopyButton?.(); + }, [onClickCopyButton]); + + const _onClickQrButton: React.MouseEventHandler = React.useCallback((event) => { + event.stopPropagation(); + onClickQrButton?.(); + }, [onClickQrButton]); + + return ( + <> +
+
+ +
+ +
+
+ {item.name} +
+
+ {toShort(item.address, 4, 5)} +
+
+ +
+
+
+ + ); +} + +const AccountProxySelectorItem = styled(Component)(({ theme: { token } }: Props) => { + return { + background: token.colorBgSecondary, + paddingLeft: token.paddingSM, + paddingRight: token.paddingXXS, + paddingTop: 6, + paddingBottom: 6, + borderRadius: token.borderRadiusLG, + alignItems: 'center', + display: 'flex', + flexDirection: 'row', + cursor: 'pointer', + transition: `background ${token.motionDurationMid} ease-in-out`, + gap: token.sizeXXS, + overflowX: 'hidden', + minHeight: 52, + + '.__item-center-part': { + display: 'flex', + overflowX: 'hidden', + 'white-space': 'nowrap', + gap: token.sizeXXS, + flex: 1, + alignItems: 'center' + }, + + '.__item-network-name': { + fontSize: token.fontSize, + lineHeight: token.lineHeight, + color: token.colorTextLight1, + overflow: 'hidden', + textOverflow: 'ellipsis' + }, + + '.__item-address': { + fontSize: token.fontSizeSM, + lineHeight: token.lineHeightSM, + color: token.colorTextLight4 + }, + + '.__item-right-part': { + display: 'flex' + + }, + + '.-show-on-hover': { + opacity: 0, + transition: `opacity ${token.motionDurationMid} ease-in-out` + }, + '.-hide-on-hover': { + opacity: 1, + transition: `opacity ${token.motionDurationMid} ease-in-out` + }, + + '&:hover': { + background: token.colorBgInput, + '.-hide-on-hover': { + opacity: 0 + }, + '.-show-on-hover': { + opacity: 1 + } + } + }; +}); + +export default AccountProxySelectorItem; diff --git a/packages/extension-koni-ui/src/components/AccountProxy/index.ts b/packages/extension-koni-ui/src/components/AccountProxy/index.ts index 3c9311b72a..87d42a649b 100644 --- a/packages/extension-koni-ui/src/components/AccountProxy/index.ts +++ b/packages/extension-koni-ui/src/components/AccountProxy/index.ts @@ -7,3 +7,4 @@ export { default as AccountProxySelectorAllItem } from './AccountProxySelectorAl export { default as AccountProxyItem } from './AccountProxyItem'; export { default as AccountProxyAvatar } from './AccountProxyAvatar'; export { default as AccountProxyAvatarGroup } from './AccountProxyAvatarGroup'; +export { default as AccountNetworkAddressItem } from './AccountNetworkAddressItem'; diff --git a/packages/extension-koni-ui/src/components/index.ts b/packages/extension-koni-ui/src/components/index.ts index 3ea854c13c..472525705a 100644 --- a/packages/extension-koni-ui/src/components/index.ts +++ b/packages/extension-koni-ui/src/components/index.ts @@ -16,6 +16,7 @@ export { default as NetworkTag } from './NetworkTag'; export * from '../contexts'; export * from './Common'; +// todo: will merge Account and AccountProxy folder export * from './Account'; export * from './AccountProxy'; export * from './Avatar'; diff --git a/packages/extension-koni-ui/src/types/account.ts b/packages/extension-koni-ui/src/types/account.ts index c2bcdc1916..89ab8bd44c 100644 --- a/packages/extension-koni-ui/src/types/account.ts +++ b/packages/extension-koni-ui/src/types/account.ts @@ -29,3 +29,9 @@ export enum AccountSignMode { INJECTED = 'injected', UNKNOWN = 'unknown' } + +export type AccountNetworkAddress = { + name: string; + slug: string; + address: string; +} From 6b9e918ffb8aae27f8a9ac9d67974a9fa5c16fa4 Mon Sep 17 00:00:00 2001 From: S2kael Date: Wed, 31 Jul 2024 17:09:31 +0700 Subject: [PATCH 025/424] [Issue-3396] Fix change account not compute balance --- .../balance-service/BalanceMapImpl.ts | 21 +++++++++++-------- .../src/services/balance-service/index.ts | 12 ++++++----- .../keyring-service/account-context.ts | 7 +++++++ 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/packages/extension-base/src/services/balance-service/BalanceMapImpl.ts b/packages/extension-base/src/services/balance-service/BalanceMapImpl.ts index d9d99e1fa3..3f7ab597a6 100644 --- a/packages/extension-base/src/services/balance-service/BalanceMapImpl.ts +++ b/packages/extension-base/src/services/balance-service/BalanceMapImpl.ts @@ -34,9 +34,9 @@ export class BalanceMapImpl { this.triggerChange(); } - public triggerChange (computeAll?: boolean): void { - if (computeAll) { - this.computeAllAccountBalance(); + public triggerChange (proxyId?: string): void { + if (proxyId) { + this.computeBalance(proxyId); } this._mapSubject.next(this._map); @@ -54,12 +54,12 @@ export class BalanceMapImpl { trigger && this.triggerChange(); } - public updateBalanceItems (balanceItems: BalanceItem[], computeAll?: boolean): void { + public updateBalanceItems (balanceItems: BalanceItem[], proxyId?: string): void { balanceItems.forEach((balanceItem) => { this.updateBalanceItem(balanceItem); }); - this.triggerChange(computeAll); + this.triggerChange(proxyId); } public removeBalanceItemByFilter (filter: (balanceItem: BalanceItem) => boolean): void { @@ -74,7 +74,8 @@ export class BalanceMapImpl { this.triggerChange(); } - public computeAllAccountBalance () { + public computeBalance (_proxyId: string): void { + const isAll = isAccountAll(_proxyId); const compoundMap: Record> = {}; const accountProxies = this.state.keyringService.context.accounts; const unifiedAccountsMap = Object.values(accountProxies) @@ -86,8 +87,10 @@ export class BalanceMapImpl { }, {}); const revertUnifiedAccountsMap = Object.entries(unifiedAccountsMap) .reduce>((rs, [proxyId, accounts]) => { - for (const account of accounts) { - rs[account] = proxyId; + if (isAll || proxyId === _proxyId) { + for (const account of accounts) { + rs[account] = proxyId; + } } return rs; @@ -112,9 +115,9 @@ export class BalanceMapImpl { compoundMap[key] = unifiedAccountBalance; }; - addItemToMap(ALL_ACCOUNT_KEY); const proxyId = revertUnifiedAccountsMap[address]; + isAll && addItemToMap(ALL_ACCOUNT_KEY); proxyId && addItemToMap(proxyId); }); diff --git a/packages/extension-base/src/services/balance-service/index.ts b/packages/extension-base/src/services/balance-service/index.ts index 169d2f1f86..8fcae04ebc 100644 --- a/packages/extension-base/src/services/balance-service/index.ts +++ b/packages/extension-base/src/services/balance-service/index.ts @@ -76,7 +76,7 @@ export class BalanceService implements StoppableServiceInterface { async loadData () { const backupBalanceData = await this.state.dbService.getStoredBalance(); - this.balanceMap.updateBalanceItems(backupBalanceData, true); + this.balanceMap.updateBalanceItems(backupBalanceData, ALL_ACCOUNT_KEY); } /** Start service */ @@ -311,12 +311,14 @@ export class BalanceService implements StoppableServiceInterface { } addLazy('updateBalanceStore', () => { - const isAllAccount = isAccountAll(this.state.keyringService.context.currentAccount.proxyId); + const proxyId = this.state.keyringService.context.currentAccount.proxyId; + const isUnifiedAccount = this.state.keyringService.context.isUnifiedAccount(proxyId); + const isAll = isAccountAll(proxyId); - this.balanceMap.updateBalanceItems(this.balanceUpdateCache, isAllAccount); + this.balanceMap.updateBalanceItems(this.balanceUpdateCache, isUnifiedAccount || isAll ? proxyId : undefined); - if (isAllAccount) { - this.balanceUpdateCache = [...this.balanceUpdateCache, ...Object.values(this.balanceMap.map[ALL_ACCOUNT_KEY])]; + if (isUnifiedAccount || isAll) { + this.balanceUpdateCache = [...this.balanceUpdateCache, ...Object.values(this.balanceMap.map[proxyId])]; } this.updateBalanceStore(this.balanceUpdateCache); diff --git a/packages/extension-base/src/services/keyring-service/account-context.ts b/packages/extension-base/src/services/keyring-service/account-context.ts index 1291ebb576..6790709a11 100644 --- a/packages/extension-base/src/services/keyring-service/account-context.ts +++ b/packages/extension-base/src/services/keyring-service/account-context.ts @@ -292,6 +292,13 @@ export class AccountContext { }); } + /* Is account proxy id */ + public isUnifiedAccount (proxyId: string): boolean { + const accountProxies = this.accounts; + + return Object.values(accountProxies).some((value) => value.accountType === AccountProxyType.UNIFIED && value.id === proxyId); + } + /* Create group id */ private createAccountGroupId (_suri: string, derivationPath?: string) { let data: string = _suri; From c242fd1f26034e16caa7fb00226bb7f54ade6f5a Mon Sep 17 00:00:00 2001 From: lw Date: Wed, 31 Jul 2024 17:36:46 +0700 Subject: [PATCH 026/424] [MasterAccount] Update logic to get network address for account detail screen --- .../AccountDetail/AccountAddressList.tsx | 82 ++++++++++++------- .../src/Popup/Account/AccountDetail/index.tsx | 33 +++----- .../src/hooks/account/index.ts | 1 + .../account/useGetAccountNetworkAddress.tsx | 62 ++++++++++++++ 4 files changed, 130 insertions(+), 48 deletions(-) create mode 100644 packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddress.tsx diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx index f498b4fa2c..5187058a3e 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx @@ -1,32 +1,47 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; -import { useTranslation } from '@subwallet/extension-koni-ui/hooks'; -import { ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { AccountProxy } from '@subwallet/extension-base/types'; +import { AccountNetworkAddressItem, GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; +import { useGetAccountNetworkAddress, useTranslation } from '@subwallet/extension-koni-ui/hooks'; +import { AccountNetworkAddress, ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { copyToClipboard } from '@subwallet/extension-koni-ui/utils'; import { SwList } from '@subwallet/react-ui'; -import React, { useCallback, useMemo } from 'react'; +import React, { useCallback } from 'react'; import styled from 'styled-components'; -type Props = ThemeProps; +import useNotification from '../../../hooks/common/useNotification'; -type ItemType = string; +type Props = ThemeProps & { + accountProxy: AccountProxy; +}; -function Component ({ className }: Props) { +function Component ({ accountProxy, className }: Props) { const { t } = useTranslation(); - const items: ItemType[] = useMemo(() => { - return []; - }, []); + const items: AccountNetworkAddress[] = useGetAccountNetworkAddress(accountProxy); + const notify = useNotification(); + + const onCopyAddress = useCallback((item: AccountNetworkAddress) => { + return () => { + copyToClipboard(item.address || ''); + notify({ + message: t('Copied to clipboard') + }); + }; + }, [notify, t]); const renderItem = useCallback( - (item: ItemType) => { + (item: AccountNetworkAddress) => { return ( -
- -
+ ); }, - [] + [onCopyAddress] ); const emptyList = useCallback(() => { @@ -34,27 +49,38 @@ function Component ({ className }: Props) { }, []); const searchFunction = useCallback( - (item: ItemType, searchText: string) => { - return true; + (item: AccountNetworkAddress, searchText: string) => { + return item.name.toLowerCase().includes(searchText.toLowerCase()); }, [] ); return ( - ('Enter network name')} - showActionBtn - /> +
+ ('Enter network name')} + /> +
); } export const AccountAddressList = styled(Component)(({ theme: { token } }: Props) => ({ + '.ant-sw-list-section': { + height: '100%' + }, + + '.ant-sw-list': { + paddingBottom: 0 + }, + '.address-item + .address-item': { + marginTop: token.marginXS + } })); diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx index ad21682328..669452fb1c 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx @@ -266,18 +266,19 @@ const Component: React.FC = (props: Props) => { onSelect={onSelectFilterTab} selectedItem={selectedFilterTab} /> -
- { - selectedFilterTab === FilterTabType.ACCOUNT_ADDRESS && ( - - ) - } - { - selectedFilterTab === FilterTabType.DERIVED_ACCOUNT && ( - - ) - } -
+ { + selectedFilterTab === FilterTabType.ACCOUNT_ADDRESS && ( + + ) + } + { + selectedFilterTab === FilterTabType.DERIVED_ACCOUNT && ( + + ) + } ); @@ -321,14 +322,6 @@ const AccountDetail = styled(Component)(({ theme: { token } }: Props) => overflow: 'hidden' }, - '.ant-sw-list-section': { - height: '100%' - }, - - '.ant-sw-list': { - paddingBottom: 0 - }, - '.filter-tabs-container': { gap: 0, paddingLeft: token.paddingXXS, diff --git a/packages/extension-koni-ui/src/hooks/account/index.ts b/packages/extension-koni-ui/src/hooks/account/index.ts index abd6aa00f8..7ddc77fcc4 100644 --- a/packages/extension-koni-ui/src/hooks/account/index.ts +++ b/packages/extension-koni-ui/src/hooks/account/index.ts @@ -17,6 +17,7 @@ export { default as useIsReadOnlyAccount } from './useIsReadOnlyAccount'; export { default as usePreCheckAction } from './usePreCheckAction'; export { default as useSetSelectedAccountTypes } from './useSetSelectedAccountTypes'; export { default as useGetAccountProxyById } from './useGetAccountProxyById'; +export { default as useGetAccountNetworkAddress } from './useGetAccountNetworkAddress'; export * from './useGetMantaPayConfig'; export * from './useGetZkAddress'; diff --git a/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddress.tsx b/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddress.tsx new file mode 100644 index 0000000000..6714318fe2 --- /dev/null +++ b/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddress.tsx @@ -0,0 +1,62 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { _ChainInfo } from '@subwallet/chain-list/types'; +import { _isChainEvmCompatible, _isPureSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils'; +import { AccountNetworkType, AccountProxy } from '@subwallet/extension-base/types'; +import { reformatAddress } from '@subwallet/extension-base/utils'; +import { useSelector } from '@subwallet/extension-koni-ui/hooks'; +import { AccountNetworkAddress } from '@subwallet/extension-koni-ui/types'; +import { useMemo } from 'react'; + +function isChainInfoAccordantNetworkType (chainInfo: _ChainInfo, networkType: AccountNetworkType): boolean { + if (networkType === AccountNetworkType.SUBSTRATE) { + return _isPureSubstrateChain(chainInfo); + } + + if (networkType === AccountNetworkType.ETHEREUM) { + return _isChainEvmCompatible(chainInfo); + } + + return false; +} + +// todo: +// - order the result +// - support ton, bitcoin +// - logic for generic, legacy ledger account +const useGetAccountNetworkAddress = (accountProxy: AccountProxy): AccountNetworkAddress[] => { + const chainInfoMap = useSelector((state) => state.chainStore.chainInfoMap); + + return useMemo(() => { + const result: AccountNetworkAddress[] = []; + + accountProxy.accounts.forEach((a) => { + for (const chainSlug in chainInfoMap) { + const chainInfo = chainInfoMap[chainSlug]; + + if (!isChainInfoAccordantNetworkType(chainInfo, a.networkType)) { + continue; + } + + if (a.networkType === AccountNetworkType.SUBSTRATE && chainInfo.substrateInfo) { + result.push({ + name: chainInfo.name, + slug: chainInfo.slug, + address: reformatAddress(a.address, chainInfo.substrateInfo.addressPrefix) + }); + } else if (a.networkType === AccountNetworkType.ETHEREUM && chainInfo.evmInfo) { + result.push({ + name: chainInfo.name, + slug: chainInfo.slug, + address: a.address + }); + } + } + }); + + return result; + }, [accountProxy.accounts, chainInfoMap]); +}; + +export default useGetAccountNetworkAddress; From 29d8a82daf93a53620a68c5bbbb514187ae171cc Mon Sep 17 00:00:00 2001 From: lw Date: Wed, 31 Jul 2024 17:50:26 +0700 Subject: [PATCH 027/424] [MasterAccount] Add button "Upgrade to Unified account" --- .../AccountDetail/AccountAddressList.tsx | 39 +++++++++++++++++-- .../src/Popup/Account/AccountDetail/index.tsx | 3 +- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx index 5187058a3e..84eed615b5 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx @@ -1,12 +1,13 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountProxy } from '@subwallet/extension-base/types'; +import { AccountProxy, AccountProxyType } from '@subwallet/extension-base/types'; import { AccountNetworkAddressItem, GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; import { useGetAccountNetworkAddress, useTranslation } from '@subwallet/extension-koni-ui/hooks'; import { AccountNetworkAddress, ThemeProps } from '@subwallet/extension-koni-ui/types'; import { copyToClipboard } from '@subwallet/extension-koni-ui/utils'; -import { SwList } from '@subwallet/react-ui'; +import { Button, Icon, SwList } from '@subwallet/react-ui'; +import { Strategy } from 'phosphor-react'; import React, { useCallback } from 'react'; import styled from 'styled-components'; @@ -58,7 +59,6 @@ function Component ({ accountProxy, className }: Props) { return (
('Enter network name')} /> + + { + accountProxy.accountType === AccountProxyType.SOLO && ( +
+ +
+ ) + }
); } export const AccountAddressList = styled(Component)(({ theme: { token } }: Props) => ({ + display: 'flex', + overflow: 'hidden', + flexDirection: 'column', + '.ant-sw-list-section': { - height: '100%' + flex: 1 }, '.ant-sw-list': { @@ -82,5 +105,13 @@ export const AccountAddressList = styled(Component)(({ theme: { token } } '.address-item + .address-item': { marginTop: token.marginXS + }, + + '.update-unified-account-button-wrapper': { + paddingLeft: token.padding, + paddingRight: token.padding, + paddingTop: token.paddingSM, + paddingBottom: token.paddingXXS } + })); diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx index 669452fb1c..65a7521444 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx @@ -318,8 +318,7 @@ const AccountDetail = styled(Component)(({ theme: { token } }: Props) => }, '.list-container': { - flex: 1, - overflow: 'hidden' + flex: 1 }, '.filter-tabs-container': { From 440993f91b9ceebdd8664cc400957ac7b0116d17 Mon Sep 17 00:00:00 2001 From: lw Date: Wed, 31 Jul 2024 18:00:30 +0700 Subject: [PATCH 028/424] [MasterAccount] Change useGetAccountNetworkAddress to useGetAccountNetworkAddresses --- .../src/Popup/Account/AccountDetail/AccountAddressList.tsx | 6 ++---- packages/extension-koni-ui/src/hooks/account/index.ts | 3 ++- ...NetworkAddress.tsx => useGetAccountNetworkAddresses.tsx} | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) rename packages/extension-koni-ui/src/hooks/account/{useGetAccountNetworkAddress.tsx => useGetAccountNetworkAddresses.tsx} (93%) diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx index 84eed615b5..6a313b5b41 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx @@ -3,7 +3,7 @@ import { AccountProxy, AccountProxyType } from '@subwallet/extension-base/types'; import { AccountNetworkAddressItem, GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; -import { useGetAccountNetworkAddress, useTranslation } from '@subwallet/extension-koni-ui/hooks'; +import { useGetAccountNetworkAddresses, useNotification, useTranslation } from '@subwallet/extension-koni-ui/hooks'; import { AccountNetworkAddress, ThemeProps } from '@subwallet/extension-koni-ui/types'; import { copyToClipboard } from '@subwallet/extension-koni-ui/utils'; import { Button, Icon, SwList } from '@subwallet/react-ui'; @@ -11,15 +11,13 @@ import { Strategy } from 'phosphor-react'; import React, { useCallback } from 'react'; import styled from 'styled-components'; -import useNotification from '../../../hooks/common/useNotification'; - type Props = ThemeProps & { accountProxy: AccountProxy; }; function Component ({ accountProxy, className }: Props) { const { t } = useTranslation(); - const items: AccountNetworkAddress[] = useGetAccountNetworkAddress(accountProxy); + const items: AccountNetworkAddress[] = useGetAccountNetworkAddresses(accountProxy); const notify = useNotification(); const onCopyAddress = useCallback((item: AccountNetworkAddress) => { diff --git a/packages/extension-koni-ui/src/hooks/account/index.ts b/packages/extension-koni-ui/src/hooks/account/index.ts index 7ddc77fcc4..77b2353d47 100644 --- a/packages/extension-koni-ui/src/hooks/account/index.ts +++ b/packages/extension-koni-ui/src/hooks/account/index.ts @@ -1,6 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 +// todo: Remove unused hooks export { default as useAccountAvatarInfo } from './useAccountAvatarInfo'; export { default as useAccountAvatarTheme } from './useAccountAvatarTheme'; export { default as useAccountRecoded } from './useAccountRecoded'; @@ -17,7 +18,7 @@ export { default as useIsReadOnlyAccount } from './useIsReadOnlyAccount'; export { default as usePreCheckAction } from './usePreCheckAction'; export { default as useSetSelectedAccountTypes } from './useSetSelectedAccountTypes'; export { default as useGetAccountProxyById } from './useGetAccountProxyById'; -export { default as useGetAccountNetworkAddress } from './useGetAccountNetworkAddress'; +export { default as useGetAccountNetworkAddresses } from './useGetAccountNetworkAddresses'; export * from './useGetMantaPayConfig'; export * from './useGetZkAddress'; diff --git a/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddress.tsx b/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx similarity index 93% rename from packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddress.tsx rename to packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx index 6714318fe2..03a0bbd642 100644 --- a/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddress.tsx +++ b/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx @@ -25,7 +25,7 @@ function isChainInfoAccordantNetworkType (chainInfo: _ChainInfo, networkType: Ac // - order the result // - support ton, bitcoin // - logic for generic, legacy ledger account -const useGetAccountNetworkAddress = (accountProxy: AccountProxy): AccountNetworkAddress[] => { +const useGetAccountNetworkAddresses = (accountProxy: AccountProxy): AccountNetworkAddress[] => { const chainInfoMap = useSelector((state) => state.chainStore.chainInfoMap); return useMemo(() => { @@ -59,4 +59,4 @@ const useGetAccountNetworkAddress = (accountProxy: AccountProxy): AccountNetwork }, [accountProxy.accounts, chainInfoMap]); }; -export default useGetAccountNetworkAddress; +export default useGetAccountNetworkAddresses; From 20d19258bebb328029d9fa748b8b6e8735983b5b Mon Sep 17 00:00:00 2001 From: lw Date: Wed, 31 Jul 2024 18:29:35 +0700 Subject: [PATCH 029/424] [MasterAccount] Update DerivedAccountList --- .../AccountDetail/DerivedAccountList.tsx | 68 +++++++++++-------- .../src/Popup/Account/AccountDetail/index.tsx | 5 +- .../AccountProxy/AccountProxySelectorItem.tsx | 1 + .../src/hooks/account/index.ts | 1 + .../account/useGetDerivedAccountProxies.tsx | 25 +++++++ 5 files changed, 72 insertions(+), 28 deletions(-) create mode 100644 packages/extension-koni-ui/src/hooks/account/useGetDerivedAccountProxies.tsx diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/DerivedAccountList.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/DerivedAccountList.tsx index c486a61fe7..f9cbb38840 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/DerivedAccountList.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/DerivedAccountList.tsx @@ -1,29 +1,29 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; -import { useTranslation } from '@subwallet/extension-koni-ui/hooks'; +import { AccountProxy } from '@subwallet/extension-base/types'; +import { AccountProxySelectorItem, GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; +import { useGetDerivedAccountProxies, useTranslation } from '@subwallet/extension-koni-ui/hooks'; import { ThemeProps } from '@subwallet/extension-koni-ui/types'; import { SwList } from '@subwallet/react-ui'; -import React, { useCallback, useMemo } from 'react'; +import React, { useCallback } from 'react'; import styled from 'styled-components'; -type Props = ThemeProps; +type Props = ThemeProps & { + accountProxy: AccountProxy; +}; -type ItemType = string; - -function Component ({ className }: Props) { +function Component ({ accountProxy, className }: Props) { const { t } = useTranslation(); - const items: ItemType[] = useMemo(() => { - return []; - }, []); + const items = useGetDerivedAccountProxies(accountProxy); const renderItem = useCallback( - (item: ItemType) => { + (item: AccountProxy) => { return ( -
- -
+ ); }, [] @@ -34,27 +34,41 @@ function Component ({ className }: Props) { }, []); const searchFunction = useCallback( - (item: ItemType, searchText: string) => { - return true; + (item: AccountProxy, searchText: string) => { + return item.name.toLowerCase().includes(searchText.toLowerCase()); }, [] ); return ( - ('Enter network name')} - showActionBtn - /> +
+ ('Enter account name')} + /> +
); } export const DerivedAccountList = styled(Component)(({ theme: { token } }: Props) => ({ + display: 'flex', + overflow: 'hidden', + flexDirection: 'column', + + '.ant-sw-list-section': { + flex: 1 + }, + + '.ant-sw-list': { + paddingBottom: 0 + }, + '.account-item + .account-item': { + marginTop: token.marginXS + } })); diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx index 65a7521444..19d2e2517f 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx @@ -276,7 +276,10 @@ const Component: React.FC = (props: Props) => { } { selectedFilterTab === FilterTabType.DERIVED_ACCOUNT && ( - + ) } diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx index 25376d18ed..d169eb9a0a 100644 --- a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx +++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx @@ -209,6 +209,7 @@ function Component (props: Props): React.ReactElement { } onClick={_onClickMoreButton} size='xs' + tooltip={t('View details')} type='ghost' />
diff --git a/packages/extension-koni-ui/src/hooks/account/index.ts b/packages/extension-koni-ui/src/hooks/account/index.ts index 77b2353d47..b59f2dae33 100644 --- a/packages/extension-koni-ui/src/hooks/account/index.ts +++ b/packages/extension-koni-ui/src/hooks/account/index.ts @@ -19,6 +19,7 @@ export { default as usePreCheckAction } from './usePreCheckAction'; export { default as useSetSelectedAccountTypes } from './useSetSelectedAccountTypes'; export { default as useGetAccountProxyById } from './useGetAccountProxyById'; export { default as useGetAccountNetworkAddresses } from './useGetAccountNetworkAddresses'; +export { default as useGetDerivedAccountProxies } from './useGetDerivedAccountProxies'; export * from './useGetMantaPayConfig'; export * from './useGetZkAddress'; diff --git a/packages/extension-koni-ui/src/hooks/account/useGetDerivedAccountProxies.tsx b/packages/extension-koni-ui/src/hooks/account/useGetDerivedAccountProxies.tsx new file mode 100644 index 0000000000..f24d7a0b7d --- /dev/null +++ b/packages/extension-koni-ui/src/hooks/account/useGetDerivedAccountProxies.tsx @@ -0,0 +1,25 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { AccountProxy } from '@subwallet/extension-base/types'; +import { useSelector } from '@subwallet/extension-koni-ui/hooks'; +import { useMemo } from 'react'; + +// todo: recheck logic to get account proxies +const useGetDerivedAccountProxies = (parentAccountProxy: AccountProxy): AccountProxy[] => { + const accountProxies = useSelector((state) => state.accountState.accountProxies); + + return useMemo(() => { + const result: AccountProxy[] = []; + + accountProxies.forEach((ap) => { + if (ap.parentId && ap.parentId === parentAccountProxy.id) { + result.push(ap); + } + }); + + return result; + }, [accountProxies, parentAccountProxy.id]); +}; + +export default useGetDerivedAccountProxies; From 6eb801dada33512cc8b1d2252dc4f9aee707b7de Mon Sep 17 00:00:00 2001 From: S2kael Date: Thu, 1 Aug 2024 10:47:47 +0700 Subject: [PATCH 030/424] [Issue-3396] Add `children` for `AccountProxyData` interface --- packages/extension-base/src/types/account/info/proxy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/extension-base/src/types/account/info/proxy.ts b/packages/extension-base/src/types/account/info/proxy.ts index dc2e1067d6..70ca20284e 100644 --- a/packages/extension-base/src/types/account/info/proxy.ts +++ b/packages/extension-base/src/types/account/info/proxy.ts @@ -52,6 +52,7 @@ export interface AccountProxy extends AccountProxyData { accounts: AccountJson[]; accountType: AccountProxyType; networkTypes: AccountNetworkType[]; + children?: string[]; } export type AccountProxyMap = Record From 8ecaf5ee52acc3e90efd4467ee21849c5334ea51 Mon Sep 17 00:00:00 2001 From: S2kael Date: Wed, 31 Jul 2024 19:55:42 +0700 Subject: [PATCH 031/424] [Issue-3396] Update subscribe for history --- .../src/services/chain-service/utils/index.ts | 2 +- .../src/services/history-service/index.ts | 35 +++++++++++++------ .../keyring-service/account-context.ts | 4 +-- .../swap-service/handler/chainflip-handler.ts | 4 +-- .../src/Popup/Settings/Chains/AddProvider.tsx | 4 +-- .../src/Popup/Settings/Chains/ChainDetail.tsx | 4 +-- .../Popup/Settings/Chains/ManageChains.tsx | 4 +-- .../src/hooks/assets/useChainAssets.ts | 4 +-- .../src/Popup/Settings/Chains/AddProvider.tsx | 4 +-- .../src/Popup/Settings/Chains/ChainDetail.tsx | 4 +-- .../Popup/Settings/Chains/ManageChains.tsx | 4 +-- .../src/hooks/assets/useChainAssets.ts | 4 +-- 12 files changed, 46 insertions(+), 31 deletions(-) diff --git a/packages/extension-base/src/services/chain-service/utils/index.ts b/packages/extension-base/src/services/chain-service/utils/index.ts index a3674bcf9e..0e4803ffe3 100644 --- a/packages/extension-base/src/services/chain-service/utils/index.ts +++ b/packages/extension-base/src/services/chain-service/utils/index.ts @@ -159,7 +159,7 @@ export function _isSmartContractToken (tokenInfo: _ChainAsset) { return _SMART_CONTRACT_STANDARDS.includes(tokenInfo.assetType); } -export function _isSubstrateChain (chainInfo: _ChainInfo) { +export function _isChainSubstrateCompatible (chainInfo: _ChainInfo) { return !!chainInfo.substrateInfo; // fallback to Ethereum } diff --git a/packages/extension-base/src/services/history-service/index.ts b/packages/extension-base/src/services/history-service/index.ts index c952099f01..acf51dc4b0 100644 --- a/packages/extension-base/src/services/history-service/index.ts +++ b/packages/extension-base/src/services/history-service/index.ts @@ -5,6 +5,7 @@ import { ExtrinsicStatus, TransactionHistoryItem } from '@subwallet/extension-ba import { CRON_RECOVER_HISTORY_INTERVAL } from '@subwallet/extension-base/constants'; import { PersistDataServiceInterface, ServiceStatus, StoppableServiceInterface } from '@subwallet/extension-base/services/base/types'; import { ChainService } from '@subwallet/extension-base/services/chain-service'; +import { _isChainEvmCompatible, _isChainSubstrateCompatible } from '@subwallet/extension-base/services/chain-service/utils'; import { EventService } from '@subwallet/extension-base/services/event-service'; import { historyRecover, HistoryRecoverStatus } from '@subwallet/extension-base/services/history-service/helpers/recoverHistoryStatus'; import { getExtrinsicParserKey } from '@subwallet/extension-base/services/history-service/helpers/subscan-extrinsic-parser-helper'; @@ -12,14 +13,14 @@ import { parseSubscanExtrinsicData, parseSubscanTransferData } from '@subwallet/ import { KeyringService } from '@subwallet/extension-base/services/keyring-service'; import DatabaseService from '@subwallet/extension-base/services/storage-service/DatabaseService'; import { SubscanService } from '@subwallet/extension-base/services/subscan-service'; -import { reformatAddress } from '@subwallet/extension-base/utils'; +import { categoryAddresses } from '@subwallet/extension-base/utils'; import { createPromiseHandler } from '@subwallet/extension-base/utils/promise'; import { keyring } from '@subwallet/ui-keyring'; import { BehaviorSubject } from 'rxjs'; -function filterHistoryItemByAddressAndChain (chain: string, address: string) { +function filterHistoryItemByAddressAndChain (chain: string, addresses: string[]) { return (item: TransactionHistoryItem) => { - return item.chain === chain && item.address === address; + return item.chain === chain && addresses.includes(item.address); }; } @@ -89,12 +90,17 @@ export class HistoryService implements StoppableServiceInterface, PersistDataSer return this.historySubject; } - private fetchSubscanTransactionHistory (chain: string, address: string) { - if (!this.subscanService.checkSupportedSubscanChain(chain)) { + /** + * @todo: Must improve performance of this function + * */ + private fetchSubscanTransactionHistory (chain: string, addresses: string[]) { + if (!this.subscanService.checkSupportedSubscanChain(chain) || !addresses.length) { return; } const chainInfo = this.chainService.getChainInfoByKey(chain); + // For now, we only use the first address + const address = addresses[0]; const excludeExtrinsicParserKeys: string[] = [ 'balances.transfer_all' @@ -173,18 +179,27 @@ export class HistoryService implements StoppableServiceInterface, PersistDataSer }); } - subscribeHistories (chain: string, address: string, cb: (items: TransactionHistoryItem[]) => void) { - const _address = reformatAddress(address); + subscribeHistories (chain: string, proxyId: string, cb: (items: TransactionHistoryItem[]) => void) { + const addresses = this.keyringService.context.getDecodedAddresses(proxyId, false); + const { evm, substrate } = categoryAddresses(addresses); const subscription = this.historySubject.subscribe((items) => { - cb(items.filter(filterHistoryItemByAddressAndChain(chain, _address))); + cb(items.filter(filterHistoryItemByAddressAndChain(chain, addresses))); }); - this.fetchSubscanTransactionHistory(chain, _address); + const chainInfo = this.chainService.getChainInfoByKey(chain); + + if (_isChainSubstrateCompatible(chainInfo)) { + if (_isChainEvmCompatible(chainInfo)) { + this.fetchSubscanTransactionHistory(chain, evm); + } else { + this.fetchSubscanTransactionHistory(chain, substrate); + } + } return { unsubscribe: subscription.unsubscribe, - value: this.historySubject.getValue().filter(filterHistoryItemByAddressAndChain(chain, _address)) + value: this.historySubject.getValue().filter(filterHistoryItemByAddressAndChain(chain, addresses)) }; } diff --git a/packages/extension-base/src/services/keyring-service/account-context.ts b/packages/extension-base/src/services/keyring-service/account-context.ts index 6790709a11..be4eaff7d2 100644 --- a/packages/extension-base/src/services/keyring-service/account-context.ts +++ b/packages/extension-base/src/services/keyring-service/account-context.ts @@ -416,7 +416,7 @@ export class AccountContext { return proxyId; } - public getDecodedAddresses (accountProxy?: string): string[] { + public getDecodedAddresses (accountProxy?: string, allowGetAllAccount = true): string[] { let proxyId: string | null | undefined = accountProxy; if (!accountProxy) { @@ -428,7 +428,7 @@ export class AccountContext { } if (proxyId === ALL_ACCOUNT_KEY) { - return this.getAllAddresses(); + return allowGetAllAccount ? this.getAllAddresses() : []; } const accountProxies = this.accountProxiesSubject.value; diff --git a/packages/extension-base/src/services/swap-service/handler/chainflip-handler.ts b/packages/extension-base/src/services/swap-service/handler/chainflip-handler.ts index c495530ce7..b82a776a46 100644 --- a/packages/extension-base/src/services/swap-service/handler/chainflip-handler.ts +++ b/packages/extension-base/src/services/swap-service/handler/chainflip-handler.ts @@ -12,7 +12,7 @@ import { BalanceService } from '@subwallet/extension-base/services/balance-servi import { getERC20TransactionObject, getEVMTransactionObject } from '@subwallet/extension-base/services/balance-service/transfer/smart-contract'; import { createTransferExtrinsic } from '@subwallet/extension-base/services/balance-service/transfer/token'; import { ChainService } from '@subwallet/extension-base/services/chain-service'; -import { _getAssetDecimals, _getChainNativeTokenSlug, _getContractAddressOfToken, _isNativeToken, _isSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils'; +import { _getAssetDecimals, _getChainNativeTokenSlug, _getContractAddressOfToken, _isNativeToken, _isChainSubstrateCompatible } from '@subwallet/extension-base/services/chain-service/utils'; import { SwapBaseHandler, SwapBaseInterface } from '@subwallet/extension-base/services/swap-service/handler/base-handler'; import { calculateSwapRate, CHAIN_FLIP_SUPPORTED_MAINNET_ASSET_MAPPING, CHAIN_FLIP_SUPPORTED_MAINNET_MAPPING, CHAIN_FLIP_SUPPORTED_TESTNET_ASSET_MAPPING, CHAIN_FLIP_SUPPORTED_TESTNET_MAPPING, SWAP_QUOTE_TIMEOUT_MAP } from '@subwallet/extension-base/services/swap-service/utils'; import { TransactionData } from '@subwallet/extension-base/types'; @@ -364,7 +364,7 @@ export class ChainflipSwapHandler implements SwapBaseInterface { const fromAsset = this.chainService.getAssetBySlug(pair.from); const toAsset = this.chainService.getAssetBySlug(pair.to); const chainInfo = this.chainService.getChainInfoByKey(fromAsset.originChain); - const chainType = _isSubstrateChain(chainInfo) ? ChainType.SUBSTRATE : ChainType.EVM; + const chainType = _isChainSubstrateCompatible(chainInfo) ? ChainType.SUBSTRATE : ChainType.EVM; const receiver = recipient ?? address; const srcChainId = this.chainMapping[fromAsset.originChain]; diff --git a/packages/extension-koni-ui/src/Popup/Settings/Chains/AddProvider.tsx b/packages/extension-koni-ui/src/Popup/Settings/Chains/AddProvider.tsx index 6521ad01e8..513f0fc442 100644 --- a/packages/extension-koni-ui/src/Popup/Settings/Chains/AddProvider.tsx +++ b/packages/extension-koni-ui/src/Popup/Settings/Chains/AddProvider.tsx @@ -3,7 +3,7 @@ import { _CHAIN_VALIDATION_ERROR } from '@subwallet/extension-base/services/chain-service/handler/types'; import { _NetworkUpsertParams } from '@subwallet/extension-base/services/chain-service/types'; -import { _generateCustomProviderKey, _getChainNativeTokenBasicInfo, _isChainEvmCompatible, _isCustomProvider, _isSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils'; +import { _generateCustomProviderKey, _getChainNativeTokenBasicInfo, _isChainEvmCompatible, _isCustomProvider, _isChainSubstrateCompatible } from '@subwallet/extension-base/services/chain-service/utils'; import { isUrl } from '@subwallet/extension-base/utils'; import { Layout, PageWrapper } from '@subwallet/extension-koni-ui/components'; import InfoIcon from '@subwallet/extension-koni-ui/components/Icon/InfoIcon'; @@ -72,7 +72,7 @@ function Component ({ className = '' }: Props): React.ReactElement { let result = ''; const types: string[] = []; - if (_isSubstrateChain(chainInfo)) { + if (_isChainSubstrateCompatible(chainInfo)) { types.push('Substrate'); } diff --git a/packages/extension-koni-ui/src/Popup/Settings/Chains/ChainDetail.tsx b/packages/extension-koni-ui/src/Popup/Settings/Chains/ChainDetail.tsx index 6a991f9890..afcef5ee79 100644 --- a/packages/extension-koni-ui/src/Popup/Settings/Chains/ChainDetail.tsx +++ b/packages/extension-koni-ui/src/Popup/Settings/Chains/ChainDetail.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { _NetworkUpsertParams } from '@subwallet/extension-base/services/chain-service/types'; -import { _getBlockExplorerFromChain, _getChainNativeTokenBasicInfo, _getChainSubstrateAddressPrefix, _getCrowdloanUrlFromChain, _getEvmChainId, _getSubstrateParaId, _isChainEvmCompatible, _isCustomChain, _isPureEvmChain, _isSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils'; +import { _getBlockExplorerFromChain, _getChainNativeTokenBasicInfo, _getChainSubstrateAddressPrefix, _getCrowdloanUrlFromChain, _getEvmChainId, _getSubstrateParaId, _isChainEvmCompatible, _isCustomChain, _isPureEvmChain, _isChainSubstrateCompatible } from '@subwallet/extension-base/services/chain-service/utils'; import { isUrl } from '@subwallet/extension-base/utils'; import { Layout, PageWrapper } from '@subwallet/extension-koni-ui/components'; import { ProviderSelector } from '@subwallet/extension-koni-ui/components/Field/ProviderSelector'; @@ -122,7 +122,7 @@ function Component ({ className = '' }: Props): React.ReactElement { let result = ''; const types: string[] = []; - if (_isSubstrateChain(chainInfo)) { + if (_isChainSubstrateCompatible(chainInfo)) { types.push('Substrate'); } diff --git a/packages/extension-koni-ui/src/Popup/Settings/Chains/ManageChains.tsx b/packages/extension-koni-ui/src/Popup/Settings/Chains/ManageChains.tsx index d6760b819a..ef9af74642 100644 --- a/packages/extension-koni-ui/src/Popup/Settings/Chains/ManageChains.tsx +++ b/packages/extension-koni-ui/src/Popup/Settings/Chains/ManageChains.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { _isChainEvmCompatible, _isCustomChain, _isSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils'; +import { _isChainEvmCompatible, _isCustomChain, _isChainSubstrateCompatible } from '@subwallet/extension-base/services/chain-service/utils'; import { FilterModal, Layout, NetworkEmptyList, NetworkToggleItem, OptionType, PageWrapper } from '@subwallet/extension-koni-ui/components'; import { DataContext } from '@subwallet/extension-koni-ui/contexts/DataContext'; import { ChainInfoWithState, useFilterModal, useTranslation } from '@subwallet/extension-koni-ui/hooks'; @@ -69,7 +69,7 @@ function Component ({ className = '' }: Props): React.ReactElement { return true; } } else if (filter === FilterValue.SUBSTRATE) { - if (_isSubstrateChain(chainInfo)) { + if (_isChainSubstrateCompatible(chainInfo)) { return true; } } else if (filter === FilterValue.EVM) { diff --git a/packages/extension-koni-ui/src/hooks/assets/useChainAssets.ts b/packages/extension-koni-ui/src/hooks/assets/useChainAssets.ts index a2123b51ad..a59503e14d 100644 --- a/packages/extension-koni-ui/src/hooks/assets/useChainAssets.ts +++ b/packages/extension-koni-ui/src/hooks/assets/useChainAssets.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { _ChainAsset, _ChainStatus } from '@subwallet/chain-list/types'; -import { _isAssetFungibleToken, _isChainEvmCompatible, _isSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils'; +import { _isAssetFungibleToken, _isChainEvmCompatible, _isChainSubstrateCompatible } from '@subwallet/extension-base/services/chain-service/utils'; import { RootState } from '@subwallet/extension-koni-ui/stores'; import { useMemo } from 'react'; import { useSelector } from 'react-redux'; @@ -32,7 +32,7 @@ export default function useChainAssets ({ chainTypes, isActive = false, isActive }, [availableChains, chainInfoMap]); const substrateChains = useMemo(() => { - return availableChains.filter((slug) => _isSubstrateChain(chainInfoMap[slug])); + return availableChains.filter((slug) => _isChainSubstrateCompatible(chainInfoMap[slug])); }, [availableChains, chainInfoMap]); const activeAssets = useMemo(() => { diff --git a/packages/extension-web-ui/src/Popup/Settings/Chains/AddProvider.tsx b/packages/extension-web-ui/src/Popup/Settings/Chains/AddProvider.tsx index 65dcc26e45..96e4604259 100644 --- a/packages/extension-web-ui/src/Popup/Settings/Chains/AddProvider.tsx +++ b/packages/extension-web-ui/src/Popup/Settings/Chains/AddProvider.tsx @@ -3,7 +3,7 @@ import { _CHAIN_VALIDATION_ERROR } from '@subwallet/extension-base/services/chain-service/handler/types'; import { _NetworkUpsertParams } from '@subwallet/extension-base/services/chain-service/types'; -import { _generateCustomProviderKey, _getChainNativeTokenBasicInfo, _isChainEvmCompatible, _isCustomProvider, _isSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils'; +import { _generateCustomProviderKey, _getChainNativeTokenBasicInfo, _isChainEvmCompatible, _isCustomProvider, _isChainSubstrateCompatible } from '@subwallet/extension-base/services/chain-service/utils'; import { isUrl } from '@subwallet/extension-base/utils'; import { Layout, PageWrapper } from '@subwallet/extension-web-ui/components'; import InfoIcon from '@subwallet/extension-web-ui/components/Icon/InfoIcon'; @@ -74,7 +74,7 @@ function Component ({ className = '' }: Props): React.ReactElement { let result = ''; const types: string[] = []; - if (_isSubstrateChain(chainInfo)) { + if (_isChainSubstrateCompatible(chainInfo)) { types.push('Substrate'); } diff --git a/packages/extension-web-ui/src/Popup/Settings/Chains/ChainDetail.tsx b/packages/extension-web-ui/src/Popup/Settings/Chains/ChainDetail.tsx index 61557a0f55..1973b4444f 100644 --- a/packages/extension-web-ui/src/Popup/Settings/Chains/ChainDetail.tsx +++ b/packages/extension-web-ui/src/Popup/Settings/Chains/ChainDetail.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { _NetworkUpsertParams } from '@subwallet/extension-base/services/chain-service/types'; -import { _getBlockExplorerFromChain, _getChainNativeTokenBasicInfo, _getChainSubstrateAddressPrefix, _getCrowdloanUrlFromChain, _getEvmChainId, _getSubstrateParaId, _isChainEvmCompatible, _isCustomChain, _isPureEvmChain, _isSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils'; +import { _getBlockExplorerFromChain, _getChainNativeTokenBasicInfo, _getChainSubstrateAddressPrefix, _getCrowdloanUrlFromChain, _getEvmChainId, _getSubstrateParaId, _isChainEvmCompatible, _isCustomChain, _isPureEvmChain, _isChainSubstrateCompatible } from '@subwallet/extension-base/services/chain-service/utils'; import { isUrl } from '@subwallet/extension-base/utils'; import { Layout, PageWrapper } from '@subwallet/extension-web-ui/components'; import { ProviderSelector } from '@subwallet/extension-web-ui/components/Field/ProviderSelector'; @@ -124,7 +124,7 @@ function Component ({ className = '' }: Props): React.ReactElement { let result = ''; const types: string[] = []; - if (_isSubstrateChain(chainInfo)) { + if (_isChainSubstrateCompatible(chainInfo)) { types.push('Substrate'); } diff --git a/packages/extension-web-ui/src/Popup/Settings/Chains/ManageChains.tsx b/packages/extension-web-ui/src/Popup/Settings/Chains/ManageChains.tsx index 0aa7c4a6a0..e2b0decf8a 100644 --- a/packages/extension-web-ui/src/Popup/Settings/Chains/ManageChains.tsx +++ b/packages/extension-web-ui/src/Popup/Settings/Chains/ManageChains.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { _isChainEvmCompatible, _isCustomChain, _isSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils'; +import { _isChainEvmCompatible, _isCustomChain, _isChainSubstrateCompatible } from '@subwallet/extension-base/services/chain-service/utils'; import { FilterModal, Layout, NetworkEmptyList, NetworkToggleItem, OptionType, PageWrapper } from '@subwallet/extension-web-ui/components'; import { DataContext } from '@subwallet/extension-web-ui/contexts/DataContext'; import { ScreenContext } from '@subwallet/extension-web-ui/contexts/ScreenContext'; @@ -65,7 +65,7 @@ function Component ({ className = '' }: Props): React.ReactElement { return true; } } else if (filter === FilterValue.SUBSTRATE) { - if (_isSubstrateChain(chainInfo)) { + if (_isChainSubstrateCompatible(chainInfo)) { return true; } } else if (filter === FilterValue.EVM) { diff --git a/packages/extension-web-ui/src/hooks/assets/useChainAssets.ts b/packages/extension-web-ui/src/hooks/assets/useChainAssets.ts index d21e92d595..fac5aaf30a 100644 --- a/packages/extension-web-ui/src/hooks/assets/useChainAssets.ts +++ b/packages/extension-web-ui/src/hooks/assets/useChainAssets.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { _ChainAsset, _ChainStatus } from '@subwallet/chain-list/types'; -import { _isAssetFungibleToken, _isChainEvmCompatible, _isSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils'; +import { _isAssetFungibleToken, _isChainEvmCompatible, _isChainSubstrateCompatible } from '@subwallet/extension-base/services/chain-service/utils'; import { RootState } from '@subwallet/extension-web-ui/stores'; import { useMemo } from 'react'; import { useSelector } from 'react-redux'; @@ -32,7 +32,7 @@ export default function useChainAssets ({ chainTypes, isActive = false, isActive }, [availableChains, chainInfoMap]); const substrateChains = useMemo(() => { - return availableChains.filter((slug) => _isSubstrateChain(chainInfoMap[slug])); + return availableChains.filter((slug) => _isChainSubstrateCompatible(chainInfoMap[slug])); }, [availableChains, chainInfoMap]); const activeAssets = useMemo(() => { From 93a5056cf240c0f142b6218622466d5d1dec6716 Mon Sep 17 00:00:00 2001 From: S2kael Date: Thu, 1 Aug 2024 18:38:55 +0700 Subject: [PATCH 032/424] [Issue-3396] Update interface for fetch balance on Ton --- .../src/services/balance-service/helpers/subscribe/index.ts | 4 ++-- .../balance-service/helpers/subscribe/{ => ton}/ton.ts | 4 ++-- .../extension-base/src/services/chain-service/utils/index.ts | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) rename packages/extension-base/src/services/balance-service/helpers/subscribe/{ => ton}/ton.ts (96%) diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts index 81de432440..a99deef00e 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts @@ -3,13 +3,13 @@ import { _AssetType, _ChainAsset, _ChainInfo } from '@subwallet/chain-list/types'; import { APIItemState, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; -import { subscribeTonBalance } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton'; import { _EvmApi, _SubstrateApi, _TonApi } from '@subwallet/extension-base/services/chain-service/types'; import { _getSubstrateGenesisHash, _isChainBitcoinCompatible, _isChainEvmCompatible, _isChainTonCompatible, _isPureEvmChain, _isPureTonChain } from '@subwallet/extension-base/services/chain-service/utils'; import { AccountJson, BalanceItem } from '@subwallet/extension-base/types'; import { categoryAddresses, filterAssetsByChainAndType, pairToAccount } from '@subwallet/extension-base/utils'; import keyring from '@subwallet/ui-keyring'; +import { subscribeTonBalance } from './ton/ton'; import { subscribeEVMBalance } from './evm'; import { subscribeSubstrateBalance } from './substrate'; @@ -138,7 +138,7 @@ export function subscribeBalance ( if (_isPureTonChain(chainInfo)) { return subscribeTonBalance({ - addresses: ['EQChB2eMoFG4ThuEsZ6ehlBPKJXOjNxlR5B7qKZNGIv256Da'], + addresses: useAddresses, assetMap: chainAssetMap, callback, chainInfo, diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/ton.ts similarity index 96% rename from packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts rename to packages/extension-base/src/services/balance-service/helpers/subscribe/ton/ton.ts index c8692bdbb2..80a9e24c43 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/ton.ts @@ -41,7 +41,7 @@ export function subscribeJettonBalanceInterval ({ addresses, assetMap, callback, const items: BalanceItem[] = balances.map((balance, index): BalanceItem => { return { - address: '5HpbHTE8NKRHffnDwUDE7VR1ZtRSK1xWT4NrbvkSv54Fvqxx', // fake address + address: addresses[index], tokenSlug: tokenInfo.slug, free: balance.toString(), locked: '0', @@ -88,7 +88,7 @@ export function subscribeTonBalance (params: SubscribeTonPalletBalance) { .then((balances) => { return balances.map((balance, index): BalanceItem => { return { - address: '5HpbHTE8NKRHffnDwUDE7VR1ZtRSK1xWT4NrbvkSv54Fvqxx', // fake address + address: addresses[index], tokenSlug: nativeTokenSlug, state: APIItemState.READY, free: balance.toString(), diff --git a/packages/extension-base/src/services/chain-service/utils/index.ts b/packages/extension-base/src/services/chain-service/utils/index.ts index 5e0ba50524..7380b031fe 100644 --- a/packages/extension-base/src/services/chain-service/utils/index.ts +++ b/packages/extension-base/src/services/chain-service/utils/index.ts @@ -147,8 +147,7 @@ export function _isChainBitcoinCompatible (chainInfo: _ChainInfo) { } export function _isChainTonCompatible (chainInfo: _ChainInfo) { - // TODO: Add TON chain info - return false; + return !!chainInfo.tonInfo; } export function _isNativeToken (tokenInfo: _ChainAsset) { From 4da51470a7dffe633b0e0aa261bcebd2a435624b Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Thu, 1 Aug 2024 18:50:40 +0700 Subject: [PATCH 033/424] [Issue-3384] style: update BigInt format --- .../src/services/balance-service/helpers/subscribe/ton/ton.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/ton.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/ton.ts index 80a9e24c43..fa485728f5 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/ton.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/ton.ts @@ -35,7 +35,7 @@ export function subscribeJettonBalanceInterval ({ addresses, assetMap, callback, } catch (e) { console.error(`Error on get balance of account ${address} for token ${tokenInfo.slug}`, e); - return 0n; + return BigInt(0); } })); @@ -72,7 +72,7 @@ async function getTonBalance (addresses: string[], tonApi: _TonApi): Promise Date: Thu, 1 Aug 2024 11:20:06 +0700 Subject: [PATCH 034/424] [MasterAccount] Update logic related to navigation between select account modal and account detail screen --- .../AccountDetail/DerivedAccountList.tsx | 28 ++- .../src/Popup/Account/AccountDetail/index.tsx | 213 ++++++++++-------- .../AccountProxy/AccountProxySelectorItem.tsx | 5 +- .../SelectAccount/AccountSelectorModal.tsx | 9 +- .../src/hooks/account/index.ts | 1 - .../account/useGetDerivedAccountProxies.tsx | 25 -- .../extension-koni-ui/src/types/navigation.ts | 8 + 7 files changed, 158 insertions(+), 131 deletions(-) delete mode 100644 packages/extension-koni-ui/src/hooks/account/useGetDerivedAccountProxies.tsx diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/DerivedAccountList.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/DerivedAccountList.tsx index f9cbb38840..28fe3735e0 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/DerivedAccountList.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/DerivedAccountList.tsx @@ -3,10 +3,12 @@ import { AccountProxy } from '@subwallet/extension-base/types'; import { AccountProxySelectorItem, GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; -import { useGetDerivedAccountProxies, useTranslation } from '@subwallet/extension-koni-ui/hooks'; +import { useTranslation } from '@subwallet/extension-koni-ui/hooks'; +import { RootState } from '@subwallet/extension-koni-ui/stores'; import { ThemeProps } from '@subwallet/extension-koni-ui/types'; import { SwList } from '@subwallet/react-ui'; -import React, { useCallback } from 'react'; +import React, { useCallback, useMemo } from 'react'; +import { useSelector } from 'react-redux'; import styled from 'styled-components'; type Props = ThemeProps & { @@ -14,8 +16,28 @@ type Props = ThemeProps & { }; function Component ({ accountProxy, className }: Props) { + const accountProxies = useSelector((state: RootState) => state.accountState.accountProxies); + const { t } = useTranslation(); - const items = useGetDerivedAccountProxies(accountProxy); + + // todo: may have to sort the result + const items = useMemo(() => { + const result: AccountProxy[] = []; + + if (!accountProxy?.children?.length) { + return []; + } + + accountProxy.children.forEach((apId) => { + const item = accountProxies.find((ap) => ap.id === apId); + + if (item) { + result.push(item); + } + }); + + return result; + }, [accountProxies, accountProxy.children]); const renderItem = useCallback( (item: AccountProxy) => { diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx index 19d2e2517f..1f421f2b1b 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx @@ -1,13 +1,14 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 +import { AccountProxy } from '@subwallet/extension-base/types'; import { CloseIcon, Layout, PageWrapper } from '@subwallet/extension-koni-ui/components'; import { FilterTabItemType, FilterTabs } from '@subwallet/extension-koni-ui/components/FilterTabs'; import { useGetAccountProxyById } from '@subwallet/extension-koni-ui/hooks'; import useNotification from '@subwallet/extension-koni-ui/hooks/common/useNotification'; import useDefaultNavigate from '@subwallet/extension-koni-ui/hooks/router/useDefaultNavigate'; import { editAccount } from '@subwallet/extension-koni-ui/messaging'; -import { ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { AccountDetailParam, ThemeProps } from '@subwallet/extension-koni-ui/types'; import { FormCallbacks, FormFieldData } from '@subwallet/extension-koni-ui/types/form'; import { convertFieldToObject } from '@subwallet/extension-koni-ui/utils/form/form'; import { Button, Form, Icon, Input } from '@subwallet/react-ui'; @@ -15,13 +16,23 @@ import CN from 'classnames'; import { CircleNotch, Export, FloppyDiskBack, GitMerge, Trash } from 'phosphor-react'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { useNavigate, useParams } from 'react-router-dom'; +import { useLocation, useParams } from 'react-router-dom'; import styled from 'styled-components'; import { AccountAddressList } from './AccountAddressList'; import { DerivedAccountList } from './DerivedAccountList'; +enum FilterTabType { + ACCOUNT_ADDRESS = 'account-address', + DERIVED_ACCOUNT = 'derived-account', +} + type Props = ThemeProps; +type ComponentProps = { + accountProxy: AccountProxy; + onBack: VoidFunction; + requestViewDerivedAccounts?: boolean; +}; enum FormFieldName { NAME = 'name' @@ -34,32 +45,23 @@ enum ActionType { DELETE = 'delete' } -enum FilterTabType { - ACCOUNT_ADDRESS = 'account-address', - DERIVED_ACCOUNT = 'derived-account', -} - interface DetailFormState { [FormFieldName.NAME]: string; } -const showDerivedAccounts = false; - -const Component: React.FC = (props: Props) => { - const { className } = props; - +const Component: React.FC = ({ accountProxy, onBack, requestViewDerivedAccounts }: ComponentProps) => { const { t } = useTranslation(); - const navigate = useNavigate(); - const { goHome } = useDefaultNavigate(); const notify = useNotification(); - const { accountProxyId } = useParams(); + const showDerivedAccounts = !!accountProxy?.children?.length; - const [selectedFilterTab, setSelectedFilterTab] = useState(FilterTabType.ACCOUNT_ADDRESS); + const [selectedFilterTab, setSelectedFilterTab] = useState( + requestViewDerivedAccounts && showDerivedAccounts + ? FilterTabType.DERIVED_ACCOUNT + : FilterTabType.ACCOUNT_ADDRESS + ); const [form] = Form.useForm(); - const accountProxy = useGetAccountProxyById(accountProxyId); - const saveTimeOutRef = useRef(); // @ts-ignore @@ -84,7 +86,7 @@ const Component: React.FC = (props: Props) => { } return result; - }, [t]); + }, [showDerivedAccounts, t]); const onSelectFilterTab = useCallback((value: string) => { setSelectedFilterTab(value); @@ -125,7 +127,7 @@ const Component: React.FC = (props: Props) => { clearTimeout(saveTimeOutRef.current); const name = values[FormFieldName.NAME]; - if (!accountProxy || name === accountProxy.name) { + if (name === accountProxy.name) { setSaving(false); return; @@ -195,99 +197,116 @@ const Component: React.FC = (props: Props) => { ; })(); + return ( + , + onClick: onBack, + disabled: false + } + ]} + title={t('Account details')} + > +
+ value.trim(), + required: true + } + ]} + statusHelpAsTooltip={true} + > + + )} + /> + +
+ + + { + selectedFilterTab === FilterTabType.ACCOUNT_ADDRESS && ( + + ) + } + { + selectedFilterTab === FilterTabType.DERIVED_ACCOUNT && ( + + ) + } +
+ ); +}; + +const Wrapper = ({ className }: Props) => { + const { goHome } = useDefaultNavigate(); + const { accountProxyId } = useParams(); + const accountProxy = useGetAccountProxyById(accountProxyId); + const locationState = useLocation().state as AccountDetailParam | undefined; + useEffect(() => { if (!accountProxy) { goHome(); } - }, [accountProxy, goHome, navigate]); + }, [accountProxy, goHome]); if (!accountProxy) { - return null; + return ( + <> + ); } return ( - , - onClick: goHome, - disabled: false - } - ]} - title={t('Account details')} - > -
- value.trim(), - required: true - } - ]} - statusHelpAsTooltip={true} - > - - )} - /> - -
- - - { - selectedFilterTab === FilterTabType.ACCOUNT_ADDRESS && ( - - ) - } - { - selectedFilterTab === FilterTabType.DERIVED_ACCOUNT && ( - - ) - } -
+
); }; -const AccountDetail = styled(Component)(({ theme: { token } }: Props) => { +const AccountDetail = styled(Wrapper)(({ theme: { token } }: Props) => { return { '.ant-sw-screen-layout-body': { display: 'flex', diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx index d169eb9a0a..52d2113a4f 100644 --- a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx +++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx @@ -22,7 +22,6 @@ type Props = ThemeProps & { onClickCopyButton?: VoidFunction; onClickDeriveButton?: VoidFunction; onClickMoreButton?: VoidFunction; - showDeriveButton?: boolean; } type AccountProxyTypeIcon = { @@ -37,7 +36,7 @@ function Component (props: Props): React.ReactElement { onClick, onClickCopyButton, onClickDeriveButton, - onClickMoreButton, showDeriveButton } = props; + onClickMoreButton } = props; const token = useContext(ThemeContext as Context).token; const logoMap = useContext(ThemeContext as Context).logoMap; @@ -123,6 +122,8 @@ function Component (props: Props): React.ReactElement { return null; })(); + const showDeriveButton = !!accountProxy?.children?.length; + return ( <>
= ({ className }: Props) => { }; }, [accountProxies, inactiveModal, location.pathname, navigate, goHome]); - const onViewAccountDetail = useCallback((accountProxy: AccountProxy) => { + const onViewAccountDetail = useCallback((accountProxy: AccountProxy, requestViewDerivedAccounts?: boolean) => { return () => { inactiveModal(modalId); setTimeout(() => { - navigate(`/accounts/detail/${accountProxy.id}`); + navigate(`/accounts/detail/${accountProxy.id}`, { state: { + requestViewDerivedAccounts + } as AccountDetailParam }); }, 100); }; }, [inactiveModal, navigate]); @@ -232,6 +234,7 @@ const Component: React.FC = ({ className }: Props) => { isSelected={item.id === currentAccountProxy?.id} key={item.id} onClick={onSelect(item as AccountProxy)} + onClickDeriveButton={onViewAccountDetail(item as AccountProxy, true)} onClickMoreButton={onViewAccountDetail(item as AccountProxy)} /> ); diff --git a/packages/extension-koni-ui/src/hooks/account/index.ts b/packages/extension-koni-ui/src/hooks/account/index.ts index b59f2dae33..77b2353d47 100644 --- a/packages/extension-koni-ui/src/hooks/account/index.ts +++ b/packages/extension-koni-ui/src/hooks/account/index.ts @@ -19,7 +19,6 @@ export { default as usePreCheckAction } from './usePreCheckAction'; export { default as useSetSelectedAccountTypes } from './useSetSelectedAccountTypes'; export { default as useGetAccountProxyById } from './useGetAccountProxyById'; export { default as useGetAccountNetworkAddresses } from './useGetAccountNetworkAddresses'; -export { default as useGetDerivedAccountProxies } from './useGetDerivedAccountProxies'; export * from './useGetMantaPayConfig'; export * from './useGetZkAddress'; diff --git a/packages/extension-koni-ui/src/hooks/account/useGetDerivedAccountProxies.tsx b/packages/extension-koni-ui/src/hooks/account/useGetDerivedAccountProxies.tsx deleted file mode 100644 index f24d7a0b7d..0000000000 --- a/packages/extension-koni-ui/src/hooks/account/useGetDerivedAccountProxies.tsx +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors -// SPDX-License-Identifier: Apache-2.0 - -import { AccountProxy } from '@subwallet/extension-base/types'; -import { useSelector } from '@subwallet/extension-koni-ui/hooks'; -import { useMemo } from 'react'; - -// todo: recheck logic to get account proxies -const useGetDerivedAccountProxies = (parentAccountProxy: AccountProxy): AccountProxy[] => { - const accountProxies = useSelector((state) => state.accountState.accountProxies); - - return useMemo(() => { - const result: AccountProxy[] = []; - - accountProxies.forEach((ap) => { - if (ap.parentId && ap.parentId === parentAccountProxy.id) { - result.push(ap); - } - }); - - return result; - }, [accountProxies, parentAccountProxy.id]); -}; - -export default useGetDerivedAccountProxies; diff --git a/packages/extension-koni-ui/src/types/navigation.ts b/packages/extension-koni-ui/src/types/navigation.ts index 948a6c2c74..cd648fa1c1 100644 --- a/packages/extension-koni-ui/src/types/navigation.ts +++ b/packages/extension-koni-ui/src/types/navigation.ts @@ -52,6 +52,14 @@ export type EarningPositionDetailParam = { earningSlug: string, }; +// general + export type RemindBackUpSeedPhraseParamState = { from: string; } + +// account detail + +export type AccountDetailParam = { + requestViewDerivedAccounts?: boolean +} From 3bc4b871b30c351bbb6429dfd808c990087285a4 Mon Sep 17 00:00:00 2001 From: lw Date: Thu, 1 Aug 2024 16:23:03 +0700 Subject: [PATCH 035/424] [MasterAccount] Add AddressQrModal and WalletModalContext --- packages/extension-koni-ui/src/Popup/Root.tsx | 6 +- .../Modal/Global/AddressQrModal.tsx | 188 ++++++++++++++++++ .../src/components/Modal/Global/index.ts | 4 + .../Modal/ReceiveModal/ReceiveQrModal.tsx | 2 +- .../Modal/ReceiveModal/SimpleQrModal.tsx | 2 + .../src/components/Modal/index.tsx | 1 + .../extension-koni-ui/src/constants/modal.ts | 1 + ...ext.tsx => WalletModalContextProvider.tsx} | 62 +++++- 8 files changed, 255 insertions(+), 11 deletions(-) create mode 100644 packages/extension-koni-ui/src/components/Modal/Global/AddressQrModal.tsx create mode 100644 packages/extension-koni-ui/src/components/Modal/Global/index.ts rename packages/extension-koni-ui/src/contexts/{WalletModalContext.tsx => WalletModalContextProvider.tsx} (64%) diff --git a/packages/extension-koni-ui/src/Popup/Root.tsx b/packages/extension-koni-ui/src/Popup/Root.tsx index 590f007f71..27df10ddb2 100644 --- a/packages/extension-koni-ui/src/Popup/Root.tsx +++ b/packages/extension-koni-ui/src/Popup/Root.tsx @@ -9,7 +9,7 @@ import { Logo2D } from '@subwallet/extension-koni-ui/components/Logo'; import { CURRENT_PAGE, TRANSACTION_STORAGES } from '@subwallet/extension-koni-ui/constants'; import { DEFAULT_ROUTER_PATH } from '@subwallet/extension-koni-ui/constants/router'; import { DataContext } from '@subwallet/extension-koni-ui/contexts/DataContext'; -import { usePredefinedModal, WalletModalContext } from '@subwallet/extension-koni-ui/contexts/WalletModalContext'; +import { usePredefinedModal, WalletModalContextProvider } from '@subwallet/extension-koni-ui/contexts/WalletModalContextProvider'; import { useGetCurrentPage, useSubscribeLanguage } from '@subwallet/extension-koni-ui/hooks'; import useNotification from '@subwallet/extension-koni-ui/hooks/common/useNotification'; import useUILock from '@subwallet/extension-koni-ui/hooks/common/useUILock'; @@ -284,10 +284,10 @@ export function Root (): React.ReactElement { // Implement WalletModalContext in Root component to make it available for all children and can use react-router-dom and ModalContextProvider return ( - + - + ); } diff --git a/packages/extension-koni-ui/src/components/Modal/Global/AddressQrModal.tsx b/packages/extension-koni-ui/src/components/Modal/Global/AddressQrModal.tsx new file mode 100644 index 0000000000..02f366d79a --- /dev/null +++ b/packages/extension-koni-ui/src/components/Modal/Global/AddressQrModal.tsx @@ -0,0 +1,188 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { getExplorerLink } from '@subwallet/extension-base/services/transaction-service/utils'; +import InfoIcon from '@subwallet/extension-koni-ui/components/Icon/InfoIcon'; +import { ADDRESS_QR_MODAL } from '@subwallet/extension-koni-ui/constants/modal'; +import useNotification from '@subwallet/extension-koni-ui/hooks/common/useNotification'; +import useTranslation from '@subwallet/extension-koni-ui/hooks/common/useTranslation'; +import useFetchChainInfo from '@subwallet/extension-koni-ui/hooks/screen/common/useFetchChainInfo'; +import { ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { toShort } from '@subwallet/extension-koni-ui/utils'; +import { Button, Icon, Logo, SwModal, SwQRCode } from '@subwallet/react-ui'; +import CN from 'classnames'; +import { ArrowSquareOut, CaretLeft, CopySimple } from 'phosphor-react'; +import React, { useCallback, useMemo } from 'react'; +import CopyToClipboard from 'react-copy-to-clipboard'; +import styled from 'styled-components'; + +export interface AddressQrModalProps { + address: string; + chainSlug: string; + onBack?: VoidFunction; +} + +type Props = ThemeProps & AddressQrModalProps & { + onCancel: VoidFunction; +}; + +const modalId = ADDRESS_QR_MODAL; + +const Component: React.FC = ({ address, chainSlug, className, onBack, onCancel }: Props) => { + const { t } = useTranslation(); + const notify = useNotification(); + const chainInfo = useFetchChainInfo(chainSlug); + + const scanExplorerAddressUrl = useMemo(() => { + return getExplorerLink(chainInfo, address, 'account'); + }, [address, chainInfo]); + + const handleClickViewOnExplorer = useCallback(() => { + try { + if (scanExplorerAddressUrl) { + // eslint-disable-next-line no-void + void chrome.tabs.create({ url: scanExplorerAddressUrl, active: true }).then(() => console.log('redirecting')); + } + } catch (e) { + console.log('error redirecting to a new tab'); + } + }, [scanExplorerAddressUrl]); + + const onClickCopyButton = useCallback(() => notify({ message: t('Copied to clipboard') }), [notify, t]); + + return ( + + } + destroyOnClose={true} + id={modalId} + onCancel={onBack || onCancel} + rightIconProps={onBack + ? undefined + : { + icon: , + onClick: onCancel + }} + title={t('Your address')} + > + <> +
+ +
+ +
+
+ + +
+ {toShort(address || '', 7, 7)} +
+ + +
+
+ + + +
+ ); +}; + +const AddressQrModal = styled(Component)(({ theme: { token } }: Props) => { + return { + '.__qr-code-wrapper': { + paddingTop: token.padding, + paddingBottom: token.padding + }, + + '.ant-sw-qr-code': { + marginLeft: 'auto', + marginRight: 'auto' + }, + + '.__address-box-wrapper': { + marginBottom: token.margin + }, + + '.__address-box': { + backgroundColor: token.colorBgSecondary, + borderRadius: token.borderRadiusLG, + display: 'flex', + alignItems: 'center', + paddingLeft: token.paddingSM, + paddingRight: token.paddingXXS, + minHeight: 48, + maxWidth: 232, + marginLeft: 'auto', + marginRight: 'auto' + }, + + '.__address': { + paddingLeft: token.paddingXS, + paddingRight: token.paddingXS, + textOverflow: 'ellipsis', + overflow: 'hidden', + 'white-space': 'nowrap', + color: token.colorTextLight4, + flex: 1 + }, + + '.__copy-button': { + color: token.colorTextLight3, + + '&:hover': { + color: token.colorTextLight2 + } + }, + + '.__view-on-explorer': { + fontSize: token.fontSizeLG + } + }; +}); + +export default AddressQrModal; diff --git a/packages/extension-koni-ui/src/components/Modal/Global/index.ts b/packages/extension-koni-ui/src/components/Modal/Global/index.ts new file mode 100644 index 0000000000..d429b314b7 --- /dev/null +++ b/packages/extension-koni-ui/src/components/Modal/Global/index.ts @@ -0,0 +1,4 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export { default as AddressQrModal } from './AddressQrModal'; diff --git a/packages/extension-koni-ui/src/components/Modal/ReceiveModal/ReceiveQrModal.tsx b/packages/extension-koni-ui/src/components/Modal/ReceiveModal/ReceiveQrModal.tsx index 1933d29eff..62921eac84 100644 --- a/packages/extension-koni-ui/src/components/Modal/ReceiveModal/ReceiveQrModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/ReceiveModal/ReceiveQrModal.tsx @@ -25,7 +25,7 @@ interface Props extends ThemeProps { const modalId = RECEIVE_QR_MODAL; -// todo: merge with simple QR modal +// @deprecated const Component: React.FC = ({ address, className, selectedNetwork }: Props) => { const { t } = useTranslation(); diff --git a/packages/extension-koni-ui/src/components/Modal/ReceiveModal/SimpleQrModal.tsx b/packages/extension-koni-ui/src/components/Modal/ReceiveModal/SimpleQrModal.tsx index 0754fd8120..4e9920b270 100644 --- a/packages/extension-koni-ui/src/components/Modal/ReceiveModal/SimpleQrModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/ReceiveModal/SimpleQrModal.tsx @@ -22,6 +22,8 @@ interface Props extends ThemeProps { onBack?: () => void; } +// @deprecated + const Component: React.FC = ({ address, className, id: modalId, onBack }: Props) => { const { t } = useTranslation(); const notify = useNotification(); diff --git a/packages/extension-koni-ui/src/components/Modal/index.tsx b/packages/extension-koni-ui/src/components/Modal/index.tsx index 6b76a62f49..f2ae88dfe3 100644 --- a/packages/extension-koni-ui/src/components/Modal/index.tsx +++ b/packages/extension-koni-ui/src/components/Modal/index.tsx @@ -10,6 +10,7 @@ export { default as RemindUpgradeVersionModal } from './RemindUpgradeFirefoxVers export { default as AddNetworkWCModal } from './AddNetworkWCModal'; export { SortingModal } from './SortingModal'; +export * from './Global'; export * from './Account'; export * from './AddressBook'; export * from './ActionModal'; diff --git a/packages/extension-koni-ui/src/constants/modal.ts b/packages/extension-koni-ui/src/constants/modal.ts index 00dfcebf26..1c365f6ca4 100644 --- a/packages/extension-koni-ui/src/constants/modal.ts +++ b/packages/extension-koni-ui/src/constants/modal.ts @@ -30,6 +30,7 @@ export const REMIND_BACKUP_SEED_PHRASE_MODAL = 'remind-backup-seed-phrase-modal' export const REMIND_UPGRADE_FIREFOX_VERSION = 'remind-update-firefox-version'; export const EXPORT_ACCOUNTS_PASSWORD_MODAL = 'export-accounts-password-modal'; export const ADD_NETWORK_WALLET_CONNECT_MODAL = 'add-network-wallet-connect-modal'; +export const ADDRESS_QR_MODAL = 'address-qr-modal'; /* Campaign */ export const HOME_CAMPAIGN_BANNER_MODAL = 'home-campaign-banner-modal'; diff --git a/packages/extension-koni-ui/src/contexts/WalletModalContext.tsx b/packages/extension-koni-ui/src/contexts/WalletModalContextProvider.tsx similarity index 64% rename from packages/extension-koni-ui/src/contexts/WalletModalContext.tsx rename to packages/extension-koni-ui/src/contexts/WalletModalContextProvider.tsx index 465926ff17..1552e418d6 100644 --- a/packages/extension-koni-ui/src/contexts/WalletModalContext.tsx +++ b/packages/extension-koni-ui/src/contexts/WalletModalContextProvider.tsx @@ -1,18 +1,19 @@ // Copyright 2019-2022 @polkadot/extension-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AttachAccountModal, ClaimDappStakingRewardsModal, CreateAccountModal, DeriveAccountModal, ImportAccountModal, ImportSeedModal, NewSeedModal, RemindBackupSeedPhraseModal, RequestCameraAccessModal, RequestCreatePasswordModal } from '@subwallet/extension-koni-ui/components'; +import { AddressQrModal, AttachAccountModal, ClaimDappStakingRewardsModal, CreateAccountModal, DeriveAccountModal, ImportAccountModal, ImportSeedModal, NewSeedModal, RemindBackupSeedPhraseModal, RequestCameraAccessModal, RequestCreatePasswordModal } from '@subwallet/extension-koni-ui/components'; import { CustomizeModal } from '@subwallet/extension-koni-ui/components/Modal/Customize/CustomizeModal'; -import { EARNING_INSTRUCTION_MODAL } from '@subwallet/extension-koni-ui/constants'; +import { ADDRESS_QR_MODAL, EARNING_INSTRUCTION_MODAL } from '@subwallet/extension-koni-ui/constants'; import { useGetConfig, useSetSessionLatest } from '@subwallet/extension-koni-ui/hooks'; import Confirmations from '@subwallet/extension-koni-ui/Popup/Confirmations'; import { RootState } from '@subwallet/extension-koni-ui/stores'; import { ModalContext, SwModal, useExcludeModal } from '@subwallet/react-ui'; import CN from 'classnames'; -import React, { useCallback, useContext, useEffect } from 'react'; +import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'; import { useSelector } from 'react-redux'; import { useSearchParams } from 'react-router-dom'; +import { AddressQrModalProps } from '../components/Modal/Global/AddressQrModal'; import { UnlockModal } from '../components/Modal/UnlockModal'; interface Props { @@ -52,8 +53,24 @@ export const usePredefinedModal = () => { return { openPModal, isOpenPModal }; }; -export const WalletModalContext = ({ children }: Props) => { - const { activeModal, hasActiveModal, inactiveAll, inactiveModals } = useContext(ModalContext); +export interface WalletModalContextType { + addressQrModal: { + open: (props: AddressQrModalProps) => void, + close: VoidFunction + } +} + +export const WalletModalContext = React.createContext({ + addressQrModal: { + // eslint-disable-next-line @typescript-eslint/no-empty-function + open: () => {}, + // eslint-disable-next-line @typescript-eslint/no-empty-function + close: () => {} + } +}); + +export const WalletModalContextProvider = ({ children }: Props) => { + const { activeModal, hasActiveModal, inactiveAll, inactiveModal, inactiveModals } = useContext(ModalContext); const [searchParams, setSearchParams] = useSearchParams(); const { hasConfirmations } = useSelector((state: RootState) => state.requestState); const { hasMasterPassword, isLocked } = useSelector((state: RootState) => state.accountState); @@ -71,6 +88,28 @@ export const WalletModalContext = ({ children }: Props) => { }); }, [setSearchParams]); + /* Address QR Modal */ + const [addressQrModalProps, setAddressQrModalProps] = useState(); + + const openAddressQrModal = useCallback((props: AddressQrModalProps) => { + setAddressQrModalProps(props); + activeModal(ADDRESS_QR_MODAL); + }, [activeModal]); + + const closeAddressQrModal = useCallback(() => { + inactiveModal(ADDRESS_QR_MODAL); + setAddressQrModalProps(undefined); + }, [inactiveModal]); + + /* Address QR Modal */ + + const contextValue: WalletModalContextType = useMemo(() => ({ + addressQrModal: { + open: openAddressQrModal, + close: closeAddressQrModal + } + }), [closeAddressQrModal, openAddressQrModal]); + useEffect(() => { if (hasMasterPassword && isLocked) { inactiveAll(); @@ -98,7 +137,7 @@ export const WalletModalContext = ({ children }: Props) => { // todo: will remove ClaimDappStakingRewardsModal after Astar upgrade to v3 - return <> + return + ); }; diff --git a/packages/extension-koni-ui/src/Popup/Account/NewSeedPhrase.tsx b/packages/extension-koni-ui/src/Popup/Account/NewSeedPhrase.tsx index f116c8769f..416586c6dc 100644 --- a/packages/extension-koni-ui/src/Popup/Account/NewSeedPhrase.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/NewSeedPhrase.tsx @@ -77,27 +77,25 @@ const Component: React.FC = ({ className }: Props) => { const onSubmit = useCallback((accountName: string) => { setLoading(true); - setTimeout(() => { - createAccountSuriV2({ - name: accountName, - suri: seedPhrase, - type: undefined, // todo: "undefined" means unified account. Will update the value if there are more types to support - isAllowed: true + createAccountSuriV2({ + name: accountName, + suri: seedPhrase, + type: undefined, // todo: "undefined" means unified account. Will update the value if there are more types to support + isAllowed: true + }) + .then(() => { + onComplete(); }) - .then(() => { - onComplete(); - }) - .catch((error: Error): void => { - notify({ - message: error.message, - type: 'error' - }); - }) - .finally(() => { - setLoading(false); - inactiveModal(ACCOUNT_NAME_MODAL); + .catch((error: Error): void => { + notify({ + message: error.message, + type: 'error' }); - }, 500); + }) + .finally(() => { + setLoading(false); + inactiveModal(ACCOUNT_NAME_MODAL); + }); }, [inactiveModal, notify, onComplete, seedPhrase]); useEffect(() => { diff --git a/packages/extension-koni-ui/src/components/Modal/Account/ImportAccountModal.tsx b/packages/extension-koni-ui/src/components/Modal/Account/ImportAccountModal.tsx index 8a4fdfd24a..2f39650212 100644 --- a/packages/extension-koni-ui/src/components/Modal/Account/ImportAccountModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/Account/ImportAccountModal.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { IMPORT_ACCOUNT_MODAL, IMPORT_SEED_MODAL } from '@subwallet/extension-koni-ui/constants'; +import { IMPORT_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants'; import { useClickOutSide, useGoBackSelectAccount, useIsPopup, useSetSessionLatest, useTranslation } from '@subwallet/extension-koni-ui/hooks'; import { windowOpen } from '@subwallet/extension-koni-ui/messaging'; import { Theme } from '@subwallet/extension-koni-ui/themes'; @@ -34,7 +34,7 @@ const Component: React.FC = ({ className }: Props) => { const { t } = useTranslation(); const { token } = useTheme() as Theme; const { setStateSelectAccount } = useSetSessionLatest(); - const { activeModal, checkActive, inactiveModal } = useContext(ModalContext); + const { checkActive, inactiveModal } = useContext(ModalContext); const isActive = checkActive(modalId); const isPopup = useIsPopup(); @@ -66,8 +66,8 @@ const Component: React.FC = ({ className }: Props) => { const onClickSeed = useCallback(() => { inactiveModal(modalId); - activeModal(IMPORT_SEED_MODAL); - }, [activeModal, inactiveModal]); + navigate('/accounts/import-seed-phrase'); + }, [inactiveModal, navigate]); const items = useMemo((): ImportAccountItem[] => [ { From 1b5b46cb5678ce3e6272ded64b9e8235c21304ed Mon Sep 17 00:00:00 2001 From: lw Date: Tue, 6 Aug 2024 16:25:02 +0700 Subject: [PATCH 053/424] [MasterAccount] Update logic to show TON address --- package.json | 2 +- .../src/components/Modal/Global/AddressQrModal.tsx | 8 +++----- .../account/useGetAccountNetworkAddresses.tsx | 14 ++++++++++++-- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index a2791dac5f..29e129c347 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "@polkadot/types-support": "^12.0.2", "@polkadot/util": "^12.6.2", "@polkadot/util-crypto": "^12.6.2", - "@subwallet/chain-list": "0.2.80-beta.4", + "@subwallet/chain-list": "file:../SubWallet-ChainList/packages/chain-list/build/", "@subwallet/keyring": "file:../SubWallet-Base/packages/keyring/build/", "@subwallet/react-ui": "5.1.2-b79", "@subwallet/ui-keyring": "file:../SubWallet-Base/packages/ui-keyring/build/", diff --git a/packages/extension-koni-ui/src/components/Modal/Global/AddressQrModal.tsx b/packages/extension-koni-ui/src/components/Modal/Global/AddressQrModal.tsx index bf5bab0e18..ed03ced229 100644 --- a/packages/extension-koni-ui/src/components/Modal/Global/AddressQrModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/Global/AddressQrModal.tsx @@ -157,12 +157,10 @@ const AddressQrModal = styled(Component)(({ theme: { token } }: Props) => borderRadius: token.borderRadiusLG, display: 'flex', alignItems: 'center', + justifyContent: 'center', paddingLeft: token.paddingSM, paddingRight: token.paddingXXS, - minHeight: 48, - maxWidth: 232, - marginLeft: 'auto', - marginRight: 'auto' + minHeight: 48 }, '.__address': { @@ -172,7 +170,7 @@ const AddressQrModal = styled(Component)(({ theme: { token } }: Props) => overflow: 'hidden', 'white-space': 'nowrap', color: token.colorTextLight4, - flex: 1 + flexShrink: 1 }, '.__copy-button': { diff --git a/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx b/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx index 03a0bbd642..8e6b8b1efc 100644 --- a/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx +++ b/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { _ChainInfo } from '@subwallet/chain-list/types'; -import { _isChainEvmCompatible, _isPureSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils'; +import { _isChainEvmCompatible, _isChainTonCompatible, _isPureSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils'; import { AccountNetworkType, AccountProxy } from '@subwallet/extension-base/types'; import { reformatAddress } from '@subwallet/extension-base/utils'; import { useSelector } from '@subwallet/extension-koni-ui/hooks'; @@ -18,12 +18,16 @@ function isChainInfoAccordantNetworkType (chainInfo: _ChainInfo, networkType: Ac return _isChainEvmCompatible(chainInfo); } + if (networkType === AccountNetworkType.TON) { + return _isChainTonCompatible(chainInfo); + } + return false; } // todo: // - order the result -// - support ton, bitcoin +// - support bitcoin // - logic for generic, legacy ledger account const useGetAccountNetworkAddresses = (accountProxy: AccountProxy): AccountNetworkAddress[] => { const chainInfoMap = useSelector((state) => state.chainStore.chainInfoMap); @@ -51,6 +55,12 @@ const useGetAccountNetworkAddresses = (accountProxy: AccountProxy): AccountNetwo slug: chainInfo.slug, address: a.address }); + } else if (a.networkType === AccountNetworkType.TON && chainInfo.tonInfo) { + result.push({ + name: chainInfo.name, + slug: chainInfo.slug, + address: reformatAddress(a.address, chainInfo.isTestnet ? 0 : 1) + }); } } }); From 5e507995dddd8ef7f9c7e6b971769ac053047fe5 Mon Sep 17 00:00:00 2001 From: lw Date: Tue, 6 Aug 2024 16:31:18 +0700 Subject: [PATCH 054/424] [MasterAccount] Update ImportSeedPhrase navigation --- .../extension-koni-ui/src/Popup/Account/ImportSeedPhrase.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/extension-koni-ui/src/Popup/Account/ImportSeedPhrase.tsx b/packages/extension-koni-ui/src/Popup/Account/ImportSeedPhrase.tsx index 0beb45b603..aa88b6bb93 100644 --- a/packages/extension-koni-ui/src/Popup/Account/ImportSeedPhrase.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/ImportSeedPhrase.tsx @@ -4,7 +4,7 @@ import { NotificationType } from '@subwallet/extension-base/background/KoniTypes'; import { ResponseMnemonicValidateV2 } from '@subwallet/extension-base/types'; import { AccountNameModal, CloseIcon, Layout, PageWrapper, PhraseNumberSelector, SeedPhraseInput } from '@subwallet/extension-koni-ui/components'; -import { ACCOUNT_NAME_MODAL, IMPORT_SEED_MODAL } from '@subwallet/extension-koni-ui/constants'; +import { ACCOUNT_NAME_MODAL, IMPORT_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants'; import { WalletModalContext } from '@subwallet/extension-koni-ui/contexts/WalletModalContextProvider'; import { useAutoNavigateToCreatePassword, useCompleteCreateAccount, useDefaultNavigate, useFocusFormItem, useGoBackFromCreateAccount, useNotification, useTranslation, useUnlockChecker } from '@subwallet/extension-koni-ui/hooks'; import { createAccountSuriV2, validateSeedV2 } from '@subwallet/extension-koni-ui/messaging'; @@ -44,7 +44,7 @@ const Component: React.FC = ({ className }: Props) => { const notify = useNotification(); const onComplete = useCompleteCreateAccount(); - const onBack = useGoBackFromCreateAccount(IMPORT_SEED_MODAL); + const onBack = useGoBackFromCreateAccount(IMPORT_ACCOUNT_MODAL); const { activeModal, inactiveModal } = useContext(ModalContext); const { alertModal } = useContext(WalletModalContext); From 928b67c949581e41e58386f9187beeaef8e0d156 Mon Sep 17 00:00:00 2001 From: S2kael Date: Tue, 6 Aug 2024 19:33:18 +0700 Subject: [PATCH 055/424] [Issue-3396] Fix wrong address on balance map --- .../src/services/balance-service/BalanceMapImpl.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/extension-base/src/services/balance-service/BalanceMapImpl.ts b/packages/extension-base/src/services/balance-service/BalanceMapImpl.ts index 3f7ab597a6..7aa5443e69 100644 --- a/packages/extension-base/src/services/balance-service/BalanceMapImpl.ts +++ b/packages/extension-base/src/services/balance-service/BalanceMapImpl.ts @@ -125,7 +125,7 @@ export class BalanceMapImpl { const rs: BalanceInfo = {}; Object.entries(balanceMap).forEach(([tokenSlug, balanceItems]) => { - rs[tokenSlug] = groupBalance(balanceItems, tokenSlug, tokenSlug); + rs[tokenSlug] = groupBalance(balanceItems, compoundKey, tokenSlug); }); this._map[compoundKey] = rs; From 10893e167b5e50825a9594d8391c4636d70390ce Mon Sep 17 00:00:00 2001 From: lw Date: Wed, 7 Aug 2024 12:07:12 +0700 Subject: [PATCH 056/424] [MasterAccount] Update logic to show balance --- .../src/Popup/Home/Tokens/DetailModal.tsx | 70 ++++--------------- .../TokenItem/AccountTokenBalanceItem.tsx | 1 + .../hooks/screen/home/useAccountBalance.ts | 55 ++++++--------- 3 files changed, 37 insertions(+), 89 deletions(-) diff --git a/packages/extension-koni-ui/src/Popup/Home/Tokens/DetailModal.tsx b/packages/extension-koni-ui/src/Popup/Home/Tokens/DetailModal.tsx index ab73cf26af..17f96a52f3 100644 --- a/packages/extension-koni-ui/src/Popup/Home/Tokens/DetailModal.tsx +++ b/packages/extension-koni-ui/src/Popup/Home/Tokens/DetailModal.tsx @@ -1,23 +1,19 @@ // Copyright 2019-2022 @polkadot/extension-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { _ChainAsset } from '@subwallet/chain-list/types'; import { APIItemState } from '@subwallet/extension-base/background/KoniTypes'; -import { getExplorerLink } from '@subwallet/extension-base/services/transaction-service/utils'; import { BalanceItem } from '@subwallet/extension-base/types'; -import { isSameAddress } from '@subwallet/extension-base/utils'; import { AccountTokenBalanceItem, EmptyList, RadioGroup } from '@subwallet/extension-koni-ui/components'; -import { useGetChainPrefixBySlug, useSelector } from '@subwallet/extension-koni-ui/hooks'; +import { useSelector } from '@subwallet/extension-koni-ui/hooks'; import useTranslation from '@subwallet/extension-koni-ui/hooks/common/useTranslation'; -import { RootState } from '@subwallet/extension-koni-ui/stores'; import { ThemeProps } from '@subwallet/extension-koni-ui/types'; import { TokenBalanceItemType } from '@subwallet/extension-koni-ui/types/balance'; -import { isAccountAll, reformatAddress } from '@subwallet/extension-koni-ui/utils'; -import { Button, Form, Icon, ModalContext, Number, SwModal } from '@subwallet/react-ui'; +import { isAccountAll } from '@subwallet/extension-koni-ui/utils'; +import { Form, Icon, ModalContext, Number, SwModal } from '@subwallet/react-ui'; import BigN from 'bignumber.js'; import CN from 'classnames'; -import { ArrowCircleLeft, ArrowSquareOut, Coins } from 'phosphor-react'; -import React, { useCallback, useContext, useEffect, useMemo } from 'react'; +import { ArrowCircleLeft, Coins } from 'phosphor-react'; +import React, { useContext, useEffect, useMemo } from 'react'; import styled from 'styled-components'; type Props = ThemeProps & { @@ -51,6 +47,7 @@ interface FormState { view: ViewValue } +// todo: need to recheck account balance logic again function Component ({ className = '', currentTokenInfo, id, onCancel, tokenBalanceMap }: Props): React.ReactElement { const { t } = useTranslation(); @@ -58,36 +55,13 @@ function Component ({ className = '', currentTokenInfo, id, onCancel, tokenBalan const isActive = checkActive(id); - const { currentAccount, isAllAccount } = useSelector((state) => state.accountState); - const { assetRegistry } = useSelector((state) => state.assetRegistry); + const { accountProxies, currentAccountProxy, isAllAccount } = useSelector((state) => state.accountState); const { balanceMap } = useSelector((state) => state.balance); - const chainInfoMap = useSelector((state: RootState) => state.chainStore.chainInfoMap); const [form] = Form.useForm(); const view = Form.useWatch('view', form); - const tokenInfo = useMemo((): _ChainAsset|undefined => currentTokenInfo && assetRegistry[currentTokenInfo?.slug], [assetRegistry, currentTokenInfo]); - const addressPrefix = useGetChainPrefixBySlug(tokenInfo?.originChain); - const reformatedAddress = useMemo(() => currentAccount?.address && reformatAddress(currentAccount?.address, addressPrefix), [currentAccount?.address, addressPrefix]); - - const chainInfo = useMemo(() => { - if (tokenInfo?.originChain === undefined) { - return undefined; - } - - return chainInfoMap[tokenInfo.originChain]; - }, [chainInfoMap, tokenInfo?.originChain]); - - const openBlockExplorer = useCallback( - (link: string) => { - return () => { - window.open(link, '_blank'); - }; - }, - [] - ); - const defaultValues = useMemo((): FormState => ({ view: ViewValue.OVERVIEW }), []); @@ -135,16 +109,16 @@ function Component ({ className = '', currentTokenInfo, id, onCancel, tokenBalan const result: BalanceItem[] = []; - const filterAddress = (address: string) => { + const filterAccountId = (accountId: string) => { if (isAllAccount) { - return !isAccountAll(address); + return !isAccountAll(accountId) && accountProxies.some((ap) => ap.id === accountId); } else { - return isSameAddress(address, currentAccount?.address || ''); + return accountId === currentAccountProxy?.id; } }; - for (const [address, info] of Object.entries(balanceMap)) { - if (filterAddress(address)) { + for (const [accountId, info] of Object.entries(balanceMap)) { + if (filterAccountId(accountId)) { const item = info[currentTokenInfo.slug]; if (item && item.state === APIItemState.READY) { @@ -159,7 +133,7 @@ function Component ({ className = '', currentTokenInfo, id, onCancel, tokenBalan return bTotal.minus(aTotal).toNumber(); }); - }, [balanceMap, currentAccount?.address, currentTokenInfo?.slug, isAllAccount]); + }, [accountProxies, balanceMap, currentAccountProxy?.id, currentTokenInfo?.slug, isAllAccount]); const symbol = currentTokenInfo?.symbol || ''; @@ -169,8 +143,6 @@ function Component ({ className = '', currentTokenInfo, id, onCancel, tokenBalan }); }, [accountItems]); - const link = (chainInfo !== undefined && reformatedAddress) && getExplorerLink(chainInfo, reformatedAddress, 'account'); - useEffect(() => { if (!isActive) { form?.resetFields(); @@ -224,22 +196,6 @@ function Component ({ className = '', currentTokenInfo, id, onCancel, tokenBalan
))}
- {!isAllAccount &&
- {!!link && ( - - )} -
} ) } diff --git a/packages/extension-koni-ui/src/components/TokenItem/AccountTokenBalanceItem.tsx b/packages/extension-koni-ui/src/components/TokenItem/AccountTokenBalanceItem.tsx index 71beddea3e..f822014e0c 100644 --- a/packages/extension-koni-ui/src/components/TokenItem/AccountTokenBalanceItem.tsx +++ b/packages/extension-koni-ui/src/components/TokenItem/AccountTokenBalanceItem.tsx @@ -22,6 +22,7 @@ interface Props extends ThemeProps { item: BalanceItem; } +// todo: logic in this file may not be correct in some case, need to recheck const Component: React.FC = (props: Props) => { const { className, item } = props; diff --git a/packages/extension-koni-ui/src/hooks/screen/home/useAccountBalance.ts b/packages/extension-koni-ui/src/hooks/screen/home/useAccountBalance.ts index 6051f75fc4..61989effb0 100644 --- a/packages/extension-koni-ui/src/hooks/screen/home/useAccountBalance.ts +++ b/packages/extension-koni-ui/src/hooks/screen/home/useAccountBalance.ts @@ -94,7 +94,7 @@ function getDefaultTokenBalance ( } function getAccountBalance ( - address: string, + accountProxyId: string, tokenGroupMap: Record, balanceMap: BalanceStore['balanceMap'], priceMap: PriceStore['priceMap'], @@ -136,7 +136,7 @@ function getAccountBalance ( tokenBalance.currency = currency; const originChain = _getAssetOriginChain(chainAsset); - const balanceItem = balanceMap[address]?.[tokenSlug]; + const balanceItem = balanceMap[accountProxyId]?.[tokenSlug]; const decimals = _getAssetDecimals(chainAsset); const isTokenBalanceReady = !!balanceItem && (balanceItem.state !== APIItemState.PENDING); @@ -164,23 +164,6 @@ function getAccountBalance ( tokenBalance.total.value = tokenBalance.free.value.plus(tokenBalance.locked.value); - // if (balanceItem?.substrateInfo) { - // const mergeData = (key: keyof SubstrateBalance) => { - // const newValue = balanceItem?.substrateInfo?.[key]; - // - // if (newValue) { - // const value = getBalanceValue(newValue, decimals); - // - // tokenBalance[key] = new BigN(tokenBalance[key] || '0').plus(value).toString(); - // tokenGroupBalance[key] = new BigN(tokenGroupBalance[key] || '0').plus(value).toString(); - // } - // }; - // - // mergeData('reserved'); - // mergeData('miscFrozen'); - // mergeData('feeFrozen'); - // } - if (!isShowZeroBalance && tokenBalance.total.value.eq(BN_0)) { return; } @@ -245,6 +228,12 @@ function getAccountBalance ( tokenGroupBalance.isReady = isTokenGroupBalanceReady; tokenGroupBalance.isNotSupport = tokenGroupNotSupport.every((e) => e); + if (multiChainAsset && !multiChainAsset.hasValue) { + tokenGroupBalance.isTestnet = true; + } else if (!multiChainAsset && tokenGroupMap[tokenGroupKey].length === 1 && tokenBalanceMap[tokenGroupKey]) { + tokenGroupBalance.isTestnet = tokenBalanceMap[tokenGroupKey].isTestnet; + } + if (!isShowZeroBalance && (!isTokenGroupBalanceReady || tokenGroupBalance.total.value.eq(BN_0))) { return; } @@ -311,22 +300,24 @@ export default function useAccountBalance (tokenGroupMap: Record state.assetRegistry.assetRegistry); const multiChainAssetMap = useSelector((state: RootState) => state.assetRegistry.multiChainAssetMap); const isShowZeroBalanceSetting = useSelector((state: RootState) => state.settings.isShowZeroBalance); - const currentAccount = useSelector((state: RootState) => state.accountState.currentAccount); + const currentAccountProxy = useSelector((state: RootState) => state.accountState.currentAccountProxy); const isShowZeroBalance = useMemo(() => { return showZeroBalance || isShowZeroBalanceSetting; }, [isShowZeroBalanceSetting, showZeroBalance]); - return getAccountBalance( - currentAccount?.address || '', - tokenGroupMap, - balanceMap, - priceMap, - price24hMap, - assetRegistryMap, - multiChainAssetMap, - chainInfoMap, - isShowZeroBalance, - currency - ); + return useMemo(() => { + return getAccountBalance( + currentAccountProxy?.id || '', + tokenGroupMap, + balanceMap, + priceMap, + price24hMap, + assetRegistryMap, + multiChainAssetMap, + chainInfoMap, + isShowZeroBalance, + currency + ); + }, [assetRegistryMap, balanceMap, chainInfoMap, currency, currentAccountProxy?.id, isShowZeroBalance, multiChainAssetMap, price24hMap, priceMap, tokenGroupMap]); } From 33681599606b04bf9aae1610fff85de0854ad5ee Mon Sep 17 00:00:00 2001 From: S2kael Date: Wed, 7 Aug 2024 14:45:09 +0700 Subject: [PATCH 057/424] [Issue-3396] Lint and remove some unused class --- .../keyring-service/account-context.ts | 17 ++--- .../swap-service/handler/chainflip-handler.ts | 2 +- .../src/signers/substrates/KeyringSigner.ts | 37 ---------- .../src/signers/substrates/LedgerSigner.ts | 45 ------------ .../src/signers/substrates/QrSigner.ts | 67 ------------------ .../src/signers/web3/QrSigner.ts | 70 ------------------- .../src/Popup/Settings/Chains/AddProvider.tsx | 2 +- .../src/Popup/Settings/Chains/ChainDetail.tsx | 2 +- .../Popup/Settings/Chains/ManageChains.tsx | 2 +- .../src/Popup/Settings/Chains/AddProvider.tsx | 2 +- .../src/Popup/Settings/Chains/ChainDetail.tsx | 2 +- .../Popup/Settings/Chains/ManageChains.tsx | 2 +- 12 files changed, 14 insertions(+), 236 deletions(-) delete mode 100644 packages/extension-base/src/signers/substrates/KeyringSigner.ts delete mode 100644 packages/extension-base/src/signers/substrates/LedgerSigner.ts delete mode 100644 packages/extension-base/src/signers/substrates/QrSigner.ts delete mode 100644 packages/extension-base/src/signers/web3/QrSigner.ts diff --git a/packages/extension-base/src/services/keyring-service/account-context.ts b/packages/extension-base/src/services/keyring-service/account-context.ts index 4a5f8fddcc..338e5ec046 100644 --- a/packages/extension-base/src/services/keyring-service/account-context.ts +++ b/packages/extension-base/src/services/keyring-service/account-context.ts @@ -485,17 +485,9 @@ export class AccountContext { throw Error(t('Please choose at least one account type')); } - // const currentAccount = this.#koniState.keyringService.context.currentAccount; - // const allGenesisHash = currentAccount?.allGenesisHash || undefined; - const multiChain = types.length > 1; const proxyId = multiChain ? this.createAccountGroupId(_suri) : ''; - // Upsert account group first, to avoid combine latest have no account group data. - if (proxyId) { - this.upsertAccountProxy({ id: proxyId, name }); - } - const modifiedPairs = this.modifyPairsSubject.value; types.forEach((type) => { @@ -507,6 +499,11 @@ export class AccountContext { addressDict[type] = address; }); + // Upsert account group first, to avoid combine latest have no account group data. + if (proxyId) { + this.upsertAccountProxy({ id: proxyId, name }); + } + // Upsert modify pair before add account to keyring this.upsertModifyPairs(modifiedPairs); @@ -559,7 +556,7 @@ export class AccountContext { genesisHash: '' }; - if ([...BitcoinKeypairTypes, ...TonKeypairTypes].includes(type)) { + if ([...BitcoinKeypairTypes, ...TonKeypairTypes].includes(type) && isReadOnly) { meta.noPublicKey = true; } @@ -1248,8 +1245,8 @@ export class AccountContext { /* Inject */ /** - * @deprecated * Account ref + * @deprecated * */ /** @deprecated */ diff --git a/packages/extension-base/src/services/swap-service/handler/chainflip-handler.ts b/packages/extension-base/src/services/swap-service/handler/chainflip-handler.ts index b82a776a46..f463055e34 100644 --- a/packages/extension-base/src/services/swap-service/handler/chainflip-handler.ts +++ b/packages/extension-base/src/services/swap-service/handler/chainflip-handler.ts @@ -12,7 +12,7 @@ import { BalanceService } from '@subwallet/extension-base/services/balance-servi import { getERC20TransactionObject, getEVMTransactionObject } from '@subwallet/extension-base/services/balance-service/transfer/smart-contract'; import { createTransferExtrinsic } from '@subwallet/extension-base/services/balance-service/transfer/token'; import { ChainService } from '@subwallet/extension-base/services/chain-service'; -import { _getAssetDecimals, _getChainNativeTokenSlug, _getContractAddressOfToken, _isNativeToken, _isChainSubstrateCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { _getAssetDecimals, _getChainNativeTokenSlug, _getContractAddressOfToken, _isChainSubstrateCompatible, _isNativeToken } from '@subwallet/extension-base/services/chain-service/utils'; import { SwapBaseHandler, SwapBaseInterface } from '@subwallet/extension-base/services/swap-service/handler/base-handler'; import { calculateSwapRate, CHAIN_FLIP_SUPPORTED_MAINNET_ASSET_MAPPING, CHAIN_FLIP_SUPPORTED_MAINNET_MAPPING, CHAIN_FLIP_SUPPORTED_TESTNET_ASSET_MAPPING, CHAIN_FLIP_SUPPORTED_TESTNET_MAPPING, SWAP_QUOTE_TIMEOUT_MAP } from '@subwallet/extension-base/services/swap-service/utils'; import { TransactionData } from '@subwallet/extension-base/types'; diff --git a/packages/extension-base/src/signers/substrates/KeyringSigner.ts b/packages/extension-base/src/signers/substrates/KeyringSigner.ts deleted file mode 100644 index 6d97827421..0000000000 --- a/packages/extension-base/src/signers/substrates/KeyringSigner.ts +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2017-2022 @polkadot/react-signer authors & contributors -// SPDX-License-Identifier: Apache-2.0 - -import type { Signer, SignerResult } from '@polkadot/api/types'; -import type { Registry, SignerPayloadJSON } from '@polkadot/types/types'; - -import { KeyringPair } from '@subwallet/keyring/types'; - -interface KeyringSignerProps { - registry: Registry; - keyPair: KeyringPair; -} - -let id = 1; - -export default class KeyringSigner implements Signer { - readonly #pair: KeyringPair; - readonly #registry: Registry; - - constructor ({ keyPair, registry }: KeyringSignerProps) { - this.#pair = keyPair; - this.#registry = registry; - } - - public async signPayload (payload: SignerPayloadJSON): Promise { - return new Promise((resolve) => { - const wrapper = this.#registry.createType('ExtrinsicPayload', payload, { version: payload.version }); - - const signature = wrapper.sign(this.#pair).signature; - - resolve({ - id: id++, - signature: signature - }); - }); - } -} diff --git a/packages/extension-base/src/signers/substrates/LedgerSigner.ts b/packages/extension-base/src/signers/substrates/LedgerSigner.ts deleted file mode 100644 index a70b8e2915..0000000000 --- a/packages/extension-base/src/signers/substrates/LedgerSigner.ts +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2019-2022 @subwallet/extension-base authors & contributors -// SPDX-License-Identifier: Apache-2.0 - -import type { Signer, SignerResult } from '@polkadot/api/types'; -import type { Registry, SignerPayloadJSON } from '@polkadot/types/types'; - -import { ExternalRequestPromise, ExternalRequestPromiseStatus } from '@subwallet/extension-base/background/KoniTypes'; -import { LedgerState } from '@subwallet/extension-base/signers/types'; - -import { u8aToHex } from '@polkadot/util'; - -interface CallbackProps { - ledgerState: LedgerState -} - -export default class LedgerSigner implements Signer { - readonly #registry: Registry; - readonly #callback: (state: CallbackProps) => void; - readonly #setState: (promise: ExternalRequestPromise) => void; - readonly #id: string; - - constructor (registry: Registry, callback: (state: CallbackProps) => void, id: string, setState: (promise: ExternalRequestPromise) => void) { - this.#registry = registry; - this.#callback = callback; - this.#id = id; - - this.#setState = setState; - } - - public async signPayload (payload: SignerPayloadJSON): Promise { - return new Promise((resolve, reject): void => { - const raw = this.#registry.createType('ExtrinsicPayload', payload, { version: payload.version }); - const ledgerPayload = raw.toU8a(true); - - this.#setState({ reject: reject, resolve: resolve, status: ExternalRequestPromiseStatus.PENDING, createdAt: new Date().getTime() }); - - this.#callback({ - ledgerState: { - ledgerPayload: u8aToHex(ledgerPayload), - ledgerId: this.#id - } - }); - }); - } -} diff --git a/packages/extension-base/src/signers/substrates/QrSigner.ts b/packages/extension-base/src/signers/substrates/QrSigner.ts deleted file mode 100644 index a24e7624e4..0000000000 --- a/packages/extension-base/src/signers/substrates/QrSigner.ts +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2017-2022 @polkadot/react-signer authors & contributors -// SPDX-License-Identifier: Apache-2.0 - -import type { Signer, SignerResult } from '@polkadot/api/types'; -import type { Registry, SignerPayloadJSON } from '@polkadot/types/types'; - -import { ExternalRequestPromise, ExternalRequestPromiseStatus } from '@subwallet/extension-base/background/KoniTypes'; -import { QrState } from '@subwallet/extension-base/signers/types'; - -import { u8aToHex } from '@polkadot/util'; -import { blake2AsU8a } from '@polkadot/util-crypto'; - -interface CallbackProps { - qrState: QrState -} - -interface QrSignerProps { - registry: Registry; - callback: (state: CallbackProps) => void; - id: string; - setState: (promise: ExternalRequestPromise) => void; - resolver: () => void; -} - -export default class QrSigner implements Signer { - readonly #callback: (state: CallbackProps) => void; - readonly #id: string; - readonly #registry: Registry; - readonly #resolver: () => void; - readonly #setState: (promise: ExternalRequestPromise) => void; - - constructor ({ callback, id, registry, resolver, setState }: QrSignerProps) { - this.#callback = callback; - this.#id = id; - this.#registry = registry; - this.#resolver = resolver; - this.#setState = setState; - } - - public async signPayload (payload: SignerPayloadJSON): Promise { - return new Promise((resolve, reject): void => { - // limit size of the transaction - const isQrHashed = (payload.method.length > 5000); - const wrapper = this.#registry.createType('ExtrinsicPayload', payload, { version: payload.version }); - const qrPayload = isQrHashed - ? blake2AsU8a(wrapper.toU8a(true)) - : wrapper.toU8a(); - - const resolver = (result: SignerResult | PromiseLike): void => { - this.#resolver(); - resolve(result); - }; - - this.#setState({ reject: reject, resolve: resolver, status: ExternalRequestPromiseStatus.PENDING, createdAt: new Date().getTime() }); - - this.#callback({ - qrState: { - isQrHashed, - qrAddress: payload.address, - qrPayload: u8aToHex(qrPayload), - qrId: this.#id, - isEthereum: false - } - }); - }); - } -} diff --git a/packages/extension-base/src/signers/web3/QrSigner.ts b/packages/extension-base/src/signers/web3/QrSigner.ts deleted file mode 100644 index 457c33954b..0000000000 --- a/packages/extension-base/src/signers/web3/QrSigner.ts +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2019-2022 @subwallet/extension-base authors & contributors -// SPDX-License-Identifier: Apache-2.0 - -import { ExternalRequestPromise, ExternalRequestPromiseStatus } from '@subwallet/extension-base/background/KoniTypes'; -import { QrState, Web3Transaction } from '@subwallet/extension-base/signers/types'; -import { addHexPrefix } from 'ethereumjs-util'; -import { ethers, TransactionLike } from 'ethers'; - -import { SignerResult } from '@polkadot/api/types'; -import { HexString } from '@polkadot/util/types'; - -interface CallbackProps { - qrState: QrState -} - -interface QrSignerProps { - callback: (state: CallbackProps) => void; - id: string; - setState: (promise: ExternalRequestPromise) => void; - resolver: () => void; -} - -export default class QrSigner { - readonly #callback: (state: CallbackProps) => void; - readonly #id: string; - readonly #resolver: () => void; - readonly #setState: (promise: ExternalRequestPromise) => void; - - constructor ({ callback, id, resolver, setState }: QrSignerProps) { - this.#callback = callback; - this.#id = id; - this.#resolver = resolver; - this.#setState = setState; - } - - public async signTransaction (tx: Web3Transaction): Promise { - return new Promise((resolve, reject): void => { - const txObject: TransactionLike = { - nonce: tx.nonce ?? 0, - gasPrice: addHexPrefix(tx.gasPrice.toString(16)), - maxPriorityFeePerGas: addHexPrefix(tx.maxPriorityFeePerGas.toString(16)), - maxFeePerGas: addHexPrefix(tx.maxFeePerGas.toString(16)), - gasLimit: addHexPrefix(tx.gasLimit.toString(16)), - to: tx.to !== undefined ? tx.to : '', - value: addHexPrefix(tx.value.toString(16)), - data: tx.data, - chainId: tx.chainId - }; - - const qrPayload = ethers.Transaction.from(txObject).unsignedSerialized as HexString; - - const resolver = (result: SignerResult | PromiseLike): void => { - this.#resolver(); - resolve(result); - }; - - this.#setState({ reject: reject, resolve: resolver, status: ExternalRequestPromiseStatus.PENDING, createdAt: new Date().getTime() }); - - this.#callback({ - qrState: { - isQrHashed: false, - qrAddress: tx.from, - qrPayload: qrPayload, - qrId: this.#id, - isEthereum: true - } - }); - }); - } -} diff --git a/packages/extension-koni-ui/src/Popup/Settings/Chains/AddProvider.tsx b/packages/extension-koni-ui/src/Popup/Settings/Chains/AddProvider.tsx index 513f0fc442..f83d46d848 100644 --- a/packages/extension-koni-ui/src/Popup/Settings/Chains/AddProvider.tsx +++ b/packages/extension-koni-ui/src/Popup/Settings/Chains/AddProvider.tsx @@ -3,7 +3,7 @@ import { _CHAIN_VALIDATION_ERROR } from '@subwallet/extension-base/services/chain-service/handler/types'; import { _NetworkUpsertParams } from '@subwallet/extension-base/services/chain-service/types'; -import { _generateCustomProviderKey, _getChainNativeTokenBasicInfo, _isChainEvmCompatible, _isCustomProvider, _isChainSubstrateCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { _generateCustomProviderKey, _getChainNativeTokenBasicInfo, _isChainEvmCompatible, _isChainSubstrateCompatible, _isCustomProvider } from '@subwallet/extension-base/services/chain-service/utils'; import { isUrl } from '@subwallet/extension-base/utils'; import { Layout, PageWrapper } from '@subwallet/extension-koni-ui/components'; import InfoIcon from '@subwallet/extension-koni-ui/components/Icon/InfoIcon'; diff --git a/packages/extension-koni-ui/src/Popup/Settings/Chains/ChainDetail.tsx b/packages/extension-koni-ui/src/Popup/Settings/Chains/ChainDetail.tsx index afcef5ee79..4b27bed4b4 100644 --- a/packages/extension-koni-ui/src/Popup/Settings/Chains/ChainDetail.tsx +++ b/packages/extension-koni-ui/src/Popup/Settings/Chains/ChainDetail.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { _NetworkUpsertParams } from '@subwallet/extension-base/services/chain-service/types'; -import { _getBlockExplorerFromChain, _getChainNativeTokenBasicInfo, _getChainSubstrateAddressPrefix, _getCrowdloanUrlFromChain, _getEvmChainId, _getSubstrateParaId, _isChainEvmCompatible, _isCustomChain, _isPureEvmChain, _isChainSubstrateCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { _getBlockExplorerFromChain, _getChainNativeTokenBasicInfo, _getChainSubstrateAddressPrefix, _getCrowdloanUrlFromChain, _getEvmChainId, _getSubstrateParaId, _isChainEvmCompatible, _isChainSubstrateCompatible, _isCustomChain, _isPureEvmChain } from '@subwallet/extension-base/services/chain-service/utils'; import { isUrl } from '@subwallet/extension-base/utils'; import { Layout, PageWrapper } from '@subwallet/extension-koni-ui/components'; import { ProviderSelector } from '@subwallet/extension-koni-ui/components/Field/ProviderSelector'; diff --git a/packages/extension-koni-ui/src/Popup/Settings/Chains/ManageChains.tsx b/packages/extension-koni-ui/src/Popup/Settings/Chains/ManageChains.tsx index ef9af74642..99754a1840 100644 --- a/packages/extension-koni-ui/src/Popup/Settings/Chains/ManageChains.tsx +++ b/packages/extension-koni-ui/src/Popup/Settings/Chains/ManageChains.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { _isChainEvmCompatible, _isCustomChain, _isChainSubstrateCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { _isChainEvmCompatible, _isChainSubstrateCompatible, _isCustomChain } from '@subwallet/extension-base/services/chain-service/utils'; import { FilterModal, Layout, NetworkEmptyList, NetworkToggleItem, OptionType, PageWrapper } from '@subwallet/extension-koni-ui/components'; import { DataContext } from '@subwallet/extension-koni-ui/contexts/DataContext'; import { ChainInfoWithState, useFilterModal, useTranslation } from '@subwallet/extension-koni-ui/hooks'; diff --git a/packages/extension-web-ui/src/Popup/Settings/Chains/AddProvider.tsx b/packages/extension-web-ui/src/Popup/Settings/Chains/AddProvider.tsx index 96e4604259..d9e831664a 100644 --- a/packages/extension-web-ui/src/Popup/Settings/Chains/AddProvider.tsx +++ b/packages/extension-web-ui/src/Popup/Settings/Chains/AddProvider.tsx @@ -3,7 +3,7 @@ import { _CHAIN_VALIDATION_ERROR } from '@subwallet/extension-base/services/chain-service/handler/types'; import { _NetworkUpsertParams } from '@subwallet/extension-base/services/chain-service/types'; -import { _generateCustomProviderKey, _getChainNativeTokenBasicInfo, _isChainEvmCompatible, _isCustomProvider, _isChainSubstrateCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { _generateCustomProviderKey, _getChainNativeTokenBasicInfo, _isChainEvmCompatible, _isChainSubstrateCompatible, _isCustomProvider } from '@subwallet/extension-base/services/chain-service/utils'; import { isUrl } from '@subwallet/extension-base/utils'; import { Layout, PageWrapper } from '@subwallet/extension-web-ui/components'; import InfoIcon from '@subwallet/extension-web-ui/components/Icon/InfoIcon'; diff --git a/packages/extension-web-ui/src/Popup/Settings/Chains/ChainDetail.tsx b/packages/extension-web-ui/src/Popup/Settings/Chains/ChainDetail.tsx index 1973b4444f..e145868ff4 100644 --- a/packages/extension-web-ui/src/Popup/Settings/Chains/ChainDetail.tsx +++ b/packages/extension-web-ui/src/Popup/Settings/Chains/ChainDetail.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { _NetworkUpsertParams } from '@subwallet/extension-base/services/chain-service/types'; -import { _getBlockExplorerFromChain, _getChainNativeTokenBasicInfo, _getChainSubstrateAddressPrefix, _getCrowdloanUrlFromChain, _getEvmChainId, _getSubstrateParaId, _isChainEvmCompatible, _isCustomChain, _isPureEvmChain, _isChainSubstrateCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { _getBlockExplorerFromChain, _getChainNativeTokenBasicInfo, _getChainSubstrateAddressPrefix, _getCrowdloanUrlFromChain, _getEvmChainId, _getSubstrateParaId, _isChainEvmCompatible, _isChainSubstrateCompatible, _isCustomChain, _isPureEvmChain } from '@subwallet/extension-base/services/chain-service/utils'; import { isUrl } from '@subwallet/extension-base/utils'; import { Layout, PageWrapper } from '@subwallet/extension-web-ui/components'; import { ProviderSelector } from '@subwallet/extension-web-ui/components/Field/ProviderSelector'; diff --git a/packages/extension-web-ui/src/Popup/Settings/Chains/ManageChains.tsx b/packages/extension-web-ui/src/Popup/Settings/Chains/ManageChains.tsx index e2b0decf8a..041e275379 100644 --- a/packages/extension-web-ui/src/Popup/Settings/Chains/ManageChains.tsx +++ b/packages/extension-web-ui/src/Popup/Settings/Chains/ManageChains.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { _isChainEvmCompatible, _isCustomChain, _isChainSubstrateCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { _isChainEvmCompatible, _isChainSubstrateCompatible, _isCustomChain } from '@subwallet/extension-base/services/chain-service/utils'; import { FilterModal, Layout, NetworkEmptyList, NetworkToggleItem, OptionType, PageWrapper } from '@subwallet/extension-web-ui/components'; import { DataContext } from '@subwallet/extension-web-ui/contexts/DataContext'; import { ScreenContext } from '@subwallet/extension-web-ui/contexts/ScreenContext'; From eb57c7b40a368c59a65b13c4a19f662390fd0161 Mon Sep 17 00:00:00 2001 From: lw Date: Wed, 7 Aug 2024 17:59:44 +0700 Subject: [PATCH 058/424] [MasterAccount] Init receive modal structure --- .../src/Popup/Home/Tokens/index.tsx | 32 +----- .../AccountProxy/AccountAddressItem.tsx | 89 +++++++++++++++ .../src/components/AccountProxy/index.ts | 1 + .../components/Modal/AccountSelectorModal.tsx | 1 + .../Modal/ReceiveModalNew/index.tsx | 34 ++++++ .../ReceiveModalNew/parts/AccountSelector.tsx | 107 ++++++++++++++++++ .../ReceiveModalNew/parts/TokenSelector.tsx | 97 ++++++++++++++++ .../src/components/Modal/index.tsx | 1 + .../TokenItem/TokenSelectionItem.tsx | 1 + .../TokenItem/TokenSelectorItem.tsx | 47 ++++++++ .../src/components/TokenItem/index.tsx | 1 + .../extension-koni-ui/src/constants/modal.ts | 2 + .../src/hooks/assets/useChainAssets.ts | 1 + .../src/hooks/screen/home/index.ts | 1 + .../screen/home/useReceiveModalHelper.ts | 85 ++++++++++++++ .../extension-koni-ui/src/types/account.ts | 6 + .../extension-koni-ui/src/types/component.ts | 16 +++ packages/extension-koni-ui/src/types/index.ts | 1 + 18 files changed, 496 insertions(+), 27 deletions(-) create mode 100644 packages/extension-koni-ui/src/components/AccountProxy/AccountAddressItem.tsx create mode 100644 packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/index.tsx create mode 100644 packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/AccountSelector.tsx create mode 100644 packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/TokenSelector.tsx create mode 100644 packages/extension-koni-ui/src/components/TokenItem/TokenSelectorItem.tsx create mode 100644 packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.ts create mode 100644 packages/extension-koni-ui/src/types/component.ts diff --git a/packages/extension-koni-ui/src/Popup/Home/Tokens/index.tsx b/packages/extension-koni-ui/src/Popup/Home/Tokens/index.tsx index 999dada6b5..69a7e265c7 100644 --- a/packages/extension-koni-ui/src/Popup/Home/Tokens/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Home/Tokens/index.tsx @@ -1,18 +1,14 @@ // Copyright 2019-2022 @polkadot/extension-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { EmptyList, PageWrapper } from '@subwallet/extension-koni-ui/components'; -import { AccountSelectorModal } from '@subwallet/extension-koni-ui/components/Modal/AccountSelectorModal'; -import ReceiveQrModal from '@subwallet/extension-koni-ui/components/Modal/ReceiveModal/ReceiveQrModal'; -import { TokensSelectorModal } from '@subwallet/extension-koni-ui/components/Modal/ReceiveModal/TokensSelectorModal'; +import { EmptyList, PageWrapper, ReceiveModal } from '@subwallet/extension-koni-ui/components'; import { TokenGroupBalanceItem } from '@subwallet/extension-koni-ui/components/TokenItem/TokenGroupBalanceItem'; import { DEFAULT_SWAP_PARAMS, DEFAULT_TRANSFER_PARAMS, SWAP_TRANSACTION, TRANSFER_TRANSACTION } from '@subwallet/extension-koni-ui/constants'; import { DataContext } from '@subwallet/extension-koni-ui/contexts/DataContext'; import { HomeContext } from '@subwallet/extension-koni-ui/contexts/screen/HomeContext'; -import { useSetCurrentPage } from '@subwallet/extension-koni-ui/hooks'; +import { useReceiveModalHelper, useSetCurrentPage } from '@subwallet/extension-koni-ui/hooks'; import useNotification from '@subwallet/extension-koni-ui/hooks/common/useNotification'; import useTranslation from '@subwallet/extension-koni-ui/hooks/common/useTranslation'; -import useReceiveQR from '@subwallet/extension-koni-ui/hooks/screen/home/useReceiveQR'; import { UpperBlock } from '@subwallet/extension-koni-ui/Popup/Home/Tokens/UpperBlock'; import { RootState } from '@subwallet/extension-koni-ui/stores'; import { ThemeProps, TransferParams } from '@subwallet/extension-koni-ui/types'; @@ -41,13 +37,7 @@ const Component = (): React.ReactElement => { totalBalanceInfo }, tokenGroupStructure: { sortedTokenGroups } } = useContext(HomeContext); const currentAccount = useSelector((state: RootState) => state.accountState.currentAccount); const notify = useNotification(); - const { accountSelectorItems, - onOpenReceive, - openSelectAccount, - openSelectToken, - selectedAccount, - selectedNetwork, - tokenSelectorItems } = useReceiveQR(); + const { onOpenReceive, receiveModalProps } = useReceiveModalHelper(); const isZkModeSyncing = useSelector((state: RootState) => state.mantaPay.isSyncing); const zkModeSyncProgress = useSelector((state: RootState) => state.mantaPay.progress); @@ -294,20 +284,8 @@ const Component = (): React.ReactElement => { - - - - - ); diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountAddressItem.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountAddressItem.tsx new file mode 100644 index 0000000000..1e518f8519 --- /dev/null +++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountAddressItem.tsx @@ -0,0 +1,89 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { AccountAddressItemType, ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { toShort } from '@subwallet/extension-koni-ui/utils'; +import CN from 'classnames'; +import React from 'react'; +import styled from 'styled-components'; + +type Props = ThemeProps & { + item: AccountAddressItemType; + onClick?: VoidFunction; +} + +function Component (props: Props): React.ReactElement { + const { className, + item, + onClick } = props; + + return ( + <> +
+
+ +
+ +
+
+ {item.accountName} +
+
+ ({toShort(item.address, 4, 5)}) +
+
+
+ + ); +} + +const AccountAddressItem = styled(Component)(({ theme: { token } }: Props) => { + return { + background: token.colorBgSecondary, + paddingLeft: token.paddingSM, + paddingRight: token.paddingXXS, + paddingTop: 6, + paddingBottom: 6, + borderRadius: token.borderRadiusLG, + alignItems: 'center', + display: 'flex', + flexDirection: 'row', + cursor: 'pointer', + transition: `background ${token.motionDurationMid} ease-in-out`, + gap: token.sizeXXS, + overflowX: 'hidden', + minHeight: 52, + + '.__item-center-part': { + display: 'flex', + overflowX: 'hidden', + 'white-space': 'nowrap', + gap: token.sizeXXS, + flex: 1, + alignItems: 'center' + }, + + '.__item-account-name': { + fontSize: token.fontSize, + lineHeight: token.lineHeight, + color: token.colorTextLight1, + overflow: 'hidden', + textOverflow: 'ellipsis' + }, + + '.__item-address': { + fontSize: token.fontSizeSM, + lineHeight: token.lineHeightSM, + color: token.colorTextLight4 + }, + + '&:hover': { + background: token.colorBgInput + } + }; +}); + +export default AccountAddressItem; diff --git a/packages/extension-koni-ui/src/components/AccountProxy/index.ts b/packages/extension-koni-ui/src/components/AccountProxy/index.ts index 87d42a649b..c42f8d6c01 100644 --- a/packages/extension-koni-ui/src/components/AccountProxy/index.ts +++ b/packages/extension-koni-ui/src/components/AccountProxy/index.ts @@ -8,3 +8,4 @@ export { default as AccountProxyItem } from './AccountProxyItem'; export { default as AccountProxyAvatar } from './AccountProxyAvatar'; export { default as AccountProxyAvatarGroup } from './AccountProxyAvatarGroup'; export { default as AccountNetworkAddressItem } from './AccountNetworkAddressItem'; +export { default as AccountAddressItem } from './AccountAddressItem'; diff --git a/packages/extension-koni-ui/src/components/Modal/AccountSelectorModal.tsx b/packages/extension-koni-ui/src/components/Modal/AccountSelectorModal.tsx index 3c8ed0930a..32e4e0d124 100644 --- a/packages/extension-koni-ui/src/components/Modal/AccountSelectorModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/AccountSelectorModal.tsx @@ -22,6 +22,7 @@ export const AccountSelectorModalId = 'accountSelectorModalId'; const renderEmpty = () => ; +// todo: deprecated, will remove function Component ({ className = '', id = AccountSelectorModalId, items, onSelectItem }: Props): React.ReactElement { const { t } = useTranslation(); const { checkActive, inactiveModal } = useContext(ModalContext); diff --git a/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/index.tsx b/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/index.tsx new file mode 100644 index 0000000000..1d1afc69c8 --- /dev/null +++ b/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/index.tsx @@ -0,0 +1,34 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { ReceiveModalProps } from '@subwallet/extension-koni-ui/types'; +import React from 'react'; + +import { AccountSelectorModal } from './parts/AccountSelector'; +import { TokenSelectorModal } from './parts/TokenSelector'; + +const ReceiveModal = ({ accountSelectorItems, + onBackAccountSelector, + onCloseAccountSelector, + onCloseTokenSelector, + onSelectAccountSelector, + onSelectTokenSelector, + tokenSelectorItems }: ReceiveModalProps): React.ReactElement => { + return ( + <> + + + + ); +}; + +export default ReceiveModal; diff --git a/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/AccountSelector.tsx b/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/AccountSelector.tsx new file mode 100644 index 0000000000..fab7a85291 --- /dev/null +++ b/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/AccountSelector.tsx @@ -0,0 +1,107 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { AccountAddressItem, CloseIcon } from '@subwallet/extension-koni-ui/components'; +import GeneralEmptyList from '@subwallet/extension-koni-ui/components/EmptyList/GeneralEmptyList'; +import { RECEIVE_MODAL_ACCOUNT_SELECTOR } from '@subwallet/extension-koni-ui/constants'; +import { useTranslation } from '@subwallet/extension-koni-ui/hooks'; +import { AccountAddressItemType, ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { Icon, ModalContext, SwList, SwModal } from '@subwallet/react-ui'; +import { SwListSectionRef } from '@subwallet/react-ui/es/sw-list'; +import CN from 'classnames'; +import { CaretLeft } from 'phosphor-react'; +import React, { useCallback, useContext, useEffect, useRef } from 'react'; +import styled from 'styled-components'; + +interface Props extends ThemeProps { + onSelectItem?: (item: AccountAddressItemType) => void, + items: AccountAddressItemType[]; + onCancel?: VoidFunction; + onBack?: VoidFunction; +} + +const modalId = RECEIVE_MODAL_ACCOUNT_SELECTOR; + +const renderEmpty = () => ; + +function Component ({ className = '', items, onBack, onCancel, onSelectItem }: Props): React.ReactElement { + const { t } = useTranslation(); + const { checkActive } = useContext(ModalContext); + + const isActive = checkActive(modalId); + + const sectionRef = useRef(null); + + const searchFunction = useCallback((item: AccountAddressItemType, searchText: string) => { + const lowerCaseSearchText = searchText.toLowerCase(); + + return item.accountName.toLowerCase().includes(lowerCaseSearchText) || + item.address.toLowerCase().includes(lowerCaseSearchText); + }, []); + + const onSelect = useCallback((item: AccountAddressItemType) => { + return () => { + onSelectItem?.(item); + }; + }, [onSelectItem]); + + const renderItem = useCallback((item: AccountAddressItemType) => { + return ( + + ); + }, [onSelect]); + + useEffect(() => { + if (!isActive) { + setTimeout(() => { + sectionRef.current?.setSearchValue(''); + }, 100); + } + }, [isActive]); + + return ( + + ) + : undefined + } + destroyOnClose={true} + id={modalId} + onCancel={onBack || onCancel} + rightIconProps={onBack + ? { + icon: , + onClick: onCancel + } + : undefined} + title={t('Select account')} + > + ('Enter your account name or address')} + /> + + ); +} + +export const AccountSelectorModal = styled(Component)(({ theme: { token } }: Props) => { + return ({ + + }); +}); diff --git a/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/TokenSelector.tsx b/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/TokenSelector.tsx new file mode 100644 index 0000000000..ddc5393cc6 --- /dev/null +++ b/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/TokenSelector.tsx @@ -0,0 +1,97 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { _ChainAsset } from '@subwallet/chain-list/types'; +import { TokenSelectorItem } from '@subwallet/extension-koni-ui/components'; +import TokenEmptyList from '@subwallet/extension-koni-ui/components/EmptyList/TokenEmptyList'; +import { RECEIVE_MODAL_TOKEN_SELECTOR } from '@subwallet/extension-koni-ui/constants'; +import { useSelector, useTranslation } from '@subwallet/extension-koni-ui/hooks'; +import { ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { ModalContext, SwList, SwModal } from '@subwallet/react-ui'; +import { SwListSectionRef } from '@subwallet/react-ui/es/sw-list'; +import React, { useCallback, useContext, useEffect, useRef } from 'react'; +import styled from 'styled-components'; + +interface Props extends ThemeProps { + onSelectItem?: (item: _ChainAsset) => void, + items: _ChainAsset[]; + onCancel?: VoidFunction; +} + +const modalId = RECEIVE_MODAL_TOKEN_SELECTOR; + +const renderEmpty = () => ; + +function Component ({ className = '', items, onCancel, onSelectItem }: Props): React.ReactElement { + const { t } = useTranslation(); + const { checkActive } = useContext(ModalContext); + + // @ts-ignore + const chainInfoMap = useSelector((state) => state.chainStore.chainInfoMap); + + const isActive = checkActive(modalId); + + const sectionRef = useRef(null); + + const searchFunction = useCallback((item: _ChainAsset, searchText: string) => { + return item.symbol.toLowerCase().includes(searchText.toLowerCase()); + }, []); + + const onSelect = useCallback((item: _ChainAsset) => { + return () => { + onSelectItem?.(item); + }; + }, [onSelectItem]); + + const renderItem = useCallback((item: _ChainAsset) => { + return ( + + ); + }, [onSelect]); + + useEffect(() => { + if (!isActive) { + setTimeout(() => { + sectionRef.current?.setSearchValue(''); + }, 100); + } + }, [isActive]); + + return ( + + ('Token name')} + /> + + ); +} + +export const TokenSelectorModal = styled(Component)(({ theme: { token } }: Props) => { + return ({ + '.ant-sw-modal-body': { + paddingLeft: 0, + paddingRight: 0 + }, + + '.token-selector-item + .token-selector-item': { + marginTop: token.marginXS + } + }); +}); diff --git a/packages/extension-koni-ui/src/components/Modal/index.tsx b/packages/extension-koni-ui/src/components/Modal/index.tsx index f2ae88dfe3..908003638e 100644 --- a/packages/extension-koni-ui/src/components/Modal/index.tsx +++ b/packages/extension-koni-ui/src/components/Modal/index.tsx @@ -9,6 +9,7 @@ export { default as RemindBackupSeedPhraseModal } from './RemindBackupSeedPhrase export { default as RemindUpgradeVersionModal } from './RemindUpgradeFirefoxVersion'; export { default as AddNetworkWCModal } from './AddNetworkWCModal'; export { SortingModal } from './SortingModal'; +export { default as ReceiveModal } from './ReceiveModalNew'; export * from './Global'; export * from './Account'; diff --git a/packages/extension-koni-ui/src/components/TokenItem/TokenSelectionItem.tsx b/packages/extension-koni-ui/src/components/TokenItem/TokenSelectionItem.tsx index c925ff4210..68581f2fdd 100644 --- a/packages/extension-koni-ui/src/components/TokenItem/TokenSelectionItem.tsx +++ b/packages/extension-koni-ui/src/components/TokenItem/TokenSelectionItem.tsx @@ -22,6 +22,7 @@ interface Props extends ThemeProps, Omit void; } +// todo: deprecated, will remove const Component = (props: Props) => { const { address, className, item, onClickCopyBtn, onClickQrBtn, onPressItem, ...restProps } = props; const { name, originChain: chain, slug, symbol } = item; diff --git a/packages/extension-koni-ui/src/components/TokenItem/TokenSelectorItem.tsx b/packages/extension-koni-ui/src/components/TokenItem/TokenSelectorItem.tsx new file mode 100644 index 0000000000..294062e8a0 --- /dev/null +++ b/packages/extension-koni-ui/src/components/TokenItem/TokenSelectorItem.tsx @@ -0,0 +1,47 @@ +// Copyright 2019-2022 @polkadot/extension-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { ThemeProps } from '@subwallet/extension-koni-ui/types'; +import CN from 'classnames'; +import React from 'react'; +import styled from 'styled-components'; + +interface Props extends ThemeProps { + onClick?: VoidFunction; + tokenSlug?: string; + tokenSymbol: string; + networkSlug?: string; + networkName?: string; +} + +const Component = ({ className, onClick, tokenSymbol }: Props) => { + return ( +
+
+
+
+ {tokenSymbol} +
+
+ +
+
+
+
+ ); +}; + +const TokenSelectorItem = styled(Component)(({ theme: { token } }: Props) => { + return ({ + display: 'flex', + backgroundColor: token.colorBgSecondary, + borderRadius: token.borderRadiusLG, + padding: token.paddingSM, + cursor: 'pointer' + }); +}); + +export default TokenSelectorItem; diff --git a/packages/extension-koni-ui/src/components/TokenItem/index.tsx b/packages/extension-koni-ui/src/components/TokenItem/index.tsx index e877bc6a23..77c9faca12 100644 --- a/packages/extension-koni-ui/src/components/TokenItem/index.tsx +++ b/packages/extension-koni-ui/src/components/TokenItem/index.tsx @@ -3,6 +3,7 @@ export { default as AccountTokenBalanceItem } from './AccountTokenBalanceItem'; export { default as TokenToggleItem } from './TokenToggleItem'; +export { default as TokenSelectorItem } from './TokenSelectorItem'; export * from './TokenBalanceDetailItem'; export * from './TokenBalanceSelectionItem'; diff --git a/packages/extension-koni-ui/src/constants/modal.ts b/packages/extension-koni-ui/src/constants/modal.ts index 76a94da8a4..6ea85808b9 100644 --- a/packages/extension-koni-ui/src/constants/modal.ts +++ b/packages/extension-koni-ui/src/constants/modal.ts @@ -18,6 +18,8 @@ export const REQUEST_CAMERA_ACCESS_MODAL = 'request-camera-access-modal'; export const VALIDATOR_DETAIL_MODAL = 'validator-detail-modal'; export const HISTORY_DETAIL_MODAL = 'history-detail-modal'; export const RECEIVE_TOKEN_SELECTOR_MODAL = 'receive-tokens-selector-modal'; +export const RECEIVE_MODAL_TOKEN_SELECTOR = 'receive-modal-token-selector'; +export const RECEIVE_MODAL_ACCOUNT_SELECTOR = 'receive-modal-account-selector'; export const ADD_ADDRESS_BOOK_MODAL = 'add-address-book-modal'; export const EDIT_ADDRESS_BOOK_MODAL = 'edit-address-book-modal'; export const DELETE_ADDRESS_BOOK_MODAL = 'delete-address-book-modal'; diff --git a/packages/extension-koni-ui/src/hooks/assets/useChainAssets.ts b/packages/extension-koni-ui/src/hooks/assets/useChainAssets.ts index a59503e14d..b90846400e 100644 --- a/packages/extension-koni-ui/src/hooks/assets/useChainAssets.ts +++ b/packages/extension-koni-ui/src/hooks/assets/useChainAssets.ts @@ -15,6 +15,7 @@ interface _ChainAssetFilters { chainTypes?: 'substrate' | 'evm' } +// todo: recheck this hook, refactor if need export default function useChainAssets ({ chainTypes, isActive = false, isActiveChain = false, isAvailableChain = true, isFungible = true }: _ChainAssetFilters = {}) { const { chainInfoMap, chainStateMap } = useSelector((state: RootState) => state.chainStore); const { assetRegistry, assetSettingMap } = useSelector((state: RootState) => state.assetRegistry); diff --git a/packages/extension-koni-ui/src/hooks/screen/home/index.ts b/packages/extension-koni-ui/src/hooks/screen/home/index.ts index 0d1ae6936b..288a388275 100644 --- a/packages/extension-koni-ui/src/hooks/screen/home/index.ts +++ b/packages/extension-koni-ui/src/hooks/screen/home/index.ts @@ -4,6 +4,7 @@ export { default as useAccountBalance } from './useAccountBalance'; export { default as useGetTokensBySettings } from './useGetTokensBySettings'; export { default as useReceiveQR } from './useReceiveQR'; +export { default as useReceiveModalHelper } from './useReceiveModalHelper'; export { default as useTokenGroup } from './useTokenGroup'; export * from './useGetChainSlugsByAccountType'; diff --git a/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.ts b/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.ts new file mode 100644 index 0000000000..b2586fc5f2 --- /dev/null +++ b/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.ts @@ -0,0 +1,85 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { _ChainAsset } from '@subwallet/chain-list/types'; +import { _getMultiChainAsset } from '@subwallet/extension-base/services/chain-service/utils'; +import { RECEIVE_MODAL_ACCOUNT_SELECTOR, RECEIVE_MODAL_TOKEN_SELECTOR } from '@subwallet/extension-koni-ui/constants'; +import { useChainAssets } from '@subwallet/extension-koni-ui/hooks/assets'; +import { AccountAddressItemType, ReceiveModalProps } from '@subwallet/extension-koni-ui/types'; +import { ModalContext } from '@subwallet/react-ui'; +import { useCallback, useContext, useMemo } from 'react'; + +type HookType = { + onOpenReceive: VoidFunction; + receiveModalProps: ReceiveModalProps; +}; + +const tokenSelectorModalId = RECEIVE_MODAL_TOKEN_SELECTOR; +const accountSelectorModalId = RECEIVE_MODAL_ACCOUNT_SELECTOR; + +export default function useReceiveModalHelper (tokenGroupSlug?: string): HookType { + const { activeModal, inactiveModal } = useContext(ModalContext); + const chainAssets = useChainAssets().chainAssets; + + const onOpenReceive = useCallback(() => { + activeModal(tokenSelectorModalId); + }, [activeModal]); + + /* --- token Selector */ + + const tokenSelectorItems = useMemo<_ChainAsset[]>(() => { + if (tokenGroupSlug) { + return chainAssets.filter((asset) => _getMultiChainAsset(asset) === tokenGroupSlug); + } + + return chainAssets; + }, [chainAssets, tokenGroupSlug]); + + const onCloseTokenSelector = useCallback(() => { + inactiveModal(tokenSelectorModalId); + }, [inactiveModal]); + + const onSelectTokenSelector = useCallback((item: _ChainAsset) => { + // + }, []); + + /* token Selector --- */ + + /* --- account Selector */ + + const accountSelectorItems = useMemo(() => { + return []; + }, []); + + const onBackAccountSelector = useCallback(() => { + inactiveModal(accountSelectorModalId); + }, [inactiveModal]); + + const onCloseAccountSelector = useCallback(() => { + inactiveModal(accountSelectorModalId); + }, [inactiveModal]); + + const onSelectAccountSelector = useCallback((item: AccountAddressItemType) => { + // + }, []); + + /* account Selector --- */ + + return useMemo(() => ({ + onOpenReceive, + receiveModalProps: { + onSelectToken: () => { + // + }, + tokenSelectorItems, + onCloseTokenSelector, + onSelectTokenSelector, + accountSelectorItems, + onBackAccountSelector, + onCloseAccountSelector, + onSelectAccountSelector + } + }), [accountSelectorItems, onBackAccountSelector, onCloseAccountSelector, + onCloseTokenSelector, onOpenReceive, onSelectAccountSelector, + onSelectTokenSelector, tokenSelectorItems]); +} diff --git a/packages/extension-koni-ui/src/types/account.ts b/packages/extension-koni-ui/src/types/account.ts index 89ab8bd44c..ddc2c46490 100644 --- a/packages/extension-koni-ui/src/types/account.ts +++ b/packages/extension-koni-ui/src/types/account.ts @@ -35,3 +35,9 @@ export type AccountNetworkAddress = { slug: string; address: string; } + +export type AccountAddressItemType = { + accountName: string; + accountProxyId: string; + address: string; +} diff --git a/packages/extension-koni-ui/src/types/component.ts b/packages/extension-koni-ui/src/types/component.ts new file mode 100644 index 0000000000..42d6161894 --- /dev/null +++ b/packages/extension-koni-ui/src/types/component.ts @@ -0,0 +1,16 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { _ChainAsset } from '@subwallet/chain-list/types'; +import { AccountAddressItemType } from '@subwallet/extension-koni-ui/types/account'; + +export type ReceiveModalProps = { + onSelectToken: VoidFunction; + tokenSelectorItems: _ChainAsset[]; + onCloseTokenSelector: VoidFunction; + onSelectTokenSelector: (item: _ChainAsset) => void; + accountSelectorItems: AccountAddressItemType[]; + onCloseAccountSelector: VoidFunction; + onBackAccountSelector: VoidFunction; + onSelectAccountSelector: (item: AccountAddressItemType) => void; +} diff --git a/packages/extension-koni-ui/src/types/index.ts b/packages/extension-koni-ui/src/types/index.ts index 96b693a6b2..ced39b2f3e 100644 --- a/packages/extension-koni-ui/src/types/index.ts +++ b/packages/extension-koni-ui/src/types/index.ts @@ -137,3 +137,4 @@ export * from './scanner'; export * from './staking'; export * from './transaction'; export * from './walletConnect'; +export * from './component'; From 75a760b489eed1cf3743cb28ed00fbd1f539de04 Mon Sep 17 00:00:00 2001 From: S2kael Date: Wed, 7 Aug 2024 19:01:00 +0700 Subject: [PATCH 059/424] [Issue-3396] Adjust `AddressJson` interface --- packages/extension-base/src/types/account/info/keyring.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/extension-base/src/types/account/info/keyring.ts b/packages/extension-base/src/types/account/info/keyring.ts index 57dfa0436a..071a9820ad 100644 --- a/packages/extension-base/src/types/account/info/keyring.ts +++ b/packages/extension-base/src/types/account/info/keyring.ts @@ -145,6 +145,7 @@ export interface AccountJson extends AbstractAddressJson, AccountMetadataData, A isSubWallet?: boolean; /** Pending migrate password */ pendingMigrate?: boolean; + type: KeypairType; } export interface AddressJson extends AbstractAddressJson { From 7ab4d2c1e9406927437c4428e85175bd4346c8ed Mon Sep 17 00:00:00 2001 From: lw Date: Thu, 8 Aug 2024 14:22:06 +0700 Subject: [PATCH 060/424] [MasterAccount] Update flow logic for receive modal --- .../src/services/chain-service/utils/index.ts | 4 +- .../src/Popup/Account/NewSeedPhrase.tsx | 28 ++- .../variants/AuthorizeConfirmation.tsx | 2 + .../ConnectWalletConnectConfirmation.tsx | 3 + .../extension-koni-ui/src/Popup/Welcome.tsx | 10 +- .../Modal/Account/CreateAccountModal.tsx | 6 +- .../ReceiveModalNew/parts/AccountSelector.tsx | 1 + .../ReceiveModalNew/parts/TokenSelector.tsx | 4 +- .../TokenItem/TokenSelectorItem.tsx | 6 +- .../src/constants/account.ts | 3 + .../src/constants/localStorage.ts | 1 + .../src/hooks/account/index.ts | 1 + .../account/useGetAccountNetworkAddresses.tsx | 19 +- .../account/useSetSelectedAccountTypes.ts | 1 + .../account/useSetSelectedMnemonicType.ts | 19 ++ .../screen/home/useReceiveModalHelper.ts | 85 ------- .../screen/home/useReceiveModalHelper.tsx | 209 ++++++++++++++++++ .../extension-koni-ui/src/types/account.ts | 7 +- .../src/utils/chain/chain.ts | 19 +- 19 files changed, 294 insertions(+), 134 deletions(-) create mode 100644 packages/extension-koni-ui/src/hooks/account/useSetSelectedMnemonicType.ts delete mode 100644 packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.ts create mode 100644 packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx diff --git a/packages/extension-base/src/services/chain-service/utils/index.ts b/packages/extension-base/src/services/chain-service/utils/index.ts index b6ac908491..f1c2d57ad5 100644 --- a/packages/extension-base/src/services/chain-service/utils/index.ts +++ b/packages/extension-base/src/services/chain-service/utils/index.ts @@ -404,8 +404,8 @@ export function _getAssetOriginChain (assetInfo?: _ChainAsset) { return assetInfo?.originChain || ''; } -export function _getChainName (chainInfo: _ChainInfo) { - return chainInfo.name; +export function _getChainName (chainInfo?: _ChainInfo) { + return chainInfo?.name || ''; } export function _getAssetDecimals (assetInfo?: _ChainAsset): number { diff --git a/packages/extension-koni-ui/src/Popup/Account/NewSeedPhrase.tsx b/packages/extension-koni-ui/src/Popup/Account/NewSeedPhrase.tsx index 416586c6dc..7c0283209c 100644 --- a/packages/extension-koni-ui/src/Popup/Account/NewSeedPhrase.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/NewSeedPhrase.tsx @@ -4,7 +4,7 @@ import { AccountProxyType } from '@subwallet/extension-base/types'; import { AccountNameModal, CloseIcon, Layout, PageWrapper, WordPhrase } from '@subwallet/extension-koni-ui/components'; import { SeedPhraseTermModal } from '@subwallet/extension-koni-ui/components/Modal/TermsAndConditions/SeedPhraseTermModal'; -import { ACCOUNT_NAME_MODAL, CONFIRM_TERM_SEED_PHRASE, CREATE_ACCOUNT_MODAL, DEFAULT_ROUTER_PATH, SEED_PREVENT_MODAL, TERM_AND_CONDITION_SEED_PHRASE_MODAL } from '@subwallet/extension-koni-ui/constants'; +import { ACCOUNT_NAME_MODAL, CONFIRM_TERM_SEED_PHRASE, CREATE_ACCOUNT_MODAL, DEFAULT_MNEMONIC_TYPE, DEFAULT_ROUTER_PATH, SEED_PREVENT_MODAL, SELECTED_MNEMONIC_TYPE, TERM_AND_CONDITION_SEED_PHRASE_MODAL } from '@subwallet/extension-koni-ui/constants'; import { useAutoNavigateToCreatePassword, useCompleteCreateAccount, useDefaultNavigate, useIsPopup, useNotification, useTranslation, useUnlockChecker } from '@subwallet/extension-koni-ui/hooks'; import { createAccountSuriV2, createSeedV2, windowOpen } from '@subwallet/extension-koni-ui/messaging'; import { RootState } from '@subwallet/extension-koni-ui/stores'; @@ -45,6 +45,7 @@ const Component: React.FC = ({ className }: Props) => { const isOpenWindowRef = useRef(false); + const [selectedMnemonicType] = useLocalStorage(SELECTED_MNEMONIC_TYPE, DEFAULT_MNEMONIC_TYPE); const [preventModalStorage] = useLocalStorage(SEED_PREVENT_MODAL, false); const [preventModal] = useState(preventModalStorage); @@ -80,7 +81,7 @@ const Component: React.FC = ({ className }: Props) => { createAccountSuriV2({ name: accountName, suri: seedPhrase, - type: undefined, // todo: "undefined" means unified account. Will update the value if there are more types to support + type: selectedMnemonicType === 'ton' ? 'ton-special' : undefined, isAllowed: true }) .then(() => { @@ -96,7 +97,7 @@ const Component: React.FC = ({ className }: Props) => { setLoading(false); inactiveModal(ACCOUNT_NAME_MODAL); }); - }, [inactiveModal, notify, onComplete, seedPhrase]); + }, [inactiveModal, notify, onComplete, seedPhrase, selectedMnemonicType]); useEffect(() => { if (_isConfirmedTermSeedPhrase === 'nonConfirmed') { @@ -105,7 +106,7 @@ const Component: React.FC = ({ className }: Props) => { }, [_isConfirmedTermSeedPhrase, activeModal, inactiveModal]); useEffect(() => { - createSeedV2(undefined, undefined, 'general') + createSeedV2(undefined, undefined, selectedMnemonicType) .then((response): void => { const phrase = response.mnemonic; @@ -114,7 +115,7 @@ const Component: React.FC = ({ className }: Props) => { .catch((e: Error) => { console.error(e); }); - }, []); + }, [selectedMnemonicType]); useEffect(() => { if (isPopup && isFirefox() && hasMasterPassword && !isOpenWindowRef.current) { @@ -137,19 +138,22 @@ const Component: React.FC = ({ className }: Props) => { resolve={waitReady} > , - onClick: goHome - } - ]} + subHeaderIcons={preventModal + ? undefined + : [ + { + icon: , + onClick: goHome + } + ]} + subHeaderLeft={preventModal ? : undefined } title={t('Your seed phrase')} >
diff --git a/packages/extension-koni-ui/src/Popup/Confirmations/variants/AuthorizeConfirmation.tsx b/packages/extension-koni-ui/src/Popup/Confirmations/variants/AuthorizeConfirmation.tsx index 6f13b71451..a24c7cf01b 100644 --- a/packages/extension-koni-ui/src/Popup/Confirmations/variants/AuthorizeConfirmation.tsx +++ b/packages/extension-koni-ui/src/Popup/Confirmations/variants/AuthorizeConfirmation.tsx @@ -64,6 +64,8 @@ function Component ({ className, request }: Props) { const { accountAuthType, allowedAccounts } = request.request; const accounts = useSelector((state: RootState) => state.accountState.accounts); const navigate = useNavigate(); + + // todo: deprecated, recheck usage const setSelectedAccountTypes = useSetSelectedAccountTypes(true); // List all of all accounts by auth type diff --git a/packages/extension-koni-ui/src/Popup/Confirmations/variants/ConnectWalletConnectConfirmation.tsx b/packages/extension-koni-ui/src/Popup/Confirmations/variants/ConnectWalletConnectConfirmation.tsx index 892afe5246..19b622bfce 100644 --- a/packages/extension-koni-ui/src/Popup/Confirmations/variants/ConnectWalletConnectConfirmation.tsx +++ b/packages/extension-koni-ui/src/Popup/Confirmations/variants/ConnectWalletConnectConfirmation.tsx @@ -42,7 +42,10 @@ function Component ({ className, request }: Props) { const { t } = useTranslation(); const navigate = useNavigate(); const notification = useNotification(); + + // todo: deprecated, recheck usage const setSelectedAccountTypes = useSetSelectedAccountTypes(true); + const [blockAddNetwork, setBlockAddNetwork] = useState(false); const [networkNeedToImport, setNetworkNeedToImport] = useState([]); diff --git a/packages/extension-koni-ui/src/Popup/Welcome.tsx b/packages/extension-koni-ui/src/Popup/Welcome.tsx index 8805e69fe3..cfb0b45a18 100644 --- a/packages/extension-koni-ui/src/Popup/Welcome.tsx +++ b/packages/extension-koni-ui/src/Popup/Welcome.tsx @@ -3,8 +3,8 @@ import { Layout } from '@subwallet/extension-koni-ui/components'; import { GeneralTermModal } from '@subwallet/extension-koni-ui/components/Modal/TermsAndConditions/GeneralTermModal'; -import { ATTACH_ACCOUNT_MODAL, CONFIRM_GENERAL_TERM, CREATE_ACCOUNT_MODAL, DEFAULT_ACCOUNT_TYPES, GENERAL_TERM_AND_CONDITION_MODAL, IMPORT_ACCOUNT_MODAL, SELECT_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants'; -import { useSetSelectedAccountTypes, useTranslation } from '@subwallet/extension-koni-ui/hooks'; +import { ATTACH_ACCOUNT_MODAL, CONFIRM_GENERAL_TERM, CREATE_ACCOUNT_MODAL, DEFAULT_MNEMONIC_TYPE, GENERAL_TERM_AND_CONDITION_MODAL, IMPORT_ACCOUNT_MODAL, SELECT_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants'; +import { useSetSelectedMnemonicType, useTranslation } from '@subwallet/extension-koni-ui/hooks'; import { PhosphorIcon, ThemeProps } from '@subwallet/extension-koni-ui/types'; import { Button, ButtonProps, Icon, Image, ModalContext } from '@subwallet/react-ui'; import CN from 'classnames'; @@ -28,7 +28,7 @@ function Component ({ className }: Props): React.ReactElement { const { t } = useTranslation(); const { activeModal, inactiveModal } = useContext(ModalContext); const navigate = useNavigate(); - const setSelectedAccountTypes = useSetSelectedAccountTypes(false); + const setSelectedMnemonicType = useSetSelectedMnemonicType(false); const [modalIdAfterConfirm, setModalIdAfterConfirm] = useState(''); const [_isConfirmedTermGeneral, setIsConfirmedTermGeneral] = useLocalStorage(CONFIRM_GENERAL_TERM, 'nonConfirmed'); const items = useMemo((): WelcomeButtonItem[] => [ @@ -58,7 +58,7 @@ function Component ({ className }: Props): React.ReactElement { const openModal = useCallback((id: string) => { return () => { if (id === CREATE_ACCOUNT_MODAL) { - setSelectedAccountTypes(DEFAULT_ACCOUNT_TYPES); + setSelectedMnemonicType(DEFAULT_MNEMONIC_TYPE); navigate('/accounts/new-seed-phrase'); } else { inactiveModal(SELECT_ACCOUNT_MODAL); @@ -67,7 +67,7 @@ function Component ({ className }: Props): React.ReactElement { setIsConfirmedTermGeneral('confirmed'); }; - }, [activeModal, inactiveModal, navigate, setIsConfirmedTermGeneral, setSelectedAccountTypes]); + }, [setSelectedMnemonicType, activeModal, inactiveModal, navigate, setIsConfirmedTermGeneral]); const onClickToSelectTypeConnect = useCallback((idModal: string) => { return () => { diff --git a/packages/extension-koni-ui/src/components/Modal/Account/CreateAccountModal.tsx b/packages/extension-koni-ui/src/components/Modal/Account/CreateAccountModal.tsx index 7be6542c9e..258cb54d7d 100644 --- a/packages/extension-koni-ui/src/components/Modal/Account/CreateAccountModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/Account/CreateAccountModal.tsx @@ -7,7 +7,7 @@ import CloseIcon from '@subwallet/extension-koni-ui/components/Icon/CloseIcon'; import { SettingItemSelection } from '@subwallet/extension-koni-ui/components/Setting/SettingItemSelection'; import { EVM_ACCOUNT_TYPE } from '@subwallet/extension-koni-ui/constants/account'; import { CREATE_ACCOUNT_MODAL, DERIVE_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants/modal'; -import { useSetSessionLatest } from '@subwallet/extension-koni-ui/hooks'; +import { useSetSelectedMnemonicType, useSetSessionLatest } from '@subwallet/extension-koni-ui/hooks'; import useTranslation from '@subwallet/extension-koni-ui/hooks/common/useTranslation'; import useClickOutSide from '@subwallet/extension-koni-ui/hooks/dom/useClickOutSide'; import useGoBackSelectAccount from '@subwallet/extension-koni-ui/hooks/modal/useGoBackSelectAccount'; @@ -44,6 +44,7 @@ const Component: React.FC = ({ className }: Props) => { const { accounts } = useSelector((state: RootState) => state.accountState); const isActive = checkActive(modalId); const navigate = useNavigate(); + const setSelectedMnemonicType = useSetSelectedMnemonicType(false); const onBack = useGoBackSelectAccount(modalId); @@ -82,6 +83,7 @@ const Component: React.FC = ({ className }: Props) => { label: t('Create with a new seed phrase'), onClick: () => { inactiveModal(modalId); + setSelectedMnemonicType('general'); navigate('/accounts/new-seed-phrase'); } }, @@ -96,7 +98,7 @@ const Component: React.FC = ({ className }: Props) => { activeModal(DERIVE_ACCOUNT_MODAL); } } - ]), [token, t, disableDerive, inactiveModal, navigate, activeModal]); + ]), [token, t, disableDerive, inactiveModal, setSelectedMnemonicType, navigate, activeModal]); return ( ); diff --git a/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/TokenSelector.tsx b/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/TokenSelector.tsx index ddc5393cc6..3c64799ce1 100644 --- a/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/TokenSelector.tsx +++ b/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/TokenSelector.tsx @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { _ChainAsset } from '@subwallet/chain-list/types'; +import { _getChainName } from '@subwallet/extension-base/services/chain-service/utils'; import { TokenSelectorItem } from '@subwallet/extension-koni-ui/components'; import TokenEmptyList from '@subwallet/extension-koni-ui/components/EmptyList/TokenEmptyList'; import { RECEIVE_MODAL_TOKEN_SELECTOR } from '@subwallet/extension-koni-ui/constants'; @@ -48,11 +49,12 @@ function Component ({ className = '', items, onCancel, onSelectItem }: Props): R ); - }, [onSelect]); + }, [chainInfoMap, onSelect]); useEffect(() => { if (!isActive) { diff --git a/packages/extension-koni-ui/src/components/TokenItem/TokenSelectorItem.tsx b/packages/extension-koni-ui/src/components/TokenItem/TokenSelectorItem.tsx index 294062e8a0..730b6b0fce 100644 --- a/packages/extension-koni-ui/src/components/TokenItem/TokenSelectorItem.tsx +++ b/packages/extension-koni-ui/src/components/TokenItem/TokenSelectorItem.tsx @@ -10,11 +10,11 @@ interface Props extends ThemeProps { onClick?: VoidFunction; tokenSlug?: string; tokenSymbol: string; - networkSlug?: string; + chainSlug?: string; networkName?: string; } -const Component = ({ className, onClick, tokenSymbol }: Props) => { +const Component = ({ className, networkName, onClick, tokenSymbol }: Props) => { return (
{ {tokenSymbol}
- + {networkName}
diff --git a/packages/extension-koni-ui/src/constants/account.ts b/packages/extension-koni-ui/src/constants/account.ts index 42b6b013e5..d6b9f5f49e 100644 --- a/packages/extension-koni-ui/src/constants/account.ts +++ b/packages/extension-koni-ui/src/constants/account.ts @@ -1,9 +1,12 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 +import { MnemonicType } from '@subwallet/extension-base/types'; + import { KeypairType } from '@polkadot/util-crypto/types'; export const SUBSTRATE_ACCOUNT_TYPE: KeypairType = 'sr25519'; export const EVM_ACCOUNT_TYPE: KeypairType = 'ethereum'; export const DEFAULT_ACCOUNT_TYPES: KeypairType[] = [SUBSTRATE_ACCOUNT_TYPE, EVM_ACCOUNT_TYPE]; +export const DEFAULT_MNEMONIC_TYPE: MnemonicType = 'general'; diff --git a/packages/extension-koni-ui/src/constants/localStorage.ts b/packages/extension-koni-ui/src/constants/localStorage.ts index 7ca5fffe7f..b63fa02c96 100644 --- a/packages/extension-koni-ui/src/constants/localStorage.ts +++ b/packages/extension-koni-ui/src/constants/localStorage.ts @@ -22,6 +22,7 @@ export const CLAIM_REWARD_TRANSACTION = 'transaction.claim-reward'; export const TRANSACTION_STORAGES = [TRANSFER_TRANSACTION, NFT_TRANSACTION, EARN_TRANSACTION, UN_STAKE_TRANSACTION, CANCEL_UN_STAKE_TRANSACTION, WITHDRAW_TRANSACTION, CLAIM_REWARD_TRANSACTION, SWAP_TRANSACTION]; export const SELECTED_ACCOUNT_TYPE = 'account.selected-type'; +export const SELECTED_MNEMONIC_TYPE = 'account.selected-mnemonic-type'; export const SEED_PREVENT_MODAL = 'seed.prevent-modal'; export const CONFIRM_GENERAL_TERM = 'general.term-and-condition'; diff --git a/packages/extension-koni-ui/src/hooks/account/index.ts b/packages/extension-koni-ui/src/hooks/account/index.ts index 77b2353d47..ee5fe86c93 100644 --- a/packages/extension-koni-ui/src/hooks/account/index.ts +++ b/packages/extension-koni-ui/src/hooks/account/index.ts @@ -19,6 +19,7 @@ export { default as usePreCheckAction } from './usePreCheckAction'; export { default as useSetSelectedAccountTypes } from './useSetSelectedAccountTypes'; export { default as useGetAccountProxyById } from './useGetAccountProxyById'; export { default as useGetAccountNetworkAddresses } from './useGetAccountNetworkAddresses'; +export { default as useSetSelectedMnemonicType } from './useSetSelectedMnemonicType'; export * from './useGetMantaPayConfig'; export * from './useGetZkAddress'; diff --git a/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx b/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx index 8e6b8b1efc..19fac97c6e 100644 --- a/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx +++ b/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx @@ -1,30 +1,13 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { _ChainInfo } from '@subwallet/chain-list/types'; -import { _isChainEvmCompatible, _isChainTonCompatible, _isPureSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils'; import { AccountNetworkType, AccountProxy } from '@subwallet/extension-base/types'; import { reformatAddress } from '@subwallet/extension-base/utils'; import { useSelector } from '@subwallet/extension-koni-ui/hooks'; import { AccountNetworkAddress } from '@subwallet/extension-koni-ui/types'; +import { isChainInfoAccordantNetworkType } from '@subwallet/extension-koni-ui/utils'; import { useMemo } from 'react'; -function isChainInfoAccordantNetworkType (chainInfo: _ChainInfo, networkType: AccountNetworkType): boolean { - if (networkType === AccountNetworkType.SUBSTRATE) { - return _isPureSubstrateChain(chainInfo); - } - - if (networkType === AccountNetworkType.ETHEREUM) { - return _isChainEvmCompatible(chainInfo); - } - - if (networkType === AccountNetworkType.TON) { - return _isChainTonCompatible(chainInfo); - } - - return false; -} - // todo: // - order the result // - support bitcoin diff --git a/packages/extension-koni-ui/src/hooks/account/useSetSelectedAccountTypes.ts b/packages/extension-koni-ui/src/hooks/account/useSetSelectedAccountTypes.ts index c2a986c45f..53ef2b2b0c 100644 --- a/packages/extension-koni-ui/src/hooks/account/useSetSelectedAccountTypes.ts +++ b/packages/extension-koni-ui/src/hooks/account/useSetSelectedAccountTypes.ts @@ -7,6 +7,7 @@ import { useLocalStorage } from 'usehooks-ts'; import { KeypairType } from '@polkadot/util-crypto/types'; +// todo: deprecated, need recheck all usages const useSetSelectedAccountTypes = (preventModal: boolean) => { const [, setTypesStorage] = useLocalStorage(SELECTED_ACCOUNT_TYPE, DEFAULT_ACCOUNT_TYPES); const [, setPreventModalStorage] = useLocalStorage(SEED_PREVENT_MODAL, preventModal); diff --git a/packages/extension-koni-ui/src/hooks/account/useSetSelectedMnemonicType.ts b/packages/extension-koni-ui/src/hooks/account/useSetSelectedMnemonicType.ts new file mode 100644 index 0000000000..8a52447dbf --- /dev/null +++ b/packages/extension-koni-ui/src/hooks/account/useSetSelectedMnemonicType.ts @@ -0,0 +1,19 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { MnemonicType } from '@subwallet/extension-base/types'; +import { DEFAULT_MNEMONIC_TYPE, SEED_PREVENT_MODAL, SELECTED_MNEMONIC_TYPE } from '@subwallet/extension-koni-ui/constants'; +import { useCallback } from 'react'; +import { useLocalStorage } from 'usehooks-ts'; + +const useSetSelectedMnemonicType = (preventModal: boolean) => { + const [, setTypesStorage] = useLocalStorage(SELECTED_MNEMONIC_TYPE, DEFAULT_MNEMONIC_TYPE); + const [, setPreventModalStorage] = useLocalStorage(SEED_PREVENT_MODAL, preventModal); + + return useCallback((values: MnemonicType) => { + setTypesStorage(values); + setPreventModalStorage(preventModal); + }, [preventModal, setPreventModalStorage, setTypesStorage]); +}; + +export default useSetSelectedMnemonicType; diff --git a/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.ts b/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.ts deleted file mode 100644 index b2586fc5f2..0000000000 --- a/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.ts +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors -// SPDX-License-Identifier: Apache-2.0 - -import { _ChainAsset } from '@subwallet/chain-list/types'; -import { _getMultiChainAsset } from '@subwallet/extension-base/services/chain-service/utils'; -import { RECEIVE_MODAL_ACCOUNT_SELECTOR, RECEIVE_MODAL_TOKEN_SELECTOR } from '@subwallet/extension-koni-ui/constants'; -import { useChainAssets } from '@subwallet/extension-koni-ui/hooks/assets'; -import { AccountAddressItemType, ReceiveModalProps } from '@subwallet/extension-koni-ui/types'; -import { ModalContext } from '@subwallet/react-ui'; -import { useCallback, useContext, useMemo } from 'react'; - -type HookType = { - onOpenReceive: VoidFunction; - receiveModalProps: ReceiveModalProps; -}; - -const tokenSelectorModalId = RECEIVE_MODAL_TOKEN_SELECTOR; -const accountSelectorModalId = RECEIVE_MODAL_ACCOUNT_SELECTOR; - -export default function useReceiveModalHelper (tokenGroupSlug?: string): HookType { - const { activeModal, inactiveModal } = useContext(ModalContext); - const chainAssets = useChainAssets().chainAssets; - - const onOpenReceive = useCallback(() => { - activeModal(tokenSelectorModalId); - }, [activeModal]); - - /* --- token Selector */ - - const tokenSelectorItems = useMemo<_ChainAsset[]>(() => { - if (tokenGroupSlug) { - return chainAssets.filter((asset) => _getMultiChainAsset(asset) === tokenGroupSlug); - } - - return chainAssets; - }, [chainAssets, tokenGroupSlug]); - - const onCloseTokenSelector = useCallback(() => { - inactiveModal(tokenSelectorModalId); - }, [inactiveModal]); - - const onSelectTokenSelector = useCallback((item: _ChainAsset) => { - // - }, []); - - /* token Selector --- */ - - /* --- account Selector */ - - const accountSelectorItems = useMemo(() => { - return []; - }, []); - - const onBackAccountSelector = useCallback(() => { - inactiveModal(accountSelectorModalId); - }, [inactiveModal]); - - const onCloseAccountSelector = useCallback(() => { - inactiveModal(accountSelectorModalId); - }, [inactiveModal]); - - const onSelectAccountSelector = useCallback((item: AccountAddressItemType) => { - // - }, []); - - /* account Selector --- */ - - return useMemo(() => ({ - onOpenReceive, - receiveModalProps: { - onSelectToken: () => { - // - }, - tokenSelectorItems, - onCloseTokenSelector, - onSelectTokenSelector, - accountSelectorItems, - onBackAccountSelector, - onCloseAccountSelector, - onSelectAccountSelector - } - }), [accountSelectorItems, onBackAccountSelector, onCloseAccountSelector, - onCloseTokenSelector, onOpenReceive, onSelectAccountSelector, - onSelectTokenSelector, tokenSelectorItems]); -} diff --git a/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx b/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx new file mode 100644 index 0000000000..125dbe7c7f --- /dev/null +++ b/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx @@ -0,0 +1,209 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { _ChainAsset } from '@subwallet/chain-list/types'; +import { NotificationType } from '@subwallet/extension-base/background/KoniTypes'; +import { _getMultiChainAsset } from '@subwallet/extension-base/services/chain-service/utils'; +import { AccountNetworkType } from '@subwallet/extension-base/types'; +import { reformatAddress } from '@subwallet/extension-base/utils'; +import { RECEIVE_MODAL_ACCOUNT_SELECTOR, RECEIVE_MODAL_TOKEN_SELECTOR } from '@subwallet/extension-koni-ui/constants'; +import { WalletModalContext } from '@subwallet/extension-koni-ui/contexts/WalletModalContextProvider'; +import { useSetSelectedMnemonicType, useTranslation } from '@subwallet/extension-koni-ui/hooks'; +import { useChainAssets } from '@subwallet/extension-koni-ui/hooks/assets'; +import { RootState } from '@subwallet/extension-koni-ui/stores'; +import { AccountAddressItemType, ReceiveModalProps } from '@subwallet/extension-koni-ui/types'; +import { isChainInfoAccordantNetworkType } from '@subwallet/extension-koni-ui/utils'; +import { ModalContext } from '@subwallet/react-ui'; +import { CheckCircle, XCircle } from 'phosphor-react'; +import React, { useCallback, useContext, useMemo, useState } from 'react'; +import { useSelector } from 'react-redux'; +import { useNavigate } from 'react-router-dom'; + +type HookType = { + onOpenReceive: VoidFunction; + receiveModalProps: ReceiveModalProps; +}; + +const tokenSelectorModalId = RECEIVE_MODAL_TOKEN_SELECTOR; +const accountSelectorModalId = RECEIVE_MODAL_ACCOUNT_SELECTOR; + +export default function useReceiveModalHelper (tokenGroupSlug?: string): HookType { + const { activeModal, inactiveModal } = useContext(ModalContext); + const chainAssets = useChainAssets().chainAssets; + const { t } = useTranslation(); + const navigate = useNavigate(); + const setSelectedMnemonicType = useSetSelectedMnemonicType(false); + + const accountProxies = useSelector((state: RootState) => state.accountState.accountProxies); + const chainInfoMap = useSelector((state: RootState) => state.chainStore.chainInfoMap); + const [selectedNetwork, setSelectedNetwork] = useState(); + const { addressQrModal, alertModal } = useContext(WalletModalContext); + + const onOpenReceive = useCallback(() => { + activeModal(tokenSelectorModalId); + }, [activeModal]); + + /* --- token Selector */ + + const tokenSelectorItems = useMemo<_ChainAsset[]>(() => { + if (tokenGroupSlug) { + return chainAssets.filter((asset) => _getMultiChainAsset(asset) === tokenGroupSlug); + } + + return chainAssets; + }, [chainAssets, tokenGroupSlug]); + + const onCloseTokenSelector = useCallback(() => { + inactiveModal(tokenSelectorModalId); + }, [inactiveModal]); + + const onSelectTokenSelector = useCallback((item: _ChainAsset) => { + setSelectedNetwork(item.originChain); + setTimeout(() => { + activeModal(accountSelectorModalId); + }, 100); + }, [activeModal]); + + /* token Selector --- */ + + /* --- account Selector */ + + // todo: recheck logic with ledger account + const accountSelectorItems = useMemo(() => { + const chainInfo = selectedNetwork ? chainInfoMap[selectedNetwork] : undefined; + + if (!chainInfo) { + return []; + } + + const result: AccountAddressItemType[] = []; + + accountProxies.forEach((ap) => { + ap.accounts.forEach((a) => { + if (!isChainInfoAccordantNetworkType(chainInfo, a.networkType)) { + return; + } + + const item = { + accountName: ap.name, + accountProxyId: ap.id, + accountType: a.type + }; + + if (a.networkType === AccountNetworkType.SUBSTRATE && chainInfo.substrateInfo) { + result.push({ + ...item, + address: reformatAddress(a.address, chainInfo.substrateInfo.addressPrefix) + }); + } else if (a.networkType === AccountNetworkType.ETHEREUM && chainInfo.evmInfo) { + result.push({ + ...item, + address: a.address + }); + } else if (a.networkType === AccountNetworkType.TON && chainInfo.tonInfo) { + result.push({ + ...item, + address: reformatAddress(a.address, chainInfo.isTestnet ? 0 : 1) + }); + } + }); + }); + + return result; + }, [accountProxies, chainInfoMap, selectedNetwork]); + + const onBackAccountSelector = useCallback(() => { + inactiveModal(accountSelectorModalId); + }, [inactiveModal]); + + const onCloseAccountSelector = useCallback(() => { + inactiveModal(accountSelectorModalId); + inactiveModal(tokenSelectorModalId); + setSelectedNetwork(undefined); + }, [inactiveModal]); + + const onSelectAccountSelector = useCallback((item: AccountAddressItemType) => { + if (!selectedNetwork) { + return; + } + + const openAddressQrModal = () => { + addressQrModal.open({ + address: item.address, + chainSlug: selectedNetwork, + onBack: addressQrModal.close, + onCancel: () => { + addressQrModal.close(); + onCloseAccountSelector(); + } + }); + }; + + if (item.accountType === 'ton') { + alertModal.open({ + closable: false, + title: t('Seed phrase incompatibility'), + type: NotificationType.WARNING, + content: ( + <> +
+ {t('Importing this seed phrase will generate a unified account that can be used on multiple ecosystems including Polkadot, Ethereum, Bitcoin, and TON.')} +
+
+
+ {t('However, SubWallet is not compatible with TON-native wallets. This means that with the same seed phrase, SubWallet and TON-native wallets will generate two different TON addresses.')} +
+ + ), + cancelButton: { + text: t('Cancel'), + icon: XCircle, + iconWeight: 'fill', + onClick: () => { + alertModal.close(); + openAddressQrModal(); + }, + schema: 'secondary' + }, + okButton: { + text: t('Apply'), + icon: CheckCircle, + iconWeight: 'fill', + onClick: () => { + setSelectedMnemonicType('ton'); + navigate('/accounts/new-seed-phrase'); + + alertModal.close(); + }, + schema: 'primary' + } + }); + + return; + } + + openAddressQrModal(); + + // todo: if is unified account with TON, need show warning about create solo TON account + }, [addressQrModal, alertModal, navigate, onCloseAccountSelector, selectedNetwork, setSelectedMnemonicType, t]); + + /* account Selector --- */ + + return useMemo(() => ({ + onOpenReceive, + receiveModalProps: { + onSelectToken: () => { + // + }, + tokenSelectorItems, + onCloseTokenSelector, + onSelectTokenSelector, + accountSelectorItems, + onBackAccountSelector, + onCloseAccountSelector, + onSelectAccountSelector + } + }), [accountSelectorItems, onBackAccountSelector, onCloseAccountSelector, + onCloseTokenSelector, onOpenReceive, onSelectAccountSelector, + onSelectTokenSelector, tokenSelectorItems]); +} diff --git a/packages/extension-koni-ui/src/types/account.ts b/packages/extension-koni-ui/src/types/account.ts index ddc2c46490..d6b4d17d36 100644 --- a/packages/extension-koni-ui/src/types/account.ts +++ b/packages/extension-koni-ui/src/types/account.ts @@ -1,11 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { KeypairType } from '@polkadot/util-crypto/types'; - -export interface NewSeedPhraseState { - accountTypes: KeypairType[]; -} +import type { KeypairType } from '@subwallet/keyring/types'; export interface WordItem { index: number; @@ -39,5 +35,6 @@ export type AccountNetworkAddress = { export type AccountAddressItemType = { accountName: string; accountProxyId: string; + accountType: KeypairType; address: string; } diff --git a/packages/extension-koni-ui/src/utils/chain/chain.ts b/packages/extension-koni-ui/src/utils/chain/chain.ts index c5073604e8..881251fc5c 100644 --- a/packages/extension-koni-ui/src/utils/chain/chain.ts +++ b/packages/extension-koni-ui/src/utils/chain/chain.ts @@ -2,7 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 import { _ChainInfo } from '@subwallet/chain-list/types'; -import { _getSubstrateGenesisHash } from '@subwallet/extension-base/services/chain-service/utils'; +import { _getSubstrateGenesisHash, _isChainEvmCompatible, _isChainTonCompatible, _isPureSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils'; +import { AccountNetworkType } from '@subwallet/extension-base/types'; export const findChainInfoByGenesisHash = (chainMap: Record, genesisHash?: string): _ChainInfo | null => { if (!genesisHash) { @@ -31,3 +32,19 @@ export const findChainInfoByChainId = (chainMap: Record, cha return null; }; + +export const isChainInfoAccordantNetworkType = (chainInfo: _ChainInfo, networkType: AccountNetworkType): boolean => { + if (networkType === AccountNetworkType.SUBSTRATE) { + return _isPureSubstrateChain(chainInfo); + } + + if (networkType === AccountNetworkType.ETHEREUM) { + return _isChainEvmCompatible(chainInfo); + } + + if (networkType === AccountNetworkType.TON) { + return _isChainTonCompatible(chainInfo); + } + + return false; +}; From 836b4269309813b1e862330244c9edbca96e75d1 Mon Sep 17 00:00:00 2001 From: S2kael Date: Thu, 8 Aug 2024 15:08:24 +0700 Subject: [PATCH 061/424] [Issue-3396] Fix bug on `crypto` function caused by `window` object --- .../src/koni/background/handlers/Extension.ts | 2 +- .../src/services/keyring-service/account-context.ts | 9 ++++++--- packages/extension-koni/src/background.ts | 2 ++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index 92de6780f9..9a46b095a7 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -1171,7 +1171,7 @@ export default class KoniExtension { return true; } - private seedCreateV2 (request: RequestMnemonicCreateV2): ResponseMnemonicCreateV2 { + private seedCreateV2 (request: RequestMnemonicCreateV2): Promise { return this.#koniState.keyringService.context.mnemonicCreateV2(request); } diff --git a/packages/extension-base/src/services/keyring-service/account-context.ts b/packages/extension-base/src/services/keyring-service/account-context.ts index 338e5ec046..cf06ea9c4a 100644 --- a/packages/extension-base/src/services/keyring-service/account-context.ts +++ b/packages/extension-base/src/services/keyring-service/account-context.ts @@ -10,7 +10,7 @@ import { AccountMetadataData, AccountProxyData, AccountProxyMap, AccountProxySto import { RequestAccountProxyEdit, RequestAccountProxyForget } from '@subwallet/extension-base/types/account/action/edit'; import { addLazy, combineAccounts, derivePair, findNextDerivePair, isAddressValidWithAuthType, modifyAccountName } from '@subwallet/extension-base/utils'; import { InjectedAccountWithMeta } from '@subwallet/extension-inject/types'; -import { createPair, getDerivePath, getKeypairTypeByAddress } from '@subwallet/keyring'; +import { createPair, getDerivePath, getKeypairTypeByAddress, tonMnemonicGenerate } from '@subwallet/keyring'; import { BitcoinKeypairTypes, KeypairType, KeyringPair, KeyringPair$Json, KeyringPair$Meta, SubstrateKeypairTypes, TonKeypairTypes } from '@subwallet/keyring/types'; import { tonMnemonicValidate } from '@subwallet/keyring/utils'; import { keyring } from '@subwallet/ui-keyring'; @@ -413,10 +413,13 @@ export class AccountContext { /* Create with mnemonic */ /* Create seed */ - public mnemonicCreateV2 ({ length = SEED_DEFAULT_LENGTH, mnemonic: _seed, type = 'general' }: RequestMnemonicCreateV2): ResponseMnemonicCreateV2 { - const seed = _seed || mnemonicGenerate(length); + public async mnemonicCreateV2 ({ length = SEED_DEFAULT_LENGTH, mnemonic: _seed, type = 'general' }: RequestMnemonicCreateV2): Promise { // At this point, only 'general' type will be accepted const types: KeypairType[] = type === 'general' ? ['sr25519', 'ethereum', 'ton'] : ['ton-special']; + const seed = _seed || + type === 'general' + ? mnemonicGenerate(length) + : await tonMnemonicGenerate(length); const rs = { mnemonic: seed, addressMap: {} } as ResponseMnemonicCreateV2; types?.forEach((type) => { diff --git a/packages/extension-koni/src/background.ts b/packages/extension-koni/src/background.ts index 3fab71b52b..08169ae09d 100644 --- a/packages/extension-koni/src/background.ts +++ b/packages/extension-koni/src/background.ts @@ -17,6 +17,8 @@ const actionHandler = ActionHandler.instance; actionHandler.setHandler(SWHandler.instance); +globalThis.window = globalThis.self; + cryptoWaitReady() .then((): void => { const koniState = SWHandler.instance.state; From 267415861c589ff875025a158349ca3b976e413e Mon Sep 17 00:00:00 2001 From: lw Date: Thu, 8 Aug 2024 16:43:51 +0700 Subject: [PATCH 062/424] [MasterAccount] Update style for receive modal --- .../src/Popup/Home/Tokens/DetailList.tsx | 30 ++--------- .../AccountProxy/AccountAddressItem.tsx | 26 ++++++---- .../components/Modal/ReceiveModal/index.tsx | 2 + .../ReceiveModalNew/parts/AccountSelector.tsx | 22 ++++++++ .../ReceiveModalNew/parts/TokenSelector.tsx | 18 ++++++- .../src/components/Modal/index.tsx | 1 - .../TokenItem/TokenSelectorItem.tsx | 52 ++++++++++++++++--- .../src/hooks/screen/home/index.ts | 1 - .../screen/home/useReceiveModalHelper.tsx | 4 +- .../src/hooks/screen/home/useReceiveQR.ts | 1 + 10 files changed, 110 insertions(+), 47 deletions(-) diff --git a/packages/extension-koni-ui/src/Popup/Home/Tokens/DetailList.tsx b/packages/extension-koni-ui/src/Popup/Home/Tokens/DetailList.tsx index eb84633f7b..79ad4d1f30 100644 --- a/packages/extension-koni-ui/src/Popup/Home/Tokens/DetailList.tsx +++ b/packages/extension-koni-ui/src/Popup/Home/Tokens/DetailList.tsx @@ -2,16 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 import { _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { ReceiveModal } from '@subwallet/extension-koni-ui/components'; import PageWrapper from '@subwallet/extension-koni-ui/components/Layout/PageWrapper'; -import { AccountSelectorModal } from '@subwallet/extension-koni-ui/components/Modal/AccountSelectorModal'; -import ReceiveQrModal from '@subwallet/extension-koni-ui/components/Modal/ReceiveModal/ReceiveQrModal'; -import { TokensSelectorModal } from '@subwallet/extension-koni-ui/components/Modal/ReceiveModal/TokensSelectorModal'; import BannerGenerator from '@subwallet/extension-koni-ui/components/StaticContent/BannerGenerator'; import { TokenBalanceDetailItem } from '@subwallet/extension-koni-ui/components/TokenItem/TokenBalanceDetailItem'; import { DEFAULT_SWAP_PARAMS, DEFAULT_TRANSFER_PARAMS, SWAP_TRANSACTION, TRANSFER_TRANSACTION } from '@subwallet/extension-koni-ui/constants'; import { DataContext } from '@subwallet/extension-koni-ui/contexts/DataContext'; import { HomeContext } from '@subwallet/extension-koni-ui/contexts/screen/HomeContext'; -import { useDefaultNavigate, useGetBannerByScreen, useNavigateOnChangeAccount, useNotification, useReceiveQR, useSelector } from '@subwallet/extension-koni-ui/hooks'; +import { useDefaultNavigate, useGetBannerByScreen, useNavigateOnChangeAccount, useNotification, useReceiveModalHelper, useSelector } from '@subwallet/extension-koni-ui/hooks'; import { DetailModal } from '@subwallet/extension-koni-ui/Popup/Home/Tokens/DetailModal'; import { DetailUpperBlock } from '@subwallet/extension-koni-ui/Popup/Home/Tokens/DetailUpperBlock'; import { RootState } from '@subwallet/extension-koni-ui/stores'; @@ -123,13 +121,7 @@ function Component (): React.ReactElement { const containerRef = useRef(null); const topBlockRef = useRef(null); - const { accountSelectorItems, - onOpenReceive, - openSelectAccount, - openSelectToken, - selectedAccount, - selectedNetwork, - tokenSelectorItems } = useReceiveQR(tokenGroupSlug); + const { onOpenReceive, receiveModalProps } = useReceiveModalHelper(tokenGroupSlug); useNavigateOnChangeAccount('/home/tokens'); @@ -449,20 +441,8 @@ function Component (): React.ReactElement { tokenBalanceMap={tokenBalanceMap} /> - - - - - ); diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountAddressItem.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountAddressItem.tsx index 1e518f8519..ecfe369383 100644 --- a/packages/extension-koni-ui/src/components/AccountProxy/AccountAddressItem.tsx +++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountAddressItem.tsx @@ -7,6 +7,8 @@ import CN from 'classnames'; import React from 'react'; import styled from 'styled-components'; +import AccountProxyAvatar from './AccountProxyAvatar'; + type Props = ThemeProps & { item: AccountAddressItemType; onClick?: VoidFunction; @@ -24,7 +26,11 @@ function Component (props: Props): React.ReactElement { onClick={onClick} >
- +
@@ -44,7 +50,7 @@ const AccountAddressItem = styled(Component)(({ theme: { token } }: Props return { background: token.colorBgSecondary, paddingLeft: token.paddingSM, - paddingRight: token.paddingXXS, + paddingRight: token.paddingSM, paddingTop: 6, paddingBottom: 6, borderRadius: token.borderRadiusLG, @@ -53,30 +59,30 @@ const AccountAddressItem = styled(Component)(({ theme: { token } }: Props flexDirection: 'row', cursor: 'pointer', transition: `background ${token.motionDurationMid} ease-in-out`, - gap: token.sizeXXS, overflowX: 'hidden', minHeight: 52, + '.__account-avatar': { + marginRight: token.marginSM + }, + '.__item-center-part': { display: 'flex', overflowX: 'hidden', 'white-space': 'nowrap', gap: token.sizeXXS, flex: 1, - alignItems: 'center' + fontSize: token.fontSize, + lineHeight: token.lineHeight }, - '.__item-account-name': { - fontSize: token.fontSize, - lineHeight: token.lineHeight, + '.__account-name': { color: token.colorTextLight1, overflow: 'hidden', textOverflow: 'ellipsis' }, - '.__item-address': { - fontSize: token.fontSizeSM, - lineHeight: token.lineHeightSM, + '.__address': { color: token.colorTextLight4 }, diff --git a/packages/extension-koni-ui/src/components/Modal/ReceiveModal/index.tsx b/packages/extension-koni-ui/src/components/Modal/ReceiveModal/index.tsx index 7b95c6653c..e641b7e14e 100644 --- a/packages/extension-koni-ui/src/components/Modal/ReceiveModal/index.tsx +++ b/packages/extension-koni-ui/src/components/Modal/ReceiveModal/index.tsx @@ -1,6 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 +// todo: deprecated, will remove + export { default as ReceiveQrModal } from './ReceiveQrModal'; export { default as SimpleQrModal } from './SimpleQrModal'; diff --git a/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/AccountSelector.tsx b/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/AccountSelector.tsx index 9a601b00e7..93cc4eeb54 100644 --- a/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/AccountSelector.tsx +++ b/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/AccountSelector.tsx @@ -48,6 +48,7 @@ function Component ({ className = '', items, onBack, onCancel, onSelectItem }: P const renderItem = useCallback((item: AccountAddressItemType) => { return ( (({ theme: { token } }: Props) => { return ({ + '.ant-sw-modal-content': { + height: '100vh' + }, + '.ant-sw-modal-body': { + paddingLeft: 0, + paddingRight: 0, + display: 'flex', + flexDirection: 'column' + }, + + '.ant-sw-list-section': { + flex: 1 + }, + + '.ant-sw-list': { + paddingBottom: 0 + }, + + '.account-selector-item + .account-selector-item': { + marginTop: token.marginXS + } }); }); diff --git a/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/TokenSelector.tsx b/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/TokenSelector.tsx index 3c64799ce1..5ee08b9cc9 100644 --- a/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/TokenSelector.tsx +++ b/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/TokenSelector.tsx @@ -47,10 +47,12 @@ function Component ({ className = '', items, onCancel, onSelectItem }: Props): R const renderItem = useCallback((item: _ChainAsset) => { return ( ); @@ -87,9 +89,23 @@ function Component ({ className = '', items, onCancel, onSelectItem }: Props): R export const TokenSelectorModal = styled(Component)(({ theme: { token } }: Props) => { return ({ + '.ant-sw-modal-content': { + height: '100vh' + }, + '.ant-sw-modal-body': { paddingLeft: 0, - paddingRight: 0 + paddingRight: 0, + display: 'flex', + flexDirection: 'column' + }, + + '.ant-sw-list-section': { + flex: 1 + }, + + '.ant-sw-list': { + paddingBottom: 0 }, '.token-selector-item + .token-selector-item': { diff --git a/packages/extension-koni-ui/src/components/Modal/index.tsx b/packages/extension-koni-ui/src/components/Modal/index.tsx index 908003638e..b2eac602b7 100644 --- a/packages/extension-koni-ui/src/components/Modal/index.tsx +++ b/packages/extension-koni-ui/src/components/Modal/index.tsx @@ -19,6 +19,5 @@ export * from './Campaign'; export * from './Customize/CustomizeModal'; export * from './FilterModal'; export * from './GlobalSearchTokenModal'; -export * from './ReceiveModal'; export * from './Common'; export * from './Announcement'; diff --git a/packages/extension-koni-ui/src/components/TokenItem/TokenSelectorItem.tsx b/packages/extension-koni-ui/src/components/TokenItem/TokenSelectorItem.tsx index 730b6b0fce..9953f53b31 100644 --- a/packages/extension-koni-ui/src/components/TokenItem/TokenSelectorItem.tsx +++ b/packages/extension-koni-ui/src/components/TokenItem/TokenSelectorItem.tsx @@ -2,25 +2,35 @@ // SPDX-License-Identifier: Apache-2.0 import { ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { Logo } from '@subwallet/react-ui'; import CN from 'classnames'; import React from 'react'; import styled from 'styled-components'; interface Props extends ThemeProps { onClick?: VoidFunction; - tokenSlug?: string; + tokenSlug: string; tokenSymbol: string; - chainSlug?: string; - networkName?: string; + chainSlug: string; + networkName: string; } -const Component = ({ className, networkName, onClick, tokenSymbol }: Props) => { +const Component = ({ chainSlug, className, networkName, onClick, tokenSlug, tokenSymbol }: Props) => { return (
-
+
+ +
{tokenSymbol} @@ -29,7 +39,6 @@ const Component = ({ className, networkName, onClick, tokenSymbol }: Props) => { {networkName}
-
); }; @@ -40,7 +49,36 @@ const TokenSelectorItem = styled(Component)(({ theme: { token } }: Props) backgroundColor: token.colorBgSecondary, borderRadius: token.borderRadiusLG, padding: token.paddingSM, - cursor: 'pointer' + cursor: 'pointer', + gap: token.sizeXS, + transition: `background ${token.motionDurationMid} ease-in-out`, + + '.__item-center-part': { + overflow: 'hidden', + flex: 1 + }, + + '.__token-symbol': { + fontSize: token.fontSizeLG, + lineHeight: token.lineHeightLG, + color: token.colorTextLight1, + overflow: 'hidden', + 'white-space': 'nowrap', + textOverflow: 'ellipsis' + }, + + '.__network-name': { + fontSize: token.fontSizeSM, + lineHeight: token.lineHeightSM, + color: token.colorTextLight3, + overflow: 'hidden', + 'white-space': 'nowrap', + textOverflow: 'ellipsis' + }, + + '&:hover': { + background: token.colorBgInput + } }); }); diff --git a/packages/extension-koni-ui/src/hooks/screen/home/index.ts b/packages/extension-koni-ui/src/hooks/screen/home/index.ts index 288a388275..aa0924f50f 100644 --- a/packages/extension-koni-ui/src/hooks/screen/home/index.ts +++ b/packages/extension-koni-ui/src/hooks/screen/home/index.ts @@ -3,7 +3,6 @@ export { default as useAccountBalance } from './useAccountBalance'; export { default as useGetTokensBySettings } from './useGetTokensBySettings'; -export { default as useReceiveQR } from './useReceiveQR'; export { default as useReceiveModalHelper } from './useReceiveModalHelper'; export { default as useTokenGroup } from './useTokenGroup'; diff --git a/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx b/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx index 125dbe7c7f..2bb46e8ed6 100644 --- a/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx +++ b/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx @@ -32,7 +32,7 @@ export default function useReceiveModalHelper (tokenGroupSlug?: string): HookTyp const chainAssets = useChainAssets().chainAssets; const { t } = useTranslation(); const navigate = useNavigate(); - const setSelectedMnemonicType = useSetSelectedMnemonicType(false); + const setSelectedMnemonicType = useSetSelectedMnemonicType(true); const accountProxies = useSelector((state: RootState) => state.accountState.accountProxies); const chainInfoMap = useSelector((state: RootState) => state.chainStore.chainInfoMap); @@ -47,7 +47,7 @@ export default function useReceiveModalHelper (tokenGroupSlug?: string): HookTyp const tokenSelectorItems = useMemo<_ChainAsset[]>(() => { if (tokenGroupSlug) { - return chainAssets.filter((asset) => _getMultiChainAsset(asset) === tokenGroupSlug); + return chainAssets.filter((asset) => asset.slug === tokenGroupSlug || _getMultiChainAsset(asset) === tokenGroupSlug); } return chainAssets; diff --git a/packages/extension-koni-ui/src/hooks/screen/home/useReceiveQR.ts b/packages/extension-koni-ui/src/hooks/screen/home/useReceiveQR.ts index 44c3e48d0b..345caa1ecc 100644 --- a/packages/extension-koni-ui/src/hooks/screen/home/useReceiveQR.ts +++ b/packages/extension-koni-ui/src/hooks/screen/home/useReceiveQR.ts @@ -62,6 +62,7 @@ function isMantaPayEnabled (account: AccountJson | null, configs: MantaPayConfig return false; } +// todo: deprecated, will remove export default function useReceiveQR (tokenGroupSlug?: string) { const { activeModal, inactiveModal } = useContext(ModalContext); const { accounts, currentAccount, isAllAccount } = useSelector((state: RootState) => state.accountState); From 68cc7264d09ef59c602c3144b5d29a7a0c640693 Mon Sep 17 00:00:00 2001 From: S2kael Date: Thu, 8 Aug 2024 20:11:43 +0700 Subject: [PATCH 063/424] [Issue-3396] Add logic check exists account when create/import account --- .../keyring-service/account-context.ts | 72 ++++++++++++++++--- 1 file changed, 64 insertions(+), 8 deletions(-) diff --git a/packages/extension-base/src/services/keyring-service/account-context.ts b/packages/extension-base/src/services/keyring-service/account-context.ts index cf06ea9c4a..91215fe0ab 100644 --- a/packages/extension-base/src/services/keyring-service/account-context.ts +++ b/packages/extension-base/src/services/keyring-service/account-context.ts @@ -410,6 +410,24 @@ export class AccountContext { /* Get address for another service */ + /* Check address exists */ + private checkAddressExists (addresses: string[]): string { + let result = ''; + + for (const address of addresses) { + try { + const pair = keyring.getPair(address); + + if (pair) { + result = pair.address; + break; + } + } catch (e) {} + } + + return result; + } + /* Create with mnemonic */ /* Create seed */ @@ -464,6 +482,10 @@ export class AccountContext { rs.addressMap[type] = keyring.createFromUri(getSuri(mnemonic, type), {}, type).address; }); + const exists = this.checkAddressExists(Object.values(rs.addressMap)); + + assert(!exists, t('Have already created account with this seed: {{address}}', { replace: { address: exists } })); + return rs; } @@ -502,6 +524,10 @@ export class AccountContext { addressDict[type] = address; }); + const exists = this.checkAddressExists(Object.values(addressDict)); + + assert(!exists, t('Have already created account with this seed: {{address}}', { replace: { address: exists } })); + // Upsert account group first, to avoid combine latest have no account group data. if (proxyId) { this.upsertAccountProxy({ id: proxyId, name }); @@ -607,6 +633,10 @@ export class AccountContext { assert(false, t('Invalid private key. Please try again.')); } + const exists = this.checkAddressExists(Object.values(rs.addressMap)); + + assert(!exists, t('Have already created account with this private key: {{address}}', { replace: { address: exists } })); + return rs; } @@ -623,7 +653,10 @@ export class AccountContext { /* Ledger */ - /* For custom derive path */ + /** + * For custom derive path + * @todo: Add check exist address + * */ public async accountsCreateHardwareV2 (request: RequestAccountCreateHardwareV2): Promise { const { accountIndex, address, addressOffset, genesisHash, hardwareType, isAllowed, name } = request; const key = keyring.addHardware(address, hardwareType, { @@ -653,7 +686,10 @@ export class AccountContext { return true; } - /* For multi select */ + /** + * For multi select + * @todo: Add check exist address + * */ public async accountsCreateHardwareMultiple ({ accounts }: RequestAccountCreateHardwareMultiple): Promise { const addresses: string[] = []; @@ -755,6 +791,10 @@ export class AccountContext { encType ); + const exists = this.checkAddressExists([pair.address]); + + assert(!exists, t('Account already exists')); + // unlock then lock (locking cleans secretKey, so needs to be last) try { pair.decodePkcs8(password); @@ -804,6 +844,10 @@ export class AccountContext { public batchRestoreV2 ({ accountsInfo, file, isAllowed, password }: RequestBatchRestoreV2): void { const addressList: string[] = accountsInfo.map((acc) => acc.address); + const exists = this.checkAddressExists(addressList); + + assert(!exists, t('Account already exists account: {{address}}', { replace: { address: exists } })); + const isPasswordValidated = this.validatedAccountsPassword(file, password); if (isPasswordValidated) { @@ -841,15 +885,14 @@ export class AccountContext { if (isHex(phrase) && isHex(phrase, 256)) { const type: KeypairType = 'ethereum'; - keyringPair = keyring.addUri(getSuri(suri, type), { name: name }, type).pair; + keyringPair = keyring.createFromUri(getSuri(suri, type), { name: name }, type); } } } else { - keyringPair = keyring.keyring.addFromPair({ + keyringPair = keyring.keyring.createFromPair({ publicKey: hexToU8a(publicKey), secretKey: hexToU8a(secretKey) - }, { name }); - keyring.addPair(keyringPair, true); + }, { name }, keyring.keyring.type); } if (!keyringPair) { @@ -860,11 +903,16 @@ export class AccountContext { } const _address = keyringPair.address; + const exists = this.checkAddressExists([_address]); + + assert(!exists, t('Account already exists account: {{address}}', { replace: { address: exists } })); + const modifiedPairs = this.modifyPairsSubject.value; modifiedPairs[_address] = { migrated: true, key: _address }; this.upsertModifyPairs(modifiedPairs); + keyring.addPair(keyringPair, true); await new Promise((resolve) => { this._saveCurrentAccountAddress(_address, () => { @@ -890,7 +938,7 @@ export class AccountContext { /** * @func derivationCreateMultiple * @desc Derive multi account - * Note: Must update before re-use + * @todo Must update before re-use * @deprecated */ public derivationCreateMultiple ({ isAllowed, items, parentAddress }: RequestDeriveCreateMultiple): boolean { @@ -962,7 +1010,7 @@ export class AccountContext { /** * @func getListDeriveAccounts * @desc Get a derivation account list. - * Note: Must update before re-use + * @todo Must update before re-use * @deprecated */ public getListDeriveAccounts ({ limit, page, parentAddress }: RequestGetDeriveAccounts): ResponseGetDeriveAccounts { @@ -1031,6 +1079,10 @@ export class AccountContext { childPair = parentPair.substrate.derive(suri, meta); } + const exists = this.checkAddressExists([childPair.address]); + + assert(!exists, t('Account already exists')); + return { address: childPair.address, suri: meta.suri as string @@ -1073,6 +1125,10 @@ export class AccountContext { const address = childPair.address; + const exists = this.checkAddressExists([childPair.address]); + + assert(!exists, t('Account already exists')); + keyring.addPair(childPair, true); this.updateMetadataForPair(); From e9e029ae569f6912a48183ff915082e695553e01 Mon Sep 17 00:00:00 2001 From: lw Date: Fri, 9 Aug 2024 16:44:58 +0700 Subject: [PATCH 064/424] [MasterAccount] Update account type tag, action condition for account detail screen --- .../src/Popup/Account/AccountDetail/index.tsx | 116 ++++++++++++++---- .../AccountProxy/AccountProxyTypeTag.tsx | 112 +++++++++++++++++ .../src/components/AccountProxy/index.ts | 1 + .../Modal/Account/AccountNameModal.tsx | 4 +- .../screen/home/useReceiveModalHelper.tsx | 2 - 5 files changed, 204 insertions(+), 31 deletions(-) create mode 100644 packages/extension-koni-ui/src/components/AccountProxy/AccountProxyTypeTag.tsx diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx index 3caf1e64b8..e3aea01282 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx @@ -2,8 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 import { NotificationType } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountProxy } from '@subwallet/extension-base/types'; -import { CloseIcon, Layout, PageWrapper } from '@subwallet/extension-koni-ui/components'; +import { AccountProxy, AccountProxyType } from '@subwallet/extension-base/types'; +import { AccountProxyTypeTag, CloseIcon, Layout, PageWrapper } from '@subwallet/extension-koni-ui/components'; import { FilterTabItemType, FilterTabs } from '@subwallet/extension-koni-ui/components/FilterTabs'; import { WalletModalContext } from '@subwallet/extension-koni-ui/contexts/WalletModalContextProvider'; import { useGetAccountProxyById } from '@subwallet/extension-koni-ui/hooks'; @@ -182,6 +182,27 @@ const Component: React.FC = ({ accountProxy, onBack, requestView }, [accountProxy]); const footerNode = (() => { + if (![AccountProxyType.UNIFIED, AccountProxyType.SOLO].includes(accountProxy.accountType)) { + return ( + + ); + } + return <>
(({ theme: { token } }: Props) => { marginBottom: 0 }, + '.account-field-wrapper': { + position: 'relative' + }, + + '.account-type-tag-wrapper': { + position: 'absolute', + zIndex: 1, + right: token.sizeSM, + top: token.sizeXS, + display: 'flex' + }, + + '.account-type-tag': { + marginRight: 0 + }, + + '.account-type-tag + .derived-account-flag': { + marginLeft: token.marginXS, + color: token.colorTextLight3 + }, + '.account-name-input .ant-input-suffix .anticon': { minWidth: 40, justifyContent: 'center' diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxyTypeTag.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxyTypeTag.tsx new file mode 100644 index 0000000000..cd5ee5d19b --- /dev/null +++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxyTypeTag.tsx @@ -0,0 +1,112 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { AccountProxyType } from '@subwallet/extension-base/types'; +import useTranslation from '@subwallet/extension-koni-ui/hooks/common/useTranslation'; +import { ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { Icon, Tag } from '@subwallet/react-ui'; +import { SwIconProps } from '@subwallet/react-ui/es/icon'; +import { TagProps } from '@subwallet/react-ui/es/tag'; +import CN from 'classnames'; +import { CirclesThreePlus, Eye, GitCommit, Needle, QrCode, Question, Strategy, Swatches } from 'phosphor-react'; +import React, { useMemo } from 'react'; +import styled from 'styled-components'; + +interface Props extends ThemeProps { + type: AccountProxyType; +} + +type TagType = { + color?: TagProps['color']; + label: string; + icon: { + size?: SwIconProps['size']; + customSize?: SwIconProps['customSize']; + phosphorIcon?: SwIconProps['phosphorIcon'] + customIcon?: SwIconProps['customIcon']; + weight?: SwIconProps['weight']; + } +} + +const Component: React.FC = ({ className, type }: Props) => { + const { t } = useTranslation(); + + const tag = useMemo(() => { + const result: TagType = { + color: 'default', + label: '', + icon: { + weight: 'fill' + } + }; + + if (type === AccountProxyType.ALL_ACCOUNT) { + result.label = t('All account'); + result.icon.phosphorIcon = CirclesThreePlus; + } else if (type === AccountProxyType.SOLO) { + result.color = 'secondary'; + result.label = t('Solo account'); + result.icon.phosphorIcon = GitCommit; + } else if (type === AccountProxyType.UNIFIED) { + result.color = 'success'; + result.label = t('Unified account'); + result.icon.phosphorIcon = Strategy; + } else if (type === AccountProxyType.QR) { + result.label = t('QR signer account'); + result.icon.phosphorIcon = QrCode; + } else if (type === AccountProxyType.LEDGER) { + result.label = t('Ledger account'); + result.icon.phosphorIcon = Swatches; + } else if (type === AccountProxyType.READ_ONLY) { + result.label = t('Watch-only account'); + result.icon.phosphorIcon = Eye; + } else if (type === AccountProxyType.INJECTED) { + result.label = t('injected account'); + result.icon.phosphorIcon = Needle; + } else if (type === AccountProxyType.UNKNOWN) { + result.label = t('Unknown account'); + result.icon.phosphorIcon = Question; + } + + return result; + }, [t, type]); + + return ( + + )} + > + {tag.label} + + ); +}; + +const AccountProxyTypeTag = styled(Component)(({ theme: { token } }: Props) => { + return { + '&.ant-tag-default': { + position: 'relative', + color: token['gray-6'], + + '&:before': { + content: '""', + backgroundColor: token['gray-10'], + width: '100%', + height: '100%', + position: 'absolute', + borderRadius: 8, + top: 0, + left: 0, + zIndex: 1, + opacity: 0.1 + } + } + }; +}); + +export default AccountProxyTypeTag; diff --git a/packages/extension-koni-ui/src/components/AccountProxy/index.ts b/packages/extension-koni-ui/src/components/AccountProxy/index.ts index c42f8d6c01..86f46dc2ed 100644 --- a/packages/extension-koni-ui/src/components/AccountProxy/index.ts +++ b/packages/extension-koni-ui/src/components/AccountProxy/index.ts @@ -9,3 +9,4 @@ export { default as AccountProxyAvatar } from './AccountProxyAvatar'; export { default as AccountProxyAvatarGroup } from './AccountProxyAvatarGroup'; export { default as AccountNetworkAddressItem } from './AccountNetworkAddressItem'; export { default as AccountAddressItem } from './AccountAddressItem'; +export { default as AccountProxyTypeTag } from './AccountProxyTypeTag'; diff --git a/packages/extension-koni-ui/src/components/Modal/Account/AccountNameModal.tsx b/packages/extension-koni-ui/src/components/Modal/Account/AccountNameModal.tsx index 9acd069a00..5fe07ee0d4 100644 --- a/packages/extension-koni-ui/src/components/Modal/Account/AccountNameModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/Account/AccountNameModal.tsx @@ -31,7 +31,7 @@ const Component: React.FC = ({ className, isLoading, onSubmit }: Props) = name: '' }), []); - const accounNameValue = Form.useWatch('name', form); + const accountNameValue = Form.useWatch('name', form); const accountNameRules = useMemo(() => { return [ @@ -85,7 +85,7 @@ const Component: React.FC = ({ className, isLoading, onSubmit }: Props) = + + + ); +}; + +const TonSignArea = styled(Component)(({ theme: { token } }: Props) => { + return {}; +}); + +export default TonSignArea; diff --git a/packages/extension-koni-ui/src/Popup/Confirmations/variants/Transaction/index.tsx b/packages/extension-koni-ui/src/Popup/Confirmations/variants/Transaction/index.tsx index 11118bba05..205b36670b 100644 --- a/packages/extension-koni-ui/src/Popup/Confirmations/variants/Transaction/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Confirmations/variants/Transaction/index.tsx @@ -1,12 +1,13 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { ConfirmationDefinitions, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; +import { ConfirmationDefinitions, ConfirmationDefinitionsTon, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; import { SigningRequest } from '@subwallet/extension-base/background/types'; import { SWTransactionResult } from '@subwallet/extension-base/services/transaction-service/types'; import { SwapTxData } from '@subwallet/extension-base/types/swap'; import { AlertBox } from '@subwallet/extension-koni-ui/components'; import { useTranslation } from '@subwallet/extension-koni-ui/hooks'; +import TonSignArea from '@subwallet/extension-koni-ui/Popup/Confirmations/parts/Sign/Ton'; import { RootState } from '@subwallet/extension-koni-ui/stores'; import { ConfirmationQueueItem } from '@subwallet/extension-koni-ui/stores/base/RequestState'; import { AlertDialogProps, ThemeProps } from '@subwallet/extension-koni-ui/types'; @@ -158,6 +159,17 @@ const Component: React.FC = (props: Props) => { /> ) } + { + (type === 'tonSendTransactionRequest' || 'tonWatchTransactionRequest') && ( + + ) + } ); }; diff --git a/packages/extension-koni-ui/src/contexts/DataContext.tsx b/packages/extension-koni-ui/src/contexts/DataContext.tsx index 8cc6df5494..f9cef79038 100644 --- a/packages/extension-koni-ui/src/contexts/DataContext.tsx +++ b/packages/extension-koni-ui/src/contexts/DataContext.tsx @@ -3,7 +3,7 @@ import { ping } from '@subwallet/extension-koni-ui/messaging'; import { persistor, store, StoreName } from '@subwallet/extension-koni-ui/stores'; -import { getMissionPoolData, subscribeAccountsData, subscribeAddressBook, subscribeAssetLogoMaps, subscribeAssetRegistry, subscribeAssetSettings, subscribeAuthorizeRequests, subscribeAuthUrls, subscribeBalance, subscribeBuyServices, subscribeBuyTokens, subscribeCampaignBannerData, subscribeCampaignConfirmationData, subscribeCampaignPopupData, subscribeCampaignPopupVisibility, subscribeChainInfoMap, subscribeChainLogoMaps, subscribeChainStakingMetadata, subscribeChainStateMap, subscribeChainStatusMap, subscribeConfirmationRequests, subscribeConnectWCRequests, subscribeCrowdloan, subscribeKeyringState, subscribeMantaPayConfig, subscribeMantaPaySyncingState, subscribeMetadataRequests, subscribeMultiChainAssetMap, subscribeNftCollections, subscribeNftItems, subscribePrice, subscribeProcessingCampaign, subscribeRewardHistory, subscribeSigningRequests, subscribeStaking, subscribeStakingNominatorMetadata, subscribeStakingReward, subscribeSwapPairs, subscribeTransactionRequests, subscribeTxHistory, subscribeUiSettings, subscribeWalletConnectSessions, subscribeWCNotSupportRequests, subscribeXcmRefMap, subscribeYieldMinAmountPercent, subscribeYieldPoolInfo, subscribeYieldPositionInfo, subscribeYieldReward } from '@subwallet/extension-koni-ui/stores/utils'; +import { getMissionPoolData, subscribeAccountsData, subscribeAddressBook, subscribeAssetLogoMaps, subscribeAssetRegistry, subscribeAssetSettings, subscribeAuthorizeRequests, subscribeAuthUrls, subscribeBalance, subscribeBuyServices, subscribeBuyTokens, subscribeCampaignBannerData, subscribeCampaignConfirmationData, subscribeCampaignPopupData, subscribeCampaignPopupVisibility, subscribeChainInfoMap, subscribeChainLogoMaps, subscribeChainStakingMetadata, subscribeChainStateMap, subscribeChainStatusMap, subscribeConfirmationRequests, subscribeConfirmationRequestsTon, subscribeConnectWCRequests, subscribeCrowdloan, subscribeKeyringState, subscribeMantaPayConfig, subscribeMantaPaySyncingState, subscribeMetadataRequests, subscribeMultiChainAssetMap, subscribeNftCollections, subscribeNftItems, subscribePrice, subscribeProcessingCampaign, subscribeRewardHistory, subscribeSigningRequests, subscribeStaking, subscribeStakingNominatorMetadata, subscribeStakingReward, subscribeSwapPairs, subscribeTransactionRequests, subscribeTxHistory, subscribeUiSettings, subscribeWalletConnectSessions, subscribeWCNotSupportRequests, subscribeXcmRefMap, subscribeYieldMinAmountPercent, subscribeYieldPoolInfo, subscribeYieldPositionInfo, subscribeYieldReward } from '@subwallet/extension-koni-ui/stores/utils'; import Bowser from 'bowser'; import React from 'react'; import { Provider } from 'react-redux'; @@ -224,6 +224,7 @@ export const DataContextProvider = ({ children }: DataContextProviderProps) => { _DataContext.addHandler({ ...subscribeMetadataRequests, name: 'subscribeMetadataRequests', relatedStores: ['requestState'], isStartImmediately: true }); _DataContext.addHandler({ ...subscribeSigningRequests, name: 'subscribeSigningRequests', relatedStores: ['requestState'], isStartImmediately: true }); _DataContext.addHandler({ ...subscribeConfirmationRequests, name: 'subscribeConfirmationRequests', relatedStores: ['requestState'], isStartImmediately: true }); + _DataContext.addHandler({ ...subscribeConfirmationRequestsTon, name: 'subscribeConfirmationRequestsTon', relatedStores: ['requestState'], isStartImmediately: true }); _DataContext.addHandler({ ...subscribeTransactionRequests, name: 'subscribeTransactionRequests', relatedStores: ['requestState'], isStartImmediately: true }); _DataContext.addHandler({ ...subscribeConnectWCRequests, name: 'subscribeConnectWCRequests', relatedStores: ['requestState'], isStartImmediately: true }); _DataContext.addHandler({ ...subscribeWCNotSupportRequests, name: 'subscribeWCNotSupportRequests', relatedStores: ['requestState'], isStartImmediately: true }); diff --git a/packages/extension-koni-ui/src/messaging/confirmation/base.ts b/packages/extension-koni-ui/src/messaging/confirmation/base.ts index b9792dc481..5a456901c9 100644 --- a/packages/extension-koni-ui/src/messaging/confirmation/base.ts +++ b/packages/extension-koni-ui/src/messaging/confirmation/base.ts @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { ConfirmationDefinitions, ConfirmationType, RequestSigningApprovePasswordV2 } from '@subwallet/extension-base/background/KoniTypes'; +import { ConfirmationDefinitions, ConfirmationDefinitionsTon, ConfirmationType, ConfirmationTypeTon, RequestSigningApprovePasswordV2 } from '@subwallet/extension-base/background/KoniTypes'; import { ResponseSigningIsLocked } from '@subwallet/extension-base/background/types'; import { HexString } from '@polkadot/util/types'; @@ -31,3 +31,7 @@ export async function approveSignSignature (id: string, signature: HexString, si export async function completeConfirmation (type: CT, payload: ConfirmationDefinitions[CT][1]): Promise { return sendMessage('pri(confirmations.complete)', { [type]: payload }); } + +export async function completeConfirmationTon (type: CT, payload: ConfirmationDefinitionsTon[CT][1]): Promise { + return sendMessage('pri(confirmationsTon.complete)', { [type]: payload }); +} diff --git a/packages/extension-koni-ui/src/stores/base/RequestState.ts b/packages/extension-koni-ui/src/stores/base/RequestState.ts index cc5c583506..f6fb5e534a 100644 --- a/packages/extension-koni-ui/src/stores/base/RequestState.ts +++ b/packages/extension-koni-ui/src/stores/base/RequestState.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { createSlice, PayloadAction } from '@reduxjs/toolkit'; -import { ConfirmationsQueue } from '@subwallet/extension-base/background/KoniTypes'; +import { ConfirmationsQueue, ConfirmationsQueueTon } from '@subwallet/extension-base/background/KoniTypes'; import { AuthorizeRequest, ConfirmationRequestBase, MetadataRequest, SigningRequest } from '@subwallet/extension-base/background/types'; import { SWTransactionResult } from '@subwallet/extension-base/services/transaction-service/types'; import { WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; @@ -26,6 +26,10 @@ const initialState: RequestState = { evmSendTransactionRequest: {}, evmWatchTransactionRequest: {}, + tonSignatureRequest: {}, + tonSendTransactionRequest: {}, + tonWatchTransactionRequest: {}, + // Summary Info reduxStatus: ReduxStatus.INIT, hasConfirmations: false, @@ -43,6 +47,9 @@ export const CONFIRMATIONS_FIELDS: Array = [ 'evmSignatureRequest', 'evmSendTransactionRequest', 'evmWatchTransactionRequest', + 'tonSignatureRequest', + 'tonSendTransactionRequest', + 'tonWatchTransactionRequest', 'connectWCRequest', 'notSupportWCRequest' ]; @@ -59,6 +66,7 @@ const readyMap = { updateMetadataRequests: false, updateSigningRequests: false, updateConfirmationRequests: false, + updateConfirmationRequestsTon: false, updateConnectWalletConnect: false, updateNotSupportWalletConnect: false }; @@ -92,22 +100,22 @@ const requestStateSlice = createSlice({ updateAuthorizeRequests (state, { payload }: PayloadAction>) { state.authorizeRequest = payload; readyMap.updateAuthorizeRequests = true; - computeStateSummary(state); + computeStateSummary(state as RequestState); }, updateMetadataRequests (state, { payload }: PayloadAction>) { state.metadataRequest = payload; readyMap.updateMetadataRequests = true; - computeStateSummary(state); + computeStateSummary(state as RequestState); }, updateSigningRequests (state, { payload }: PayloadAction>) { state.signingRequest = payload; readyMap.updateSigningRequests = true; - computeStateSummary(state); + computeStateSummary(state as RequestState); }, updateConfirmationRequests (state, action: PayloadAction>) { Object.assign(state, action.payload); readyMap.updateConfirmationRequests = true; - computeStateSummary(state); + computeStateSummary(state as RequestState); }, updateTransactionRequests (state, { payload }: PayloadAction>) { state.transactionRequest = payload; @@ -115,13 +123,17 @@ const requestStateSlice = createSlice({ updateConnectWCRequests (state, { payload }: PayloadAction>) { state.connectWCRequest = payload; readyMap.updateConnectWalletConnect = true; - computeStateSummary(state); + computeStateSummary(state as RequestState); + }, + updateConfirmationRequestsTon (state, action: PayloadAction>) { + Object.assign(state, action.payload); + readyMap.updateConfirmationRequestsTon = true; + computeStateSummary(state as RequestState); }, - updateWCNotSupportRequests (state, { payload }: PayloadAction>) { state.notSupportWCRequest = payload; readyMap.updateNotSupportWalletConnect = true; - computeStateSummary(state); + computeStateSummary(state as RequestState); } } }); diff --git a/packages/extension-koni-ui/src/stores/types.ts b/packages/extension-koni-ui/src/stores/types.ts index 1e79931970..ab24d83b71 100644 --- a/packages/extension-koni-ui/src/stores/types.ts +++ b/packages/extension-koni-ui/src/stores/types.ts @@ -3,7 +3,7 @@ import { _AssetRef, _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet/chain-list/types'; import { AuthUrlInfo } from '@subwallet/extension-base/background/handlers/State'; -import { AddressBookState, AllLogoMap, AssetSetting, CampaignBanner, ChainStakingMetadata, ConfirmationDefinitions, ConfirmationsQueue, ConfirmationType, CrowdloanItem, KeyringState, LanguageType, MantaPayConfig, NftCollection, NftItem, NominatorMetadata, PriceJson, StakingItem, StakingRewardItem, TransactionHistoryItem, UiSettings, ValidatorInfo } from '@subwallet/extension-base/background/KoniTypes'; +import { AddressBookState, AllLogoMap, AssetSetting, CampaignBanner, ChainStakingMetadata, ConfirmationDefinitions, ConfirmationsQueue, ConfirmationsQueueTon, ConfirmationType, CrowdloanItem, KeyringState, LanguageType, MantaPayConfig, NftCollection, NftItem, NominatorMetadata, PriceJson, StakingItem, StakingRewardItem, TransactionHistoryItem, UiSettings, ValidatorInfo } from '@subwallet/extension-base/background/KoniTypes'; import { AccountsContext, AuthorizeRequest, MetadataRequest, SigningRequest } from '@subwallet/extension-base/background/types'; import { _ChainApiStatus, _ChainState } from '@subwallet/extension-base/services/chain-service/types'; import { AppBannerData, AppConfirmationData, AppPopupData } from '@subwallet/extension-base/services/mkt-campaign-service/types'; @@ -97,7 +97,7 @@ export interface AccountState extends AccountsContext, KeyringState, AddressBook isAllAccount: boolean } -export interface RequestState extends ConfirmationsQueue, BaseReduxStore { +export interface RequestState extends ConfirmationsQueue, ConfirmationsQueueTon, BaseReduxStore { authorizeRequest: Record; metadataRequest: Record; signingRequest: Record; diff --git a/packages/extension-koni-ui/src/stores/utils/index.ts b/packages/extension-koni-ui/src/stores/utils/index.ts index 73af0d9a85..2b1ccd879f 100644 --- a/packages/extension-koni-ui/src/stores/utils/index.ts +++ b/packages/extension-koni-ui/src/stores/utils/index.ts @@ -3,7 +3,7 @@ import { _AssetRef, _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet/chain-list/types'; import { AuthUrls } from '@subwallet/extension-base/background/handlers/State'; -import { AddressBookInfo, AssetSetting, CampaignBanner, ChainStakingMetadata, ConfirmationsQueue, CrowdloanJson, KeyringState, MantaPayConfig, MantaPaySyncState, NftCollection, NftJson, NominatorMetadata, PriceJson, ShowCampaignPopupRequest, StakingJson, StakingRewardJson, TransactionHistoryItem, UiSettings } from '@subwallet/extension-base/background/KoniTypes'; +import { AddressBookInfo, AssetSetting, CampaignBanner, ChainStakingMetadata, ConfirmationsQueue, ConfirmationsQueueTon, CrowdloanJson, KeyringState, MantaPayConfig, MantaPaySyncState, NftCollection, NftJson, NominatorMetadata, PriceJson, ShowCampaignPopupRequest, StakingJson, StakingRewardJson, TransactionHistoryItem, UiSettings } from '@subwallet/extension-base/background/KoniTypes'; import { AccountsContext, AuthorizeRequest, ConfirmationRequestBase, MetadataRequest, SigningRequest } from '@subwallet/extension-base/background/types'; import { _ChainApiStatus, _ChainState } from '@subwallet/extension-base/services/chain-service/types'; import { AppBannerData, AppConfirmationData, AppPopupData } from '@subwallet/extension-base/services/mkt-campaign-service/types'; @@ -142,6 +142,12 @@ export const updateConfirmationRequests = (data: ConfirmationsQueue) => { export const subscribeConfirmationRequests = lazySubscribeMessage('pri(confirmations.subscribe)', null, updateConfirmationRequests, updateConfirmationRequests); +export const updateConfirmationRequestsTon = (data: ConfirmationsQueueTon) => { + store.dispatch({ type: 'requestState/updateConfirmationRequestsTon', payload: data }); +}; + +export const subscribeConfirmationRequestsTon = lazySubscribeMessage('pri(confirmationsTon.subscribe)', null, updateConfirmationRequestsTon, updateConfirmationRequestsTon); + export const updateTransactionRequests = (data: Record) => { // Convert data to object with key as id diff --git a/packages/extension-koni-ui/src/types/confirmation.ts b/packages/extension-koni-ui/src/types/confirmation.ts index 00b0249098..2fe33c5e4d 100644 --- a/packages/extension-koni-ui/src/types/confirmation.ts +++ b/packages/extension-koni-ui/src/types/confirmation.ts @@ -1,6 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { ConfirmationDefinitions } from '@subwallet/extension-base/background/KoniTypes'; +import { ConfirmationDefinitions, ConfirmationDefinitionsTon } from '@subwallet/extension-base/background/KoniTypes'; export type EvmSignatureSupportType = keyof Pick; + +export type TonSignatureSupportType = keyof Pick; From e70803697ce51bce397daddf3ebe33f2e350a377 Mon Sep 17 00:00:00 2001 From: lw Date: Sat, 17 Aug 2024 18:01:26 +0700 Subject: [PATCH 107/424] [Issue-3448] Update account selector for earn transaction screen --- .../EarningEntry/EarningOptions/index.tsx | 8 +-- .../Popup/Home/Earning/EarningPools/index.tsx | 11 ++-- .../src/Popup/Transaction/variants/Earn.tsx | 66 +++++++++++-------- 3 files changed, 49 insertions(+), 36 deletions(-) diff --git a/packages/extension-koni-ui/src/Popup/Home/Earning/EarningEntry/EarningOptions/index.tsx b/packages/extension-koni-ui/src/Popup/Home/Earning/EarningEntry/EarningOptions/index.tsx index b12f3997f1..f9e372ae7a 100644 --- a/packages/extension-koni-ui/src/Popup/Home/Earning/EarningEntry/EarningOptions/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Home/Earning/EarningEntry/EarningOptions/index.tsx @@ -14,7 +14,7 @@ import { useFilterModal, useGroupYieldPosition, useHandleChainConnection, useSel import { getBalanceValue } from '@subwallet/extension-koni-ui/hooks/screen/home/useAccountBalance'; import { ChainConnectionWrapper } from '@subwallet/extension-koni-ui/Popup/Home/Earning/shared/ChainConnectionWrapper'; import { EarningEntryView, EarningPoolsParam, ThemeProps, YieldGroupInfo } from '@subwallet/extension-koni-ui/types'; -import { isAccountAll, isRelatedToAstar, openInNewTab } from '@subwallet/extension-koni-ui/utils'; +import { isRelatedToAstar, openInNewTab } from '@subwallet/extension-koni-ui/utils'; import { Icon, ModalContext, SwList } from '@subwallet/react-ui'; import CN from 'classnames'; import { FadersHorizontal, Vault } from 'phosphor-react'; @@ -69,7 +69,7 @@ function Component ({ className, hasEarningPositions, setEntryView }: Props) { const { poolInfoMap } = useSelector((state) => state.earning); const assetRegistry = useSelector((state) => state.assetRegistry.assetRegistry); const chainInfoMap = useSelector((state) => state.chainStore.chainInfoMap); - const { currentAccount } = useSelector((state) => state.accountState); + const { currentAccountProxy } = useSelector((state) => state.accountState); const { accountBalance: { tokenBalanceMap } } = useContext(HomeContext); const isShowBalance = useSelector((state) => state.settings.isShowBalance); @@ -129,11 +129,11 @@ function Component ({ className, hasEarningPositions, setEntryView }: Props) { ...DEFAULT_EARN_PARAMS, slug, chain, - from: currentAccount?.address ? isAccountAll(currentAccount.address) ? '' : currentAccount.address : '' + fromAccountProxy: currentAccountProxy?.id ? currentAccountProxy.id : '' }); navigate('/transaction/earn'); }, - [currentAccount?.address, navigate, setEarnStorage] + [currentAccountProxy?.id, navigate, setEarnStorage] ); const onConnectChainSuccess = useCallback(() => { diff --git a/packages/extension-koni-ui/src/Popup/Home/Earning/EarningPools/index.tsx b/packages/extension-koni-ui/src/Popup/Home/Earning/EarningPools/index.tsx index a8c8e2ba88..20a391f3e3 100644 --- a/packages/extension-koni-ui/src/Popup/Home/Earning/EarningPools/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Home/Earning/EarningPools/index.tsx @@ -14,7 +14,6 @@ import { useFilterModal, useGroupYieldPosition, useHandleChainConnection, useSel import { getBalanceValue } from '@subwallet/extension-koni-ui/hooks/screen/home/useAccountBalance'; import { ChainConnectionWrapper } from '@subwallet/extension-koni-ui/Popup/Home/Earning/shared/ChainConnectionWrapper'; import { EarningEntryParam, EarningEntryView, EarningPoolsParam, ThemeProps } from '@subwallet/extension-koni-ui/types'; -import { isAccountAll } from '@subwallet/extension-koni-ui/utils'; import { Icon, ModalContext, SwList } from '@subwallet/react-ui'; import BigN from 'bignumber.js'; import CN from 'classnames'; @@ -44,7 +43,7 @@ function Component ({ poolGroup, symbol }: ComponentProps) { const chainInfoMap = useSelector((state) => state.chainStore.chainInfoMap); const assetRegistry = useSelector((state) => state.assetRegistry.assetRegistry); - const { currentAccount } = useSelector((state) => state.accountState); + const { currentAccountProxy } = useSelector((state) => state.accountState); const [, setEarnStorage] = useLocalStorage(EARN_TRANSACTION, DEFAULT_EARN_PARAMS); const yieldPositions = useGroupYieldPosition(); @@ -56,14 +55,14 @@ function Component ({ poolGroup, symbol }: ComponentProps) { const { filterSelectionMap, onApplyFilter, onChangeFilterOption, onCloseFilterModal, selectedFilters } = useFilterModal(FILTER_MODAL_ID); - const filterOptions = [ + const filterOptions = useMemo(() => [ { label: t('Nomination pool'), value: YieldPoolType.NOMINATION_POOL }, { label: t('Direct nomination'), value: YieldPoolType.NATIVE_STAKING }, { label: t('Liquid staking'), value: YieldPoolType.LIQUID_STAKING }, { label: t('Lending'), value: YieldPoolType.LENDING }, { label: t('Parachain staking'), value: YieldPoolType.PARACHAIN_STAKING }, { label: t('Single farming'), value: YieldPoolType.SINGLE_FARMING } - ]; + ], [t]); const positionSlugs = useMemo(() => { return yieldPositions.map((p) => p.slug); @@ -174,11 +173,11 @@ function Component ({ poolGroup, symbol }: ComponentProps) { ...DEFAULT_EARN_PARAMS, slug: item.slug, chain: item.chain, - from: currentAccount?.address ? isAccountAll(currentAccount.address) ? '' : currentAccount.address : '' + fromAccountProxy: currentAccountProxy?.id ? currentAccountProxy?.id : '' }); navigate('/transaction/earn'); }, - [currentAccount?.address, navigate, setEarnStorage] + [currentAccountProxy?.id, navigate, setEarnStorage] ); const onConnectChainSuccess = useCallback(() => { diff --git a/packages/extension-koni-ui/src/Popup/Transaction/variants/Earn.tsx b/packages/extension-koni-ui/src/Popup/Transaction/variants/Earn.tsx index 2b8c2fe22f..ee12df9272 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/variants/Earn.tsx +++ b/packages/extension-koni-ui/src/Popup/Transaction/variants/Earn.tsx @@ -4,12 +4,12 @@ import { _ChainAsset } from '@subwallet/chain-list/types'; import { ExtrinsicType, NotificationType } from '@subwallet/extension-base/background/KoniTypes'; import { _handleDisplayForEarningError, _handleDisplayInsufficientEarningError } from '@subwallet/extension-base/core/logic-validation/earning'; -import { _getAssetDecimals, _getAssetSymbol, _getSubstrateGenesisHash, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { _getAssetDecimals, _getAssetSymbol } from '@subwallet/extension-base/services/chain-service/utils'; import { isLendingPool, isLiquidPool } from '@subwallet/extension-base/services/earning-service/utils'; import { SWTransactionResponse } from '@subwallet/extension-base/services/transaction-service/types'; -import { NominationPoolInfo, OptimalYieldPath, OptimalYieldPathParams, SubmitJoinNativeStaking, SubmitJoinNominationPool, SubmitYieldJoinData, ValidatorInfo, YieldPoolType, YieldStepType } from '@subwallet/extension-base/types'; +import { AccountProxyType, NominationPoolInfo, OptimalYieldPath, OptimalYieldPathParams, SubmitJoinNativeStaking, SubmitJoinNominationPool, SubmitYieldJoinData, ValidatorInfo, YieldPoolType, YieldStepType } from '@subwallet/extension-base/types'; import { addLazy } from '@subwallet/extension-base/utils'; -import { AccountSelector, AlertBox, AmountInput, EarningPoolSelector, EarningValidatorSelector, HiddenInput, InfoIcon, LoadingScreen, MetaInfo } from '@subwallet/extension-koni-ui/components'; +import { AccountAddressSelector, AlertBox, AmountInput, EarningPoolSelector, EarningValidatorSelector, HiddenInput, InfoIcon, LoadingScreen, MetaInfo } from '@subwallet/extension-koni-ui/components'; import { EarningProcessItem } from '@subwallet/extension-koni-ui/components/Earning'; import { getInputValuesFromString } from '@subwallet/extension-koni-ui/components/Field/AmountInput'; import { EarningInstructionModal } from '@subwallet/extension-koni-ui/components/Modal/Earning'; @@ -18,8 +18,8 @@ import { useChainConnection, useFetchChainState, useGetBalance, useGetNativeToke import { fetchPoolTarget, getOptimalYieldPath, submitJoinYieldPool, validateYieldProcess } from '@subwallet/extension-koni-ui/messaging'; import { DEFAULT_YIELD_PROCESS, EarningActionType, earningReducer } from '@subwallet/extension-koni-ui/reducer'; import { store } from '@subwallet/extension-koni-ui/stores'; -import { EarnParams, FormCallbacks, FormFieldData, ThemeProps } from '@subwallet/extension-koni-ui/types'; -import { convertFieldToObject, isAccountAll, parseNominations, reformatAddress, simpleCheckForm } from '@subwallet/extension-koni-ui/utils'; +import { AccountAddressItemType, EarnParams, FormCallbacks, FormFieldData, ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { convertFieldToObject, getReformatedAddressRelatedToNetwork, isAccountAll, parseNominations, reformatAddress, simpleCheckForm } from '@subwallet/extension-koni-ui/utils'; import { ActivityIndicator, Button, ButtonProps, Form, Icon, ModalContext, Number } from '@subwallet/react-ui'; import BigN from 'bignumber.js'; import CN from 'classnames'; @@ -28,14 +28,12 @@ import React, { useCallback, useContext, useEffect, useMemo, useReducer, useRef, import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; -import { isEthereumAddress } from '@polkadot/util-crypto'; - import { getJoinYieldParams } from '../helper'; import { EarnOutlet, FreeBalance, FreeBalanceToEarn, TransactionContent, TransactionFooter } from '../parts'; type Props = ThemeProps; -const hideFields: Array = ['slug', 'chain', 'asset']; +const hideFields: Array = ['slug', 'chain', 'asset', 'fromAccountProxy']; const validateFields: Array = ['from']; const loadingStepPromiseKey = 'earning.step.loading'; @@ -53,9 +51,9 @@ const Component = () => { openAlert, persistData, setBackProps, setIsDisableHeader, setSubHeaderRightButtons } = useTransactionContext(); - const { slug } = defaultData; + const { fromAccountProxy, slug } = defaultData; - const { accounts, isAllAccount } = useSelector((state) => state.accountState); + const accountProxies = useSelector((state) => state.accountState.accountProxies); const chainInfoMap = useSelector((state) => state.chainStore.chainInfoMap); const poolInfoMap = useSelector((state) => state.earning.poolInfoMap); const poolTargetsMap = useSelector((state) => state.earning.poolTargetsMap); @@ -239,25 +237,43 @@ const Component = () => { } }, [poolTargetValue, poolTargetsMap, poolType, slug]); - const accountSelectorList = useMemo(() => { - const chainInfo = chainInfoMap[poolChain]; + // todo: will convert logic to util if is necessary + const accountAddressItems = useMemo(() => { + const chainInfo = poolChain ? chainInfoMap[poolChain] : undefined; if (!chainInfo) { return []; } - return accounts.filter((a) => { - if (isAccountAll(a.address)) { - return false; + const result: AccountAddressItemType[] = []; + + accountProxies.forEach((ap) => { + if (!(isAccountAll(fromAccountProxy) || ap.id === fromAccountProxy)) { + return; } - if (a.genesisHash && _getSubstrateGenesisHash(chainInfo) !== a.genesisHash) { - return false; + // todo: support ledger later + if ([AccountProxyType.READ_ONLY, AccountProxyType.LEDGER].includes(ap.accountType)) { + return; } - return _isChainEvmCompatible(chainInfo) === isEthereumAddress(a.address); + ap.accounts.forEach((a) => { + const address = getReformatedAddressRelatedToNetwork(a, chainInfo); + + if (address) { + result.push({ + accountName: ap.name, + accountProxyId: ap.id, + accountProxyType: ap.accountType, + accountType: a.type, + address + }); + } + }); }); - }, [accounts, chainInfoMap, poolChain]); + + return result; + }, [accountProxies, chainInfoMap, fromAccountProxy, poolChain]); const onFieldsChange: FormCallbacks['onFieldsChange'] = useCallback((changedFields: FormFieldData[], allFields: FormFieldData[]) => { // TODO: field change @@ -722,10 +738,10 @@ const Component = () => { }, [form, inputAsset.slug]); useEffect(() => { - if (!fromValue && accountSelectorList.length === 1) { - form.setFieldValue('from', accountSelectorList[0].address); + if (!fromValue && accountAddressItems.length === 1) { + form.setFieldValue('from', accountAddressItems[0].address); } - }, [accountSelectorList, form, fromValue]); + }, [accountAddressItems, form, fromValue]); useEffect(() => { if (currentStep === 0) { @@ -916,10 +932,8 @@ const Component = () => { - From e8195f7233d1714cf1c4b8a4271fcf563c27d93d Mon Sep 17 00:00:00 2001 From: S2kael Date: Sat, 17 Aug 2024 18:01:57 +0700 Subject: [PATCH 108/424] [Issue-3462] [Earning] Fix filter error --- .../hooks/account/useGetAccountNetworkAddresses.tsx | 2 -- .../src/hooks/earning/useYieldGroupInfo.ts | 4 ++-- packages/extension-koni-ui/src/utils/chain/chain.ts | 10 ++++++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx b/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx index 97683f8251..6190ca4d8c 100644 --- a/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx +++ b/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx @@ -9,8 +9,6 @@ import { useMemo } from 'react'; // todo: // - order the result -// - support bitcoin -// - logic for generic, legacy ledger account const useGetAccountNetworkAddresses = (accountProxy: AccountProxy): AccountNetworkAddress[] => { const chainInfoMap = useSelector((state) => state.chainStore.chainInfoMap); diff --git a/packages/extension-koni-ui/src/hooks/earning/useYieldGroupInfo.ts b/packages/extension-koni-ui/src/hooks/earning/useYieldGroupInfo.ts index c3a01a3e9d..a76a4433b5 100644 --- a/packages/extension-koni-ui/src/hooks/earning/useYieldGroupInfo.ts +++ b/packages/extension-koni-ui/src/hooks/earning/useYieldGroupInfo.ts @@ -3,7 +3,7 @@ import { calculateReward } from '@subwallet/extension-base/services/earning-service/utils'; import { BN_ZERO } from '@subwallet/extension-koni-ui/constants'; -import { useAccountBalance, useGetChainSlugsByCurrentAccount, useSelector, useTokenGroup } from '@subwallet/extension-koni-ui/hooks'; +import { useAccountBalance, useGetChainSlugsByAccount, useSelector, useTokenGroup } from '@subwallet/extension-koni-ui/hooks'; import { BalanceValueInfo, YieldGroupInfo } from '@subwallet/extension-koni-ui/types'; import { useMemo } from 'react'; @@ -11,7 +11,7 @@ const useYieldGroupInfo = (): YieldGroupInfo[] => { const poolInfoMap = useSelector((state) => state.earning.poolInfoMap); const { assetRegistry, multiChainAssetMap } = useSelector((state) => state.assetRegistry); const chainInfoMap = useSelector((state) => state.chainStore.chainInfoMap); - const chainsByAccountType = useGetChainSlugsByCurrentAccount(); + const chainsByAccountType = useGetChainSlugsByAccount(); const { tokenGroupMap } = useTokenGroup(chainsByAccountType); const { tokenBalanceMap } = useAccountBalance(tokenGroupMap, true); diff --git a/packages/extension-koni-ui/src/utils/chain/chain.ts b/packages/extension-koni-ui/src/utils/chain/chain.ts index e98d5d8713..fba673b609 100644 --- a/packages/extension-koni-ui/src/utils/chain/chain.ts +++ b/packages/extension-koni-ui/src/utils/chain/chain.ts @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { _ChainInfo } from '@subwallet/chain-list/types'; +import { _ChainInfo, _ChainStatus } from '@subwallet/chain-list/types'; import { _getSubstrateGenesisHash, _isChainBitcoinCompatible, _isChainEvmCompatible, _isChainSubstrateCompatible, _isChainTonCompatible, _isPureSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils'; import { AccountNetworkType } from '@subwallet/extension-base/types'; @@ -46,10 +46,16 @@ export const isChainInfoAccordantNetworkType = (chainInfo: _ChainInfo, networkTy return _isChainTonCompatible(chainInfo); } + if (networkType === AccountNetworkType.BITCOIN) { + return _isChainBitcoinCompatible(chainInfo); + } + return false; }; -export const getChainsByAccountType = (chainInfoMap: Record, networkTypes: AccountNetworkType[], specialNetwork?: string): string[] => { +export const getChainsByAccountType = (_chainInfoMap: Record, networkTypes: AccountNetworkType[], specialNetwork?: string): string[] => { + const chainInfoMap = Object.fromEntries(Object.entries(_chainInfoMap).filter(([, chainInfo]) => chainInfo.chainStatus === _ChainStatus.ACTIVE)); + if (specialNetwork) { return Object.keys(chainInfoMap).filter((chain) => specialNetwork === chain); } else { From b860cacd9479c54768b04d6ba7f4a05ca2e1e634 Mon Sep 17 00:00:00 2001 From: Thiendekaco Date: Sat, 17 Aug 2024 17:59:28 +0700 Subject: [PATCH 109/424] [Issue 3457] [update] Extension - update add account name step when import by private key --- .../src/Popup/Account/ImportPrivateKey.tsx | 79 ++++++++++++------- .../src/Popup/Account/ImportSeedPhrase.tsx | 7 +- .../src/Popup/Account/NewSeedPhrase.tsx | 6 +- .../Modal/Account/AccountNameModal.tsx | 9 +-- .../Modal/Account/DeriveAccountModal.tsx | 7 +- 5 files changed, 68 insertions(+), 40 deletions(-) diff --git a/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx b/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx index f972d65d13..091c88c4d6 100644 --- a/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx @@ -1,17 +1,23 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { CloseIcon, Layout, PageWrapper, PrivateKeyInput } from '@subwallet/extension-koni-ui/components'; -import { EVM_ACCOUNT_TYPE } from '@subwallet/extension-koni-ui/constants/account'; -import { IMPORT_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants/modal'; +import { + AccountNameModal, + CloseIcon, + Layout, + PageWrapper, + PrivateKeyInput +} from '@subwallet/extension-koni-ui/components'; +import {ACCOUNT_NAME_MODAL, IMPORT_ACCOUNT_MODAL} from '@subwallet/extension-koni-ui/constants/modal'; import { useAutoNavigateToCreatePassword, useCompleteCreateAccount, useDefaultNavigate, useFocusFormItem, useGetDefaultAccountName, useGoBackFromCreateAccount, useTranslation, useUnlockChecker } from '@subwallet/extension-koni-ui/hooks'; import { createAccountSuriV2, validateMetamaskPrivateKeyV2 } from '@subwallet/extension-koni-ui/messaging'; import { FormCallbacks, ThemeProps, ValidateState } from '@subwallet/extension-koni-ui/types'; -import { Button, Form, Icon } from '@subwallet/react-ui'; +import {Button, Form, Icon, ModalContext} from '@subwallet/react-ui'; import CN from 'classnames'; import { Eye, EyeSlash, FileArrowDown } from 'phosphor-react'; -import React, { useCallback, useEffect, useRef, useState } from 'react'; +import React, {useCallback, useContext, useEffect, useRef, useState} from 'react'; import styled from 'styled-components'; +import {AccountProxyType} from "@subwallet/extension-base/types"; type Props = ThemeProps; @@ -45,6 +51,8 @@ const Component: React.FC = ({ className }: Props) => { const [loading, setLoading] = useState(false); const [show, setShow] = useState(false); const [changed, setChanged] = useState(false); + const [ privatekeySubmit, setPrivateKeySubmit ] = useState(''); + const { activeModal, inactiveModal } = useContext(ModalContext); const [form] = Form.useForm(); const checkUnlock = useUnlockChecker(); @@ -59,33 +67,38 @@ const Component: React.FC = ({ className }: Props) => { const { [fieldName]: privateKey } = values; checkUnlock().then(() => { - if (privateKey?.trim()) { - setLoading(true); - createAccountSuriV2({ - name: accountName, - suri: privateKey.trim(), - isAllowed: true, - types: [EVM_ACCOUNT_TYPE] - }) - .then(() => { - onComplete(); - }) - .catch((error: Error): void => { - setValidateState({ - status: 'error', - message: error.message - }); - }) - .finally(() => { - setLoading(false); - }); - } + setPrivateKeySubmit(privateKey); }) .catch(() => { // User cancel unlock }); }, [accountName, checkUnlock, onComplete]); + + const onSubmitFinal = useCallback((name : string) => { + if (privatekeySubmit?.trim()) { + setLoading(true); + createAccountSuriV2({ + name: name, + suri: privatekeySubmit.trim(), + isAllowed: true + }) + .then(() => { + onComplete(); + }) + .catch((error: Error): void => { + setValidateState({ + status: 'error', + message: error.message + }); + }) + .finally(() => { + inactiveModal(ACCOUNT_NAME_MODAL) + setLoading(false); + }); + } + }, [privatekeySubmit, onComplete]) + useEffect(() => { let amount = true; @@ -102,7 +115,7 @@ const Component: React.FC = ({ className }: Props) => { }); timeOutRef.current = setTimeout(() => { - validateMetamaskPrivateKeyV2(privateKey.trim(), [EVM_ACCOUNT_TYPE]) + validateMetamaskPrivateKeyV2(privateKey.trim()) .then(({ autoAddPrefix }) => { if (amount) { if (autoAddPrefix) { @@ -141,6 +154,12 @@ const Component: React.FC = ({ className }: Props) => { }; }, [privateKey, form, changed, t]); + useEffect(() => { + if(privatekeySubmit.trim()){ + activeModal(ACCOUNT_NAME_MODAL); + } + }, [activeModal, privatekeySubmit]); + const onValuesChange: FormCallbacks['onValuesChange'] = useCallback((changedValues: Partial) => { if (fieldName in changedValues) { setChanged(true); @@ -211,6 +230,12 @@ const Component: React.FC = ({ className }: Props) => { + +
); diff --git a/packages/extension-koni-ui/src/Popup/Account/ImportSeedPhrase.tsx b/packages/extension-koni-ui/src/Popup/Account/ImportSeedPhrase.tsx index 8b83f9eb1f..fcb8e3085f 100644 --- a/packages/extension-koni-ui/src/Popup/Account/ImportSeedPhrase.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/ImportSeedPhrase.tsx @@ -28,6 +28,7 @@ const FooterIcon = ( const formName = 'import-seed-phrase-form'; const fieldNamePrefix = 'seed-phrase-'; +const accountNameModalId = 'seedPhrase.' + ACCOUNT_NAME_MODAL interface FormState extends Record<`seed-phrase-${number}`, string> { phraseNumber: string; @@ -165,14 +166,14 @@ const Component: React.FC = ({ className }: Props) => { icon: CheckCircle, iconWeight: 'fill', onClick: () => { - activeModal(ACCOUNT_NAME_MODAL); + activeModal(accountNameModalId); alertModal.close(); }, schema: 'primary' } }); } else { - activeModal(ACCOUNT_NAME_MODAL); + activeModal(accountNameModalId); } }) .catch((error: Error): void => { @@ -216,7 +217,7 @@ const Component: React.FC = ({ className }: Props) => { setSeedValidationResponse(undefined); setAccountCreating(false); setSubmitting(false); - inactiveModal(ACCOUNT_NAME_MODAL); + inactiveModal(accountNameModalId); }); }, [inactiveModal, notify, onComplete, seedValidationResponse]); diff --git a/packages/extension-koni-ui/src/Popup/Account/NewSeedPhrase.tsx b/packages/extension-koni-ui/src/Popup/Account/NewSeedPhrase.tsx index f524767368..d929b0f259 100644 --- a/packages/extension-koni-ui/src/Popup/Account/NewSeedPhrase.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/NewSeedPhrase.tsx @@ -28,6 +28,8 @@ const FooterIcon = ( /> ); +const accountNameModalId = 'seedPhrase.' + ACCOUNT_NAME_MODAL + const Component: React.FC = ({ className }: Props) => { useAutoNavigateToCreatePassword(); const { t } = useTranslation(); @@ -70,7 +72,7 @@ const Component: React.FC = ({ className }: Props) => { } checkUnlock().then(() => { - activeModal(ACCOUNT_NAME_MODAL); + activeModal(accountNameModalId); }).catch(() => { // User cancel unlock }); @@ -95,7 +97,7 @@ const Component: React.FC = ({ className }: Props) => { }) .finally(() => { setLoading(false); - inactiveModal(ACCOUNT_NAME_MODAL); + inactiveModal(accountNameModalId); }); }, [inactiveModal, notify, onComplete, seedPhrase, selectedMnemonicType]); diff --git a/packages/extension-koni-ui/src/components/Modal/Account/AccountNameModal.tsx b/packages/extension-koni-ui/src/components/Modal/Account/AccountNameModal.tsx index 6ca458dd6b..0a447dbf42 100644 --- a/packages/extension-koni-ui/src/components/Modal/Account/AccountNameModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/Account/AccountNameModal.tsx @@ -15,16 +15,15 @@ import styled from 'styled-components'; type Props = ThemeProps & { isLoading?: boolean; accountType?: AccountProxyType; // for display account proxy tag - onSubmit?: (name: string) => void + onSubmit?: (name: string) => void; + modalId?: string; }; interface FormProps { name: string; } -const modalId = ACCOUNT_NAME_MODAL; - -const Component: React.FC = ({ accountType, className, isLoading, onSubmit }: Props) => { +const Component: React.FC = ({ accountType, className, isLoading, onSubmit, modalId }: Props) => { const { t } = useTranslation(); const [form] = Form.useForm(); const defaultValues = useMemo(() => ({ @@ -51,7 +50,7 @@ const Component: React.FC = ({ accountType, className, isLoading, onSubmi ('Account name')} > diff --git a/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx b/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx index 53f69aed1e..a95b54f66d 100644 --- a/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx @@ -32,7 +32,7 @@ import {AccountNameModal, AccountProxyItem} from "@subwallet/extension-koni-ui/c type Props = ThemeProps; const modalId = DERIVE_ACCOUNT_MODAL; - +const accountNameModalId = 'derive.' + ACCOUNT_NAME_MODAL const renderEmpty = () => ; const renderLoaderIcon = (x: React.ReactNode): React.ReactNode => { @@ -109,7 +109,7 @@ const Component: React.FC = ({ className }: Props) => { }); }).finally(() => { setSelected(''); - inactiveModal(ACCOUNT_NAME_MODAL) + inactiveModal(accountNameModalId) }); }, 500); } @@ -117,7 +117,7 @@ const Component: React.FC = ({ className }: Props) => { useEffect(() => { if(accountSelected) { - activeModal(ACCOUNT_NAME_MODAL); + activeModal(accountNameModalId); } }, [accountSelected, activeModal]) @@ -165,6 +165,7 @@ const Component: React.FC = ({ className }: Props) => { From a8ba4adb15bbc007a229b50bd030bcd0fdf53744 Mon Sep 17 00:00:00 2001 From: Thiendekaco Date: Sat, 17 Aug 2024 18:33:52 +0700 Subject: [PATCH 110/424] [Issue 3457] [update] Extension - update add account name step when add account watch only --- .../src/Popup/Account/AttachReadOnly.tsx | 73 ++++++++++--------- .../src/Popup/Account/ImportPrivateKey.tsx | 18 ++--- .../src/Popup/Account/ImportSeedPhrase.tsx | 2 +- .../src/Popup/Account/NewSeedPhrase.tsx | 2 +- 4 files changed, 49 insertions(+), 46 deletions(-) diff --git a/packages/extension-koni-ui/src/Popup/Account/AttachReadOnly.tsx b/packages/extension-koni-ui/src/Popup/Account/AttachReadOnly.tsx index 6c9f3f7add..3b7713e3c6 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AttachReadOnly.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AttachReadOnly.tsx @@ -1,10 +1,10 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { Layout, PageWrapper } from '@subwallet/extension-koni-ui/components'; +import {AccountNameModal, Layout, PageWrapper} from '@subwallet/extension-koni-ui/components'; import { AddressInput } from '@subwallet/extension-koni-ui/components/Field/AddressInput'; import CloseIcon from '@subwallet/extension-koni-ui/components/Icon/CloseIcon'; -import { ATTACH_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants/modal'; +import {ACCOUNT_NAME_MODAL, ATTACH_ACCOUNT_MODAL} from '@subwallet/extension-koni-ui/constants/modal'; import useCompleteCreateAccount from '@subwallet/extension-koni-ui/hooks/account/useCompleteCreateAccount'; import useGetDefaultAccountName from '@subwallet/extension-koni-ui/hooks/account/useGetDefaultAccountName'; import useGoBackFromCreateAccount from '@subwallet/extension-koni-ui/hooks/account/useGoBackFromCreateAccount'; @@ -16,14 +16,15 @@ import { RootState } from '@subwallet/extension-koni-ui/stores'; import { ThemeProps } from '@subwallet/extension-koni-ui/types'; import { convertFieldToObject, simpleCheckForm } from '@subwallet/extension-koni-ui/utils/form/form'; import { readOnlyScan } from '@subwallet/extension-koni-ui/utils/scanner/attach'; -import { Form, Icon, PageIcon } from '@subwallet/react-ui'; +import {Form, Icon, ModalContext, PageIcon} from '@subwallet/react-ui'; import CN from 'classnames'; import { Eye } from 'phosphor-react'; import { Callbacks, FieldData, RuleObject } from 'rc-field-form/lib/interface'; -import React, { useCallback, useState } from 'react'; +import React, {useCallback, useContext, useState} from 'react'; import { useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; import styled from 'styled-components'; +import {AccountProxyType} from "@subwallet/extension-base/types"; type Props = ThemeProps; @@ -47,7 +48,7 @@ const Component: React.FC = ({ className }: Props) => { const { t } = useTranslation(); const { goHome } = useDefaultNavigate(); - + const { activeModal, inactiveModal } = useContext(ModalContext); const onComplete = useCompleteCreateAccount(); const accountName = useGetDefaultAccountName(); @@ -59,7 +60,6 @@ const Component: React.FC = ({ className }: Props) => { const [reformatAddress, setReformatAddress] = useState(''); const [loading, setLoading] = useState(false); - const [isEthereum, setIsEthereum] = useState(false); const [isDisable, setIsDisable] = useState(true); const handleResult = useCallback((val: string) => { @@ -67,7 +67,6 @@ const Component: React.FC = ({ className }: Props) => { if (result) { setReformatAddress(result.content); - setIsEthereum(result.isEthereum); } }, []); @@ -107,34 +106,36 @@ const Component: React.FC = ({ className }: Props) => { }, [accounts, t]); const onSubmit = useCallback(() => { - setLoading(true); - if (reformatAddress) { - createAccountExternalV2({ - name: accountName, - address: reformatAddress, - genesisHash: '', - isEthereum: isEthereum, - isAllowed: true, - isReadOnly: true - }) - .then((errors) => { - if (errors.length) { - form.setFields([{ name: fieldName, errors: errors.map((e) => e.message) }]); - } else { - onComplete(); - } - }) - .catch((error: Error) => { - form.setFields([{ name: fieldName, errors: [error.message] }]); - }) - .finally(() => { - setLoading(false); - }); - } else { - setLoading(false); + activeModal(ACCOUNT_NAME_MODAL); } - }, [form, reformatAddress, accountName, isEthereum, onComplete]); + }, [activeModal, reformatAddress]); + + + const onSubmitFinal = useCallback((name: string) => { + setLoading(true); + createAccountExternalV2({ + name: name, + address: reformatAddress, + genesisHash: '', + isAllowed: true, + isReadOnly: true + }) + .then((errors) => { + if (errors.length) { + form.setFields([{ name: fieldName, errors: errors.map((e) => e.message) }]); + } else { + onComplete(); + } + }) + .catch((error: Error) => { + form.setFields([{ name: fieldName, errors: [error.message] }]); + }) + .finally(() => { + inactiveModal(ACCOUNT_NAME_MODAL); + setLoading(false); + }); + }, [form, reformatAddress, accountName, onComplete, inactiveModal]); useFocusById(modalId); @@ -198,6 +199,12 @@ const Component: React.FC = ({ className }: Props) => { + + ); diff --git a/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx b/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx index 091c88c4d6..dd9fd91619 100644 --- a/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx @@ -51,7 +51,6 @@ const Component: React.FC = ({ className }: Props) => { const [loading, setLoading] = useState(false); const [show, setShow] = useState(false); const [changed, setChanged] = useState(false); - const [ privatekeySubmit, setPrivateKeySubmit ] = useState(''); const { activeModal, inactiveModal } = useContext(ModalContext); const [form] = Form.useForm(); const checkUnlock = useUnlockChecker(); @@ -67,20 +66,22 @@ const Component: React.FC = ({ className }: Props) => { const { [fieldName]: privateKey } = values; checkUnlock().then(() => { - setPrivateKeySubmit(privateKey); + if(privateKey?.trim()){ + activeModal(ACCOUNT_NAME_MODAL); + } }) .catch(() => { // User cancel unlock }); - }, [accountName, checkUnlock, onComplete]); + }, [accountName, checkUnlock, onComplete, activeModal]); const onSubmitFinal = useCallback((name : string) => { - if (privatekeySubmit?.trim()) { + if (privateKey?.trim()) { setLoading(true); createAccountSuriV2({ name: name, - suri: privatekeySubmit.trim(), + suri: privateKey.trim(), isAllowed: true }) .then(() => { @@ -97,7 +98,7 @@ const Component: React.FC = ({ className }: Props) => { setLoading(false); }); } - }, [privatekeySubmit, onComplete]) + }, [privateKey, onComplete]) useEffect(() => { let amount = true; @@ -154,11 +155,6 @@ const Component: React.FC = ({ className }: Props) => { }; }, [privateKey, form, changed, t]); - useEffect(() => { - if(privatekeySubmit.trim()){ - activeModal(ACCOUNT_NAME_MODAL); - } - }, [activeModal, privatekeySubmit]); const onValuesChange: FormCallbacks['onValuesChange'] = useCallback((changedValues: Partial) => { if (fieldName in changedValues) { diff --git a/packages/extension-koni-ui/src/Popup/Account/ImportSeedPhrase.tsx b/packages/extension-koni-ui/src/Popup/Account/ImportSeedPhrase.tsx index fcb8e3085f..f8bdc99022 100644 --- a/packages/extension-koni-ui/src/Popup/Account/ImportSeedPhrase.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/ImportSeedPhrase.tsx @@ -28,7 +28,7 @@ const FooterIcon = ( const formName = 'import-seed-phrase-form'; const fieldNamePrefix = 'seed-phrase-'; -const accountNameModalId = 'seedPhrase.' + ACCOUNT_NAME_MODAL +const accountNameModalId = ACCOUNT_NAME_MODAL; interface FormState extends Record<`seed-phrase-${number}`, string> { phraseNumber: string; diff --git a/packages/extension-koni-ui/src/Popup/Account/NewSeedPhrase.tsx b/packages/extension-koni-ui/src/Popup/Account/NewSeedPhrase.tsx index d929b0f259..de901257f3 100644 --- a/packages/extension-koni-ui/src/Popup/Account/NewSeedPhrase.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/NewSeedPhrase.tsx @@ -28,7 +28,7 @@ const FooterIcon = ( /> ); -const accountNameModalId = 'seedPhrase.' + ACCOUNT_NAME_MODAL +const accountNameModalId = ACCOUNT_NAME_MODAL; const Component: React.FC = ({ className }: Props) => { useAutoNavigateToCreatePassword(); From c5a76bcc4d1d1bc75ede2a371b9547992ee105cb Mon Sep 17 00:00:00 2001 From: Thiendekaco Date: Sat, 17 Aug 2024 18:58:47 +0700 Subject: [PATCH 111/424] [Issue 3457] [update] Extension - update add account name step when add account qr scan --- .../Popup/Account/ConnectQrSigner/index.tsx | 98 ++++++++++++------- 1 file changed, 61 insertions(+), 37 deletions(-) diff --git a/packages/extension-koni-ui/src/Popup/Account/ConnectQrSigner/index.tsx b/packages/extension-koni-ui/src/Popup/Account/ConnectQrSigner/index.tsx index dd27725e39..e76d19f8cc 100644 --- a/packages/extension-koni-ui/src/Popup/Account/ConnectQrSigner/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/ConnectQrSigner/index.tsx @@ -2,11 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 import { detectTranslate } from '@subwallet/extension-base/utils'; -import { Layout, PageWrapper } from '@subwallet/extension-koni-ui/components'; +import {AccountNameModal, Layout, PageWrapper} from '@subwallet/extension-koni-ui/components'; import CloseIcon from '@subwallet/extension-koni-ui/components/Icon/CloseIcon'; import DualLogo from '@subwallet/extension-koni-ui/components/Logo/DualLogo'; import QrScannerErrorNotice from '@subwallet/extension-koni-ui/components/Qr/Scanner/ErrorNotice'; -import { ATTACH_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants/modal'; +import {ACCOUNT_NAME_MODAL, ATTACH_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants/modal'; import useCompleteCreateAccount from '@subwallet/extension-koni-ui/hooks/account/useCompleteCreateAccount'; import useGetDefaultAccountName from '@subwallet/extension-koni-ui/hooks/account/useGetDefaultAccountName'; import useGoBackFromCreateAccount from '@subwallet/extension-koni-ui/hooks/account/useGoBackFromCreateAccount'; @@ -20,11 +20,12 @@ import { qrSignerScan } from '@subwallet/extension-koni-ui/utils/scanner/attach' import { Icon, Image, ModalContext, SwQrScanner } from '@subwallet/react-ui'; import CN from 'classnames'; import { QrCode, XCircle } from 'phosphor-react'; -import React, { useCallback, useContext, useState } from 'react'; +import React, { useCallback, useContext, useEffect, useState } from 'react'; import { Trans, useTranslation } from 'react-i18next'; import styled from 'styled-components'; import DefaultLogosMap from '../../../assets/logo'; +import {AccountProxyType} from "@subwallet/extension-base/types"; const FooterIcon = ( = (props: Props) => { const onBack = useGoBackFromCreateAccount(ATTACH_ACCOUNT_MODAL); const accountName = useGetDefaultAccountName(); - const { inactiveModal } = useContext(ModalContext); + const { activeModal, inactiveModal } = useContext(ModalContext); const [validateState, setValidateState] = useState({}); const [loading, setLoading] = useState(false); + const [ accountScanned, setAccountScanned ] = useState(); const onSubmit = useCallback((account: QrAccount) => { - setLoading(true); inactiveModal(modalId); - setValidateState({ - message: '', - status: 'validating' - }); - - setTimeout(() => { - createAccountExternalV2({ - name: accountName, - address: account.content, - genesisHash: '', - isEthereum: account.isEthereum, - isAllowed: true, - isReadOnly: false - }) - .then((errors) => { - if (errors.length) { + setAccountScanned(account); + }, []); + + const onSubmitFinal = useCallback((name: string) => { + if(accountScanned) { + setLoading(true); + setValidateState({ + message: '', + status: 'validating' + }); + + setTimeout(() => { + createAccountExternalV2({ + name: accountName, + address: accountScanned.content, + genesisHash: '', + isAllowed: true, + isReadOnly: false + }) + .then((errors) => { + if (errors.length) { + setValidateState({ + message: errors[0].message, + status: 'error' + }); + } else { + setValidateState({}); + onComplete(); + } + }) + .catch((error: Error) => { setValidateState({ - message: errors[0].message, + message: error.message, status: 'error' }); - } else { - setValidateState({}); - onComplete(); - } - }) - .catch((error: Error) => { - setValidateState({ - message: error.message, - status: 'error' + }) + .finally(() => { + setLoading(false); + inactiveModal(ACCOUNT_NAME_MODAL) }); - }) - .finally(() => { - setLoading(false); - }); - }, 300); - }, [accountName, onComplete, inactiveModal]); + }, 300); + } + + }, [accountScanned, inactiveModal]) + + useEffect(() => { + if(accountScanned) { + activeModal(ACCOUNT_NAME_MODAL); + } + + }, [accountScanned, activeModal]) + + const { onClose, onError, onSuccess, openCamera } = useScanAccountQr(modalId, qrSignerScan, setValidateState, onSubmit); @@ -180,6 +198,12 @@ const Component: React.FC = (props: Props) => { overlay={validateState.message && ()} /> + + ); From 57345c4192c3bfea7c04e4b66a0ce8ab91cdda5e Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Sat, 17 Aug 2024 19:19:44 +0700 Subject: [PATCH 112/424] [Issue-3450] fix: fix minor bugs --- .../src/koni/background/handlers/Extension.ts | 46 +------------------ .../src/services/chain-service/types.ts | 2 +- 2 files changed, 2 insertions(+), 46 deletions(-) diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index da6ee08beb..197a6089b2 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -1786,7 +1786,7 @@ export default class KoniExtension { this.cancelSubscription(id); }); - return this.#koniState.getConfirmationsQueueSubject().getValue(); + return this.#koniState.getConfirmationsQueueSubjectTon().getValue(); } private async completeConfirmation (request: RequestConfirmationComplete) { @@ -2454,50 +2454,6 @@ export default class KoniExtension { return true; } - // alibaba - // @ts-ignore - // private async signingTon ({ id }: RequestSigningApprovePasswordV2): Promise { - // const queued = this.#koniState.getSignRequest(id); - // - // assert(queued, t('Unable to proceed. Please try again')); - // - // const { reject, request, resolve } = queued; - // const pair = keyring.getPair(queued.account.address); - // - // // unlike queued.account.address the following - // // address is encoded with the default prefix - // // which what is used for password caching mapping - // const { address } = pair; - // - // if (!pair) { - // reject(new Error(t('Unable to find account'))); - // - // return false; - // } - // - // if (pair.isLocked) { - // keyring.unlockPair(address); - // } - // - // const { payload } = request; - // const data = payload as unknown as Cell; - // - // const rs = pair.ton.sign(data); - // - // const result = request.sign(registry as unknown as TypeRegistry, pair); - // - // resolve({ - // id, - // signature: result.signature - // }); - // - // if (this.#alwaysLock) { - // this.keyringLock(); - // } - // - // return true; - // } - /// Derive account private derivationCreateMultiple (request: RequestDeriveCreateMultiple): boolean { diff --git a/packages/extension-base/src/services/chain-service/types.ts b/packages/extension-base/src/services/chain-service/types.ts index e23adbef71..cc651fc584 100644 --- a/packages/extension-base/src/services/chain-service/types.ts +++ b/packages/extension-base/src/services/chain-service/types.ts @@ -6,6 +6,7 @@ import type { ApiInterfaceRx } from '@polkadot/api/types'; import { _AssetRef, _AssetType, _ChainAsset, _ChainInfo, _CrowdloanFund } from '@subwallet/chain-list/types'; +import { TxByMsgResponse } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/types'; import { _CHAIN_VALIDATION_ERROR } from '@subwallet/extension-base/services/chain-service/handler/types'; import { Cell } from '@ton/core'; import { Address, Contract, OpenedContract } from '@ton/ton'; @@ -17,7 +18,6 @@ import { Getters } from '@polkadot/api/base/Getters'; import { SubmittableExtrinsicFunction } from '@polkadot/api/promise/types'; import { ChainProperties, ChainType, RuntimeVersion } from '@polkadot/types/interfaces'; import { AnyJson, Registry } from '@polkadot/types/types'; -import {TxByMsgResponse} from "@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/types"; export interface _DataMap { chainInfoMap: Record, From 6ccd89a088b6a13e32096dcfdcebab0f24cc3d40 Mon Sep 17 00:00:00 2001 From: Thiendekaco Date: Sat, 17 Aug 2024 19:18:22 +0700 Subject: [PATCH 113/424] [Issue 3457] [update] Extension - update ui for detail account --- .../Popup/Account/AccountDetail/AccountAddressList.tsx | 9 ++++++--- .../Popup/Account/AccountDetail/DerivedAccountList.tsx | 8 ++++++-- .../AccountProxy/AccountNetworkAddressItem.tsx | 9 ++++++++- .../src/components/Modal/Account/DeriveAccountModal.tsx | 2 +- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx index 738a421840..eac8528a25 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx @@ -16,6 +16,8 @@ type Props = ThemeProps & { accountProxy: AccountProxy; }; +const isHide = false; + function Component ({ accountProxy, className }: Props) { const { t } = useTranslation(); const items: AccountNetworkAddress[] = useGetAccountNetworkAddresses(accountProxy); @@ -47,6 +49,7 @@ function Component ({ accountProxy, className }: Props) { className={'address-item'} item={item} key={item.slug} + onClick={onShowQr(item)} onClickCopyButton={onCopyAddress(item)} onClickQrButton={onShowQr(item)} /> @@ -61,7 +64,7 @@ function Component ({ accountProxy, className }: Props) { const searchFunction = useCallback( (item: AccountNetworkAddress, searchText: string) => { - return item.name.toLowerCase().includes(searchText.toLowerCase()); + return item.name.toLowerCase().includes(searchText.toLowerCase()) || item.address.toLowerCase().includes(searchText.toLowerCase()); }, [] ); @@ -75,11 +78,11 @@ function Component ({ accountProxy, className }: Props) { renderWhenEmpty={emptyList} searchFunction={searchFunction} searchMinCharactersCount={2} - searchPlaceholder={t('Enter network name')} + searchPlaceholder={t('Enter network name or address ')} /> { - accountProxy.accountType === AccountProxyType.SOLO && ( + isHide && accountProxy.accountType === AccountProxyType.SOLO && (
); diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountNetworkAddressItem.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountNetworkAddressItem.tsx index 761989fa85..b1ca339b67 100644 --- a/packages/extension-koni-ui/src/components/AccountProxy/AccountNetworkAddressItem.tsx +++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountNetworkAddressItem.tsx @@ -11,6 +11,7 @@ import styled from 'styled-components'; type Props = ThemeProps & { item: AccountNetworkAddress; + onClick?: VoidFunction; onClickCopyButton?: VoidFunction; onClickQrButton?: VoidFunction; } @@ -18,7 +19,7 @@ type Props = ThemeProps & { function Component (props: Props): React.ReactElement { const { className, item, - onClickCopyButton, onClickQrButton } = props; + onClickCopyButton, onClickQrButton, onClick } = props; const _onClickCopyButton: React.MouseEventHandler = React.useCallback((event) => { event.stopPropagation(); @@ -30,10 +31,16 @@ function Component (props: Props): React.ReactElement { onClickQrButton?.(); }, [onClickQrButton]); + const _onClickButton: React.MouseEventHandler = React.useCallback((event) => { + event.stopPropagation(); + onClick?.(); + }, [onClickQrButton]); + return ( <>
(({ theme: { token } }: Props }, '.account-derive-item': { - display: 'flex !important' + display: 'flex' } }; }); From 9083e75955c99b202d7fd879e61d7af79a52a730 Mon Sep 17 00:00:00 2001 From: S2kael Date: Sat, 17 Aug 2024 19:51:40 +0700 Subject: [PATCH 114/424] [Issue-3462] [Earning] Add `proxyId` to account info --- packages/extension-base/src/types/account/info/keyring.ts | 1 + packages/extension-base/src/utils/account/transform.ts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/packages/extension-base/src/types/account/info/keyring.ts b/packages/extension-base/src/types/account/info/keyring.ts index f179fab6ec..002c1dd46b 100644 --- a/packages/extension-base/src/types/account/info/keyring.ts +++ b/packages/extension-base/src/types/account/info/keyring.ts @@ -143,6 +143,7 @@ export interface AccountActionData { signMode: AccountSignMode; specialNetwork?: string; tokenTypes: _AssetType[]; + proxyId?: string; } /** diff --git a/packages/extension-base/src/utils/account/transform.ts b/packages/extension-base/src/utils/account/transform.ts index 9137eb9657..019937a867 100644 --- a/packages/extension-base/src/utils/account/transform.ts +++ b/packages/extension-base/src/utils/account/transform.ts @@ -393,6 +393,8 @@ export const combineAccounts = (pairs: SubjectInfo, modifyPairs: ModifyPairStore temp[accountGroup.id] = { ...accountGroup, accounts: [], networkTypes: [], tokenTypes: [] }; } + account.proxyId = accountGroup.id; + temp[accountGroup.id].accounts.push(account); continue; } From a5c014d0579c685afe1bec91c917643173adc6b8 Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Mon, 19 Aug 2024 11:15:28 +0700 Subject: [PATCH 115/424] [Issue-3449] add comments for readability --- .../services/balance-service/helpers/subscribe/ton/utils.ts | 6 +++--- .../src/services/chain-service/handler/TonApi.ts | 5 ++--- .../src/services/transaction-service/index.ts | 3 +-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts index fafa464f1f..19b4744b7d 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts @@ -32,7 +32,7 @@ export function externalMessage (contract: WalletContractV4, seqno: number, body storeMessage( external({ to: contract.address, - init: seqno === 0 ? contract.init : undefined, + init: seqno === 0 ? contract.init : undefined, // contract init for first transaction. body: body }) ) @@ -51,11 +51,11 @@ export async function retry (fn: () => Promise, options: { retries: number lastError = e; } - await new Promise((resolve) => setTimeout(resolve, options.delay)); + await new Promise((resolve) => setTimeout(resolve, options.delay)); // wait for delay period, then recall the fn() } } - throw lastError; + throw lastError; // throw only last error, in case no successful result from fn() } export function getMessageTxStatus (txByMsgInfo: TxByMsgResponse) { diff --git a/packages/extension-base/src/services/chain-service/handler/TonApi.ts b/packages/extension-base/src/services/chain-service/handler/TonApi.ts index faf3305950..df76e66e52 100644 --- a/packages/extension-base/src/services/chain-service/handler/TonApi.ts +++ b/packages/extension-base/src/services/chain-service/handler/TonApi.ts @@ -191,9 +191,8 @@ export class TonApi implements _TonApi { return await resp.json() as TxByMsgResponse; } - async getStatusByExtMsgHash (extMsgHash: string): Promise<[boolean, string]> { // noted: can move this function to utils file for more flexible uses - return retry(async () => { - // get external msg transaction and transaction hex + async getStatusByExtMsgHash (extMsgHash: string): Promise<[boolean, string]> { + return retry<[boolean, string]>(async () => { // retry many times to get transaction status and transaction hex const externalTxInfoRaw = await this.getTxByInMsg(extMsgHash); const externalTxInfo = externalTxInfoRaw.transactions[0]; const isExternalTxCompute = externalTxInfo.description.compute_ph.success; diff --git a/packages/extension-base/src/services/transaction-service/index.ts b/packages/extension-base/src/services/transaction-service/index.ts index b3b34c18b5..c10959ba49 100644 --- a/packages/extension-base/src/services/transaction-service/index.ts +++ b/packages/extension-base/src/services/transaction-service/index.ts @@ -1169,14 +1169,13 @@ export default class TransactionService { const signer = (message: Cell): Promise => { return new Promise((resolve) => { this.state.requestService.addConfirmationTon(id, url || EXTENSION_REQUEST_URL, 'tonSendTransactionRequest', { ...payload, messagePayload: cellToBase64Str(message), messages: [] }, {}) - .then(async ({ isApproved, payload }) => { + .then(({ isApproved, payload }) => { if (payload) { resolve(Buffer.from(hexToU8a(payload))); } }); }); }; - // --// const tonTransactionConfig = transaction as TonTransactionConfig; const seqno = tonTransactionConfig.seqno; From 1fce9e32d6a4f6ebba7fba7fd7abe7ce75a552a3 Mon Sep 17 00:00:00 2001 From: Thiendekaco Date: Mon, 19 Aug 2024 11:39:14 +0700 Subject: [PATCH 116/424] [Issue 3457] [update] Extension - In account details, add a warning flow for TON accounts --- .../AccountDetail/AccountAddressList.tsx | 14 ++-- .../AccountDetail/DerivedAccountList.tsx | 6 +- .../src/Popup/Account/AccountExport.tsx | 2 +- .../src/Popup/Account/AttachReadOnly.tsx | 17 ++-- .../src/Popup/Account/ConnectLedger.tsx | 2 +- .../Popup/Account/ConnectQrSigner/index.tsx | 26 +++--- .../src/Popup/Account/ImportPrivateKey.tsx | 34 +++----- .../src/Popup/Account/ImportSeedPhrase.tsx | 3 +- .../AccountNetworkAddressItem.tsx | 4 +- .../SelectAccount/AccountSelectorModal.tsx | 2 +- .../Layout/parts/SelectAccount/index.tsx | 9 +-- .../Modal/Account/AccountNameModal.tsx | 2 +- .../Modal/Account/DeriveAccountModal.tsx | 81 +++++++++---------- .../src/components/Search/index.tsx | 2 +- .../account/useGetAccountNetworkAddresses.tsx | 3 +- .../src/hooks/screen/account/index.tsx | 4 + .../account/useGetAccountAddressDetail.tsx | 81 +++++++++++++++++++ .../screen/home/useReceiveModalHelper.tsx | 2 +- .../src/hooks/screen/index.ts | 1 + .../extension-koni-ui/src/types/account.ts | 1 + 20 files changed, 179 insertions(+), 117 deletions(-) create mode 100644 packages/extension-koni-ui/src/hooks/screen/account/index.tsx create mode 100644 packages/extension-koni-ui/src/hooks/screen/account/useGetAccountAddressDetail.tsx diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx index eac8528a25..486956de3a 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx @@ -3,13 +3,12 @@ import { AccountProxy, AccountProxyType } from '@subwallet/extension-base/types'; import { AccountNetworkAddressItem, GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; -import { WalletModalContext } from '@subwallet/extension-koni-ui/contexts/WalletModalContextProvider'; -import { useGetAccountNetworkAddresses, useNotification, useTranslation } from '@subwallet/extension-koni-ui/hooks'; +import { useGetAccountAddressDetail, useGetAccountNetworkAddresses, useNotification, useTranslation } from '@subwallet/extension-koni-ui/hooks'; import { AccountNetworkAddress, ThemeProps } from '@subwallet/extension-koni-ui/types'; import { copyToClipboard } from '@subwallet/extension-koni-ui/utils'; import { Button, Icon, SwList } from '@subwallet/react-ui'; import { Strategy } from 'phosphor-react'; -import React, { useCallback, useContext } from 'react'; +import React, { useCallback } from 'react'; import styled from 'styled-components'; type Props = ThemeProps & { @@ -22,16 +21,13 @@ function Component ({ accountProxy, className }: Props) { const { t } = useTranslation(); const items: AccountNetworkAddress[] = useGetAccountNetworkAddresses(accountProxy); const notify = useNotification(); - const { addressQrModal } = useContext(WalletModalContext); + const { onSelectAccountSelector } = useGetAccountAddressDetail(); const onShowQr = useCallback((item: AccountNetworkAddress) => { return () => { - addressQrModal.open({ - address: item.address, - chainSlug: item.slug - }); + onSelectAccountSelector(item); }; - }, [addressQrModal]); + }, [onSelectAccountSelector]); const onCopyAddress = useCallback((item: AccountNetworkAddress) => { return () => { diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/DerivedAccountList.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/DerivedAccountList.tsx index 6d3f77e2cf..4b549e900f 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/DerivedAccountList.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/DerivedAccountList.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import {AccountProxy} from '@subwallet/extension-base/types'; +import { AccountProxy } from '@subwallet/extension-base/types'; import { AccountProxySelectorItem, GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; import { useTranslation } from '@subwallet/extension-koni-ui/hooks'; import { RootState } from '@subwallet/extension-koni-ui/stores'; @@ -57,8 +57,8 @@ function Component ({ accountProxy, className }: Props) { const searchFunction = useCallback( (item: AccountProxy, searchText: string) => { - if(item.accounts.length === 1){ - return item.name.toLowerCase().includes(searchText.toLowerCase()) || item.accounts[0].address.toLowerCase().includes(searchText.toLowerCase()); + if (item.accounts.length === 1) { + return item.name.toLowerCase().includes(searchText.toLowerCase()) || item.accounts[0].address.toLowerCase().includes(searchText.toLowerCase()); } return item.name.toLowerCase().includes(searchText.toLowerCase()); diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountExport.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountExport.tsx index e3470c6be6..00fbdc15a4 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AccountExport.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AccountExport.tsx @@ -113,7 +113,7 @@ const Component: React.FC = (props: Props) => { } return result.join(':'); - }, [account?.name, publicKey, privateKey]); + }, [account?.name, privateKey, publicKey]); const onCopyPrivateKey = useCopy(privateKey); diff --git a/packages/extension-koni-ui/src/Popup/Account/AttachReadOnly.tsx b/packages/extension-koni-ui/src/Popup/Account/AttachReadOnly.tsx index 3b7713e3c6..d966887b4c 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AttachReadOnly.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AttachReadOnly.tsx @@ -1,12 +1,12 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import {AccountNameModal, Layout, PageWrapper} from '@subwallet/extension-koni-ui/components'; +import { AccountProxyType } from '@subwallet/extension-base/types'; +import { AccountNameModal, Layout, PageWrapper } from '@subwallet/extension-koni-ui/components'; import { AddressInput } from '@subwallet/extension-koni-ui/components/Field/AddressInput'; import CloseIcon from '@subwallet/extension-koni-ui/components/Icon/CloseIcon'; -import {ACCOUNT_NAME_MODAL, ATTACH_ACCOUNT_MODAL} from '@subwallet/extension-koni-ui/constants/modal'; +import { ACCOUNT_NAME_MODAL, ATTACH_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants/modal'; import useCompleteCreateAccount from '@subwallet/extension-koni-ui/hooks/account/useCompleteCreateAccount'; -import useGetDefaultAccountName from '@subwallet/extension-koni-ui/hooks/account/useGetDefaultAccountName'; import useGoBackFromCreateAccount from '@subwallet/extension-koni-ui/hooks/account/useGoBackFromCreateAccount'; import useFocusById from '@subwallet/extension-koni-ui/hooks/form/useFocusById'; import useAutoNavigateToCreatePassword from '@subwallet/extension-koni-ui/hooks/router/useAutoNavigateToCreatePassword'; @@ -16,15 +16,14 @@ import { RootState } from '@subwallet/extension-koni-ui/stores'; import { ThemeProps } from '@subwallet/extension-koni-ui/types'; import { convertFieldToObject, simpleCheckForm } from '@subwallet/extension-koni-ui/utils/form/form'; import { readOnlyScan } from '@subwallet/extension-koni-ui/utils/scanner/attach'; -import {Form, Icon, ModalContext, PageIcon} from '@subwallet/react-ui'; +import { Form, Icon, ModalContext, PageIcon } from '@subwallet/react-ui'; import CN from 'classnames'; import { Eye } from 'phosphor-react'; import { Callbacks, FieldData, RuleObject } from 'rc-field-form/lib/interface'; -import React, {useCallback, useContext, useState} from 'react'; +import React, { useCallback, useContext, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; import styled from 'styled-components'; -import {AccountProxyType} from "@subwallet/extension-base/types"; type Props = ThemeProps; @@ -50,7 +49,6 @@ const Component: React.FC = ({ className }: Props) => { const { goHome } = useDefaultNavigate(); const { activeModal, inactiveModal } = useContext(ModalContext); const onComplete = useCompleteCreateAccount(); - const accountName = useGetDefaultAccountName(); const accounts = useSelector((root: RootState) => root.accountState.accounts); @@ -111,7 +109,6 @@ const Component: React.FC = ({ className }: Props) => { } }, [activeModal, reformatAddress]); - const onSubmitFinal = useCallback((name: string) => { setLoading(true); createAccountExternalV2({ @@ -135,7 +132,7 @@ const Component: React.FC = ({ className }: Props) => { inactiveModal(ACCOUNT_NAME_MODAL); setLoading(false); }); - }, [form, reformatAddress, accountName, onComplete, inactiveModal]); + }, [form, reformatAddress, onComplete, inactiveModal]); useFocusById(modalId); @@ -201,9 +198,9 @@ const Component: React.FC = ({ className }: Props) => {
diff --git a/packages/extension-koni-ui/src/Popup/Account/ConnectLedger.tsx b/packages/extension-koni-ui/src/Popup/Account/ConnectLedger.tsx index 3101a8dc5d..c243ae90c7 100644 --- a/packages/extension-koni-ui/src/Popup/Account/ConnectLedger.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/ConnectLedger.tsx @@ -307,6 +307,7 @@ const Component: React.FC = (props: Props) => { <>
= (props: Props) => { width={52} /> )} - innerSize={52} sizeLinkIcon={36} sizeSquircleBorder={108} /> diff --git a/packages/extension-koni-ui/src/Popup/Account/ConnectQrSigner/index.tsx b/packages/extension-koni-ui/src/Popup/Account/ConnectQrSigner/index.tsx index e76d19f8cc..ab591b2be4 100644 --- a/packages/extension-koni-ui/src/Popup/Account/ConnectQrSigner/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/ConnectQrSigner/index.tsx @@ -1,12 +1,13 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 +import { AccountProxyType } from '@subwallet/extension-base/types'; import { detectTranslate } from '@subwallet/extension-base/utils'; -import {AccountNameModal, Layout, PageWrapper} from '@subwallet/extension-koni-ui/components'; +import { AccountNameModal, Layout, PageWrapper } from '@subwallet/extension-koni-ui/components'; import CloseIcon from '@subwallet/extension-koni-ui/components/Icon/CloseIcon'; import DualLogo from '@subwallet/extension-koni-ui/components/Logo/DualLogo'; import QrScannerErrorNotice from '@subwallet/extension-koni-ui/components/Qr/Scanner/ErrorNotice'; -import {ACCOUNT_NAME_MODAL, ATTACH_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants/modal'; +import { ACCOUNT_NAME_MODAL, ATTACH_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants/modal'; import useCompleteCreateAccount from '@subwallet/extension-koni-ui/hooks/account/useCompleteCreateAccount'; import useGetDefaultAccountName from '@subwallet/extension-koni-ui/hooks/account/useGetDefaultAccountName'; import useGoBackFromCreateAccount from '@subwallet/extension-koni-ui/hooks/account/useGoBackFromCreateAccount'; @@ -25,7 +26,6 @@ import { Trans, useTranslation } from 'react-i18next'; import styled from 'styled-components'; import DefaultLogosMap from '../../../assets/logo'; -import {AccountProxyType} from "@subwallet/extension-base/types"; const FooterIcon = ( = (props: Props) => { const [validateState, setValidateState] = useState({}); const [loading, setLoading] = useState(false); - const [ accountScanned, setAccountScanned ] = useState(); + const [accountScanned, setAccountScanned] = useState(); const onSubmit = useCallback((account: QrAccount) => { inactiveModal(modalId); setAccountScanned(account); - }, []); + }, [inactiveModal]); const onSubmitFinal = useCallback((name: string) => { - if(accountScanned) { + if (accountScanned) { setLoading(true); setValidateState({ message: '', @@ -101,21 +101,17 @@ const Component: React.FC = (props: Props) => { }) .finally(() => { setLoading(false); - inactiveModal(ACCOUNT_NAME_MODAL) + inactiveModal(ACCOUNT_NAME_MODAL); }); }, 300); } - - }, [accountScanned, inactiveModal]) + }, [accountName, accountScanned, inactiveModal, onComplete]); useEffect(() => { - if(accountScanned) { + if (accountScanned) { activeModal(ACCOUNT_NAME_MODAL); } - - }, [accountScanned, activeModal]) - - + }, [accountScanned, activeModal]); const { onClose, onError, onSuccess, openCamera } = useScanAccountQr(modalId, qrSignerScan, setValidateState, onSubmit); @@ -200,9 +196,9 @@ const Component: React.FC = (props: Props) => {
diff --git a/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx b/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx index dd9fd91619..cbacc35d0a 100644 --- a/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx @@ -1,23 +1,17 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { - AccountNameModal, - CloseIcon, - Layout, - PageWrapper, - PrivateKeyInput -} from '@subwallet/extension-koni-ui/components'; -import {ACCOUNT_NAME_MODAL, IMPORT_ACCOUNT_MODAL} from '@subwallet/extension-koni-ui/constants/modal'; -import { useAutoNavigateToCreatePassword, useCompleteCreateAccount, useDefaultNavigate, useFocusFormItem, useGetDefaultAccountName, useGoBackFromCreateAccount, useTranslation, useUnlockChecker } from '@subwallet/extension-koni-ui/hooks'; +import { AccountProxyType } from '@subwallet/extension-base/types'; +import { AccountNameModal, CloseIcon, Layout, PageWrapper, PrivateKeyInput } from '@subwallet/extension-koni-ui/components'; +import { ACCOUNT_NAME_MODAL, IMPORT_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants/modal'; +import { useAutoNavigateToCreatePassword, useCompleteCreateAccount, useDefaultNavigate, useFocusFormItem, useGoBackFromCreateAccount, useTranslation, useUnlockChecker } from '@subwallet/extension-koni-ui/hooks'; import { createAccountSuriV2, validateMetamaskPrivateKeyV2 } from '@subwallet/extension-koni-ui/messaging'; import { FormCallbacks, ThemeProps, ValidateState } from '@subwallet/extension-koni-ui/types'; -import {Button, Form, Icon, ModalContext} from '@subwallet/react-ui'; +import { Button, Form, Icon, ModalContext } from '@subwallet/react-ui'; import CN from 'classnames'; import { Eye, EyeSlash, FileArrowDown } from 'phosphor-react'; -import React, {useCallback, useContext, useEffect, useRef, useState} from 'react'; +import React, { useCallback, useContext, useEffect, useRef, useState } from 'react'; import styled from 'styled-components'; -import {AccountProxyType} from "@subwallet/extension-base/types"; type Props = ThemeProps; @@ -55,8 +49,6 @@ const Component: React.FC = ({ className }: Props) => { const [form] = Form.useForm(); const checkUnlock = useUnlockChecker(); - const accountName = useGetDefaultAccountName(); - // Auto-focus field useFocusFormItem(form, fieldName); @@ -66,17 +58,16 @@ const Component: React.FC = ({ className }: Props) => { const { [fieldName]: privateKey } = values; checkUnlock().then(() => { - if(privateKey?.trim()){ + if (privateKey?.trim()) { activeModal(ACCOUNT_NAME_MODAL); } }) .catch(() => { // User cancel unlock }); - }, [accountName, checkUnlock, onComplete, activeModal]); - + }, [checkUnlock, activeModal]); - const onSubmitFinal = useCallback((name : string) => { + const onSubmitFinal = useCallback((name: string) => { if (privateKey?.trim()) { setLoading(true); createAccountSuriV2({ @@ -94,11 +85,11 @@ const Component: React.FC = ({ className }: Props) => { }); }) .finally(() => { - inactiveModal(ACCOUNT_NAME_MODAL) + inactiveModal(ACCOUNT_NAME_MODAL); setLoading(false); }); } - }, [privateKey, onComplete]) + }, [privateKey, onComplete, inactiveModal]); useEffect(() => { let amount = true; @@ -155,7 +146,6 @@ const Component: React.FC = ({ className }: Props) => { }; }, [privateKey, form, changed, t]); - const onValuesChange: FormCallbacks['onValuesChange'] = useCallback((changedValues: Partial) => { if (fieldName in changedValues) { setChanged(true); @@ -228,8 +218,8 @@ const Component: React.FC = ({ className }: Props) => {
diff --git a/packages/extension-koni-ui/src/Popup/Account/ImportSeedPhrase.tsx b/packages/extension-koni-ui/src/Popup/Account/ImportSeedPhrase.tsx index f8bdc99022..89b8f5d9b9 100644 --- a/packages/extension-koni-ui/src/Popup/Account/ImportSeedPhrase.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/ImportSeedPhrase.tsx @@ -28,7 +28,7 @@ const FooterIcon = ( const formName = 'import-seed-phrase-form'; const fieldNamePrefix = 'seed-phrase-'; -const accountNameModalId = ACCOUNT_NAME_MODAL; +const accountNameModalId = ACCOUNT_NAME_MODAL; interface FormState extends Record<`seed-phrase-${number}`, string> { phraseNumber: string; @@ -178,6 +178,7 @@ const Component: React.FC = ({ className }: Props) => { }) .catch((error: Error): void => { const message = error.message.includes('with this seed') ? t('Have already created account with this seed') : error.message; + setSeedValidationResponse(undefined); setSubmitting(false); notify({ diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountNetworkAddressItem.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountNetworkAddressItem.tsx index b1ca339b67..00b0e9a608 100644 --- a/packages/extension-koni-ui/src/components/AccountProxy/AccountNetworkAddressItem.tsx +++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountNetworkAddressItem.tsx @@ -19,7 +19,7 @@ type Props = ThemeProps & { function Component (props: Props): React.ReactElement { const { className, item, - onClickCopyButton, onClickQrButton, onClick } = props; + onClick, onClickCopyButton, onClickQrButton } = props; const _onClickCopyButton: React.MouseEventHandler = React.useCallback((event) => { event.stopPropagation(); @@ -34,7 +34,7 @@ function Component (props: Props): React.ReactElement { const _onClickButton: React.MouseEventHandler = React.useCallback((event) => { event.stopPropagation(); onClick?.(); - }, [onClickQrButton]); + }, [onClick]); return ( <> diff --git a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx index 86d053bec9..26ed90cc16 100644 --- a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx +++ b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx @@ -79,7 +79,7 @@ const accountNetworkAddressesModalId = ACCOUNT_NETWORK_ADDRESSES_MODAL; const Component: React.FC = ({ className }: Props) => { const location = useLocation(); const { t } = useTranslation(); - const { activeModal, inactiveModal} = useContext(ModalContext); + const { activeModal, inactiveModal } = useContext(ModalContext); const [searchValue, setSearchValue] = useState(''); const { token } = useTheme() as Theme; const { goHome } = useDefaultNavigate(); diff --git a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/index.tsx b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/index.tsx index 32b3b1aba3..2d5211d96b 100644 --- a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/index.tsx +++ b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/index.tsx @@ -5,18 +5,17 @@ import { AccountJson } from '@subwallet/extension-base/types'; import { AccountProxyBriefInfo } from '@subwallet/extension-koni-ui/components'; import { AccountSelectorModal } from '@subwallet/extension-koni-ui/components/Layout/parts/SelectAccount/AccountSelectorModal'; import { SELECT_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants'; -import { CaretDown } from 'phosphor-react'; import { useGetCurrentAuth, useGetCurrentTab, useIsPopup, useTranslation } from '@subwallet/extension-koni-ui/hooks'; import { RootState } from '@subwallet/extension-koni-ui/stores'; import { Theme } from '@subwallet/extension-koni-ui/themes'; import { ThemeProps } from '@subwallet/extension-koni-ui/types'; import { funcSortByName, isAccountAll } from '@subwallet/extension-koni-ui/utils'; -import {BackgroundIcon, Icon, ModalContext, Tooltip} from '@subwallet/react-ui'; +import { BackgroundIcon, Icon, ModalContext, Tooltip } from '@subwallet/react-ui'; import CN from 'classnames'; -import { Plug, Plugs, PlugsConnected } from 'phosphor-react'; +import { CaretDown, Plug, Plugs, PlugsConnected } from 'phosphor-react'; import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'; import { useSelector } from 'react-redux'; -import styled, {useTheme} from 'styled-components'; +import styled, { useTheme } from 'styled-components'; import { isEthereumAddress } from '@polkadot/util-crypto'; @@ -210,8 +209,8 @@ function Component ({ className }: Props): React.ReactElement { ); diff --git a/packages/extension-koni-ui/src/components/Modal/Account/AccountNameModal.tsx b/packages/extension-koni-ui/src/components/Modal/Account/AccountNameModal.tsx index 0a447dbf42..1edba2f2e2 100644 --- a/packages/extension-koni-ui/src/components/Modal/Account/AccountNameModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/Account/AccountNameModal.tsx @@ -23,7 +23,7 @@ interface FormProps { name: string; } -const Component: React.FC = ({ accountType, className, isLoading, onSubmit, modalId }: Props) => { +const Component: React.FC = ({ accountType, className, isLoading, modalId, onSubmit }: Props) => { const { t } = useTranslation(); const [form] = Form.useForm(); const defaultValues = useMemo(() => ({ diff --git a/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx b/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx index 56bf5a6ac4..e438a572ff 100644 --- a/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx @@ -1,13 +1,10 @@ // Copyright 2019-2022 @polkadot/extension-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import {AccountActions, AccountProxy} from '@subwallet/extension-base/types'; +import { AccountActions, AccountProxy } from '@subwallet/extension-base/types'; +import { AccountNameModal, AccountProxyItem } from '@subwallet/extension-koni-ui/components'; import BackIcon from '@subwallet/extension-koni-ui/components/Icon/BackIcon'; -import { - ACCOUNT_NAME_MODAL, - CREATE_ACCOUNT_MODAL, - DERIVE_ACCOUNT_MODAL -} from '@subwallet/extension-koni-ui/constants/modal'; +import { ACCOUNT_NAME_MODAL, CREATE_ACCOUNT_MODAL, DERIVE_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants/modal'; import { useSetSessionLatest } from '@subwallet/extension-koni-ui/hooks'; import useNotification from '@subwallet/extension-koni-ui/hooks/common/useNotification'; import useTranslation from '@subwallet/extension-koni-ui/hooks/common/useTranslation'; @@ -16,23 +13,22 @@ import useClickOutSide from '@subwallet/extension-koni-ui/hooks/dom/useClickOutS import useSwitchModal from '@subwallet/extension-koni-ui/hooks/modal/useSwitchModal'; import { deriveAccountV3 } from '@subwallet/extension-koni-ui/messaging'; import { RootState } from '@subwallet/extension-koni-ui/stores'; -import {Theme, ThemeProps} from '@subwallet/extension-koni-ui/types'; +import { ThemeProps } from '@subwallet/extension-koni-ui/types'; import { searchAccountFunction } from '@subwallet/extension-koni-ui/utils/account/account'; import { renderModalSelector } from '@subwallet/extension-koni-ui/utils/common/dom'; import { ActivityIndicator, ModalContext, SwList, SwModal } from '@subwallet/react-ui'; import { SwListSectionRef } from '@subwallet/react-ui/es/sw-list'; import CN from 'classnames'; -import React, {useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react'; +import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; import { useSelector } from 'react-redux'; -import styled, { useTheme } from 'styled-components'; +import styled from 'styled-components'; import { GeneralEmptyList } from '../../EmptyList'; -import {AccountNameModal, AccountProxyItem} from "@subwallet/extension-koni-ui/components"; type Props = ThemeProps; const modalId = DERIVE_ACCOUNT_MODAL; -const accountNameModalId = 'derive.' + ACCOUNT_NAME_MODAL +const accountNameModalId = 'derive.' + ACCOUNT_NAME_MODAL; const renderEmpty = () => ; const renderLoaderIcon = (x: React.ReactNode): React.ReactNode => { @@ -48,11 +44,10 @@ const renderLoaderIcon = (x: React.ReactNode): React.ReactNode => { const Component: React.FC = ({ className }: Props) => { const { t } = useTranslation(); - const { token } = useTheme() as Theme; const notify = useNotification(); const sectionRef = useRef(null); - const [accountSelected, setAccountSelected] = useState() - const { checkActive, inactiveModal, activeModal } = useContext(ModalContext); + const [accountSelected, setAccountSelected] = useState(); + const { activeModal, checkActive, inactiveModal } = useContext(ModalContext); const { setStateSelectAccount } = useSetSessionLatest(); const checkUnlock = useUnlockChecker(); @@ -88,38 +83,38 @@ const Component: React.FC = ({ className }: Props) => { // User cancel unlock }); }; - }, [checkUnlock, clearSearch, inactiveModal, notify, setStateSelectAccount]); + }, [checkUnlock]); const onSubmitAccount = useCallback((name: string) => { - if(accountSelected) { - setSelected(accountSelected.id); - setTimeout(() => { - deriveAccountV3({ - proxyId: accountSelected.id, - name, - suri: accountSelected.suri - }).then(() => { - inactiveModal(modalId); - setStateSelectAccount(true); - clearSearch(); - }).catch((e: Error) => { - notify({ - message: e.message, - type: 'error' - }); - }).finally(() => { - setSelected(''); - inactiveModal(accountNameModalId) + if (accountSelected) { + setSelected(accountSelected.id); + setTimeout(() => { + deriveAccountV3({ + proxyId: accountSelected.id, + name, + suri: accountSelected.suri + }).then(() => { + inactiveModal(modalId); + setStateSelectAccount(true); + clearSearch(); + }).catch((e: Error) => { + notify({ + message: e.message, + type: 'error' }); - }, 500); - } - }, [accountSelected]) + }).finally(() => { + setSelected(''); + inactiveModal(accountNameModalId); + }); + }, 500); + } + }, [accountSelected, clearSearch, inactiveModal, notify, setStateSelectAccount]); useEffect(() => { - if(accountSelected) { + if (accountSelected) { activeModal(accountNameModalId); } - }, [accountSelected, activeModal]) + }, [accountSelected, activeModal]); const renderItem = useCallback((account: AccountProxy): React.ReactNode => { const disabled = !!selected; @@ -131,12 +126,12 @@ const Component: React.FC = ({ className }: Props) => { accountProxy={account} className={CN({ disabled: disabled && !isSelected }, 'account-derive-item') } onClick={disabled ? undefined : onSelectAccount(account)} - showUnselectIcon={false} renderRightPart={isSelected ? renderLoaderIcon : undefined} + showUnselectIcon={false} /> ); - }, [onSelectAccount, selected, token.sizeLG]); + }, [onSelectAccount, selected]); const onBack = useSwitchModal(modalId, CREATE_ACCOUNT_MODAL, clearSearch); @@ -164,10 +159,10 @@ const Component: React.FC = ({ className }: Props) => {
diff --git a/packages/extension-koni-ui/src/components/Search/index.tsx b/packages/extension-koni-ui/src/components/Search/index.tsx index f9f2a883bb..9107899211 100644 --- a/packages/extension-koni-ui/src/components/Search/index.tsx +++ b/packages/extension-koni-ui/src/components/Search/index.tsx @@ -27,8 +27,8 @@ const Component: React.FC = ({ actionBtnIcon, showActionBtn }) => { const handleInputChange: ChangeEventHandler = useCallback((e) => { const value = e?.target?.value; - onSearch(value); + onSearch(value); }, [onSearch] ); diff --git a/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx b/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx index 834333c155..9c001ce274 100644 --- a/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx +++ b/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx @@ -26,7 +26,8 @@ const useGetAccountNetworkAddresses = (accountProxy: AccountProxy): AccountNetwo result.push({ name: chainInfo.name, slug: chainInfo.slug, - address: reformatedAddress + address: reformatedAddress, + accountType: a.type }); } } diff --git a/packages/extension-koni-ui/src/hooks/screen/account/index.tsx b/packages/extension-koni-ui/src/hooks/screen/account/index.tsx new file mode 100644 index 0000000000..26edc55c46 --- /dev/null +++ b/packages/extension-koni-ui/src/hooks/screen/account/index.tsx @@ -0,0 +1,4 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export { default as useGetAccountAddressDetail } from './useGetAccountAddressDetail'; diff --git a/packages/extension-koni-ui/src/hooks/screen/account/useGetAccountAddressDetail.tsx b/packages/extension-koni-ui/src/hooks/screen/account/useGetAccountAddressDetail.tsx new file mode 100644 index 0000000000..4789acc172 --- /dev/null +++ b/packages/extension-koni-ui/src/hooks/screen/account/useGetAccountAddressDetail.tsx @@ -0,0 +1,81 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { NotificationType } from '@subwallet/extension-base/background/KoniTypes'; +import { WalletModalContext } from '@subwallet/extension-koni-ui/contexts/WalletModalContextProvider'; +import { useSetSelectedMnemonicType, useTranslation } from '@subwallet/extension-koni-ui/hooks'; +import { AccountNetworkAddress } from '@subwallet/extension-koni-ui/types'; +import { CheckCircle, XCircle } from 'phosphor-react'; +import React, { useCallback, useContext, useMemo } from 'react'; +import { useNavigate } from 'react-router-dom'; + +type HookType = { + onSelectAccountSelector: (item: AccountNetworkAddress) => void; +}; + +export default function useGetAccountAddressDetail (): HookType { + const { t } = useTranslation(); + const navigate = useNavigate(); + const setSelectedMnemonicType = useSetSelectedMnemonicType(true); + const { addressQrModal, alertModal } = useContext(WalletModalContext); + + const onSelectAccountSelector = useCallback((item: AccountNetworkAddress) => { + const openAddressQrModal = () => { + addressQrModal.open({ + address: item.address, + chainSlug: item.slug, + onBack: addressQrModal.close, + onCancel: () => { + addressQrModal.close(); + } + }); + }; + + if (item.accountType === 'ton') { + alertModal.open({ + closable: false, + title: t('Seed phrase incompatibility'), + type: NotificationType.WARNING, + content: ( + <> +
+ {t('Importing this seed phrase will generate a unified account that can be used on multiple ecosystems including Polkadot, Ethereum, Bitcoin, and TON.')} +
+
+
+ {t('However, SubWallet is not compatible with TON-native wallets. This means that with the same seed phrase, SubWallet and TON-native wallets will generate two different TON addresses.')} +
+ + ), + cancelButton: { + text: t('Cancel'), + icon: XCircle, + iconWeight: 'fill', + onClick: () => { + alertModal.close(); + openAddressQrModal(); + }, + schema: 'secondary' + }, + okButton: { + text: t('OK'), + icon: CheckCircle, + iconWeight: 'fill', + onClick: () => { + setSelectedMnemonicType('ton'); + navigate('/accounts/new-seed-phrase'); + + alertModal.close(); + }, + schema: 'primary' + } + }); + + return; + } + + openAddressQrModal(); + }, [addressQrModal, alertModal, navigate, setSelectedMnemonicType, t]); + + return useMemo(() => ({ onSelectAccountSelector }), [onSelectAccountSelector]); +} diff --git a/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx b/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx index cb4afef896..86830a658f 100644 --- a/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx +++ b/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx @@ -149,7 +149,7 @@ export default function useReceiveModalHelper (tokenGroupSlug?: string): HookTyp schema: 'secondary' }, okButton: { - text: t('Apply'), + text: t('OK'), icon: CheckCircle, iconWeight: 'fill', onClick: () => { diff --git a/packages/extension-koni-ui/src/hooks/screen/index.ts b/packages/extension-koni-ui/src/hooks/screen/index.ts index 946cd97dad..aca6d60eab 100644 --- a/packages/extension-koni-ui/src/hooks/screen/index.ts +++ b/packages/extension-koni-ui/src/hooks/screen/index.ts @@ -6,3 +6,4 @@ export * from './confirmation'; export * from './crowdloan'; export * from './home'; export * from './nft'; +export * from './account'; diff --git a/packages/extension-koni-ui/src/types/account.ts b/packages/extension-koni-ui/src/types/account.ts index 474bda6f39..f02f22edaa 100644 --- a/packages/extension-koni-ui/src/types/account.ts +++ b/packages/extension-koni-ui/src/types/account.ts @@ -32,6 +32,7 @@ export type AccountNetworkAddress = { name: string; slug: string; address: string; + accountType: KeypairType; } export type AccountAddressItemType = { From 9c9d0f427f2cdacf86d1d90297be85b1d812525d Mon Sep 17 00:00:00 2001 From: S2kael Date: Mon, 19 Aug 2024 15:01:34 +0700 Subject: [PATCH 117/424] [Issue-3472] Change name `network` to `chain` --- .../src/types/account/info/keyring.ts | 10 +-- .../src/types/account/info/proxy.ts | 10 +-- .../src/utils/account/transform.ts | 72 +++++++++---------- .../src/Popup/Account/ConnectLedger.tsx | 2 +- .../Popup/Transaction/variants/SendFund.tsx | 2 +- .../AccountProxy/AccountProxySelectorItem.tsx | 12 ++-- .../src/components/Logo/DualLogo.tsx | 10 ++- .../account/useGetAccountNetworkAddresses.tsx | 2 +- .../screen/home/useGetChainSlugsByAccount.ts | 22 +++--- .../src/utils/account/account.ts | 12 ++-- .../src/utils/chain/chain.ts | 22 +++--- .../src/utils/common/common.ts | 2 +- 12 files changed, 92 insertions(+), 86 deletions(-) diff --git a/packages/extension-base/src/types/account/info/keyring.ts b/packages/extension-base/src/types/account/info/keyring.ts index f179fab6ec..5eea57f44c 100644 --- a/packages/extension-base/src/types/account/info/keyring.ts +++ b/packages/extension-base/src/types/account/info/keyring.ts @@ -111,7 +111,7 @@ export enum AccountSignMode { UNKNOWN = 'unknown' } -export enum AccountNetworkType { +export enum AccountChainType { SUBSTRATE = 'substrate', ETHEREUM = 'ethereum', BITCOIN = 'bitcoin', @@ -129,19 +129,19 @@ export enum AccountActions { /** * Represents the actions associated with an account. * @interface AccountActionData - * @prop {AccountNetworkType} networkType - The network type will account used on + * @prop {AccountChainType} chainType - The chain type will account used on * @prop {string[]} accountActions - A list of account-specific actions. These could be actions like 'derive', 'export', etc., that are applicable to the account. * @prop {ExtrinsicType[]} transactionActions - A list of transaction types that the account can initiate. This is dependent on the blockchain's supported extrinsic types, such as 'transfer', 'bond', etc. * @prop {AccountSignMode} signMode - Account sign mode - * @prop {string} [specialNetwork] - Optional the special network, which account can only be used on + * @prop {string} [specialChain] - Optional the special chain, which account can only be used on * @prop {_AssetType[]} tokenTypes - Asset types, which account can be used */ export interface AccountActionData { - networkType: AccountNetworkType; + chainType: AccountChainType; accountActions: AccountActions[]; transactionActions: ExtrinsicType[]; signMode: AccountSignMode; - specialNetwork?: string; + specialChain?: string; tokenTypes: _AssetType[]; } diff --git a/packages/extension-base/src/types/account/info/proxy.ts b/packages/extension-base/src/types/account/info/proxy.ts index eece607e5d..7db2df58ad 100644 --- a/packages/extension-base/src/types/account/info/proxy.ts +++ b/packages/extension-base/src/types/account/info/proxy.ts @@ -3,7 +3,7 @@ import { _AssetType } from '@subwallet/chain-list/types'; -import { AccountJson, AccountNetworkType } from './keyring'; +import { AccountChainType, AccountJson } from './keyring'; /** * Represents the basic data structure for an account proxy. @@ -48,15 +48,15 @@ export enum AccountProxyType { * * @prop {AccountJson[]} accounts - An array of `AccountJson` objects representing the accounts associated with this proxy. * @prop {AccountProxyType} accountType - The type of the account proxy. - * @prop {AccountNetworkType[]} networkTypes - An array of network types associated with this proxy. - * @prop {string} [specialNetwork] - Optional the special networks, which account proxy can only be used on + * @prop {AccountChainType[]} chainTypes - An array of network types associated with this proxy. + * @prop {string} [specialChain] - Optional the special networks, which account proxy can only be used on * @prop {_AssetType[]} tokenTypes - Asset types, which account proxy can be used */ export interface AccountProxy extends AccountProxyData { accounts: AccountJson[]; accountType: AccountProxyType; - networkTypes: AccountNetworkType[]; - specialNetwork?: string; + chainTypes: AccountChainType[]; + specialChain?: string; children?: string[]; tokenTypes: _AssetType[]; } diff --git a/packages/extension-base/src/utils/account/transform.ts b/packages/extension-base/src/utils/account/transform.ts index 9137eb9657..58bb99aa82 100644 --- a/packages/extension-base/src/utils/account/transform.ts +++ b/packages/extension-base/src/utils/account/transform.ts @@ -5,7 +5,7 @@ import { _AssetType, _ChainInfo } from '@subwallet/chain-list/types'; import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; import { _getSubstrateGenesisHash } from '@subwallet/extension-base/services/chain-service/utils'; -import { AccountActions, AccountJson, AccountMetadataData, AccountNetworkType, AccountProxy, AccountProxyMap, AccountProxyStoreData, AccountProxyType, AccountSignMode, AddressJson, ModifyPairStoreData } from '@subwallet/extension-base/types'; +import { AccountActions, AccountChainType, AccountJson, AccountMetadataData, AccountProxy, AccountProxyMap, AccountProxyStoreData, AccountProxyType, AccountSignMode, AddressJson, ModifyPairStoreData } from '@subwallet/extension-base/types'; import { getKeypairTypeByAddress } from '@subwallet/keyring'; import { BitcoinKeypairTypes, EthereumKeypairTypes, KeypairType, KeyringPair, KeyringPair$Meta, TonKeypairTypes } from '@subwallet/keyring/types'; import { SingleAddress, SubjectInfo } from '@subwallet/ui-keyring/observable/types'; @@ -65,7 +65,7 @@ export const getAccountSignMode = (address: string, _meta?: KeyringPair$Meta): A } }; -export const getAccountActions = (signMode: AccountSignMode, networkType: AccountNetworkType, type?: KeypairType, _meta?: KeyringPair$Meta): AccountActions[] => { +export const getAccountActions = (signMode: AccountSignMode, networkType: AccountChainType, type?: KeypairType, _meta?: KeyringPair$Meta): AccountActions[] => { const result: AccountActions[] = []; const meta = _meta as AccountMetadataData; @@ -80,18 +80,18 @@ export const getAccountActions = (signMode: AccountSignMode, networkType: Accoun } // Private key - if (signMode === AccountSignMode.PASSWORD && networkType === AccountNetworkType.ETHEREUM) { + if (signMode === AccountSignMode.PASSWORD && networkType === AccountChainType.ETHEREUM) { result.push(AccountActions.EXPORT_PRIVATE_KEY); } // QR - if (signMode === AccountSignMode.PASSWORD && networkType === AccountNetworkType.SUBSTRATE) { + if (signMode === AccountSignMode.PASSWORD && networkType === AccountChainType.SUBSTRATE) { result.push(AccountActions.EXPORT_QR); } // Derive if (signMode === AccountSignMode.PASSWORD) { - if (networkType === AccountNetworkType.SUBSTRATE) { + if (networkType === AccountChainType.SUBSTRATE) { result.push(AccountActions.DERIVE); } else if (type !== 'ton-native') { if (meta && meta.isMasterAccount) { @@ -173,10 +173,10 @@ const OTHER_ACTIONS: ExtrinsicType[] = [ ExtrinsicType.CROWDLOAN ]; -export const getAccountTransactionActions = (signMode: AccountSignMode, networkType: AccountNetworkType, type?: KeypairType, _meta?: KeyringPair$Meta, _specialNetwork?: string): ExtrinsicType[] => { +export const getAccountTransactionActions = (signMode: AccountSignMode, networkType: AccountChainType, type?: KeypairType, _meta?: KeyringPair$Meta, _specialNetwork?: string): ExtrinsicType[] => { if ([AccountSignMode.PASSWORD, AccountSignMode.INJECTED].includes(signMode)) { switch (networkType) { - case AccountNetworkType.SUBSTRATE: + case AccountChainType.SUBSTRATE: return [ ...BASE_TRANSFER_ACTIONS, ...NATIVE_STAKE_ACTIONS, @@ -188,7 +188,7 @@ export const getAccountTransactionActions = (signMode: AccountSignMode, networkT ...EARN_VMANTA_ACTIONS, ...OTHER_ACTIONS ]; - case AccountNetworkType.ETHEREUM: + case AccountChainType.ETHEREUM: return [ ...BASE_TRANSFER_ACTIONS, ...NATIVE_STAKE_ACTIONS, @@ -197,14 +197,14 @@ export const getAccountTransactionActions = (signMode: AccountSignMode, networkT ...OTHER_ACTIONS, ...EVM_ACTIONS ]; - case AccountNetworkType.TON: + case AccountChainType.TON: return [ ...BASE_TRANSFER_ACTIONS ]; } } else if (signMode === AccountSignMode.QR || signMode === AccountSignMode.GENERIC_LEDGER) { switch (networkType) { - case AccountNetworkType.SUBSTRATE: + case AccountChainType.SUBSTRATE: return [ ...BASE_TRANSFER_ACTIONS, ...NATIVE_STAKE_ACTIONS, @@ -216,7 +216,7 @@ export const getAccountTransactionActions = (signMode: AccountSignMode, networkT ...EARN_VMANTA_ACTIONS, ...OTHER_ACTIONS ]; - case AccountNetworkType.ETHEREUM: + case AccountChainType.ETHEREUM: return [ ...BASE_TRANSFER_ACTIONS, ...EARN_STDOT_ACTIONS, @@ -224,7 +224,7 @@ export const getAccountTransactionActions = (signMode: AccountSignMode, networkT ExtrinsicType.SEND_NFT, ExtrinsicType.SWAP ]; - case AccountNetworkType.TON: + case AccountChainType.TON: return [ ...BASE_TRANSFER_ACTIONS ]; @@ -306,15 +306,15 @@ export const getAccountTokenTypes = (type: KeypairType): _AssetType[] => { export const transformAccount = (address: string, _type?: KeypairType, meta?: KeyringPair$Meta, chainInfoMap?: Record): AccountJson => { const signMode = getAccountSignMode(address, meta); const type = _type || getKeypairTypeByAddress(address); - const networkType: AccountNetworkType = type + const networkType: AccountChainType = type ? EthereumKeypairTypes.includes(type) - ? AccountNetworkType.ETHEREUM + ? AccountChainType.ETHEREUM : TonKeypairTypes.includes(type) - ? AccountNetworkType.TON + ? AccountChainType.TON : BitcoinKeypairTypes.includes(type) - ? AccountNetworkType.BITCOIN - : AccountNetworkType.SUBSTRATE - : AccountNetworkType.SUBSTRATE; + ? AccountChainType.BITCOIN + : AccountChainType.SUBSTRATE + : AccountChainType.SUBSTRATE; let specialNetwork: string | undefined; if (!chainInfoMap) { @@ -326,7 +326,7 @@ export const transformAccount = (address: string, _type?: KeypairType, meta?: Ke transactionActions: [], tokenTypes: [], signMode, - networkType + chainType: networkType }; } @@ -353,8 +353,8 @@ export const transformAccount = (address: string, _type?: KeypairType, meta?: Ke accountActions, transactionActions, signMode, - networkType, - specialNetwork, + chainType: networkType, + specialChain: specialNetwork, tokenTypes }; }; @@ -390,7 +390,7 @@ export const combineAccounts = (pairs: SubjectInfo, modifyPairs: ModifyPairStore if (accountGroup) { if (!temp[accountGroup.id]) { - temp[accountGroup.id] = { ...accountGroup, accounts: [], networkTypes: [], tokenTypes: [] }; + temp[accountGroup.id] = { ...accountGroup, accounts: [], chainTypes: [], tokenTypes: [] }; } temp[accountGroup.id].accounts.push(account); @@ -402,7 +402,7 @@ export const combineAccounts = (pairs: SubjectInfo, modifyPairs: ModifyPairStore id: address, name: account.name || account.address, accounts: [account], - networkTypes: [account.networkType], + chainTypes: [account.chainType], parentId: account.parentAddress, suri: account.suri, tokenTypes: account.tokenTypes @@ -413,13 +413,13 @@ export const combineAccounts = (pairs: SubjectInfo, modifyPairs: ModifyPairStore Object.entries(temp) .map(([key, value]): [string, AccountProxy] => { let accountType: AccountProxyType = AccountProxyType.UNKNOWN; - let networkTypes: AccountNetworkType[] = []; + let chainTypes: AccountChainType[] = []; let tokenTypes: _AssetType[] = []; - let specialNetwork: string | undefined; + let specialChain: string | undefined; if (value.accounts.length > 1) { accountType = AccountProxyType.UNIFIED; - networkTypes = Array.from(value.accounts.reduce>((rs, account) => rs.add(account.networkType), new Set())); + chainTypes = Array.from(value.accounts.reduce>((rs, account) => rs.add(account.chainType), new Set())); tokenTypes = Array.from(value.accounts.reduce>((rs, account) => { for (const tokenType of account.tokenTypes) { rs.add(tokenType); @@ -430,14 +430,14 @@ export const combineAccounts = (pairs: SubjectInfo, modifyPairs: ModifyPairStore } else if (value.accounts.length === 1) { const account = value.accounts[0]; - networkTypes = [account.networkType]; + chainTypes = [account.chainType]; tokenTypes = account.tokenTypes; switch (account.signMode) { case AccountSignMode.GENERIC_LEDGER: case AccountSignMode.LEGACY_LEDGER: accountType = AccountProxyType.LEDGER; - specialNetwork = account.specialNetwork; + specialChain = account.specialChain; break; case AccountSignMode.QR: accountType = AccountProxyType.QR; @@ -460,7 +460,7 @@ export const combineAccounts = (pairs: SubjectInfo, modifyPairs: ModifyPairStore } } - return [key, { ...value, accountType, networkTypes, specialNetwork, tokenTypes }]; + return [key, { ...value, accountType, chainTypes, specialChain, tokenTypes }]; }) ); @@ -500,18 +500,18 @@ export const combineAccounts = (pairs: SubjectInfo, modifyPairs: ModifyPairStore }; export const combineAllAccountProxy = (accountProxies: AccountProxy[]): AccountProxy => { - const networkTypes = new Set(); + const chainTypes = new Set(); const tokenTypes = new Set<_AssetType>(); - const specialNetwork: string | undefined = accountProxies.length === 1 ? accountProxies[0].specialNetwork : undefined; + const specialChain: string | undefined = accountProxies.length === 1 ? accountProxies[0].specialChain : undefined; for (const accountProxy of accountProxies) { // Have 4 network types, but at the moment, we only support 3 network types - if (networkTypes.size === 3) { + if (chainTypes.size === 3) { break; } - for (const networkType of accountProxy.networkTypes) { - networkTypes.add(networkType); + for (const chainType of accountProxy.chainTypes) { + chainTypes.add(chainType); } } @@ -526,8 +526,8 @@ export const combineAllAccountProxy = (accountProxies: AccountProxy[]): AccountP name: 'All', accounts: [], accountType: AccountProxyType.ALL_ACCOUNT, - networkTypes: Array.from(networkTypes), + chainTypes: Array.from(chainTypes), tokenTypes: Array.from(tokenTypes), - specialNetwork + specialChain }; }; diff --git a/packages/extension-koni-ui/src/Popup/Account/ConnectLedger.tsx b/packages/extension-koni-ui/src/Popup/Account/ConnectLedger.tsx index 3101a8dc5d..c243ae90c7 100644 --- a/packages/extension-koni-ui/src/Popup/Account/ConnectLedger.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/ConnectLedger.tsx @@ -307,6 +307,7 @@ const Component: React.FC = (props: Props) => { <>
= (props: Props) => { width={52} /> )} - innerSize={52} sizeLinkIcon={36} sizeSquircleBorder={108} /> diff --git a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx index fc430eb744..8531a49a29 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx +++ b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx @@ -42,7 +42,7 @@ function isAssetTypeValid ( ) { const chainInfo = chainInfoMap[chainAsset.originChain]; - return !!chainInfo && accountProxy.networkTypes.some((nt) => isChainInfoAccordantNetworkType(chainInfo, nt)); + return !!chainInfo && accountProxy.chainTypes.some((nt) => isChainInfoAccordantNetworkType(chainInfo, nt)); } // todo: recheck with ledger account, All account diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx index 52d2113a4f..2d4bf11e6b 100644 --- a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx +++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountNetworkType, AccountProxy, AccountProxyType } from '@subwallet/extension-base/types'; +import { AccountChainType, AccountProxy, AccountProxyType } from '@subwallet/extension-base/types'; import { useTranslation } from '@subwallet/extension-koni-ui/hooks'; import { Theme } from '@subwallet/extension-koni-ui/themes'; import { PhosphorIcon, ThemeProps } from '@subwallet/extension-koni-ui/types'; @@ -45,10 +45,10 @@ function Component (props: Props): React.ReactElement { const networkTypeLogoMap = useMemo(() => { return { - [AccountNetworkType.SUBSTRATE]: logoMap.network.polkadot as string, - [AccountNetworkType.ETHEREUM]: logoMap.network.ethereum as string, - [AccountNetworkType.BITCOIN]: logoMap.network.bitcoin as string, - [AccountNetworkType.TON]: logoMap.network.ton as string + [AccountChainType.SUBSTRATE]: logoMap.network.polkadot as string, + [AccountChainType.ETHEREUM]: logoMap.network.ethereum as string, + [AccountChainType.BITCOIN]: logoMap.network.bitcoin as string, + [AccountChainType.TON]: logoMap.network.ton as string }; }, [logoMap.network.bitcoin, logoMap.network.ethereum, logoMap.network.polkadot, logoMap.network.ton]); @@ -157,7 +157,7 @@ function Component (props: Props): React.ReactElement {
{accountProxy.name}
{ - accountProxy.networkTypes.map((nt) => { + accountProxy.chainTypes.map((nt) => { return ( Network type; const Component = ({ className, leftLogo = defaultLogo, linkIcon = defaultLinkIcon, rightLogo = defaultLogo, sizeSquircleBorder, innerSize }: Props) => { return (
- + {leftLogo}
{linkIcon}
- + {rightLogo}
diff --git a/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx b/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx index 6190ca4d8c..aa42e6d8a6 100644 --- a/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx +++ b/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx @@ -14,7 +14,7 @@ const useGetAccountNetworkAddresses = (accountProxy: AccountProxy): AccountNetwo return useMemo(() => { const result: AccountNetworkAddress[] = []; - const chains: string[] = getChainsByAccountType(chainInfoMap, accountProxy.networkTypes, accountProxy.specialNetwork); + const chains: string[] = getChainsByAccountType(chainInfoMap, accountProxy.chainTypes, accountProxy.specialChain); accountProxy.accounts.forEach((a) => { for (const chain of chains) { diff --git a/packages/extension-koni-ui/src/hooks/screen/home/useGetChainSlugsByAccount.ts b/packages/extension-koni-ui/src/hooks/screen/home/useGetChainSlugsByAccount.ts index b557d1daa4..4ca869f21f 100644 --- a/packages/extension-koni-ui/src/hooks/screen/home/useGetChainSlugsByAccount.ts +++ b/packages/extension-koni-ui/src/hooks/screen/home/useGetChainSlugsByAccount.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; -import { AccountNetworkType } from '@subwallet/extension-base/types'; +import { AccountChainType } from '@subwallet/extension-base/types'; import { RootState } from '@subwallet/extension-koni-ui/stores'; import { findAccountByAddress, getChainsByAccountType, isAccountAll } from '@subwallet/extension-koni-ui/utils'; import { useMemo } from 'react'; @@ -12,52 +12,52 @@ export const useGetChainSlugsByAccount = (address?: string): string[] => { const chainInfoMap = useSelector((state: RootState) => state.chainStore.chainInfoMap); const { accountProxies, accounts, currentAccountProxy } = useSelector((state: RootState) => state.accountState); - const networkTypes = useMemo((): AccountNetworkType[] => { + const chainTypes = useMemo((): AccountChainType[] => { const _address = address || currentAccountProxy?.id; if (_address) { if (isAccountAll(_address)) { const allAccount = accountProxies.find((proxy) => proxy.id === ALL_ACCOUNT_KEY); - return allAccount?.networkTypes || []; + return allAccount?.chainTypes || []; } const proxy = accountProxies.find((proxy) => proxy.id === _address); if (proxy) { - return proxy.networkTypes; + return proxy.chainTypes; } const account = findAccountByAddress(accounts, _address); if (account) { - return [account.networkType]; + return [account.chainType]; } } return []; }, [accountProxies, accounts, address, currentAccountProxy]); - const specialNetwork = useMemo((): string | undefined => { + const specialChain = useMemo((): string | undefined => { const _address = address || currentAccountProxy?.id; if (_address) { if (isAccountAll(_address)) { const allAccount = accountProxies.find((proxy) => proxy.id === ALL_ACCOUNT_KEY); - return allAccount?.specialNetwork; + return allAccount?.specialChain; } const proxy = accountProxies.find((proxy) => proxy.id === _address); if (proxy) { - return proxy.specialNetwork; + return proxy.specialChain; } const account = findAccountByAddress(accounts, _address); if (account) { - return account.specialNetwork; + return account.specialChain; } } @@ -65,6 +65,6 @@ export const useGetChainSlugsByAccount = (address?: string): string[] => { }, [accountProxies, accounts, address, currentAccountProxy?.id]); return useMemo(() => { - return getChainsByAccountType(chainInfoMap, networkTypes, specialNetwork); - }, [networkTypes, chainInfoMap, specialNetwork]); + return getChainsByAccountType(chainInfoMap, chainTypes, specialChain); + }, [chainTypes, chainInfoMap, specialChain]); }; diff --git a/packages/extension-koni-ui/src/utils/account/account.ts b/packages/extension-koni-ui/src/utils/account/account.ts index 858e8e36b8..e04b7551de 100644 --- a/packages/extension-koni-ui/src/utils/account/account.ts +++ b/packages/extension-koni-ui/src/utils/account/account.ts @@ -6,7 +6,7 @@ import { NetworkJson } from '@subwallet/extension-base/background/KoniTypes'; import { AccountAuthType } from '@subwallet/extension-base/background/types'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; import { _getChainSubstrateAddressPrefix, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; -import { AbstractAddressJson, AccountJson, AccountNetworkType } from '@subwallet/extension-base/types'; +import { AbstractAddressJson, AccountChainType, AccountJson } from '@subwallet/extension-base/types'; import { isAccountAll, uniqueStringArray } from '@subwallet/extension-base/utils'; import { DEFAULT_ACCOUNT_TYPES, EVM_ACCOUNT_TYPE, SUBSTRATE_ACCOUNT_TYPE } from '@subwallet/extension-koni-ui/constants'; import { MODE_CAN_SIGN } from '@subwallet/extension-koni-ui/constants/signing'; @@ -182,19 +182,19 @@ export const convertKeyTypes = (authTypes: AccountAuthType[]): KeypairType[] => // todo: // - support bitcoin export function getReformatedAddressRelatedToNetwork (accountJson: AccountJson, chainInfo: _ChainInfo): string | undefined { - if (accountJson.specialNetwork && accountJson.specialNetwork !== chainInfo.slug) { + if (accountJson.specialChain && accountJson.specialChain !== chainInfo.slug) { return undefined; } - if (!isChainInfoAccordantNetworkType(chainInfo, accountJson.networkType)) { + if (!isChainInfoAccordantNetworkType(chainInfo, accountJson.chainType)) { return undefined; } - if (accountJson.networkType === AccountNetworkType.SUBSTRATE && chainInfo.substrateInfo) { + if (accountJson.chainType === AccountChainType.SUBSTRATE && chainInfo.substrateInfo) { return reformatAddress(accountJson.address, chainInfo.substrateInfo.addressPrefix); - } else if (accountJson.networkType === AccountNetworkType.ETHEREUM && chainInfo.evmInfo) { + } else if (accountJson.chainType === AccountChainType.ETHEREUM && chainInfo.evmInfo) { return accountJson.address; - } else if (accountJson.networkType === AccountNetworkType.TON && chainInfo.tonInfo) { + } else if (accountJson.chainType === AccountChainType.TON && chainInfo.tonInfo) { return reformatAddress(accountJson.address, chainInfo.isTestnet ? 0 : 1); } diff --git a/packages/extension-koni-ui/src/utils/chain/chain.ts b/packages/extension-koni-ui/src/utils/chain/chain.ts index fba673b609..e6aa4523c8 100644 --- a/packages/extension-koni-ui/src/utils/chain/chain.ts +++ b/packages/extension-koni-ui/src/utils/chain/chain.ts @@ -2,8 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 import { _ChainInfo, _ChainStatus } from '@subwallet/chain-list/types'; -import { _getSubstrateGenesisHash, _isChainBitcoinCompatible, _isChainEvmCompatible, _isChainSubstrateCompatible, _isChainTonCompatible, _isPureSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils'; -import { AccountNetworkType } from '@subwallet/extension-base/types'; +import { _getSubstrateGenesisHash, _isChainBitcoinCompatible, _isChainEvmCompatible, _isChainTonCompatible, _isPureSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils'; +import { AccountChainType } from '@subwallet/extension-base/types'; export const findChainInfoByGenesisHash = (chainMap: Record, genesisHash?: string): _ChainInfo | null => { if (!genesisHash) { @@ -33,37 +33,37 @@ export const findChainInfoByChainId = (chainMap: Record, cha return null; }; -export const isChainInfoAccordantNetworkType = (chainInfo: _ChainInfo, networkType: AccountNetworkType): boolean => { - if (networkType === AccountNetworkType.SUBSTRATE) { +export const isChainInfoAccordantNetworkType = (chainInfo: _ChainInfo, chainType: AccountChainType): boolean => { + if (chainType === AccountChainType.SUBSTRATE) { return _isPureSubstrateChain(chainInfo); } - if (networkType === AccountNetworkType.ETHEREUM) { + if (chainType === AccountChainType.ETHEREUM) { return _isChainEvmCompatible(chainInfo); } - if (networkType === AccountNetworkType.TON) { + if (chainType === AccountChainType.TON) { return _isChainTonCompatible(chainInfo); } - if (networkType === AccountNetworkType.BITCOIN) { + if (chainType === AccountChainType.BITCOIN) { return _isChainBitcoinCompatible(chainInfo); } return false; }; -export const getChainsByAccountType = (_chainInfoMap: Record, networkTypes: AccountNetworkType[], specialNetwork?: string): string[] => { +export const getChainsByAccountType = (_chainInfoMap: Record, chainTypes: AccountChainType[], specialChain?: string): string[] => { const chainInfoMap = Object.fromEntries(Object.entries(_chainInfoMap).filter(([, chainInfo]) => chainInfo.chainStatus === _ChainStatus.ACTIVE)); - if (specialNetwork) { - return Object.keys(chainInfoMap).filter((chain) => specialNetwork === chain); + if (specialChain) { + return Object.keys(chainInfoMap).filter((chain) => specialChain === chain); } else { const result: string[] = []; for (const chainInfo of Object.values(chainInfoMap)) { const chain = chainInfo.slug; - const isChainCompatible = networkTypes.some((networkType) => isChainInfoAccordantNetworkType(chainInfo, networkType)); + const isChainCompatible = chainTypes.some((chainType) => isChainInfoAccordantNetworkType(chainInfo, chainType)); if (isChainCompatible) { result.push(chain); diff --git a/packages/extension-koni-ui/src/utils/common/common.ts b/packages/extension-koni-ui/src/utils/common/common.ts index 7f0a5ce582..688c2afc5a 100644 --- a/packages/extension-koni-ui/src/utils/common/common.ts +++ b/packages/extension-koni-ui/src/utils/common/common.ts @@ -34,6 +34,6 @@ export function shuffle (array: T[]) { } } -export const getLogoByNetworkKey = (networkKey: string, defaultLogo = 'default'): string =>{ +export const getLogoByNetworkKey = (networkKey: string, defaultLogo = 'default'): string => { return ChainLogoMap[networkKey] || ChainLogoMap[defaultLogo] || ChainLogoMap.default; }; From 7119ac0e443d446b6773199c14629f9cd7689e93 Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Mon, 19 Aug 2024 15:20:38 +0700 Subject: [PATCH 118/424] [Issue-3449] feat: add getMaxTransferable logic for ton before send --- .../src/koni/background/handlers/Extension.ts | 6 +++-- .../balance-service/transfer/token.ts | 24 ++++++++++++++++--- .../balance-service/transfer/ton-transfer.ts | 6 ++--- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index 197a6089b2..93b28dcfaa 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -32,7 +32,7 @@ import { createTonTransaction } from '@subwallet/extension-base/services/balance import { createSnowBridgeExtrinsic, createXcmExtrinsic, getXcmMockTxFee } from '@subwallet/extension-base/services/balance-service/transfer/xcm'; import { _API_OPTIONS_CHAIN_GROUP, _DEFAULT_MANTA_ZK_CHAIN, _MANTA_ZK_CHAIN_GROUP, _ZK_ASSET_PREFIX } from '@subwallet/extension-base/services/chain-service/constants'; import { _ChainApiStatus, _ChainConnectionStatus, _ChainState, _NetworkUpsertParams, _ValidateCustomAssetRequest, _ValidateCustomAssetResponse, EnableChainParams, EnableMultiChainParams } from '@subwallet/extension-base/services/chain-service/types'; -import { _getAssetDecimals, _getAssetSymbol, _getChainNativeTokenBasicInfo, _getContractAddressOfToken, _getEvmChainId, _isAssetSmartContractNft, _isChainEvmCompatible, _isCustomAsset, _isLocalToken, _isMantaZkAsset, _isNativeToken, _isPureEvmChain, _isTokenEvmSmartContract, _isTokenTransferredByEvm, _isTokenTransferredByTon } from '@subwallet/extension-base/services/chain-service/utils'; +import { _getAssetDecimals, _getAssetSymbol, _getChainNativeTokenBasicInfo, _getContractAddressOfToken, _getEvmChainId, _isAssetSmartContractNft, _isChainEvmCompatible, _isChainTonCompatible, _isCustomAsset, _isLocalToken, _isMantaZkAsset, _isNativeToken, _isPureEvmChain, _isTokenEvmSmartContract, _isTokenTransferredByEvm, _isTokenTransferredByTon } from '@subwallet/extension-base/services/chain-service/utils'; import { AppBannerData, AppConfirmationData, AppPopupData } from '@subwallet/extension-base/services/mkt-campaign-service/types'; import { EXTENSION_REQUEST_URL } from '@subwallet/extension-base/services/request-service/constants'; import { AuthUrls } from '@subwallet/extension-base/services/request-service/types'; @@ -1626,7 +1626,9 @@ export default class KoniExtension { const chainInfo = this.#koniState.chainService.getChainInfoByKey(networkKey); const api = _isChainEvmCompatible(chainInfo) && _isTokenTransferredByEvm(tokenInfo) ? this.#koniState.chainService.getEvmApi(networkKey) - : this.#koniState.chainService.getSubstrateApi(networkKey); + : _isChainTonCompatible(chainInfo) && _isTokenTransferredByTon(tokenInfo) + ? this.#koniState.chainService.getTonApi(networkKey) + : this.#koniState.chainService.getSubstrateApi(networkKey); const [mockTxFee, { value }] = await Promise.all([ getTransferMockTxFee(address, chainInfo, tokenInfo, api), diff --git a/packages/extension-base/src/services/balance-service/transfer/token.ts b/packages/extension-base/src/services/balance-service/transfer/token.ts index d7347d5288..3e830a250e 100644 --- a/packages/extension-base/src/services/balance-service/transfer/token.ts +++ b/packages/extension-base/src/services/balance-service/transfer/token.ts @@ -5,11 +5,16 @@ import { GearApi } from '@gear-js/api'; import { _AssetType, _ChainAsset, _ChainInfo } from '@subwallet/chain-list/types'; import { getPSP22ContractPromise } from '@subwallet/extension-base/koni/api/contract-handler/wasm'; import { getWasmContractGasLimit } from '@subwallet/extension-base/koni/api/contract-handler/wasm/utils'; +import { WORKCHAIN } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/consts'; +import { estimateTonTxFee } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/utils'; import { _TRANSFER_CHAIN_GROUP } from '@subwallet/extension-base/services/chain-service/constants'; -import { _EvmApi, _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; -import { _getContractAddressOfToken, _getTokenOnChainAssetId, _getTokenOnChainInfo, _getXcmAssetMultilocation, _isBridgedToken, _isChainEvmCompatible, _isNativeToken, _isTokenGearSmartContract, _isTokenTransferredByEvm, _isTokenWasmSmartContract } from '@subwallet/extension-base/services/chain-service/utils'; +import { _EvmApi, _SubstrateApi, _TonApi } from '@subwallet/extension-base/services/chain-service/types'; +import { _getContractAddressOfToken, _getTokenOnChainAssetId, _getTokenOnChainInfo, _getXcmAssetMultilocation, _isBridgedToken, _isChainEvmCompatible, _isChainTonCompatible, _isNativeToken, _isTokenGearSmartContract, _isTokenTransferredByEvm, _isTokenTransferredByTon, _isTokenWasmSmartContract } from '@subwallet/extension-base/services/chain-service/utils'; import { calculateGasFeeParams } from '@subwallet/extension-base/services/fee-service/utils'; import { getGRC20ContractPromise, getVFTContractPromise } from '@subwallet/extension-base/utils'; +import { keyring } from '@subwallet/ui-keyring'; +import { internal } from '@ton/core'; +import { WalletContractV4 } from '@ton/ton'; import BigN from 'bignumber.js'; import { TransactionConfig } from 'web3-core'; @@ -121,7 +126,7 @@ export const createTransferExtrinsic = async ({ from, networkKey, substrateApi, return [transfer, transferAmount || value]; }; -export const getTransferMockTxFee = async (address: string, chainInfo: _ChainInfo, tokenInfo: _ChainAsset, api: _SubstrateApi | _EvmApi): Promise => { +export const getTransferMockTxFee = async (address: string, chainInfo: _ChainInfo, tokenInfo: _ChainAsset, api: _SubstrateApi | _EvmApi | _TonApi): Promise => { try { let estimatedFee; @@ -142,6 +147,19 @@ export const getTransferMockTxFee = async (address: string, chainInfo: _ChainInf } else { estimatedFee = new BigN(priority.gasPrice).multipliedBy(gasLimit); } + } else if (_isChainTonCompatible(chainInfo) && _isTokenTransferredByTon(tokenInfo)) { + const keyPair = keyring.getPair(address); + const tonApi = api as _TonApi; + const mockMessage = + internal({ + to: address, // anyAddress + value: '0.05', // anyValue + bounce: false // anyMode + }); + + const mockWalletContract = WalletContractV4.create({ workchain: WORKCHAIN, publicKey: Buffer.from(keyPair.publicKey) }); + + estimatedFee = new BigN((await estimateTonTxFee(tonApi, [mockMessage], mockWalletContract)).toString()); } else { const substrateApi = api as _SubstrateApi; const chainApi = await substrateApi.isReady; diff --git a/packages/extension-base/src/services/balance-service/transfer/ton-transfer.ts b/packages/extension-base/src/services/balance-service/transfer/ton-transfer.ts index c0ab73e9ba..ac66c12f67 100644 --- a/packages/extension-base/src/services/balance-service/transfer/ton-transfer.ts +++ b/packages/extension-base/src/services/balance-service/transfer/ton-transfer.ts @@ -61,12 +61,12 @@ async function createTonNativeTransaction ({ from, networkKey, to, tonApi, trans const messagePayload = cellToBase64Str(messageRelaxedToCell(messages)); - const estimateFee = await estimateTonTxFee(tonApi, [messages], walletContract); + const estimateExternalFee = await estimateTonTxFee(tonApi, [messages], walletContract); if (transferAll) { const balance = await tonApi.getBalance(tonAddress); - transferValue = (balance - estimateFee).toString(); + transferValue = (balance - estimateExternalFee).toString(); } const transactionObject = { @@ -76,7 +76,7 @@ async function createTonNativeTransaction ({ from, networkKey, to, tonApi, trans value: transferValue ?? value, messagePayload, messages: [messages], - estimateFee: estimateFee.toString(), + estimateFee: estimateExternalFee.toString(), seqno } as unknown as TonTransactionConfig; From 76eb5e956c913479ed9ebeb0b7670992f142e916 Mon Sep 17 00:00:00 2001 From: Thiendekaco Date: Mon, 19 Aug 2024 14:49:02 +0700 Subject: [PATCH 119/424] [Issue 3457] [fix] Extension - Derived accounts: show a toast notification when copying and detail button does not redirect --- .../AccountDetail/DerivedAccountList.tsx | 53 ++++++++++++++++--- .../src/Popup/Account/AccountDetail/index.tsx | 21 ++++---- .../Popup/Transaction/variants/SendFund.tsx | 2 +- .../AccountProxy/AccountProxySelectorItem.tsx | 48 ++++++++++++----- .../src/components/Logo/DualLogo.tsx | 10 +++- 5 files changed, 102 insertions(+), 32 deletions(-) diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/DerivedAccountList.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/DerivedAccountList.tsx index 4b549e900f..8fccca5673 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/DerivedAccountList.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/DerivedAccountList.tsx @@ -2,23 +2,28 @@ // SPDX-License-Identifier: Apache-2.0 import { AccountProxy } from '@subwallet/extension-base/types'; -import { AccountProxySelectorItem, GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; +import { AccountNetworkAddressesModal, AccountProxySelectorItem, GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; +import { ACCOUNT_NETWORK_ADDRESSES_MODAL } from '@subwallet/extension-koni-ui/constants'; import { useTranslation } from '@subwallet/extension-koni-ui/hooks'; import { RootState } from '@subwallet/extension-koni-ui/stores'; -import { ThemeProps } from '@subwallet/extension-koni-ui/types'; -import { SwList } from '@subwallet/react-ui'; -import React, { useCallback, useMemo } from 'react'; +import { AccountDetailParam, ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { ModalContext, SwList } from '@subwallet/react-ui'; +import React, { useCallback, useContext, useMemo, useState } from 'react'; import { useSelector } from 'react-redux'; +import { useNavigate } from 'react-router-dom'; import styled from 'styled-components'; type Props = ThemeProps & { accountProxy: AccountProxy; }; +const accountNetworkAddressesModalId = ACCOUNT_NETWORK_ADDRESSES_MODAL; function Component ({ accountProxy, className }: Props) { const accountProxies = useSelector((state: RootState) => state.accountState.accountProxies); - const { t } = useTranslation(); + const [accountProxyToCopyAddresses, setAccountProxyToCopyAddresses] = useState(); + const { activeModal, inactiveModal } = useContext(ModalContext); + const navigate = useNavigate(); // todo: may have to sort the result const items = useMemo(() => { @@ -39,16 +44,44 @@ function Component ({ accountProxy, className }: Props) { return result; }, [accountProxies, accountProxy.children]); + const onCopyAddress = useCallback((item: AccountProxy) => { + return () => { + setAccountProxyToCopyAddresses(item); + setTimeout(() => { + activeModal(accountNetworkAddressesModalId); + }, 100); + }; + }, [activeModal]); + + const onCancelCopyModal = useCallback(() => { + inactiveModal(accountNetworkAddressesModalId); + }, [inactiveModal]); + + const onViewAccountDetail = useCallback((accountProxy: AccountProxy) => { + return () => { + setTimeout(() => { + navigate(`/accounts/detail/${accountProxy.id}`, { + state: { + requestViewDerivedAccounts: false + } as AccountDetailParam + }); + }, 100); + }; + }, [navigate]); + const renderItem = useCallback( (item: AccountProxy) => { return ( ); }, - [] + [onCopyAddress, onViewAccountDetail] ); const emptyList = useCallback(() => { @@ -77,6 +110,14 @@ function Component ({ accountProxy, className }: Props) { searchMinCharactersCount={2} searchPlaceholder={t('Enter account name or address')} /> + + {accountProxyToCopyAddresses && ( + + )}
); } diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx index 9f354d7364..ad88422551 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/index.tsx @@ -251,6 +251,16 @@ const Component: React.FC = ({ accountProxy, onBack, requestView ; })(); + useEffect(() => { + if (accountProxy) { + form.setFieldValue(FormFieldName.NAME, accountProxy.name); + } + + setSelectedFilterTab(requestViewDerivedAccounts && showDerivedAccounts + ? FilterTabType.DERIVED_ACCOUNT + : FilterTabType.ACCOUNT_ADDRESS); + }, [accountProxy, form, requestViewDerivedAccounts, showDerivedAccounts]); + return ( = ({ accountProxy, onBack, requestView className={'account-type-tag'} type={accountProxy.accountType} /> - - { - !!accountProxy.parentId && ( - - ) - }
=> { diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx index e843af01f0..2c1479f2a7 100644 --- a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx +++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx @@ -18,6 +18,7 @@ type Props = ThemeProps & { className?: string; isSelected?: boolean; accountProxy: AccountProxy; + showDerivedPath?: boolean; onClick?: VoidFunction; onClickCopyButton?: VoidFunction; onClickDeriveButton?: VoidFunction; @@ -36,7 +37,8 @@ function Component (props: Props): React.ReactElement { onClick, onClickCopyButton, onClickDeriveButton, - onClickMoreButton } = props; + onClickMoreButton, + showDerivedPath } = props; const token = useContext(ThemeContext as Context).token; const logoMap = useContext(ThemeContext as Context).logoMap; @@ -122,8 +124,6 @@ function Component (props: Props): React.ReactElement { return null; })(); - console.log(accountProxy, '-' , accountProxy.children); - const showDeriveButton = !!accountProxy?.children?.length; return ( @@ -159,16 +159,28 @@ function Component (props: Props): React.ReactElement {
{accountProxy.name}
{ - accountProxy.networkTypes.map((nt) => { - return ( - Network type + - ); - }) +
+ {accountProxy.suri || ''} +
+
+ : accountProxy.networkTypes.map((nt) => { + return ( + Network type + ); + }) } @@ -361,6 +373,18 @@ const AccountProxySelectorItem = styled(Component)(({ theme }) => { '.-show-on-hover': { opacity: 1 } + }, + + '.__item-derived-path': { + display: 'flex', + gap: token.sizeXS - 2, + alignItems: 'center', + + '.__derive-account-path': { + fontSize: token.fontSizeSM, + color: token.colorTextLight4, + lineHeight: token.lineHeightSM + } } }; }); diff --git a/packages/extension-koni-ui/src/components/Logo/DualLogo.tsx b/packages/extension-koni-ui/src/components/Logo/DualLogo.tsx index 8ba5122b2e..55b694ceec 100644 --- a/packages/extension-koni-ui/src/components/Logo/DualLogo.tsx +++ b/packages/extension-koni-ui/src/components/Logo/DualLogo.tsx @@ -33,13 +33,19 @@ const defaultLogo = ; const Component = ({ className, leftLogo = defaultLogo, linkIcon = defaultLinkIcon, rightLogo = defaultLogo, sizeSquircleBorder, innerSize }: Props) => { return (
- + {leftLogo}
{linkIcon}
- + {rightLogo}
From e0a7c2d4367d9705c41122b56bddbfab0bed0934 Mon Sep 17 00:00:00 2001 From: Thiendekaco Date: Mon, 19 Aug 2024 17:18:09 +0700 Subject: [PATCH 120/424] [Issue 3457] [fix] Extension - Derived accounts: show a toast notification when copying and detail button does not redirect #2 --- .../src/Popup/Account/ImportPrivateKey.tsx | 29 ++----------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx b/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx index 2d968f2225..6f3b1bf23f 100644 --- a/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx @@ -3,6 +3,7 @@ import { AccountProxyType } from '@subwallet/extension-base/types'; import { AccountNameModal, CloseIcon, Layout, PageWrapper, PrivateKeyInput } from '@subwallet/extension-koni-ui/components'; +import { EVM_ACCOUNT_TYPE } from '@subwallet/extension-koni-ui/constants'; import { ACCOUNT_NAME_MODAL, IMPORT_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants/modal'; import { useAutoNavigateToCreatePassword, useCompleteCreateAccount, useDefaultNavigate, useFocusFormItem, useGoBackFromCreateAccount, useTranslation, useUnlockChecker } from '@subwallet/extension-koni-ui/hooks'; import { createAccountSuriV2, validateMetamaskPrivateKeyV2 } from '@subwallet/extension-koni-ui/messaging'; @@ -73,7 +74,8 @@ const Component: React.FC = ({ className }: Props) => { createAccountSuriV2({ name: name, suri: privateKey.trim(), - isAllowed: true + isAllowed: true, + type: EVM_ACCOUNT_TYPE }) .then(() => { onComplete(); @@ -90,31 +92,6 @@ const Component: React.FC = ({ className }: Props) => { }); } }, [privateKey, onComplete, inactiveModal]); - setLoading(true); - createAccountSuriV2({ - name: accountName, - suri: privateKey.trim(), - isAllowed: true, - type: EVM_ACCOUNT_TYPE - }) - .then(() => { - onComplete(); - }) - .catch((error: Error): void => { - setValidateState({ - status: 'error', - message: error.message - }); - }) - .finally(() => { - setLoading(false); - }); - } - }) - .catch(() => { - // User cancel unlock - }); - }, [accountName, checkUnlock, onComplete]); useEffect(() => { let amount = true; From 29ce2d422dcb4a0c334ec98bfe519f0a0484eedc Mon Sep 17 00:00:00 2001 From: Thiendekaco Date: Mon, 19 Aug 2024 17:24:35 +0700 Subject: [PATCH 121/424] [Issue 3457] [fix] Extension - fix eslint issue --- .../parts/SelectAccount/AccountSelectorModal.tsx | 11 +++++++++++ .../components/Modal/Account/DeriveAccountModal.tsx | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx index 26ed90cc16..ec729e55c8 100644 --- a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx +++ b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx @@ -437,6 +437,17 @@ export const AccountSelectorModal = styled(Component)(({ theme: { token } '> div + div': { marginTop: token.marginXS } + }, + + '.__icon-export-remind': { + position: 'absolute', + top: '-35%', + left: '40%' + }, + + '.anticon.__export-remind-btn': { + height: 23, + width: 24 } }; }); diff --git a/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx b/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx index e438a572ff..333f43c55f 100644 --- a/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx @@ -124,7 +124,7 @@ const Component: React.FC = ({ className }: Props) => { (({ theme: { token } }: Props } }, - '.account-derive-item': { - display: 'flex' + '.__account-derive-item': { + display: 'flex !important' } }; }); From 7259a0709988e6bf302ed9009430977a07d86c65 Mon Sep 17 00:00:00 2001 From: Thiendekaco Date: Mon, 19 Aug 2024 19:12:56 +0700 Subject: [PATCH 122/424] [Issue 3457] [fix] Extension - recheck flow --- .../AccountDetail/AccountAddressList.tsx | 8 ++++---- .../src/Popup/Account/AccountDetail/index.tsx | 4 +++- .../src/Popup/Account/AttachReadOnly.tsx | 6 ++++-- .../Popup/Account/ConnectQrSigner/index.tsx | 20 ++++++++++--------- .../src/Popup/Account/ImportPrivateKey.tsx | 6 ++++-- .../AccountNetworkAddressItem.tsx | 7 +------ .../AccountProxy/AccountProxySelectorItem.tsx | 20 ++++++++++--------- .../Layout/parts/SelectAccount/index.tsx | 7 ++++++- .../Modal/Account/AccountNameModal.tsx | 4 +++- .../src/hooks/screen/account/index.tsx | 2 +- ...Detail.tsx => useViewAccountAddressQr.tsx} | 12 ++++------- 11 files changed, 52 insertions(+), 44 deletions(-) rename packages/extension-koni-ui/src/hooks/screen/account/{useGetAccountAddressDetail.tsx => useViewAccountAddressQr.tsx} (86%) diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx index 486956de3a..1c8ddf1b5d 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx @@ -3,7 +3,7 @@ import { AccountProxy, AccountProxyType } from '@subwallet/extension-base/types'; import { AccountNetworkAddressItem, GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; -import { useGetAccountAddressDetail, useGetAccountNetworkAddresses, useNotification, useTranslation } from '@subwallet/extension-koni-ui/hooks'; +import { useGetAccountNetworkAddresses, useNotification, useTranslation, useViewAccountAddressQr } from '@subwallet/extension-koni-ui/hooks'; import { AccountNetworkAddress, ThemeProps } from '@subwallet/extension-koni-ui/types'; import { copyToClipboard } from '@subwallet/extension-koni-ui/utils'; import { Button, Icon, SwList } from '@subwallet/react-ui'; @@ -15,13 +15,13 @@ type Props = ThemeProps & { accountProxy: AccountProxy; }; -const isHide = false; +const isNotHide = false; function Component ({ accountProxy, className }: Props) { const { t } = useTranslation(); const items: AccountNetworkAddress[] = useGetAccountNetworkAddresses(accountProxy); const notify = useNotification(); - const { onSelectAccountSelector } = useGetAccountAddressDetail(); + const onSelectAccountSelector = useViewAccountAddressQr(); const onShowQr = useCallback((item: AccountNetworkAddress) => { return () => { @@ -78,7 +78,7 @@ function Component ({ accountProxy, className }: Props) { /> { - isHide && accountProxy.accountType === AccountProxyType.SOLO && ( + isNotHide && accountProxy.accountType === AccountProxyType.SOLO && (
- - ); diff --git a/packages/extension-koni-ui/src/components/Modal/Account/AccountNameModal.tsx b/packages/extension-koni-ui/src/components/Modal/Account/AccountNameModal.tsx index fad5511a15..ef2cb70dee 100644 --- a/packages/extension-koni-ui/src/components/Modal/Account/AccountNameModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/Account/AccountNameModal.tsx @@ -23,9 +23,7 @@ interface FormProps { name: string; } -const modalIdDefault = ACCOUNT_NAME_MODAL; - -const Component: React.FC = ({ accountType, className, isLoading, modalId, onSubmit }: Props) => { +const Component: React.FC = ({ accountType, className, isLoading, modalId = ACCOUNT_NAME_MODAL, onSubmit }: Props) => { const { t } = useTranslation(); const [form] = Form.useForm(); const defaultValues = useMemo(() => ({ @@ -52,7 +50,7 @@ const Component: React.FC = ({ accountType, className, isLoading, modalId ('Account name')} > diff --git a/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx b/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx index 333f43c55f..87bba8c638 100644 --- a/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx @@ -46,7 +46,7 @@ const Component: React.FC = ({ className }: Props) => { const { t } = useTranslation(); const notify = useNotification(); const sectionRef = useRef(null); - const [accountSelected, setAccountSelected] = useState(); + const [selectedAccount, setSelectedAccount] = useState(); const { activeModal, checkActive, inactiveModal } = useContext(ModalContext); const { setStateSelectAccount } = useSetSessionLatest(); const checkUnlock = useUnlockChecker(); @@ -78,7 +78,7 @@ const Component: React.FC = ({ className }: Props) => { const onSelectAccount = useCallback((account: AccountProxy): () => void => { return () => { checkUnlock().then(() => { - setAccountSelected(account); + setSelectedAccount(account); }).catch(() => { // User cancel unlock }); @@ -86,13 +86,13 @@ const Component: React.FC = ({ className }: Props) => { }, [checkUnlock]); const onSubmitAccount = useCallback((name: string) => { - if (accountSelected) { - setSelected(accountSelected.id); + if (selectedAccount) { + setSelected(selectedAccount.id); setTimeout(() => { deriveAccountV3({ - proxyId: accountSelected.id, + proxyId: selectedAccount.id, name, - suri: accountSelected.suri + suri: selectedAccount.suri }).then(() => { inactiveModal(modalId); setStateSelectAccount(true); @@ -108,13 +108,13 @@ const Component: React.FC = ({ className }: Props) => { }); }, 500); } - }, [accountSelected, clearSearch, inactiveModal, notify, setStateSelectAccount]); + }, [selectedAccount, clearSearch, inactiveModal, notify, setStateSelectAccount]); useEffect(() => { - if (accountSelected) { + if (selectedAccount) { activeModal(accountNameModalId); } - }, [accountSelected, activeModal]); + }, [selectedAccount, activeModal]); const renderItem = useCallback((account: AccountProxy): React.ReactNode => { const disabled = !!selected; @@ -159,7 +159,7 @@ const Component: React.FC = ({ className }: Props) => { Date: Tue, 20 Aug 2024 10:39:32 +0700 Subject: [PATCH 124/424] [Issue 3457] [fix] Extension - handle navigate modal when derive account --- .../src/Popup/Account/AttachReadOnly.tsx | 1 - .../src/Popup/Account/ImportPrivateKey.tsx | 1 - .../Modal/Account/AccountNameModal.tsx | 20 ++++++--- .../Modal/Account/DeriveAccountModal.tsx | 42 +++++++++---------- 4 files changed, 34 insertions(+), 30 deletions(-) diff --git a/packages/extension-koni-ui/src/Popup/Account/AttachReadOnly.tsx b/packages/extension-koni-ui/src/Popup/Account/AttachReadOnly.tsx index cac9b67d52..3fc0ec8238 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AttachReadOnly.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AttachReadOnly.tsx @@ -216,7 +216,6 @@ const Component: React.FC = ({ className }: Props) => { className='__account-name-input' disabled={loading} label={t('Account name')} - onBlur={form.submit} placeholder={t('Enter the account name')} />
diff --git a/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx b/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx index 235f8ef5d4..28240a52e3 100644 --- a/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx @@ -206,7 +206,6 @@ const Component: React.FC = ({ className }: Props) => { className='__account-name-input' disabled={loading} label={t('Account name')} - onBlur={form.submit} placeholder={t('Enter the account name')} /> diff --git a/packages/extension-koni-ui/src/components/Modal/Account/AccountNameModal.tsx b/packages/extension-koni-ui/src/components/Modal/Account/AccountNameModal.tsx index ef2cb70dee..220d58bb79 100644 --- a/packages/extension-koni-ui/src/components/Modal/Account/AccountNameModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/Account/AccountNameModal.tsx @@ -6,16 +6,18 @@ import { AccountProxyTypeTag } from '@subwallet/extension-koni-ui/components'; import { ACCOUNT_NAME_MODAL } from '@subwallet/extension-koni-ui/constants'; import { useTranslation } from '@subwallet/extension-koni-ui/hooks'; import { FormCallbacks, ThemeProps } from '@subwallet/extension-koni-ui/types'; -import { Button, Form, Icon, Input, SwModal } from '@subwallet/react-ui'; +import { Button, Form, Icon, Input, ModalContext, SwModal } from '@subwallet/react-ui'; import CN from 'classnames'; import { CheckCircle } from 'phosphor-react'; -import React, { useCallback, useMemo } from 'react'; +import React, { useCallback, useContext, useEffect, useMemo } from 'react'; import styled from 'styled-components'; type Props = ThemeProps & { isLoading?: boolean; accountType?: AccountProxyType; // for display account proxy tag onSubmit?: (name: string) => void; + onCancel?: () => void; + closeable?: boolean; modalId?: string; }; @@ -23,9 +25,11 @@ interface FormProps { name: string; } -const Component: React.FC = ({ accountType, className, isLoading, modalId = ACCOUNT_NAME_MODAL, onSubmit }: Props) => { +const Component: React.FC = ({ accountType, className, isLoading, onSubmit, onCancel, closeable = false, modalId = ACCOUNT_NAME_MODAL }: Props) => { const { t } = useTranslation(); const [form] = Form.useForm(); + const { checkActive } = useContext(ModalContext); + const isActive = useMemo(() => checkActive(modalId), [checkActive, modalId]); const defaultValues = useMemo(() => ({ name: '' }), []); @@ -46,12 +50,19 @@ const Component: React.FC = ({ accountType, className, isLoading, modalId onSubmit?.(name); }, [onSubmit]); + useEffect(() => { + if (!isActive) { + form.resetFields(['name']); + } + }, [form, isActive]); + return ( ('Account name')} >
@@ -85,7 +96,6 @@ const Component: React.FC = ({ accountType, className, isLoading, modalId className='__account-name-input' disabled={isLoading} label={t('Account name')} - onBlur={form.submit} placeholder={t('Enter the account name')} /> diff --git a/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx b/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx index 87bba8c638..c460d4a7d9 100644 --- a/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/Account/DeriveAccountModal.tsx @@ -9,13 +9,11 @@ import { useSetSessionLatest } from '@subwallet/extension-koni-ui/hooks'; import useNotification from '@subwallet/extension-koni-ui/hooks/common/useNotification'; import useTranslation from '@subwallet/extension-koni-ui/hooks/common/useTranslation'; import useUnlockChecker from '@subwallet/extension-koni-ui/hooks/common/useUnlockChecker'; -import useClickOutSide from '@subwallet/extension-koni-ui/hooks/dom/useClickOutSide'; import useSwitchModal from '@subwallet/extension-koni-ui/hooks/modal/useSwitchModal'; import { deriveAccountV3 } from '@subwallet/extension-koni-ui/messaging'; import { RootState } from '@subwallet/extension-koni-ui/stores'; import { ThemeProps } from '@subwallet/extension-koni-ui/types'; import { searchAccountFunction } from '@subwallet/extension-koni-ui/utils/account/account'; -import { renderModalSelector } from '@subwallet/extension-koni-ui/utils/common/dom'; import { ActivityIndicator, ModalContext, SwList, SwModal } from '@subwallet/react-ui'; import { SwListSectionRef } from '@subwallet/react-ui/es/sw-list'; import CN from 'classnames'; @@ -47,16 +45,13 @@ const Component: React.FC = ({ className }: Props) => { const notify = useNotification(); const sectionRef = useRef(null); const [selectedAccount, setSelectedAccount] = useState(); - const { activeModal, checkActive, inactiveModal } = useContext(ModalContext); + const [loading, setLoading] = useState(false); + const { activeModal, inactiveModal } = useContext(ModalContext); const { setStateSelectAccount } = useSetSessionLatest(); const checkUnlock = useUnlockChecker(); const accountProxies = useSelector((state: RootState) => state.accountState.accountProxies); - const isActive = checkActive(modalId); - - const [selected, setSelected] = useState(''); - const filtered = useMemo( () => accountProxies .filter(({ accountActions }) => accountActions.includes(AccountActions.DERIVE)), @@ -67,14 +62,6 @@ const Component: React.FC = ({ className }: Props) => { sectionRef.current?.setSearchValue(''); }, []); - const onCancel = useCallback(() => { - setStateSelectAccount(true); - inactiveModal(modalId); - clearSearch(); - }, [clearSearch, inactiveModal, setStateSelectAccount]); - - useClickOutSide(isActive || !!selected, renderModalSelector(className), onCancel); - const onSelectAccount = useCallback((account: AccountProxy): () => void => { return () => { checkUnlock().then(() => { @@ -87,7 +74,7 @@ const Component: React.FC = ({ className }: Props) => { const onSubmitAccount = useCallback((name: string) => { if (selectedAccount) { - setSelected(selectedAccount.id); + setLoading(true); setTimeout(() => { deriveAccountV3({ proxyId: selectedAccount.id, @@ -103,7 +90,8 @@ const Component: React.FC = ({ className }: Props) => { type: 'error' }); }).finally(() => { - setSelected(''); + setLoading(false); + setSelectedAccount(undefined); inactiveModal(accountNameModalId); }); }, 500); @@ -117,8 +105,8 @@ const Component: React.FC = ({ className }: Props) => { }, [selectedAccount, activeModal]); const renderItem = useCallback((account: AccountProxy): React.ReactNode => { - const disabled = !!selected; - const isSelected = account.id === selected; + const disabled = !!selectedAccount?.id; + const isSelected = account.id === selectedAccount?.id; return ( @@ -131,18 +119,24 @@ const Component: React.FC = ({ className }: Props) => { /> ); - }, [onSelectAccount, selected]); + }, [onSelectAccount, selectedAccount?.id]); const onBack = useSwitchModal(modalId, CREATE_ACCOUNT_MODAL, clearSearch); + const onAccountNameModalCancel = useCallback(() => { + setSelectedAccount(undefined); + inactiveModal(accountNameModalId); + activeModal(modalId); + }, [activeModal, inactiveModal]); + return ( <> )} id={modalId} - maskClosable={false} - onCancel={selected ? undefined : onBack} + maskClosable={true} + onCancel={selectedAccount ? undefined : onBack} title={t('Select account')} > = ({ className }: Props) => { From 77216d01ee144e9611831a0d85fcf52b46b171a1 Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Tue, 20 Aug 2024 14:21:02 +0700 Subject: [PATCH 125/424] [Issue-3449] feat: add real sending amount for getMaxTransferable. --- .../src/koni/background/handlers/Extension.ts | 2 +- .../balance-service/transfer/token.ts | 5 ++-- .../balance-service/transfer/ton-transfer.ts | 28 ++++--------------- 3 files changed, 9 insertions(+), 26 deletions(-) diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index 93b28dcfaa..58d6fb794a 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -1293,7 +1293,7 @@ export default class KoniExtension { to, networkKey, value: value || '0', - transferAll: !!transferAll, + transferAll: !!transferAll, // currently not used tonApi }); } else { diff --git a/packages/extension-base/src/services/balance-service/transfer/token.ts b/packages/extension-base/src/services/balance-service/transfer/token.ts index 3e830a250e..6a902c3d52 100644 --- a/packages/extension-base/src/services/balance-service/transfer/token.ts +++ b/packages/extension-base/src/services/balance-service/transfer/token.ts @@ -14,7 +14,7 @@ import { calculateGasFeeParams } from '@subwallet/extension-base/services/fee-se import { getGRC20ContractPromise, getVFTContractPromise } from '@subwallet/extension-base/utils'; import { keyring } from '@subwallet/ui-keyring'; import { internal } from '@ton/core'; -import { WalletContractV4 } from '@ton/ton'; +import {Address, WalletContractV4} from '@ton/ton'; import BigN from 'bignumber.js'; import { TransactionConfig } from 'web3-core'; @@ -150,10 +150,11 @@ export const getTransferMockTxFee = async (address: string, chainInfo: _ChainInf } else if (_isChainTonCompatible(chainInfo) && _isTokenTransferredByTon(tokenInfo)) { const keyPair = keyring.getPair(address); const tonApi = api as _TonApi; + const maxBlance = await tonApi.getBalance(Address.parse(address)); const mockMessage = internal({ to: address, // anyAddress - value: '0.05', // anyValue + value: maxBlance, // estimate value bounce: false // anyMode }); diff --git a/packages/extension-base/src/services/balance-service/transfer/ton-transfer.ts b/packages/extension-base/src/services/balance-service/transfer/ton-transfer.ts index ac66c12f67..1a57559a3e 100644 --- a/packages/extension-base/src/services/balance-service/transfer/ton-transfer.ts +++ b/packages/extension-base/src/services/balance-service/transfer/ton-transfer.ts @@ -8,7 +8,7 @@ import { _TonApi } from '@subwallet/extension-base/services/chain-service/types' import { _getContractAddressOfToken, _isJettonToken, _isNativeToken } from '@subwallet/extension-base/services/chain-service/utils'; import { keyring } from '@subwallet/ui-keyring'; import { beginCell, fromNano, internal, MessageRelaxed, toNano } from '@ton/core'; -import { Address, JettonMaster, JettonWallet, WalletContractV4 } from '@ton/ton'; +import { Address, JettonMaster, WalletContractV4 } from '@ton/ton'; interface TonTransactionConfigProps { tokenInfo: _ChainAsset; @@ -43,15 +43,12 @@ export async function createTonTransaction ({ from, networkKey, to, tokenInfo, t return [null, value]; } -async function createTonNativeTransaction ({ from, networkKey, to, tonApi, transferAll, value }: TonTransactionConfigProps): Promise<[TonTransactionConfig | null, string]> { +async function createTonNativeTransaction ({ from, networkKey, to, tonApi, value }: TonTransactionConfigProps): Promise<[TonTransactionConfig | null, string]> { const keyPair = keyring.getPair(from); - const tonAddress = Address.parse(from); const walletContract = WalletContractV4.create({ workchain: WORKCHAIN, publicKey: Buffer.from(keyPair.publicKey) }); const contract = tonApi.open(walletContract); const seqno = await contract.getSeqno(); - let transferValue: string | undefined; - const messages = internal({ to: to, @@ -63,17 +60,11 @@ async function createTonNativeTransaction ({ from, networkKey, to, tonApi, trans const estimateExternalFee = await estimateTonTxFee(tonApi, [messages], walletContract); - if (transferAll) { - const balance = await tonApi.getBalance(tonAddress); - - transferValue = (balance - estimateExternalFee).toString(); - } - const transactionObject = { from, to, networkKey, - value: transferValue ?? value, + value: value, messagePayload, messages: [messages], estimateFee: estimateExternalFee.toString(), @@ -83,7 +74,7 @@ async function createTonNativeTransaction ({ from, networkKey, to, tonApi, trans return [transactionObject, transactionObject.value]; } -async function createJettonTransaction ({ from, networkKey, to, tokenInfo, tonApi, transferAll, value }: TonTransactionConfigProps): Promise<[TonTransactionConfig | null, string]> { +async function createJettonTransaction ({ from, networkKey, to, tokenInfo, tonApi, value }: TonTransactionConfigProps): Promise<[TonTransactionConfig | null, string]> { const keyPair = keyring.getPair(from); const sendertonAddress = Address.parse(from); const destinationAddress = Address.parse(to); @@ -91,13 +82,10 @@ async function createJettonTransaction ({ from, networkKey, to, tokenInfo, tonAp const contract = tonApi.open(walletContract); const seqno = await contract.getSeqno(); - let transferValue: string | undefined; - // retrieve jetton info const jettonContractAddress = Address.parse(_getContractAddressOfToken(tokenInfo)); const jettonMasterContract = tonApi.open(JettonMaster.create(jettonContractAddress)); const jettonWalletAddress = await jettonMasterContract.getWalletAddress(sendertonAddress); - const jettonWalletContract = tonApi.open(JettonWallet.create(jettonWalletAddress)); const messageBody = beginCell() .storeUint(TON_OPCODES.JETTON_TRANSFER, 32) // opcode for jetton transfer @@ -123,17 +111,11 @@ async function createJettonTransaction ({ from, networkKey, to, tokenInfo, tonAp const estimateExternalFee = await estimateTonTxFee(tonApi, [messages], walletContract); const estimateFee = toNano(INIT_FEE_JETTON_TRANSFER) > estimateExternalFee ? toNano(INIT_FEE_JETTON_TRANSFER) : estimateExternalFee; - if (transferAll) { - const balance = await jettonWalletContract.getBalance(); - - transferValue = (balance - estimateFee).toString(); - } - const transactionObject = { from, to, networkKey, - value: transferValue ?? value, + value, messagePayload, messages: [messages], estimateFee: estimateFee.toString(), From 36cfdedbd21c6b6bd13f800282b56f686cd7a0f1 Mon Sep 17 00:00:00 2001 From: S2kael Date: Tue, 20 Aug 2024 15:30:05 +0700 Subject: [PATCH 126/424] [Issue-3472] Add subscribe input handler --- .../src/background/KoniTypes.ts | 6 +- .../src/koni/background/handlers/Extension.ts | 42 +++- .../src/services/chain-service/utils/index.ts | 21 ++ .../context/account-context.ts | 4 + .../services/keyring-service/context/state.ts | 28 ++- .../src/types/account/action/index.ts | 1 + .../src/types/account/action/subscribe.ts | 20 ++ .../src/types/account/info/keyring.ts | 1 + .../src/utils/account/analyze.ts | 184 ++++++++++++++++++ .../extension-base/src/utils/account/index.ts | 1 + .../src/utils/account/transform.ts | 56 ++++-- .../src/messaging/accounts/legacy.ts | 7 +- 12 files changed, 334 insertions(+), 37 deletions(-) create mode 100644 packages/extension-base/src/types/account/action/subscribe.ts create mode 100644 packages/extension-base/src/utils/account/analyze.ts diff --git a/packages/extension-base/src/background/KoniTypes.ts b/packages/extension-base/src/background/KoniTypes.ts index 55f084951b..e600584b33 100644 --- a/packages/extension-base/src/background/KoniTypes.ts +++ b/packages/extension-base/src/background/KoniTypes.ts @@ -12,7 +12,9 @@ import { AppBannerData, AppConfirmationData, AppPopupData } from '@subwallet/ext import { CrowdloanContributionsResponse } from '@subwallet/extension-base/services/subscan-service/types'; import { SWTransactionResponse, SWTransactionResult } from '@subwallet/extension-base/services/transaction-service/types'; import { WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; -import { AccountJson, AccountsWithCurrentAddress, AddressJson, BalanceJson, BuyServiceInfo, BuyTokenInfo, CurrentAccountInfo, EarningRewardHistoryItem, EarningRewardJson, EarningStatus, HandleYieldStepParams, LeavePoolAdditionalData, NominationPoolInfo, OptimalYieldPath, OptimalYieldPathParams, RequestAccountCreateSuriV2, RequestCheckPublicAndSecretKey, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestEarlyValidateYield, RequestExportAccountProxyMnemonic, RequestGetDeriveAccounts, RequestGetYieldPoolTargets, RequestMetadataHash, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseAccountCreateSuriV2, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseEarlyValidateYield, ResponseExportAccountProxyMnemonic, ResponseGetDeriveAccounts, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2, ResponseShortenMetadata, StorageDataInterface, SubmitYieldStepData, TokenSpendingApprovalParams, UnlockDotTransactionNft, UnstakingStatus, ValidateYieldProcessParams, YieldPoolInfo, YieldPositionInfo, YieldValidationStatus } from '@subwallet/extension-base/types'; +import { + AccountJson, AccountsWithCurrentAddress, AddressJson, BalanceJson, BuyServiceInfo, BuyTokenInfo, CurrentAccountInfo, EarningRewardHistoryItem, EarningRewardJson, EarningStatus, HandleYieldStepParams, LeavePoolAdditionalData, NominationPoolInfo, OptimalYieldPath, OptimalYieldPathParams, RequestAccountCreateSuriV2, RequestCheckPublicAndSecretKey, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestEarlyValidateYield, RequestExportAccountProxyMnemonic, RequestGetDeriveAccounts, RequestGetYieldPoolTargets, RequestInputAccountSubscribe, RequestMetadataHash, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseAccountCreateSuriV2, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseEarlyValidateYield, ResponseExportAccountProxyMnemonic, ResponseGetDeriveAccounts, ResponseGetYieldPoolTargets, ResponseInputAccountSubscribe, ResponseMetadataHash, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2, ResponseShortenMetadata, StorageDataInterface, SubmitYieldStepData, TokenSpendingApprovalParams, UnlockDotTransactionNft, UnstakingStatus, ValidateYieldProcessParams, YieldPoolInfo, YieldPositionInfo, YieldValidationStatus +} from '@subwallet/extension-base/types'; import { RequestAccountProxyEdit, RequestAccountProxyForget } from '@subwallet/extension-base/types/account/action/edit'; import { CommonOptimalPath } from '@subwallet/extension-base/types/service-base'; import { SwapErrorType, SwapPair, SwapQuoteResponse, SwapRequest, SwapRequestResult, SwapSubmitParams, SwapTxData, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap'; @@ -2077,7 +2079,7 @@ export interface KoniRequestSignatures { 'pri(accounts.resolveAddressToDomain)': [ResolveAddressToDomainRequest, string | undefined]; // For input UI - 'pri(accounts.subscribeAccountsInputAddress)': [RequestAccountSubscribe, string, OptionInputAddress]; + 'pri(accounts.subscribeAccountsInputAddress)': [RequestInputAccountSubscribe, ResponseInputAccountSubscribe, ResponseInputAccountSubscribe]; /* Account management */ diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index 9e1017ad69..a09fc3149f 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -7,7 +7,7 @@ import { _AssetRef, _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError'; import { withErrorLog } from '@subwallet/extension-base/background/handlers/helpers'; import { createSubscription } from '@subwallet/extension-base/background/handlers/subscriptions'; -import { AccountExternalError, AddressBookInfo, AmountData, AmountDataWithId, AssetSetting, AssetSettingUpdateReq, BasicTxErrorType, BondingOptionParams, BrowserConfirmationType, CampaignBanner, CampaignData, CampaignDataType, ChainType, CronReloadRequest, CrowdloanJson, ExternalRequestPromiseStatus, ExtrinsicType, KeyringState, MantaPayEnableMessage, MantaPayEnableParams, MantaPayEnableResponse, MantaPaySyncState, MetadataItem, NftCollection, NftJson, NftTransactionRequest, NftTransactionResponse, OptionInputAddress, PriceJson, RequestAccountBatchExportV2, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateWithSecretKey, RequestAccountExportPrivateKey, RequestAddInjectedAccounts, RequestApproveConnectWalletSession, RequestApproveWalletConnectNotSupport, RequestAuthorization, RequestAuthorizationBlock, RequestAuthorizationPerAccount, RequestAuthorizationPerSite, RequestAuthorizeApproveV2, RequestBatchRestoreV2, RequestBondingSubmit, RequestCameraSettings, RequestCampaignBannerComplete, RequestChangeEnableChainPatrol, RequestChangeLanguage, RequestChangeMasterPassword, RequestChangePriceCurrency, RequestChangeShowBalance, RequestChangeShowZeroBalance, RequestChangeTimeAutoLock, RequestConfirmationComplete, RequestConnectWalletConnect, RequestCrossChainTransfer, RequestCrowdloanContributions, RequestDeleteContactAccount, RequestDisconnectWalletConnectSession, RequestEditContactAccount, RequestFindRawMetadata, RequestForgetSite, RequestFreeBalance, RequestGetTransaction, RequestJsonRestoreV2, RequestKeyringExportMnemonic, RequestMaxTransferable, RequestMigratePassword, RequestParseEvmContractInput, RequestParseTransactionSubstrate, RequestPassPhishingPage, RequestQrParseRLP, RequestQrSignEvm, RequestQrSignSubstrate, RequestRejectConnectWalletSession, RequestRejectExternalRequest, RequestRejectWalletConnectNotSupport, RequestRemoveInjectedAccounts, RequestResetWallet, RequestResolveExternalRequest, RequestSaveRecentAccount, RequestSettingsType, RequestSigningApprovePasswordV2, RequestStakePoolingBonding, RequestStakePoolingUnbonding, RequestSubscribeHistory, RequestSubstrateNftSubmitTransaction, RequestTransfer, RequestTuringCancelStakeCompound, RequestTuringStakeCompound, RequestUnbondingSubmit, RequestUnlockKeyring, RequestUnlockType, ResolveAddressToDomainRequest, ResolveDomainRequest, ResponseAccountBatchExportV2, ResponseAccountCreateWithSecretKey, ResponseAccountExportPrivateKey, ResponseChangeMasterPassword, ResponseFindRawMetadata, ResponseKeyringExportMnemonic, ResponseMigratePassword, ResponseParseEvmContractInput, ResponseParseTransactionSubstrate, ResponseQrParseRLP, ResponseQrSignEvm, ResponseQrSignSubstrate, ResponseRejectExternalRequest, ResponseResetWallet, ResponseResolveExternalRequest, ResponseSubscribeHistory, ResponseUnlockKeyring, ShowCampaignPopupRequest, StakingJson, StakingRewardJson, StakingTxErrorType, StakingType, ThemeNames, TransactionHistoryItem, TransactionResponse, ValidateNetworkRequest, ValidateNetworkResponse, ValidatorInfo } from '@subwallet/extension-base/background/KoniTypes'; +import { AccountExternalError, AddressBookInfo, AmountData, AmountDataWithId, AssetSetting, AssetSettingUpdateReq, BasicTxErrorType, BondingOptionParams, BrowserConfirmationType, CampaignBanner, CampaignData, CampaignDataType, ChainType, CronReloadRequest, CrowdloanJson, ExternalRequestPromiseStatus, ExtrinsicType, KeyringState, MantaPayEnableMessage, MantaPayEnableParams, MantaPayEnableResponse, MantaPaySyncState, MetadataItem, NftCollection, NftJson, NftTransactionRequest, NftTransactionResponse, PriceJson, RequestAccountBatchExportV2, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateWithSecretKey, RequestAccountExportPrivateKey, RequestAddInjectedAccounts, RequestApproveConnectWalletSession, RequestApproveWalletConnectNotSupport, RequestAuthorization, RequestAuthorizationBlock, RequestAuthorizationPerAccount, RequestAuthorizationPerSite, RequestAuthorizeApproveV2, RequestBatchRestoreV2, RequestBondingSubmit, RequestCameraSettings, RequestCampaignBannerComplete, RequestChangeEnableChainPatrol, RequestChangeLanguage, RequestChangeMasterPassword, RequestChangePriceCurrency, RequestChangeShowBalance, RequestChangeShowZeroBalance, RequestChangeTimeAutoLock, RequestConfirmationComplete, RequestConnectWalletConnect, RequestCrossChainTransfer, RequestCrowdloanContributions, RequestDeleteContactAccount, RequestDisconnectWalletConnectSession, RequestEditContactAccount, RequestFindRawMetadata, RequestForgetSite, RequestFreeBalance, RequestGetTransaction, RequestJsonRestoreV2, RequestKeyringExportMnemonic, RequestMaxTransferable, RequestMigratePassword, RequestParseEvmContractInput, RequestParseTransactionSubstrate, RequestPassPhishingPage, RequestQrParseRLP, RequestQrSignEvm, RequestQrSignSubstrate, RequestRejectConnectWalletSession, RequestRejectExternalRequest, RequestRejectWalletConnectNotSupport, RequestRemoveInjectedAccounts, RequestResetWallet, RequestResolveExternalRequest, RequestSaveRecentAccount, RequestSettingsType, RequestSigningApprovePasswordV2, RequestStakePoolingBonding, RequestStakePoolingUnbonding, RequestSubscribeHistory, RequestSubstrateNftSubmitTransaction, RequestTransfer, RequestTuringCancelStakeCompound, RequestTuringStakeCompound, RequestUnbondingSubmit, RequestUnlockKeyring, RequestUnlockType, ResolveAddressToDomainRequest, ResolveDomainRequest, ResponseAccountBatchExportV2, ResponseAccountCreateWithSecretKey, ResponseAccountExportPrivateKey, ResponseChangeMasterPassword, ResponseFindRawMetadata, ResponseKeyringExportMnemonic, ResponseMigratePassword, ResponseParseEvmContractInput, ResponseParseTransactionSubstrate, ResponseQrParseRLP, ResponseQrSignEvm, ResponseQrSignSubstrate, ResponseRejectExternalRequest, ResponseResetWallet, ResponseResolveExternalRequest, ResponseSubscribeHistory, ResponseUnlockKeyring, ShowCampaignPopupRequest, StakingJson, StakingRewardJson, StakingTxErrorType, StakingType, ThemeNames, TransactionHistoryItem, TransactionResponse, ValidateNetworkRequest, ValidateNetworkResponse, ValidatorInfo } from '@subwallet/extension-base/background/KoniTypes'; import { AccountAuthType, AuthorizeRequest, MessageTypes, MetadataRequest, RequestAccountExport, RequestAuthorizeCancel, RequestAuthorizeReject, RequestCurrentAccountAddress, RequestMetadataApprove, RequestMetadataReject, RequestSigningApproveSignature, RequestSigningCancel, RequestTypes, ResponseAccountExport, ResponseAuthorizeList, ResponseJsonGetAccountInfo, ResponseType, SigningRequest, WindowOpenParams } from '@subwallet/extension-base/background/types'; import { TransactionWarning } from '@subwallet/extension-base/background/warnings/TransactionWarning'; import { ALL_ACCOUNT_KEY, LATEST_SESSION, XCM_FEE_RATIO } from '@subwallet/extension-base/constants'; @@ -42,11 +42,11 @@ import { isProposalExpired, isSupportWalletConnectChain, isSupportWalletConnectN import { ResultApproveWalletConnectSession, WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; import { SWStorage } from '@subwallet/extension-base/storage'; import { AccountsStore } from '@subwallet/extension-base/stores'; -import { AccountJson, AccountsWithCurrentAddress, BalanceJson, BuyServiceInfo, BuyTokenInfo, EarningRewardJson, NominationPoolInfo, OptimalYieldPathParams, RequestAccountCreateSuriV2, RequestCheckPublicAndSecretKey, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestEarlyValidateYield, RequestExportAccountProxyMnemonic, RequestGetDeriveAccounts, RequestGetYieldPoolTargets, RequestMetadataHash, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseAccountCreateSuriV2, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseExportAccountProxyMnemonic, ResponseGetDeriveAccounts, ResponseGetYieldPoolTargets, ResponseMetadataHash, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2, ResponseShortenMetadata, StorageDataInterface, TokenSpendingApprovalParams, ValidateYieldProcessParams, YieldPoolType } from '@subwallet/extension-base/types'; +import { AccountJson, AccountProxyMap, AccountsWithCurrentAddress, BalanceJson, BuyServiceInfo, BuyTokenInfo, EarningRewardJson, NominationPoolInfo, OptimalYieldPathParams, RequestAccountCreateSuriV2, RequestCheckPublicAndSecretKey, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestEarlyValidateYield, RequestExportAccountProxyMnemonic, RequestGetDeriveAccounts, RequestGetYieldPoolTargets, RequestInputAccountSubscribe, RequestMetadataHash, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseAccountCreateSuriV2, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseExportAccountProxyMnemonic, ResponseGetDeriveAccounts, ResponseGetYieldPoolTargets, ResponseInputAccountSubscribe, ResponseMetadataHash, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2, ResponseShortenMetadata, StorageDataInterface, TokenSpendingApprovalParams, ValidateYieldProcessParams, YieldPoolType } from '@subwallet/extension-base/types'; import { RequestAccountProxyEdit, RequestAccountProxyForget } from '@subwallet/extension-base/types/account/action/edit'; import { CommonOptimalPath } from '@subwallet/extension-base/types/service-base'; import { SwapPair, SwapQuoteResponse, SwapRequest, SwapRequestResult, SwapSubmitParams, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap'; -import { BN_ZERO, combineAllAccountProxy, createTransactionFromRLP, isSameAddress, MODULE_SUPPORT, reformatAddress, signatureToHex, Transaction as QrTransaction, transformAccounts, transformAddresses, uniqueStringArray } from '@subwallet/extension-base/utils'; +import { _analyzeAddress, BN_ZERO, combineAllAccountProxy, createTransactionFromRLP, isSameAddress, MODULE_SUPPORT, reformatAddress, signatureToHex, Transaction as QrTransaction, transformAccounts, transformAddresses, uniqueStringArray } from '@subwallet/extension-base/utils'; import { parseContractInput, parseEvmRlp } from '@subwallet/extension-base/utils/eth/parseTransaction'; import { metadataExpand } from '@subwallet/extension-chains'; import { MetadataDef } from '@subwallet/extension-inject/types'; @@ -316,14 +316,32 @@ export default class KoniExtension { return responseData; } - private accountsGetAll (id: string, port: chrome.runtime.Port): string { + private async subscribeInputAddressData (request: RequestInputAccountSubscribe, id: string, port: chrome.runtime.Port): Promise { + const { chain, data } = request; + const cb = createSubscription<'pri(accounts.subscribeAccountsInputAddress)'>(id, port); - const subscription = keyring.keyringOption.optionsSubject.subscribe((options): void => { - const optionsInputAddress: OptionInputAddress = { - options + + const combineFunction = async (chainInfoMap: Record, accountProxyMap: AccountProxyMap, _contacts: SubjectInfo): Promise => { + const accountProxies = Object.values(accountProxyMap); + const contacts = transformAddresses(_contacts); + const chainInfo = chainInfoMap[chain]; + const substrateApi = this.#koniState.chainService.getSubstrateApi(chain); + const rs = await _analyzeAddress(data, accountProxies, contacts, chainInfo, substrateApi); + + return { + id, + ...rs }; + }; - cb(optionsInputAddress); + const accountObservable = this.#koniState.keyringService.context.observable.accounts; + const contactObservable = this.#koniState.keyringService.context.observable.contacts; + const chainInfoMapObservable = this.#koniState.chainService.subscribeChainInfoMap().asObservable(); + + const subscription = combineLatest({ chainInfoMap: chainInfoMapObservable, accountProxies: accountObservable, contacts: contactObservable }).subscribe(async ({ accountProxies, chainInfoMap, contacts }) => { + const rs = await combineFunction(chainInfoMap, accountProxies, contacts); + + cb(rs); }); this.createUnsubscriptionHandle(id, () => { @@ -334,7 +352,11 @@ export default class KoniExtension { this.cancelSubscription(id); }); - return id; + const accountProxyMap = this.#koniState.keyringService.context.value.accounts; + const contacts = this.#koniState.keyringService.context.value.contacts; + const chainInfoMap = this.#koniState.chainService.getChainInfoMap(); + + return combineFunction(chainInfoMap, accountProxyMap, contacts); } /** @@ -3802,7 +3824,7 @@ export default class KoniExtension { case 'pri(accounts.subscribeWithCurrentProxy)': return await this.accountsGetAllWithCurrentAddress(id, port); case 'pri(accounts.subscribeAccountsInputAddress)': - return this.accountsGetAll(id, port); + return this.subscribeInputAddressData(request as RequestInputAccountSubscribe, id, port); // Save current account case 'pri(accounts.saveCurrentProxy)': diff --git a/packages/extension-base/src/services/chain-service/utils/index.ts b/packages/extension-base/src/services/chain-service/utils/index.ts index bd3cecc2c5..9376064a8a 100644 --- a/packages/extension-base/src/services/chain-service/utils/index.ts +++ b/packages/extension-base/src/services/chain-service/utils/index.ts @@ -6,6 +6,7 @@ import { BasicTokenInfo } from '@subwallet/extension-base/background/KoniTypes'; import { _MANTA_ZK_CHAIN_GROUP, _ZK_ASSET_PREFIX } from '@subwallet/extension-base/services/chain-service/constants'; import { _ChainState, _CUSTOM_PREFIX, _DataMap, _SMART_CONTRACT_STANDARDS } from '@subwallet/extension-base/services/chain-service/types'; import { IChain } from '@subwallet/extension-base/services/storage-service/databases'; +import { AccountChainType } from '@subwallet/extension-base/types'; import { isEthereumAddress } from '@polkadot/util-crypto'; @@ -602,4 +603,24 @@ export function updateLatestChainInfo (currentDataMap: _DataMap, latestChainInfo }; } +export const _chainInfoToChainType = (chainInfo: _ChainInfo): AccountChainType => { + if (_isPureSubstrateChain(chainInfo)) { + return AccountChainType.SUBSTRATE; + } + + if (_isChainEvmCompatible(chainInfo)) { + return AccountChainType.ETHEREUM; + } + + if (_isChainTonCompatible(chainInfo)) { + return AccountChainType.TON; + } + + if (_isChainBitcoinCompatible(chainInfo)) { + return AccountChainType.BITCOIN; + } + + return AccountChainType.SUBSTRATE; +}; + export * from './patch'; diff --git a/packages/extension-base/src/services/keyring-service/context/account-context.ts b/packages/extension-base/src/services/keyring-service/context/account-context.ts index 0db873043a..4c68b3d28f 100644 --- a/packages/extension-base/src/services/keyring-service/context/account-context.ts +++ b/packages/extension-base/src/services/keyring-service/context/account-context.ts @@ -42,6 +42,10 @@ export class AccountContext { return this.state.observable; } + get value () { + return this.state.value; + } + get contacts (): SubjectInfo { return this.state.contacts; } diff --git a/packages/extension-base/src/services/keyring-service/context/state.ts b/packages/extension-base/src/services/keyring-service/context/state.ts index b84b95aa5e..87bb2e3c86 100644 --- a/packages/extension-base/src/services/keyring-service/context/state.ts +++ b/packages/extension-base/src/services/keyring-service/context/state.ts @@ -97,7 +97,7 @@ export class AccountState { const result = combineAccounts(pairs, modifyPairs, accountGroups, chainInfoMap); this.accountSubject.next(result); - }, 300, 1800, false); + }, 300, 1800, true); }); } @@ -129,6 +129,32 @@ export class AccountState { return this._modifyPair.value; } + get value () { + const pairs = this.pairSubject; + const accounts = this.accountSubject; + const accountProxy = this._accountProxy; + const currentAccount = this._currentAccount; + const contacts = this.contactSubject; + + return { + get pairs () { + return pairs.value; + }, + get accounts () { + return accounts.value; + }, + get accountProxy () { + return accountProxy.value; + }, + get currentAccount () { + return currentAccount.value; + }, + get contacts () { + return contacts.value; + } + }; + } + get observable () { const pairs = this.pairSubject; const accounts = this.accountSubject; diff --git a/packages/extension-base/src/types/account/action/index.ts b/packages/extension-base/src/types/account/action/index.ts index 1d9830fbfc..ba20043e17 100644 --- a/packages/extension-base/src/types/account/action/index.ts +++ b/packages/extension-base/src/types/account/action/index.ts @@ -5,3 +5,4 @@ export * from './add'; export * from './derive'; export * from './edit'; export * from './export'; +export * from './subscribe'; diff --git a/packages/extension-base/src/types/account/action/subscribe.ts b/packages/extension-base/src/types/account/action/subscribe.ts new file mode 100644 index 0000000000..4217f6c816 --- /dev/null +++ b/packages/extension-base/src/types/account/action/subscribe.ts @@ -0,0 +1,20 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export interface RequestInputAccountSubscribe { + data: string; + chain: string; +} + +export interface AnalyzeAddress { + address: string; + domainName?: string; + accountName?: string; + displayName?: string; +} + +export interface ResponseInputAccountSubscribe { + id: string; + options: AnalyzeAddress[]; + current?: AnalyzeAddress; +} diff --git a/packages/extension-base/src/types/account/info/keyring.ts b/packages/extension-base/src/types/account/info/keyring.ts index 5eea57f44c..8865040f0a 100644 --- a/packages/extension-base/src/types/account/info/keyring.ts +++ b/packages/extension-base/src/types/account/info/keyring.ts @@ -162,6 +162,7 @@ export interface AccountJson extends AbstractAddressJson, AccountMetadataData, A } export interface AddressJson extends AbstractAddressJson { + chainType: AccountChainType; isRecent?: boolean; recentChainSlugs?: string[]; } diff --git a/packages/extension-base/src/utils/account/analyze.ts b/packages/extension-base/src/utils/account/analyze.ts new file mode 100644 index 0000000000..4e28a6a718 --- /dev/null +++ b/packages/extension-base/src/utils/account/analyze.ts @@ -0,0 +1,184 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { _ChainInfo } from '@subwallet/chain-list/types'; +import { resolveAzeroAddressToDomain, resolveAzeroDomainToAddress } from '@subwallet/extension-base/koni/api/dotsama/domain'; +import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; +import { _chainInfoToChainType, _getChainSubstrateAddressPrefix } from '@subwallet/extension-base/services/chain-service/utils'; +import { AbstractAddressJson, AccountChainType, AccountProxy, AddressJson, AnalyzeAddress, ResponseInputAccountSubscribe } from '@subwallet/extension-base/types'; + +import { isAddress } from '@polkadot/util-crypto'; + +import { reformatAddress } from './common'; + +interface AddressDataJson extends AbstractAddressJson { + chainType: AccountChainType; +} + +type ValidDataType = 'invalid' | 'valid' | 'extracted'; + +// TODO: Re-confirm to compare without +const isStrValidWithAddress = (str: string, account: AddressDataJson, chainInfo: _ChainInfo): ValidDataType => { + if (account.chainType === AccountChainType.SUBSTRATE) { + const reformated = reformatAddress(account.address, _getChainSubstrateAddressPrefix(chainInfo)); + + if (account.address.toLowerCase() === str || reformated.toLowerCase() === str) { + return 'extracted'; + } else if (account.address.toLowerCase().includes(str) || reformated.toLowerCase().includes(str)) { + return 'valid'; + } + } else if (account.chainType === AccountChainType.TON) { + const isTestnet = chainInfo.isTestnet; + const reformated = reformatAddress(account.address, isTestnet ? 0 : 1); + + if (account.address.toLowerCase() === str || reformated.toLowerCase() === str) { + return 'extracted'; + } else if (account.address.toLowerCase().includes(str) || reformated.toLowerCase().includes(str)) { + return 'valid'; + } + } else { + if (account.address.toLowerCase() === str) { + return 'extracted'; + } else if (account.address.toLowerCase().includes(str)) { + return 'valid'; + } + } + + return 'invalid'; +}; + +const isNameValid = (str: string, name: string): ValidDataType => { + if (name === str) { + return 'extracted'; + } else if (name.includes(str)) { + return 'valid'; + } else { + return 'invalid'; + } +}; + +export const _analyzeAddress = async (data: string, accountProxies: AccountProxy[], contacts: AddressJson[], chainInfo: _ChainInfo, substrateApi?: _SubstrateApi): Promise> => { + const chain = chainInfo.slug; + const _data = data.trim().toLowerCase(); + const options: AnalyzeAddress[] = []; + const currentChainType = _chainInfoToChainType(chainInfo); + let current: AnalyzeAddress | undefined; + + // Filter account proxies + for (const accountProxy of accountProxies) { + const _name = accountProxy.name.trim().toLowerCase(); + const nameCondition = isNameValid(_data, _name); + const filterAccounts = accountProxy.accounts.filter((account) => account.chainType === currentChainType); + + for (const account of filterAccounts) { + const addressCondition = isStrValidWithAddress(_data, account, chainInfo); + const condition = nameCondition !== 'invalid' ? nameCondition : addressCondition; + + const rs: AnalyzeAddress = { + address: account.address, + accountName: accountProxy.name, + displayName: accountProxy.name + }; + + if (condition !== 'invalid') { + if (account.specialChain) { + if (account.specialChain === chain) { + options.push(rs); + + if (condition === 'extracted') { + current = rs; + } + } + } else { + options.push(rs); + + if (condition === 'extracted') { + current = rs; + } + } + } + } + } + + const filterContacts = contacts.filter((contact) => contact.chainType === currentChainType); + + // Filter address book addresses + for (const contact of filterContacts) { + const name = contact?.name || ''; + const _name = name.trim().toLowerCase(); + const nameCondition = isNameValid(_data, _name); + const addressCondition = isStrValidWithAddress(_data, contact, chainInfo); + const condition = nameCondition !== 'invalid' ? nameCondition : addressCondition; + + const rs: AnalyzeAddress = { + address: contact.address, + accountName: name, + displayName: name + }; + + if (condition !== 'invalid') { + if (contact.isRecent) { + if (contact.recentChainSlugs?.includes(chain)) { + options.push(rs); + + if (condition === 'extracted') { + current = rs; + } + } + } else { + options.push(rs); + + if (condition === 'extracted') { + current = rs; + } + } + } + } + + if (substrateApi) { + await substrateApi?.isReady; + + const _raw = current?.address || _data; + + if (isAddress(_raw)) { + const domain = await resolveAzeroAddressToDomain(_raw, chain, substrateApi.api); + + if (domain) { + if (current) { + current.domainName = domain; + } else { + const rs: AnalyzeAddress = { + address: _raw, + displayName: domain, + domainName: domain + }; + + options.push(rs); + current = rs; + } + } + } else { + const address = await resolveAzeroDomainToAddress(_raw, chain, substrateApi.api); + + if (address) { + if (current) { + current.domainName = _raw; + } else { + const rs: AnalyzeAddress = { + address: address, + displayName: _raw, + domainName: _raw + }; + + options.push(rs); + current = rs; + } + } + } + } + + return { + options, + current + }; +}; diff --git a/packages/extension-base/src/utils/account/index.ts b/packages/extension-base/src/utils/account/index.ts index 947472213d..ce1b6bdf15 100644 --- a/packages/extension-base/src/utils/account/index.ts +++ b/packages/extension-base/src/utils/account/index.ts @@ -1,6 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-base authors & contributors // SPDX-License-Identifier: Apache-2.0 +export * from './analyze'; export * from './common'; export * from './derive'; export * from './transform'; diff --git a/packages/extension-base/src/utils/account/transform.ts b/packages/extension-base/src/utils/account/transform.ts index 58bb99aa82..47447028be 100644 --- a/packages/extension-base/src/utils/account/transform.ts +++ b/packages/extension-base/src/utils/account/transform.ts @@ -6,8 +6,9 @@ import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; import { _getSubstrateGenesisHash } from '@subwallet/extension-base/services/chain-service/utils'; import { AccountActions, AccountChainType, AccountJson, AccountMetadataData, AccountProxy, AccountProxyMap, AccountProxyStoreData, AccountProxyType, AccountSignMode, AddressJson, ModifyPairStoreData } from '@subwallet/extension-base/types'; -import { getKeypairTypeByAddress } from '@subwallet/keyring'; +import { getKeypairTypeByAddress, tonMnemonicToEntropy } from '@subwallet/keyring'; import { BitcoinKeypairTypes, EthereumKeypairTypes, KeypairType, KeyringPair, KeyringPair$Meta, TonKeypairTypes } from '@subwallet/keyring/types'; +import { tonMnemonicValidate } from '@subwallet/keyring/utils'; import { SingleAddress, SubjectInfo } from '@subwallet/ui-keyring/observable/types'; import { hexStripPrefix, u8aToHex } from '@polkadot/util'; @@ -21,6 +22,14 @@ export const createAccountProxyId = (_suri: string, derivationPath?: string) => data = u8aToHex(entropy); + if (derivationPath) { + data = blake2AsHex(data, 256); + } + } else if (tonMnemonicValidate(_suri)) { + const entropy = tonMnemonicToEntropy(_suri); + + data = u8aToHex(entropy); + if (derivationPath) { data = blake2AsHex(data, 256); } @@ -33,6 +42,18 @@ export const createAccountProxyId = (_suri: string, derivationPath?: string) => return blake2AsHex(data, 256); }; +export const getAccountChainType = (type: KeypairType): AccountChainType => { + return type + ? EthereumKeypairTypes.includes(type) + ? AccountChainType.ETHEREUM + : TonKeypairTypes.includes(type) + ? AccountChainType.TON + : BitcoinKeypairTypes.includes(type) + ? AccountChainType.BITCOIN + : AccountChainType.SUBSTRATE + : AccountChainType.SUBSTRATE; +}; + export const getAccountSignMode = (address: string, _meta?: KeyringPair$Meta): AccountSignMode => { const meta = _meta as AccountMetadataData; @@ -306,16 +327,8 @@ export const getAccountTokenTypes = (type: KeypairType): _AssetType[] => { export const transformAccount = (address: string, _type?: KeypairType, meta?: KeyringPair$Meta, chainInfoMap?: Record): AccountJson => { const signMode = getAccountSignMode(address, meta); const type = _type || getKeypairTypeByAddress(address); - const networkType: AccountChainType = type - ? EthereumKeypairTypes.includes(type) - ? AccountChainType.ETHEREUM - : TonKeypairTypes.includes(type) - ? AccountChainType.TON - : BitcoinKeypairTypes.includes(type) - ? AccountChainType.BITCOIN - : AccountChainType.SUBSTRATE - : AccountChainType.SUBSTRATE; - let specialNetwork: string | undefined; + const chainType: AccountChainType = getAccountChainType(type); + let specialChain: string | undefined; if (!chainInfoMap) { return { @@ -326,7 +339,7 @@ export const transformAccount = (address: string, _type?: KeypairType, meta?: Ke transactionActions: [], tokenTypes: [], signMode, - chainType: networkType + chainType }; } @@ -336,12 +349,12 @@ export const transformAccount = (address: string, _type?: KeypairType, meta?: Ke const chainInfo = Object.values(chainInfoMap).find((info) => _getSubstrateGenesisHash(info) === genesisHash); if (chainInfo) { - specialNetwork = chainInfo.slug; + specialChain = chainInfo.slug; } } - const accountActions = getAccountActions(signMode, networkType, type, meta); - const transactionActions = getAccountTransactionActions(signMode, networkType, type, meta, specialNetwork); + const accountActions = getAccountActions(signMode, chainType, type, meta); + const transactionActions = getAccountTransactionActions(signMode, chainType, type, meta, specialChain); const tokenTypes = getAccountTokenTypes(type); /* Account actions */ @@ -353,8 +366,8 @@ export const transformAccount = (address: string, _type?: KeypairType, meta?: Ke accountActions, transactionActions, signMode, - chainType: networkType, - specialChain: specialNetwork, + chainType, + specialChain, tokenTypes }; }; @@ -369,14 +382,17 @@ export const pairToAccount = ({ address, export const transformAccounts = (accounts: SubjectInfo): AccountJson[] => Object.values(accounts).map((data) => singleAddressToAccount(data)); export const transformAddress = (address: string, meta?: KeyringPair$Meta): AddressJson => { + const type = getKeypairTypeByAddress(address); + const chainType: AccountChainType = getAccountChainType(type); + return { address, - ...meta + ...meta, + chainType }; }; -export const transformAddresses = (addresses: SubjectInfo): AddressJson[] => Object.values(addresses).map(({ json: { address, - meta } }) => transformAddress(address, meta)); +export const transformAddresses = (addresses: SubjectInfo): AddressJson[] => Object.values(addresses).map(({ json: { address, meta } }) => transformAddress(address, meta)); export const combineAccounts = (pairs: SubjectInfo, modifyPairs: ModifyPairStoreData, accountProxies: AccountProxyStoreData, chainInfoMap?: Record) => { const temp: Record> = {}; diff --git a/packages/extension-koni-ui/src/messaging/accounts/legacy.ts b/packages/extension-koni-ui/src/messaging/accounts/legacy.ts index 05360f2b5e..acb7925b2a 100644 --- a/packages/extension-koni-ui/src/messaging/accounts/legacy.ts +++ b/packages/extension-koni-ui/src/messaging/accounts/legacy.ts @@ -1,8 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { OptionInputAddress } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountsWithCurrentAddress } from '@subwallet/extension-base/types'; +import { AccountsWithCurrentAddress, RequestInputAccountSubscribe, ResponseInputAccountSubscribe } from '@subwallet/extension-base/types'; import { sendMessage } from '../base'; @@ -10,6 +9,6 @@ export async function subscribeAccountsWithCurrentAddress (cb: (data: AccountsWi return sendMessage('pri(accounts.subscribeWithCurrentProxy)', {}, cb); } -export async function subscribeAccountsInputAddress (cb: (data: OptionInputAddress) => void): Promise { - return sendMessage('pri(accounts.subscribeAccountsInputAddress)', {}, cb); +export async function subscribeAccountsInputAddress (request: RequestInputAccountSubscribe, cb: (data: ResponseInputAccountSubscribe) => void): Promise { + return sendMessage('pri(accounts.subscribeAccountsInputAddress)', request, cb); } From fb6a6915f3c43ba76a66bc92d90f68df3dd9e9c4 Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Tue, 20 Aug 2024 16:03:35 +0700 Subject: [PATCH 127/424] [Issue-3449] feat: add queryId to message body --- .../balance-service/helpers/subscribe/ton/consts.ts | 2 ++ .../balance-service/helpers/subscribe/ton/utils.ts | 13 ++++++++++++- .../balance-service/transfer/ton-transfer.ts | 4 ++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/consts.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/consts.ts index 690288a1b8..1fbe94657c 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/consts.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/consts.ts @@ -11,6 +11,8 @@ export enum TON_OPCODES { STONFI_SWAP = 0x25938561 } +export const SW_QUERYID_HEX = 0x20010503; + export const EXTRA_TON_ESTIMATE_FEE = BigInt(500); // todo: This is just free API for dev, remove this and set better RPC later diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts index 19b4744b7d..7605ce0e47 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts @@ -1,12 +1,13 @@ // Copyright 2019-2022 @subwallet/extension-base // SPDX-License-Identifier: Apache-2.0 -import { EXTRA_TON_ESTIMATE_FEE } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/consts'; +import { EXTRA_TON_ESTIMATE_FEE, SW_QUERYID_HEX } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/consts'; import { TxByMsgResponse } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/types'; import { TonApi } from '@subwallet/extension-base/services/chain-service/handler/TonApi'; import { _TonApi } from '@subwallet/extension-base/services/chain-service/types'; import { Address, beginCell, Cell, MessageRelaxed, storeMessage, storeMessageRelaxed } from '@ton/core'; import { external, JettonMaster, JettonWallet, OpenedContract, WalletContractV4 } from '@ton/ton'; +import nacl from 'tweetnacl'; export function getJettonMasterContract (tonApi: _TonApi, contractAddress: string) { const masterAddress = Address.parse(contractAddress); @@ -115,3 +116,13 @@ export function messageRelaxedToCell (message: MessageRelaxed) { export function cellToBase64Str (cell: Cell) { return cell.toBoc().toString('base64'); } + +export function getWalletQueryId () { + const swSignal = SW_QUERYID_HEX.toString(16); + + const swSignalBuffer = Buffer.from(swSignal, 'hex'); + const randomBuffer = nacl.randomBytes(4); + const buffer = Buffer.concat([swSignalBuffer, randomBuffer]); + + return BigInt('0x' + buffer.toString('hex')); +} diff --git a/packages/extension-base/src/services/balance-service/transfer/ton-transfer.ts b/packages/extension-base/src/services/balance-service/transfer/ton-transfer.ts index 1a57559a3e..78d3e9edda 100644 --- a/packages/extension-base/src/services/balance-service/transfer/ton-transfer.ts +++ b/packages/extension-base/src/services/balance-service/transfer/ton-transfer.ts @@ -3,7 +3,7 @@ import { _ChainAsset } from '@subwallet/chain-list/types'; import { INIT_FEE_JETTON_TRANSFER, TON_OPCODES, WORKCHAIN } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/consts'; -import { cellToBase64Str, estimateTonTxFee, messageRelaxedToCell } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/utils'; +import { cellToBase64Str, estimateTonTxFee, getWalletQueryId, messageRelaxedToCell } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/utils'; import { _TonApi } from '@subwallet/extension-base/services/chain-service/types'; import { _getContractAddressOfToken, _isJettonToken, _isNativeToken } from '@subwallet/extension-base/services/chain-service/utils'; import { keyring } from '@subwallet/ui-keyring'; @@ -89,7 +89,7 @@ async function createJettonTransaction ({ from, networkKey, to, tokenInfo, tonAp const messageBody = beginCell() .storeUint(TON_OPCODES.JETTON_TRANSFER, 32) // opcode for jetton transfer - .storeUint(0, 64) // query id todo: research more about this + .storeUint(getWalletQueryId(), 64) // query id .storeCoins(BigInt(value)) // jetton bigint amount .storeAddress(destinationAddress) .storeAddress(sendertonAddress) // response destination, who get remain token From 2bcb9bf85a135c85a02121f293d97d4b0d240c3e Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Tue, 20 Aug 2024 16:20:41 +0700 Subject: [PATCH 128/424] [Issue-3449] fix: update logic tracking status transaction --- .../balance-service/helpers/subscribe/ton/utils.ts | 1 + .../src/services/chain-service/handler/TonApi.ts | 11 ++++++++--- .../src/services/transaction-service/index.ts | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts index 7605ce0e47..b1d96042e6 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/utils.ts @@ -68,6 +68,7 @@ export function getMessageTxStatus (txByMsgInfo: TxByMsgResponse) { return isCompute && isAction && !isBounced; } +// @ts-ignore export async function getNativeTonTxStatus (tonApi: TonApi, internalMsgHash: string) { const internalTxInfoRaw = await tonApi.getTxByInMsg(internalMsgHash); diff --git a/packages/extension-base/src/services/chain-service/handler/TonApi.ts b/packages/extension-base/src/services/chain-service/handler/TonApi.ts index df76e66e52..2a3869c52c 100644 --- a/packages/extension-base/src/services/chain-service/handler/TonApi.ts +++ b/packages/extension-base/src/services/chain-service/handler/TonApi.ts @@ -1,9 +1,10 @@ // Copyright 2019-2022 @subwallet/extension-base authors & contributors // SPDX-License-Identifier: Apache-2.0 +import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; import { TON_API_ENDPOINT, TON_CENTER_API_KEY, TON_OPCODES } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/consts'; import { TxByMsgResponse } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/types'; -import { getJettonTxStatus, getNativeTonTxStatus, retry } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/utils'; +import { getJettonTxStatus, retry } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/utils'; import { _ApiOptions } from '@subwallet/extension-base/services/chain-service/handler/types'; import { _ChainConnectionStatus, _TonApi } from '@subwallet/extension-base/services/chain-service/types'; import { createPromiseHandler, PromiseHandler } from '@subwallet/extension-base/utils'; @@ -191,7 +192,7 @@ export class TonApi implements _TonApi { return await resp.json() as TxByMsgResponse; } - async getStatusByExtMsgHash (extMsgHash: string): Promise<[boolean, string]> { + async getStatusByExtMsgHash (extMsgHash: string, extrinsicType?: ExtrinsicType): Promise<[boolean, string]> { return retry<[boolean, string]>(async () => { // retry many times to get transaction status and transaction hex const externalTxInfoRaw = await this.getTxByInMsg(extMsgHash); const externalTxInfo = externalTxInfoRaw.transactions[0]; @@ -204,6 +205,10 @@ export class TonApi implements _TonApi { return [false, hex]; } + if (extrinsicType === ExtrinsicType.TRANSFER_BALANCE) { + return [true, hex]; + } + // get out msg info from tx const internalMsgHash = externalTxInfo.out_msgs[0]?.hash; const opcode = parseInt(externalTxInfo.out_msgs[0]?.opcode || '0'); @@ -211,7 +216,7 @@ export class TonApi implements _TonApi { if (internalMsgHash) { // notice to update opcode check when supporting more transaction type in ton blockchain const status = opcode === TON_OPCODES.JETTON_TRANSFER ? await getJettonTxStatus(this, internalMsgHash) - : await getNativeTonTxStatus(this, internalMsgHash); + : false; return [status, hex]; } diff --git a/packages/extension-base/src/services/transaction-service/index.ts b/packages/extension-base/src/services/transaction-service/index.ts index c10959ba49..fc8112bf7d 100644 --- a/packages/extension-base/src/services/transaction-service/index.ts +++ b/packages/extension-base/src/services/transaction-service/index.ts @@ -1154,7 +1154,7 @@ export default class TransactionService { return emitter; } - private async signAndSendTonTransaction ({ address, chain, id, transaction, url }: SWTransaction): Promise { + private async signAndSendTonTransaction ({ address, chain, extrinsicType, id, transaction, url }: SWTransaction): Promise { const keyPair = keyring.getPair(address); const emitter = new EventEmitter(); const eventData: TransactionEventResponse = { @@ -1202,7 +1202,7 @@ export default class TransactionService { return; } - tonApi.getStatusByExtMsgHash(externalMsgHash).then(([status, hex]) => { + tonApi.getStatusByExtMsgHash(externalMsgHash, extrinsicType).then(([status, hex]) => { if (status && hex) { eventData.extrinsicHash = hex; emitter.emit('extrinsicHash', eventData); From de66d693a3c46bf3f0d3f2afd4bcf96721b3afd9 Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Tue, 20 Aug 2024 16:45:48 +0700 Subject: [PATCH 129/424] [Issue-3449] fix: handle user reject tx action and add tx hash info --- .../src/services/chain-service/handler/TonApi.ts | 2 +- .../src/services/transaction-service/index.ts | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/extension-base/src/services/chain-service/handler/TonApi.ts b/packages/extension-base/src/services/chain-service/handler/TonApi.ts index 2a3869c52c..d85a3b7913 100644 --- a/packages/extension-base/src/services/chain-service/handler/TonApi.ts +++ b/packages/extension-base/src/services/chain-service/handler/TonApi.ts @@ -199,7 +199,7 @@ export class TonApi implements _TonApi { const isExternalTxCompute = externalTxInfo.description.compute_ph.success; const isExternalTxAction = externalTxInfo.description.action.success; const base64Hex = externalTxInfo.hash; - const hex = Buffer.from(base64Hex, 'base64').toString('hex'); + const hex = '0x'.concat(Buffer.from(base64Hex, 'base64').toString('hex')); if (!(isExternalTxCompute && isExternalTxAction)) { return [false, hex]; diff --git a/packages/extension-base/src/services/transaction-service/index.ts b/packages/extension-base/src/services/transaction-service/index.ts index fc8112bf7d..aad49390b2 100644 --- a/packages/extension-base/src/services/transaction-service/index.ts +++ b/packages/extension-base/src/services/transaction-service/index.ts @@ -1170,7 +1170,15 @@ export default class TransactionService { return new Promise((resolve) => { this.state.requestService.addConfirmationTon(id, url || EXTENSION_REQUEST_URL, 'tonSendTransactionRequest', { ...payload, messagePayload: cellToBase64Str(message), messages: [] }, {}) .then(({ isApproved, payload }) => { - if (payload) { + if (!isApproved) { + this.removeTransaction(id); + eventData.errors.push(new TransactionError(BasicTxErrorType.USER_REJECT_REQUEST)); + emitter.emit('error', eventData); + } else { + if (!payload) { + throw new Error('Bad signature'); + } + resolve(Buffer.from(hexToU8a(payload))); } }); From 82badb14537f59106e76763f1f355d3f009103f3 Mon Sep 17 00:00:00 2001 From: S2kael Date: Tue, 20 Aug 2024 17:02:07 +0700 Subject: [PATCH 130/424] [Issue-3472] Add `formatedAddress ` info --- .../src/types/account/action/subscribe.ts | 1 + .../src/utils/account/analyze.ts | 26 ++++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/packages/extension-base/src/types/account/action/subscribe.ts b/packages/extension-base/src/types/account/action/subscribe.ts index 4217f6c816..3fae9c3666 100644 --- a/packages/extension-base/src/types/account/action/subscribe.ts +++ b/packages/extension-base/src/types/account/action/subscribe.ts @@ -8,6 +8,7 @@ export interface RequestInputAccountSubscribe { export interface AnalyzeAddress { address: string; + formatedAddress: string; domainName?: string; accountName?: string; displayName?: string; diff --git a/packages/extension-base/src/utils/account/analyze.ts b/packages/extension-base/src/utils/account/analyze.ts index 4e28a6a718..9d5aea2dd4 100644 --- a/packages/extension-base/src/utils/account/analyze.ts +++ b/packages/extension-base/src/utils/account/analyze.ts @@ -17,6 +17,20 @@ interface AddressDataJson extends AbstractAddressJson { type ValidDataType = 'invalid' | 'valid' | 'extracted'; +const _reformatAddressWithChain = (address: string, chainInfo: _ChainInfo): string => { + const chainType = _chainInfoToChainType(chainInfo); + + if (chainType === AccountChainType.SUBSTRATE) { + return reformatAddress(address, _getChainSubstrateAddressPrefix(chainInfo)); + } else if (chainType === AccountChainType.TON) { + const isTestnet = chainInfo.isTestnet; + + return reformatAddress(address, isTestnet ? 0 : 1); + } else { + return address; + } +}; + // TODO: Re-confirm to compare without const isStrValidWithAddress = (str: string, account: AddressDataJson, chainInfo: _ChainInfo): ValidDataType => { if (account.chainType === AccountChainType.SUBSTRATE) { @@ -77,7 +91,8 @@ export const _analyzeAddress = async (data: string, accountProxies: AccountProxy const rs: AnalyzeAddress = { address: account.address, accountName: accountProxy.name, - displayName: accountProxy.name + displayName: accountProxy.name, + formatedAddress: _reformatAddressWithChain(account.address, chainInfo) }; if (condition !== 'invalid') { @@ -113,7 +128,8 @@ export const _analyzeAddress = async (data: string, accountProxies: AccountProxy const rs: AnalyzeAddress = { address: contact.address, accountName: name, - displayName: name + displayName: name, + formatedAddress: _reformatAddressWithChain(contact.address, chainInfo) }; if (condition !== 'invalid') { @@ -150,7 +166,8 @@ export const _analyzeAddress = async (data: string, accountProxies: AccountProxy const rs: AnalyzeAddress = { address: _raw, displayName: domain, - domainName: domain + domainName: domain, + formatedAddress: _reformatAddressWithChain(_raw, chainInfo) }; options.push(rs); @@ -167,7 +184,8 @@ export const _analyzeAddress = async (data: string, accountProxies: AccountProxy const rs: AnalyzeAddress = { address: address, displayName: _raw, - domainName: _raw + domainName: _raw, + formatedAddress: _reformatAddressWithChain(address, chainInfo) }; options.push(rs); From 25fa53dbfdc5bf522aa425c09c847689d3ef5f9d Mon Sep 17 00:00:00 2001 From: Thiendekaco Date: Tue, 20 Aug 2024 18:09:52 +0700 Subject: [PATCH 131/424] [Issue 3457] [fix] Extension - fix ui bug --- .../src/components/AccountProxy/AccountNetworkAddressItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountNetworkAddressItem.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountNetworkAddressItem.tsx index 8a0d5c4302..82d6fdcd02 100644 --- a/packages/extension-koni-ui/src/components/AccountProxy/AccountNetworkAddressItem.tsx +++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountNetworkAddressItem.tsx @@ -106,7 +106,7 @@ const AccountProxySelectorItem = styled(Component)(({ theme: { token } }: 'white-space': 'nowrap', gap: token.sizeXXS, flex: 1, - alignItems: 'center' + alignItems: 'flex-end' }, '.__item-network-name': { From 2cf428eadf8d81134b3fb4f37375c5d3df33a686 Mon Sep 17 00:00:00 2001 From: lw Date: Tue, 20 Aug 2024 18:29:19 +0700 Subject: [PATCH 132/424] [Issue-3448] Update Swap feature --- .../EarningEntry/EarningOptions/index.tsx | 6 +- .../Popup/Home/Earning/EarningPools/index.tsx | 5 +- .../src/Popup/Home/Tokens/DetailList.tsx | 31 +- .../src/Popup/Home/Tokens/index.tsx | 37 +- .../src/Popup/Transaction/variants/Earn.tsx | 4 +- .../Popup/Transaction/variants/SendFund.tsx | 12 +- .../src/Popup/Transaction/variants/Swap.tsx | 318 +++++++++++------- .../src/utils/chain/chain.ts | 13 +- .../src/utils/chain/chainAndAsset.ts | 21 +- .../src/utils/transaction/formValue.ts | 9 + .../src/utils/transaction/index.ts | 1 + 11 files changed, 278 insertions(+), 179 deletions(-) create mode 100644 packages/extension-koni-ui/src/utils/transaction/formValue.ts diff --git a/packages/extension-koni-ui/src/Popup/Home/Earning/EarningEntry/EarningOptions/index.tsx b/packages/extension-koni-ui/src/Popup/Home/Earning/EarningEntry/EarningOptions/index.tsx index f9e372ae7a..2ce1e4def0 100644 --- a/packages/extension-koni-ui/src/Popup/Home/Earning/EarningEntry/EarningOptions/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Home/Earning/EarningEntry/EarningOptions/index.tsx @@ -14,7 +14,7 @@ import { useFilterModal, useGroupYieldPosition, useHandleChainConnection, useSel import { getBalanceValue } from '@subwallet/extension-koni-ui/hooks/screen/home/useAccountBalance'; import { ChainConnectionWrapper } from '@subwallet/extension-koni-ui/Popup/Home/Earning/shared/ChainConnectionWrapper'; import { EarningEntryView, EarningPoolsParam, ThemeProps, YieldGroupInfo } from '@subwallet/extension-koni-ui/types'; -import { isRelatedToAstar, openInNewTab } from '@subwallet/extension-koni-ui/utils'; +import { getTransactionFromAccountProxyValue, isRelatedToAstar, openInNewTab } from '@subwallet/extension-koni-ui/utils'; import { Icon, ModalContext, SwList } from '@subwallet/react-ui'; import CN from 'classnames'; import { FadersHorizontal, Vault } from 'phosphor-react'; @@ -129,11 +129,11 @@ function Component ({ className, hasEarningPositions, setEntryView }: Props) { ...DEFAULT_EARN_PARAMS, slug, chain, - fromAccountProxy: currentAccountProxy?.id ? currentAccountProxy.id : '' + fromAccountProxy: getTransactionFromAccountProxyValue(currentAccountProxy) }); navigate('/transaction/earn'); }, - [currentAccountProxy?.id, navigate, setEarnStorage] + [currentAccountProxy, navigate, setEarnStorage] ); const onConnectChainSuccess = useCallback(() => { diff --git a/packages/extension-koni-ui/src/Popup/Home/Earning/EarningPools/index.tsx b/packages/extension-koni-ui/src/Popup/Home/Earning/EarningPools/index.tsx index 20a391f3e3..374ee129a8 100644 --- a/packages/extension-koni-ui/src/Popup/Home/Earning/EarningPools/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Home/Earning/EarningPools/index.tsx @@ -14,6 +14,7 @@ import { useFilterModal, useGroupYieldPosition, useHandleChainConnection, useSel import { getBalanceValue } from '@subwallet/extension-koni-ui/hooks/screen/home/useAccountBalance'; import { ChainConnectionWrapper } from '@subwallet/extension-koni-ui/Popup/Home/Earning/shared/ChainConnectionWrapper'; import { EarningEntryParam, EarningEntryView, EarningPoolsParam, ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { getTransactionFromAccountProxyValue } from '@subwallet/extension-koni-ui/utils'; import { Icon, ModalContext, SwList } from '@subwallet/react-ui'; import BigN from 'bignumber.js'; import CN from 'classnames'; @@ -173,11 +174,11 @@ function Component ({ poolGroup, symbol }: ComponentProps) { ...DEFAULT_EARN_PARAMS, slug: item.slug, chain: item.chain, - fromAccountProxy: currentAccountProxy?.id ? currentAccountProxy?.id : '' + fromAccountProxy: getTransactionFromAccountProxyValue(currentAccountProxy) }); navigate('/transaction/earn'); }, - [currentAccountProxy?.id, navigate, setEarnStorage] + [currentAccountProxy, navigate, setEarnStorage] ); const onConnectChainSuccess = useCallback(() => { diff --git a/packages/extension-koni-ui/src/Popup/Home/Tokens/DetailList.tsx b/packages/extension-koni-ui/src/Popup/Home/Tokens/DetailList.tsx index 370ca42016..1010ec4bcc 100644 --- a/packages/extension-koni-ui/src/Popup/Home/Tokens/DetailList.tsx +++ b/packages/extension-koni-ui/src/Popup/Home/Tokens/DetailList.tsx @@ -16,7 +16,7 @@ import { DetailUpperBlock } from '@subwallet/extension-koni-ui/Popup/Home/Tokens import { RootState } from '@subwallet/extension-koni-ui/stores'; import { BuyTokenInfo, ThemeProps } from '@subwallet/extension-koni-ui/types'; import { TokenBalanceItemType } from '@subwallet/extension-koni-ui/types/balance'; -import { getAccountType, isAccountAll, sortTokenByValue } from '@subwallet/extension-koni-ui/utils'; +import { getAccountType, getTransactionFromAccountProxyValue, isAccountAll, sortTokenByValue } from '@subwallet/extension-koni-ui/utils'; import { ModalContext } from '@subwallet/react-ui'; import { SwNumberProps } from '@subwallet/react-ui/es/number'; import classNames from 'classnames'; @@ -65,6 +65,7 @@ function Component (): React.ReactElement { const multiChainAssetMap = useSelector((state: RootState) => state.assetRegistry.multiChainAssetMap); const currentAccount = useSelector((state: RootState) => state.accountState.currentAccount); const accounts = useSelector((state: RootState) => state.accountState.accounts); + const accountProxies = useSelector((state: RootState) => state.accountState.accountProxies); const currentAccountProxy = useSelector((state: RootState) => state.accountState.currentAccountProxy); const { tokens } = useSelector((state: RootState) => state.buyService); const swapPairs = useSelector((state) => state.swap.swapPairs); @@ -73,10 +74,6 @@ function Component (): React.ReactElement { const [, setSwapStorage] = useLocalStorage(SWAP_TRANSACTION, DEFAULT_SWAP_PARAMS); const { banners, dismissBanner, onClickBanner } = useGetBannerByScreen('token_detail', tokenGroupSlug); - const transactionFromValue = useMemo(() => { - return currentAccount?.address ? isAccountAll(currentAccount.address) ? '' : currentAccount.address : ''; - }, [currentAccount?.address]); - const fromAndToTokenMap = useMemo>(() => { const result: Record = {}; @@ -292,7 +289,11 @@ function Component (): React.ReactElement { }, []); const onOpenSendFund = useCallback(() => { - if (currentAccountProxy && currentAccountProxy.accountType === AccountProxyType.READ_ONLY) { + if (!currentAccountProxy) { + return; + } + + if (currentAccountProxy.accountType === AccountProxyType.READ_ONLY) { notify({ message: t('The account you are using is watch-only, you cannot send assets with it'), type: 'info', @@ -302,11 +303,9 @@ function Component (): React.ReactElement { return; } - const fromAccountProxy = currentAccountProxy ? currentAccountProxy.id : ''; - setStorage({ ...DEFAULT_TRANSFER_PARAMS, - fromAccountProxy, + fromAccountProxy: getTransactionFromAccountProxyValue(currentAccountProxy), defaultSlug: tokenGroupSlug || '' }); @@ -332,7 +331,11 @@ function Component (): React.ReactElement { ); const onOpenSwap = useCallback(() => { - if (currentAccount && currentAccount.isReadOnly) { + if (!currentAccountProxy) { + return; + } + + if (currentAccountProxy.accountType === AccountProxyType.READ_ONLY) { notify({ message: t('The account you are using is watch-only, you cannot send assets with it'), type: 'info', @@ -342,9 +345,9 @@ function Component (): React.ReactElement { return; } - const filteredAccounts = accounts.filter((account) => !isAccountAll(account.address)); + const filteredAccounts = accountProxies.filter((ap) => !isAccountAll(ap.id)); - const isAllLedger = (filteredAccounts.length > 0 && filteredAccounts.every((account) => account.isHardware)) || (currentAccount && !isAccountAll(currentAccount.address) && (currentAccount.isHardware)); + const isAllLedger = currentAccountProxy.accountType === AccountProxyType.LEDGER || (filteredAccounts.length > 0 && filteredAccounts.every((ap) => ap.accountType === AccountProxyType.LEDGER)); if ((currentAccount && currentAccount.isHardware) || (isAllLedger)) { notify({ @@ -358,11 +361,11 @@ function Component (): React.ReactElement { setSwapStorage({ ...DEFAULT_SWAP_PARAMS, - from: transactionFromValue, + fromAccountProxy: getTransactionFromAccountProxyValue(currentAccountProxy), defaultSlug: tokenGroupSlug || '' }); navigate('/transaction/swap'); - }, [accounts, currentAccount, navigate, notify, setSwapStorage, t, tokenGroupSlug, transactionFromValue]); + }, [accountProxies, currentAccount, currentAccountProxy, navigate, notify, setSwapStorage, t, tokenGroupSlug]); useEffect(() => { if (currentTokenInfo) { diff --git a/packages/extension-koni-ui/src/Popup/Home/Tokens/index.tsx b/packages/extension-koni-ui/src/Popup/Home/Tokens/index.tsx index e21029ae64..95a240f79e 100644 --- a/packages/extension-koni-ui/src/Popup/Home/Tokens/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Home/Tokens/index.tsx @@ -14,7 +14,7 @@ import { UpperBlock } from '@subwallet/extension-koni-ui/Popup/Home/Tokens/Upper import { RootState } from '@subwallet/extension-koni-ui/stores'; import { ThemeProps, TransferParams } from '@subwallet/extension-koni-ui/types'; import { TokenBalanceItemType } from '@subwallet/extension-koni-ui/types/balance'; -import { isAccountAll, sortTokenByValue } from '@subwallet/extension-koni-ui/utils'; +import { getTransactionFromAccountProxyValue, isAccountAll, sortTokenByValue } from '@subwallet/extension-koni-ui/utils'; import { Button, Icon, SwAlert } from '@subwallet/react-ui'; import classNames from 'classnames'; import { Coins, FadersHorizontal } from 'phosphor-react'; @@ -33,11 +33,10 @@ const Component = (): React.ReactElement => { const navigate = useNavigate(); const containerRef = useRef(null); const topBlockRef = useRef(null); - const accounts = useSelector((state: RootState) => state.accountState.accounts); + const accountProxies = useSelector((state: RootState) => state.accountState.accountProxies); + const currentAccountProxy = useSelector((state: RootState) => state.accountState.currentAccountProxy); const { accountBalance: { tokenGroupBalanceMap, totalBalanceInfo }, tokenGroupStructure: { sortedTokenGroups } } = useContext(HomeContext); - const currentAccount = useSelector((state: RootState) => state.accountState.currentAccount); - const currentAccountProxy = useSelector((state: RootState) => state.accountState.currentAccountProxy); const notify = useNotification(); const { onOpenReceive, receiveModalProps } = useReceiveModalHelper(); @@ -46,10 +45,6 @@ const Component = (): React.ReactElement => { const [, setStorage] = useLocalStorage(TRANSFER_TRANSACTION, DEFAULT_TRANSFER_PARAMS); const [, setSwapStorage] = useLocalStorage(SWAP_TRANSACTION, DEFAULT_SWAP_PARAMS); - const transactionFromValue = useMemo(() => { - return currentAccount?.address ? isAccountAll(currentAccount.address) ? '' : currentAccount.address : ''; - }, [currentAccount?.address]); - const handleScroll = useCallback((event: React.UIEvent) => { const topPosition = event.currentTarget.scrollTop; @@ -135,7 +130,11 @@ const Component = (): React.ReactElement => { }, [navigate]); const onOpenSendFund = useCallback(() => { - if (currentAccountProxy && currentAccountProxy.accountType === AccountProxyType.READ_ONLY) { + if (!currentAccountProxy) { + return; + } + + if (currentAccountProxy.accountType === AccountProxyType.READ_ONLY) { notify({ message: t('The account you are using is watch-only, you cannot send assets with it'), type: 'info', @@ -145,11 +144,9 @@ const Component = (): React.ReactElement => { return; } - const fromAccountProxy = currentAccountProxy ? currentAccountProxy.id : ''; - setStorage({ ...DEFAULT_TRANSFER_PARAMS, - fromAccountProxy + fromAccountProxy: getTransactionFromAccountProxyValue(currentAccountProxy) }); navigate('/transaction/send-fund'); }, @@ -163,7 +160,11 @@ const Component = (): React.ReactElement => { ); const onOpenSwap = useCallback(() => { - if (currentAccount && currentAccount.isReadOnly) { + if (!currentAccountProxy) { + return; + } + + if (currentAccountProxy.accountType === AccountProxyType.READ_ONLY) { notify({ message: t('The account you are using is watch-only, you cannot send assets with it'), type: 'info', @@ -173,11 +174,11 @@ const Component = (): React.ReactElement => { return; } - const filteredAccounts = accounts.filter((account) => !isAccountAll(account.address)); + const filteredAccounts = accountProxies.filter((ap) => !isAccountAll(ap.id)); - const isAllLedger = (filteredAccounts.length > 0 && filteredAccounts.every((account) => account.isHardware)) || (currentAccount && !isAccountAll(currentAccount.address) && (currentAccount.isHardware)); + const isAllLedger = currentAccountProxy.accountType === AccountProxyType.LEDGER || (filteredAccounts.length > 0 && filteredAccounts.every((ap) => ap.accountType === AccountProxyType.LEDGER)); - if ((currentAccount && currentAccount.isHardware) || (isAllLedger)) { + if (isAllLedger) { notify({ message: 'The account you are using is Ledger account, you cannot use this feature with it', type: 'error', @@ -189,10 +190,10 @@ const Component = (): React.ReactElement => { setSwapStorage({ ...DEFAULT_SWAP_PARAMS, - from: transactionFromValue + fromAccountProxy: getTransactionFromAccountProxyValue(currentAccountProxy) }); navigate('/transaction/swap'); - }, [accounts, currentAccount, navigate, notify, setSwapStorage, t, transactionFromValue]); + }, [accountProxies, currentAccountProxy, navigate, notify, setSwapStorage, t]); const tokenGroupBalanceItems = useMemo(() => { const result: TokenBalanceItemType[] = []; diff --git a/packages/extension-koni-ui/src/Popup/Transaction/variants/Earn.tsx b/packages/extension-koni-ui/src/Popup/Transaction/variants/Earn.tsx index ee12df9272..0d5ba7ac15 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/variants/Earn.tsx +++ b/packages/extension-koni-ui/src/Popup/Transaction/variants/Earn.tsx @@ -19,7 +19,7 @@ import { fetchPoolTarget, getOptimalYieldPath, submitJoinYieldPool, validateYiel import { DEFAULT_YIELD_PROCESS, EarningActionType, earningReducer } from '@subwallet/extension-koni-ui/reducer'; import { store } from '@subwallet/extension-koni-ui/stores'; import { AccountAddressItemType, EarnParams, FormCallbacks, FormFieldData, ThemeProps } from '@subwallet/extension-koni-ui/types'; -import { convertFieldToObject, getReformatedAddressRelatedToNetwork, isAccountAll, parseNominations, reformatAddress, simpleCheckForm } from '@subwallet/extension-koni-ui/utils'; +import { convertFieldToObject, getReformatedAddressRelatedToNetwork, parseNominations, reformatAddress, simpleCheckForm } from '@subwallet/extension-koni-ui/utils'; import { ActivityIndicator, Button, ButtonProps, Form, Icon, ModalContext, Number } from '@subwallet/react-ui'; import BigN from 'bignumber.js'; import CN from 'classnames'; @@ -248,7 +248,7 @@ const Component = () => { const result: AccountAddressItemType[] = []; accountProxies.forEach((ap) => { - if (!(isAccountAll(fromAccountProxy) || ap.id === fromAccountProxy)) { + if (!(!fromAccountProxy || ap.id === fromAccountProxy)) { return; } diff --git a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx index fc430eb744..785be1ea9e 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx +++ b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx @@ -55,7 +55,13 @@ function getTokenItems ( tokenGroupSlug?: string, // is ether a token slug or a multiChainAsset slug isZkModeEnabled?: boolean ): TokenItemType[] { - const accountProxy = accountProxies.find((ap) => ap.id === accountProxyId); + const accountProxy = accountProxies.find((ap) => { + if (!accountProxyId) { + return isAccountAll(ap.id); + } + + return ap.id === accountProxyId; + }); if (!accountProxy) { return []; @@ -265,7 +271,7 @@ const _SendFund = ({ className = '' }: Props): React.ReactElement => { const result: AccountAddressItemType[] = []; accountProxies.forEach((ap) => { - if (!(isAccountAll(fromAccountProxy) || ap.id === fromAccountProxy)) { + if (!(!fromAccountProxy || ap.id === fromAccountProxy)) { return; } @@ -672,7 +678,7 @@ const _SendFund = ({ className = '' }: Props): React.ReactElement => { } if (accountAddressItems.length === 1) { - if (!fromValue || !accountAddressItems.some((i) => i.address === fromValue)) { + if (!fromValue || accountAddressItems[0].address !== fromValue) { form.setFieldValue('from', accountAddressItems[0].address); } } else { diff --git a/packages/extension-koni-ui/src/Popup/Transaction/variants/Swap.tsx b/packages/extension-koni-ui/src/Popup/Transaction/variants/Swap.tsx index f6c354190f..ed18eb5f5b 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/variants/Swap.tsx +++ b/packages/extension-koni-ui/src/Popup/Transaction/variants/Swap.tsx @@ -4,28 +4,29 @@ import { _ChainAsset } from '@subwallet/chain-list/types'; import { SwapError } from '@subwallet/extension-base/background/errors/SwapError'; import { ExtrinsicType, NotificationType } from '@subwallet/extension-base/background/KoniTypes'; -import { _getAssetDecimals, _getAssetOriginChain, _getAssetSymbol, _getChainNativeTokenSlug, _getOriginChainOfAsset, _isChainEvmCompatible, _parseAssetRefKey } from '@subwallet/extension-base/services/chain-service/utils'; +import { _getAssetDecimals, _getAssetOriginChain, _getAssetSymbol, _getChainNativeTokenSlug, _getMultiChainAsset, _getOriginChainOfAsset, _isChainEvmCompatible, _parseAssetRefKey } from '@subwallet/extension-base/services/chain-service/utils'; import { getSwapAlternativeAsset } from '@subwallet/extension-base/services/swap-service/utils'; import { SWTransactionResponse } from '@subwallet/extension-base/services/transaction-service/types'; +import { AccountProxy, AccountProxyType } from '@subwallet/extension-base/types'; import { CommonFeeComponent, CommonOptimalPath, CommonStepType } from '@subwallet/extension-base/types/service-base'; import { SlippageType, SwapFeeType, SwapProviderId, SwapQuote, SwapRequest } from '@subwallet/extension-base/types/swap'; import { formatNumberString, swapCustomFormatter } from '@subwallet/extension-base/utils'; -import { AccountSelector, AddressInput, AlertBox, HiddenInput, MetaInfo, PageWrapper } from '@subwallet/extension-koni-ui/components'; +import { AccountAddressSelector, AddressInputNew, AlertBox, HiddenInput, MetaInfo, PageWrapper } from '@subwallet/extension-koni-ui/components'; import { SwapFromField, SwapToField } from '@subwallet/extension-koni-ui/components/Field/Swap'; import { AddMoreBalanceModal, ChooseFeeTokenModal, SlippageModal, SwapIdleWarningModal, SwapQuotesSelectorModal, SwapTermsOfServiceModal } from '@subwallet/extension-koni-ui/components/Modal/Swap'; import { QuoteResetTime, SwapRoute } from '@subwallet/extension-koni-ui/components/Swap'; -import { BN_TEN, BN_ZERO, CONFIRM_SWAP_TERM, DEFAULT_SWAP_PARAMS, SWAP_ALL_QUOTES_MODAL, SWAP_CHOOSE_FEE_TOKEN_MODAL, SWAP_IDLE_WARNING_MODAL, SWAP_MORE_BALANCE_MODAL, SWAP_SLIPPAGE_MODAL, SWAP_TERMS_OF_SERVICE_MODAL } from '@subwallet/extension-koni-ui/constants'; +import { BN_TEN, BN_ZERO, CONFIRM_SWAP_TERM, SWAP_ALL_QUOTES_MODAL, SWAP_CHOOSE_FEE_TOKEN_MODAL, SWAP_IDLE_WARNING_MODAL, SWAP_MORE_BALANCE_MODAL, SWAP_SLIPPAGE_MODAL, SWAP_TERMS_OF_SERVICE_MODAL } from '@subwallet/extension-koni-ui/constants'; import { DataContext } from '@subwallet/extension-koni-ui/contexts/DataContext'; -import { useChainConnection, useGetChainPrefixBySlug, useNotification, usePreCheckAction, useSelector, useSetCurrentPage, useTransactionContext, useWatchTransaction } from '@subwallet/extension-koni-ui/hooks'; +import { useChainConnection, useDefaultNavigate, useNotification, usePreCheckAction, useSelector, useSetCurrentPage, useTransactionContext, useWatchTransaction } from '@subwallet/extension-koni-ui/hooks'; import useHandleSubmitMultiTransaction from '@subwallet/extension-koni-ui/hooks/transaction/useHandleSubmitMultiTransaction'; import { getLatestSwapQuote, handleSwapRequest, handleSwapStep, validateSwapProcess } from '@subwallet/extension-koni-ui/messaging/transaction/swap'; import { FreeBalance, FreeBalanceToEarn, TransactionContent, TransactionFooter } from '@subwallet/extension-koni-ui/Popup/Transaction/parts'; import { CommonActionType, commonProcessReducer, DEFAULT_COMMON_PROCESS } from '@subwallet/extension-koni-ui/reducer'; import { RootState } from '@subwallet/extension-koni-ui/stores'; import { Theme } from '@subwallet/extension-koni-ui/themes'; -import { FormCallbacks, FormFieldData, SwapParams, ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { AccountAddressItemType, FormCallbacks, FormFieldData, SwapParams, ThemeProps } from '@subwallet/extension-koni-ui/types'; import { TokenSelectorItemType } from '@subwallet/extension-koni-ui/types/field'; -import { convertFieldToObject, findAccountByAddress, isAccountAll, reformatAddress } from '@subwallet/extension-koni-ui/utils'; +import { convertFieldToObject, findAccountByAddress, getReformatedAddressRelatedToNetwork, isAccountAll, isChainInfoAccordantNetworkType, isTokenCompatibleWithAccountNetworkTypes, reformatAddress } from '@subwallet/extension-koni-ui/utils'; import { ActivityIndicator, BackgroundIcon, Button, Form, Icon, Logo, ModalContext, Number, Tooltip } from '@subwallet/react-ui'; import BigN from 'bignumber.js'; import CN from 'classnames'; @@ -39,7 +40,11 @@ import { useLocalStorage } from 'usehooks-ts'; import { isAddress, isEthereumAddress } from '@polkadot/util-crypto'; -type Props = ThemeProps; +type WrapperProps = ThemeProps; + +type ComponentProps = { + targetAccountProxy: AccountProxy; +}; interface FeeItem { value: BigN, @@ -49,7 +54,7 @@ interface FeeItem { suffix?: string } -const hideFields: Array = ['fromAmount', 'fromTokenSlug', 'toTokenSlug', 'chain']; +const hideFields: Array = ['fromAmount', 'fromTokenSlug', 'toTokenSlug', 'chain', 'fromAccountProxy']; function getTokenSelectorItem (tokenSlugs: string[], assetRegistryMap: Record): TokenSelectorItemType[] { const result: TokenSelectorItemType[] = []; @@ -70,11 +75,11 @@ function getTokenSelectorItem (tokenSlugs: string[], assetRegistryMap: Record { +// todo: recheck validation logic, especially recipientAddress + +const Component = ({ targetAccountProxy }: ComponentProps) => { useSetCurrentPage('/transaction/swap'); const { t } = useTranslation(); const notify = useNotification(); @@ -82,7 +87,7 @@ const Component = () => { const { activeModal, inactiveAll, inactiveModal } = useContext(ModalContext); - const { accounts, currentAccount, isAllAccount } = useSelector((state) => state.accountState); + const { accountProxies, accounts } = useSelector((state) => state.accountState); const assetRegistryMap = useSelector((state) => state.assetRegistry.assetRegistry); const swapPairs = useSelector((state) => state.swap.swapPairs); const { currencyData, priceMap } = useSelector((state) => state.price); @@ -115,7 +120,7 @@ const Component = () => { const continueRefreshQuoteRef = useRef(false); const { token } = useTheme() as Theme; - const { defaultSlug: swapSlug } = defaultData; + const { defaultSlug } = defaultData; const onIdle = useCallback(() => { !hasInternalConfirmations && !!confirmedTerm && showQuoteArea && setRequestUserInteractToContinue(true); }, [confirmedTerm, hasInternalConfirmations, showQuoteArea]); @@ -166,30 +171,48 @@ const Component = () => { return result; }, [swapPairs]); - const rawFromTokenItems = useMemo(() => { - return getTokenSelectorItem(Object.keys(fromAndToTokenMap), assetRegistryMap); - }, [assetRegistryMap, fromAndToTokenMap]); - const fromTokenItems = useMemo(() => { - if (!fromValue) { - return rawFromTokenItems; - } + const rawTokenSlugs = Object.keys(fromAndToTokenMap); + const targetTokenSlugs: string[] = []; + + (() => { + // defaultSlug is just TokenSlug + if (defaultSlug && rawTokenSlugs.includes(defaultSlug)) { + if (isTokenCompatibleWithAccountNetworkTypes(defaultSlug, targetAccountProxy.networkTypes, chainInfoMap)) { + targetTokenSlugs.push(defaultSlug); + } - return rawFromTokenItems.filter((i) => { - return chainInfoMap[i.originChain] && isEthereumAddress(fromValue) === _isChainEvmCompatible(chainInfoMap[i.originChain]); - }); - }, [chainInfoMap, fromValue, rawFromTokenItems]); + return; + } - const filterFromAssetInfo = useMemo(() => { - if (!fromTokenItems || !assetRegistryMap) { - return []; - } + rawTokenSlugs.forEach((rts) => { + const assetInfo = assetRegistryMap[rts]; + + if (!assetInfo) { + return; + } - const filteredAssets = fromTokenItems.map((item) => assetRegistryMap[item.slug]) - .filter((chainAsset) => chainAsset.slug === swapSlug || chainAsset.multiChainAsset === swapSlug); + if (defaultSlug) { + // defaultSlug is MultiChainAssetSlug + if (_getMultiChainAsset(assetInfo) === defaultSlug && isTokenCompatibleWithAccountNetworkTypes(rts, targetAccountProxy.networkTypes, chainInfoMap)) { + targetTokenSlugs.push(rts); + } + + return; + } + + if (isTokenCompatibleWithAccountNetworkTypes(rts, targetAccountProxy.networkTypes, chainInfoMap)) { + targetTokenSlugs.push(rts); + } + }); + })(); + + if (targetTokenSlugs.length) { + return getTokenSelectorItem(targetTokenSlugs, assetRegistryMap); + } - return filteredAssets; - }, [assetRegistryMap, fromTokenItems, swapSlug]); + return []; + }, [assetRegistryMap, chainInfoMap, defaultSlug, fromAndToTokenMap, targetAccountProxy.networkTypes]); const toTokenItems = useMemo(() => { return getTokenSelectorItem(fromAndToTokenMap[fromTokenSlugValue] || [], assetRegistryMap); @@ -203,9 +226,7 @@ const Component = () => { return assetRegistryMap[toTokenSlugValue] || undefined; }, [assetRegistryMap, toTokenSlugValue]); - const destChain = toAssetInfo?.originChain; - const destChainNetworkPrefix = useGetChainPrefixBySlug(destChain); - const destChainGenesisHash = chainInfoMap[destChain]?.substrateInfo?.genesisHash || ''; + const destChainValue = _getAssetOriginChain(toAssetInfo); const feeAssetInfo = useMemo(() => { return (currentFeeOption ? assetRegistryMap[currentFeeOption] : undefined); @@ -216,15 +237,21 @@ const Component = () => { return false; } - if (!fromValue) { - return true; - } - - const toChain = _getAssetOriginChain(toAssetInfo); + return isTokenCompatibleWithAccountNetworkTypes(toTokenSlugValue, targetAccountProxy.networkTypes, chainInfoMap); + }, [chainInfoMap, fromAndToTokenMap, targetAccountProxy.networkTypes, toTokenSlugValue]); - return chainInfoMap[toChain] && isEthereumAddress(fromValue) === _isChainEvmCompatible(chainInfoMap[toChain]); - }, [chainInfoMap, fromAndToTokenMap, fromValue, toAssetInfo, toTokenSlugValue]); + const onSwitchSide = useCallback(() => { + if (fromTokenSlugValue && toTokenSlugValue) { + form.setFieldsValue({ + fromTokenSlug: toTokenSlugValue, + toTokenSlug: fromTokenSlugValue, + from: '', + recipient: undefined + }); + } + }, [form, fromTokenSlugValue, toTokenSlugValue]); + // todo: this logic is only true with substrate, evm address. Make sure it work with ton, bitcoin, and more const recipientAddressValidator = useCallback((rule: Rule, _recipientAddress: string): Promise => { if (!_recipientAddress) { return Promise.reject(t('Recipient address is required')); @@ -270,18 +297,19 @@ const Component = () => { }, [accounts, chainInfoMap, t, toAssetInfo]); const showRecipientField = useMemo(() => { - if (fromValue && toAssetInfo?.originChain && - chainInfoMap[toAssetInfo?.originChain]) { - const isAddressEvm = isEthereumAddress(fromValue); - const isEvmCompatibleTo = _isChainEvmCompatible( - chainInfoMap[toAssetInfo?.originChain] - ); - - return isAddressEvm !== isEvmCompatibleTo; + if (!fromValue || !destChainValue || !chainInfoMap[destChainValue]) { + return false; + } + + // todo: convert this find logic to util + const fromAccountJson = accounts.find((account) => account.address === fromValue); + + if (!fromAccountJson) { + return false; } - return false; // Add a default return value in case none of the conditions are met - }, [chainInfoMap, fromValue, toAssetInfo]); + return !isChainInfoAccordantNetworkType(chainInfoMap[destChainValue], fromAccountJson.networkType); + }, [accounts, chainInfoMap, destChainValue, fromValue]); const onSelectFromToken = useCallback((tokenSlug: string) => { form.setFieldValue('fromTokenSlug', tokenSlug); @@ -334,21 +362,6 @@ const Component = () => { form.setFieldValue('fromAmount', value); }, [form]); - const onSwitchSide = useCallback(() => { - if (fromTokenSlugValue && toTokenSlugValue) { - form.setFieldsValue({ - fromTokenSlug: toTokenSlugValue, - toTokenSlug: fromTokenSlugValue - }); - form.validateFields(['from', 'recipient']).then(() => { - setIsFormInvalid(false); - }).catch((e) => { - console.log('Error when validating', e); - setIsFormInvalid(true); - }); - } - }, [form, fromTokenSlugValue, toTokenSlugValue]); - const onFieldsChange: FormCallbacks['onFieldsChange'] = useCallback((changedFields: FormFieldData[], allFields: FormFieldData[]) => { const values = convertFieldToObject(allFields); @@ -834,9 +847,65 @@ const Component = () => { return result; }, [chainInfoMap, currentPair, fromAssetInfo, isSwapXCM]); - const fromTokenLists = useMemo(() => { - return swapSlug ? filterFromAssetInfo : fromTokenItems; - }, [swapSlug, filterFromAssetInfo, fromTokenItems]); + const addressInputResolver = useCallback((input: string, chainSlug: string) => { + return Promise.resolve([]); + }, []); + + const accountAddressItems = useMemo(() => { + const chainInfo = chainValue ? chainInfoMap[chainValue] : undefined; + + if (!chainInfo) { + return []; + } + + const result: AccountAddressItemType[] = []; + + accountProxies.forEach((ap) => { + if (!(isAccountAll(targetAccountProxy.id) || ap.id === targetAccountProxy.id)) { + return; + } + + if ([AccountProxyType.READ_ONLY, AccountProxyType.LEDGER].includes(ap.accountType)) { + return; + } + + ap.accounts.forEach((a) => { + const address = getReformatedAddressRelatedToNetwork(a, chainInfo); + + if (address) { + result.push({ + accountName: ap.name, + accountProxyId: ap.id, + accountProxyType: ap.accountType, + accountType: a.type, + address + }); + } + }); + }); + + return result; + }, [accountProxies, chainInfoMap, chainValue, targetAccountProxy.id]); + + useEffect(() => { + const updateFromValue = () => { + if (!accountAddressItems.length) { + return; + } + + if (accountAddressItems.length === 1) { + if (!fromValue || accountAddressItems[0].address !== fromValue) { + form.setFieldValue('from', accountAddressItems[0].address); + } + } else { + if (fromValue && !accountAddressItems.some((i) => i.address === fromValue)) { + form.setFieldValue('from', ''); + } + } + }; + + updateFromValue(); + }, [accountAddressItems, form, fromValue]); useEffect(() => { setBackProps((prev) => ({ @@ -1026,19 +1095,19 @@ const Component = () => { }, [activeModal, inactiveAll, requestUserInteractToContinue]); useEffect(() => { - if (fromTokenLists.length) { + if (fromTokenItems.length) { if (!fromTokenSlugValue) { - form.setFieldValue('fromTokenSlug', fromTokenLists[0].slug); + form.setFieldValue('fromTokenSlug', fromTokenItems[0].slug); } else { - if (!fromTokenLists.some((i) => i.slug === fromTokenSlugValue)) { - form.setFieldValue('fromTokenSlug', fromTokenLists[0].slug); + if (!fromTokenItems.some((i) => i.slug === fromTokenSlugValue)) { + form.setFieldValue('fromTokenSlug', fromTokenItems[0].slug); } } } else { form.setFieldValue('fromTokenSlug', ''); form.setFieldValue('toTokenSlug', ''); } - }, [filterFromAssetInfo, form, fromTokenLists, fromTokenSlugValue, fromValue]); + }, [form, fromTokenItems, fromTokenSlugValue]); useEffect(() => { if (toTokenItems.length) { @@ -1048,31 +1117,6 @@ const Component = () => { } }, [form, toTokenItems, toTokenSlugValue]); - const defaultFromValue = useMemo(() => { - return currentAccount?.address ? isAccountAll(currentAccount.address) ? '' : currentAccount.address : ''; - }, [currentAccount?.address]); - - useEffect(() => { - if (defaultData.from !== defaultFromValue && !isAllAccount) { - form.setFieldValue('from', defaultFromValue); - } - }, [defaultData, defaultFromValue, form, fromValue, isAllAccount]); - - useEffect(() => { - const restoreFormDefault = () => { - persistData({ - ...DEFAULT_SWAP_PARAMS, - from: defaultFromValue - }); - }; - - window.addEventListener('beforeunload', restoreFormDefault); - - return () => { - window.removeEventListener('beforeunload', restoreFormDefault); - }; - }, [defaultFromValue, persistData]); - useEffect(() => { if (altChain && !checkChainConnected(altChain)) { turnOnChain(altChain); @@ -1087,10 +1131,6 @@ const Component = () => { return false; }, [altChain, checkChainConnected]); - const onFilterAccount = useMemo(() => { - return accounts.filter((account) => !isAccountAll(account.address) && !account.isHardware); - }, [accounts]); - const networkName = useMemo(() => { return (isEthereumAddress(fromValue)) ? 'Polkadot' : 'Ethereum'; }, [fromValue]); @@ -1143,17 +1183,6 @@ const Component = () => { > - - - -
{ label={t('From')} onChangeAmount={onChangeAmount} onSelectToken={onSelectFromToken} - tokenSelectorItems={fromTokenLists} + tokenSelectorItems={fromTokenItems} tokenSelectorValue={fromTokenSlugValue} /> @@ -1195,7 +1224,17 @@ const Component = () => { />
- {swapSlug && !fromAssetInfo && ( + + + + + {defaultSlug && !fromAssetInfo && ( { } ]} statusHelpAsTooltip={true} - validateTrigger='onBlur' > - @@ -1564,21 +1599,46 @@ const Component = () => { ); }; -const Wrapper: React.FC = (props: Props) => { +const Wrapper: React.FC = (props: WrapperProps) => { const { className } = props; const dataContext = useContext(DataContext); + const { defaultData } = useTransactionContext(); + const { goHome } = useDefaultNavigate(); + const accountProxies = useSelector((state) => state.accountState.accountProxies); + + const targetAccountProxy = useMemo(() => { + return accountProxies.find((ap) => { + if (!defaultData.fromAccountProxy) { + return isAccountAll(ap.id); + } + + return ap.id === defaultData.fromAccountProxy; + }); + }, [accountProxies, defaultData.fromAccountProxy]); + + useEffect(() => { + if (!targetAccountProxy) { + goHome(); + } + }, [goHome, targetAccountProxy]); + + if (!targetAccountProxy) { + return ( + <> + ); + } return ( - + ); }; -const Swap = styled(Wrapper)(({ theme: { token } }: Props) => { +const Swap = styled(Wrapper)(({ theme: { token } }: WrapperProps) => { return { '.__fee-paid-wrapper': { color: token.colorTextTertiary, diff --git a/packages/extension-koni-ui/src/utils/chain/chain.ts b/packages/extension-koni-ui/src/utils/chain/chain.ts index fba673b609..c035750c83 100644 --- a/packages/extension-koni-ui/src/utils/chain/chain.ts +++ b/packages/extension-koni-ui/src/utils/chain/chain.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { _ChainInfo, _ChainStatus } from '@subwallet/chain-list/types'; -import { _getSubstrateGenesisHash, _isChainBitcoinCompatible, _isChainEvmCompatible, _isChainSubstrateCompatible, _isChainTonCompatible, _isPureSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils'; +import { _getSubstrateGenesisHash, _isChainBitcoinCompatible, _isChainEvmCompatible, _isChainTonCompatible, _isPureSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils'; import { AccountNetworkType } from '@subwallet/extension-base/types'; export const findChainInfoByGenesisHash = (chainMap: Record, genesisHash?: string): _ChainInfo | null => { @@ -53,6 +53,10 @@ export const isChainInfoAccordantNetworkType = (chainInfo: _ChainInfo, networkTy return false; }; +export const isChainCompatibleWithAccountNetworkTypes = (chainInfo: _ChainInfo, networkTypes: AccountNetworkType[]): boolean => { + return networkTypes.some((networkType) => isChainInfoAccordantNetworkType(chainInfo, networkType)); +}; + export const getChainsByAccountType = (_chainInfoMap: Record, networkTypes: AccountNetworkType[], specialNetwork?: string): string[] => { const chainInfoMap = Object.fromEntries(Object.entries(_chainInfoMap).filter(([, chainInfo]) => chainInfo.chainStatus === _ChainStatus.ACTIVE)); @@ -62,11 +66,8 @@ export const getChainsByAccountType = (_chainInfoMap: Record const result: string[] = []; for (const chainInfo of Object.values(chainInfoMap)) { - const chain = chainInfo.slug; - const isChainCompatible = networkTypes.some((networkType) => isChainInfoAccordantNetworkType(chainInfo, networkType)); - - if (isChainCompatible) { - result.push(chain); + if (isChainCompatibleWithAccountNetworkTypes(chainInfo, networkTypes)) { + result.push(chainInfo.slug); } } diff --git a/packages/extension-koni-ui/src/utils/chain/chainAndAsset.ts b/packages/extension-koni-ui/src/utils/chain/chainAndAsset.ts index 1da7776f9f..e003115a2b 100644 --- a/packages/extension-koni-ui/src/utils/chain/chainAndAsset.ts +++ b/packages/extension-koni-ui/src/utils/chain/chainAndAsset.ts @@ -1,10 +1,12 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { _ChainAsset } from '@subwallet/chain-list/types'; +import { _ChainAsset, _ChainInfo } from '@subwallet/chain-list/types'; import { AssetSetting } from '@subwallet/extension-base/background/KoniTypes'; import { _ChainState } from '@subwallet/extension-base/services/chain-service/types'; -import { _isAssetFungibleToken } from '@subwallet/extension-base/services/chain-service/utils'; +import { _getOriginChainOfAsset, _isAssetFungibleToken } from '@subwallet/extension-base/services/chain-service/utils'; +import { AccountNetworkType } from '@subwallet/extension-base/types'; +import { isChainCompatibleWithAccountNetworkTypes } from '@subwallet/extension-koni-ui/utils'; export function isTokenAvailable ( chainAsset: _ChainAsset, @@ -26,3 +28,18 @@ export function isTokenAvailable ( return isAssetVisible && isAssetFungible && isValidLedger; } + +export function getChainInfoFromToken (tokenSlug: string, chainInfoMap: Record): _ChainInfo | undefined { + const chainSlug = _getOriginChainOfAsset(tokenSlug); + + return chainInfoMap[chainSlug]; +} + +export function isTokenCompatibleWithAccountNetworkTypes ( + tokenSlug: string, + networkTypes: AccountNetworkType[], + chainInfoMap: Record): boolean { + const chainInfo = getChainInfoFromToken(tokenSlug, chainInfoMap); + + return !!chainInfo && isChainCompatibleWithAccountNetworkTypes(chainInfo, networkTypes); +} diff --git a/packages/extension-koni-ui/src/utils/transaction/formValue.ts b/packages/extension-koni-ui/src/utils/transaction/formValue.ts new file mode 100644 index 0000000000..d28d10367a --- /dev/null +++ b/packages/extension-koni-ui/src/utils/transaction/formValue.ts @@ -0,0 +1,9 @@ +// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { AccountProxy } from '@subwallet/extension-base/types'; +import { isAccountAll } from '@subwallet/extension-koni-ui/utils'; + +export const getTransactionFromAccountProxyValue = (currentAccountProxy: AccountProxy | null): string => { + return currentAccountProxy?.id ? isAccountAll(currentAccountProxy.id) ? '' : currentAccountProxy.id : ''; +}; diff --git a/packages/extension-koni-ui/src/utils/transaction/index.ts b/packages/extension-koni-ui/src/utils/transaction/index.ts index 2c76bc6920..5fee704bce 100644 --- a/packages/extension-koni-ui/src/utils/transaction/index.ts +++ b/packages/extension-koni-ui/src/utils/transaction/index.ts @@ -4,3 +4,4 @@ export * from './detectType'; export * from './persist'; export * from './stake'; +export * from './formValue'; From fc72b78082253c5498f062caea77f23318a965b8 Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Tue, 20 Aug 2024 18:31:17 +0700 Subject: [PATCH 133/424] fix eslint --- .../src/services/balance-service/transfer/token.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/extension-base/src/services/balance-service/transfer/token.ts b/packages/extension-base/src/services/balance-service/transfer/token.ts index 6a902c3d52..a877d8a592 100644 --- a/packages/extension-base/src/services/balance-service/transfer/token.ts +++ b/packages/extension-base/src/services/balance-service/transfer/token.ts @@ -14,7 +14,7 @@ import { calculateGasFeeParams } from '@subwallet/extension-base/services/fee-se import { getGRC20ContractPromise, getVFTContractPromise } from '@subwallet/extension-base/utils'; import { keyring } from '@subwallet/ui-keyring'; import { internal } from '@ton/core'; -import {Address, WalletContractV4} from '@ton/ton'; +import { Address, WalletContractV4 } from '@ton/ton'; import BigN from 'bignumber.js'; import { TransactionConfig } from 'web3-core'; From ef32b0419bee1ff864b4f4563056e340ca30d67b Mon Sep 17 00:00:00 2001 From: lw Date: Tue, 20 Aug 2024 18:56:44 +0700 Subject: [PATCH 134/424] [Util] Fix issue related to out-date function --- .../src/utils/account/account.ts | 3 +- .../src/utils/account/reformatAddress.ts | 33 ++----------------- 2 files changed, 4 insertions(+), 32 deletions(-) diff --git a/packages/extension-koni-ui/src/utils/account/account.ts b/packages/extension-koni-ui/src/utils/account/account.ts index 858e8e36b8..8443f06306 100644 --- a/packages/extension-koni-ui/src/utils/account/account.ts +++ b/packages/extension-koni-ui/src/utils/account/account.ts @@ -7,11 +7,10 @@ import { AccountAuthType } from '@subwallet/extension-base/background/types'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; import { _getChainSubstrateAddressPrefix, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; import { AbstractAddressJson, AccountJson, AccountNetworkType } from '@subwallet/extension-base/types'; -import { isAccountAll, uniqueStringArray } from '@subwallet/extension-base/utils'; +import { isAccountAll, reformatAddress, uniqueStringArray } from '@subwallet/extension-base/utils'; import { DEFAULT_ACCOUNT_TYPES, EVM_ACCOUNT_TYPE, SUBSTRATE_ACCOUNT_TYPE } from '@subwallet/extension-koni-ui/constants'; import { MODE_CAN_SIGN } from '@subwallet/extension-koni-ui/constants/signing'; import { AccountAddressType, AccountSignMode, AccountType } from '@subwallet/extension-koni-ui/types'; -import reformatAddress from '@subwallet/extension-koni-ui/utils/account/reformatAddress'; import { getNetworkKeyByGenesisHash } from '@subwallet/extension-koni-ui/utils/chain/getNetworkJsonByGenesisHash'; import { AccountInfoByNetwork } from '@subwallet/extension-koni-ui/utils/types'; diff --git a/packages/extension-koni-ui/src/utils/account/reformatAddress.ts b/packages/extension-koni-ui/src/utils/account/reformatAddress.ts index 54149ba3ab..8fa26e9f70 100644 --- a/packages/extension-koni-ui/src/utils/account/reformatAddress.ts +++ b/packages/extension-koni-ui/src/utils/account/reformatAddress.ts @@ -1,36 +1,9 @@ // Copyright 2019-2022 @polkadot/extension-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { isAccountAll } from '@subwallet/extension-koni-ui/utils/account/accountAll'; - -import { decodeAddress, encodeAddress, ethereumEncode, isAddress, isEthereumAddress } from '@polkadot/util-crypto'; +import { reformatAddress as baseReformatAddress } from '@subwallet/extension-base/utils'; +// todo: migrate all usages to the one in extension-base/utils then remove this function export default function reformatAddress (address: string, networkPrefix = 42, isEthereum = false): string { - if (!isAddress(address)) { - return address; - } - - if (isAccountAll(address)) { - return address; - } - - if (isEthereumAddress(address)) { - return address; - } - - try { - const publicKey = decodeAddress(address); - - if (isEthereum) { - return ethereumEncode(publicKey); - } - - if (networkPrefix < 0) { - return address; - } - - return encodeAddress(publicKey, networkPrefix); - } catch { - return address; - } + return baseReformatAddress(address, networkPrefix, isEthereum); } From 00259f00ea9e3924434efc3a26d063b77afdaea2 Mon Sep 17 00:00:00 2001 From: lw Date: Tue, 20 Aug 2024 19:03:21 +0700 Subject: [PATCH 135/424] [UI] Fix text issues --- .../src/Popup/Transaction/variants/SendFund.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx index 785be1ea9e..563417c100 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx +++ b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx @@ -503,7 +503,7 @@ const _SendFund = ({ className = '' }: Props): React.ReactElement => { transferAll: isTransferAll }); } else { - // Make cross chainValue transfer + // Make cross chain transfer sendPromise = makeCrossChainTransfer({ destinationNetworkKey: destChain, from, @@ -600,7 +600,7 @@ const _SendFund = ({ className = '' }: Props): React.ReactElement => { const onSubmit: FormCallbacks['onFinish'] = useCallback((values: TransferParams) => { if (values.chain !== values.destChain) { - const originChainInfo = chainInfoMap[chainValue]; + const originChainInfo = chainInfoMap[values.chain]; const destChainInfo = chainInfoMap[values.destChain]; if (_isXcmTransferUnstable(originChainInfo, destChainInfo)) { @@ -652,7 +652,7 @@ const _SendFund = ({ className = '' }: Props): React.ReactElement => { } doSubmit(values); - }, [assetInfo, chainValue, chainInfoMap, closeAlert, doSubmit, isTransferAll, openAlert, t]); + }, [assetInfo, chainInfoMap, closeAlert, doSubmit, isTransferAll, openAlert, t]); // todo: recheck with ledger account useEffect(() => { @@ -806,8 +806,8 @@ const _SendFund = ({ className = '' }: Props): React.ReactElement => {
@@ -877,7 +877,7 @@ const _SendFund = ({ className = '' }: Props): React.ReactElement => { chainValue !== destChainValue && (
From 815179e1cd44e959005b9147951473ebdb6b2997 Mon Sep 17 00:00:00 2001 From: S2kael Date: Wed, 21 Aug 2024 12:03:18 +0700 Subject: [PATCH 136/424] [Issue-3485] Add feature to import ton with secret key --- .../src/background/KoniTypes.ts | 2 +- .../src/koni/background/handlers/Extension.ts | 8 +-- .../context/account-context.ts | 4 +- .../context/handlers/Secret.ts | 34 +++++++--- .../src/types/account/action/add/index.ts | 3 +- .../src/types/account/action/add/metamask.ts | 20 ------ .../src/types/account/action/add/secret.ts | 62 +++++++++++++++++++ .../src/types/account/action/add/substrate.ts | 13 ---- .../src/Popup/Account/ImportPrivateKey.tsx | 32 ++++++---- .../src/Popup/Debugger/DebuggerAPI.tsx | 2 +- .../src/messaging/accounts/validate.ts | 2 +- .../src/Popup/Debugger/DebuggerAPI.tsx | 2 +- .../src/messaging/accounts/validate.ts | 2 +- yarn.lock | 8 +-- 14 files changed, 121 insertions(+), 73 deletions(-) delete mode 100644 packages/extension-base/src/types/account/action/add/metamask.ts create mode 100644 packages/extension-base/src/types/account/action/add/secret.ts delete mode 100644 packages/extension-base/src/types/account/action/add/substrate.ts diff --git a/packages/extension-base/src/background/KoniTypes.ts b/packages/extension-base/src/background/KoniTypes.ts index e600584b33..880368dbcc 100644 --- a/packages/extension-base/src/background/KoniTypes.ts +++ b/packages/extension-base/src/background/KoniTypes.ts @@ -2036,7 +2036,7 @@ export interface KoniRequestSignatures { // Validate 'pri(accounts.validate.seed)': [RequestMnemonicValidateV2, ResponseMnemonicValidateV2]; - 'pri(accounts.validate.metamask.privateKey)': [RequestPrivateKeyValidateV2, ResponsePrivateKeyValidateV2]; + 'pri(accounts.validate.privateKey)': [RequestPrivateKeyValidateV2, ResponsePrivateKeyValidateV2]; 'pri(accounts.validate.substrate.publicAndPrivateKey)': [RequestCheckPublicAndSecretKey, ResponseCheckPublicAndSecretKey]; // Create account diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index a09fc3149f..3aa76d7c64 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -1080,8 +1080,8 @@ export default class KoniExtension { return this.#koniState.keyringService.context.mnemonicValidateV2(request); } - private metamaskPrivateKeyValidateV2 (request: RequestPrivateKeyValidateV2): ResponsePrivateKeyValidateV2 { - return this.#koniState.keyringService.context.metamaskPrivateKeyValidateV2(request); + private privateKeyValidateV2 (request: RequestPrivateKeyValidateV2): ResponsePrivateKeyValidateV2 { + return this.#koniState.keyringService.context.privateKeyValidateV2(request); } private jsonRestoreV2 (request: RequestJsonRestoreV2): void { @@ -3807,8 +3807,8 @@ export default class KoniExtension { // Validate account case 'pri(accounts.validate.seed)': return this.seedValidateV2(request as RequestMnemonicValidateV2); - case 'pri(accounts.validate.metamask.privateKey)': - return this.metamaskPrivateKeyValidateV2(request as RequestPrivateKeyValidateV2); + case 'pri(accounts.validate.privateKey)': + return this.privateKeyValidateV2(request as RequestPrivateKeyValidateV2); case 'pri(accounts.validate.substrate.publicAndPrivateKey)': return this.checkPublicAndSecretKey(request as RequestCheckPublicAndSecretKey); diff --git a/packages/extension-base/src/services/keyring-service/context/account-context.ts b/packages/extension-base/src/services/keyring-service/context/account-context.ts index 4c68b3d28f..4bb66ceaab 100644 --- a/packages/extension-base/src/services/keyring-service/context/account-context.ts +++ b/packages/extension-base/src/services/keyring-service/context/account-context.ts @@ -132,8 +132,8 @@ export class AccountContext { } /* Import ethereum account with the private key */ - public metamaskPrivateKeyValidateV2 (request: RequestPrivateKeyValidateV2): ResponsePrivateKeyValidateV2 { - return this.secretHandler.metamaskPrivateKeyValidateV2(request); + public privateKeyValidateV2 (request: RequestPrivateKeyValidateV2): ResponsePrivateKeyValidateV2 { + return this.secretHandler.privateKeyValidateV2(request); } /* Import ethereum account with the private key */ diff --git a/packages/extension-base/src/services/keyring-service/context/handlers/Secret.ts b/packages/extension-base/src/services/keyring-service/context/handlers/Secret.ts index 0620561099..74d9fc797b 100644 --- a/packages/extension-base/src/services/keyring-service/context/handlers/Secret.ts +++ b/packages/extension-base/src/services/keyring-service/context/handlers/Secret.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { AccountExternalError, AccountExternalErrorCode, RequestAccountCreateExternalV2, RequestAccountCreateWithSecretKey, RequestAccountExportPrivateKey, ResponseAccountCreateWithSecretKey, ResponseAccountExportPrivateKey } from '@subwallet/extension-base/background/KoniTypes'; -import { RequestCheckPublicAndSecretKey, RequestPrivateKeyValidateV2, ResponseCheckPublicAndSecretKey, ResponsePrivateKeyValidateV2 } from '@subwallet/extension-base/types'; +import { AccountChainType, RequestCheckPublicAndSecretKey, RequestPrivateKeyValidateV2, ResponseCheckPublicAndSecretKey, ResponsePrivateKeyValidateV2 } from '@subwallet/extension-base/types'; import { getKeypairTypeByAddress } from '@subwallet/keyring'; import { decodePair } from '@subwallet/keyring/pair/decode'; import { BitcoinKeypairTypes, KeypairType, KeyringPair, KeyringPair$Meta, TonKeypairTypes } from '@subwallet/keyring/types'; @@ -74,20 +74,38 @@ export class AccountSecretHandler extends AccountBaseHandler { } /* Import ethereum account with the private key */ - private _checkValidatePrivateKey ({ privateKey }: RequestPrivateKeyValidateV2, autoAddPrefix = false): ResponsePrivateKeyValidateV2 { + private _checkValidatePrivateKey ({ chainType, privateKey }: RequestPrivateKeyValidateV2, autoAddPrefix = false): ResponsePrivateKeyValidateV2 { const { phrase } = keyExtractSuri(privateKey); const rs = { autoAddPrefix: autoAddPrefix, addressMap: {} } as ResponsePrivateKeyValidateV2; - const types: KeypairType[] = ['ethereum']; + const types: KeypairType[] = []; + + if (chainType) { + switch (chainType) { + case AccountChainType.ETHEREUM: + types.push('ethereum'); + break; + case AccountChainType.TON: + types.push('ton'); + break; + } + } else { + if (isHex(phrase, 256)) { + types.push('ethereum'); + } else if (isHex(phrase, 512)) { + types.push('ton'); + } + } types.forEach((type) => { // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access rs.addressMap[type] = ''; }); - if (isHex(phrase) && isHex(phrase, 256)) { + if (types.length) { types && types.forEach((type) => { rs.addressMap[type] = keyring.createFromUri(privateKey, {}, type).address; }); + rs.keyTypes = types; } else { rs.autoAddPrefix = false; assert(false, t('Invalid private key. Please try again.')); @@ -100,14 +118,10 @@ export class AccountSecretHandler extends AccountBaseHandler { return rs; } - public metamaskPrivateKeyValidateV2 ({ privateKey }: RequestPrivateKeyValidateV2): ResponsePrivateKeyValidateV2 { + public privateKeyValidateV2 ({ chainType, privateKey }: RequestPrivateKeyValidateV2): ResponsePrivateKeyValidateV2 { const isHex = privateKey.startsWith('0x'); - if (isHex) { - return this._checkValidatePrivateKey({ privateKey }); - } else { - return this._checkValidatePrivateKey({ privateKey: `0x${privateKey}` }, true); - } + return this._checkValidatePrivateKey({ chainType, privateKey }, !isHex); } public async accountsCreateWithSecret (request: RequestAccountCreateWithSecretKey): Promise { diff --git a/packages/extension-base/src/types/account/action/add/index.ts b/packages/extension-base/src/types/account/action/add/index.ts index 0e36a5c494..442999af3b 100644 --- a/packages/extension-base/src/types/account/action/add/index.ts +++ b/packages/extension-base/src/types/account/action/add/index.ts @@ -1,6 +1,5 @@ // Copyright 2019-2022 @subwallet/extension-base authors & contributors // SPDX-License-Identifier: Apache-2.0 -export * from './metamask'; export * from './mnemonic'; -export * from './substrate'; +export * from './secret'; diff --git a/packages/extension-base/src/types/account/action/add/metamask.ts b/packages/extension-base/src/types/account/action/add/metamask.ts deleted file mode 100644 index b99cc8149e..0000000000 --- a/packages/extension-base/src/types/account/action/add/metamask.ts +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2019-2022 @subwallet/extension-base authors & contributors -// SPDX-License-Identifier: Apache-2.0 - -import { KeypairType } from '@subwallet/keyring/types'; - -export interface RequestPrivateKeyValidateV2 { - privateKey: string; -} - -/** - * @interface ResponsePrivateKeyValidateV2 - * @description Represents the response for validating a private key. - * - * @property {Record} addressMap - A map of key pair types to their corresponding addresses. - * @property {boolean} autoAddPrefix - Indicates if the prefix should be automatically added. - */ -export interface ResponsePrivateKeyValidateV2 { - addressMap: Record, - autoAddPrefix: boolean -} diff --git a/packages/extension-base/src/types/account/action/add/secret.ts b/packages/extension-base/src/types/account/action/add/secret.ts new file mode 100644 index 0000000000..212b2cb557 --- /dev/null +++ b/packages/extension-base/src/types/account/action/add/secret.ts @@ -0,0 +1,62 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { KeypairType } from '@subwallet/keyring/types'; + +import { AccountNetworkType } from '../../info/keyring'; + +/** + * @interface RequestPrivateKeyValidateV2 + * @description Represents the request payload for validating a private key. + * + * Use for ethereum and ton private key only. + * + * @property {string} privateKey - The private key to be validated. + * @property {AccountNetworkType} [chainType] - Optional chain type associated with the private key. + * If not provided, the chain type will be determined based on the private key length (work only with 2 keypair types). + */ +export interface RequestPrivateKeyValidateV2 { + privateKey: string; + chainType?: AccountNetworkType; +} + +/** + * @interface ResponsePrivateKeyValidateV2 + * @description Represents the response for validating a private key. + * + * @property {Record} addressMap - A map of key pair types to their corresponding addresses. + * @property {boolean} autoAddPrefix - Indicates if the prefix should be automatically added. + */ +export interface ResponsePrivateKeyValidateV2 { + addressMap: Record; + autoAddPrefix: boolean; + keyTypes: KeypairType[]; +} + +/** + * @interface RequestCheckPublicAndSecretKey + * @description Represents the request payload for checking the validity of a public and secret key pair. + * + * Use for check ethereum and substrate key pair only. + * + * @property {string} secretKey - The secret key to be validated. + * @property {string} publicKey - The public key to be validated. + */ +export interface RequestCheckPublicAndSecretKey { + secretKey: string; + publicKey: string; +} + +/** + * @interface ResponseCheckPublicAndSecretKey + * @description Represents the response for checking the validity of a public and secret key pair. + * + * @property {string} address - The address derived from the public and secret key pair. + * @property {boolean} isValid - Indicates whether the public and secret key pair is valid. + * @property {boolean} isEthereum - Indicates whether the key pair is for an Ethereum account. + */ +export interface ResponseCheckPublicAndSecretKey { + address: string; + isValid: boolean; + isEthereum: boolean; +} diff --git a/packages/extension-base/src/types/account/action/add/substrate.ts b/packages/extension-base/src/types/account/action/add/substrate.ts deleted file mode 100644 index 0d27980e42..0000000000 --- a/packages/extension-base/src/types/account/action/add/substrate.ts +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2019-2022 @subwallet/extension-base authors & contributors -// SPDX-License-Identifier: Apache-2.0 - -export interface RequestCheckPublicAndSecretKey { - secretKey: string; - publicKey: string; -} - -export interface ResponseCheckPublicAndSecretKey { - address: string; - isValid: boolean; - isEthereum: boolean; -} diff --git a/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx b/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx index 057ab18326..42c78a1bb7 100644 --- a/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx @@ -1,12 +1,12 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { CloseIcon, Layout, PageWrapper, PrivateKeyInput } from '@subwallet/extension-koni-ui/components'; -import { EVM_ACCOUNT_TYPE } from '@subwallet/extension-koni-ui/constants/account'; +import { CloseIcon, HiddenInput, Layout, PageWrapper, PrivateKeyInput } from '@subwallet/extension-koni-ui/components'; import { IMPORT_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants/modal'; import { useAutoNavigateToCreatePassword, useCompleteCreateAccount, useDefaultNavigate, useFocusFormItem, useGetDefaultAccountName, useGoBackFromCreateAccount, useTranslation, useUnlockChecker } from '@subwallet/extension-koni-ui/hooks'; import { createAccountSuriV2, validateMetamaskPrivateKeyV2 } from '@subwallet/extension-koni-ui/messaging'; import { FormCallbacks, ThemeProps, ValidateState } from '@subwallet/extension-koni-ui/types'; +import { KeypairType } from '@subwallet/keyring/types'; import { Button, Form, Icon } from '@subwallet/react-ui'; import CN from 'classnames'; import { Eye, EyeSlash, FileArrowDown } from 'phosphor-react'; @@ -23,10 +23,13 @@ const FooterIcon = ( ); const formName = 'import-private-key-form'; -const fieldName = 'private-key'; +const privateKeyField = 'private-key'; +const typeField = 'type'; +const hiddenFields = [typeField]; interface FormState { - [fieldName]: string; + [privateKeyField]: string; + [typeField]: KeypairType; } const Component: React.FC = ({ className }: Props) => { @@ -51,12 +54,12 @@ const Component: React.FC = ({ className }: Props) => { const accountName = useGetDefaultAccountName(); // Auto-focus field - useFocusFormItem(form, fieldName); + useFocusFormItem(form, privateKeyField); - const privateKey = Form.useWatch(fieldName, form); + const privateKey = Form.useWatch(privateKeyField, form); const onSubmit: FormCallbacks['onFinish'] = useCallback((values: FormState) => { - const { [fieldName]: privateKey } = values; + const { [privateKeyField]: privateKey, [typeField]: keypairType } = values; checkUnlock().then(() => { if (privateKey?.trim()) { @@ -65,7 +68,7 @@ const Component: React.FC = ({ className }: Props) => { name: accountName, suri: privateKey.trim(), isAllowed: true, - type: EVM_ACCOUNT_TYPE + type: keypairType }) .then(() => { onComplete(); @@ -103,12 +106,14 @@ const Component: React.FC = ({ className }: Props) => { timeOutRef.current = setTimeout(() => { validateMetamaskPrivateKeyV2(privateKey.trim()) - .then(({ autoAddPrefix }) => { + .then(({ autoAddPrefix, keyTypes }) => { if (amount) { if (autoAddPrefix) { - form.setFieldValue(fieldName, `0x${privateKey}`); + form.setFieldValue(privateKeyField, `0x${privateKey}`); } + form.setFieldValue(typeField, keyTypes[0]); + setValidateState({}); } }) @@ -142,7 +147,7 @@ const Component: React.FC = ({ className }: Props) => { }, [privateKey, form, changed, t]); const onValuesChange: FormCallbacks['onValuesChange'] = useCallback((changedValues: Partial) => { - if (fieldName in changedValues) { + if (privateKeyField in changedValues) { setChanged(true); } }, []); @@ -177,13 +182,14 @@ const Component: React.FC = ({ className }: Props) => {
+ { - return sendMessage('pri(accounts.validate.metamask.privateKey)', { privateKey }); + return sendMessage('pri(accounts.validate.privateKey)', { privateKey }); } diff --git a/packages/extension-web-ui/src/Popup/Debugger/DebuggerAPI.tsx b/packages/extension-web-ui/src/Popup/Debugger/DebuggerAPI.tsx index de537c8dc8..8220786035 100644 --- a/packages/extension-web-ui/src/Popup/Debugger/DebuggerAPI.tsx +++ b/packages/extension-web-ui/src/Popup/Debugger/DebuggerAPI.tsx @@ -79,7 +79,7 @@ const API_LIST = [ // 'pri(signing.requests)', // 'pri(seed.validate)', // 'pri(accounts.validate.seed)', - // 'pri(accounts.validate.metamask.privateKey)', + // 'pri(accounts.validate.privateKey)', // 'pri(derivation.validate)', // 'pri(derivation.create)', // 'pri(derivation.createV2)', diff --git a/packages/extension-web-ui/src/messaging/accounts/validate.ts b/packages/extension-web-ui/src/messaging/accounts/validate.ts index 389f28eeb7..5c075ef438 100644 --- a/packages/extension-web-ui/src/messaging/accounts/validate.ts +++ b/packages/extension-web-ui/src/messaging/accounts/validate.ts @@ -13,5 +13,5 @@ export async function validateSeedV2 (mnemonic: string): Promise { - return sendMessage('pri(accounts.validate.metamask.privateKey)', { privateKey }); + return sendMessage('pri(accounts.validate.privateKey)', { privateKey }); } diff --git a/yarn.lock b/yarn.lock index c91b5e6d4c..b4fe7da225 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6061,12 +6061,12 @@ __metadata: "@subwallet/chain-list@file:../SubWallet-ChainList/packages/chain-list/build/::locator=root-workspace-0b6124%40workspace%3A.": version: 0.2.80-beta.3 - resolution: "@subwallet/chain-list@file:../SubWallet-ChainList/packages/chain-list/build/#../SubWallet-ChainList/packages/chain-list/build/::hash=ca6e93&locator=root-workspace-0b6124%40workspace%3A." + resolution: "@subwallet/chain-list@file:../SubWallet-ChainList/packages/chain-list/build/#../SubWallet-ChainList/packages/chain-list/build/::hash=4da360&locator=root-workspace-0b6124%40workspace%3A." dependencies: "@polkadot/dev": 0.67.167 "@polkadot/util": ^12.5.1 eventemitter3: ^5.0.1 - checksum: 77d9e0ece7f9898baf88ee035941f3a7e29b0453fe4627b2e9c57e90a972b4ccc66a561349af6630e2ac0648835eba4cc5a5b8198657782b79ed25f670076ca1 + checksum: 8d059237e5c1a6aefbc9d5c180f9edbb9187d2b1f5c6ebaaf80a6d51db486c7678d298711efabba2abd0afdcfcbc96e0ebd0af40536ce9e0c4bbe495c9d079bf languageName: node linkType: hard @@ -6451,7 +6451,7 @@ __metadata: "@subwallet/keyring@file:../SubWallet-Base/packages/keyring/build/::locator=root-workspace-0b6124%40workspace%3A.": version: 0.1.5 - resolution: "@subwallet/keyring@file:../SubWallet-Base/packages/keyring/build/#../SubWallet-Base/packages/keyring/build/::hash=ae5273&locator=root-workspace-0b6124%40workspace%3A." + resolution: "@subwallet/keyring@file:../SubWallet-Base/packages/keyring/build/#../SubWallet-Base/packages/keyring/build/::hash=9b4004&locator=root-workspace-0b6124%40workspace%3A." dependencies: "@ethereumjs/tx": ^5.0.0 "@polkadot/util": ^12.2.1 @@ -6470,7 +6470,7 @@ __metadata: rxjs: ^7.5.6 tiny-secp256k1: ^2.2.3 tslib: ^2.6.2 - checksum: 9cdda65bb4ce9868ac3df4401767d76e3a3a8d33f4955d3fa02f83f875be0b3d7e1fdaa888cb33fe4e3aea85d565972cd7af2a79527cbb0b8b61ec39f8972ef4 + checksum: d67582b3b2f32125488f3f4a59635a581d5b18ae53e10c3cf253539ec5e6a3e9a434604faa48f69003ef832b4c4eecc86376960c2e4b7900fc235907382cbee6 languageName: node linkType: hard From 83f42d8a4a3f48433ebc7e7113361f671b656c6b Mon Sep 17 00:00:00 2001 From: Thiendekaco Date: Wed, 21 Aug 2024 14:26:10 +0700 Subject: [PATCH 137/424] [Issue 3457] [fix] Extension - fix ui bug #2 --- .../AccountDetail/AccountAddressList.tsx | 11 ++--- .../Popup/Account/ConnectQrSigner/index.tsx | 6 +-- .../src/Popup/Account/ImportPrivateKey.tsx | 28 ++++++------- .../AccountProxy/AccountProxyTypeTag.tsx | 12 +++++- .../Layout/parts/SelectAccount/index.tsx | 9 ++--- .../components/Modal/Common/AlertModal.tsx | 9 ++++- .../Modal/Global/AddressQrModal.tsx | 1 + .../account/useViewAccountAddressQr.tsx | 40 ++++++++++++------- .../screen/home/useReceiveModalHelper.tsx | 1 + packages/extension-koni-ui/src/types/index.ts | 1 + 10 files changed, 67 insertions(+), 51 deletions(-) diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx index 69ef3ce1e3..792d4e6213 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx @@ -3,9 +3,8 @@ import { AccountProxy, AccountProxyType } from '@subwallet/extension-base/types'; import { AccountNetworkAddressItem, GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; -import { useGetAccountNetworkAddresses, useNotification, useTranslation, useViewAccountAddressQr } from '@subwallet/extension-koni-ui/hooks'; +import { useGetAccountNetworkAddresses, useTranslation, useViewAccountAddressQr } from '@subwallet/extension-koni-ui/hooks'; import { AccountNetworkAddress, ThemeProps } from '@subwallet/extension-koni-ui/types'; -import { copyToClipboard } from '@subwallet/extension-koni-ui/utils'; import { Button, Icon, SwList } from '@subwallet/react-ui'; import { Strategy } from 'phosphor-react'; import React, { useCallback } from 'react'; @@ -20,7 +19,6 @@ const isNotHide = false; function Component ({ accountProxy, className }: Props) { const { t } = useTranslation(); const items: AccountNetworkAddress[] = useGetAccountNetworkAddresses(accountProxy); - const notify = useNotification(); const onViewAccountAddressQr = useViewAccountAddressQr(); const onShowQr = useCallback((item: AccountNetworkAddress) => { @@ -31,12 +29,9 @@ function Component ({ accountProxy, className }: Props) { const onCopyAddress = useCallback((item: AccountNetworkAddress) => { return () => { - copyToClipboard(item.address || ''); - notify({ - message: t('Copied to clipboard') - }); + onViewAccountAddressQr(item, true); }; - }, [notify, t]); + }, [onViewAccountAddressQr]); const renderItem = useCallback( (item: AccountNetworkAddress) => { diff --git a/packages/extension-koni-ui/src/Popup/Account/ConnectQrSigner/index.tsx b/packages/extension-koni-ui/src/Popup/Account/ConnectQrSigner/index.tsx index ecf400c085..c2bf5fa7fb 100644 --- a/packages/extension-koni-ui/src/Popup/Account/ConnectQrSigner/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/ConnectQrSigner/index.tsx @@ -9,7 +9,6 @@ import DualLogo from '@subwallet/extension-koni-ui/components/Logo/DualLogo'; import QrScannerErrorNotice from '@subwallet/extension-koni-ui/components/Qr/Scanner/ErrorNotice'; import { ACCOUNT_NAME_MODAL, ATTACH_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants/modal'; import useCompleteCreateAccount from '@subwallet/extension-koni-ui/hooks/account/useCompleteCreateAccount'; -import useGetDefaultAccountName from '@subwallet/extension-koni-ui/hooks/account/useGetDefaultAccountName'; import useGoBackFromCreateAccount from '@subwallet/extension-koni-ui/hooks/account/useGoBackFromCreateAccount'; import useScanAccountQr from '@subwallet/extension-koni-ui/hooks/qr/useScanAccountQr'; import useAutoNavigateToCreatePassword from '@subwallet/extension-koni-ui/hooks/router/useAutoNavigateToCreatePassword'; @@ -59,7 +58,6 @@ const Component: React.FC = (props: Props) => { const onBack = useGoBackFromCreateAccount(ATTACH_ACCOUNT_MODAL); const accounts = useSelector((root: RootState) => root.accountState.accounts); - const accountName = useGetDefaultAccountName(); const { activeModal, inactiveModal } = useContext(ModalContext); const [validateState, setValidateState] = useState({}); @@ -102,7 +100,7 @@ const Component: React.FC = (props: Props) => { setTimeout(() => { createAccountExternalV2({ - name: accountName, + name, address: scannedAccount.content, genesisHash: '', isAllowed: true, @@ -131,7 +129,7 @@ const Component: React.FC = (props: Props) => { }); }, 300); } - }, [accountName, scannedAccount, inactiveModal, onComplete]); + }, [scannedAccount, onComplete, inactiveModal]); useEffect(() => { if (scannedAccount) { diff --git a/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx b/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx index 28240a52e3..763e83ce89 100644 --- a/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/ImportPrivateKey.tsx @@ -191,6 +191,18 @@ const Component: React.FC = ({ className }: Props) => { onFinish={onSubmit} onValuesChange={onValuesChange} > + + + = ({ className }: Props) => { message: t('Account name is required'), transform: (value: string) => value.trim(), required: true - } - - ]} + }]} > = ({ className }: Props) => { placeholder={t('Enter the account name')} /> - - -
); @@ -352,6 +353,7 @@ const SelectAccount = styled(Component)(({ theme }) => { '.selected-account': { display: 'flex', + width: '100%', flexDirection: 'row', alignItems: 'center', padding: `${token.paddingXS}px ${token.padding}px`, @@ -399,11 +401,6 @@ const SelectAccount = styled(Component)(({ theme }) => { '.anticon.__export-remind-btn': { height: 23, width: 24 - }, - - '.account-name': { - fontSize: token.fontSizeHeading6, - fontWeight: 500 } }); }); diff --git a/packages/extension-koni-ui/src/components/Modal/Common/AlertModal.tsx b/packages/extension-koni-ui/src/components/Modal/Common/AlertModal.tsx index dad1ec1f99..f5418c347f 100644 --- a/packages/extension-koni-ui/src/components/Modal/Common/AlertModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/Common/AlertModal.tsx @@ -41,6 +41,7 @@ const Component: React.FC = (props: Props) => { modalId, okButton, title, + longTitle, type = NotificationType.INFO } = props; const { inactiveModal } = useContext(ModalContext); @@ -52,7 +53,7 @@ const Component: React.FC = (props: Props) => { return ( <> (({ theme: { token } }: Props) => { gap: token.sizeXXS }, + '&.-long-title': { + '.ant-sw-header-center-part': { + width: 'fit-content' + } + }, + '.__modal-content': { fontSize: token.fontSize, lineHeight: token.lineHeightHeading6, diff --git a/packages/extension-koni-ui/src/components/Modal/Global/AddressQrModal.tsx b/packages/extension-koni-ui/src/components/Modal/Global/AddressQrModal.tsx index ed03ced229..22b2b5a10f 100644 --- a/packages/extension-koni-ui/src/components/Modal/Global/AddressQrModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/Global/AddressQrModal.tsx @@ -139,6 +139,7 @@ const Component: React.FC = ({ address, chainSlug, className, onBack, onC const AddressQrModal = styled(Component)(({ theme: { token } }: Props) => { return { + '.__qr-code-wrapper': { paddingTop: token.padding, paddingBottom: token.padding diff --git a/packages/extension-koni-ui/src/hooks/screen/account/useViewAccountAddressQr.tsx b/packages/extension-koni-ui/src/hooks/screen/account/useViewAccountAddressQr.tsx index 10a48a14c7..29b8155976 100644 --- a/packages/extension-koni-ui/src/hooks/screen/account/useViewAccountAddressQr.tsx +++ b/packages/extension-koni-ui/src/hooks/screen/account/useViewAccountAddressQr.tsx @@ -3,34 +3,44 @@ import { NotificationType } from '@subwallet/extension-base/background/KoniTypes'; import { WalletModalContext } from '@subwallet/extension-koni-ui/contexts/WalletModalContextProvider'; -import { useSetSelectedMnemonicType, useTranslation } from '@subwallet/extension-koni-ui/hooks'; +import { useNotification, useSetSelectedMnemonicType, useTranslation } from '@subwallet/extension-koni-ui/hooks'; import { AccountNetworkAddress } from '@subwallet/extension-koni-ui/types'; +import { copyToClipboard } from '@subwallet/extension-koni-ui/utils'; import { CheckCircle, XCircle } from 'phosphor-react'; import React, { useCallback, useContext } from 'react'; import { useNavigate } from 'react-router-dom'; -type HookType = (item: AccountNetworkAddress) => void; +type HookType = (item: AccountNetworkAddress, isCopy?: boolean) => void; export default function useViewAccountAddressQr (): HookType { const { t } = useTranslation(); const navigate = useNavigate(); + const notify = useNotification(); const setSelectedMnemonicType = useSetSelectedMnemonicType(true); const { addressQrModal, alertModal } = useContext(WalletModalContext); - return useCallback((item: AccountNetworkAddress) => { - const openAddressQrModal = () => { - addressQrModal.open({ - address: item.address, - chainSlug: item.slug, - onBack: addressQrModal.close, - onCancel: () => { - addressQrModal.close(); - } - }); + return useCallback((item: AccountNetworkAddress, isCopy = false) => { + const handleAfterAlertWarning = () => { + if (!isCopy) { + addressQrModal.open({ + address: item.address, + chainSlug: item.slug, + onBack: addressQrModal.close, + onCancel: () => { + addressQrModal.close(); + } + }); + } else { + copyToClipboard(item.address || ''); + notify({ + message: t('Copied to clipboard') + }); + } }; if (item.accountType === 'ton') { alertModal.open({ + longTitle: true, closable: false, title: t('Seed phrase incompatibility'), type: NotificationType.WARNING, @@ -51,7 +61,7 @@ export default function useViewAccountAddressQr (): HookType { iconWeight: 'fill', onClick: () => { alertModal.close(); - openAddressQrModal(); + handleAfterAlertWarning(); }, schema: 'secondary' }, @@ -72,6 +82,6 @@ export default function useViewAccountAddressQr (): HookType { return; } - openAddressQrModal(); - }, [addressQrModal, alertModal, navigate, setSelectedMnemonicType, t]); + handleAfterAlertWarning(); + }, [addressQrModal, alertModal, navigate, notify, setSelectedMnemonicType, t]); } diff --git a/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx b/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx index 5296648ada..5be0a7cd65 100644 --- a/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx +++ b/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx @@ -127,6 +127,7 @@ export default function useReceiveModalHelper (tokenGroupSlug?: string): HookTyp if (item.accountType === 'ton') { alertModal.open({ + longTitle: true, closable: false, title: t('Seed phrase incompatibility'), type: NotificationType.WARNING, diff --git a/packages/extension-koni-ui/src/types/index.ts b/packages/extension-koni-ui/src/types/index.ts index ced39b2f3e..3899749b35 100644 --- a/packages/extension-koni-ui/src/types/index.ts +++ b/packages/extension-koni-ui/src/types/index.ts @@ -24,6 +24,7 @@ export type AlertDialogButtonProps = { export type AlertDialogProps = { title: string, type?: NotificationType, + longTitle?: boolean, closable?: boolean, content: React.ReactNode, cancelButton?: AlertDialogButtonProps, From f6fc070891ec65f2f14f2cb4b9a1c6f84624d0cb Mon Sep 17 00:00:00 2001 From: lw Date: Wed, 21 Aug 2024 15:05:55 +0700 Subject: [PATCH 138/424] [Refactor] Rename "network" to "chain" for recent files --- .../AccountDetail/AccountAddressList.tsx | 18 +++++----- .../src/Popup/Transaction/variants/Earn.tsx | 4 +-- .../Popup/Transaction/variants/SendFund.tsx | 6 ++-- .../src/Popup/Transaction/variants/Swap.tsx | 18 +++++----- ...ssItem.tsx => AccountChainAddressItem.tsx} | 12 +++---- .../AccountProxy/AccountProxySelectorItem.tsx | 14 ++++---- .../src/components/AccountProxy/index.ts | 2 +- .../SelectAccount/AccountSelectorModal.tsx | 36 +++++++++---------- ...dal.tsx => AccountChainAddressesModal.tsx} | 26 +++++++------- .../src/components/Modal/Account/index.tsx | 2 +- .../Modal/AddressBook/AddressBookModal.tsx | 4 +-- .../ReceiveModalNew/parts/TokenSelector.tsx | 2 +- .../TokenItem/TokenSelectorItem.tsx | 10 +++--- .../extension-koni-ui/src/constants/modal.ts | 2 +- .../src/hooks/account/index.ts | 2 +- ...es.tsx => useGetAccountChainAddresses.tsx} | 12 +++---- .../screen/home/useReceiveModalHelper.tsx | 20 +++++------ .../extension-koni-ui/src/types/account.ts | 2 +- .../src/utils/account/account.ts | 6 ++-- .../src/utils/chain/chain.ts | 24 ++++++------- .../src/utils/chain/chainAndAsset.ts | 10 +++--- 21 files changed, 116 insertions(+), 116 deletions(-) rename packages/extension-koni-ui/src/components/AccountProxy/{AccountNetworkAddressItem.tsx => AccountChainAddressItem.tsx} (91%) rename packages/extension-koni-ui/src/components/Modal/Account/{AccountNetworkAddressesModal.tsx => AccountChainAddressesModal.tsx} (78%) rename packages/extension-koni-ui/src/hooks/account/{useGetAccountNetworkAddresses.tsx => useGetAccountChainAddresses.tsx} (66%) diff --git a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx index 738a421840..f728d1287a 100644 --- a/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/AccountDetail/AccountAddressList.tsx @@ -2,10 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 import { AccountProxy, AccountProxyType } from '@subwallet/extension-base/types'; -import { AccountNetworkAddressItem, GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; +import { AccountChainAddressItem, GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; import { WalletModalContext } from '@subwallet/extension-koni-ui/contexts/WalletModalContextProvider'; -import { useGetAccountNetworkAddresses, useNotification, useTranslation } from '@subwallet/extension-koni-ui/hooks'; -import { AccountNetworkAddress, ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { useGetAccountChainAddresses, useNotification, useTranslation } from '@subwallet/extension-koni-ui/hooks'; +import { AccountChainAddress, ThemeProps } from '@subwallet/extension-koni-ui/types'; import { copyToClipboard } from '@subwallet/extension-koni-ui/utils'; import { Button, Icon, SwList } from '@subwallet/react-ui'; import { Strategy } from 'phosphor-react'; @@ -18,11 +18,11 @@ type Props = ThemeProps & { function Component ({ accountProxy, className }: Props) { const { t } = useTranslation(); - const items: AccountNetworkAddress[] = useGetAccountNetworkAddresses(accountProxy); + const items: AccountChainAddress[] = useGetAccountChainAddresses(accountProxy); const notify = useNotification(); const { addressQrModal } = useContext(WalletModalContext); - const onShowQr = useCallback((item: AccountNetworkAddress) => { + const onShowQr = useCallback((item: AccountChainAddress) => { return () => { addressQrModal.open({ address: item.address, @@ -31,7 +31,7 @@ function Component ({ accountProxy, className }: Props) { }; }, [addressQrModal]); - const onCopyAddress = useCallback((item: AccountNetworkAddress) => { + const onCopyAddress = useCallback((item: AccountChainAddress) => { return () => { copyToClipboard(item.address || ''); notify({ @@ -41,9 +41,9 @@ function Component ({ accountProxy, className }: Props) { }, [notify, t]); const renderItem = useCallback( - (item: AccountNetworkAddress) => { + (item: AccountChainAddress) => { return ( - { + (item: AccountChainAddress, searchText: string) => { return item.name.toLowerCase().includes(searchText.toLowerCase()); }, [] diff --git a/packages/extension-koni-ui/src/Popup/Transaction/variants/Earn.tsx b/packages/extension-koni-ui/src/Popup/Transaction/variants/Earn.tsx index 0d5ba7ac15..5e7ba77391 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/variants/Earn.tsx +++ b/packages/extension-koni-ui/src/Popup/Transaction/variants/Earn.tsx @@ -19,7 +19,7 @@ import { fetchPoolTarget, getOptimalYieldPath, submitJoinYieldPool, validateYiel import { DEFAULT_YIELD_PROCESS, EarningActionType, earningReducer } from '@subwallet/extension-koni-ui/reducer'; import { store } from '@subwallet/extension-koni-ui/stores'; import { AccountAddressItemType, EarnParams, FormCallbacks, FormFieldData, ThemeProps } from '@subwallet/extension-koni-ui/types'; -import { convertFieldToObject, getReformatedAddressRelatedToNetwork, parseNominations, reformatAddress, simpleCheckForm } from '@subwallet/extension-koni-ui/utils'; +import { convertFieldToObject, getReformatedAddressRelatedToChain, parseNominations, reformatAddress, simpleCheckForm } from '@subwallet/extension-koni-ui/utils'; import { ActivityIndicator, Button, ButtonProps, Form, Icon, ModalContext, Number } from '@subwallet/react-ui'; import BigN from 'bignumber.js'; import CN from 'classnames'; @@ -258,7 +258,7 @@ const Component = () => { } ap.accounts.forEach((a) => { - const address = getReformatedAddressRelatedToNetwork(a, chainInfo); + const address = getReformatedAddressRelatedToChain(a, chainInfo); if (address) { result.push({ diff --git a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx index 942d920f7f..61804e4519 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx +++ b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx @@ -17,7 +17,7 @@ import { approveSpending, getMaxTransfer, getOptimalTransferProcess, makeCrossCh import { CommonActionType, commonProcessReducer, DEFAULT_COMMON_PROCESS } from '@subwallet/extension-koni-ui/reducer'; import { RootState } from '@subwallet/extension-koni-ui/stores'; import { AccountAddressItemType, ChainItemType, FormCallbacks, Theme, ThemeProps, TransferParams } from '@subwallet/extension-koni-ui/types'; -import { findAccountByAddress, formatBalance, getReformatedAddressRelatedToNetwork, isChainInfoAccordantNetworkType, noop, reformatAddress } from '@subwallet/extension-koni-ui/utils'; +import { findAccountByAddress, formatBalance, getReformatedAddressRelatedToChain, isChainInfoAccordantAccountChainType, noop, reformatAddress } from '@subwallet/extension-koni-ui/utils'; import { Button, Form, Icon } from '@subwallet/react-ui'; import { Rule } from '@subwallet/react-ui/es/form'; import BigN from 'bignumber.js'; @@ -42,7 +42,7 @@ function isAssetTypeValid ( ) { const chainInfo = chainInfoMap[chainAsset.originChain]; - return !!chainInfo && accountProxy.chainTypes.some((nt) => isChainInfoAccordantNetworkType(chainInfo, nt)); + return !!chainInfo && accountProxy.chainTypes.some((nt) => isChainInfoAccordantAccountChainType(chainInfo, nt)); } // todo: recheck with ledger account, All account @@ -281,7 +281,7 @@ const _SendFund = ({ className = '' }: Props): React.ReactElement => { } ap.accounts.forEach((a) => { - const address = getReformatedAddressRelatedToNetwork(a, chainInfo); + const address = getReformatedAddressRelatedToChain(a, chainInfo); if (address) { result.push({ diff --git a/packages/extension-koni-ui/src/Popup/Transaction/variants/Swap.tsx b/packages/extension-koni-ui/src/Popup/Transaction/variants/Swap.tsx index ed18eb5f5b..61bcb554da 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/variants/Swap.tsx +++ b/packages/extension-koni-ui/src/Popup/Transaction/variants/Swap.tsx @@ -26,7 +26,7 @@ import { RootState } from '@subwallet/extension-koni-ui/stores'; import { Theme } from '@subwallet/extension-koni-ui/themes'; import { AccountAddressItemType, FormCallbacks, FormFieldData, SwapParams, ThemeProps } from '@subwallet/extension-koni-ui/types'; import { TokenSelectorItemType } from '@subwallet/extension-koni-ui/types/field'; -import { convertFieldToObject, findAccountByAddress, getReformatedAddressRelatedToNetwork, isAccountAll, isChainInfoAccordantNetworkType, isTokenCompatibleWithAccountNetworkTypes, reformatAddress } from '@subwallet/extension-koni-ui/utils'; +import { convertFieldToObject, findAccountByAddress, getReformatedAddressRelatedToChain, isAccountAll, isChainInfoAccordantAccountChainType, isTokenCompatibleWithAccountChainTypes, reformatAddress } from '@subwallet/extension-koni-ui/utils'; import { ActivityIndicator, BackgroundIcon, Button, Form, Icon, Logo, ModalContext, Number, Tooltip } from '@subwallet/react-ui'; import BigN from 'bignumber.js'; import CN from 'classnames'; @@ -178,7 +178,7 @@ const Component = ({ targetAccountProxy }: ComponentProps) => { (() => { // defaultSlug is just TokenSlug if (defaultSlug && rawTokenSlugs.includes(defaultSlug)) { - if (isTokenCompatibleWithAccountNetworkTypes(defaultSlug, targetAccountProxy.networkTypes, chainInfoMap)) { + if (isTokenCompatibleWithAccountChainTypes(defaultSlug, targetAccountProxy.chainTypes, chainInfoMap)) { targetTokenSlugs.push(defaultSlug); } @@ -194,14 +194,14 @@ const Component = ({ targetAccountProxy }: ComponentProps) => { if (defaultSlug) { // defaultSlug is MultiChainAssetSlug - if (_getMultiChainAsset(assetInfo) === defaultSlug && isTokenCompatibleWithAccountNetworkTypes(rts, targetAccountProxy.networkTypes, chainInfoMap)) { + if (_getMultiChainAsset(assetInfo) === defaultSlug && isTokenCompatibleWithAccountChainTypes(rts, targetAccountProxy.chainTypes, chainInfoMap)) { targetTokenSlugs.push(rts); } return; } - if (isTokenCompatibleWithAccountNetworkTypes(rts, targetAccountProxy.networkTypes, chainInfoMap)) { + if (isTokenCompatibleWithAccountChainTypes(rts, targetAccountProxy.chainTypes, chainInfoMap)) { targetTokenSlugs.push(rts); } }); @@ -212,7 +212,7 @@ const Component = ({ targetAccountProxy }: ComponentProps) => { } return []; - }, [assetRegistryMap, chainInfoMap, defaultSlug, fromAndToTokenMap, targetAccountProxy.networkTypes]); + }, [assetRegistryMap, chainInfoMap, defaultSlug, fromAndToTokenMap, targetAccountProxy.chainTypes]); const toTokenItems = useMemo(() => { return getTokenSelectorItem(fromAndToTokenMap[fromTokenSlugValue] || [], assetRegistryMap); @@ -237,8 +237,8 @@ const Component = ({ targetAccountProxy }: ComponentProps) => { return false; } - return isTokenCompatibleWithAccountNetworkTypes(toTokenSlugValue, targetAccountProxy.networkTypes, chainInfoMap); - }, [chainInfoMap, fromAndToTokenMap, targetAccountProxy.networkTypes, toTokenSlugValue]); + return isTokenCompatibleWithAccountChainTypes(toTokenSlugValue, targetAccountProxy.chainTypes, chainInfoMap); + }, [chainInfoMap, fromAndToTokenMap, targetAccountProxy.chainTypes, toTokenSlugValue]); const onSwitchSide = useCallback(() => { if (fromTokenSlugValue && toTokenSlugValue) { @@ -308,7 +308,7 @@ const Component = ({ targetAccountProxy }: ComponentProps) => { return false; } - return !isChainInfoAccordantNetworkType(chainInfoMap[destChainValue], fromAccountJson.networkType); + return !isChainInfoAccordantAccountChainType(chainInfoMap[destChainValue], fromAccountJson.chainType); }, [accounts, chainInfoMap, destChainValue, fromValue]); const onSelectFromToken = useCallback((tokenSlug: string) => { @@ -870,7 +870,7 @@ const Component = ({ targetAccountProxy }: ComponentProps) => { } ap.accounts.forEach((a) => { - const address = getReformatedAddressRelatedToNetwork(a, chainInfo); + const address = getReformatedAddressRelatedToChain(a, chainInfo); if (address) { result.push({ diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountNetworkAddressItem.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountChainAddressItem.tsx similarity index 91% rename from packages/extension-koni-ui/src/components/AccountProxy/AccountNetworkAddressItem.tsx rename to packages/extension-koni-ui/src/components/AccountProxy/AccountChainAddressItem.tsx index 761989fa85..178a62787c 100644 --- a/packages/extension-koni-ui/src/components/AccountProxy/AccountNetworkAddressItem.tsx +++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountChainAddressItem.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountNetworkAddress, ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { AccountChainAddress, ThemeProps } from '@subwallet/extension-koni-ui/types'; import { toShort } from '@subwallet/extension-koni-ui/utils'; import { Button, Icon, Logo } from '@subwallet/react-ui'; import CN from 'classnames'; @@ -10,7 +10,7 @@ import React from 'react'; import styled from 'styled-components'; type Props = ThemeProps & { - item: AccountNetworkAddress; + item: AccountChainAddress; onClickCopyButton?: VoidFunction; onClickQrButton?: VoidFunction; } @@ -44,7 +44,7 @@ function Component (props: Props): React.ReactElement {
-
+
{item.name}
@@ -81,7 +81,7 @@ function Component (props: Props): React.ReactElement { ); } -const AccountProxySelectorItem = styled(Component)(({ theme: { token } }: Props) => { +const AccountChainAddressItem = styled(Component)(({ theme: { token } }: Props) => { return { background: token.colorBgSecondary, paddingLeft: token.paddingSM, @@ -107,7 +107,7 @@ const AccountProxySelectorItem = styled(Component)(({ theme: { token } }: alignItems: 'center' }, - '.__item-network-name': { + '.__item-chain-name': { fontSize: token.fontSize, lineHeight: token.lineHeight, color: token.colorTextLight1, @@ -147,4 +147,4 @@ const AccountProxySelectorItem = styled(Component)(({ theme: { token } }: }; }); -export default AccountProxySelectorItem; +export default AccountChainAddressItem; diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx index 2d4bf11e6b..5269929a7c 100644 --- a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx +++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx @@ -43,7 +43,7 @@ function Component (props: Props): React.ReactElement { const { t } = useTranslation(); - const networkTypeLogoMap = useMemo(() => { + const chainTypeLogoMap = useMemo(() => { return { [AccountChainType.SUBSTRATE]: logoMap.network.polkadot as string, [AccountChainType.ETHEREUM]: logoMap.network.ethereum as string, @@ -155,15 +155,15 @@ function Component (props: Props): React.ReactElement {
{accountProxy.name}
-
+
{ accountProxy.chainTypes.map((nt) => { return ( Network type ); }) @@ -300,11 +300,11 @@ const AccountProxySelectorItem = styled(Component)(({ theme }) => { overflow: 'hidden', 'white-space': 'nowrap' }, - '.__item-network-types': { + '.__item-chain-types': { display: 'flex', paddingTop: 2 }, - '.__item-network-type-item': { + '.__item-chain-type-item': { display: 'block', boxShadow: '-4px 0px 4px 0px rgba(0, 0, 0, 0.40)', width: token.size, @@ -312,7 +312,7 @@ const AccountProxySelectorItem = styled(Component)(({ theme }) => { borderRadius: '100%', marginLeft: -token.marginXXS }, - '.__item-network-type-item:first-of-type': { + '.__item-chain-type-item:first-of-type': { marginLeft: 0 }, '.__item-address': { diff --git a/packages/extension-koni-ui/src/components/AccountProxy/index.ts b/packages/extension-koni-ui/src/components/AccountProxy/index.ts index 86f46dc2ed..0bb062ac69 100644 --- a/packages/extension-koni-ui/src/components/AccountProxy/index.ts +++ b/packages/extension-koni-ui/src/components/AccountProxy/index.ts @@ -7,6 +7,6 @@ export { default as AccountProxySelectorAllItem } from './AccountProxySelectorAl export { default as AccountProxyItem } from './AccountProxyItem'; export { default as AccountProxyAvatar } from './AccountProxyAvatar'; export { default as AccountProxyAvatarGroup } from './AccountProxyAvatarGroup'; -export { default as AccountNetworkAddressItem } from './AccountNetworkAddressItem'; +export { default as AccountChainAddressItem } from './AccountChainAddressItem'; export { default as AccountAddressItem } from './AccountAddressItem'; export { default as AccountProxyTypeTag } from './AccountProxyTypeTag'; diff --git a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx index 2a7c5d70bc..21eb29cb35 100644 --- a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx +++ b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/AccountSelectorModal.tsx @@ -5,10 +5,10 @@ import type { ButtonProps } from '@subwallet/react-ui/es/button/button'; import { CurrentAccountInfo } from '@subwallet/extension-base/background/types'; import { AccountProxy, AccountProxyType } from '@subwallet/extension-base/types'; -import { AccountNetworkAddressesModal, AccountProxySelectorAllItem, AccountProxySelectorItem, GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; +import { AccountChainAddressesModal, AccountProxySelectorAllItem, AccountProxySelectorItem, GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; import SelectAccountFooter from '@subwallet/extension-koni-ui/components/Layout/parts/SelectAccount/Footer'; import Search from '@subwallet/extension-koni-ui/components/Search'; -import { ACCOUNT_NETWORK_ADDRESSES_MODAL, SELECT_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants/modal'; +import { ACCOUNT_CHAIN_ADDRESSES_MODAL, SELECT_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants/modal'; import { useDefaultNavigate, useSetSessionLatest } from '@subwallet/extension-koni-ui/hooks'; import useTranslation from '@subwallet/extension-koni-ui/hooks/common/useTranslation'; import { saveCurrentAccountAddress } from '@subwallet/extension-koni-ui/messaging'; @@ -74,7 +74,7 @@ function reorderAccounts (items: AccountProxy[]): AccountProxy[] { const renderEmpty = () => ; const modalId = SELECT_ACCOUNT_MODAL; -const accountNetworkAddressesModalId = ACCOUNT_NETWORK_ADDRESSES_MODAL; +const accountChainAddressesModalId = ACCOUNT_CHAIN_ADDRESSES_MODAL; const Component: React.FC = ({ className }: Props) => { const location = useLocation(); @@ -236,11 +236,11 @@ const Component: React.FC = ({ className }: Props) => { }; }, [accountProxies, inactiveModal, location.pathname, navigate, goHome]); - const onViewNetworkAddresses = useCallback((accountProxy: AccountProxy) => { + const onViewChainAddresses = useCallback((accountProxy: AccountProxy) => { return () => { setIdOfAccountProxyToGetAddresses(accountProxy.id); setTimeout(() => { - activeModal(accountNetworkAddressesModalId); + activeModal(accountChainAddressesModalId); }, 100); }; }, [activeModal]); @@ -294,12 +294,12 @@ const Component: React.FC = ({ className }: Props) => { isSelected={item.id === currentAccountProxy?.id} key={item.id} onClick={onSelect(item as AccountProxy)} - onClickCopyButton={onViewNetworkAddresses(item as AccountProxy)} + onClickCopyButton={onViewChainAddresses(item as AccountProxy)} onClickDeriveButton={onViewAccountDetail(item as AccountProxy, true)} onClickMoreButton={onViewAccountDetail(item as AccountProxy)} /> ); - }, [currentAccountProxy?.id, onSelect, onViewAccountDetail, onViewNetworkAddresses, showAllAccount]); + }, [currentAccountProxy?.id, onSelect, onViewAccountDetail, onViewChainAddresses, showAllAccount]); const handleSearch = useCallback((value: string) => { setSearchValue(value); @@ -348,19 +348,19 @@ const Component: React.FC = ({ className }: Props) => { }); }, [t, token.colorHighlight]); - const closeAccountNetworkAddressesModal = useCallback(() => { - inactiveModal(accountNetworkAddressesModalId); + const closeAccountChainAddressesModal = useCallback(() => { + inactiveModal(accountChainAddressesModalId); setIdOfAccountProxyToGetAddresses(undefined); }, [inactiveModal]); - const onBackAccountNetworkAddressesModal = useCallback(() => { - closeAccountNetworkAddressesModal(); - }, [closeAccountNetworkAddressesModal]); + const onBackAccountChainAddressesModal = useCallback(() => { + closeAccountChainAddressesModal(); + }, [closeAccountChainAddressesModal]); - const onCancelAccountNetworkAddressesModal = useCallback(() => { + const onCancelAccountChainAddressesModal = useCallback(() => { inactiveModal(modalId); - closeAccountNetworkAddressesModal(); - }, [closeAccountNetworkAddressesModal, inactiveModal]); + closeAccountChainAddressesModal(); + }, [closeAccountChainAddressesModal, inactiveModal]); return ( <> @@ -388,10 +388,10 @@ const Component: React.FC = ({ className }: Props) => { { accountProxyToGetAddresses && ( - ) } diff --git a/packages/extension-koni-ui/src/components/Modal/Account/AccountNetworkAddressesModal.tsx b/packages/extension-koni-ui/src/components/Modal/Account/AccountChainAddressesModal.tsx similarity index 78% rename from packages/extension-koni-ui/src/components/Modal/Account/AccountNetworkAddressesModal.tsx rename to packages/extension-koni-ui/src/components/Modal/Account/AccountChainAddressesModal.tsx index a0b8c6f942..df72a616be 100644 --- a/packages/extension-koni-ui/src/components/Modal/Account/AccountNetworkAddressesModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/Account/AccountChainAddressesModal.tsx @@ -2,12 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 import { AccountProxy } from '@subwallet/extension-base/types'; -import { AccountNetworkAddressItem, CloseIcon, GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; -import { ACCOUNT_NETWORK_ADDRESSES_MODAL } from '@subwallet/extension-koni-ui/constants/modal'; +import { AccountChainAddressItem, CloseIcon, GeneralEmptyList } from '@subwallet/extension-koni-ui/components'; +import { ACCOUNT_CHAIN_ADDRESSES_MODAL } from '@subwallet/extension-koni-ui/constants/modal'; import { WalletModalContext } from '@subwallet/extension-koni-ui/contexts/WalletModalContextProvider'; -import { useGetAccountNetworkAddresses, useNotification } from '@subwallet/extension-koni-ui/hooks'; +import { useGetAccountChainAddresses, useNotification } from '@subwallet/extension-koni-ui/hooks'; import useTranslation from '@subwallet/extension-koni-ui/hooks/common/useTranslation'; -import { AccountNetworkAddress, ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { AccountChainAddress, ThemeProps } from '@subwallet/extension-koni-ui/types'; import { copyToClipboard } from '@subwallet/extension-koni-ui/utils'; import { Icon, SwList, SwModal } from '@subwallet/react-ui'; import CN from 'classnames'; @@ -21,15 +21,15 @@ type Props = ThemeProps & { onBack?: VoidFunction; }; -const modalId = ACCOUNT_NETWORK_ADDRESSES_MODAL; +const modalId = ACCOUNT_CHAIN_ADDRESSES_MODAL; const Component: React.FC = ({ accountProxy, className, onBack, onCancel }: Props) => { const { t } = useTranslation(); - const items: AccountNetworkAddress[] = useGetAccountNetworkAddresses(accountProxy); + const items: AccountChainAddress[] = useGetAccountChainAddresses(accountProxy); const notify = useNotification(); const { addressQrModal } = useContext(WalletModalContext); - const onShowQr = useCallback((item: AccountNetworkAddress) => { + const onShowQr = useCallback((item: AccountChainAddress) => { return () => { addressQrModal.open({ address: item.address, @@ -43,7 +43,7 @@ const Component: React.FC = ({ accountProxy, className, onBack, onCancel }; }, [addressQrModal, onCancel]); - const onCopyAddress = useCallback((item: AccountNetworkAddress) => { + const onCopyAddress = useCallback((item: AccountChainAddress) => { return () => { copyToClipboard(item.address || ''); notify({ @@ -53,9 +53,9 @@ const Component: React.FC = ({ accountProxy, className, onBack, onCancel }, [notify, t]); const renderItem = useCallback( - (item: AccountNetworkAddress) => { + (item: AccountChainAddress) => { return ( - = ({ accountProxy, className, onBack, onCancel }, []); const searchFunction = useCallback( - (item: AccountNetworkAddress, searchText: string) => { + (item: AccountChainAddress, searchText: string) => { return item.name.toLowerCase().includes(searchText.toLowerCase()); }, [] @@ -115,7 +115,7 @@ const Component: React.FC = ({ accountProxy, className, onBack, onCancel ); }; -const AccountNetworkAddressesModal = styled(Component)(({ theme: { token } }: Props) => { +const AccountChainAddressesModal = styled(Component)(({ theme: { token } }: Props) => { return { '.ant-sw-modal-content': { height: '200vh', @@ -152,4 +152,4 @@ const AccountNetworkAddressesModal = styled(Component)(({ theme: { token }; }); -export default AccountNetworkAddressesModal; +export default AccountChainAddressesModal; diff --git a/packages/extension-koni-ui/src/components/Modal/Account/index.tsx b/packages/extension-koni-ui/src/components/Modal/Account/index.tsx index 7562b69fa1..be63639d0e 100644 --- a/packages/extension-koni-ui/src/components/Modal/Account/index.tsx +++ b/packages/extension-koni-ui/src/components/Modal/Account/index.tsx @@ -9,5 +9,5 @@ export { default as DeriveAccountModal } from './DeriveAccountModal'; export { default as ImportAccountModal } from './ImportAccountModal'; export { default as ImportSeedModal } from './ImportSeedModal'; export { default as NewSeedModal } from './NewSeedModal'; -export { default as AccountNetworkAddressesModal } from './AccountNetworkAddressesModal'; +export { default as AccountChainAddressesModal } from './AccountChainAddressesModal'; export { default as AccountNameModal } from './AccountNameModal'; diff --git a/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx b/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx index 9ce4f9bab6..5af9f67c26 100644 --- a/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx @@ -4,7 +4,7 @@ import { BackIcon } from '@subwallet/extension-koni-ui/components'; import { useChainInfo, useFilterModal, useSelector } from '@subwallet/extension-koni-ui/hooks'; import { ThemeProps } from '@subwallet/extension-koni-ui/types'; -import { getReformatedAddressRelatedToNetwork, isAccountAll, reformatAddress } from '@subwallet/extension-koni-ui/utils'; +import { getReformatedAddressRelatedToChain, isAccountAll, reformatAddress } from '@subwallet/extension-koni-ui/utils'; import { Badge, Icon, ModalContext, SwList, SwModal } from '@subwallet/react-ui'; import { SwListSectionRef } from '@subwallet/react-ui/es/sw-list'; import CN from 'classnames'; @@ -118,7 +118,7 @@ const Component: React.FC = (props: Props) => { // todo: recheck with ledger ap.accounts.forEach((a) => { - const address = getReformatedAddressRelatedToNetwork(a, chainInfo); + const address = getReformatedAddressRelatedToChain(a, chainInfo); if (address) { result.push({ name: ap.name, address: address, group: AccountGroup.WALLET }); diff --git a/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/TokenSelector.tsx b/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/TokenSelector.tsx index 54229ed306..e5f9fe0118 100644 --- a/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/TokenSelector.tsx +++ b/packages/extension-koni-ui/src/components/Modal/ReceiveModalNew/parts/TokenSelector.tsx @@ -48,10 +48,10 @@ function Component ({ className = '', items, onCancel, onSelectItem }: Props): R const renderItem = useCallback((item: _ChainAsset) => { return ( { +const Component = ({ chainName, chainSlug, className, onClick, tokenSlug, tokenSymbol }: Props) => { return (
{tokenSymbol}
-
- {networkName} +
+ {chainName}
@@ -67,7 +67,7 @@ const TokenSelectorItem = styled(Component)(({ theme: { token } }: Props) textOverflow: 'ellipsis' }, - '.__network-name': { + '.__chain-name': { fontSize: token.fontSizeSM, lineHeight: token.lineHeightSM, color: token.colorTextLight3, diff --git a/packages/extension-koni-ui/src/constants/modal.ts b/packages/extension-koni-ui/src/constants/modal.ts index 6ea85808b9..ab3ade9e3a 100644 --- a/packages/extension-koni-ui/src/constants/modal.ts +++ b/packages/extension-koni-ui/src/constants/modal.ts @@ -33,7 +33,7 @@ export const REMIND_UPGRADE_FIREFOX_VERSION = 'remind-update-firefox-version'; export const EXPORT_ACCOUNTS_PASSWORD_MODAL = 'export-accounts-password-modal'; export const ADD_NETWORK_WALLET_CONNECT_MODAL = 'add-network-wallet-connect-modal'; export const ADDRESS_QR_MODAL = 'address-qr-modal'; -export const ACCOUNT_NETWORK_ADDRESSES_MODAL = 'account-network-addresses-modal'; +export const ACCOUNT_CHAIN_ADDRESSES_MODAL = 'account-chain-addresses-modal'; export const ACCOUNT_NAME_MODAL = 'account-name-modal'; export const GLOBAL_ALERT_MODAL = 'global-alert-modal'; diff --git a/packages/extension-koni-ui/src/hooks/account/index.ts b/packages/extension-koni-ui/src/hooks/account/index.ts index ee5fe86c93..0c72fe6427 100644 --- a/packages/extension-koni-ui/src/hooks/account/index.ts +++ b/packages/extension-koni-ui/src/hooks/account/index.ts @@ -18,7 +18,7 @@ export { default as useIsReadOnlyAccount } from './useIsReadOnlyAccount'; export { default as usePreCheckAction } from './usePreCheckAction'; export { default as useSetSelectedAccountTypes } from './useSetSelectedAccountTypes'; export { default as useGetAccountProxyById } from './useGetAccountProxyById'; -export { default as useGetAccountNetworkAddresses } from './useGetAccountNetworkAddresses'; +export { default as useGetAccountChainAddresses } from './useGetAccountChainAddresses'; export { default as useSetSelectedMnemonicType } from './useSetSelectedMnemonicType'; export * from './useGetMantaPayConfig'; diff --git a/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx b/packages/extension-koni-ui/src/hooks/account/useGetAccountChainAddresses.tsx similarity index 66% rename from packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx rename to packages/extension-koni-ui/src/hooks/account/useGetAccountChainAddresses.tsx index aa42e6d8a6..cc4aee9f70 100644 --- a/packages/extension-koni-ui/src/hooks/account/useGetAccountNetworkAddresses.tsx +++ b/packages/extension-koni-ui/src/hooks/account/useGetAccountChainAddresses.tsx @@ -3,23 +3,23 @@ import { AccountProxy } from '@subwallet/extension-base/types'; import { useSelector } from '@subwallet/extension-koni-ui/hooks'; -import { AccountNetworkAddress } from '@subwallet/extension-koni-ui/types'; -import { getChainsByAccountType, getReformatedAddressRelatedToNetwork } from '@subwallet/extension-koni-ui/utils'; +import { AccountChainAddress } from '@subwallet/extension-koni-ui/types'; +import { getChainsByAccountType, getReformatedAddressRelatedToChain } from '@subwallet/extension-koni-ui/utils'; import { useMemo } from 'react'; // todo: // - order the result -const useGetAccountNetworkAddresses = (accountProxy: AccountProxy): AccountNetworkAddress[] => { +const useGetAccountChainAddresses = (accountProxy: AccountProxy): AccountChainAddress[] => { const chainInfoMap = useSelector((state) => state.chainStore.chainInfoMap); return useMemo(() => { - const result: AccountNetworkAddress[] = []; + const result: AccountChainAddress[] = []; const chains: string[] = getChainsByAccountType(chainInfoMap, accountProxy.chainTypes, accountProxy.specialChain); accountProxy.accounts.forEach((a) => { for (const chain of chains) { const chainInfo = chainInfoMap[chain]; - const reformatedAddress = getReformatedAddressRelatedToNetwork(a, chainInfo); + const reformatedAddress = getReformatedAddressRelatedToChain(a, chainInfo); if (reformatedAddress) { result.push({ @@ -35,4 +35,4 @@ const useGetAccountNetworkAddresses = (accountProxy: AccountProxy): AccountNetwo }, [accountProxy, chainInfoMap]); }; -export default useGetAccountNetworkAddresses; +export default useGetAccountChainAddresses; diff --git a/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx b/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx index 55aaee92b7..7dafb97ee6 100644 --- a/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx +++ b/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx @@ -10,7 +10,7 @@ import { useGetChainSlugsByAccount, useSetSelectedMnemonicType, useTranslation } import { useChainAssets } from '@subwallet/extension-koni-ui/hooks/assets'; import { RootState } from '@subwallet/extension-koni-ui/stores'; import { AccountAddressItemType, ReceiveModalProps } from '@subwallet/extension-koni-ui/types'; -import { getReformatedAddressRelatedToNetwork } from '@subwallet/extension-koni-ui/utils'; +import { getReformatedAddressRelatedToChain } from '@subwallet/extension-koni-ui/utils'; import { ModalContext } from '@subwallet/react-ui'; import { CheckCircle, XCircle } from 'phosphor-react'; import React, { useCallback, useContext, useMemo, useState } from 'react'; @@ -34,7 +34,7 @@ export default function useReceiveModalHelper (tokenGroupSlug?: string): HookTyp const { accountProxies } = useSelector((state: RootState) => state.accountState); const chainInfoMap = useSelector((state: RootState) => state.chainStore.chainInfoMap); - const [selectedNetwork, setSelectedNetwork] = useState(); + const [selectedChain, setSelectedChain] = useState(); const { addressQrModal, alertModal } = useContext(WalletModalContext); const chainSupported = useGetChainSlugsByAccount(); @@ -59,7 +59,7 @@ export default function useReceiveModalHelper (tokenGroupSlug?: string): HookTyp }, [inactiveModal]); const onSelectTokenSelector = useCallback((item: _ChainAsset) => { - setSelectedNetwork(item.originChain); + setSelectedChain(item.originChain); setTimeout(() => { activeModal(accountSelectorModalId); }, 100); @@ -71,7 +71,7 @@ export default function useReceiveModalHelper (tokenGroupSlug?: string): HookTyp // todo: recheck logic with ledger account const accountSelectorItems = useMemo(() => { - const chainInfo = selectedNetwork ? chainInfoMap[selectedNetwork] : undefined; + const chainInfo = selectedChain ? chainInfoMap[selectedChain] : undefined; if (!chainInfo) { return []; @@ -81,7 +81,7 @@ export default function useReceiveModalHelper (tokenGroupSlug?: string): HookTyp accountProxies.forEach((ap) => { ap.accounts.forEach((a) => { - const reformatedAddress = getReformatedAddressRelatedToNetwork(a, chainInfo); + const reformatedAddress = getReformatedAddressRelatedToChain(a, chainInfo); if (reformatedAddress) { result.push({ @@ -96,7 +96,7 @@ export default function useReceiveModalHelper (tokenGroupSlug?: string): HookTyp }); return result; - }, [accountProxies, chainInfoMap, selectedNetwork]); + }, [accountProxies, chainInfoMap, selectedChain]); const onBackAccountSelector = useCallback(() => { inactiveModal(accountSelectorModalId); @@ -105,18 +105,18 @@ export default function useReceiveModalHelper (tokenGroupSlug?: string): HookTyp const onCloseAccountSelector = useCallback(() => { inactiveModal(accountSelectorModalId); inactiveModal(tokenSelectorModalId); - setSelectedNetwork(undefined); + setSelectedChain(undefined); }, [inactiveModal]); const onSelectAccountSelector = useCallback((item: AccountAddressItemType) => { - if (!selectedNetwork) { + if (!selectedChain) { return; } const openAddressQrModal = () => { addressQrModal.open({ address: item.address, - chainSlug: selectedNetwork, + chainSlug: selectedChain, onBack: addressQrModal.close, onCancel: () => { addressQrModal.close(); @@ -169,7 +169,7 @@ export default function useReceiveModalHelper (tokenGroupSlug?: string): HookTyp } openAddressQrModal(); - }, [addressQrModal, alertModal, navigate, onCloseAccountSelector, selectedNetwork, setSelectedMnemonicType, t]); + }, [addressQrModal, alertModal, navigate, onCloseAccountSelector, selectedChain, setSelectedMnemonicType, t]); /* account Selector --- */ diff --git a/packages/extension-koni-ui/src/types/account.ts b/packages/extension-koni-ui/src/types/account.ts index 474bda6f39..96fdb2844a 100644 --- a/packages/extension-koni-ui/src/types/account.ts +++ b/packages/extension-koni-ui/src/types/account.ts @@ -28,7 +28,7 @@ export enum AccountSignMode { UNKNOWN = 'unknown' } -export type AccountNetworkAddress = { +export type AccountChainAddress = { name: string; slug: string; address: string; diff --git a/packages/extension-koni-ui/src/utils/account/account.ts b/packages/extension-koni-ui/src/utils/account/account.ts index 91d8c25088..6ebeb7b2f4 100644 --- a/packages/extension-koni-ui/src/utils/account/account.ts +++ b/packages/extension-koni-ui/src/utils/account/account.ts @@ -17,7 +17,7 @@ import { AccountInfoByNetwork } from '@subwallet/extension-koni-ui/utils/types'; import { decodeAddress, encodeAddress, isAddress, isEthereumAddress } from '@polkadot/util-crypto'; import { KeypairType } from '@polkadot/util-crypto/types'; -import { isChainInfoAccordantNetworkType } from '../chain'; +import { isChainInfoAccordantAccountChainType } from '../chain'; import { getLogoByNetworkKey } from '../common'; export function getAccountType (address: string): AccountType { @@ -180,12 +180,12 @@ export const convertKeyTypes = (authTypes: AccountAuthType[]): KeypairType[] => // todo: // - support bitcoin -export function getReformatedAddressRelatedToNetwork (accountJson: AccountJson, chainInfo: _ChainInfo): string | undefined { +export function getReformatedAddressRelatedToChain (accountJson: AccountJson, chainInfo: _ChainInfo): string | undefined { if (accountJson.specialChain && accountJson.specialChain !== chainInfo.slug) { return undefined; } - if (!isChainInfoAccordantNetworkType(chainInfo, accountJson.chainType)) { + if (!isChainInfoAccordantAccountChainType(chainInfo, accountJson.chainType)) { return undefined; } diff --git a/packages/extension-koni-ui/src/utils/chain/chain.ts b/packages/extension-koni-ui/src/utils/chain/chain.ts index c035750c83..c033cee3ca 100644 --- a/packages/extension-koni-ui/src/utils/chain/chain.ts +++ b/packages/extension-koni-ui/src/utils/chain/chain.ts @@ -3,7 +3,7 @@ import { _ChainInfo, _ChainStatus } from '@subwallet/chain-list/types'; import { _getSubstrateGenesisHash, _isChainBitcoinCompatible, _isChainEvmCompatible, _isChainTonCompatible, _isPureSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils'; -import { AccountNetworkType } from '@subwallet/extension-base/types'; +import { AccountChainType } from '@subwallet/extension-base/types'; export const findChainInfoByGenesisHash = (chainMap: Record, genesisHash?: string): _ChainInfo | null => { if (!genesisHash) { @@ -33,40 +33,40 @@ export const findChainInfoByChainId = (chainMap: Record, cha return null; }; -export const isChainInfoAccordantNetworkType = (chainInfo: _ChainInfo, networkType: AccountNetworkType): boolean => { - if (networkType === AccountNetworkType.SUBSTRATE) { +export const isChainInfoAccordantAccountChainType = (chainInfo: _ChainInfo, chainType: AccountChainType): boolean => { + if (chainType === AccountChainType.SUBSTRATE) { return _isPureSubstrateChain(chainInfo); } - if (networkType === AccountNetworkType.ETHEREUM) { + if (chainType === AccountChainType.ETHEREUM) { return _isChainEvmCompatible(chainInfo); } - if (networkType === AccountNetworkType.TON) { + if (chainType === AccountChainType.TON) { return _isChainTonCompatible(chainInfo); } - if (networkType === AccountNetworkType.BITCOIN) { + if (chainType === AccountChainType.BITCOIN) { return _isChainBitcoinCompatible(chainInfo); } return false; }; -export const isChainCompatibleWithAccountNetworkTypes = (chainInfo: _ChainInfo, networkTypes: AccountNetworkType[]): boolean => { - return networkTypes.some((networkType) => isChainInfoAccordantNetworkType(chainInfo, networkType)); +export const isChainCompatibleWithAccountChainTypes = (chainInfo: _ChainInfo, chainTypes: AccountChainType[]): boolean => { + return chainTypes.some((chainType) => isChainInfoAccordantAccountChainType(chainInfo, chainType)); }; -export const getChainsByAccountType = (_chainInfoMap: Record, networkTypes: AccountNetworkType[], specialNetwork?: string): string[] => { +export const getChainsByAccountType = (_chainInfoMap: Record, chainTypes: AccountChainType[], specialChain?: string): string[] => { const chainInfoMap = Object.fromEntries(Object.entries(_chainInfoMap).filter(([, chainInfo]) => chainInfo.chainStatus === _ChainStatus.ACTIVE)); - if (specialNetwork) { - return Object.keys(chainInfoMap).filter((chain) => specialNetwork === chain); + if (specialChain) { + return Object.keys(chainInfoMap).filter((chain) => specialChain === chain); } else { const result: string[] = []; for (const chainInfo of Object.values(chainInfoMap)) { - if (isChainCompatibleWithAccountNetworkTypes(chainInfo, networkTypes)) { + if (isChainCompatibleWithAccountChainTypes(chainInfo, chainTypes)) { result.push(chainInfo.slug); } } diff --git a/packages/extension-koni-ui/src/utils/chain/chainAndAsset.ts b/packages/extension-koni-ui/src/utils/chain/chainAndAsset.ts index e003115a2b..e5909e510f 100644 --- a/packages/extension-koni-ui/src/utils/chain/chainAndAsset.ts +++ b/packages/extension-koni-ui/src/utils/chain/chainAndAsset.ts @@ -5,8 +5,8 @@ import { _ChainAsset, _ChainInfo } from '@subwallet/chain-list/types'; import { AssetSetting } from '@subwallet/extension-base/background/KoniTypes'; import { _ChainState } from '@subwallet/extension-base/services/chain-service/types'; import { _getOriginChainOfAsset, _isAssetFungibleToken } from '@subwallet/extension-base/services/chain-service/utils'; -import { AccountNetworkType } from '@subwallet/extension-base/types'; -import { isChainCompatibleWithAccountNetworkTypes } from '@subwallet/extension-koni-ui/utils'; +import { AccountChainType } from '@subwallet/extension-base/types'; +import { isChainCompatibleWithAccountChainTypes } from '@subwallet/extension-koni-ui/utils'; export function isTokenAvailable ( chainAsset: _ChainAsset, @@ -35,11 +35,11 @@ export function getChainInfoFromToken (tokenSlug: string, chainInfoMap: Record): boolean { const chainInfo = getChainInfoFromToken(tokenSlug, chainInfoMap); - return !!chainInfo && isChainCompatibleWithAccountNetworkTypes(chainInfo, networkTypes); + return !!chainInfo && isChainCompatibleWithAccountChainTypes(chainInfo, chainTypes); } From e674baa6e3ce3b4682682dd9e27278cf070f01f4 Mon Sep 17 00:00:00 2001 From: Thiendekaco Date: Wed, 21 Aug 2024 16:45:37 +0700 Subject: [PATCH 139/424] [Issue 3457] [fix] Extension - fix ui bug #3 --- .../components/Layout/parts/SelectAccount/index.tsx | 5 +++++ .../src/components/Modal/Common/AlertModal.tsx | 10 ++++------ .../hooks/screen/account/useViewAccountAddressQr.tsx | 1 - .../src/hooks/screen/home/useReceiveModalHelper.tsx | 1 - packages/extension-koni-ui/src/types/index.ts | 1 - 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/index.tsx b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/index.tsx index 29b2814308..1754c84326 100644 --- a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/index.tsx +++ b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/index.tsx @@ -398,6 +398,11 @@ const SelectAccount = styled(Component)(({ theme }) => { left: '40%' }, + '.account-name': { + fontSize: token.fontSizeHeading6, + fontWeight: 500 + }, + '.anticon.__export-remind-btn': { height: 23, width: 24 diff --git a/packages/extension-koni-ui/src/components/Modal/Common/AlertModal.tsx b/packages/extension-koni-ui/src/components/Modal/Common/AlertModal.tsx index f5418c347f..883a947d85 100644 --- a/packages/extension-koni-ui/src/components/Modal/Common/AlertModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/Common/AlertModal.tsx @@ -41,7 +41,6 @@ const Component: React.FC = (props: Props) => { modalId, okButton, title, - longTitle, type = NotificationType.INFO } = props; const { inactiveModal } = useContext(ModalContext); @@ -53,7 +52,7 @@ const Component: React.FC = (props: Props) => { return ( <> (({ theme: { token } }: Props) => { gap: token.sizeXXS }, - '&.-long-title': { - '.ant-sw-header-center-part': { - width: 'fit-content' - } + '.ant-sw-header-center-part': { + width: '100%', + maxWidth: 292 }, '.__modal-content': { diff --git a/packages/extension-koni-ui/src/hooks/screen/account/useViewAccountAddressQr.tsx b/packages/extension-koni-ui/src/hooks/screen/account/useViewAccountAddressQr.tsx index 9af83487e3..7adfa6a713 100644 --- a/packages/extension-koni-ui/src/hooks/screen/account/useViewAccountAddressQr.tsx +++ b/packages/extension-koni-ui/src/hooks/screen/account/useViewAccountAddressQr.tsx @@ -40,7 +40,6 @@ export default function useViewAccountAddressQr (): HookType { if (item.accountType === 'ton') { alertModal.open({ - longTitle: true, closable: false, title: t('Seed phrase incompatibility'), type: NotificationType.WARNING, diff --git a/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx b/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx index 67a19c461d..c6e58bcaf3 100644 --- a/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx +++ b/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx @@ -127,7 +127,6 @@ export default function useReceiveModalHelper (tokenGroupSlug?: string): HookTyp if (item.accountType === 'ton') { alertModal.open({ - longTitle: true, closable: false, title: t('Seed phrase incompatibility'), type: NotificationType.WARNING, diff --git a/packages/extension-koni-ui/src/types/index.ts b/packages/extension-koni-ui/src/types/index.ts index 3899749b35..ced39b2f3e 100644 --- a/packages/extension-koni-ui/src/types/index.ts +++ b/packages/extension-koni-ui/src/types/index.ts @@ -24,7 +24,6 @@ export type AlertDialogButtonProps = { export type AlertDialogProps = { title: string, type?: NotificationType, - longTitle?: boolean, closable?: boolean, content: React.ReactNode, cancelButton?: AlertDialogButtonProps, From 466e59c4f0d96ff7121aea100ec4b1cbbf34b59b Mon Sep 17 00:00:00 2001 From: lw Date: Thu, 22 Aug 2024 11:38:15 +0700 Subject: [PATCH 140/424] [Issue-3462] Update flow logic for receive modal --- .../src/Popup/Home/Tokens/DetailList.tsx | 4 +- .../src/Popup/Home/Tokens/index.tsx | 4 +- .../src/hooks/screen/home/index.ts | 2 +- ...lper.tsx => useCoreReceiveModalHelper.tsx} | 241 ++++++++++++------ .../extension-koni-ui/src/types/component.ts | 3 +- .../src/utils/account/account.ts | 1 + 6 files changed, 174 insertions(+), 81 deletions(-) rename packages/extension-koni-ui/src/hooks/screen/home/{useReceiveModalHelper.tsx => useCoreReceiveModalHelper.tsx} (57%) diff --git a/packages/extension-koni-ui/src/Popup/Home/Tokens/DetailList.tsx b/packages/extension-koni-ui/src/Popup/Home/Tokens/DetailList.tsx index 1010ec4bcc..b87a691b48 100644 --- a/packages/extension-koni-ui/src/Popup/Home/Tokens/DetailList.tsx +++ b/packages/extension-koni-ui/src/Popup/Home/Tokens/DetailList.tsx @@ -10,7 +10,7 @@ import { TokenBalanceDetailItem } from '@subwallet/extension-koni-ui/components/ import { DEFAULT_SWAP_PARAMS, DEFAULT_TRANSFER_PARAMS, SWAP_TRANSACTION, TRANSFER_TRANSACTION } from '@subwallet/extension-koni-ui/constants'; import { DataContext } from '@subwallet/extension-koni-ui/contexts/DataContext'; import { HomeContext } from '@subwallet/extension-koni-ui/contexts/screen/HomeContext'; -import { useDefaultNavigate, useGetBannerByScreen, useNavigateOnChangeAccount, useNotification, useReceiveModalHelper, useSelector } from '@subwallet/extension-koni-ui/hooks'; +import { useCoreReceiveModalHelper, useDefaultNavigate, useGetBannerByScreen, useNavigateOnChangeAccount, useNotification, useSelector } from '@subwallet/extension-koni-ui/hooks'; import { DetailModal } from '@subwallet/extension-koni-ui/Popup/Home/Tokens/DetailModal'; import { DetailUpperBlock } from '@subwallet/extension-koni-ui/Popup/Home/Tokens/DetailUpperBlock'; import { RootState } from '@subwallet/extension-koni-ui/stores'; @@ -120,7 +120,7 @@ function Component (): React.ReactElement { const containerRef = useRef(null); const topBlockRef = useRef(null); - const { onOpenReceive, receiveModalProps } = useReceiveModalHelper(tokenGroupSlug); + const { onOpenReceive, receiveModalProps } = useCoreReceiveModalHelper(tokenGroupSlug); useNavigateOnChangeAccount('/home/tokens'); diff --git a/packages/extension-koni-ui/src/Popup/Home/Tokens/index.tsx b/packages/extension-koni-ui/src/Popup/Home/Tokens/index.tsx index 95a240f79e..09140c3c30 100644 --- a/packages/extension-koni-ui/src/Popup/Home/Tokens/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Home/Tokens/index.tsx @@ -7,7 +7,7 @@ import { TokenGroupBalanceItem } from '@subwallet/extension-koni-ui/components/T import { DEFAULT_SWAP_PARAMS, DEFAULT_TRANSFER_PARAMS, SWAP_TRANSACTION, TRANSFER_TRANSACTION } from '@subwallet/extension-koni-ui/constants'; import { DataContext } from '@subwallet/extension-koni-ui/contexts/DataContext'; import { HomeContext } from '@subwallet/extension-koni-ui/contexts/screen/HomeContext'; -import { useReceiveModalHelper, useSetCurrentPage } from '@subwallet/extension-koni-ui/hooks'; +import { useCoreReceiveModalHelper, useSetCurrentPage } from '@subwallet/extension-koni-ui/hooks'; import useNotification from '@subwallet/extension-koni-ui/hooks/common/useNotification'; import useTranslation from '@subwallet/extension-koni-ui/hooks/common/useTranslation'; import { UpperBlock } from '@subwallet/extension-koni-ui/Popup/Home/Tokens/UpperBlock'; @@ -38,7 +38,7 @@ const Component = (): React.ReactElement => { const { accountBalance: { tokenGroupBalanceMap, totalBalanceInfo }, tokenGroupStructure: { sortedTokenGroups } } = useContext(HomeContext); const notify = useNotification(); - const { onOpenReceive, receiveModalProps } = useReceiveModalHelper(); + const { onOpenReceive, receiveModalProps } = useCoreReceiveModalHelper(); const isZkModeSyncing = useSelector((state: RootState) => state.mantaPay.isSyncing); const zkModeSyncProgress = useSelector((state: RootState) => state.mantaPay.progress); diff --git a/packages/extension-koni-ui/src/hooks/screen/home/index.ts b/packages/extension-koni-ui/src/hooks/screen/home/index.ts index 12c2380774..b038de2d89 100644 --- a/packages/extension-koni-ui/src/hooks/screen/home/index.ts +++ b/packages/extension-koni-ui/src/hooks/screen/home/index.ts @@ -3,7 +3,7 @@ export { default as useAccountBalance } from './useAccountBalance'; export { default as useGetTokensBySettings } from './useGetTokensBySettings'; -export { default as useReceiveModalHelper } from './useReceiveModalHelper'; +export { default as useCoreReceiveModalHelper } from './useCoreReceiveModalHelper'; export { default as useTokenGroup } from './useTokenGroup'; export * from './useGetChainSlugsByAccount'; diff --git a/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx b/packages/extension-koni-ui/src/hooks/screen/home/useCoreReceiveModalHelper.tsx similarity index 57% rename from packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx rename to packages/extension-koni-ui/src/hooks/screen/home/useCoreReceiveModalHelper.tsx index 7dafb97ee6..649b07bfda 100644 --- a/packages/extension-koni-ui/src/hooks/screen/home/useReceiveModalHelper.tsx +++ b/packages/extension-koni-ui/src/hooks/screen/home/useCoreReceiveModalHelper.tsx @@ -1,9 +1,11 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 +import type { KeypairType } from '@subwallet/keyring/types'; + import { _ChainAsset } from '@subwallet/chain-list/types'; import { NotificationType } from '@subwallet/extension-base/background/KoniTypes'; -import { _getMultiChainAsset } from '@subwallet/extension-base/services/chain-service/utils'; +import { _getAssetOriginChain, _getMultiChainAsset } from '@subwallet/extension-base/services/chain-service/utils'; import { RECEIVE_MODAL_ACCOUNT_SELECTOR, RECEIVE_MODAL_TOKEN_SELECTOR } from '@subwallet/extension-koni-ui/constants'; import { WalletModalContext } from '@subwallet/extension-koni-ui/contexts/WalletModalContextProvider'; import { useGetChainSlugsByAccount, useSetSelectedMnemonicType, useTranslation } from '@subwallet/extension-koni-ui/hooks'; @@ -25,22 +27,132 @@ type HookType = { const tokenSelectorModalId = RECEIVE_MODAL_TOKEN_SELECTOR; const accountSelectorModalId = RECEIVE_MODAL_ACCOUNT_SELECTOR; -export default function useReceiveModalHelper (tokenGroupSlug?: string): HookType { +export default function useCoreReceiveModalHelper (tokenGroupSlug?: string): HookType { const { activeModal, inactiveModal } = useContext(ModalContext); const { chainAssets } = useChainAssets(); const { t } = useTranslation(); const navigate = useNavigate(); const setSelectedMnemonicType = useSetSelectedMnemonicType(true); - const { accountProxies } = useSelector((state: RootState) => state.accountState); + const accountProxies = useSelector((state: RootState) => state.accountState.accountProxies); + const isAllAccount = useSelector((state: RootState) => state.accountState.isAllAccount); + const currentAccountProxy = useSelector((state: RootState) => state.accountState.currentAccountProxy); + const assetRegistryMap = useSelector((state: RootState) => state.assetRegistry.assetRegistry); const chainInfoMap = useSelector((state: RootState) => state.chainStore.chainInfoMap); const [selectedChain, setSelectedChain] = useState(); const { addressQrModal, alertModal } = useContext(WalletModalContext); const chainSupported = useGetChainSlugsByAccount(); + // chain related to tokenGroupSlug, if it is token slug + const specificChain = useMemo(() => { + if (tokenGroupSlug && assetRegistryMap[tokenGroupSlug]) { + return _getAssetOriginChain(assetRegistryMap[tokenGroupSlug]); + } + + return undefined; + }, [assetRegistryMap, tokenGroupSlug]); + + const openAddressQrModal = useCallback((address: string, accountType: KeypairType, chainSlug: string, closeCallback?: VoidCallback, showQrBack = true) => { + const _openAddressQrModal = () => { + addressQrModal.open({ + address, + chainSlug, + onBack: showQrBack ? addressQrModal.close : undefined, + onCancel: () => { + addressQrModal.close(); + closeCallback?.(); + } + }); + }; + + if (accountType === 'ton') { + alertModal.open({ + closable: false, + title: t('Seed phrase incompatibility'), + type: NotificationType.WARNING, + content: ( + <> +
+ {t('Importing this seed phrase will generate a unified account that can be used on multiple ecosystems including Polkadot, Ethereum, Bitcoin, and TON.')} +
+
+
+ {t('However, SubWallet is not compatible with TON-native wallets. This means that with the same seed phrase, SubWallet and TON-native wallets will generate two different TON addresses.')} +
+ + ), + cancelButton: { + text: t('Cancel'), + icon: XCircle, + iconWeight: 'fill', + onClick: () => { + alertModal.close(); + closeCallback?.(); + }, + schema: 'secondary' + }, + okButton: { + text: t('Apply'), + icon: CheckCircle, + iconWeight: 'fill', + onClick: () => { + setSelectedMnemonicType('ton'); + navigate('/accounts/new-seed-phrase'); + + alertModal.close(); + }, + schema: 'primary' + } + }); + + return; + } + + _openAddressQrModal(); + }, [addressQrModal, alertModal, navigate, setSelectedMnemonicType, t]); + const onOpenReceive = useCallback(() => { + if (!currentAccountProxy) { + return; + } + + if (specificChain) { + if (!chainSupported.includes(specificChain)) { + console.warn('tokenGroupSlug does not work with current account'); + + return; + } + + // current account is All + if (isAllAccount) { + activeModal(accountSelectorModalId); + + return; + } + + // current account is not All, just do show QR logic + + const specificChainInfo = chainInfoMap[specificChain]; + + if (!specificChainInfo) { + return; + } + + for (const accountJson of currentAccountProxy.accounts) { + const reformatedAddress = getReformatedAddressRelatedToChain(accountJson, specificChainInfo); + + if (reformatedAddress) { + openAddressQrModal(reformatedAddress, accountJson.type, specificChain, undefined, false); + + break; + } + } + + return; + } + activeModal(tokenSelectorModalId); - }, [activeModal]); + }, [activeModal, chainInfoMap, chainSupported, currentAccountProxy, isAllAccount, openAddressQrModal, specificChain]); /* --- token Selector */ @@ -59,19 +171,49 @@ export default function useReceiveModalHelper (tokenGroupSlug?: string): HookTyp }, [inactiveModal]); const onSelectTokenSelector = useCallback((item: _ChainAsset) => { + // do not need the logic to check if item is compatible with currentAccountProxy here, it's already in tokenSelectorItems code block + + if (!currentAccountProxy) { + return; + } + setSelectedChain(item.originChain); - setTimeout(() => { - activeModal(accountSelectorModalId); - }, 100); - }, [activeModal]); + + if (isAllAccount) { + setTimeout(() => { + activeModal(accountSelectorModalId); + }, 100); + + return; + } + + // current account is not All, just do show QR logic + + const chainSlug = _getAssetOriginChain(item); + const chainInfo = chainInfoMap[chainSlug]; + + if (!chainInfo) { + return; + } + + for (const accountJson of currentAccountProxy.accounts) { + const reformatedAddress = getReformatedAddressRelatedToChain(accountJson, chainInfo); + + if (reformatedAddress) { + openAddressQrModal(reformatedAddress, accountJson.type, chainSlug); + + break; + } + } + }, [activeModal, chainInfoMap, currentAccountProxy, isAllAccount, openAddressQrModal]); /* token Selector --- */ /* --- account Selector */ - // todo: recheck logic with ledger account const accountSelectorItems = useMemo(() => { - const chainInfo = selectedChain ? chainInfoMap[selectedChain] : undefined; + const targetChain = specificChain || selectedChain; + const chainInfo = targetChain ? chainInfoMap[targetChain] : undefined; if (!chainInfo) { return []; @@ -96,11 +238,18 @@ export default function useReceiveModalHelper (tokenGroupSlug?: string): HookTyp }); return result; - }, [accountProxies, chainInfoMap, selectedChain]); + }, [accountProxies, chainInfoMap, selectedChain, specificChain]); - const onBackAccountSelector = useCallback(() => { - inactiveModal(accountSelectorModalId); - }, [inactiveModal]); + const onBackAccountSelector = useMemo(() => { + // if specificChain has value, it means tokenSelector does not show up, so accountSelector does not have back action + if (specificChain) { + return undefined; + } + + return () => { + inactiveModal(accountSelectorModalId); + }; + }, [inactiveModal, specificChain]); const onCloseAccountSelector = useCallback(() => { inactiveModal(accountSelectorModalId); @@ -109,76 +258,20 @@ export default function useReceiveModalHelper (tokenGroupSlug?: string): HookTyp }, [inactiveModal]); const onSelectAccountSelector = useCallback((item: AccountAddressItemType) => { - if (!selectedChain) { - return; - } - - const openAddressQrModal = () => { - addressQrModal.open({ - address: item.address, - chainSlug: selectedChain, - onBack: addressQrModal.close, - onCancel: () => { - addressQrModal.close(); - onCloseAccountSelector(); - } - }); - }; - - if (item.accountType === 'ton') { - alertModal.open({ - closable: false, - title: t('Seed phrase incompatibility'), - type: NotificationType.WARNING, - content: ( - <> -
- {t('Importing this seed phrase will generate a unified account that can be used on multiple ecosystems including Polkadot, Ethereum, Bitcoin, and TON.')} -
-
-
- {t('However, SubWallet is not compatible with TON-native wallets. This means that with the same seed phrase, SubWallet and TON-native wallets will generate two different TON addresses.')} -
- - ), - cancelButton: { - text: t('Cancel'), - icon: XCircle, - iconWeight: 'fill', - onClick: () => { - alertModal.close(); - openAddressQrModal(); - }, - schema: 'secondary' - }, - okButton: { - text: t('Apply'), - icon: CheckCircle, - iconWeight: 'fill', - onClick: () => { - setSelectedMnemonicType('ton'); - navigate('/accounts/new-seed-phrase'); - - alertModal.close(); - }, - schema: 'primary' - } - }); + const targetChain = specificChain || selectedChain; + if (!targetChain) { return; } - openAddressQrModal(); - }, [addressQrModal, alertModal, navigate, onCloseAccountSelector, selectedChain, setSelectedMnemonicType, t]); + openAddressQrModal(item.address, item.accountType, targetChain, onCloseAccountSelector); + }, [onCloseAccountSelector, openAddressQrModal, selectedChain, specificChain]); /* account Selector --- */ return useMemo(() => ({ onOpenReceive, receiveModalProps: { - onSelectToken: () => { - // - }, tokenSelectorItems, onCloseTokenSelector, onSelectTokenSelector, diff --git a/packages/extension-koni-ui/src/types/component.ts b/packages/extension-koni-ui/src/types/component.ts index 42d6161894..7d39fcab97 100644 --- a/packages/extension-koni-ui/src/types/component.ts +++ b/packages/extension-koni-ui/src/types/component.ts @@ -5,12 +5,11 @@ import { _ChainAsset } from '@subwallet/chain-list/types'; import { AccountAddressItemType } from '@subwallet/extension-koni-ui/types/account'; export type ReceiveModalProps = { - onSelectToken: VoidFunction; tokenSelectorItems: _ChainAsset[]; onCloseTokenSelector: VoidFunction; onSelectTokenSelector: (item: _ChainAsset) => void; accountSelectorItems: AccountAddressItemType[]; onCloseAccountSelector: VoidFunction; - onBackAccountSelector: VoidFunction; + onBackAccountSelector?: VoidFunction; onSelectAccountSelector: (item: AccountAddressItemType) => void; } diff --git a/packages/extension-koni-ui/src/utils/account/account.ts b/packages/extension-koni-ui/src/utils/account/account.ts index 6ebeb7b2f4..3215bc3fb4 100644 --- a/packages/extension-koni-ui/src/utils/account/account.ts +++ b/packages/extension-koni-ui/src/utils/account/account.ts @@ -39,6 +39,7 @@ export const getAccountInfoByNetwork = (networkMap: Record, }; }; +// todo: recheck this function with current account export const findAccountByAddress = (accounts: AccountJson[], address?: string): AccountJson | null => { try { const isAllAccount = address && isAccountAll(address); From 287d03a747193c9ab69d1ce1e0d34fb0e37ba224 Mon Sep 17 00:00:00 2001 From: lw Date: Thu, 22 Aug 2024 12:33:56 +0700 Subject: [PATCH 141/424] [Issue-3462] Update logic to get token lists for send fund screen --- .../Popup/Transaction/variants/SendFund.tsx | 187 ++++++++---------- 1 file changed, 84 insertions(+), 103 deletions(-) diff --git a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx index 61804e4519..8e1a0898df 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx +++ b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx @@ -1,23 +1,23 @@ // Copyright 2019-2022 @polkadot/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { _AssetRef, _AssetType, _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet/chain-list/types'; +import { _AssetRef, _AssetType, _ChainAsset, _ChainInfo } from '@subwallet/chain-list/types'; import { ExtrinsicType, NotificationType } from '@subwallet/extension-base/background/KoniTypes'; import { _getXcmUnstableWarning, _isXcmTransferUnstable } from '@subwallet/extension-base/core/substrate/xcm-parser'; import { getSnowBridgeGatewayContract } from '@subwallet/extension-base/koni/api/contract-handler/utils'; -import { _getAssetDecimals, _getContractAddressOfToken, _getOriginChainOfAsset, _getTokenMinAmount, _isAssetFungibleToken, _isChainEvmCompatible, _isMantaZkAsset, _isNativeToken, _isTokenTransferredByEvm } from '@subwallet/extension-base/services/chain-service/utils'; +import { _getAssetDecimals, _getAssetName, _getAssetOriginChain, _getAssetSymbol, _getContractAddressOfToken, _getMultiChainAsset, _getOriginChainOfAsset, _getTokenMinAmount, _isChainEvmCompatible, _isNativeToken, _isTokenTransferredByEvm } from '@subwallet/extension-base/services/chain-service/utils'; import { SWTransactionResponse } from '@subwallet/extension-base/services/transaction-service/types'; import { AccountProxy, AccountProxyType } from '@subwallet/extension-base/types'; import { CommonStepType } from '@subwallet/extension-base/types/service-base'; import { detectTranslate, isAccountAll, isSameAddress } from '@subwallet/extension-base/utils'; import { AccountAddressSelector, AddressInputNew, AlertBox, AlertModal, AmountInput, ChainSelector, HiddenInput, TokenItemType, TokenSelector } from '@subwallet/extension-koni-ui/components'; -import { useAlert, useFetchChainAssetInfo, useInitValidateTransaction, useIsMantaPayEnabled, useNotification, usePreCheckAction, useRestoreTransaction, useSelector, useSetCurrentPage, useTransactionContext, useWatchTransaction } from '@subwallet/extension-koni-ui/hooks'; +import { useAlert, useDefaultNavigate, useFetchChainAssetInfo, useInitValidateTransaction, useNotification, usePreCheckAction, useRestoreTransaction, useSelector, useSetCurrentPage, useTransactionContext, useWatchTransaction } from '@subwallet/extension-koni-ui/hooks'; import useHandleSubmitMultiTransaction from '@subwallet/extension-koni-ui/hooks/transaction/useHandleSubmitMultiTransaction'; import { approveSpending, getMaxTransfer, getOptimalTransferProcess, makeCrossChainTransfer, makeTransfer } from '@subwallet/extension-koni-ui/messaging'; import { CommonActionType, commonProcessReducer, DEFAULT_COMMON_PROCESS } from '@subwallet/extension-koni-ui/reducer'; import { RootState } from '@subwallet/extension-koni-ui/stores'; import { AccountAddressItemType, ChainItemType, FormCallbacks, Theme, ThemeProps, TransferParams } from '@subwallet/extension-koni-ui/types'; -import { findAccountByAddress, formatBalance, getReformatedAddressRelatedToChain, isChainInfoAccordantAccountChainType, noop, reformatAddress } from '@subwallet/extension-koni-ui/utils'; +import { findAccountByAddress, formatBalance, getChainsByAccountType, getReformatedAddressRelatedToChain, noop, reformatAddress } from '@subwallet/extension-koni-ui/utils'; import { Button, Form, Icon } from '@subwallet/react-ui'; import { Rule } from '@subwallet/react-ui/es/form'; import BigN from 'bignumber.js'; @@ -33,98 +33,40 @@ import { isAddress, isEthereumAddress } from '@polkadot/util-crypto'; import { FreeBalance, TransactionContent, TransactionFooter } from '../parts'; -type Props = ThemeProps; +type WrapperProps = ThemeProps; -function isAssetTypeValid ( - chainAsset: _ChainAsset, - chainInfoMap: Record, - accountProxy: AccountProxy -) { - const chainInfo = chainInfoMap[chainAsset.originChain]; - - return !!chainInfo && accountProxy.chainTypes.some((nt) => isChainInfoAccordantAccountChainType(chainInfo, nt)); -} +type ComponentProps = { + className?: string; + targetAccountProxy: AccountProxy; +}; -// todo: recheck with ledger account, All account function getTokenItems ( - accountProxyId: string, - accountProxies: AccountProxy[], + accountProxy: AccountProxy, chainInfoMap: Record, assetRegistry: Record, - multiChainAssetMap: Record, - tokenGroupSlug?: string, // is ether a token slug or a multiChainAsset slug - isZkModeEnabled?: boolean + tokenGroupSlug?: string // is ether a token slug or a multiChainAsset slug ): TokenItemType[] { - const accountProxy = accountProxies.find((ap) => { - if (!accountProxyId) { - return isAccountAll(ap.id); - } - - return ap.id === accountProxyId; - }); - - if (!accountProxy) { - return []; - } - - const isSetTokenSlug = !!tokenGroupSlug && !!assetRegistry[tokenGroupSlug]; - const isSetMultiChainAssetSlug = !!tokenGroupSlug && !!multiChainAssetMap[tokenGroupSlug]; - - if (tokenGroupSlug) { - if (!(isSetTokenSlug || isSetMultiChainAssetSlug)) { - return []; - } - } - - if (isSetTokenSlug) { - const chainAsset = assetRegistry[tokenGroupSlug]; - - if (isAssetTypeValid(chainAsset, chainInfoMap, accountProxy)) { - const { name, originChain, slug, symbol } = assetRegistry[tokenGroupSlug]; - - return [ - { - name, - slug, - symbol, - originChain - } - ]; - } else { - return []; - } - } + const allowedChains = getChainsByAccountType(chainInfoMap, accountProxy.chainTypes, accountProxy.specialChain); const items: TokenItemType[] = []; Object.values(assetRegistry).forEach((chainAsset) => { - const isTokenFungible = _isAssetFungibleToken(chainAsset); + const originChain = _getAssetOriginChain(chainAsset); - if (!(isTokenFungible && isAssetTypeValid(chainAsset, chainInfoMap, accountProxy))) { + if (!allowedChains.includes(originChain)) { return; } - if (!isZkModeEnabled && _isMantaZkAsset(chainAsset)) { + if (!(chainAsset.slug === tokenGroupSlug || _getMultiChainAsset(chainAsset) === tokenGroupSlug)) { return; } - if (isSetMultiChainAssetSlug) { - if (chainAsset.multiChainAsset === tokenGroupSlug) { - items.push({ - name: chainAsset.name, - slug: chainAsset.slug, - symbol: chainAsset.symbol, - originChain: chainAsset.originChain - }); - } - } else { - items.push({ - name: chainAsset.name, - slug: chainAsset.slug, - symbol: chainAsset.symbol, - originChain: chainAsset.originChain - }); - } + items.push({ + slug: chainAsset.slug, + name: _getAssetName(chainAsset), + symbol: _getAssetSymbol(chainAsset), + originChain + }); }); return items; @@ -158,17 +100,17 @@ function getTokenAvailableDestinations (tokenSlug: string, xcmRefMap: Record = ['chain', 'fromAccountProxy']; +const hiddenFields: Array = ['chain', 'fromAccountProxy', 'defaultSlug']; const validateFields: Array = ['value', 'to']; const alertModalId = 'confirmation-alert-modal'; -const _SendFund = ({ className = '' }: Props): React.ReactElement => { +const Component = ({ className = '', targetAccountProxy }: ComponentProps): React.ReactElement => { useSetCurrentPage('/transaction/send-fund'); const { t } = useTranslation(); const notification = useNotification(); const { defaultData, persistData } = useTransactionContext(); - const { defaultSlug: sendFundSlug, fromAccountProxy } = defaultData; + const { defaultSlug: sendFundSlug } = defaultData; const isFirstRender = useIsFirstRender(); const [form] = Form.useForm(); @@ -188,13 +130,12 @@ const _SendFund = ({ className = '' }: Props): React.ReactElement => { const { alertProps, closeAlert, openAlert } = useAlert(alertModalId); const { chainInfoMap, chainStatusMap } = useSelector((root) => root.chainStore); - const { assetRegistry, multiChainAssetMap, xcmRefMap } = useSelector((root) => root.assetRegistry); + const { assetRegistry, xcmRefMap } = useSelector((root) => root.assetRegistry); const { accounts } = useSelector((state: RootState) => state.accountState); const accountProxies = useSelector((state: RootState) => state.accountState.accountProxies); const [maxTransfer, setMaxTransfer] = useState('0'); const checkAction = usePreCheckAction(fromValue, true, detectTranslate('The account you are using is {{accountTitle}}, you cannot send assets with it')); - const isZKModeEnabled = useIsMantaPayEnabled(fromValue); const hideMaxButton = useMemo(() => { const chainInfo = chainInfoMap[chainValue]; @@ -251,15 +192,12 @@ const _SendFund = ({ className = '' }: Props): React.ReactElement => { const tokenItems = useMemo(() => { return getTokenItems( - fromAccountProxy, - accountProxies, + targetAccountProxy, chainInfoMap, assetRegistry, - multiChainAssetMap, - sendFundSlug, - isZKModeEnabled + sendFundSlug ); - }, [accountProxies, assetRegistry, chainInfoMap, fromAccountProxy, isZKModeEnabled, multiChainAssetMap, sendFundSlug]); + }, [assetRegistry, chainInfoMap, sendFundSlug, targetAccountProxy]); const accountAddressItems = useMemo(() => { const chainInfo = chainValue ? chainInfoMap[chainValue] : undefined; @@ -270,16 +208,7 @@ const _SendFund = ({ className = '' }: Props): React.ReactElement => { const result: AccountAddressItemType[] = []; - accountProxies.forEach((ap) => { - if (!(!fromAccountProxy || ap.id === fromAccountProxy)) { - return; - } - - // todo: support ledger later - if ([AccountProxyType.READ_ONLY, AccountProxyType.LEDGER].includes(ap.accountType)) { - return; - } - + const updateResult = (ap: AccountProxy) => { ap.accounts.forEach((a) => { const address = getReformatedAddressRelatedToChain(a, chainInfo); @@ -293,10 +222,26 @@ const _SendFund = ({ className = '' }: Props): React.ReactElement => { }); } }); - }); + }; + + if (isAccountAll(targetAccountProxy.id)) { + accountProxies.forEach((ap) => { + if (isAccountAll(ap.id)) { + return; + } + + if ([AccountProxyType.READ_ONLY].includes(ap.accountType)) { + return; + } + + updateResult(ap); + }); + } else { + updateResult(targetAccountProxy); + } return result; - }, [accountProxies, chainInfoMap, chainValue, fromAccountProxy]); + }, [accountProxies, chainInfoMap, chainValue, targetAccountProxy]); const validateRecipientAddress = useCallback((rule: Rule, _recipientAddress: string): Promise => { if (!_recipientAddress) { @@ -915,7 +860,43 @@ const _SendFund = ({ className = '' }: Props): React.ReactElement => { ); }; -const SendFund = styled(_SendFund)(({ theme }) => { +const Wrapper: React.FC = (props: WrapperProps) => { + const { className } = props; + const { defaultData } = useTransactionContext(); + const { goHome } = useDefaultNavigate(); + const accountProxies = useSelector((state) => state.accountState.accountProxies); + + const targetAccountProxy = useMemo(() => { + return accountProxies.find((ap) => { + if (!defaultData.fromAccountProxy) { + return isAccountAll(ap.id); + } + + return ap.id === defaultData.fromAccountProxy; + }); + }, [accountProxies, defaultData.fromAccountProxy]); + + useEffect(() => { + if (!targetAccountProxy) { + goHome(); + } + }, [goHome, targetAccountProxy]); + + if (!targetAccountProxy) { + return ( + <> + ); + } + + return ( + + ); +}; + +const SendFund = styled(Wrapper)(({ theme }) => { const token = (theme as Theme).token; return ({ From 8f613ab0c49460547d4ead80e43d62b3ec9accb2 Mon Sep 17 00:00:00 2001 From: S2kael Date: Thu, 22 Aug 2024 18:36:33 +0700 Subject: [PATCH 142/424] [BuyService] Convert support type --- packages/extension-base/src/services/buy-service/index.ts | 8 ++++++-- packages/extension-base/src/services/buy-service/types.ts | 4 ++-- packages/extension-base/src/types/buy.ts | 6 +++++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/extension-base/src/services/buy-service/index.ts b/packages/extension-base/src/services/buy-service/index.ts index d8e056d8f0..208c4a4d64 100644 --- a/packages/extension-base/src/services/buy-service/index.ts +++ b/packages/extension-base/src/services/buy-service/index.ts @@ -3,12 +3,16 @@ import KoniState from '@subwallet/extension-base/koni/background/handlers/State'; import { ListBuyServicesResponse, ListBuyTokenResponse } from '@subwallet/extension-base/services/buy-service/types'; -import { BuyServiceInfo, BuyTokenInfo, SupportService } from '@subwallet/extension-base/types'; +import { AccountChainType, BuyServiceInfo, BuyTokenInfo, OnrampAccountSupportType, SupportService } from '@subwallet/extension-base/types'; import { fetchStaticData } from '@subwallet/extension-base/utils/fetchStaticData'; import { BehaviorSubject } from 'rxjs'; import { DEFAULT_SERVICE_INFO } from './constants'; +const convertSupportType = (support: OnrampAccountSupportType): AccountChainType => { + return support === 'ETHEREUM' ? AccountChainType.ETHEREUM : AccountChainType.SUBSTRATE; +}; + export default class BuyService { readonly #state: KoniState; @@ -44,7 +48,7 @@ export default class BuyService { serviceInfo: { ...DEFAULT_SERVICE_INFO }, - support: datum.support, + support: convertSupportType(datum.support), services: [], slug: datum.slug, symbol: datum.symbol, diff --git a/packages/extension-base/src/services/buy-service/types.ts b/packages/extension-base/src/services/buy-service/types.ts index 3f16995c83..1509fef5db 100644 --- a/packages/extension-base/src/services/buy-service/types.ts +++ b/packages/extension-base/src/services/buy-service/types.ts @@ -1,14 +1,14 @@ // Copyright 2019-2022 @subwallet/extension-koni authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { BuyService, BuyTokenInfo, SupportService } from '@subwallet/extension-base/types'; +import { BuyService, OnrampAccountSupportType, SupportService } from '@subwallet/extension-base/types'; interface _BuyTokenInfo { serviceInfo: Record; network: string; slug: string; symbol: string; - support: BuyTokenInfo['support']; + support: OnrampAccountSupportType; } interface _BuyServiceInfo { diff --git a/packages/extension-base/src/types/buy.ts b/packages/extension-base/src/types/buy.ts index 6f4532128b..61f99d0cd8 100644 --- a/packages/extension-base/src/types/buy.ts +++ b/packages/extension-base/src/types/buy.ts @@ -1,6 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 +import { AccountChainType } from './account'; + export interface BuyService { network: string; symbol: string; @@ -8,11 +10,13 @@ export interface BuyService { export type SupportService = 'transak' | 'banxa' | 'coinbase' | 'moonpay' | 'onramper'; +export type OnrampAccountSupportType = 'ETHEREUM' | 'SUBSTRATE'; + export interface BuyTokenInfo { network: string; symbol: string; slug: string; - support: 'ETHEREUM' | 'SUBSTRATE'; + support: AccountChainType; services: Array; serviceInfo: Record; } From 0e210c1f5b2a4abe3748db509e1dfc35f1c2487b Mon Sep 17 00:00:00 2001 From: S2kael Date: Thu, 22 Aug 2024 18:48:06 +0700 Subject: [PATCH 143/424] [Issue-3485] Update import json interface --- .../src/background/KoniTypes.ts | 44 +---- .../extension-base/src/background/types.ts | 9 - .../src/koni/background/handlers/Extension.ts | 41 ++-- .../context/account-context.ts | 18 +- .../context/handlers/Derive.ts | 2 +- .../keyring-service/context/handlers/Json.ts | 175 +++++++++++++----- .../context/handlers/Mnemonic.ts | 2 +- .../context/handlers/Modify.ts | 2 +- .../services/keyring-service/context/state.ts | 18 +- .../src/types/account/action/add/index.ts | 1 + .../src/types/account/action/add/json.ts | 41 ++++ .../src/types/account/action/add/mnemonic.ts | 2 - .../src/types/account/action/export.ts | 11 ++ .../src/types/account/info/proxy.ts | 6 + .../src/utils/account/transform.ts | 66 ++++--- .../src/Popup/Account/RestoreJson.tsx | 116 +++++------- .../src/Popup/Debugger/DebuggerAPI.tsx | 2 +- .../Account/AccountExportPasswordModal.tsx | 2 +- .../src/messaging/accounts/export.ts | 3 +- .../src/messaging/accounts/json.ts | 17 +- .../src/Popup/Account/RestoreJson.tsx | 2 +- .../src/Popup/Debugger/DebuggerAPI.tsx | 2 +- .../Account/AccountExportPasswordModal.tsx | 2 +- .../src/messaging/accounts/export.ts | 3 +- .../src/messaging/accounts/json.ts | 5 +- yarn.lock | 8 +- 26 files changed, 364 insertions(+), 236 deletions(-) create mode 100644 packages/extension-base/src/types/account/action/add/json.ts diff --git a/packages/extension-base/src/background/KoniTypes.ts b/packages/extension-base/src/background/KoniTypes.ts index 880368dbcc..85aa7187e2 100644 --- a/packages/extension-base/src/background/KoniTypes.ts +++ b/packages/extension-base/src/background/KoniTypes.ts @@ -4,7 +4,7 @@ import { _AssetRef, _AssetType, _ChainAsset, _ChainInfo, _FundStatus, _MultiChainAsset } from '@subwallet/chain-list/types'; import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError'; import { AuthUrls, Resolver } from '@subwallet/extension-base/background/handlers/State'; -import { AccountAuthType, AuthorizeRequest, ConfirmationRequestBase, RequestAccountList, RequestAccountSubscribe, RequestAccountUnsubscribe, RequestAuthorizeCancel, RequestAuthorizeReject, RequestAuthorizeSubscribe, RequestAuthorizeTab, RequestCurrentAccountAddress, ResponseAuthorizeList, ResponseJsonGetAccountInfo } from '@subwallet/extension-base/background/types'; +import { AccountAuthType, AuthorizeRequest, ConfirmationRequestBase, RequestAccountList, RequestAccountSubscribe, RequestAccountUnsubscribe, RequestAuthorizeCancel, RequestAuthorizeReject, RequestAuthorizeSubscribe, RequestAuthorizeTab, RequestCurrentAccountAddress, ResponseAuthorizeList } from '@subwallet/extension-base/background/types'; import { RequestOptimalTransferProcess } from '@subwallet/extension-base/services/balance-service/helpers'; import { _CHAIN_VALIDATION_ERROR } from '@subwallet/extension-base/services/chain-service/handler/types'; import { _ChainState, _EvmApi, _NetworkUpsertParams, _SubstrateApi, _ValidateCustomAssetRequest, _ValidateCustomAssetResponse, EnableChainParams, EnableMultiChainParams } from '@subwallet/extension-base/services/chain-service/types'; @@ -12,16 +12,14 @@ import { AppBannerData, AppConfirmationData, AppPopupData } from '@subwallet/ext import { CrowdloanContributionsResponse } from '@subwallet/extension-base/services/subscan-service/types'; import { SWTransactionResponse, SWTransactionResult } from '@subwallet/extension-base/services/transaction-service/types'; import { WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; -import { - AccountJson, AccountsWithCurrentAddress, AddressJson, BalanceJson, BuyServiceInfo, BuyTokenInfo, CurrentAccountInfo, EarningRewardHistoryItem, EarningRewardJson, EarningStatus, HandleYieldStepParams, LeavePoolAdditionalData, NominationPoolInfo, OptimalYieldPath, OptimalYieldPathParams, RequestAccountCreateSuriV2, RequestCheckPublicAndSecretKey, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestEarlyValidateYield, RequestExportAccountProxyMnemonic, RequestGetDeriveAccounts, RequestGetYieldPoolTargets, RequestInputAccountSubscribe, RequestMetadataHash, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseAccountCreateSuriV2, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseEarlyValidateYield, ResponseExportAccountProxyMnemonic, ResponseGetDeriveAccounts, ResponseGetYieldPoolTargets, ResponseInputAccountSubscribe, ResponseMetadataHash, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2, ResponseShortenMetadata, StorageDataInterface, SubmitYieldStepData, TokenSpendingApprovalParams, UnlockDotTransactionNft, UnstakingStatus, ValidateYieldProcessParams, YieldPoolInfo, YieldPositionInfo, YieldValidationStatus -} from '@subwallet/extension-base/types'; +import { AccountJson, AccountsWithCurrentAddress, AddressJson, BalanceJson, BuyServiceInfo, BuyTokenInfo, CurrentAccountInfo, EarningRewardHistoryItem, EarningRewardJson, EarningStatus, HandleYieldStepParams, LeavePoolAdditionalData, NominationPoolInfo, OptimalYieldPath, OptimalYieldPathParams, RequestAccountBatchExportV2, RequestAccountCreateSuriV2, RequestBatchJsonGetAccountInfo, RequestBatchRestoreV2, RequestCheckPublicAndSecretKey, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestEarlyValidateYield, RequestExportAccountProxyMnemonic, RequestGetDeriveAccounts, RequestGetYieldPoolTargets, RequestInputAccountSubscribe, RequestJsonGetAccountInfo, RequestJsonRestoreV2, RequestMetadataHash, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseAccountBatchExportV2, ResponseAccountCreateSuriV2, ResponseBatchJsonGetAccountInfo, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseEarlyValidateYield, ResponseExportAccountProxyMnemonic, ResponseGetDeriveAccounts, ResponseGetYieldPoolTargets, ResponseInputAccountSubscribe, ResponseJsonGetAccountInfo, ResponseMetadataHash, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2, ResponseShortenMetadata, StorageDataInterface, SubmitYieldStepData, TokenSpendingApprovalParams, UnlockDotTransactionNft, UnstakingStatus, ValidateYieldProcessParams, YieldPoolInfo, YieldPositionInfo, YieldValidationStatus } from '@subwallet/extension-base/types'; import { RequestAccountProxyEdit, RequestAccountProxyForget } from '@subwallet/extension-base/types/account/action/edit'; import { CommonOptimalPath } from '@subwallet/extension-base/types/service-base'; import { SwapErrorType, SwapPair, SwapQuoteResponse, SwapRequest, SwapRequestResult, SwapSubmitParams, SwapTxData, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap'; import { InjectedAccount, InjectedAccountWithMeta, MetadataDefBase } from '@subwallet/extension-inject/types'; -import { KeyringPair$Json, KeyringPair$Meta } from '@subwallet/keyring/types'; +import { KeyringPair$Meta } from '@subwallet/keyring/types'; import { KeyringOptions } from '@subwallet/ui-keyring/options/types'; -import { KeyringAddress, KeyringPairs$Json } from '@subwallet/ui-keyring/types'; +import { KeyringAddress } from '@subwallet/ui-keyring/types'; import { SessionTypes } from '@walletconnect/types/dist/types/sign-client/session'; import { DexieExportJsonStructure } from 'dexie-export-import'; import Web3 from 'web3'; @@ -785,38 +783,6 @@ export interface ResponseAccountExportPrivateKey { // Export batch accounts -export interface RequestAccountBatchExportV2 { - password: string; - addresses?: string[]; -} - -export interface ResponseAccountBatchExportV2 { - exportedJson: KeyringPairs$Json; -} - -// Get account info with private key - -// Create derive account - -// Restore account with json file (single account) - -export interface RequestJsonRestoreV2 { - file: KeyringPair$Json; - password: string; - address: string; - isAllowed: boolean; - withMasterPassword: boolean; -} - -// Restore account with json file (multi account) - -export interface RequestBatchRestoreV2 { - file: KeyringPairs$Json; - password: string; - accountsInfo: ResponseJsonGetAccountInfo[]; - isAllowed: boolean; -} - // External account export enum AccountExternalErrorCode { @@ -2052,7 +2018,9 @@ export interface KoniRequestSignatures { 'pri(accounts.inject.remove)': [RequestRemoveInjectedAccounts, boolean]; // Restore by json + 'pri(accounts.json.info)': [RequestJsonGetAccountInfo, ResponseJsonGetAccountInfo]; 'pri(accounts.json.restoreV2)': [RequestJsonRestoreV2, void]; + 'pri(accounts.json.batchInfo)': [RequestBatchJsonGetAccountInfo, ResponseBatchJsonGetAccountInfo]; 'pri(accounts.json.batchRestoreV2)': [RequestBatchRestoreV2, void]; // Export account diff --git a/packages/extension-base/src/background/types.ts b/packages/extension-base/src/background/types.ts index aec5716e90..4c426be31d 100644 --- a/packages/extension-base/src/background/types.ts +++ b/packages/extension-base/src/background/types.ts @@ -9,7 +9,6 @@ import type { KeyringPairs$Json } from '@subwallet/ui-keyring/types'; import type { JsonRpcResponse } from '@polkadot/rpc-provider/types'; import type { SignerPayloadJSON, SignerPayloadRaw } from '@polkadot/types/types'; import type { HexString } from '@polkadot/util/types'; -import type { KeypairType } from '@polkadot/util-crypto/types'; import { KoniRequestSignatures, NetworkJson } from '@subwallet/extension-base/background/KoniTypes'; import { AccountJson } from '@subwallet/extension-base/types'; @@ -96,7 +95,6 @@ export interface RequestSignatures extends KoniRequestSignatures { 'pri(derivation.validate)': [RequestDeriveValidate, ResponseDeriveValidate]; 'pri(json.batchRestore)': [RequestBatchRestore, void]; 'pri(json.validate.password)': []; - 'pri(json.account.info)': [KeyringPair$Json, ResponseJsonGetAccountInfo]; 'pri(metadata.approve)': [RequestMetadataApprove, boolean]; 'pri(metadata.get)': [string | null, MetadataDef | null]; 'pri(metadata.reject)': [RequestMetadataReject, boolean]; @@ -391,13 +389,6 @@ export type WindowOpenParams = { params?: Record; } -export interface ResponseJsonGetAccountInfo { - address: string; - name: string; - genesisHash: string; - type: KeypairType; -} - export interface ResponseAuthorizeList { list: AuthUrls; } diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index 3aa76d7c64..8a59f2b730 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -7,8 +7,8 @@ import { _AssetRef, _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError'; import { withErrorLog } from '@subwallet/extension-base/background/handlers/helpers'; import { createSubscription } from '@subwallet/extension-base/background/handlers/subscriptions'; -import { AccountExternalError, AddressBookInfo, AmountData, AmountDataWithId, AssetSetting, AssetSettingUpdateReq, BasicTxErrorType, BondingOptionParams, BrowserConfirmationType, CampaignBanner, CampaignData, CampaignDataType, ChainType, CronReloadRequest, CrowdloanJson, ExternalRequestPromiseStatus, ExtrinsicType, KeyringState, MantaPayEnableMessage, MantaPayEnableParams, MantaPayEnableResponse, MantaPaySyncState, MetadataItem, NftCollection, NftJson, NftTransactionRequest, NftTransactionResponse, PriceJson, RequestAccountBatchExportV2, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateWithSecretKey, RequestAccountExportPrivateKey, RequestAddInjectedAccounts, RequestApproveConnectWalletSession, RequestApproveWalletConnectNotSupport, RequestAuthorization, RequestAuthorizationBlock, RequestAuthorizationPerAccount, RequestAuthorizationPerSite, RequestAuthorizeApproveV2, RequestBatchRestoreV2, RequestBondingSubmit, RequestCameraSettings, RequestCampaignBannerComplete, RequestChangeEnableChainPatrol, RequestChangeLanguage, RequestChangeMasterPassword, RequestChangePriceCurrency, RequestChangeShowBalance, RequestChangeShowZeroBalance, RequestChangeTimeAutoLock, RequestConfirmationComplete, RequestConnectWalletConnect, RequestCrossChainTransfer, RequestCrowdloanContributions, RequestDeleteContactAccount, RequestDisconnectWalletConnectSession, RequestEditContactAccount, RequestFindRawMetadata, RequestForgetSite, RequestFreeBalance, RequestGetTransaction, RequestJsonRestoreV2, RequestKeyringExportMnemonic, RequestMaxTransferable, RequestMigratePassword, RequestParseEvmContractInput, RequestParseTransactionSubstrate, RequestPassPhishingPage, RequestQrParseRLP, RequestQrSignEvm, RequestQrSignSubstrate, RequestRejectConnectWalletSession, RequestRejectExternalRequest, RequestRejectWalletConnectNotSupport, RequestRemoveInjectedAccounts, RequestResetWallet, RequestResolveExternalRequest, RequestSaveRecentAccount, RequestSettingsType, RequestSigningApprovePasswordV2, RequestStakePoolingBonding, RequestStakePoolingUnbonding, RequestSubscribeHistory, RequestSubstrateNftSubmitTransaction, RequestTransfer, RequestTuringCancelStakeCompound, RequestTuringStakeCompound, RequestUnbondingSubmit, RequestUnlockKeyring, RequestUnlockType, ResolveAddressToDomainRequest, ResolveDomainRequest, ResponseAccountBatchExportV2, ResponseAccountCreateWithSecretKey, ResponseAccountExportPrivateKey, ResponseChangeMasterPassword, ResponseFindRawMetadata, ResponseKeyringExportMnemonic, ResponseMigratePassword, ResponseParseEvmContractInput, ResponseParseTransactionSubstrate, ResponseQrParseRLP, ResponseQrSignEvm, ResponseQrSignSubstrate, ResponseRejectExternalRequest, ResponseResetWallet, ResponseResolveExternalRequest, ResponseSubscribeHistory, ResponseUnlockKeyring, ShowCampaignPopupRequest, StakingJson, StakingRewardJson, StakingTxErrorType, StakingType, ThemeNames, TransactionHistoryItem, TransactionResponse, ValidateNetworkRequest, ValidateNetworkResponse, ValidatorInfo } from '@subwallet/extension-base/background/KoniTypes'; -import { AccountAuthType, AuthorizeRequest, MessageTypes, MetadataRequest, RequestAccountExport, RequestAuthorizeCancel, RequestAuthorizeReject, RequestCurrentAccountAddress, RequestMetadataApprove, RequestMetadataReject, RequestSigningApproveSignature, RequestSigningCancel, RequestTypes, ResponseAccountExport, ResponseAuthorizeList, ResponseJsonGetAccountInfo, ResponseType, SigningRequest, WindowOpenParams } from '@subwallet/extension-base/background/types'; +import { AccountExternalError, AddressBookInfo, AmountData, AmountDataWithId, AssetSetting, AssetSettingUpdateReq, BasicTxErrorType, BondingOptionParams, BrowserConfirmationType, CampaignBanner, CampaignData, CampaignDataType, ChainType, CronReloadRequest, CrowdloanJson, ExternalRequestPromiseStatus, ExtrinsicType, KeyringState, MantaPayEnableMessage, MantaPayEnableParams, MantaPayEnableResponse, MantaPaySyncState, MetadataItem, NftCollection, NftJson, NftTransactionRequest, NftTransactionResponse, PriceJson, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateWithSecretKey, RequestAccountExportPrivateKey, RequestAddInjectedAccounts, RequestApproveConnectWalletSession, RequestApproveWalletConnectNotSupport, RequestAuthorization, RequestAuthorizationBlock, RequestAuthorizationPerAccount, RequestAuthorizationPerSite, RequestAuthorizeApproveV2, RequestBondingSubmit, RequestCameraSettings, RequestCampaignBannerComplete, RequestChangeEnableChainPatrol, RequestChangeLanguage, RequestChangeMasterPassword, RequestChangePriceCurrency, RequestChangeShowBalance, RequestChangeShowZeroBalance, RequestChangeTimeAutoLock, RequestConfirmationComplete, RequestConnectWalletConnect, RequestCrossChainTransfer, RequestCrowdloanContributions, RequestDeleteContactAccount, RequestDisconnectWalletConnectSession, RequestEditContactAccount, RequestFindRawMetadata, RequestForgetSite, RequestFreeBalance, RequestGetTransaction, RequestKeyringExportMnemonic, RequestMaxTransferable, RequestMigratePassword, RequestParseEvmContractInput, RequestParseTransactionSubstrate, RequestPassPhishingPage, RequestQrParseRLP, RequestQrSignEvm, RequestQrSignSubstrate, RequestRejectConnectWalletSession, RequestRejectExternalRequest, RequestRejectWalletConnectNotSupport, RequestRemoveInjectedAccounts, RequestResetWallet, RequestResolveExternalRequest, RequestSaveRecentAccount, RequestSettingsType, RequestSigningApprovePasswordV2, RequestStakePoolingBonding, RequestStakePoolingUnbonding, RequestSubscribeHistory, RequestSubstrateNftSubmitTransaction, RequestTransfer, RequestTuringCancelStakeCompound, RequestTuringStakeCompound, RequestUnbondingSubmit, RequestUnlockKeyring, RequestUnlockType, ResolveAddressToDomainRequest, ResolveDomainRequest, ResponseAccountCreateWithSecretKey, ResponseAccountExportPrivateKey, ResponseChangeMasterPassword, ResponseFindRawMetadata, ResponseKeyringExportMnemonic, ResponseMigratePassword, ResponseParseEvmContractInput, ResponseParseTransactionSubstrate, ResponseQrParseRLP, ResponseQrSignEvm, ResponseQrSignSubstrate, ResponseRejectExternalRequest, ResponseResetWallet, ResponseResolveExternalRequest, ResponseSubscribeHistory, ResponseUnlockKeyring, ShowCampaignPopupRequest, StakingJson, StakingRewardJson, StakingTxErrorType, StakingType, ThemeNames, TransactionHistoryItem, TransactionResponse, ValidateNetworkRequest, ValidateNetworkResponse, ValidatorInfo } from '@subwallet/extension-base/background/KoniTypes'; +import { AccountAuthType, AuthorizeRequest, MessageTypes, MetadataRequest, RequestAccountExport, RequestAuthorizeCancel, RequestAuthorizeReject, RequestCurrentAccountAddress, RequestMetadataApprove, RequestMetadataReject, RequestSigningApproveSignature, RequestSigningCancel, RequestTypes, ResponseAccountExport, ResponseAuthorizeList, ResponseType, SigningRequest, WindowOpenParams } from '@subwallet/extension-base/background/types'; import { TransactionWarning } from '@subwallet/extension-base/background/warnings/TransactionWarning'; import { ALL_ACCOUNT_KEY, LATEST_SESSION, XCM_FEE_RATIO } from '@subwallet/extension-base/constants'; import { additionalValidateTransfer, additionalValidateXcmTransfer, validateTransferRequest, validateXcmTransferRequest } from '@subwallet/extension-base/core/logic-validation/transfer'; @@ -42,7 +42,7 @@ import { isProposalExpired, isSupportWalletConnectChain, isSupportWalletConnectN import { ResultApproveWalletConnectSession, WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; import { SWStorage } from '@subwallet/extension-base/storage'; import { AccountsStore } from '@subwallet/extension-base/stores'; -import { AccountJson, AccountProxyMap, AccountsWithCurrentAddress, BalanceJson, BuyServiceInfo, BuyTokenInfo, EarningRewardJson, NominationPoolInfo, OptimalYieldPathParams, RequestAccountCreateSuriV2, RequestCheckPublicAndSecretKey, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestEarlyValidateYield, RequestExportAccountProxyMnemonic, RequestGetDeriveAccounts, RequestGetYieldPoolTargets, RequestInputAccountSubscribe, RequestMetadataHash, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseAccountCreateSuriV2, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseExportAccountProxyMnemonic, ResponseGetDeriveAccounts, ResponseGetYieldPoolTargets, ResponseInputAccountSubscribe, ResponseMetadataHash, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2, ResponseShortenMetadata, StorageDataInterface, TokenSpendingApprovalParams, ValidateYieldProcessParams, YieldPoolType } from '@subwallet/extension-base/types'; +import { AccountJson, AccountProxyMap, AccountsWithCurrentAddress, BalanceJson, BuyServiceInfo, BuyTokenInfo, EarningRewardJson, NominationPoolInfo, OptimalYieldPathParams, RequestAccountBatchExportV2, RequestAccountCreateSuriV2, RequestBatchJsonGetAccountInfo, RequestBatchRestoreV2, RequestCheckPublicAndSecretKey, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestEarlyValidateYield, RequestExportAccountProxyMnemonic, RequestGetDeriveAccounts, RequestGetYieldPoolTargets, RequestInputAccountSubscribe, RequestJsonGetAccountInfo, RequestJsonRestoreV2, RequestMetadataHash, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseAccountBatchExportV2, ResponseAccountCreateSuriV2, ResponseBatchJsonGetAccountInfo, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseExportAccountProxyMnemonic, ResponseGetDeriveAccounts, ResponseGetYieldPoolTargets, ResponseInputAccountSubscribe, ResponseJsonGetAccountInfo, ResponseMetadataHash, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2, ResponseShortenMetadata, StorageDataInterface, TokenSpendingApprovalParams, ValidateYieldProcessParams, YieldPoolType } from '@subwallet/extension-base/types'; import { RequestAccountProxyEdit, RequestAccountProxyForget } from '@subwallet/extension-base/types/account/action/edit'; import { CommonOptimalPath } from '@subwallet/extension-base/types/service-base'; import { SwapPair, SwapQuoteResponse, SwapRequest, SwapRequestResult, SwapSubmitParams, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap'; @@ -51,7 +51,7 @@ import { parseContractInput, parseEvmRlp } from '@subwallet/extension-base/utils import { metadataExpand } from '@subwallet/extension-chains'; import { MetadataDef } from '@subwallet/extension-inject/types'; import { getKeypairTypeByAddress } from '@subwallet/keyring'; -import { EthereumKeypairTypes, KeyringPair$Json, SubstrateKeypairTypes } from '@subwallet/keyring/types'; +import { EthereumKeypairTypes, SubstrateKeypairTypes } from '@subwallet/keyring/types'; import { keyring } from '@subwallet/ui-keyring'; import { SubjectInfo } from '@subwallet/ui-keyring/observable/types'; import { KeyringAddress, KeyringJson$Meta } from '@subwallet/ui-keyring/types'; @@ -184,10 +184,6 @@ export default class KoniExtension { return this.#koniState.metaSubject.value; } - private jsonGetAccountInfo (json: KeyringPair$Json): ResponseJsonGetAccountInfo { - return this.#koniState.keyringService.context.jsonGetAccountInfo(json); - } - // TODO: move to request service private signingApproveSignature ({ id, signature, signedTransaction }: RequestSigningApproveSignature): boolean { const queued = this.#koniState.getSignRequest(id); @@ -338,10 +334,10 @@ export default class KoniExtension { const contactObservable = this.#koniState.keyringService.context.observable.contacts; const chainInfoMapObservable = this.#koniState.chainService.subscribeChainInfoMap().asObservable(); - const subscription = combineLatest({ chainInfoMap: chainInfoMapObservable, accountProxies: accountObservable, contacts: contactObservable }).subscribe(async ({ accountProxies, chainInfoMap, contacts }) => { - const rs = await combineFunction(chainInfoMap, accountProxies, contacts); - - cb(rs); + const subscription = combineLatest({ chainInfoMap: chainInfoMapObservable, accountProxies: accountObservable, contacts: contactObservable }).subscribe(({ accountProxies, chainInfoMap, contacts }) => { + combineFunction(chainInfoMap, accountProxies, contacts) + .then((rs) => cb(rs)) + .catch(console.error); }); this.createUnsubscriptionHandle(id, () => { @@ -1084,6 +1080,12 @@ export default class KoniExtension { return this.#koniState.keyringService.context.privateKeyValidateV2(request); } + /* JSON */ + + private parseInfoSingleJson (request: RequestJsonGetAccountInfo): ResponseJsonGetAccountInfo { + return this.#koniState.keyringService.context.parseInfoSingleJson(request); + } + private jsonRestoreV2 (request: RequestJsonRestoreV2): void { this.#koniState.keyringService.context.jsonRestoreV2(request); @@ -1092,6 +1094,10 @@ export default class KoniExtension { } } + private parseInfoMultiJson (request: RequestBatchJsonGetAccountInfo): ResponseBatchJsonGetAccountInfo { + return this.#koniState.keyringService.context.parseInfoMultiJson(request); + } + private batchRestoreV2 (request: RequestBatchRestoreV2): void { this.#koniState.keyringService.context.batchRestoreV2(request); } @@ -1100,6 +1106,8 @@ export default class KoniExtension { return this.#koniState.keyringService.context.batchExportV2(request); } + /* JSON */ + private exportAccountProxyMnemonic (request: RequestExportAccountProxyMnemonic): ResponseExportAccountProxyMnemonic { return this.#koniState.keyringService.context.exportAccountProxyMnemonic(request); } @@ -3624,9 +3632,6 @@ export default class KoniExtension { case 'pri(metadata.requests)': return this.metadataSubscribe(id, port); - case 'pri(json.account.info)': - return this.jsonGetAccountInfo(request as KeyringPair$Json); - case 'pri(signing.approve.signature)': return this.signingApproveSignature(request as RequestSigningApproveSignature); @@ -3793,8 +3798,14 @@ export default class KoniExtension { return await this.accountsCreateHardwareMultiple(request as RequestAccountCreateHardwareMultiple); case 'pri(accounts.create.withSecret)': return await this.accountsCreateWithSecret(request as RequestAccountCreateWithSecretKey); + + case 'pri(accounts.json.info)': + return this.parseInfoSingleJson(request as RequestJsonGetAccountInfo); case 'pri(accounts.json.restoreV2)': return this.jsonRestoreV2(request as RequestJsonRestoreV2); + + case 'pri(accounts.json.batchInfo)': + return this.parseInfoMultiJson(request as RequestBatchJsonGetAccountInfo); case 'pri(accounts.json.batchRestoreV2)': return this.batchRestoreV2(request as RequestBatchRestoreV2); case 'pri(seed.createV2)': diff --git a/packages/extension-base/src/services/keyring-service/context/account-context.ts b/packages/extension-base/src/services/keyring-service/context/account-context.ts index 4bb66ceaab..2f08a10f86 100644 --- a/packages/extension-base/src/services/keyring-service/context/account-context.ts +++ b/packages/extension-base/src/services/keyring-service/context/account-context.ts @@ -1,13 +1,11 @@ // Copyright 2019-2022 @subwallet/extension-base // SPDX-License-Identifier: Apache-2.0 -import { AccountExternalError, RequestAccountBatchExportV2, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateWithSecretKey, RequestAccountExportPrivateKey, RequestBatchRestoreV2, RequestChangeMasterPassword, RequestJsonRestoreV2, RequestMigratePassword, ResponseAccountBatchExportV2, ResponseAccountCreateWithSecretKey, ResponseAccountExportPrivateKey, ResponseChangeMasterPassword, ResponseMigratePassword } from '@subwallet/extension-base/background/KoniTypes'; -import { ResponseJsonGetAccountInfo } from '@subwallet/extension-base/background/types'; +import { AccountExternalError, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateWithSecretKey, RequestAccountExportPrivateKey, RequestChangeMasterPassword, RequestMigratePassword, ResponseAccountCreateWithSecretKey, ResponseAccountExportPrivateKey, ResponseChangeMasterPassword, ResponseMigratePassword } from '@subwallet/extension-base/background/KoniTypes'; import KoniState from '@subwallet/extension-base/koni/background/handlers/State'; import { KeyringService } from '@subwallet/extension-base/services/keyring-service'; -import { AccountProxyMap, CurrentAccountInfo, RequestAccountCreateSuriV2, RequestAccountProxyEdit, RequestAccountProxyForget, RequestCheckPublicAndSecretKey, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestExportAccountProxyMnemonic, RequestGetDeriveAccounts, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, ResponseAccountCreateSuriV2, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseExportAccountProxyMnemonic, ResponseGetDeriveAccounts, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2 } from '@subwallet/extension-base/types'; +import { AccountProxyMap, CurrentAccountInfo, RequestAccountBatchExportV2, RequestAccountCreateSuriV2, RequestAccountProxyEdit, RequestAccountProxyForget, RequestBatchJsonGetAccountInfo, RequestBatchRestoreV2, RequestCheckPublicAndSecretKey, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestExportAccountProxyMnemonic, RequestGetDeriveAccounts, RequestJsonGetAccountInfo, RequestJsonRestoreV2, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, ResponseAccountBatchExportV2, ResponseAccountCreateSuriV2, ResponseBatchJsonGetAccountInfo, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseExportAccountProxyMnemonic, ResponseGetDeriveAccounts, ResponseJsonGetAccountInfo, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2 } from '@subwallet/extension-base/types'; import { InjectedAccountWithMeta } from '@subwallet/extension-inject/types'; -import { KeyringPair$Json } from '@subwallet/keyring/types'; import { SubjectInfo } from '@subwallet/ui-keyring/observable/types'; import { AccountDeriveHandler, AccountInjectHandler, AccountJsonHandler, AccountLedgerHandler, AccountMnemonicHandler, AccountModifyHandler, AccountSecretHandler } from './handlers'; @@ -154,16 +152,20 @@ export class AccountContext { /* JSON */ + public parseInfoSingleJson (request: RequestJsonGetAccountInfo): ResponseJsonGetAccountInfo { + return this.jsonHandler.parseInfoSingleJson(request); + } + public jsonRestoreV2 (request: RequestJsonRestoreV2): void { this.jsonHandler.jsonRestoreV2(request); } - public batchRestoreV2 (request: RequestBatchRestoreV2): void { - this.jsonHandler.batchRestoreV2(request); + public parseInfoMultiJson (request: RequestBatchJsonGetAccountInfo): ResponseBatchJsonGetAccountInfo { + return this.jsonHandler.parseInfoMultiJson(request); } - public jsonGetAccountInfo (json: KeyringPair$Json): ResponseJsonGetAccountInfo { - return this.jsonHandler.jsonGetAccountInfo(json); + public batchRestoreV2 (request: RequestBatchRestoreV2): void { + this.jsonHandler.batchRestoreV2(request); } public batchExportV2 (request: RequestAccountBatchExportV2): Promise { diff --git a/packages/extension-base/src/services/keyring-service/context/handlers/Derive.ts b/packages/extension-base/src/services/keyring-service/context/handlers/Derive.ts index 06dee95d37..8a12159b84 100644 --- a/packages/extension-base/src/services/keyring-service/context/handlers/Derive.ts +++ b/packages/extension-base/src/services/keyring-service/context/handlers/Derive.ts @@ -239,7 +239,7 @@ export class AccountDeriveHandler extends AccountBaseHandler { const proxyId = createAccountProxyId(parentProxyId, suri); const pairs: KeyringPair[] = []; - this.state.upsertAccountProxy({ id: proxyId, name, parentId: parentProxyId, suri: suri }); + this.state.upsertAccountProxyByKey({ id: proxyId, name, parentId: parentProxyId, suri: suri }); for (const parentAddress of addresses) { const parentPair = keyring.getPair(parentAddress); diff --git a/packages/extension-base/src/services/keyring-service/context/handlers/Json.ts b/packages/extension-base/src/services/keyring-service/context/handlers/Json.ts index 7b8786c58b..1500ba92b1 100644 --- a/packages/extension-base/src/services/keyring-service/context/handlers/Json.ts +++ b/packages/extension-base/src/services/keyring-service/context/handlers/Json.ts @@ -1,9 +1,9 @@ // Copyright 2019-2022 @subwallet/extension-base // SPDX-License-Identifier: Apache-2.0 -import { RequestAccountBatchExportV2, RequestBatchRestoreV2, RequestJsonRestoreV2, ResponseAccountBatchExportV2 } from '@subwallet/extension-base/background/KoniTypes'; -import { ResponseJsonGetAccountInfo } from '@subwallet/extension-base/background/types'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; +import { AccountProxy, AccountProxyStoreData, KeyringPairs$JsonV2, ModifyPairStoreData, RequestAccountBatchExportV2, RequestBatchJsonGetAccountInfo, RequestBatchRestoreV2, RequestJsonGetAccountInfo, RequestJsonRestoreV2, ResponseAccountBatchExportV2, ResponseBatchJsonGetAccountInfo, ResponseJsonGetAccountInfo } from '@subwallet/extension-base/types'; +import { combineAccountsWithKeyPair, convertAccountProxyType, transformAccount } from '@subwallet/extension-base/utils'; import { createPair } from '@subwallet/keyring'; import { KeypairType, KeyringPair$Json } from '@subwallet/keyring/types'; import { keyring } from '@subwallet/ui-keyring'; @@ -39,7 +39,6 @@ export class AccountJsonHandler extends AccountBaseHandler { isHex(json.encoded) ? hexToU8a(json.encoded) : base64Decode(json.encoded), encType ); - const exists = this.state.checkAddressExists([pair.address]); assert(!exists, t('Account already exists account: {{name}}', { replace: { name: exists?.name || exists?.address || pair.address } })); @@ -57,19 +56,45 @@ export class AccountJsonHandler extends AccountBaseHandler { } } + public parseInfoSingleJson ({ json, password }: RequestJsonGetAccountInfo): ResponseJsonGetAccountInfo { + const isPasswordValidated = this.validatePassword(json, password); + + if (isPasswordValidated) { + try { + const { address, meta, type } = keyring.createFromJson(json); + const account = transformAccount(address, type, meta); + const proxy: AccountProxy = { + id: address, + accountType: convertAccountProxyType(account.signMode), + name: account.name || account.address, + accounts: [account], + chainTypes: [account.chainType], + parentId: account.parentAddress, + suri: account.suri, + tokenTypes: account.tokenTypes, + accountActions: [] + }; + + return { + accountProxy: proxy + }; + } catch (e) { + console.error(e); + throw new Error((e as Error).message); + } + } else { + throw new Error(t('Wrong password')); + } + } + public jsonRestoreV2 ({ address, file, isAllowed, password, withMasterPassword }: RequestJsonRestoreV2): void { const isPasswordValidated = this.validatePassword(file, password); if (isPasswordValidated) { try { - this.state.saveCurrentAccountProxyId(address, () => { - const newAccount = keyring.restoreAccount(file, password, withMasterPassword); - - // genesisHash is not used in SubWallet => reset it to empty string, if it is not hardware wallet - if (!newAccount.meta?.isHardware && newAccount.meta?.genesisHash !== '') { - keyring.saveAccountMeta(newAccount, { ...newAccount.meta, genesisHash: '' }); - } + keyring.restoreAccount(file, password, withMasterPassword); + this.state.saveCurrentAccountProxyId(address, () => { this.state.updateMetadataForPair(); this.state._addAddressToAuthList(address, isAllowed); }); @@ -81,30 +106,98 @@ export class AccountJsonHandler extends AccountBaseHandler { } } - private validatedAccountsPassword (json: EncryptedJson, password: string): boolean { + private validatedAccountsPassword (json: EncryptedJson, password: string): KeyringPair$Json[] | null { try { - u8aToString(jsonDecrypt(json, password)); + const decoded = u8aToString(jsonDecrypt(json, password)); - return true; + return JSON.parse(decoded) as KeyringPair$Json[]; } catch (e) { - return false; + return null; } } - public batchRestoreV2 ({ accountsInfo, file, isAllowed, password }: RequestBatchRestoreV2): void { - const addressList: string[] = accountsInfo.map((acc) => acc.address); - const isPasswordValidated = this.validatedAccountsPassword(file, password); - const exists = this.state.checkAddressExists(addressList); + public parseInfoMultiJson ({ json, password }: RequestBatchJsonGetAccountInfo): ResponseBatchJsonGetAccountInfo { + const jsons = this.validatedAccountsPassword(json, password); - assert(!exists, t('Account already exists account: {{name}}', { replace: { name: exists?.name || exists?.address || '' } })); + if (jsons) { + try { + const { accountProxies, modifyPairs } = json; + const pairs = jsons.map((pair) => keyring.createFromJson(pair)); + const accountProxyMap = combineAccountsWithKeyPair(pairs, modifyPairs, accountProxies); + const result = Object.values(accountProxyMap); + + return { + accountProxies: result + }; + } catch (e) { + console.error(e); + throw new Error((e as Error).message); + } + } else { + throw new Error(t('Wrong password')); + } + } - if (isPasswordValidated) { + public batchRestoreV2 ({ file, isAllowed, password, proxyIds: _proxyIds }: RequestBatchRestoreV2): void { + const jsons = this.validatedAccountsPassword(file, password); + + if (jsons) { try { - this.state.saveCurrentAccountProxyId(ALL_ACCOUNT_KEY, () => { - keyring.restoreAccounts(file, password); + const { accountProxies, modifyPairs } = file; + const pairs = jsons.map((pair) => keyring.createFromJson(pair)); + const accountProxyMap = combineAccountsWithKeyPair(pairs, modifyPairs, accountProxies); + const rawProxyIds = _proxyIds && _proxyIds.length ? _proxyIds : Object.keys(accountProxyMap); + + const filteredAccountProxies = Object.fromEntries(Object.entries(accountProxyMap) + .filter(([key, value]) => { + if (!rawProxyIds.includes(key)) { + return false; + } + + const addresses = value.accounts.map((account) => account.address); + const exists = this.state.checkAddressExists(addresses); + + return !exists; + }) + ); + + const addresses = Object.values(filteredAccountProxies).flatMap((proxy) => proxy.accounts.map((account) => account.address)); + const proxyIds = Object.values(filteredAccountProxies).flatMap((proxy) => proxy.id); + + const _accountProxies = this.state.value.accountProxy; + const _modifyPairs = this.state.value.modifyPair; + const currentProxyId = this.state.value.currentAccount.proxyId; + + const nextAccountProxyId = !proxyIds.length + ? currentProxyId + : proxyIds.length === 1 + ? proxyIds[0] + : ALL_ACCOUNT_KEY; + + if (accountProxies) { + for (const proxyId of proxyIds) { + if (accountProxies[proxyId]) { + _accountProxies[proxyId] = accountProxies[proxyId]; + } + } + } + if (modifyPairs) { + for (const [key, modifyPair] of Object.entries(modifyPairs)) { + if (proxyIds.includes(modifyPair.accountProxyId || '')) { + _modifyPairs[key] = modifyPair; + } + } + } + + this.state.upsertAccountProxy(_accountProxies); + this.state.upsertModifyPairs(_modifyPairs); + + keyring.restoreAccounts(file, password, addresses); + + this.state.saveCurrentAccountProxyId(nextAccountProxyId, () => { this.state.updateMetadataForPair(); - this.state._addAddressesToAuthList(addressList, isAllowed); + this.state._addAddressesToAuthList(addresses, isAllowed); }); } catch (error) { throw new Error((error as Error).message); @@ -114,32 +207,30 @@ export class AccountJsonHandler extends AccountBaseHandler { } } - public jsonGetAccountInfo (json: KeyringPair$Json): ResponseJsonGetAccountInfo { - try { - const { address, meta: { genesisHash, name }, type } = keyring.createFromJson(json); - - return { - address, - genesisHash, - name, - type - } as ResponseJsonGetAccountInfo; - } catch (e) { - console.error(e); - throw new Error((e as Error).message); - } - } - public async batchExportV2 (request: RequestAccountBatchExportV2): Promise { - const { addresses, password } = request; + const { password, proxyIds } = request; try { - if (addresses && !addresses.length) { + if (proxyIds && !proxyIds.length) { throw new Error(t('No accounts found to export')); } + const _accountProxy = this.state.value.accountProxy; + const _modifyPair = this.state.value.modifyPair; + const _account = this.state.value.accounts; + const _proxyIds = proxyIds || Object.keys(_account); + const modifyPairs: ModifyPairStoreData = Object.fromEntries(Object.entries(_modifyPair).filter(([, modifyPair]) => _proxyIds.includes(modifyPair.accountProxyId || ''))); + const accountProxies: AccountProxyStoreData = Object.fromEntries(Object.entries(_accountProxy).filter(([, proxy]) => _proxyIds.includes(proxy.id))); + const addresses = Object.values(_account).filter((account) => _proxyIds.includes(account.id)).flatMap((proxy) => proxy.accounts.map((account) => account.address)); + const rs: KeyringPairs$JsonV2 = await keyring.backupAccounts(password, addresses); + + if (Object.keys(modifyPairs).length && Object.keys(accountProxies).length) { + rs.accountProxies = accountProxies; + rs.modifyPairs = modifyPairs; + } + return { - exportedJson: await keyring.backupAccounts(password, addresses) + exportedJson: rs }; } catch (e) { const error = e as Error; diff --git a/packages/extension-base/src/services/keyring-service/context/handlers/Mnemonic.ts b/packages/extension-base/src/services/keyring-service/context/handlers/Mnemonic.ts index 0900928562..97cb5fd6b0 100644 --- a/packages/extension-base/src/services/keyring-service/context/handlers/Mnemonic.ts +++ b/packages/extension-base/src/services/keyring-service/context/handlers/Mnemonic.ts @@ -124,7 +124,7 @@ export class AccountMnemonicHandler extends AccountBaseHandler { // Upsert account group first, to avoid combine latest have no account group data. if (proxyId) { - this.state.upsertAccountProxy({ id: proxyId, name }); + this.state.upsertAccountProxyByKey({ id: proxyId, name }); } // Upsert modify pair before add account to keyring diff --git a/packages/extension-base/src/services/keyring-service/context/handlers/Modify.ts b/packages/extension-base/src/services/keyring-service/context/handlers/Modify.ts index 935f3f1edf..c15449118c 100644 --- a/packages/extension-base/src/services/keyring-service/context/handlers/Modify.ts +++ b/packages/extension-base/src/services/keyring-service/context/handlers/Modify.ts @@ -102,7 +102,7 @@ export class AccountModifyHandler extends AccountBaseHandler { const addresses = Object.keys(modifyPairs).filter((address) => modifyPairs[address].accountProxyId === proxyId); accountProxy.name = name; - this.state.upsertAccountProxy(accountProxy); + this.state.upsertAccountProxyByKey(accountProxy); for (const address of addresses) { const pair = keyring.getPair(address); diff --git a/packages/extension-base/src/services/keyring-service/context/state.ts b/packages/extension-base/src/services/keyring-service/context/state.ts index 87bb2e3c86..a5f582fca7 100644 --- a/packages/extension-base/src/services/keyring-service/context/state.ts +++ b/packages/extension-base/src/services/keyring-service/context/state.ts @@ -6,8 +6,8 @@ import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; import KoniState from '@subwallet/extension-base/koni/background/handlers/State'; import { AccountProxyStoreSubject, CurrentAccountStoreSubject, ModifyPairStoreSubject } from '@subwallet/extension-base/services/keyring-service/context/stores'; import { AccountRefStore } from '@subwallet/extension-base/stores'; -import { AccountMetadataData, AccountProxyData, AccountProxyMap, AccountProxyType, CurrentAccountInfo, ModifyPairStoreData } from '@subwallet/extension-base/types'; -import { addLazy, combineAccounts, isAddressValidWithAuthType } from '@subwallet/extension-base/utils'; +import { AccountMetadataData, AccountProxyData, AccountProxyMap, AccountProxyStoreData, AccountProxyType, CurrentAccountInfo, ModifyPairStoreData } from '@subwallet/extension-base/types'; +import { addLazy, combineAccountsWithSubjectInfo, isAddressValidWithAuthType } from '@subwallet/extension-base/utils'; import { keyring } from '@subwallet/ui-keyring'; import { SubjectInfo } from '@subwallet/ui-keyring/observable/types'; import { BehaviorSubject, combineLatest } from 'rxjs'; @@ -94,7 +94,7 @@ export class AccountState { combineLatest([pairs, modifyPairs, accountGroups, chainInfoMap]).subscribe(([pairs, modifyPairs, accountGroups, chainInfoMap]) => { addLazy('combineAccounts', () => { - const result = combineAccounts(pairs, modifyPairs, accountGroups, chainInfoMap); + const result = combineAccountsWithSubjectInfo(pairs, modifyPairs, accountGroups, chainInfoMap); this.accountSubject.next(result); }, 300, 1800, true); @@ -135,6 +135,7 @@ export class AccountState { const accountProxy = this._accountProxy; const currentAccount = this._currentAccount; const contacts = this.contactSubject; + const modifyPair = this._modifyPair; return { get pairs () { @@ -151,6 +152,9 @@ export class AccountState { }, get contacts () { return contacts.value; + }, + get modifyPair () { + return modifyPair.value; } }; } @@ -221,7 +225,7 @@ export class AccountState { const accountProxies = this.accountProxies; const modifyPairs = this.modifyPairs; - const data = combineAccounts(pairs, modifyPairs, accountProxies); + const data = combineAccountsWithSubjectInfo(pairs, modifyPairs, accountProxies); const accounts = Object.keys(data); const firstAccount = accounts[0]; @@ -299,7 +303,11 @@ export class AccountState { /* Account groups */ /* Upsert account group */ - public upsertAccountProxy (data: AccountProxyData, callback?: () => void) { + public upsertAccountProxy (data: AccountProxyStoreData, callback?: () => void) { + this._accountProxy.upsertData(data, callback); + } + + public upsertAccountProxyByKey (data: AccountProxyData, callback?: () => void) { this._accountProxy.upsertByKey(data, callback); } diff --git a/packages/extension-base/src/types/account/action/add/index.ts b/packages/extension-base/src/types/account/action/add/index.ts index 442999af3b..e3d328b35e 100644 --- a/packages/extension-base/src/types/account/action/add/index.ts +++ b/packages/extension-base/src/types/account/action/add/index.ts @@ -1,5 +1,6 @@ // Copyright 2019-2022 @subwallet/extension-base authors & contributors // SPDX-License-Identifier: Apache-2.0 +export * from './json'; export * from './mnemonic'; export * from './secret'; diff --git a/packages/extension-base/src/types/account/action/add/json.ts b/packages/extension-base/src/types/account/action/add/json.ts new file mode 100644 index 0000000000..56828a049c --- /dev/null +++ b/packages/extension-base/src/types/account/action/add/json.ts @@ -0,0 +1,41 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { KeyringPair$Json } from '@subwallet/keyring/types'; + +import { AccountProxy, KeyringPairs$JsonV2 } from '../../info'; + +export interface RequestJsonGetAccountInfo { + json: KeyringPair$Json; + password: string; +} + +export interface ResponseJsonGetAccountInfo { + accountProxy: AccountProxy; +} + +// Restore account with json file (single account) +export interface RequestJsonRestoreV2 { + file: KeyringPair$Json; + password: string; + address: string; + isAllowed: boolean; + withMasterPassword: boolean; +} + +export interface RequestBatchJsonGetAccountInfo { + json: KeyringPairs$JsonV2; + password: string; +} + +export interface ResponseBatchJsonGetAccountInfo { + accountProxies: AccountProxy[]; +} + +// Restore account with json file (multi account) +export interface RequestBatchRestoreV2 { + file: KeyringPairs$JsonV2; + password: string; + isAllowed: boolean; + proxyIds?: string[]; +} diff --git a/packages/extension-base/src/types/account/action/add/mnemonic.ts b/packages/extension-base/src/types/account/action/add/mnemonic.ts index c54e9ffc83..8610c1c786 100644 --- a/packages/extension-base/src/types/account/action/add/mnemonic.ts +++ b/packages/extension-base/src/types/account/action/add/mnemonic.ts @@ -80,8 +80,6 @@ export interface RequestAccountCreateSuriV2 { isAllowed: boolean; } -// Copyright 2019-2022 @subwallet/extension-base authors & contributors -// SPDX-License-Identifier: Apache-2.0 /** * @typedef {Record} ResponseAccountCreateSuriV2 * @description Represents the response for creating an account from a mnemonic phrase. diff --git a/packages/extension-base/src/types/account/action/export.ts b/packages/extension-base/src/types/account/action/export.ts index 815570f7c2..02c2649506 100644 --- a/packages/extension-base/src/types/account/action/export.ts +++ b/packages/extension-base/src/types/account/action/export.ts @@ -1,6 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-base authors & contributors // SPDX-License-Identifier: Apache-2.0 +import { KeyringPairs$JsonV2 } from '../info'; + export interface RequestExportAccountProxyMnemonic { proxyId: string; password: string; @@ -9,3 +11,12 @@ export interface RequestExportAccountProxyMnemonic { export interface ResponseExportAccountProxyMnemonic { result: string; } + +export interface RequestAccountBatchExportV2 { + password: string; + proxyIds?: string[]; +} + +export interface ResponseAccountBatchExportV2 { + exportedJson: KeyringPairs$JsonV2; +} diff --git a/packages/extension-base/src/types/account/info/proxy.ts b/packages/extension-base/src/types/account/info/proxy.ts index d43323d68d..54cee1f8b5 100644 --- a/packages/extension-base/src/types/account/info/proxy.ts +++ b/packages/extension-base/src/types/account/info/proxy.ts @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { _AssetType } from '@subwallet/chain-list/types'; +import { KeyringPairs$Json } from '@subwallet/ui-keyring/types'; import { AccountActions, AccountChainType, AccountJson } from './keyring'; @@ -73,3 +74,8 @@ export interface ModifyPairData { } export type ModifyPairStoreData = Record; + +export interface KeyringPairs$JsonV2 extends KeyringPairs$Json { + modifyPairs?: ModifyPairStoreData; + accountProxies?: AccountProxyStoreData; +} diff --git a/packages/extension-base/src/utils/account/transform.ts b/packages/extension-base/src/utils/account/transform.ts index 6e11f69de5..a84e4764ed 100644 --- a/packages/extension-base/src/utils/account/transform.ts +++ b/packages/extension-base/src/utils/account/transform.ts @@ -101,8 +101,10 @@ export const getAccountActions = (signMode: AccountSignMode, networkType: Accoun } // Private key - if (signMode === AccountSignMode.PASSWORD && networkType === AccountChainType.ETHEREUM) { - result.push(AccountActions.EXPORT_PRIVATE_KEY); + if (signMode === AccountSignMode.PASSWORD) { + if (networkType === AccountChainType.ETHEREUM || networkType === AccountChainType.TON) { + result.push(AccountActions.EXPORT_PRIVATE_KEY); + } } // QR @@ -394,12 +396,34 @@ export const transformAddress = (address: string, meta?: KeyringPair$Meta): Addr export const transformAddresses = (addresses: SubjectInfo): AddressJson[] => Object.values(addresses).map(({ json: { address, meta } }) => transformAddress(address, meta)); -export const combineAccounts = (pairs: SubjectInfo, modifyPairs: ModifyPairStoreData, accountProxies: AccountProxyStoreData, chainInfoMap?: Record) => { +export const convertAccountProxyType = (accountSignMode: AccountSignMode): AccountProxyType => { + switch (accountSignMode) { + case AccountSignMode.GENERIC_LEDGER: + case AccountSignMode.LEGACY_LEDGER: + return AccountProxyType.LEDGER; + case AccountSignMode.QR: + return AccountProxyType.QR; + case AccountSignMode.READ_ONLY: + return AccountProxyType.READ_ONLY; + case AccountSignMode.INJECTED: + return AccountProxyType.INJECTED; + case AccountSignMode.PASSWORD: + return AccountProxyType.SOLO; + case AccountSignMode.ALL_ACCOUNT: + return AccountProxyType.ALL_ACCOUNT; + case AccountSignMode.UNKNOWN: + return AccountProxyType.UNKNOWN; + } + + return AccountProxyType.UNKNOWN; +}; + +export const _combineAccounts = (accounts: AccountJson[], modifyPairs: ModifyPairStoreData, accountProxies: AccountProxyStoreData) => { const temp: Record> = {}; - for (const [address, pair] of Object.entries(pairs)) { + for (const account of accounts) { + const address = account.address; const modifyPair = modifyPairs[address]; - const account: AccountJson = singleAddressToAccount(pair, chainInfoMap); if (modifyPair && modifyPair.accountProxyId) { const accountGroup = accountProxies[modifyPair.accountProxyId]; @@ -464,32 +488,14 @@ export const combineAccounts = (pairs: SubjectInfo, modifyPairs: ModifyPairStore chainTypes = [account.chainType]; tokenTypes = account.tokenTypes; + accountType = convertAccountProxyType(account.signMode); accountActions = account.accountActions; switch (account.signMode) { case AccountSignMode.GENERIC_LEDGER: case AccountSignMode.LEGACY_LEDGER: - accountType = AccountProxyType.LEDGER; specialChain = account.specialChain; break; - case AccountSignMode.QR: - accountType = AccountProxyType.QR; - break; - case AccountSignMode.READ_ONLY: - accountType = AccountProxyType.READ_ONLY; - break; - case AccountSignMode.INJECTED: - accountType = AccountProxyType.INJECTED; - break; - case AccountSignMode.PASSWORD: - accountType = AccountProxyType.SOLO; - break; - case AccountSignMode.ALL_ACCOUNT: - accountType = AccountProxyType.ALL_ACCOUNT; - break; - case AccountSignMode.UNKNOWN: - accountType = AccountProxyType.UNKNOWN; - break; } } @@ -532,6 +538,18 @@ export const combineAccounts = (pairs: SubjectInfo, modifyPairs: ModifyPairStore return result; }; +export const combineAccountsWithSubjectInfo = (pairs: SubjectInfo, modifyPairs: ModifyPairStoreData, accountProxies: AccountProxyStoreData, chainInfoMap?: Record) => { + const accounts = Object.values(pairs).map((data) => singleAddressToAccount(data, chainInfoMap)); + + return _combineAccounts(accounts, modifyPairs, accountProxies); +}; + +export const combineAccountsWithKeyPair = (pairs: KeyringPair[], modifyPairs?: ModifyPairStoreData, accountProxies?: AccountProxyStoreData, chainInfoMap?: Record) => { + const accounts = Object.values(pairs).map((data) => pairToAccount(data, chainInfoMap)); + + return _combineAccounts(accounts, modifyPairs || {}, accountProxies || {}); +}; + export const combineAllAccountProxy = (accountProxies: AccountProxy[]): AccountProxy => { const chainTypes = new Set(); const tokenTypes = new Set<_AssetType>(); diff --git a/packages/extension-koni-ui/src/Popup/Account/RestoreJson.tsx b/packages/extension-koni-ui/src/Popup/Account/RestoreJson.tsx index e442f6853f..c97aaa2cbe 100644 --- a/packages/extension-koni-ui/src/Popup/Account/RestoreJson.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/RestoreJson.tsx @@ -1,22 +1,13 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { ResponseJsonGetAccountInfo } from '@subwallet/extension-base/background/types'; -import { Layout, PageWrapper } from '@subwallet/extension-koni-ui/components'; -import AvatarGroup from '@subwallet/extension-koni-ui/components/Account/Info/AvatarGroup'; -import CloseIcon from '@subwallet/extension-koni-ui/components/Icon/CloseIcon'; -import { IMPORT_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants/modal'; -import { useSelector } from '@subwallet/extension-koni-ui/hooks'; -import useCompleteCreateAccount from '@subwallet/extension-koni-ui/hooks/account/useCompleteCreateAccount'; -import useGoBackFromCreateAccount from '@subwallet/extension-koni-ui/hooks/account/useGoBackFromCreateAccount'; -import useTranslation from '@subwallet/extension-koni-ui/hooks/common/useTranslation'; -import useUnlockChecker from '@subwallet/extension-koni-ui/hooks/common/useUnlockChecker'; -import useAutoNavigateToCreatePassword from '@subwallet/extension-koni-ui/hooks/router/useAutoNavigateToCreatePassword'; -import useDefaultNavigate from '@subwallet/extension-koni-ui/hooks/router/useDefaultNavigate'; -import { batchRestoreV2, jsonGetAccountInfo, jsonRestoreV2 } from '@subwallet/extension-koni-ui/messaging'; +import { AccountProxy } from '@subwallet/extension-base/types'; +import { AccountProxyAvatarGroup, CloseIcon, Layout, PageWrapper } from '@subwallet/extension-koni-ui/components'; +import { IMPORT_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants'; +import { useAutoNavigateToCreatePassword, useCompleteCreateAccount, useDefaultNavigate, useGoBackFromCreateAccount, useTranslation, useUnlockChecker } from '@subwallet/extension-koni-ui/hooks'; +import { batchRestoreV2, jsonRestoreV2, parseBatchSingleJson, parseInfoSingleJson } from '@subwallet/extension-koni-ui/messaging'; import { ThemeProps, ValidateState } from '@subwallet/extension-koni-ui/types'; -import { findNetworkJsonByGenesisHash, reformatAddress } from '@subwallet/extension-koni-ui/utils'; -import { isKeyringPairs$Json } from '@subwallet/extension-koni-ui/utils/account/typeGuards'; +import { isKeyringPairs$Json } from '@subwallet/extension-koni-ui/utils'; import { KeyringPair$Json } from '@subwallet/keyring/types'; import { Form, Icon, Input, ModalContext, SettingItem, SwList, SwModal, Upload } from '@subwallet/react-ui'; import { UploadChangeParam, UploadFile } from '@subwallet/react-ui/es/upload/interface'; @@ -28,8 +19,7 @@ import React, { ChangeEventHandler, useCallback, useContext, useEffect, useState import { useNavigate } from 'react-router-dom'; import styled from 'styled-components'; -import { hexToU8a, isHex, u8aToHex, u8aToString } from '@polkadot/util'; -import { ethereumEncode, keccakAsU8a, secp256k1Expand } from '@polkadot/util-crypto'; +import { u8aToString } from '@polkadot/util'; type Props = ThemeProps; @@ -74,7 +64,6 @@ const Component: React.FC = ({ className }: Props) => { const onBack = useGoBackFromCreateAccount(IMPORT_ACCOUNT_MODAL); const { goHome } = useDefaultNavigate(); const { activeModal, inactiveModal } = useContext(ModalContext); - const chainInfoMap = useSelector((state) => state.chainStore.chainInfoMap); const [form] = Form.useForm(); @@ -85,7 +74,7 @@ const Component: React.FC = ({ className }: Props) => { const [requirePassword, setRequirePassword] = useState(false); const [password, setPassword] = useState(''); const [jsonFile, setJsonFile] = useState(undefined); - const [accountsInfo, setAccountsInfo] = useState([]); + const [accountsInfo, setAccountsInfo] = useState([]); const checkUnlock = useUnlockChecker(); const closeModal = useCallback(() => { @@ -137,50 +126,34 @@ const Component: React.FC = ({ className }: Props) => { setSubmitValidateState({}); if (isKeyringPairs$Json(json)) { - const accounts: ResponseJsonGetAccountInfo[] = json.accounts.map((account) => { - const genesisHash: string = account.meta.genesisHash as string; - - let addressPrefix: number | undefined; - - if (account.meta.genesisHash) { - addressPrefix = findNetworkJsonByGenesisHash(chainInfoMap, genesisHash)?.substrateInfo?.addressPrefix; - } - - let address = account.address; - - if (addressPrefix !== undefined) { - address = reformatAddress(account.address, addressPrefix); - } - - if (isHex(account.address) && hexToU8a(account.address).length !== 20) { - address = ethereumEncode(keccakAsU8a(secp256k1Expand(hexToU8a(account.address)))); - } - - return { - address: address, - genesisHash: account.meta.genesisHash, - name: account.meta.name - } as ResponseJsonGetAccountInfo; - }); - - setRequirePassword(true); - setAccountsInfo(accounts); - setFileValidateState({}); - setValidating(false); - } else { - jsonGetAccountInfo(json) - .then((accountInfo) => { - let address = accountInfo.address; - - if (isHex(accountInfo.address) && hexToU8a(accountInfo.address).length !== 20) { - address = u8aToHex(keccakAsU8a(secp256k1Expand(hexToU8a(accountInfo.address)))); - } - - accountInfo.address = address; + parseBatchSingleJson({ + json, + password: '123123123' + }) + .then(({ accountProxies }) => { setRequirePassword(true); - setAccountsInfo([accountInfo]); + setAccountsInfo(accountProxies); setFileValidateState({}); + }) + .catch((e: Error) => { + setRequirePassword(false); + setFileValidateState({ + status: 'error', + message: e.message + }); + }) + .finally(() => { setValidating(false); + }); + } else { + parseInfoSingleJson({ + json, + password: '123123123' + }) + .then(({ accountProxy }) => { + setRequirePassword(true); + setAccountsInfo([accountProxy]); + setFileValidateState({}); }) .catch((e: Error) => { setRequirePassword(false); @@ -188,6 +161,8 @@ const Component: React.FC = ({ className }: Props) => { status: 'error', message: e.message }); + }) + .finally(() => { setValidating(false); }); } @@ -207,7 +182,7 @@ const Component: React.FC = ({ className }: Props) => { }); setValidating(false); }); - }, [validating, jsonFile, chainInfoMap, t]); + }, [validating, jsonFile, t]); const onSubmit = useCallback(() => { if (!jsonFile) { @@ -225,11 +200,16 @@ const Component: React.FC = ({ className }: Props) => { const isMultiple = isKeyringPairs$Json(jsonFile); (isMultiple - ? batchRestoreV2(jsonFile, password, accountsInfo, true) + ? batchRestoreV2({ + file: jsonFile, + password, + isAllowed: true, + proxyIds: undefined + }) : jsonRestoreV2({ file: jsonFile, password: password, - address: accountsInfo[0].address, + address: accountsInfo[0].id, isAllowed: true, withMasterPassword: true })) @@ -258,16 +238,16 @@ const Component: React.FC = ({ className }: Props) => { }); }, [jsonFile, requirePassword, password, checkUnlock, accountsInfo, navigate, onComplete]); - const renderItem = useCallback((account: ResponseJsonGetAccountInfo): React.ReactNode => { + const renderItem = useCallback((account: AccountProxy): React.ReactNode => { return ( ); }, []); @@ -343,7 +323,7 @@ const Component: React.FC = ({ className }: Props) => { ? ( } + leftItemIcon={} name={t('Import {{number}} accounts', { replace: { number: String(accountsInfo.length).padStart(2, '0') } })} onPressItem={openModal} rightItem={( @@ -357,7 +337,7 @@ const Component: React.FC = ({ className }: Props) => { : ( } + leftItemIcon={} name={accountsInfo[0].name} /> ) diff --git a/packages/extension-koni-ui/src/Popup/Debugger/DebuggerAPI.tsx b/packages/extension-koni-ui/src/Popup/Debugger/DebuggerAPI.tsx index 286eb1d0c5..021eadf168 100644 --- a/packages/extension-koni-ui/src/Popup/Debugger/DebuggerAPI.tsx +++ b/packages/extension-koni-ui/src/Popup/Debugger/DebuggerAPI.tsx @@ -83,7 +83,7 @@ const API_LIST = [ // 'pri(derivation.create)', // 'pri(derivation.createV2)', // 'pri(window.open)', - // 'pri(json.account.info)', + // 'pri(accounts.json.info)', // 'pri(json.restore)', // 'pri(json.batchRestore)', // 'pri(accounts.json.restoreV2)', diff --git a/packages/extension-koni-ui/src/components/Modal/Account/AccountExportPasswordModal.tsx b/packages/extension-koni-ui/src/components/Modal/Account/AccountExportPasswordModal.tsx index ef6c9dd298..3d9aa39db5 100644 --- a/packages/extension-koni-ui/src/components/Modal/Account/AccountExportPasswordModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/Account/AccountExportPasswordModal.tsx @@ -73,7 +73,7 @@ function Component ({ addresses, className = '' }: Props): React.ReactElement { exportAccountsV2({ password: values[FormFieldName.PASSWORD], - addresses: addresses + proxyIds: addresses }) .then((data) => { closeModal(); diff --git a/packages/extension-koni-ui/src/messaging/accounts/export.ts b/packages/extension-koni-ui/src/messaging/accounts/export.ts index d1fcfdc667..36ee9a984f 100644 --- a/packages/extension-koni-ui/src/messaging/accounts/export.ts +++ b/packages/extension-koni-ui/src/messaging/accounts/export.ts @@ -1,7 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { RequestAccountBatchExportV2, ResponseAccountExportPrivateKey } from '@subwallet/extension-base/background/KoniTypes'; +import { ResponseAccountExportPrivateKey } from '@subwallet/extension-base/background/KoniTypes'; +import { RequestAccountBatchExportV2 } from '@subwallet/extension-base/types'; import { sendMessage } from '@subwallet/extension-koni-ui/messaging'; import { KeyringPair$Json } from '@subwallet/keyring/types'; import { KeyringPairs$Json } from '@subwallet/ui-keyring/types'; diff --git a/packages/extension-koni-ui/src/messaging/accounts/json.ts b/packages/extension-koni-ui/src/messaging/accounts/json.ts index fdbb929648..e50ed7d4d4 100644 --- a/packages/extension-koni-ui/src/messaging/accounts/json.ts +++ b/packages/extension-koni-ui/src/messaging/accounts/json.ts @@ -1,21 +1,22 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { RequestJsonRestoreV2 } from '@subwallet/extension-base/background/KoniTypes'; -import { ResponseJsonGetAccountInfo } from '@subwallet/extension-base/background/types'; -import { KeyringPair$Json } from '@subwallet/keyring/types'; -import { KeyringPairs$Json } from '@subwallet/ui-keyring/types'; +import { RequestBatchJsonGetAccountInfo, RequestBatchRestoreV2, RequestJsonGetAccountInfo, RequestJsonRestoreV2, ResponseBatchJsonGetAccountInfo, ResponseJsonGetAccountInfo } from '@subwallet/extension-base/types'; import { sendMessage } from '../base'; -export async function jsonGetAccountInfo (json: KeyringPair$Json): Promise { - return sendMessage('pri(json.account.info)', json); +export async function parseInfoSingleJson (request: RequestJsonGetAccountInfo): Promise { + return sendMessage('pri(accounts.json.info)', request); } export async function jsonRestoreV2 (request: RequestJsonRestoreV2): Promise { return sendMessage('pri(accounts.json.restoreV2)', request); } -export async function batchRestoreV2 (file: KeyringPairs$Json, password: string, accountsInfo: ResponseJsonGetAccountInfo[], isAllowed: boolean): Promise { - return sendMessage('pri(accounts.json.batchRestoreV2)', { file, password, accountsInfo, isAllowed }); +export async function parseBatchSingleJson (request: RequestBatchJsonGetAccountInfo): Promise { + return sendMessage('pri(accounts.json.batchInfo)', request); +} + +export async function batchRestoreV2 (request: RequestBatchRestoreV2): Promise { + return sendMessage('pri(accounts.json.batchRestoreV2)', request); } diff --git a/packages/extension-web-ui/src/Popup/Account/RestoreJson.tsx b/packages/extension-web-ui/src/Popup/Account/RestoreJson.tsx index 075dd327b9..454dead6b8 100644 --- a/packages/extension-web-ui/src/Popup/Account/RestoreJson.tsx +++ b/packages/extension-web-ui/src/Popup/Account/RestoreJson.tsx @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { ResponseJsonGetAccountInfo } from '@subwallet/extension-base/background/types'; +import { ResponseJsonGetAccountInfo } from '@subwallet/extension-base/types'; import { Layout, PageWrapper } from '@subwallet/extension-web-ui/components'; import AvatarGroup from '@subwallet/extension-web-ui/components/Account/Info/AvatarGroup'; import CloseIcon from '@subwallet/extension-web-ui/components/Icon/CloseIcon'; diff --git a/packages/extension-web-ui/src/Popup/Debugger/DebuggerAPI.tsx b/packages/extension-web-ui/src/Popup/Debugger/DebuggerAPI.tsx index 8220786035..f66447538a 100644 --- a/packages/extension-web-ui/src/Popup/Debugger/DebuggerAPI.tsx +++ b/packages/extension-web-ui/src/Popup/Debugger/DebuggerAPI.tsx @@ -84,7 +84,7 @@ const API_LIST = [ // 'pri(derivation.create)', // 'pri(derivation.createV2)', // 'pri(window.open)', - // 'pri(json.account.info)', + // 'pri(accounts.json.info)', // 'pri(json.restore)', // 'pri(json.batchRestore)', // 'pri(accounts.json.restoreV2)', diff --git a/packages/extension-web-ui/src/components/Modal/Account/AccountExportPasswordModal.tsx b/packages/extension-web-ui/src/components/Modal/Account/AccountExportPasswordModal.tsx index 844b226fe2..51edec3e4a 100644 --- a/packages/extension-web-ui/src/components/Modal/Account/AccountExportPasswordModal.tsx +++ b/packages/extension-web-ui/src/components/Modal/Account/AccountExportPasswordModal.tsx @@ -77,7 +77,7 @@ function Component ({ addresses, className = '' }: Props): React.ReactElement { exportAccountsV2({ password: values[FormFieldName.PASSWORD], - addresses: addresses + proxyIds: addresses }) .then((data) => { closeModal(); diff --git a/packages/extension-web-ui/src/messaging/accounts/export.ts b/packages/extension-web-ui/src/messaging/accounts/export.ts index 35af01e0fa..bde72bf2aa 100644 --- a/packages/extension-web-ui/src/messaging/accounts/export.ts +++ b/packages/extension-web-ui/src/messaging/accounts/export.ts @@ -1,7 +1,8 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { RequestAccountBatchExportV2, ResponseAccountExportPrivateKey } from '@subwallet/extension-base/background/KoniTypes'; +import { ResponseAccountExportPrivateKey } from '@subwallet/extension-base/background/KoniTypes'; +import { RequestAccountBatchExportV2 } from '@subwallet/extension-base/types'; import { sendMessage } from '@subwallet/extension-web-ui/messaging'; import { KeyringPair$Json } from '@subwallet/keyring/types'; import { KeyringPairs$Json } from '@subwallet/ui-keyring/types'; diff --git a/packages/extension-web-ui/src/messaging/accounts/json.ts b/packages/extension-web-ui/src/messaging/accounts/json.ts index 8ba8f2c193..1e11c64c78 100644 --- a/packages/extension-web-ui/src/messaging/accounts/json.ts +++ b/packages/extension-web-ui/src/messaging/accounts/json.ts @@ -1,15 +1,14 @@ // Copyright 2019-2022 @subwallet/extension-web-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { RequestJsonRestoreV2 } from '@subwallet/extension-base/background/KoniTypes'; -import { ResponseJsonGetAccountInfo } from '@subwallet/extension-base/background/types'; +import { RequestJsonRestoreV2, ResponseJsonGetAccountInfo } from '@subwallet/extension-base/types'; import { KeyringPair$Json } from '@subwallet/keyring/types'; import { KeyringPairs$Json } from '@subwallet/ui-keyring/types'; import { sendMessage } from '../base'; export async function jsonGetAccountInfo (json: KeyringPair$Json): Promise { - return sendMessage('pri(json.account.info)', json); + return sendMessage('pri(accounts.json.info)', json); } export async function jsonRestoreV2 (request: RequestJsonRestoreV2): Promise { diff --git a/yarn.lock b/yarn.lock index b4fe7da225..1db0b38e49 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6451,7 +6451,7 @@ __metadata: "@subwallet/keyring@file:../SubWallet-Base/packages/keyring/build/::locator=root-workspace-0b6124%40workspace%3A.": version: 0.1.5 - resolution: "@subwallet/keyring@file:../SubWallet-Base/packages/keyring/build/#../SubWallet-Base/packages/keyring/build/::hash=9b4004&locator=root-workspace-0b6124%40workspace%3A." + resolution: "@subwallet/keyring@file:../SubWallet-Base/packages/keyring/build/#../SubWallet-Base/packages/keyring/build/::hash=c6202a&locator=root-workspace-0b6124%40workspace%3A." dependencies: "@ethereumjs/tx": ^5.0.0 "@polkadot/util": ^12.2.1 @@ -6470,7 +6470,7 @@ __metadata: rxjs: ^7.5.6 tiny-secp256k1: ^2.2.3 tslib: ^2.6.2 - checksum: d67582b3b2f32125488f3f4a59635a581d5b18ae53e10c3cf253539ec5e6a3e9a434604faa48f69003ef832b4c4eecc86376960c2e4b7900fc235907382cbee6 + checksum: 47216f7e390d267da5ab6bda3cc7e5097ba9585c9c4b24eda7729d3461b092e9cea3aca087c6c24cf463be959b20d4c540a33ce86ea485ea5d3fb4a595a04b17 languageName: node linkType: hard @@ -6554,7 +6554,7 @@ __metadata: "@subwallet/ui-keyring@file:../SubWallet-Base/packages/ui-keyring/build/::locator=root-workspace-0b6124%40workspace%3A.": version: 0.1.5 - resolution: "@subwallet/ui-keyring@file:../SubWallet-Base/packages/ui-keyring/build/#../SubWallet-Base/packages/ui-keyring/build/::hash=9447e0&locator=root-workspace-0b6124%40workspace%3A." + resolution: "@subwallet/ui-keyring@file:../SubWallet-Base/packages/ui-keyring/build/#../SubWallet-Base/packages/ui-keyring/build/::hash=8162e9&locator=root-workspace-0b6124%40workspace%3A." dependencies: "@babel/runtime": ^7.20.1 "@polkadot/ui-settings": 2.9.14 @@ -6564,7 +6564,7 @@ __metadata: mkdirp: ^1.0.4 rxjs: ^7.5.7 store: ^2.0.12 - checksum: ee4c18439aefa5826f17c507a95014b641354972283de661b583c990d0935ea05ab3ebd7384d8bf398eaacd84a88ffa5d21871cf4d0bbc4f2af53e2b2fdf681b + checksum: 555c015e51c25d5cc18805ea6bd3293b2c02d11181128020d6f2525d4f9ffbbd172fd94e216eb9a1b7a367bfa8941f0a6c78cde80247ead3c3550a84490c4826 languageName: node linkType: hard From 0f50b5820f5cf45043ae10fe14dbd6399c392dd2 Mon Sep 17 00:00:00 2001 From: lw Date: Fri, 23 Aug 2024 11:17:47 +0700 Subject: [PATCH 144/424] [Issue-3496] Update logic for buy token screen --- .../extension-koni-ui/src/Popup/BuyTokens.tsx | 278 ++++++++++-------- .../src/Popup/Home/Tokens/DetailList.tsx | 33 +-- .../src/Popup/Home/Tokens/UpperBlock.tsx | 3 + .../src/Popup/Home/Tokens/index.tsx | 9 +- 4 files changed, 174 insertions(+), 149 deletions(-) diff --git a/packages/extension-koni-ui/src/Popup/BuyTokens.tsx b/packages/extension-koni-ui/src/Popup/BuyTokens.tsx index ab86bbc13f..0275968de2 100644 --- a/packages/extension-koni-ui/src/Popup/BuyTokens.tsx +++ b/packages/extension-koni-ui/src/Popup/BuyTokens.tsx @@ -2,20 +2,18 @@ // SPDX-License-Identifier: Apache-2.0 import { Resolver } from '@subwallet/extension-base/background/types'; -import { AccountJson } from '@subwallet/extension-base/types'; +import { _getOriginChainOfAsset } from '@subwallet/extension-base/services/chain-service/utils'; +import { AccountProxy, BuyTokenInfo } from '@subwallet/extension-base/types'; import { detectTranslate, isAccountAll } from '@subwallet/extension-base/utils'; -import { baseServiceItems, Layout, PageWrapper, ServiceItem } from '@subwallet/extension-koni-ui/components'; -import { AccountSelector } from '@subwallet/extension-koni-ui/components/Field/AccountSelector'; +import { AccountAddressSelector, baseServiceItems, Layout, PageWrapper, ServiceItem } from '@subwallet/extension-koni-ui/components'; import { ServiceSelector } from '@subwallet/extension-koni-ui/components/Field/BuyTokens/ServiceSelector'; import { TokenItemType, TokenSelector } from '@subwallet/extension-koni-ui/components/Field/TokenSelector'; -import { useAssetChecker, useDefaultNavigate, useNotification, useTranslation } from '@subwallet/extension-koni-ui/hooks'; +import { useAssetChecker, useDefaultNavigate, useGetChainSlugsByAccount, useNotification, useTranslation } from '@subwallet/extension-koni-ui/hooks'; import { RootState } from '@subwallet/extension-koni-ui/stores'; -import { AccountType, BuyServiceInfo, BuyTokenInfo, CreateBuyOrderFunction, SupportService, ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { AccountAddressItemType, BuyServiceInfo, CreateBuyOrderFunction, SupportService, ThemeProps } from '@subwallet/extension-koni-ui/types'; import { BuyTokensParam } from '@subwallet/extension-koni-ui/types/navigation'; -import { createBanxaOrder, createCoinbaseOrder, createTransakOrder, findAccountByAddress, noop, openInNewTab } from '@subwallet/extension-koni-ui/utils'; -import { getAccountType } from '@subwallet/extension-koni-ui/utils/account/account'; +import { createBanxaOrder, createCoinbaseOrder, createTransakOrder, getReformatedAddressRelatedToChain, noop, openInNewTab } from '@subwallet/extension-koni-ui/utils'; import reformatAddress from '@subwallet/extension-koni-ui/utils/account/reformatAddress'; -import { findNetworkJsonByGenesisHash } from '@subwallet/extension-koni-ui/utils/chain/getNetworkJsonByGenesisHash'; import { Button, Form, Icon, ModalContext, SwModal, SwSubHeader } from '@subwallet/react-ui'; import CN from 'classnames'; import { CheckCircle, ShoppingCartSimple, XCircle } from 'phosphor-react'; @@ -25,13 +23,16 @@ import { useSelector } from 'react-redux'; import { useLocation } from 'react-router-dom'; import styled from 'styled-components'; -import { isEthereumAddress } from '@polkadot/util-crypto'; +type WrapperProps = ThemeProps; -type Props = ThemeProps; +type ComponentProps = { + className?: string; + currentAccountProxy: AccountProxy; +}; type BuyTokensFormProps = { address: string; - tokenKey: string; + tokenSlug: string; service: SupportService; } @@ -57,7 +58,7 @@ const LinkUrl: React.FC = (props: LinkUrlProps) => { const modalId = 'disclaimer-modal'; -function Component ({ className }: Props) { +function Component ({ className, currentAccountProxy }: ComponentProps) { const locationState = useLocation().state as BuyTokensParam; const [currentSymbol] = useState(locationState?.symbol); @@ -65,14 +66,16 @@ function Component ({ className }: Props) { const { activeModal, inactiveModal } = useContext(ModalContext); - const { accounts, currentAccount, isAllAccount } = useSelector((state: RootState) => state.accountState); + const accountProxies = useSelector((state: RootState) => state.accountState.accountProxies); + // const isAllAccount = useSelector((state: RootState) => state.accountState.isAllAccount); const { chainInfoMap } = useSelector((state: RootState) => state.chainStore); const { assetRegistry } = useSelector((state: RootState) => state.assetRegistry); const { walletReference } = useSelector((state: RootState) => state.settings); const { services, tokens } = useSelector((state: RootState) => state.buyService); const checkAsset = useAssetChecker(); + const allowedChains = useGetChainSlugsByAccount(); - const fixedTokenKey = useMemo((): string | undefined => { + const fixedTokenSlug = useMemo((): string | undefined => { if (currentSymbol) { return Object.values(tokens).filter((value) => value.slug === currentSymbol || value.symbol === currentSymbol)[0]?.slug; } else { @@ -80,15 +83,14 @@ function Component ({ className }: Props) { } }, [currentSymbol, tokens]); - const [currentAddress] = useState(currentAccount?.address); const { t } = useTranslation(); const { goBack } = useDefaultNavigate(); const [form] = Form.useForm(); const formDefault = useMemo((): BuyTokensFormProps => ({ - address: isAllAccount ? '' : (currentAccount?.address || ''), - tokenKey: fixedTokenKey || '', + address: '', + tokenSlug: fixedTokenSlug || '', service: '' as SupportService - }), [currentAccount?.address, fixedTokenKey, isAllAccount]); + }), [fixedTokenSlug]); const promiseRef = useRef>({ resolve: noop, reject: noop }); @@ -102,7 +104,7 @@ function Component ({ className }: Props) { }); const selectedAddress = Form.useWatch('address', form); - const selectedTokenKey = Form.useWatch('tokenKey', form); + const selectedTokenSlug = Form.useWatch('tokenSlug', form); const selectedService = Form.useWatch('service', form); const { contactUrl, name: serviceName, policyUrl, termUrl, url } = useMemo((): BuyServiceInfo => { @@ -150,24 +152,9 @@ function Component ({ className }: Props) { promiseRef.current.reject(new Error('User reject')); }, []); - const accountType = selectedAddress ? getAccountType(selectedAddress) : ''; - const ledgerNetwork = useMemo((): string | undefined => { - const account = findAccountByAddress(accounts, selectedAddress); - - if (account?.genesisHash) { - return findNetworkJsonByGenesisHash(chainInfoMap, account.genesisHash)?.slug; - } - - return undefined; - }, [accounts, chainInfoMap, selectedAddress]); - const tokenItems = useMemo(() => { const result: TokenItemType[] = []; - const list = [...Object.values(tokens)]; - - const filtered = currentSymbol ? list.filter((value) => value.slug === currentSymbol || value.symbol === currentSymbol) : list; - const convertToItem = (info: BuyTokenInfo): TokenItemType => { return { name: assetRegistry[info.slug]?.name || info.symbol, @@ -177,44 +164,82 @@ function Component ({ className }: Props) { }; }; - filtered.forEach((info) => { - const item = convertToItem(info); + Object.values(tokens).forEach((item) => { + if (!allowedChains.includes(item.network)) { + return; + } - if (ledgerNetwork) { - if (info.network === ledgerNetwork) { - result.push(item); - } - } else { - if (accountType === 'ALL' || accountType === info.support) { - result.push(item); - } + if (!currentSymbol || (item.slug === currentSymbol || item.symbol === currentSymbol)) { + result.push(convertToItem(item)); } }); return result; - }, [accountType, assetRegistry, currentSymbol, ledgerNetwork, tokens]); + }, [allowedChains, assetRegistry, currentSymbol, tokens]); - const serviceItems = useMemo(() => getServiceItems(selectedTokenKey), [getServiceItems, selectedTokenKey]); + const serviceItems = useMemo(() => getServiceItems(selectedTokenSlug), [getServiceItems, selectedTokenSlug]); + + const accountAddressItems = useMemo(() => { + const chainSlug = selectedTokenSlug ? _getOriginChainOfAsset(selectedTokenSlug) : undefined; + const chainInfo = chainSlug ? chainInfoMap[chainSlug] : undefined; + + if (!chainInfo) { + return []; + } + + const result: AccountAddressItemType[] = []; + + const updateResult = (ap: AccountProxy) => { + ap.accounts.forEach((a) => { + const address = getReformatedAddressRelatedToChain(a, chainInfo); + + if (address) { + result.push({ + accountName: ap.name, + accountProxyId: ap.id, + accountProxyType: ap.accountType, + accountType: a.type, + address + }); + } + }); + }; + + if (isAccountAll(currentAccountProxy.id)) { + accountProxies.forEach((ap) => { + if (isAccountAll(ap.id)) { + return; + } + + updateResult(ap); + }); + } else { + updateResult(currentAccountProxy); + } + + return result; + }, [accountProxies, chainInfoMap, currentAccountProxy, selectedTokenSlug]); const isSupportBuyTokens = useMemo(() => { - if (selectedService && selectedAddress && selectedTokenKey) { - const buyInfo = tokens[selectedTokenKey]; - const accountType = getAccountType(selectedAddress); + if (selectedService && selectedTokenSlug) { + const buyInfo = tokens[selectedTokenSlug]; - return buyInfo && buyInfo.support === accountType && buyInfo.services.includes(selectedService) && tokenItems.find((item) => item.slug === selectedTokenKey); + return buyInfo && + buyInfo.services.includes(selectedService) && + tokenItems.find((item) => item.slug === selectedTokenSlug); } return false; - }, [selectedService, selectedAddress, selectedTokenKey, tokens, tokenItems]); + }, [selectedService, selectedTokenSlug, tokens, tokenItems]); const onClickNext = useCallback(() => { setLoading(true); - const { address, service, tokenKey } = form.getFieldsValue(); + const { address, service, tokenSlug } = form.getFieldsValue(); let urlPromise: CreateBuyOrderFunction | undefined; - const buyInfo = tokens[tokenKey]; + const buyInfo = tokens[tokenSlug]; const { network } = buyInfo; const serviceInfo = buyInfo.serviceInfo[service]; @@ -274,79 +299,53 @@ function Component ({ className }: Props) { } }, [form, tokens, chainInfoMap, disclaimerAgree, onConfirm, walletReference, notify, t]); - const filterAccountType = useMemo((): AccountType => { - if (currentSymbol) { - let result: AccountType = '' as AccountType; + useEffect(() => { + if (!fixedTokenSlug && tokenItems.length) { + const { tokenSlug } = form.getFieldsValue(); - const list = Object.values(tokens).filter((value) => value.slug === currentSymbol || value.symbol === currentSymbol); + if (!tokenSlug) { + form.setFieldsValue({ tokenSlug: tokenItems[0].slug }); + } else { + const isSelectedTokenInList = tokenItems.some((i) => i.slug === tokenSlug); - list.forEach((info) => { - if (result) { - if (result !== info.support) { - if (result === 'SUBSTRATE' || result === 'ETHEREUM') { - result = 'ALL'; - } - } - } else { - result = info.support; + if (!isSelectedTokenInList) { + form.setFieldsValue({ tokenSlug: tokenItems[0].slug }); } - }); - - return result; - } else { - return 'ALL'; - } - }, [currentSymbol, tokens]); - - const accountsFilter = useCallback((account: AccountJson) => { - if (isAccountAll(account.address)) { - return false; - } - - if (filterAccountType !== 'ALL') { - if (filterAccountType === 'ETHEREUM') { - return isEthereumAddress(account.address); - } else { - return !isEthereumAddress(account.address); } + } else if (fixedTokenSlug) { + setTimeout(() => { + form.setFieldsValue({ tokenSlug: fixedTokenSlug }); + }, 100); } - - return true; - }, [filterAccountType]); + }, [tokenItems, fixedTokenSlug, form]); useEffect(() => { - if (currentAddress !== currentAccount?.address) { - goBack(); - } - }, [currentAccount?.address, currentAddress, goBack]); + selectedTokenSlug && checkAsset(selectedTokenSlug); + }, [checkAsset, selectedTokenSlug]); useEffect(() => { - if (!fixedTokenKey && tokenItems.length) { - const { tokenKey } = form.getFieldsValue(); + const updateFromValue = () => { + if (!accountAddressItems.length) { + return; + } - if (!tokenKey) { - form.setFieldsValue({ tokenKey: tokenItems[0].slug }); + if (accountAddressItems.length === 1) { + if (!selectedAddress || accountAddressItems[0].address !== selectedAddress) { + form.setFieldValue('address', accountAddressItems[0].address); + } } else { - const isSelectedTokenInList = tokenItems.some((i) => i.slug === tokenKey); - - if (!isSelectedTokenInList) { - form.setFieldsValue({ tokenKey: tokenItems[0].slug }); + if (selectedAddress && !accountAddressItems.some((i) => i.address === selectedAddress)) { + form.setFieldValue('address', ''); } } - } else if (fixedTokenKey) { - setTimeout(() => { - form.setFieldsValue({ tokenKey: fixedTokenKey }); - }, 100); - } - }, [tokenItems, fixedTokenKey, form]); + }; - useEffect(() => { - selectedTokenKey && checkAsset(selectedTokenKey); - }, [checkAsset, selectedTokenKey]); + updateFromValue(); + }, [accountAddressItems, form, selectedAddress]); useEffect(() => { - if (selectedTokenKey) { - const services = getServiceItems(selectedTokenKey); + if (selectedTokenSlug) { + const services = getServiceItems(selectedTokenSlug); const filtered = services.filter((service) => !service.disabled); if (filtered.length > 1) { @@ -355,7 +354,7 @@ function Component ({ className }: Props) { form.setFieldValue('service', filtered[0]?.key || ''); } } - }, [selectedTokenKey, form, getServiceItems]); + }, [selectedTokenSlug, form, getServiceItems]); return ( - - - -
- +
+ + + +
@@ -512,7 +511,32 @@ function Component ({ className }: Props) { ); } -const BuyTokens = styled(Component)(({ theme: { token } }: Props) => { +const Wrapper: React.FC = (props: WrapperProps) => { + const { className } = props; + const { goHome } = useDefaultNavigate(); + const currentAccountProxy = useSelector((state: RootState) => state.accountState.currentAccountProxy); + + useEffect(() => { + if (!currentAccountProxy) { + goHome(); + } + }, [goHome, currentAccountProxy]); + + if (!currentAccountProxy) { + return ( + <> + ); + } + + return ( + + ); +}; + +const BuyTokens = styled(Wrapper)(({ theme: { token } }: WrapperProps) => { return ({ display: 'flex', flexDirection: 'column', diff --git a/packages/extension-koni-ui/src/Popup/Home/Tokens/DetailList.tsx b/packages/extension-koni-ui/src/Popup/Home/Tokens/DetailList.tsx index b87a691b48..d30e36ae90 100644 --- a/packages/extension-koni-ui/src/Popup/Home/Tokens/DetailList.tsx +++ b/packages/extension-koni-ui/src/Popup/Home/Tokens/DetailList.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; -import { AccountProxyType } from '@subwallet/extension-base/types'; +import { AccountProxyType, BuyTokenInfo } from '@subwallet/extension-base/types'; import { ReceiveModal } from '@subwallet/extension-koni-ui/components'; import PageWrapper from '@subwallet/extension-koni-ui/components/Layout/PageWrapper'; import BannerGenerator from '@subwallet/extension-koni-ui/components/StaticContent/BannerGenerator'; @@ -10,13 +10,13 @@ import { TokenBalanceDetailItem } from '@subwallet/extension-koni-ui/components/ import { DEFAULT_SWAP_PARAMS, DEFAULT_TRANSFER_PARAMS, SWAP_TRANSACTION, TRANSFER_TRANSACTION } from '@subwallet/extension-koni-ui/constants'; import { DataContext } from '@subwallet/extension-koni-ui/contexts/DataContext'; import { HomeContext } from '@subwallet/extension-koni-ui/contexts/screen/HomeContext'; -import { useCoreReceiveModalHelper, useDefaultNavigate, useGetBannerByScreen, useNavigateOnChangeAccount, useNotification, useSelector } from '@subwallet/extension-koni-ui/hooks'; +import { useCoreReceiveModalHelper, useDefaultNavigate, useGetBannerByScreen, useGetChainSlugsByAccount, useNavigateOnChangeAccount, useNotification, useSelector } from '@subwallet/extension-koni-ui/hooks'; import { DetailModal } from '@subwallet/extension-koni-ui/Popup/Home/Tokens/DetailModal'; import { DetailUpperBlock } from '@subwallet/extension-koni-ui/Popup/Home/Tokens/DetailUpperBlock'; import { RootState } from '@subwallet/extension-koni-ui/stores'; -import { BuyTokenInfo, ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { ThemeProps } from '@subwallet/extension-koni-ui/types'; import { TokenBalanceItemType } from '@subwallet/extension-koni-ui/types/balance'; -import { getAccountType, getTransactionFromAccountProxyValue, isAccountAll, sortTokenByValue } from '@subwallet/extension-koni-ui/utils'; +import { getTransactionFromAccountProxyValue, isAccountAll, sortTokenByValue } from '@subwallet/extension-koni-ui/utils'; import { ModalContext } from '@subwallet/react-ui'; import { SwNumberProps } from '@subwallet/react-ui/es/number'; import classNames from 'classnames'; @@ -73,6 +73,7 @@ function Component (): React.ReactElement { const [, setStorage] = useLocalStorage(TRANSFER_TRANSACTION, DEFAULT_TRANSFER_PARAMS); const [, setSwapStorage] = useLocalStorage(SWAP_TRANSACTION, DEFAULT_SWAP_PARAMS); const { banners, dismissBanner, onClickBanner } = useGetBannerByScreen('token_detail', tokenGroupSlug); + const allowedChains = useGetChainSlugsByAccount(); const fromAndToTokenMap = useMemo>(() => { const result: Record = {}; @@ -143,26 +144,16 @@ function Component (): React.ReactElement { const slugs = tokenGroupMap[slug] ? tokenGroupMap[slug] : [slug]; const result: BuyTokenInfo[] = []; - for (const [slug, buyInfo] of Object.entries(tokens)) { - if (slugs.includes(slug)) { - const supportType = buyInfo.support; - - if (isAccountAll(currentAccount?.address || '')) { - const support = accounts.some((account) => supportType === getAccountType(account.address)); - - if (support) { - result.push(buyInfo); - } - } else { - if (currentAccount?.address && (supportType === getAccountType(currentAccount?.address))) { - result.push(buyInfo); - } - } + Object.values(tokens).forEach((item) => { + if (!allowedChains.includes(item.network) || !slugs.includes(slug)) { + return; } - } + + result.push(item); + }); return result; - }, [accounts, currentAccount?.address, tokenGroupMap, tokenGroupSlug, tokens]); + }, [allowedChains, tokenGroupMap, tokenGroupSlug, tokens]); const tokenBalanceValue = useMemo(() => { if (tokenGroupSlug) { diff --git a/packages/extension-koni-ui/src/Popup/Home/Tokens/UpperBlock.tsx b/packages/extension-koni-ui/src/Popup/Home/Tokens/UpperBlock.tsx index 8171cc3b21..6f48c12e1b 100644 --- a/packages/extension-koni-ui/src/Popup/Home/Tokens/UpperBlock.tsx +++ b/packages/extension-koni-ui/src/Popup/Home/Tokens/UpperBlock.tsx @@ -17,6 +17,7 @@ type Props = ThemeProps & { totalChangePercent: SwNumberProps['value']; isPriceDecrease: boolean; isShrink: boolean; + isSupportBuyTokens: boolean; onOpenSendFund: () => void; onOpenBuyTokens: () => void; onOpenReceive: () => void; @@ -27,6 +28,7 @@ function Component ( { className = '', isPriceDecrease, isShrink, + isSupportBuyTokens, onOpenBuyTokens, onOpenReceive, onOpenSendFund, @@ -177,6 +179,7 @@ function Component (