diff --git a/.env.example b/.env.example
index ab9f2dad4b6..61e7fadaffe 100644
--- a/.env.example
+++ b/.env.example
@@ -14,3 +14,4 @@ BITTENSOR_API_KEY_8=tao-abafdbad8
 BITTENSOR_API_KEY_9=tao-abafdbad9
 BITTENSOR_API_KEY_10=tao-abafdbad10
 SIMPLE_SWAP_API_KEY=26c8c21
+SUBWALLET_API=localhost
diff --git a/.github/workflows/push-koni-dev.yml b/.github/workflows/push-koni-dev.yml
index a537161c924..39731cbe3bf 100644
--- a/.github/workflows/push-koni-dev.yml
+++ b/.github/workflows/push-koni-dev.yml
@@ -47,7 +47,7 @@ jobs:
         TRANSAK_API_KEY: ${{ secrets.TRANSAK_API_KEY }}
         COINBASE_PAY_ID: ${{ secrets.COINBASE_PAY_ID }}
         CHAINFLIP_BROKER_API: ${{ secrets.CHAINFLIP_BROKER_API }}
-        BITTENSOR_API_KEY_1: ${{ secrets.BITTENSOR_API_KEY_1 }} 
+        BITTENSOR_API_KEY_1: ${{ secrets.BITTENSOR_API_KEY_1 }}
         BITTENSOR_API_KEY_2: ${{ secrets.BITTENSOR_API_KEY_2 }}
         BITTENSOR_API_KEY_3: ${{ secrets.BITTENSOR_API_KEY_3 }}
         BITTENSOR_API_KEY_4: ${{ secrets.BITTENSOR_API_KEY_4 }}
@@ -57,6 +57,7 @@ jobs:
         BITTENSOR_API_KEY_8: ${{ secrets.BITTENSOR_API_KEY_8 }}
         BITTENSOR_API_KEY_9: ${{ secrets.BITTENSOR_API_KEY_9 }}
         BITTENSOR_API_KEY_10: ${{ secrets.BITTENSOR_API_KEY_10 }}
+        SUBWALLET_API: ${{ secrets.SUBWALLET_API }}
         SIMPLE_SWAP_API_KEY: ${{ secrets.SIMPLE_SWAP_API_KEY }}
         GH_RELEASE_FILES: master-build.zip,master-src.zip
         COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
diff --git a/.github/workflows/push-master.yml b/.github/workflows/push-master.yml
index fa700048b3a..e057f1e8a0f 100644
--- a/.github/workflows/push-master.yml
+++ b/.github/workflows/push-master.yml
@@ -28,7 +28,7 @@ jobs:
         TRANSAK_API_KEY: ${{ secrets.TRANSAK_API_KEY }}
         COINBASE_PAY_ID: ${{ secrets.COINBASE_PAY_ID }}
         CHAINFLIP_BROKER_API: ${{ secrets.CHAINFLIP_BROKER_API }}
-        BITTENSOR_API_KEY_1: ${{ secrets.BITTENSOR_API_KEY_1 }} 
+        BITTENSOR_API_KEY_1: ${{ secrets.BITTENSOR_API_KEY_1 }}
         BITTENSOR_API_KEY_2: ${{ secrets.BITTENSOR_API_KEY_2 }}
         BITTENSOR_API_KEY_3: ${{ secrets.BITTENSOR_API_KEY_3 }}
         BITTENSOR_API_KEY_4: ${{ secrets.BITTENSOR_API_KEY_4 }}
@@ -39,6 +39,7 @@ jobs:
         BITTENSOR_API_KEY_9: ${{ secrets.BITTENSOR_API_KEY_9 }}
         BITTENSOR_API_KEY_10: ${{ secrets.BITTENSOR_API_KEY_10 }}
         SIMPLE_SWAP_API_KEY: ${{ secrets.SIMPLE_SWAP_API_KEY }}
+        SUBWALLET_API: ${{ secrets.SUBWALLET_API }}
         BRANCH_NAME: ${{ github.ref_name }}
       run: |
         yarn install --immutable | grep -v 'YN0013'
diff --git a/.github/workflows/push-web-runner.yml b/.github/workflows/push-web-runner.yml
index e27c73f5a49..a617d09f5b4 100644
--- a/.github/workflows/push-web-runner.yml
+++ b/.github/workflows/push-web-runner.yml
@@ -32,7 +32,7 @@ jobs:
         TRANSAK_API_KEY: ${{ secrets.TRANSAK_API_KEY }}
         COINBASE_PAY_ID: ${{ secrets.COINBASE_PAY_ID }}
         CHAINFLIP_BROKER_API: ${{ secrets.CHAINFLIP_BROKER_API }}
-        BITTENSOR_API_KEY_1: ${{ secrets.BITTENSOR_API_KEY_1 }} 
+        BITTENSOR_API_KEY_1: ${{ secrets.BITTENSOR_API_KEY_1 }}
         BITTENSOR_API_KEY_2: ${{ secrets.BITTENSOR_API_KEY_2 }}
         BITTENSOR_API_KEY_3: ${{ secrets.BITTENSOR_API_KEY_3 }}
         BITTENSOR_API_KEY_4: ${{ secrets.BITTENSOR_API_KEY_4 }}
@@ -43,6 +43,7 @@ jobs:
         BITTENSOR_API_KEY_9: ${{ secrets.BITTENSOR_API_KEY_9 }}
         BITTENSOR_API_KEY_10: ${{ secrets.BITTENSOR_API_KEY_10 }}
         SIMPLE_SWAP_API_KEY: ${{ secrets.SIMPLE_SWAP_API_KEY }}
+        SUBWALLET_API: ${{ secrets.SUBWALLET_API }}
         BRANCH_NAME: master
       run: |
         yarn install --immutable | grep -v 'YN0013'
diff --git a/.github/workflows/push-webapp.yml b/.github/workflows/push-webapp.yml
index 28568cf2fc9..0eda76b82e1 100644
--- a/.github/workflows/push-webapp.yml
+++ b/.github/workflows/push-webapp.yml
@@ -32,7 +32,7 @@ jobs:
         COINBASE_PAY_ID: ${{ secrets.COINBASE_PAY_ID }}
         NFT_MINTING_HOST: ${{ secrets.NFT_MINTING_HOST }}
         CHAINFLIP_BROKER_API: ${{ secrets.CHAINFLIP_BROKER_API }}
-        BITTENSOR_API_KEY_1: ${{ secrets.BITTENSOR_API_KEY_1 }} 
+        BITTENSOR_API_KEY_1: ${{ secrets.BITTENSOR_API_KEY_1 }}
         BITTENSOR_API_KEY_2: ${{ secrets.BITTENSOR_API_KEY_2 }}
         BITTENSOR_API_KEY_3: ${{ secrets.BITTENSOR_API_KEY_3 }}
         BITTENSOR_API_KEY_4: ${{ secrets.BITTENSOR_API_KEY_4 }}
@@ -43,6 +43,7 @@ jobs:
         BITTENSOR_API_KEY_9: ${{ secrets.BITTENSOR_API_KEY_9 }}
         BITTENSOR_API_KEY_10: ${{ secrets.BITTENSOR_API_KEY_10 }}
         SIMPLE_SWAP_API_KEY: ${{ secrets.SIMPLE_SWAP_API_KEY }}
+        SUBWALLET_API: ${{ secrets.SUBWALLET_API }}
         BRANCH_NAME: ${{ github.ref_name }}
       run: |
         yarn install --immutable | grep -v 'YN0013'
diff --git a/package.json b/package.json
index f2a4b6cf4c0..ab231b27817 100644
--- a/package.json
+++ b/package.json
@@ -105,10 +105,10 @@
     "@polkadot/types-support": "^15.0.1",
     "@polkadot/util": "^13.2.3",
     "@polkadot/util-crypto": "^13.2.3",
-    "@subwallet/chain-list": "0.2.98",
-    "@subwallet/keyring": "^0.1.8-beta.0",
+    "@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": "0.1.8-beta.0",
+    "@subwallet/ui-keyring": "file:../SubWallet-Base/packages/ui-keyring/build/",
     "@types/bn.js": "^5.1.6",
     "@zondax/ledger-substrate": "1.0.1",
     "babel-core": "^7.0.0-bridge.0",
diff --git a/packages/extension-base/package.json b/packages/extension-base/package.json
index cbdf6bca56b..9a7d54f9ef0 100644
--- a/packages/extension-base/package.json
+++ b/packages/extension-base/package.json
@@ -24,6 +24,7 @@
     "@apollo/client": "^3.7.14",
     "@azns/resolver-core": "^1.4.0",
     "@chainflip/sdk": "^1.6.0",
+    "@emurgo/cardano-serialization-lib-nodejs": "^13.2.0",
     "@equilab/api": "~1.14.25",
     "@ethereumjs/common": "^4.1.0",
     "@ethereumjs/tx": "^5.1.0",
@@ -61,6 +62,7 @@
     "@subwallet/extension-dapp": "^1.3.15-0",
     "@subwallet/extension-inject": "^1.3.15-0",
     "@subwallet/keyring": "^0.1.8-beta.0",
+    "@subwallet/subwallet-api-sdk": "^1.3.12-1",
     "@subwallet/ui-keyring": "^0.1.8-beta.0",
     "@ton/core": "^0.56.3",
     "@ton/crypto": "^3.2.0",
diff --git a/packages/extension-base/src/background/KoniTypes.ts b/packages/extension-base/src/background/KoniTypes.ts
index 26778ad2670..93289efe184 100644
--- a/packages/extension-base/src/background/KoniTypes.ts
+++ b/packages/extension-base/src/background/KoniTypes.ts
@@ -7,6 +7,7 @@ import { Resolver } from '@subwallet/extension-base/background/handlers/State';
 import { AccountAuthType, AuthorizeRequest, ConfirmationRequestBase, RequestAccountList, RequestAccountSubscribe, RequestAccountUnsubscribe, RequestAuthorizeCancel, RequestAuthorizeReject, RequestAuthorizeSubscribe, RequestAuthorizeTab, RequestCurrentAccountAddress, ResponseAuthorizeList } from '@subwallet/extension-base/background/types';
 import { AppConfig, BrowserConfig, OSConfig } from '@subwallet/extension-base/constants';
 import { RequestOptimalTransferProcess } from '@subwallet/extension-base/services/balance-service/helpers';
+import { CardanoTransactionConfig } from '@subwallet/extension-base/services/balance-service/transfer/cardano-transfer';
 import { TonTransactionConfig } from '@subwallet/extension-base/services/balance-service/transfer/ton-transfer';
 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';
@@ -16,7 +17,7 @@ import { AuthUrls } from '@subwallet/extension-base/services/request-service/typ
 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, BaseRequestSign, BuyServiceInfo, BuyTokenInfo, CommonOptimalPath, CurrentAccountInfo, EarningRewardHistoryItem, EarningRewardJson, EarningStatus, HandleYieldStepParams, InternalRequestSign, LeavePoolAdditionalData, NominationPoolInfo, OptimalYieldPath, OptimalYieldPathParams, RequestAccountBatchExportV2, RequestAccountCreateSuriV2, RequestAccountNameValidate, RequestAccountProxyEdit, RequestAccountProxyForget, RequestBatchJsonGetAccountInfo, RequestBatchRestoreV2, RequestBounceableValidate, RequestChangeTonWalletContractVersion, RequestCheckCrossChainTransfer, RequestCheckPublicAndSecretKey, RequestCheckTransfer, RequestCrossChainTransfer, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestEarlyValidateYield, RequestExportAccountProxyMnemonic, RequestGetAllTonWalletContractVersion, RequestGetDeriveAccounts, RequestGetDeriveSuggestion, RequestGetYieldPoolTargets, RequestInputAccountSubscribe, RequestJsonGetAccountInfo, RequestJsonRestoreV2, RequestMetadataHash, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestTransfer, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseAccountBatchExportV2, ResponseAccountCreateSuriV2, ResponseAccountNameValidate, ResponseBatchJsonGetAccountInfo, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseEarlyValidateYield, ResponseExportAccountProxyMnemonic, ResponseGetAllTonWalletContractVersion, ResponseGetDeriveAccounts, ResponseGetDeriveSuggestion, ResponseGetYieldPoolTargets, ResponseInputAccountSubscribe, ResponseJsonGetAccountInfo, ResponseMetadataHash, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2, ResponseShortenMetadata, StorageDataInterface, SubmitYieldStepData, SwapPair, SwapQuoteResponse, SwapRequest, SwapRequestResult, SwapSubmitParams, SwapTxData, TokenSpendingApprovalParams, UnlockDotTransactionNft, UnstakingStatus, ValidateSwapProcessParams, ValidateYieldProcessParams, YieldPoolInfo, YieldPositionInfo } from '@subwallet/extension-base/types';
+import { AccountChainType, AccountJson, AccountsWithCurrentAddress, AddressJson, BalanceJson, BaseRequestSign, BuyServiceInfo, BuyTokenInfo, CommonOptimalPath, CurrentAccountInfo, EarningRewardHistoryItem, EarningRewardJson, EarningStatus, HandleYieldStepParams, InternalRequestSign, LeavePoolAdditionalData, NominationPoolInfo, OptimalYieldPath, OptimalYieldPathParams, RequestAccountBatchExportV2, RequestAccountCreateSuriV2, RequestAccountNameValidate, RequestAccountProxyEdit, RequestAccountProxyForget, RequestBatchJsonGetAccountInfo, RequestBatchRestoreV2, RequestBounceableValidate, RequestChangeTonWalletContractVersion, RequestCheckCrossChainTransfer, RequestCheckPublicAndSecretKey, RequestCheckTransfer, RequestCrossChainTransfer, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestEarlyValidateYield, RequestExportAccountProxyMnemonic, RequestGetAllTonWalletContractVersion, RequestGetDeriveAccounts, RequestGetDeriveSuggestion, RequestGetYieldPoolTargets, RequestInputAccountSubscribe, RequestJsonGetAccountInfo, RequestJsonRestoreV2, RequestMetadataHash, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestTransfer, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseAccountBatchExportV2, ResponseAccountCreateSuriV2, ResponseAccountNameValidate, ResponseBatchJsonGetAccountInfo, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseEarlyValidateYield, ResponseExportAccountProxyMnemonic, ResponseGetAllTonWalletContractVersion, ResponseGetDeriveAccounts, ResponseGetDeriveSuggestion, ResponseGetYieldPoolTargets, ResponseInputAccountSubscribe, ResponseJsonGetAccountInfo, ResponseMetadataHash, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2, ResponseShortenMetadata, StorageDataInterface, SubmitYieldStepData, SwapPair, SwapQuoteResponse, SwapRequest, SwapRequestResult, SwapSubmitParams, SwapTxData, TokenSpendingApprovalParams, UnlockDotTransactionNft, UnstakingStatus, ValidateSwapProcessParams, ValidateYieldProcessParams, YieldPoolInfo, YieldPositionInfo } from '@subwallet/extension-base/types';
 import { RequestClaimBridge } from '@subwallet/extension-base/types/bridge';
 import { GetNotificationParams, RequestIsClaimedPolygonBridge, RequestSwitchStatusParams } from '@subwallet/extension-base/types/notification';
 import { InjectedAccount, InjectedAccountWithMeta, MetadataDefBase } from '@subwallet/extension-inject/types';
@@ -435,6 +436,9 @@ export interface UiSettings {
   unlockType: WalletUnlockType;
   enableChainPatrol: boolean;
   notificationSetup: NotificationSetup;
+  isAcknowledgedUnifiedAccountMigration: boolean;
+  isUnifiedAccountMigrationInProgress: boolean;
+  isUnifiedAccountMigrationDone: boolean;
   // On-ramp service account reference
   walletReference: string;
 }
@@ -478,7 +482,9 @@ export enum TransactionDirection {
 export enum ChainType {
   EVM = 'evm',
   SUBSTRATE = 'substrate',
-  TON = 'ton'
+  BITCOIN = 'bitcoin',
+  TON = 'ton',
+  CARDANO = 'cardano'
 }
 
 export enum ExtrinsicType {
@@ -1091,6 +1097,12 @@ export interface TonSignRequest {
   canSign: boolean;
 }
 
+export interface CardanoSignRequest {
+  account: AccountJson;
+  hashPayload: string;
+  canSign: boolean;
+}
+
 export interface ErrorValidation {
   message: string;
   name: string;
@@ -1109,6 +1121,12 @@ export interface TonSignatureRequest extends TonSignRequest {
   payload: unknown;
 }
 
+export interface CardanoSignatureRequest extends CardanoSignRequest {
+  id: string;
+  type: string;
+  payload: unknown
+}
+
 export interface EvmSendTransactionRequest extends TransactionConfig, EvmSignRequest {
   estimateGas: string;
   parseData: EvmTransactionData;
@@ -1118,9 +1136,11 @@ export interface EvmSendTransactionRequest extends TransactionConfig, EvmSignReq
 
 // TODO: add account info + dataToSign
 export type TonSendTransactionRequest = TonTransactionConfig;
+export type CardanoSendTransactionRequest = CardanoTransactionConfig;
 
 export type EvmWatchTransactionRequest = EvmSendTransactionRequest;
 export type TonWatchTransactionRequest = TonSendTransactionRequest;
+export type CardanoWatchTransactionRequest = CardanoSendTransactionRequest;
 
 export interface ConfirmationsQueueItemOptions {
   requiredPassword?: boolean;
@@ -1186,8 +1206,15 @@ export interface ConfirmationDefinitionsTon {
   tonWatchTransactionRequest: [ConfirmationsQueueItem<TonWatchTransactionRequest>, ConfirmationResult<string>]
 }
 
+export interface ConfirmationDefinitionsCardano {
+  cardanoSignatureRequest: [ConfirmationsQueueItem<CardanoSignatureRequest>, ConfirmationResult<string>],
+  cardanoSendTransactionRequest: [ConfirmationsQueueItem<CardanoSendTransactionRequest>, ConfirmationResult<string>],
+  cardanoWatchTransactionRequest: [ConfirmationsQueueItem<CardanoWatchTransactionRequest>, ConfirmationResult<string>]
+}
+
 export type ConfirmationType = keyof ConfirmationDefinitions;
 export type ConfirmationTypeTon = keyof ConfirmationDefinitionsTon;
+export type ConfirmationTypeCardano = keyof ConfirmationDefinitionsCardano;
 
 export type ConfirmationsQueue = {
   [CT in ConfirmationType]: Record<string, ConfirmationDefinitions[CT][0]>;
@@ -1195,19 +1222,24 @@ export type ConfirmationsQueue = {
 export type ConfirmationsQueueTon = {
   [CT in ConfirmationTypeTon]: Record<string, ConfirmationDefinitionsTon[CT][0]>;
 }
+export type ConfirmationsQueueCardano = {
+  [CT in ConfirmationTypeCardano]: Record<string, ConfirmationDefinitionsCardano[CT][0]>;
+}
 
 export type RequestConfirmationsSubscribe = null;
-
 export type RequestConfirmationsSubscribeTon = null;
+export type RequestConfirmationsSubscribeCardano = null;
 
 // Design to use only one confirmation
 export type RequestConfirmationComplete = {
   [CT in ConfirmationType]?: ConfirmationDefinitions[CT][1];
 }
-
 export type RequestConfirmationCompleteTon = {
   [CT in ConfirmationTypeTon]?: ConfirmationDefinitionsTon[CT][1];
 }
+export type RequestConfirmationCompleteCardano = {
+  [CT in ConfirmationTypeCardano]?: ConfirmationDefinitionsCardano[CT][1];
+}
 
 export interface BondingOptionParams {
   chain: string;
@@ -1904,6 +1936,47 @@ export interface ResponseNftImport {
 
 /* Campaign */
 
+/* Migrate Unified Account */
+export interface RequestSaveMigrationAcknowledgedStatus {
+  isAcknowledgedUnifiedAccountMigration: boolean;
+}
+
+export interface RequestSaveUnifiedAccountMigrationInProgress {
+  isUnifiedAccountMigrationInProgress: boolean;
+}
+
+export interface RequestMigrateUnifiedAndFetchEligibleSoloAccounts {
+  password: string
+}
+
+export interface ResponseMigrateUnifiedAndFetchEligibleSoloAccounts {
+  migratedUnifiedAccountIds: string[],
+  soloAccounts: Record<string, SoloAccountToBeMigrated[]>
+  sessionId: string; // to keep linking to password in state
+}
+
+export interface SoloAccountToBeMigrated {
+  upcomingProxyId: string,
+  proxyId: string,
+  address: string,
+  name: string,
+  chainType: AccountChainType
+}
+
+export interface RequestMigrateSoloAccount {
+  soloAccounts: SoloAccountToBeMigrated[];
+  accountName: string;
+  sessionId: string;
+}
+
+export interface ResponseMigrateSoloAccount {
+  migratedUnifiedAccountId: string
+}
+
+export interface RequestPingSession {
+  sessionId: string;
+}
+
 /* Core types */
 export type _Address = string;
 export type _BalanceMetadata = unknown;
@@ -2083,7 +2156,10 @@ export interface KoniRequestSignatures {
   'pri(settings.saveAutoLockTime)': [RequestChangeTimeAutoLock, boolean];
   'pri(settings.saveUnlockType)': [RequestUnlockType, boolean];
   'pri(settings.saveEnableChainPatrol)': [RequestChangeEnableChainPatrol, boolean];
-  'pri(settings.saveNotificationSetup)': [NotificationSetup, boolean]
+  'pri(settings.saveNotificationSetup)': [NotificationSetup, boolean];
+  'pri(settings.saveUnifiedAccountMigrationInProgress)': [RequestSaveUnifiedAccountMigrationInProgress, boolean];
+  'pri(settings.pingUnifiedAccountMigrationDone)': [null, boolean];
+  'pri(settings.saveMigrationAcknowledgedStatus)': [RequestSaveMigrationAcknowledgedStatus, boolean];
   'pri(settings.saveLanguage)': [RequestChangeLanguage, boolean];
   'pri(settings.savePriceCurrency)': [RequestChangePriceCurrency, boolean];
   'pri(settings.saveShowZeroBalance)': [RequestChangeShowZeroBalance, boolean];
@@ -2167,8 +2243,10 @@ export interface KoniRequestSignatures {
   // Confirmation Queues
   'pri(confirmations.subscribe)': [RequestConfirmationsSubscribe, ConfirmationsQueue, ConfirmationsQueue];
   'pri(confirmationsTon.subscribe)': [RequestConfirmationsSubscribeTon, ConfirmationsQueueTon, ConfirmationsQueueTon];
+  'pri(confirmationsCardano.subscribe)': [RequestConfirmationsSubscribeCardano, ConfirmationsQueueCardano, ConfirmationsQueueCardano];
   'pri(confirmations.complete)': [RequestConfirmationComplete, boolean];
   'pri(confirmationsTon.complete)': [RequestConfirmationCompleteTon, boolean];
+  'pri(confirmationsCardano.complete)': [RequestConfirmationCompleteCardano, boolean];
 
   'pub(utils.getRandom)': [RandomTestRequest, number];
   'pub(accounts.listV2)': [RequestAccountList, InjectedAccount[]];
@@ -2308,6 +2386,11 @@ export interface KoniRequestSignatures {
 
   /* Ledger */
   'pri(ledger.generic.allow)': [null, string[], string[]];
+
+  /* Migrate Unified Account */
+  'pri(migrate.migrateUnifiedAndFetchEligibleSoloAccounts)': [RequestMigrateUnifiedAndFetchEligibleSoloAccounts, ResponseMigrateUnifiedAndFetchEligibleSoloAccounts];
+  'pri(migrate.migrateSoloAccount)': [RequestMigrateSoloAccount, ResponseMigrateSoloAccount];
+  'pri(migrate.pingSession)': [RequestPingSession, boolean];
 }
 
 export interface ApplicationMetadataType {
diff --git a/packages/extension-base/src/constants/signing.ts b/packages/extension-base/src/constants/signing.ts
index f2eb61466f7..3d1b83eb608 100644
--- a/packages/extension-base/src/constants/signing.ts
+++ b/packages/extension-base/src/constants/signing.ts
@@ -7,11 +7,15 @@ import { AccountChainType } from '@subwallet/extension-base/types';
 export const SIGNING_COMPATIBLE_MAP: Record<ChainType, AccountChainType[]> = {
   [ChainType.SUBSTRATE]: [AccountChainType.SUBSTRATE, AccountChainType.ETHEREUM],
   [ChainType.EVM]: [AccountChainType.ETHEREUM],
-  [ChainType.TON]: [AccountChainType.TON]
+  [ChainType.BITCOIN]: [AccountChainType.BITCOIN],
+  [ChainType.TON]: [AccountChainType.TON],
+  [ChainType.CARDANO]: [AccountChainType.CARDANO]
 };
 
 export const LEDGER_SIGNING_COMPATIBLE_MAP: Record<ChainType, AccountChainType[]> = {
   [ChainType.SUBSTRATE]: [AccountChainType.SUBSTRATE],
   [ChainType.EVM]: [AccountChainType.ETHEREUM],
-  [ChainType.TON]: [AccountChainType.TON]
+  [ChainType.BITCOIN]: [AccountChainType.BITCOIN],
+  [ChainType.TON]: [AccountChainType.TON],
+  [ChainType.CARDANO]: [AccountChainType.CARDANO]
 };
diff --git a/packages/extension-base/src/core/logic-validation/recipientAddress.ts b/packages/extension-base/src/core/logic-validation/recipientAddress.ts
index 91da1b52732..d4b04b1e034 100644
--- a/packages/extension-base/src/core/logic-validation/recipientAddress.ts
+++ b/packages/extension-base/src/core/logic-validation/recipientAddress.ts
@@ -2,10 +2,10 @@
 // SPDX-License-Identifier: Apache-2.0
 
 import { ActionType, ValidateRecipientParams, ValidationCondition } from '@subwallet/extension-base/core/types';
-import { _isAddress, _isNotDuplicateAddress, _isNotNull, _isSupportLedgerAccount, _isValidAddressForEcosystem, _isValidSubstrateAddressFormat, _isValidTonAddressFormat } from '@subwallet/extension-base/core/utils';
+import { _isAddress, _isNotDuplicateAddress, _isNotNull, _isSupportLedgerAccount, _isValidAddressForEcosystem, _isValidCardanoAddressFormat, _isValidSubstrateAddressFormat, _isValidTonAddressFormat } from '@subwallet/extension-base/core/utils';
 import { AccountSignMode } from '@subwallet/extension-base/types';
 import { detectTranslate } from '@subwallet/extension-base/utils';
-import { isSubstrateAddress, isTonAddress } from '@subwallet/keyring';
+import { isCardanoAddress, isSubstrateAddress, isTonAddress } from '@subwallet/keyring';
 
 function getConditions (validateRecipientParams: ValidateRecipientParams): ValidationCondition[] {
   const { account, actionType, autoFormatValue, destChainInfo, srcChain, toAddress } = validateRecipientParams;
@@ -25,7 +25,11 @@ function getConditions (validateRecipientParams: ValidateRecipientParams): Valid
     conditions.push(ValidationCondition.IS_VALID_TON_ADDRESS_FORMAT);
   }
 
-  if (srcChain === destChainInfo.slug && isSendAction && !destChainInfo.tonInfo) {
+  if (isCardanoAddress(toAddress)) {
+    conditions.push(ValidationCondition.IS_VALID_CARDANO_ADDRESS_FORMAT);
+  }
+
+  if (srcChain === destChainInfo.slug && isSendAction && !destChainInfo.tonInfo && !destChainInfo.cardanoInfo) {
     conditions.push(ValidationCondition.IS_NOT_DUPLICATE_ADDRESS);
   }
 
@@ -75,6 +79,12 @@ function getValidationFunctions (conditions: ValidationCondition[]): Array<(vali
         break;
       }
 
+      case ValidationCondition.IS_VALID_CARDANO_ADDRESS_FORMAT: {
+        validationFunctions.push(_isValidCardanoAddressFormat);
+
+        break;
+      }
+
       case ValidationCondition.IS_NOT_DUPLICATE_ADDRESS: {
         validationFunctions.push(_isNotDuplicateAddress);
 
diff --git a/packages/extension-base/src/core/logic-validation/transfer.ts b/packages/extension-base/src/core/logic-validation/transfer.ts
index 57be57f2cdc..5875ddd0208 100644
--- a/packages/extension-base/src/core/logic-validation/transfer.ts
+++ b/packages/extension-base/src/core/logic-validation/transfer.ts
@@ -8,16 +8,17 @@ import { TransactionWarning } from '@subwallet/extension-base/background/warning
 import { LEDGER_SIGNING_COMPATIBLE_MAP, SIGNING_COMPATIBLE_MAP, XCM_MIN_AMOUNT_RATIO } from '@subwallet/extension-base/constants';
 import { _canAccountBeReaped, _isAccountActive } from '@subwallet/extension-base/core/substrate/system-pallet';
 import { FrameSystemAccountInfo } from '@subwallet/extension-base/core/substrate/types';
+import { getCardanoAssetId } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/cardano/utils';
 import { isBounceableAddress } 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, _TonApi } from '@subwallet/extension-base/services/chain-service/types';
-import { _getAssetDecimals, _getChainExistentialDeposit, _getChainNativeTokenBasicInfo, _getContractAddressOfToken, _getTokenMinAmount, _isNativeToken, _isTokenEvmSmartContract, _isTokenTonSmartContract } from '@subwallet/extension-base/services/chain-service/utils';
+import { _getAssetDecimals, _getChainExistentialDeposit, _getChainNativeTokenBasicInfo, _getContractAddressOfToken, _getTokenMinAmount, _isCIP26Token, _isNativeToken, _isTokenEvmSmartContract, _isTokenTonSmartContract } from '@subwallet/extension-base/services/chain-service/utils';
 import { calculateGasFeeParams } from '@subwallet/extension-base/services/fee-service/utils';
-import { isSubstrateTransaction, isTonTransaction } from '@subwallet/extension-base/services/transaction-service/helpers';
+import { isCardanoTransaction, isSubstrateTransaction, isTonTransaction } from '@subwallet/extension-base/services/transaction-service/helpers';
 import { OptionalSWTransaction, SWTransactionInput, SWTransactionResponse } from '@subwallet/extension-base/services/transaction-service/types';
 import { AccountSignMode, BasicTxErrorType, BasicTxWarningCode, TransferTxErrorType } from '@subwallet/extension-base/types';
 import { balanceFormatter, formatNumber, pairToAccount } from '@subwallet/extension-base/utils';
-import { isTonAddress } from '@subwallet/keyring';
+import { isCardanoAddress, isTonAddress } from '@subwallet/keyring';
 import { KeyringPair } from '@subwallet/keyring/types';
 import { keyring } from '@subwallet/ui-keyring';
 import BigN from 'bignumber.js';
@@ -53,6 +54,10 @@ export function validateTransferRequest (tokenInfo: _ChainAsset, from: _Address,
     errors.push(new TransactionError(BasicTxErrorType.INVALID_PARAMS, t('Not found TEP74 address for this token')));
   }
 
+  if (isCardanoAddress(from) && isCardanoAddress(to) && _isCIP26Token(tokenInfo) && getCardanoAssetId(tokenInfo).length === 0) {
+    errors.push(new TransactionError(BasicTxErrorType.INVALID_PARAMS, t('Not found policy id of this token')));
+  }
+
   return [errors, keypair, transferValue];
 }
 
@@ -388,6 +393,8 @@ export async function estimateFeeForTransaction (validationResponse: SWTransacti
         estimateFee.value = (await transaction.paymentInfo(validationResponse.address)).partialFee.toString();
       } else if (isTonTransaction(transaction)) {
         estimateFee.value = transaction.estimateFee; // todo: might need to update logic estimate fee inside for future actions excluding normal transfer Ton and Jetton
+      } else if (isCardanoTransaction(transaction)) {
+        estimateFee.value = transaction.estimateCardanoFee;
       } else {
         const gasLimit = transaction.gas || await evmApi.api.eth.estimateGas(transaction);
 
diff --git a/packages/extension-base/src/core/types.ts b/packages/extension-base/src/core/types.ts
index 3543493e4b3..41d9a680f31 100644
--- a/packages/extension-base/src/core/types.ts
+++ b/packages/extension-base/src/core/types.ts
@@ -12,6 +12,7 @@ export enum ValidationCondition {
   IS_VALID_ADDRESS_FOR_ECOSYSTEM = 'IS_VALID_ADDRESS_FOR_ECOSYSTEM',
   IS_VALID_SUBSTRATE_ADDRESS_FORMAT = 'IS_VALID_SUBSTRATE_ADDRESS_FORMAT',
   IS_VALID_TON_ADDRESS_FORMAT = 'IS_VALID_TON_ADDRESS_FORMAT',
+  IS_VALID_CARDANO_ADDRESS_FORMAT = 'IS_VALID_CARDANO_ADDRESS_FORMAT',
   IS_NOT_DUPLICATE_ADDRESS = 'IS_NOT_DUPLICATE_ADDRESS',
   IS_SUPPORT_LEDGER_ACCOUNT = 'IS_SUPPORT_LEDGER_ACCOUNT'
 }
diff --git a/packages/extension-base/src/core/utils.ts b/packages/extension-base/src/core/utils.ts
index c3899a1e036..380f4552c61 100644
--- a/packages/extension-base/src/core/utils.ts
+++ b/packages/extension-base/src/core/utils.ts
@@ -5,10 +5,10 @@ import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
 import { BalanceAccountType } from '@subwallet/extension-base/core/substrate/types';
 import { LedgerMustCheckType, ValidateRecipientParams } from '@subwallet/extension-base/core/types';
 import { tonAddressInfo } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/utils';
-import { _isChainEvmCompatible, _isChainSubstrateCompatible, _isChainTonCompatible } from '@subwallet/extension-base/services/chain-service/utils';
+import { _isChainCardanoCompatible, _isChainEvmCompatible, _isChainSubstrateCompatible, _isChainTonCompatible } from '@subwallet/extension-base/services/chain-service/utils';
 import { AccountJson } from '@subwallet/extension-base/types';
 import { isAddressAndChainCompatible, isSameAddress, reformatAddress } from '@subwallet/extension-base/utils';
-import { isAddress, isTonAddress } from '@subwallet/keyring';
+import { isAddress, isCardanoTestnetAddress, isTonAddress } from '@subwallet/keyring';
 
 import { isEthereumAddress } from '@polkadot/util-crypto';
 
@@ -64,7 +64,8 @@ export function _isValidAddressForEcosystem (validateRecipientParams: ValidateRe
   if (!isAddressAndChainCompatible(toAddress, destChainInfo)) {
     if (_isChainEvmCompatible(destChainInfo) ||
       _isChainSubstrateCompatible(destChainInfo) ||
-      _isChainTonCompatible(destChainInfo)) {
+      _isChainTonCompatible(destChainInfo) ||
+      _isChainCardanoCompatible(destChainInfo)) {
       return 'Recipient address must be the same type as sender address';
     }
 
@@ -98,6 +99,16 @@ export function _isValidTonAddressFormat (validateRecipientParams: ValidateRecip
   return '';
 }
 
+export function _isValidCardanoAddressFormat (validateRecipientParams: ValidateRecipientParams): string {
+  const { destChainInfo, toAddress } = validateRecipientParams;
+
+  if (isCardanoTestnetAddress(toAddress) !== destChainInfo.isTestnet) {
+    return `Recipient address must be a valid ${destChainInfo.name} address`;
+  }
+
+  return '';
+}
+
 export function _isNotDuplicateAddress (validateRecipientParams: ValidateRecipientParams): string {
   const { fromAddress, toAddress } = validateRecipientParams;
 
diff --git a/packages/extension-base/src/defaults.ts b/packages/extension-base/src/defaults.ts
index 6af6bb847f8..14ca5580336 100644
--- a/packages/extension-base/src/defaults.ts
+++ b/packages/extension-base/src/defaults.ts
@@ -7,7 +7,8 @@ const ALLOWED_PATH = [
   '/accounts/connect-ledger',
   '/accounts/restore-json',
   '/accounts/detail',
-  '/accounts/new-seed-phrase'
+  '/accounts/new-seed-phrase',
+  '/migrate-account'
 ] as const;
 const PHISHING_PAGE_REDIRECT = '/phishing-page-detected';
 const EXTENSION_PREFIX = process.env.EXTENSION_PREFIX as string || '';
diff --git a/packages/extension-base/src/koni/api/dotsama/crowdloan.ts b/packages/extension-base/src/koni/api/dotsama/crowdloan.ts
index f41a0bbe3bd..de7960e4db9 100644
--- a/packages/extension-base/src/koni/api/dotsama/crowdloan.ts
+++ b/packages/extension-base/src/koni/api/dotsama/crowdloan.ts
@@ -3,11 +3,11 @@
 
 import { COMMON_CHAIN_SLUGS } from '@subwallet/chain-list';
 import { _ChainInfo, _CrowdloanFund, _FundStatus } from '@subwallet/chain-list/types';
-import { APIItemState, CrowdloanItem, CrowdloanParaState } from '@subwallet/extension-base/background/KoniTypes';
+import { APIItemState, ChainType, CrowdloanItem, CrowdloanParaState } from '@subwallet/extension-base/background/KoniTypes';
 import { ACALA_REFRESH_CROWDLOAN_INTERVAL } from '@subwallet/extension-base/constants';
 import registry from '@subwallet/extension-base/koni/api/dotsama/typeRegistry';
 import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types';
-import { categoryAddresses, fetchJson, reformatAddress } from '@subwallet/extension-base/utils';
+import { fetchJson, getAddressesByChainType, reformatAddress } from '@subwallet/extension-base/utils';
 import { fetchStaticData } from '@subwallet/extension-base/utils/fetchStaticData';
 
 import { DeriveOwnContributions } from '@polkadot/api-derive/types';
@@ -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).substrate;
+    const substrateAddresses = getAddressesByChainType(addresses, [ChainType.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 e6e03a0f1af..f6f1016303d 100644
--- a/packages/extension-base/src/koni/api/nft/index.ts
+++ b/packages/extension-base/src/koni/api/nft/index.ts
@@ -2,7 +2,7 @@
 // SPDX-License-Identifier: Apache-2.0
 
 import { _ChainAsset, _ChainInfo } from '@subwallet/chain-list/types';
-import { NftCollection, NftItem } from '@subwallet/extension-base/background/KoniTypes';
+import { ChainType, NftCollection, NftItem } from '@subwallet/extension-base/background/KoniTypes';
 import { AcalaNftApi } from '@subwallet/extension-base/koni/api/nft/acala_nft';
 import AssetHubUniquesPalletApi from '@subwallet/extension-base/koni/api/nft/assethub_unique';
 import { BitCountryNftApi } from '@subwallet/extension-base/koni/api/nft/bit.country';
@@ -13,13 +13,12 @@ import { BaseNftApi } from '@subwallet/extension-base/koni/api/nft/nft';
 import OrdinalNftApi from '@subwallet/extension-base/koni/api/nft/ordinal_nft';
 import { RmrkNftApi } from '@subwallet/extension-base/koni/api/nft/rmrk_nft';
 import { UniqueNftApi } from '@subwallet/extension-base/koni/api/nft/unique_network_nft';
-// import UniqueNftApi from '@subwallet/extension-base/koni/api/nft/unique_nft';
 import { VaraNftApi } from '@subwallet/extension-base/koni/api/nft/vara_nft';
 import { WasmNftApi } from '@subwallet/extension-base/koni/api/nft/wasm_nft';
 import { _NFT_CHAIN_GROUP } from '@subwallet/extension-base/services/chain-service/constants';
 import { _EvmApi, _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types';
 import { _isChainSupportEvmNft, _isChainSupportNativeNft, _isChainSupportWasmNft, _isSupportOrdinal } from '@subwallet/extension-base/services/chain-service/utils';
-import { categoryAddresses, targetIsWeb } from '@subwallet/extension-base/utils';
+import { getAddressesByChainType, targetIsWeb } from '@subwallet/extension-base/utils';
 
 import AssetHubNftsPalletApi from './assethub_nft';
 import { RariNftApi } from './rari';
@@ -27,7 +26,8 @@ import { OdysseyNftApi } from './story_odyssey_nft';
 import { TernoaNftApi } from './ternoa_nft';
 
 function createSubstrateNftApi (chain: string, substrateApi: _SubstrateApi | null, addresses: string[]): BaseNftApi[] | null {
-  const { evm: evmAddresses, substrate: substrateAddresses } = categoryAddresses(addresses);
+  const evmAddresses = getAddressesByChainType(addresses, [ChainType.EVM]);
+  const substrateAddresses = getAddressesByChainType(addresses, [ChainType.SUBSTRATE]);
 
   if (_NFT_CHAIN_GROUP.acala.includes(chain)) {
     return [new AcalaNftApi(substrateApi, substrateAddresses, chain)];
@@ -61,13 +61,13 @@ function createSubstrateNftApi (chain: string, substrateApi: _SubstrateApi | nul
 }
 
 function createWasmNftApi (chain: string, apiProps: _SubstrateApi | null, addresses: string[]): BaseNftApi | null {
-  const substrateAddresses = categoryAddresses(addresses).substrate;
+  const substrateAddresses = getAddressesByChainType(addresses, [ChainType.SUBSTRATE]);
 
   return new WasmNftApi(apiProps, substrateAddresses, chain);
 }
 
 function createWeb3NftApi (chain: string, evmApi: _EvmApi | null, addresses: string[]): BaseNftApi | null {
-  const evmAddresses = categoryAddresses(addresses).evm;
+  const evmAddresses = getAddressesByChainType(addresses, [ChainType.EVM]);
 
   return new EvmNftApi(evmApi, evmAddresses, chain);
 }
@@ -109,7 +109,8 @@ export class NftHandler {
   setAddresses (addresses: string[]) {
     this.addresses = addresses;
 
-    const { evm: evmAddresses, substrate: substrateAddresses } = categoryAddresses(addresses);
+    const evmAddresses = getAddressesByChainType(addresses, [ChainType.EVM]);
+    const substrateAddresses = getAddressesByChainType(addresses, [ChainType.SUBSTRATE]);
 
     for (const handler of this.handlers) {
       const useAddresses = handler.isEthereum ? evmAddresses : substrateAddresses;
@@ -140,7 +141,8 @@ export class NftHandler {
     try {
       if (this.needSetupApi) { // setup connections for first time use
         this.handlers = [];
-        const { evm: evmAddresses, substrate: substrateAddresses } = categoryAddresses(this.addresses);
+        const evmAddresses = getAddressesByChainType(this.addresses, [ChainType.EVM]);
+        const substrateAddresses = getAddressesByChainType(this.addresses, [ChainType.SUBSTRATE]);
 
         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 4055d1f65d2..b0cf0771f21 100644
--- a/packages/extension-base/src/koni/api/staking/index.ts
+++ b/packages/extension-base/src/koni/api/staking/index.ts
@@ -2,7 +2,7 @@
 // SPDX-License-Identifier: Apache-2.0
 
 import { _ChainInfo } from '@subwallet/chain-list/types';
-import { NominatorMetadata, StakingItem, StakingRewardItem } from '@subwallet/extension-base/background/KoniTypes';
+import { ChainType, NominatorMetadata, StakingItem, StakingRewardItem } from '@subwallet/extension-base/background/KoniTypes';
 import { getAmplitudeStakingOnChain, getAstarStakingOnChain, getParaStakingOnChain } from '@subwallet/extension-base/koni/api/staking/paraChain';
 import { getNominationPoolReward, getRelayPoolingOnChain, getRelayStakingOnChain } from '@subwallet/extension-base/koni/api/staking/relayChain';
 import { getAllSubsquidStaking } from '@subwallet/extension-base/koni/api/staking/subsquidStaking';
@@ -10,7 +10,7 @@ import { _PURE_EVM_CHAINS } from '@subwallet/extension-base/services/chain-servi
 import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types';
 import { _isChainEvmCompatible, _isChainSupportSubstrateStaking, _isSubstrateRelayChain } from '@subwallet/extension-base/services/chain-service/utils';
 import { _STAKING_CHAIN_GROUP } from '@subwallet/extension-base/services/earning-service/constants';
-import { categoryAddresses } from '@subwallet/extension-base/utils';
+import { getAddressesByChainType } from '@subwallet/extension-base/utils';
 
 interface PromiseMapping {
   api: _SubstrateApi,
@@ -19,7 +19,8 @@ interface PromiseMapping {
 
 export function stakingOnChainApi (addresses: string[], substrateApiMap: Record<string, _SubstrateApi>, chainInfoMap: Record<string, _ChainInfo>, stakingCallback: (networkKey: string, rs: StakingItem) => void, nominatorStateCallback: (nominatorMetadata: NominatorMetadata) => void) {
   const filteredApiMap: PromiseMapping[] = [];
-  const { evm: evmAddresses, substrate: substrateAddresses } = categoryAddresses(addresses);
+  const evmAddresses = getAddressesByChainType(addresses, [ChainType.EVM]);
+  const substrateAddresses = getAddressesByChainType(addresses, [ChainType.SUBSTRATE]);
 
   Object.entries(chainInfoMap).forEach(([networkKey, chainInfo]) => {
     if (_PURE_EVM_CHAINS.indexOf(networkKey) < 0 && _isChainSupportSubstrateStaking(chainInfo)) {
diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts
index ad8c22d3987..d975803eba8 100644
--- a/packages/extension-base/src/koni/background/handlers/Extension.ts
+++ b/packages/extension-base/src/koni/background/handlers/Extension.ts
@@ -8,7 +8,7 @@ import { _AssetRef, _AssetType, _ChainAsset, _ChainInfo, _MultiChainAsset } from
 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, 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, RequestConfirmationCompleteTon, RequestConnectWalletConnect, RequestCrowdloanContributions, RequestDeleteContactAccount, RequestDisconnectWalletConnectSession, RequestEditContactAccount, RequestFindRawMetadata, RequestForgetSite, RequestFreeBalance, RequestGetTransaction, RequestKeyringExportMnemonic, RequestMaxTransferable, RequestMigratePassword, RequestParseEvmContractInput, RequestParseTransactionSubstrate, RequestPassPhishingPage, RequestQrParseRLP, RequestQrSignEvm, RequestQrSignSubstrate, RequestRejectConnectWalletSession, RequestRejectExternalRequest, RequestRejectWalletConnectNotSupport, RequestRemoveInjectedAccounts, RequestResetWallet, RequestResolveExternalRequest, RequestSaveAppConfig, RequestSaveBrowserConfig, RequestSaveOSConfig, RequestSaveRecentAccount, RequestSettingsType, RequestSigningApprovePasswordV2, RequestStakePoolingBonding, RequestStakePoolingUnbonding, RequestSubscribeHistory, RequestSubstrateNftSubmitTransaction, RequestTuringCancelStakeCompound, RequestTuringStakeCompound, RequestUnbondingSubmit, RequestUnlockKeyring, RequestUnlockType, ResolveAddressToDomainRequest, ResolveDomainRequest, ResponseAccountCreateWithSecretKey, ResponseAccountExportPrivateKey, ResponseChangeMasterPassword, ResponseFindRawMetadata, ResponseKeyringExportMnemonic, ResponseMigratePassword, ResponseNftImport, ResponseParseEvmContractInput, ResponseParseTransactionSubstrate, ResponseQrParseRLP, ResponseQrSignEvm, ResponseQrSignSubstrate, ResponseRejectExternalRequest, ResponseResetWallet, ResponseResolveExternalRequest, ResponseSubscribeHistory, ResponseUnlockKeyring, ShowCampaignPopupRequest, StakingJson, StakingRewardJson, StakingType, SufficientMetadata, ThemeNames, TransactionHistoryItem, TransactionResponse, ValidateNetworkRequest, ValidateNetworkResponse, ValidatorInfo } from '@subwallet/extension-base/background/KoniTypes';
+import { AccountExternalError, AddressBookInfo, AmountData, AmountDataWithId, AssetSetting, AssetSettingUpdateReq, 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, RequestConfirmationCompleteCardano, RequestConfirmationCompleteTon, RequestConnectWalletConnect, RequestCrowdloanContributions, RequestDeleteContactAccount, RequestDisconnectWalletConnectSession, RequestEditContactAccount, RequestFindRawMetadata, RequestForgetSite, RequestFreeBalance, RequestGetTransaction, RequestKeyringExportMnemonic, RequestMaxTransferable, RequestMigratePassword, RequestMigrateSoloAccount, RequestMigrateUnifiedAndFetchEligibleSoloAccounts, RequestParseEvmContractInput, RequestParseTransactionSubstrate, RequestPassPhishingPage, RequestPingSession, RequestQrParseRLP, RequestQrSignEvm, RequestQrSignSubstrate, RequestRejectConnectWalletSession, RequestRejectExternalRequest, RequestRejectWalletConnectNotSupport, RequestRemoveInjectedAccounts, RequestResetWallet, RequestResolveExternalRequest, RequestSaveAppConfig, RequestSaveBrowserConfig, RequestSaveMigrationAcknowledgedStatus, RequestSaveOSConfig, RequestSaveRecentAccount, RequestSaveUnifiedAccountMigrationInProgress, RequestSettingsType, RequestSigningApprovePasswordV2, RequestStakePoolingBonding, RequestStakePoolingUnbonding, RequestSubscribeHistory, RequestSubstrateNftSubmitTransaction, RequestTuringCancelStakeCompound, RequestTuringStakeCompound, RequestUnbondingSubmit, RequestUnlockKeyring, RequestUnlockType, ResolveAddressToDomainRequest, ResolveDomainRequest, ResponseAccountCreateWithSecretKey, ResponseAccountExportPrivateKey, ResponseChangeMasterPassword, ResponseFindRawMetadata, ResponseKeyringExportMnemonic, ResponseMigratePassword, ResponseMigrateSoloAccount, ResponseMigrateUnifiedAndFetchEligibleSoloAccounts, ResponseNftImport, ResponseParseEvmContractInput, ResponseParseTransactionSubstrate, ResponseQrParseRLP, ResponseQrSignEvm, ResponseQrSignSubstrate, ResponseRejectExternalRequest, ResponseResetWallet, ResponseResolveExternalRequest, ResponseSubscribeHistory, ResponseUnlockKeyring, ShowCampaignPopupRequest, StakingJson, StakingRewardJson, StakingType, SufficientMetadata, 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';
@@ -28,9 +28,11 @@ import { getPoolingBondingExtrinsic, getPoolingUnbondingExtrinsic, validatePoolB
 import { YIELD_EXTRINSIC_TYPES } from '@subwallet/extension-base/koni/api/yield/helper/utils';
 import KoniState from '@subwallet/extension-base/koni/background/handlers/State';
 import { RequestOptimalTransferProcess } from '@subwallet/extension-base/services/balance-service/helpers/process';
+import { DEFAULT_CARDANO_TTL_OFFSET } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/cardano/consts';
 import { isBounceableAddress } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/utils';
+import { createCardanoTransaction } from '@subwallet/extension-base/services/balance-service/transfer/cardano-transfer';
 import { getERC20TransactionObject, getERC721Transaction, getEVMTransactionObject, getPSP34TransferExtrinsic } from '@subwallet/extension-base/services/balance-service/transfer/smart-contract';
-import { createTransferExtrinsic, getTransferMockTxFee } from '@subwallet/extension-base/services/balance-service/transfer/token';
+import { createSubstrateExtrinsic, getTransferMockTxFee } from '@subwallet/extension-base/services/balance-service/transfer/token';
 import { createTonTransaction } from '@subwallet/extension-base/services/balance-service/transfer/ton-transfer';
 import { createAvailBridgeExtrinsicFromAvail, createAvailBridgeTxFromEth, createPolygonBridgeExtrinsic, createSnowBridgeExtrinsic, createXcmExtrinsic, CreateXcmExtrinsicProps, FunctionCreateXcmExtrinsic, getXcmMockTxFee } from '@subwallet/extension-base/services/balance-service/transfer/xcm';
 import { getClaimTxOnAvail, getClaimTxOnEthereum, isAvailChainBridge } from '@subwallet/extension-base/services/balance-service/transfer/xcm/availBridge';
@@ -38,7 +40,7 @@ import { _isPolygonChainBridge, getClaimPolygonBridge, isClaimedPolygonBridge }
 import { _isPosChainBridge, getClaimPosBridge } from '@subwallet/extension-base/services/balance-service/transfer/xcm/posBridge';
 import { _API_OPTIONS_CHAIN_GROUP, _DEFAULT_MANTA_ZK_CHAIN, _MANTA_ZK_CHAIN_GROUP, _ZK_ASSET_PREFIX, SUFFICIENT_CHAIN } from '@subwallet/extension-base/services/chain-service/constants';
 import { _ChainApiStatus, _ChainConnectionStatus, _ChainState, _NetworkUpsertParams, _SubstrateAdapterQueryArgs, _SubstrateApi, _ValidateCustomAssetRequest, _ValidateCustomAssetResponse, EnableChainParams, EnableMultiChainParams } from '@subwallet/extension-base/services/chain-service/types';
-import { _getAssetDecimals, _getAssetSymbol, _getChainNativeTokenBasicInfo, _getContractAddressOfToken, _getEvmChainId, _getTokenMinAmount, _getTokenOnChainAssetId, _getXcmAssetMultilocation, _isAssetSmartContractNft, _isBridgedToken, _isChainEvmCompatible, _isChainSubstrateCompatible, _isChainTonCompatible, _isCustomAsset, _isLocalToken, _isMantaZkAsset, _isNativeToken, _isPureEvmChain, _isTokenEvmSmartContract, _isTokenTransferredByEvm, _isTokenTransferredByTon } from '@subwallet/extension-base/services/chain-service/utils';
+import { _getAssetDecimals, _getAssetSymbol, _getChainNativeTokenBasicInfo, _getContractAddressOfToken, _getEvmChainId, _getTokenMinAmount, _getTokenOnChainAssetId, _getXcmAssetMultilocation, _isAssetSmartContractNft, _isBridgedToken, _isChainEvmCompatible, _isChainSubstrateCompatible, _isChainTonCompatible, _isCustomAsset, _isLocalToken, _isMantaZkAsset, _isNativeToken, _isPureEvmChain, _isTokenEvmSmartContract, _isTokenTransferredByCardano, _isTokenTransferredByEvm, _isTokenTransferredByTon } from '@subwallet/extension-base/services/chain-service/utils';
 import { ClaimPolygonBridgeNotificationMetadata, NotificationSetup } from '@subwallet/extension-base/services/inapp-notification-service/interfaces';
 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';
@@ -49,16 +51,15 @@ 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, BasicTxErrorType, BasicTxWarningCode, BuyServiceInfo, BuyTokenInfo, EarningRewardJson, NominationPoolInfo, OptimalYieldPathParams, RequestAccountBatchExportV2, RequestAccountCreateSuriV2, RequestAccountNameValidate, RequestBatchJsonGetAccountInfo, RequestBatchRestoreV2, RequestBounceableValidate, RequestChangeTonWalletContractVersion, RequestCheckPublicAndSecretKey, RequestCrossChainTransfer, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestEarlyValidateYield, RequestExportAccountProxyMnemonic, RequestGetAllTonWalletContractVersion, RequestGetDeriveAccounts, RequestGetDeriveSuggestion, RequestGetYieldPoolTargets, RequestInputAccountSubscribe, RequestJsonGetAccountInfo, RequestJsonRestoreV2, RequestMetadataHash, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestTransfer, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseAccountBatchExportV2, ResponseAccountCreateSuriV2, ResponseAccountNameValidate, ResponseBatchJsonGetAccountInfo, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseExportAccountProxyMnemonic, ResponseGetAllTonWalletContractVersion, ResponseGetDeriveAccounts, ResponseGetDeriveSuggestion, ResponseGetYieldPoolTargets, ResponseInputAccountSubscribe, ResponseJsonGetAccountInfo, ResponseMetadataHash, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2, ResponseShortenMetadata, StakingTxErrorType, StorageDataInterface, TokenSpendingApprovalParams, ValidateYieldProcessParams, YieldPoolType } from '@subwallet/extension-base/types';
+import { AccountJson, AccountProxyMap, AccountsWithCurrentAddress, BalanceJson, BasicTxErrorType, BasicTxWarningCode, BuyServiceInfo, BuyTokenInfo, EarningRewardJson, NominationPoolInfo, OptimalYieldPathParams, RequestAccountBatchExportV2, RequestAccountCreateSuriV2, RequestAccountNameValidate, RequestBatchJsonGetAccountInfo, RequestBatchRestoreV2, RequestBounceableValidate, RequestChangeTonWalletContractVersion, RequestCheckPublicAndSecretKey, RequestClaimBridge, RequestCrossChainTransfer, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestEarlyValidateYield, RequestExportAccountProxyMnemonic, RequestGetAllTonWalletContractVersion, RequestGetDeriveAccounts, RequestGetDeriveSuggestion, RequestGetYieldPoolTargets, RequestInputAccountSubscribe, RequestJsonGetAccountInfo, RequestJsonRestoreV2, RequestMetadataHash, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestTransfer, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseAccountBatchExportV2, ResponseAccountCreateSuriV2, ResponseAccountNameValidate, ResponseBatchJsonGetAccountInfo, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseExportAccountProxyMnemonic, ResponseGetAllTonWalletContractVersion, ResponseGetDeriveAccounts, ResponseGetDeriveSuggestion, ResponseGetYieldPoolTargets, ResponseInputAccountSubscribe, ResponseJsonGetAccountInfo, ResponseMetadataHash, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2, ResponseShortenMetadata, StakingTxErrorType, StorageDataInterface, TokenSpendingApprovalParams, ValidateYieldProcessParams, YieldPoolType } from '@subwallet/extension-base/types';
 import { RequestAccountProxyEdit, RequestAccountProxyForget } from '@subwallet/extension-base/types/account/action/edit';
-import { RequestClaimBridge } from '@subwallet/extension-base/types/bridge';
 import { GetNotificationParams, RequestIsClaimedPolygonBridge, RequestSwitchStatusParams } from '@subwallet/extension-base/types/notification';
 import { CommonOptimalPath } from '@subwallet/extension-base/types/service-base';
 import { SwapPair, SwapQuoteResponse, SwapRequest, SwapRequestResult, SwapSubmitParams, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap';
 import { _analyzeAddress, BN_ZERO, combineAllAccountProxy, createTransactionFromRLP, isSameAddress, MODULE_SUPPORT, reformatAddress, signatureToHex, toBNString, Transaction as QrTransaction, transformAccounts, transformAddresses, uniqueStringArray } from '@subwallet/extension-base/utils';
 import { parseContractInput, parseEvmRlp } from '@subwallet/extension-base/utils/eth/parseTransaction';
 import { MetadataDef } from '@subwallet/extension-inject/types';
-import { getKeypairTypeByAddress, isAddress, isSubstrateAddress, isTonAddress } from '@subwallet/keyring';
+import { getKeypairTypeByAddress, isAddress, isCardanoAddress, isSubstrateAddress, isTonAddress } from '@subwallet/keyring';
 import { EthereumKeypairTypes, SubstrateKeypairTypes, TonKeypairTypes } from '@subwallet/keyring/types';
 import { keyring } from '@subwallet/ui-keyring';
 import { SubjectInfo } from '@subwallet/ui-keyring/observable/types';
@@ -911,6 +912,24 @@ export default class KoniExtension {
     return true;
   }
 
+  private saveMigrationAcknowledgedStatus ({ isAcknowledgedUnifiedAccountMigration }: RequestSaveMigrationAcknowledgedStatus) {
+    this.#koniState.updateSetting('isAcknowledgedUnifiedAccountMigration', isAcknowledgedUnifiedAccountMigration);
+
+    return true;
+  }
+
+  private saveUnifiedAccountMigrationInProgress ({ isUnifiedAccountMigrationInProgress }: RequestSaveUnifiedAccountMigrationInProgress) {
+    this.#koniState.updateSetting('isUnifiedAccountMigrationInProgress', isUnifiedAccountMigrationInProgress);
+
+    return true;
+  }
+
+  private pingUnifiedAccountMigrationDone (): boolean {
+    this.#koniState.updateSetting('isUnifiedAccountMigrationInProgress', false);
+
+    return true;
+  }
+
   private setShowZeroBalance ({ show }: RequestChangeShowZeroBalance) {
     this.#koniState.updateSetting('isShowZeroBalance', show);
 
@@ -1362,10 +1381,25 @@ export default class KoniExtension {
           transferAll: !!transferAll, // currently not used
           tonApi
         });
+      } else if (isCardanoAddress(from) && isCardanoAddress(to) && _isTokenTransferredByCardano(transferTokenInfo)) {
+        chainType = ChainType.CARDANO;
+        const cardanoApi = this.#koniState.getCardanoApi(networkKey);
+
+        [transaction, transferAmount.value] = await createCardanoTransaction({
+          tokenInfo: transferTokenInfo,
+          from,
+          to,
+          networkKey,
+          value: value || '0',
+          cardanoTtlOffset: DEFAULT_CARDANO_TTL_OFFSET,
+          transferAll: !!transferAll,
+          cardanoApi,
+          nativeTokenInfo
+        });
       } else {
         const substrateApi = this.#koniState.getSubstrateApi(networkKey);
 
-        [transaction, transferAmount.value] = await createTransferExtrinsic({
+        [transaction, transferAmount.value] = await createSubstrateExtrinsic({
           transferAll: !!transferAll,
           value: value || '0',
           from: from,
@@ -1972,6 +2006,20 @@ export default class KoniExtension {
     return this.#koniState.getConfirmationsQueueSubjectTon().getValue();
   }
 
+  private subscribeConfirmationsCardano (id: string, port: chrome.runtime.Port) {
+    const cb = createSubscription<'pri(confirmationsCardano.subscribe)'>(id, port);
+
+    const subscription = this.#koniState.getConfirmationsQueueSubjectCardano().subscribe(cb);
+
+    this.createUnsubscriptionHandle(id, subscription.unsubscribe);
+
+    port.onDisconnect.addListener((): void => {
+      this.cancelSubscription(id);
+    });
+
+    return this.#koniState.getConfirmationsQueueSubjectCardano().getValue();
+  }
+
   private async completeConfirmation (request: RequestConfirmationComplete) {
     return await this.#koniState.completeConfirmation(request);
   }
@@ -1980,6 +2028,10 @@ export default class KoniExtension {
     return await this.#koniState.completeConfirmationTon(request);
   }
 
+  private async completeConfirmationCardano (request: RequestConfirmationCompleteCardano) {
+    return await this.#koniState.completeConfirmationCardano(request);
+  }
+
   /// Sign Qr
 
   private getNetworkJsonByChainId (chainId?: number): _ChainInfo | null {
@@ -3898,6 +3950,36 @@ export default class KoniExtension {
 
   /* Ledger */
 
+  /* Migrate Unified Account */
+  private async migrateUnifiedAndFetchEligibleSoloAccounts (request: RequestMigrateUnifiedAndFetchEligibleSoloAccounts): Promise<ResponseMigrateUnifiedAndFetchEligibleSoloAccounts> {
+    const setMigratingMode = () => {
+      this.saveUnifiedAccountMigrationInProgress({ isUnifiedAccountMigrationInProgress: true });
+    };
+
+    return await this.#koniState.keyringService.context.migrateUnifiedAndFetchEligibleSoloAccounts(request, setMigratingMode);
+  }
+
+  private async migrateSoloAccount (request: RequestMigrateSoloAccount): Promise<ResponseMigrateSoloAccount> {
+    const proxyIds = request.soloAccounts.map((account) => account.proxyId);
+
+    const response = this.#koniState.keyringService.context.migrateSoloAccount(request);
+    const newProxyId = response.migratedUnifiedAccountId; // get from response to ensure account migration is done.
+    const newName = request.accountName;
+
+    try {
+      this.#koniState.inappNotificationService.migrateNotificationProxyId(proxyIds, newProxyId, newName);
+    } catch (error) {
+      console.error('Error on migrating notification for unified account migration', error);
+    }
+
+    return response;
+  }
+
+  private pingSession (request: RequestPingSession): boolean {
+    return this.#koniState.keyringService.context.pingSession(request);
+  }
+  /* Migrate Unified Account */
+
   // --------------------------------------------------------------
   // eslint-disable-next-line @typescript-eslint/require-await
   public async handle<TMessageType extends MessageTypes> (id: string, type: TMessageType, request: RequestTypes[TMessageType], port: chrome.runtime.Port): Promise<ResponseType<TMessageType>> {
@@ -3994,6 +4076,12 @@ export default class KoniExtension {
         return this.setEnableChainPatrol(request as RequestChangeEnableChainPatrol);
       case 'pri(settings.saveNotificationSetup)':
         return this.saveNotificationSetup(request as NotificationSetup);
+      case 'pri(settings.saveMigrationAcknowledgedStatus)':
+        return this.saveMigrationAcknowledgedStatus(request as RequestSaveMigrationAcknowledgedStatus);
+      case 'pri(settings.saveUnifiedAccountMigrationInProgress)':
+        return this.saveUnifiedAccountMigrationInProgress(request as RequestSaveUnifiedAccountMigrationInProgress);
+      case 'pri(settings.pingUnifiedAccountMigrationDone)':
+        return this.pingUnifiedAccountMigrationDone();
       case 'pri(settings.saveShowZeroBalance)':
         return this.setShowZeroBalance(request as RequestChangeShowZeroBalance);
       case 'pri(settings.saveLanguage)':
@@ -4271,10 +4359,14 @@ export default class KoniExtension {
         return this.subscribeConfirmations(id, port);
       case 'pri(confirmationsTon.subscribe)':
         return this.subscribeConfirmationsTon(id, port);
+      case 'pri(confirmationsCardano.subscribe)':
+        return this.subscribeConfirmationsCardano(id, port);
       case 'pri(confirmations.complete)':
         return await this.completeConfirmation(request as RequestConfirmationComplete);
       case 'pri(confirmationsTon.complete)':
         return await this.completeConfirmationTon(request as RequestConfirmationCompleteTon);
+      case 'pri(confirmationsCardano.complete)':
+        return await this.completeConfirmationCardano(request as RequestConfirmationCompleteCardano);
 
       /// Stake
       case 'pri(bonding.getBondingOptions)':
@@ -4508,6 +4600,14 @@ export default class KoniExtension {
       case 'pri(ledger.generic.allow)':
         return this.subscribeLedgerGenericAllowChains(id, port);
         /* Ledger */
+
+        /* Migrate Unified Account */
+      case 'pri(migrate.migrateUnifiedAndFetchEligibleSoloAccounts)':
+        return await this.migrateUnifiedAndFetchEligibleSoloAccounts(request as RequestMigrateUnifiedAndFetchEligibleSoloAccounts);
+      case 'pri(migrate.migrateSoloAccount)':
+        return await this.migrateSoloAccount(request as RequestMigrateSoloAccount);
+      case 'pri(migrate.pingSession)':
+        return this.pingSession(request as RequestPingSession);
       // Default
       default:
         throw new Error(`Unable to handle message of type ${type}`);
diff --git a/packages/extension-base/src/koni/background/handlers/State.ts b/packages/extension-base/src/koni/background/handlers/State.ts
index 98a78580cd4..36885ac4d3d 100644
--- a/packages/extension-base/src/koni/background/handlers/State.ts
+++ b/packages/extension-base/src/koni/background/handlers/State.ts
@@ -6,7 +6,7 @@ import { EvmProviderError } from '@subwallet/extension-base/background/errors/Ev
 import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
 import { withErrorLog } from '@subwallet/extension-base/background/handlers/helpers';
 import { isSubscriptionRunning, unsubscribe } from '@subwallet/extension-base/background/handlers/subscriptions';
-import { AddTokenRequestExternal, AmountData, APIItemState, ApiMap, AuthRequestV2, ChainStakingMetadata, ChainType, ConfirmationsQueue, ConfirmationsQueueTon, CrowdloanItem, CrowdloanJson, CurrencyType, EvmProviderErrorType, EvmSendTransactionParams, EvmSendTransactionRequest, EvmSignatureRequest, ExternalRequestPromise, ExternalRequestPromiseStatus, ExtrinsicType, MantaAuthorizationContext, MantaPayConfig, MantaPaySyncState, NftCollection, NftItem, NftJson, NominatorMetadata, RequestAccountExportPrivateKey, RequestConfirmationComplete, RequestConfirmationCompleteTon, RequestCrowdloanContributions, RequestSettingsType, ResponseAccountExportPrivateKey, ServiceInfo, SingleModeJson, StakingItem, StakingJson, StakingRewardItem, StakingRewardJson, StakingType, UiSettings } from '@subwallet/extension-base/background/KoniTypes';
+import { AddTokenRequestExternal, AmountData, APIItemState, ApiMap, AuthRequestV2, ChainStakingMetadata, ChainType, ConfirmationsQueue, ConfirmationsQueueCardano, ConfirmationsQueueTon, CrowdloanItem, CrowdloanJson, CurrencyType, EvmProviderErrorType, EvmSendTransactionParams, EvmSendTransactionRequest, EvmSignatureRequest, ExternalRequestPromise, ExternalRequestPromiseStatus, ExtrinsicType, MantaAuthorizationContext, MantaPayConfig, MantaPaySyncState, NftCollection, NftItem, NftJson, NominatorMetadata, RequestAccountExportPrivateKey, RequestConfirmationComplete, RequestConfirmationCompleteCardano, RequestConfirmationCompleteTon, 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 { EnvConfig, MANTA_PAY_BALANCE_INTERVAL, REMIND_EXPORT_ACCOUNT } from '@subwallet/extension-base/constants';
 import { convertErrorFormat, generateValidationProcess, PayloadValidated, ValidateStepFunction, validationAuthMiddleware, validationAuthWCMiddleware, validationConnectMiddleware, validationEvmDataTransactionMiddleware, validationEvmSignMessageMiddleware } from '@subwallet/extension-base/core/logic-validation';
@@ -46,6 +46,7 @@ import { BalanceItem, BasicTxErrorType, CurrentAccountInfo, EvmFeeInfo, RequestC
 import { isManifestV3, stripUrl, targetIsWeb } from '@subwallet/extension-base/utils';
 import { createPromiseHandler } from '@subwallet/extension-base/utils/promise';
 import { MetadataDef, ProviderMeta } from '@subwallet/extension-inject/types';
+import subwalletApiSdk from '@subwallet/subwallet-api-sdk';
 import { keyring } from '@subwallet/ui-keyring';
 import BN from 'bn.js';
 import { t } from 'i18next';
@@ -141,6 +142,9 @@ export default class KoniState {
   private waitStarting: Promise<void> | null = null;
 
   constructor (providers: Providers = {}) {
+    // Init subwallet api sdk
+    subwalletApiSdk.init(process.env.SUBWALLET_API || '');
+
     this.providers = providers;
 
     this.eventService = new EventService();
@@ -925,6 +929,14 @@ export default class KoniState {
     return this.chainService.getTonApi(networkKey);
   }
 
+  public getCardanoApiMap () {
+    return this.chainService.getCardanoApiMap();
+  }
+
+  public getCardanoApi (networkKey: string) {
+    return this.chainService.getCardanoApi(networkKey);
+  }
+
   public getApiMap () {
     return {
       substrate: this.chainService.getSubstrateApiMap(),
@@ -1264,6 +1276,10 @@ export default class KoniState {
     return this.requestService.confirmationsQueueSubjectTon;
   }
 
+  public getConfirmationsQueueSubjectCardano (): BehaviorSubject<ConfirmationsQueueCardano> {
+    return this.requestService.confirmationsQueueSubjectCardano;
+  }
+
   public async completeConfirmation (request: RequestConfirmationComplete) {
     return await this.requestService.completeConfirmation(request);
   }
@@ -1272,6 +1288,10 @@ export default class KoniState {
     return await this.requestService.completeConfirmationTon(request);
   }
 
+  public async completeConfirmationCardano (request: RequestConfirmationCompleteCardano) {
+    return await this.requestService.completeConfirmationCardano(request);
+  }
+
   private async onMV3Update () {
     const migrationStatus = await SWStorage.instance.getItem('mv3_migration');
 
diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/cardano/consts.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/cardano/consts.ts
new file mode 100644
index 00000000000..70656418409
--- /dev/null
+++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/cardano/consts.ts
@@ -0,0 +1,4 @@
+// Copyright 2019-2022 @subwallet/extension-base
+// SPDX-License-Identifier: Apache-2.0
+
+export const DEFAULT_CARDANO_TTL_OFFSET = 2 * 60 * 60 * 1000; // 2 hours
diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/cardano/index.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/cardano/index.ts
new file mode 100644
index 00000000000..d159c0ea2a7
--- /dev/null
+++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/cardano/index.ts
@@ -0,0 +1,65 @@
+// 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 { CardanoBalanceItem } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/cardano/types';
+import { getCardanoAssetId } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/cardano/utils';
+import { _CardanoApi } from '@subwallet/extension-base/services/chain-service/types';
+import { BalanceItem, SusbcribeCardanoPalletBalance } from '@subwallet/extension-base/types';
+import { filterAssetsByChainAndType, reformatAddress } from '@subwallet/extension-base/utils';
+
+async function getBalanceMap (addresses: string[], cardanoApi: _CardanoApi, isTestnet: boolean): Promise<Record<string, CardanoBalanceItem[]>> {
+  const addressBalanceMap: Record<string, CardanoBalanceItem[]> = {};
+
+  for (const address of addresses) {
+    addressBalanceMap[address] = await cardanoApi.getBalanceMap(isTestnet ? reformatAddress(address, 0) : address);
+  }
+
+  return addressBalanceMap;
+}
+
+export function subscribeCardanoBalance (params: SusbcribeCardanoPalletBalance) {
+  const { addresses, assetMap, callback, cardanoApi, chainInfo } = params;
+  const chain = chainInfo.slug;
+  const isTestnet = chainInfo.isTestnet;
+  const tokens = filterAssetsByChainAndType(assetMap, chain, [_AssetType.NATIVE, _AssetType.CIP26]);
+
+  function getBalance () {
+    getBalanceMap(addresses, cardanoApi, isTestnet)
+      .then((addressBalanceMap) => {
+        Object.values(tokens).forEach((tokenInfo) => {
+          const id = getCardanoAssetId(tokenInfo);
+          const balances = addresses.map((address) => {
+            if (!addressBalanceMap[address]) {
+              return '0';
+            }
+
+            return addressBalanceMap[address].find((asset) => asset.unit === id)?.quantity || '0';
+          });
+
+          const items: BalanceItem[] = balances.map((balance, index): BalanceItem => {
+            return {
+              address: addresses[index],
+              tokenSlug: tokenInfo.slug,
+              free: balance,
+              locked: '0', // todo: research cardano lock balance
+              state: APIItemState.READY
+            };
+          });
+
+          callback(items);
+        });
+      })
+      .catch((e) => console.error('Error while fetching cardano balance', e));
+  }
+
+  const interval = setInterval(getBalance, ASTAR_REFRESH_BALANCE_INTERVAL);
+
+  getBalance();
+
+  return () => {
+    clearInterval(interval);
+  };
+}
diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/cardano/types.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/cardano/types.ts
new file mode 100644
index 00000000000..14723354849
--- /dev/null
+++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/cardano/types.ts
@@ -0,0 +1,40 @@
+// Copyright 2019-2022 @subwallet/extension-base
+// SPDX-License-Identifier: Apache-2.0
+
+export interface CardanoAddressBalance {
+  address: string;
+  amount: CardanoBalanceItem[],
+  stake_address: string,
+  type: string, // todo: consider create interface for type
+  script: boolean
+}
+
+export interface CardanoBalanceItem {
+  unit: string,
+  quantity: string
+}
+
+export interface CardanoTxJson {
+  body: {
+    inputs: CardanoTxInput[],
+    outputs: CardanoTxOutput[],
+    fee: string,
+    ttl: string
+  }
+  witness_set: any,
+  is_valid: any,
+  auxiliary_data: any
+}
+
+export interface CardanoTxOutput {
+  address: string,
+  amount: {
+    coin: string,
+    multiasset: Record<string, Record<string, string>>;
+  }
+}
+
+interface CardanoTxInput {
+  transaction_id: string,
+  index: number
+}
diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/cardano/utils.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/cardano/utils.ts
new file mode 100644
index 00000000000..1b6c68ff016
--- /dev/null
+++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/cardano/utils.ts
@@ -0,0 +1,78 @@
+// Copyright 2019-2022 @subwallet/extension-base
+// SPDX-License-Identifier: Apache-2.0
+
+import { Transaction } from '@emurgo/cardano-serialization-lib-nodejs';
+import { _ChainAsset } from '@subwallet/chain-list/types';
+import { CardanoTxOutput } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/cardano/types';
+
+export function getCardanoAssetId (chainAsset: _ChainAsset): string {
+  return chainAsset.metadata?.cardanoId as string;
+}
+
+export function getCardanoTxFee (payload: string) {
+  return BigInt(Transaction.from_hex(payload).body().fee().to_str());
+}
+
+export function getAdaBelongUtxo (payload: string, receiverAddress: string) {
+  const txOutputsRaw = Transaction.from_hex(payload).body().outputs().to_json();
+  const txOutputs = JSON.parse(txOutputsRaw) as CardanoTxOutput[];
+  const receiverUtxo = txOutputs.find((utxo) => utxo.address === receiverAddress); // must has utxo to receiver
+
+  // @ts-ignore
+  return BigInt(receiverUtxo.amount.coin);
+}
+
+export const cborToBytes = (hex: string): Uint8Array => {
+  if (hex.length % 2 === 0 && /^[0-9A-F]*$/i.test(hex)) {
+    return Buffer.from(hex, 'hex');
+  }
+
+  return Buffer.from(hex, 'utf-8');
+};
+
+export async function retryCardanoTxStatus (fn: () => Promise<boolean>, options: { retries: number, delay: number }): Promise<boolean> {
+  let lastError: Error | undefined;
+
+  for (let i = 0; i < options.retries; i++) {
+    try {
+      return await fn();
+    } catch (e) {
+      if (e instanceof Error) {
+        lastError = e;
+      }
+
+      // todo: improve the timeout tx
+      await new Promise((resolve) => setTimeout(resolve, options.delay)); // wait for delay period, then recall the fn()
+    }
+  }
+
+  console.error('Cardano transaction timeout', lastError); // throw only last error, in case no successful result from fn()
+
+  return false;
+}
+
+export interface CardanoAssetMetadata {
+  cardanoId: string;
+  policyId: string;
+  nameHex: string;
+}
+
+export function splitCardanoId (id: string): CardanoAssetMetadata {
+  if (id === 'lovelace') {
+    return {
+      cardanoId: id,
+      policyId: '',
+      nameHex: ''
+    };
+  }
+
+  if (!id || id.length < 56) {
+    throw new Error('The cardano native asset policy id must has 28 bytes in length.');
+  } else {
+    return {
+      cardanoId: id,
+      policyId: id.slice(0, 56),
+      nameHex: id.slice(56)
+    };
+  }
+}
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 b9c96ec8810..71eb63b1953 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,11 @@
 
 import { _AssetType, _ChainAsset, _ChainInfo } from '@subwallet/chain-list/types';
 import { APIItemState, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
-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 { subscribeCardanoBalance } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/cardano';
+import { _CardanoApi, _EvmApi, _SubstrateApi, _TonApi } from '@subwallet/extension-base/services/chain-service/types';
+import { _getSubstrateGenesisHash, _isChainBitcoinCompatible, _isChainCardanoCompatible, _isChainEvmCompatible, _isChainTonCompatible, _isPureCardanoChain, _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 { filterAssetsByChainAndType, getAddressesByChainTypeMap, pairToAccount } from '@subwallet/extension-base/utils';
 import keyring from '@subwallet/ui-keyring';
 
 import { subscribeTonBalance } from './ton/ton';
@@ -40,14 +41,16 @@ export const getAccountJsonByAddress = (address: string): AccountJson | null =>
 
 /** Filter addresses to subscribe by chain info */
 const filterAddress = (addresses: string[], chainInfo: _ChainInfo): [string[], string[]] => {
-  const { bitcoin, evm, substrate, ton } = categoryAddresses(addresses);
+  const { bitcoin, cardano, evm, substrate, ton } = getAddressesByChainTypeMap(addresses);
 
   if (_isChainEvmCompatible(chainInfo)) {
-    return [evm, [...bitcoin, ...substrate, ...ton]];
+    return [evm, [...bitcoin, ...substrate, ...ton, ...cardano]];
   } else if (_isChainBitcoinCompatible(chainInfo)) {
-    return [bitcoin, [...evm, ...substrate, ...ton]];
+    return [bitcoin, [...evm, ...substrate, ...ton, ...cardano]];
   } else if (_isChainTonCompatible(chainInfo)) {
-    return [ton, [...bitcoin, ...evm, ...substrate]];
+    return [ton, [...bitcoin, ...evm, ...substrate, ...cardano]];
+  } else if (_isChainCardanoCompatible(chainInfo)) {
+    return [cardano, [...bitcoin, ...evm, ...substrate, ...ton]];
   } else {
     const fetchList: string[] = [];
     const unfetchList: string[] = [];
@@ -77,7 +80,7 @@ const filterAddress = (addresses: string[], chainInfo: _ChainInfo): [string[], s
       }
     });
 
-    return [fetchList, [...unfetchList, ...bitcoin, ...evm, ...ton]];
+    return [fetchList, [...unfetchList, ...bitcoin, ...evm, ...ton, ...cardano]];
   }
 };
 
@@ -94,7 +97,9 @@ const handleUnsupportedOrPendingAddresses = (
     _AssetType.PSP22,
     _AssetType.LOCAL,
     _AssetType.GRC20,
-    _AssetType.VFT
+    _AssetType.VFT,
+    _AssetType.TEP74,
+    _AssetType.CIP26
   ]);
 
   const now = new Date().getTime();
@@ -123,6 +128,7 @@ export function subscribeBalance (
   substrateApiMap: Record<string, _SubstrateApi>,
   evmApiMap: Record<string, _EvmApi>,
   tonApiMap: Record<string, _TonApi>,
+  cardanoApiMap: Record<string, _CardanoApi>,
   callback: (rs: BalanceItem[]) => void,
   extrinsicType?: ExtrinsicType
 ) {
@@ -169,6 +175,18 @@ export function subscribeBalance (
       });
     }
 
+    const cardanoApi = cardanoApiMap[chainSlug];
+
+    if (_isPureCardanoChain(chainInfo)) {
+      return subscribeCardanoBalance({
+        addresses: useAddresses,
+        assetMap: chainAssetMap,
+        callback,
+        chainInfo,
+        cardanoApi
+      });
+    }
+
     // If the chain is not ready, return pending state
     if (!substrateApiMap[chainSlug].isApiReady) {
       handleUnsupportedOrPendingAddresses(
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 40dd534eaa9..935d1218557 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
@@ -41,7 +41,7 @@ export function externalMessage (contract: TonWalletContract, seqno: number, bod
     .endCell();
 }
 
-export async function retry<T> (fn: () => Promise<T>, options: { retries: number, delay: number }): Promise<T> {
+export async function retryTonTxStatus<T> (fn: () => Promise<T>, options: { retries: number, delay: number }): Promise<T> {
   let lastError: Error | undefined;
 
   for (let i = 0; i < options.retries; i++) {
diff --git a/packages/extension-base/src/services/balance-service/index.ts b/packages/extension-base/src/services/balance-service/index.ts
index 9db8df64e1b..2d3a81f9407 100644
--- a/packages/extension-base/src/services/balance-service/index.ts
+++ b/packages/extension-base/src/services/balance-service/index.ts
@@ -220,10 +220,11 @@ export class BalanceService implements StoppableServiceInterface {
       const evmApiMap = this.state.chainService.getEvmApiMap();
       const substrateApiMap = this.state.chainService.getSubstrateApiMap();
       const tonApiMap = this.state.chainService.getTonApiMap();
+      const cardanoApiMap = this.state.chainService.getCardanoApiMap();
 
       let unsub = noop;
 
-      unsub = subscribeBalance([address], [chain], [tSlug], assetMap, chainInfoMap, substrateApiMap, evmApiMap, tonApiMap, (result) => {
+      unsub = subscribeBalance([address], [chain], [tSlug], assetMap, chainInfoMap, substrateApiMap, evmApiMap, tonApiMap, cardanoApiMap, (result) => {
         const rs = result[0];
 
         let value: string;
@@ -398,6 +399,7 @@ export class BalanceService implements StoppableServiceInterface {
     const evmApiMap = this.state.chainService.getEvmApiMap();
     const substrateApiMap = this.state.chainService.getSubstrateApiMap();
     const tonApiMap = this.state.chainService.getTonApiMap();
+    const cardanoApiMap = this.state.chainService.getCardanoApiMap();
 
     const activeChainSlugs = Object.keys(this.state.getActiveChainInfoMap());
     const assetState = this.state.chainService.subscribeAssetSettings().value;
@@ -407,7 +409,7 @@ export class BalanceService implements StoppableServiceInterface {
       })
       .map((asset) => asset.slug);
 
-    const unsub = subscribeBalance(addresses, activeChainSlugs, assets, assetMap, chainInfoMap, substrateApiMap, evmApiMap, tonApiMap, (result) => {
+    const unsub = subscribeBalance(addresses, activeChainSlugs, assets, assetMap, chainInfoMap, substrateApiMap, evmApiMap, tonApiMap, cardanoApiMap, (result) => {
       !cancel && this.setBalanceItem(result);
     }, ExtrinsicType.TRANSFER_BALANCE);
 
diff --git a/packages/extension-base/src/services/balance-service/transfer/cardano-transfer.ts b/packages/extension-base/src/services/balance-service/transfer/cardano-transfer.ts
new file mode 100644
index 00000000000..ab7feac3922
--- /dev/null
+++ b/packages/extension-base/src/services/balance-service/transfer/cardano-transfer.ts
@@ -0,0 +1,159 @@
+// Copyright 2019-2022 @subwallet/extension-base
+// SPDX-License-Identifier: Apache-2.0
+
+import * as csl from '@emurgo/cardano-serialization-lib-nodejs';
+import { _AssetType, _ChainAsset } from '@subwallet/chain-list/types';
+import { CardanoTxJson, CardanoTxOutput } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/cardano/types';
+import { CardanoAssetMetadata, getAdaBelongUtxo, getCardanoTxFee, splitCardanoId } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/cardano/utils';
+import { _CardanoApi } from '@subwallet/extension-base/services/chain-service/types';
+import { subwalletApiSdk } from '@subwallet/subwallet-api-sdk';
+
+export interface CardanoTransactionConfigProps {
+  tokenInfo: _ChainAsset;
+  nativeTokenInfo: _ChainAsset;
+  from: string,
+  to: string,
+  networkKey: string,
+  value: string,
+  transferAll: boolean,
+  cardanoTtlOffset: number,
+  cardanoApi: _CardanoApi
+}
+
+export interface CardanoTransactionConfig {
+  from: string,
+  to: string,
+  networkKey: string,
+  value: string,
+  transferAll: boolean,
+  cardanoTtlOffset: number,
+  estimateCardanoFee: string,
+  cardanoPayload: string // hex unsigned tx
+}
+
+export async function createCardanoTransaction (params: CardanoTransactionConfigProps): Promise<[CardanoTransactionConfig | null, string]> {
+  const { cardanoTtlOffset, from, networkKey, to, tokenInfo, transferAll, value } = params;
+
+  const cardanoId = tokenInfo.metadata?.cardanoId;
+  const isNativeTransfer = tokenInfo.assetType === _AssetType.NATIVE;
+  const isSelfTransfer = from === to;
+
+  if (!cardanoId) {
+    throw new Error('Missing token policy id metadata');
+  }
+
+  const payload = await subwalletApiSdk.fetchUnsignedPayload({
+    tokenDecimals: params.tokenInfo.decimals || 0,
+    nativeTokenSymbol: params.nativeTokenInfo.symbol,
+    cardanoId,
+    from: params.from,
+    to: params.to,
+    value: params.value,
+    cardanoTtlOffset: params.cardanoTtlOffset
+  });
+
+  console.log('Build cardano payload successfully!', payload);
+
+  validatePayload(payload, params);
+
+  const fee = getCardanoTxFee(payload);
+  const adaBelongToCnaUtxo = isNativeTransfer || isSelfTransfer ? BigInt(0) : getAdaBelongUtxo(payload, to);
+
+  const tx: CardanoTransactionConfig = {
+    from,
+    to,
+    networkKey,
+    value,
+    transferAll,
+    cardanoTtlOffset,
+    estimateCardanoFee: (fee + adaBelongToCnaUtxo).toString(),
+    cardanoPayload: payload
+  };
+
+  return [tx, value];
+}
+
+function validatePayload (payload: string, params: CardanoTransactionConfigProps) {
+  const txInfo = JSON.parse(csl.Transaction.from_hex(payload).to_json()) as CardanoTxJson;
+  const outputs = txInfo.body.outputs;
+  const cardanoId = params.tokenInfo.metadata?.cardanoId;
+  const assetType = params.tokenInfo.assetType;
+  const isSendSameAddress = params.from === params.to;
+
+  if (!cardanoId) {
+    throw new Error('Missing cardano id metadata');
+  }
+
+  const cardanoAssetMetadata = splitCardanoId(cardanoId);
+
+  if (isSendSameAddress) {
+    validateAllOutputsBelongToAddress(params.from, outputs);
+    validateExistOutputWithAmountSend(params.value, outputs, assetType, cardanoAssetMetadata);
+  } else {
+    const [outputsBelongToReceiver, outputsNotBelongToReceiver] = [
+      outputs.filter((output) => output.address === params.to),
+      outputs.filter((output) => output.address !== params.to)
+    ];
+
+    validateReceiverOutputsWithAmountSend(params.value, outputsBelongToReceiver, assetType, cardanoAssetMetadata);
+    validateAllOutputsBelongToAddress(params.from, outputsNotBelongToReceiver);
+  }
+}
+
+function validateAllOutputsBelongToAddress (address: string, outputs: CardanoTxOutput[]) {
+  const found = outputs.find((output) => output.address !== address);
+
+  if (found) {
+    throw new Error('Transaction has invalid address information');
+  }
+}
+
+function validateExistOutputWithAmountSend (amount: string, outputs: CardanoTxOutput[], assetType: _AssetType, cardanoAssetMetadata: CardanoAssetMetadata) {
+  if (assetType === _AssetType.NATIVE) {
+    const found = outputs.find((output) => output.amount.coin === amount);
+
+    if (found) {
+      return;
+    }
+
+    throw new Error('Transaction has invalid transfer amount information');
+  }
+
+  if (assetType === _AssetType.CIP26) {
+    const found = outputs.find((output) => amount === output.amount.multiasset[cardanoAssetMetadata.policyId]?.[cardanoAssetMetadata.nameHex]);
+
+    if (found) {
+      return;
+    }
+
+    throw new Error('Transaction has invalid transfer amount information');
+  }
+
+  throw new Error('Invalid asset type!');
+}
+
+function validateReceiverOutputsWithAmountSend (amount: string, outputs: CardanoTxOutput[], assetType: _AssetType, cardanoAssetMetadata: CardanoAssetMetadata) {
+  if (outputs.length !== 1) {
+    throw new Error('Transaction has invalid transfer amount information');
+  }
+
+  const receiverOutput = outputs[0];
+
+  if (assetType === _AssetType.NATIVE) {
+    if (receiverOutput.amount.coin === amount) {
+      return;
+    }
+
+    throw new Error('Transaction has invalid transfer amount information');
+  }
+
+  if (assetType === _AssetType.CIP26) {
+    if (receiverOutput.amount.multiasset[cardanoAssetMetadata.policyId][cardanoAssetMetadata.nameHex] === amount) {
+      return;
+    }
+
+    throw new Error('Transaction has invalid transfer amount information');
+  }
+
+  throw new Error('Invalid asset type!');
+}
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 79da9c13c41..9286156669a 100644
--- a/packages/extension-base/src/services/balance-service/transfer/token.ts
+++ b/packages/extension-base/src/services/balance-service/transfer/token.ts
@@ -31,7 +31,7 @@ interface CreateTransferExtrinsicProps {
   tokenInfo: _ChainAsset,
 }
 
-export const createTransferExtrinsic = async ({ from, networkKey, substrateApi, to, tokenInfo, transferAll, value }: CreateTransferExtrinsicProps): Promise<[SubmittableExtrinsic | null, string]> => {
+export const createSubstrateExtrinsic = async ({ from, networkKey, substrateApi, to, tokenInfo, transferAll, value }: CreateTransferExtrinsicProps): Promise<[SubmittableExtrinsic | null, string]> => {
   const api = substrateApi.api;
 
   const isDisableTransfer = tokenInfo.metadata?.isDisableTransfer as boolean;
@@ -161,7 +161,7 @@ export const getTransferMockTxFee = async (address: string, chainInfo: _ChainInf
     } else {
       const substrateApi = api as _SubstrateApi;
       const chainApi = await substrateApi.isReady;
-      const [mockTx] = await createTransferExtrinsic({
+      const [mockTx] = await createSubstrateExtrinsic({
         from: address,
         networkKey: chainInfo.slug,
         substrateApi: chainApi,
diff --git a/packages/extension-base/src/services/chain-service/handler/CardanoApi.ts b/packages/extension-base/src/services/chain-service/handler/CardanoApi.ts
new file mode 100644
index 00000000000..91384840d6c
--- /dev/null
+++ b/packages/extension-base/src/services/chain-service/handler/CardanoApi.ts
@@ -0,0 +1,213 @@
+// Copyright 2019-2022 @subwallet/extension-base authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import { CardanoAddressBalance, CardanoBalanceItem } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/cardano/types';
+import { cborToBytes, retryCardanoTxStatus } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/cardano/utils';
+import { _ApiOptions } from '@subwallet/extension-base/services/chain-service/handler/types';
+import { _CardanoApi, _ChainConnectionStatus } from '@subwallet/extension-base/services/chain-service/types';
+import { createPromiseHandler, PromiseHandler } from '@subwallet/extension-base/utils';
+import { BehaviorSubject } from 'rxjs';
+
+import { hexAddPrefix, isHex } from '@polkadot/util';
+
+export const API_KEY = { // todo: move to env.
+  mainnet: 'mainnet6uE9JH3zGYquaxRKA7IMhEuzRUB58uGK',
+  testnet: 'preprodcnP5RADcrWMlf2cQe4ZKm4cjRvrBQFXM'
+};
+
+export class CardanoApi implements _CardanoApi {
+  chainSlug: string;
+  // private api: BlockFrostAPI;
+  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<_CardanoApi>;
+  isTestnet: boolean; // todo: add api with interface BlockFrostAPI to remove isTestnet check
+  private projectId: string;
+
+  providerName: string;
+
+  constructor (chainSlug: string, apiUrl: string, { isTestnet, providerName }: _ApiOptions) {
+    this.chainSlug = chainSlug;
+    this.apiUrl = apiUrl;
+    this.isTestnet = isTestnet ?? true;
+    this.projectId = isTestnet ? API_KEY.testnet : API_KEY.mainnet;
+    this.providerName = providerName || 'unknown';
+    // this.api = this.createProvider(isTestnet);
+    this.isReadyHandler = createPromiseHandler<_CardanoApi>();
+
+    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<_CardanoApi> {
+    return this.isReadyHandler.promise;
+  }
+
+  async updateApiUrl (apiUrl: string) {
+    if (this.apiUrl === apiUrl) {
+      return;
+    }
+
+    await this.disconnect();
+
+    this.apiUrl = apiUrl;
+    // this.api = this.createProvider();
+  }
+
+  async recoverConnect () {
+    await this.disconnect();
+    this.connect();
+
+    await this.isReadyHandler.promise;
+  }
+
+  // private createProvider (isTestnet = true): BlockFrostAPI {
+  //   const projectId = isTestnet ? API_KEY.testnet : API_KEY.mainnet;
+  //
+  //   return new BlockFrostAPI({
+  //     projectId
+  //   });
+  // }
+
+  connect (): void {
+    this.updateConnectionStatus(_ChainConnectionStatus.CONNECTING);
+    // 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}`);
+      this.isApiReady = false;
+      this.isReadyHandler = createPromiseHandler<_CardanoApi>();
+    }
+  }
+
+  async getBalanceMap (address: string): Promise<CardanoBalanceItem[]> {
+    try {
+      const url = this.isTestnet ? `https://cardano-preprod.blockfrost.io/api/v0/addresses/${address}` : `https://cardano-mainnet.blockfrost.io/api/v0/addresses/${address}`;
+      const response = await fetch(
+        url, {
+          method: 'GET',
+          headers: {
+            Project_id: this.projectId
+          }
+        }
+      );
+
+      const addressBalance = await response.json() as CardanoAddressBalance;
+
+      return addressBalance.amount;
+    } catch (e) {
+      console.error('Error on getting account balance', e);
+
+      return [];
+    }
+  }
+
+  async sendCardanoTxReturnHash (tx: string): Promise<string> {
+    try {
+      const url = this.isTestnet ? 'https://cardano-preprod.blockfrost.io/api/v0/tx/submit' : 'https://cardano-mainnet.blockfrost.io/api/v0/tx/submit';
+      const response = await fetch(
+        url, {
+          method: 'POST',
+          headers: {
+            Project_id: this.projectId,
+            'Content-Type': 'application/cbor'
+          },
+          body: cborToBytes(tx)
+        }
+      );
+
+      const hash = (await response.text()).replace(/^"|"$/g, '');
+
+      if (isHex(hexAddPrefix(hash))) {
+        return hash;
+      } else {
+        console.error('Error on submitting cardano tx');
+
+        return '';
+      }
+    } catch (e) {
+      console.error('Error on submitting cardano tx', e);
+
+      return '';
+    }
+  }
+
+  async getStatusByTxHash (txHash: string, ttl: number): Promise<boolean> {
+    const cronTime = 30000;
+
+    return retryCardanoTxStatus(async () => {
+      const url = this.isTestnet ? `https://cardano-preprod.blockfrost.io/api/v0/txs/${txHash}` : `https://cardano-mainnet.blockfrost.io/api/v0/txs/${txHash}`;
+      const response = await fetch(
+        url, {
+          method: 'GET',
+          headers: {
+            Project_id: this.projectId
+          }
+        }
+      );
+
+      const txInfo = await response.json() as { hash: string, block: string, index: number };
+
+      if (txInfo.block && txInfo.hash && txInfo.index >= 0) {
+        return true;
+      }
+
+      throw new Error('Transaction not found');
+    }, { retries: ttl / cronTime, delay: cronTime });
+  }
+}
diff --git a/packages/extension-base/src/services/chain-service/handler/CardanoChainHandler.ts b/packages/extension-base/src/services/chain-service/handler/CardanoChainHandler.ts
new file mode 100644
index 00000000000..4544e9b9c7e
--- /dev/null
+++ b/packages/extension-base/src/services/chain-service/handler/CardanoChainHandler.ts
@@ -0,0 +1,93 @@
+// 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 { CardanoApi } from '@subwallet/extension-base/services/chain-service/handler/CardanoApi';
+import { _ApiOptions } from '@subwallet/extension-base/services/chain-service/handler/types';
+
+export class CardanoChainHandler extends AbstractChainHandler {
+  private cardanoApiMap: Record<string, CardanoApi> = {};
+
+  // eslint-disable-next-line no-useless-constructor
+  constructor (parent?: ChainService) {
+    super(parent);
+  }
+
+  public getCardanoApiMap () {
+    return this.cardanoApiMap;
+  }
+
+  public getCardanoApiByChain (chain: string) {
+    return this.cardanoApiMap[chain];
+  }
+
+  public getApiByChain (chain: string) {
+    return this.getCardanoApiByChain(chain);
+  }
+
+  public setCardanoApi (chain: string, cardanoApi: CardanoApi) {
+    this.cardanoApiMap[chain] = cardanoApi;
+  }
+
+  public async initApi (chainSlug: string, apiUrl: string, { isTestnet, onUpdateStatus, providerName }: Omit<_ApiOptions, 'metadata'> = {}) {
+    const existed = this.getCardanoApiByChain(chainSlug);
+
+    if (existed) {
+      existed.connect();
+
+      if (apiUrl !== existed.apiUrl) {
+        existed.updateApiUrl(apiUrl).catch(console.error);
+      }
+
+      return existed;
+    }
+
+    const apiObject = new CardanoApi(chainSlug, apiUrl, { isTestnet, providerName });
+
+    apiObject.connectionStatusSubject.subscribe(this.handleConnection.bind(this, chainSlug));
+    apiObject.connectionStatusSubject.subscribe(onUpdateStatus);
+
+    return Promise.resolve(apiObject);
+  }
+
+  public async recoverApi (chain: string): Promise<void> {
+    const existed = this.getCardanoApiByChain(chain);
+
+    if (existed && !existed.isApiReadyOnce) {
+      console.log(`Reconnect ${existed.providerName || existed.chainSlug} at ${existed.apiUrl}`);
+
+      return existed.recoverConnect();
+    }
+  }
+
+  destroyCardanoApi (chain: string) {
+    const cardanoApi = this.getCardanoApiByChain(chain);
+
+    cardanoApi?.destroy().catch(console.error);
+  }
+
+  async sleep () {
+    this.isSleeping = true;
+    this.cancelAllRecover();
+
+    await Promise.all(Object.values(this.getCardanoApiMap()).map((cardanoApi) => {
+      return cardanoApi.disconnect().catch(console.error);
+    }));
+
+    return Promise.resolve();
+  }
+
+  wakeUp () {
+    this.isSleeping = false;
+    const activeChains = this.parent?.getActiveChains() || [];
+
+    for (const chain of activeChains) {
+      const cardanoApi = this.getCardanoApiByChain(chain);
+
+      cardanoApi?.connect();
+    }
+
+    return Promise.resolve();
+  }
+}
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 3ce683aef15..009a75a0ade 100644
--- a/packages/extension-base/src/services/chain-service/handler/TonApi.ts
+++ b/packages/extension-base/src/services/chain-service/handler/TonApi.ts
@@ -4,7 +4,7 @@
 import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
 import { TON_CENTER_API_KEY, TON_OPCODES } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/consts';
 import { AccountState, TxByMsgResponse } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/types';
-import { getJettonTxStatus, retry } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/utils';
+import { getJettonTxStatus, retryTonTxStatus } 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';
@@ -70,10 +70,7 @@ export class TonApi implements _TonApi {
 
     // Create new provider and api
     this.apiUrl = apiUrl;
-    this.api = new TonClient({
-      endpoint: this.getJsonRpc(this.apiUrl),
-      apiKey: TON_CENTER_API_KEY
-    });
+    this.api = this.createProvider(apiUrl);
   }
 
   async recoverConnect () {
@@ -204,7 +201,7 @@ export class TonApi implements _TonApi {
   }
 
   async getStatusByExtMsgHash (extMsgHash: string, extrinsicType?: ExtrinsicType): Promise<[boolean, string]> {
-    return retry<[boolean, string]>(async () => { // retry many times to get transaction status and transaction hex
+    return retryTonTxStatus<[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/chain-service/handler/types.ts b/packages/extension-base/src/services/chain-service/handler/types.ts
index 8f95d2b6224..485d740bc03 100644
--- a/packages/extension-base/src/services/chain-service/handler/types.ts
+++ b/packages/extension-base/src/services/chain-service/handler/types.ts
@@ -29,6 +29,7 @@ export interface _ApiOptions {
   metadata?: MetadataItem,
   onUpdateStatus?: (status: _ChainConnectionStatus) => void,
   externalApiPromise?: ApiPromise
+  isTestnet?: boolean
 }
 
 export enum _CHAIN_VALIDATION_ERROR {
diff --git a/packages/extension-base/src/services/chain-service/index.ts b/packages/extension-base/src/services/chain-service/index.ts
index 4b836160aa6..e8db247a8af 100644
--- a/packages/extension-base/src/services/chain-service/index.ts
+++ b/packages/extension-base/src/services/chain-service/index.ts
@@ -2,9 +2,10 @@
 // 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, _TonInfo } from '@subwallet/chain-list/types';
+import { _AssetRef, _AssetRefPath, _AssetType, _CardanoInfo, _ChainAsset, _ChainInfo, _ChainStatus, _EvmInfo, _MultiChainAsset, _SubstrateChainType, _SubstrateInfo, _TonInfo } from '@subwallet/chain-list/types';
 import { AssetSetting, MetadataItem, 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 { CardanoChainHandler } from '@subwallet/extension-base/services/chain-service/handler/CardanoChainHandler';
 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';
@@ -73,6 +74,7 @@ export class ChainService {
   private substrateChainHandler: SubstrateChainHandler;
   private evmChainHandler: EvmChainHandler;
   private tonChainHandler: TonChainHandler;
+  private cardanoChainHandler: CardanoChainHandler;
   private mantaChainHandler: MantaPrivateHandler | undefined;
 
   refreshLatestChainDataTimeOut: NodeJS.Timer | undefined;
@@ -117,6 +119,7 @@ export class ChainService {
     this.substrateChainHandler = new SubstrateChainHandler(this);
     this.evmChainHandler = new EvmChainHandler(this);
     this.tonChainHandler = new TonChainHandler(this);
+    this.cardanoChainHandler = new CardanoChainHandler(this);
 
     this.logger = createLogger('chain-service');
   }
@@ -202,6 +205,14 @@ export class ChainService {
     return this.tonChainHandler.getTonApiMap();
   }
 
+  public getCardanoApi (slug: string) {
+    return this.cardanoChainHandler.getCardanoApiByChain(slug);
+  }
+
+  public getCardanoApiMap () {
+    return this.cardanoChainHandler.getCardanoApiMap();
+  }
+
   public getChainCurrentProviderByKey (slug: string) {
     const providerName = this.getChainStateByKey(slug).currentProvider;
     const providerMap = this.getChainInfoByKey(slug).providers;
@@ -896,6 +907,14 @@ export class ChainService {
 
       this.tonChainHandler.setTonApi(chainInfo.slug, chainApi);
     }
+
+    if (chainInfo.cardanoInfo !== null && chainInfo.cardanoInfo !== undefined) {
+      const isTestnet = chainInfo.isTestnet;
+
+      const chainApi = await this.cardanoChainHandler.initApi(chainInfo.slug, endpoint, { isTestnet, providerName, onUpdateStatus });
+
+      this.cardanoChainHandler.setCardanoApi(chainInfo.slug, chainApi);
+    }
   }
 
   private destroyApiForChain (chainInfo: _ChainInfo) {
@@ -910,6 +929,10 @@ export class ChainService {
     if (chainInfo.tonInfo !== null) {
       this.tonChainHandler.destroyTonApi(chainInfo.slug);
     }
+
+    if (chainInfo.cardanoInfo !== null) {
+      this.cardanoChainHandler.destroyCardanoApi(chainInfo.slug);
+    }
   }
 
   public async enableChain (chainSlug: string) {
@@ -1223,6 +1246,7 @@ export class ChainService {
               substrateInfo: storedChainInfo.substrateInfo,
               bitcoinInfo: storedChainInfo.bitcoinInfo ?? null,
               tonInfo: storedChainInfo.tonInfo,
+              cardanoInfo: storedChainInfo.cardanoInfo ?? null,
               isTestnet: storedChainInfo.isTestnet,
               chainStatus: storedChainInfo.chainStatus,
               icon: storedChainInfo.icon,
@@ -1251,6 +1275,7 @@ export class ChainService {
             substrateInfo: storedChainInfo.substrateInfo,
             bitcoinInfo: storedChainInfo.bitcoinInfo ?? null,
             tonInfo: storedChainInfo.tonInfo,
+            cardanoInfo: storedChainInfo.cardanoInfo ?? null,
             isTestnet: storedChainInfo.isTestnet,
             chainStatus: storedChainInfo.chainStatus,
             icon: storedChainInfo.icon,
@@ -1455,6 +1480,7 @@ export class ChainService {
     let substrateInfo: _SubstrateInfo | null = null;
     let evmInfo: _EvmInfo | null = null;
     const tonInfo: _TonInfo | null = null;
+    const cardanoInfo: _CardanoInfo | null = null;
 
     if (params.chainSpec.genesisHash !== '') {
       substrateInfo = {
@@ -1494,6 +1520,7 @@ export class ChainService {
       evmInfo,
       bitcoinInfo: null,
       tonInfo,
+      cardanoInfo,
       isTestnet: false,
       chainStatus: _ChainStatus.ACTIVE,
       icon: '', // Todo: Allow update with custom chain,
@@ -1615,6 +1642,7 @@ export class ChainService {
         // TODO: EVM chain might have WS provider
         if (provider.startsWith('http')) {
           // todo: handle validate ton provider
+          // todo: handle validate cardano provider
 
           // HTTP provider is EVM by default
           api = await this.evmChainHandler.initApi('custom', provider);
@@ -1853,15 +1881,12 @@ export class ChainService {
     this.evmChainHandler.recoverApi(slug).catch(console.error);
   }
 
-  public refreshTonApi (slug: string) {
-    this.tonChainHandler.recoverApi(slug).catch(console.error);
-  }
-
   public async stopAllChainApis () {
     await Promise.all([
       this.substrateChainHandler.sleep(),
       this.evmChainHandler.sleep(),
-      this.tonChainHandler.sleep()
+      this.tonChainHandler.sleep(),
+      this.cardanoChainHandler.sleep()
     ]);
 
     this.stopCheckLatestChainData();
@@ -1871,7 +1896,8 @@ export class ChainService {
     await Promise.all([
       this.substrateChainHandler.wakeUp(),
       this.evmChainHandler.wakeUp(),
-      this.tonChainHandler.wakeUp()
+      this.tonChainHandler.wakeUp(),
+      this.cardanoChainHandler.wakeUp()
     ]);
 
     this.checkLatestData();
diff --git a/packages/extension-base/src/services/chain-service/types.ts b/packages/extension-base/src/services/chain-service/types.ts
index 5d0b84b84da..390f36fcb40 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 { CardanoBalanceItem } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/cardano/types';
 import { AccountState, 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 { TonWalletContract } from '@subwallet/keyring/types';
@@ -135,7 +136,7 @@ export interface _TonApi extends _ChainBaseApi, _TonUtilsApi {
   isReady: Promise<_TonApi>;
 }
 
-export interface _TonUtilsApi {
+interface _TonUtilsApi {
   getBalance (address: Address): Promise<bigint>;
   open<T extends Contract>(src: T): OpenedContract<T>;
   estimateExternalMessageFee (walletContract: TonWalletContract, body: Cell, isInit: boolean, ignoreSignature?: boolean): Promise<EstimateExternalMessageFee>;
@@ -145,6 +146,14 @@ export interface _TonUtilsApi {
   getAccountState (address: string): Promise<AccountState>;
 }
 
+export interface _CardanoApi extends _ChainBaseApi, _CardanoUtilsApi {
+  isReady: Promise<_CardanoApi>;
+}
+
+interface _CardanoUtilsApi {
+  getBalanceMap (address: string): Promise<CardanoBalanceItem[]>
+}
+
 export interface EstimateExternalMessageFee {
   source_fees: {
     in_fwd_fee: number,
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 5aeb6637a8f..c1c9694d1d5 100644
--- a/packages/extension-base/src/services/chain-service/utils/index.ts
+++ b/packages/extension-base/src/services/chain-service/utils/index.ts
@@ -62,15 +62,19 @@ export function _isEqualSmartContractAsset (asset1: _ChainAsset, asset2: _ChainA
 }
 
 export function _isPureEvmChain (chainInfo: _ChainInfo) {
-  return (!!chainInfo.evmInfo && !chainInfo.substrateInfo && !chainInfo.tonInfo);
+  return (!!chainInfo.evmInfo && !chainInfo.substrateInfo && !chainInfo.tonInfo && !chainInfo.cardanoInfo);
 }
 
 export function _isPureSubstrateChain (chainInfo: _ChainInfo) {
-  return (!chainInfo.evmInfo && !!chainInfo.substrateInfo && !chainInfo.tonInfo);
+  return (!chainInfo.evmInfo && !!chainInfo.substrateInfo && !chainInfo.tonInfo && !chainInfo.cardanoInfo);
 }
 
 export function _isPureTonChain (chainInfo: _ChainInfo) {
-  return (!chainInfo.evmInfo && !chainInfo.substrateInfo && !!chainInfo.tonInfo);
+  return (!chainInfo.evmInfo && !chainInfo.substrateInfo && !!chainInfo.tonInfo && !chainInfo.cardanoInfo);
+}
+
+export function _isPureCardanoChain (chainInfo: _ChainInfo) {
+  return (!chainInfo.evmInfo && !chainInfo.substrateInfo && !chainInfo.tonInfo && !!chainInfo.cardanoInfo);
 }
 
 export function _getOriginChainOfAsset (assetSlug: string) {
@@ -130,6 +134,10 @@ export function _isTokenTransferredByTon (tokenInfo: _ChainAsset) {
   return _isJettonToken(tokenInfo) || _isNativeToken(tokenInfo);
 }
 
+export function _isTokenTransferredByCardano (tokenInfo: _ChainAsset) {
+  return _isCIP26Token(tokenInfo) || _isNativeToken(tokenInfo);
+}
+
 // Utils for balance functions
 export function _getTokenOnChainAssetId (tokenInfo: _ChainAsset): string {
   return tokenInfo.metadata?.assetId as string || '-1';
@@ -159,6 +167,10 @@ export function _isChainTonCompatible (chainInfo: _ChainInfo) {
   return !!chainInfo.tonInfo;
 }
 
+export function _isChainCardanoCompatible (chainInfo: _ChainInfo) {
+  return !!chainInfo.cardanoInfo;
+}
+
 export function _isNativeToken (tokenInfo: _ChainAsset) {
   return tokenInfo.assetType === _AssetType.NATIVE;
 }
@@ -294,11 +306,13 @@ export function _getTokenTypesSupportedByChain (chainInfo: _ChainInfo): _AssetTy
 }
 
 export function _getChainNativeTokenBasicInfo (chainInfo: _ChainInfo): BasicTokenInfo {
+  const defaultTokenInfo = {
+    symbol: '',
+    decimals: -1
+  };
+
   if (!chainInfo) {
-    return {
-      symbol: '',
-      decimals: -1
-    };
+    return defaultTokenInfo;
   }
 
   if (chainInfo.substrateInfo) { // substrate by default
@@ -316,12 +330,14 @@ export function _getChainNativeTokenBasicInfo (chainInfo: _ChainInfo): BasicToke
       symbol: chainInfo.tonInfo.symbol,
       decimals: chainInfo.tonInfo.decimals
     };
+  } else if (chainInfo.cardanoInfo) {
+    return {
+      symbol: chainInfo.cardanoInfo.symbol,
+      decimals: chainInfo.cardanoInfo.decimals
+    };
   }
 
-  return {
-    symbol: '',
-    decimals: -1
-  };
+  return defaultTokenInfo;
 }
 
 export function _getChainNativeTokenSlug (chainInfo: _ChainInfo) {
@@ -344,6 +360,10 @@ export function _isTokenTonSmartContract (tokenInfo: _ChainAsset) {
   return [_AssetType.TEP74].includes(tokenInfo.assetType); // add TEP-62 when supporting
 }
 
+export function _isCIP26Token (tokenInfo: _ChainAsset) {
+  return [_AssetType.CIP26].includes(tokenInfo.assetType);
+}
+
 export function _isTokenWasmSmartContract (tokenInfo: _ChainAsset) {
   return [_AssetType.PSP22, _AssetType.PSP34].includes(tokenInfo.assetType);
 }
@@ -649,6 +669,10 @@ export const _chainInfoToChainType = (chainInfo: _ChainInfo): AccountChainType =
     return AccountChainType.TON;
   }
 
+  if (_isChainCardanoCompatible(chainInfo)) {
+    return AccountChainType.CARDANO;
+  }
+
   if (_isChainBitcoinCompatible(chainInfo)) {
     return AccountChainType.BITCOIN;
   }
diff --git a/packages/extension-base/src/services/earning-service/service.ts b/packages/extension-base/src/services/earning-service/service.ts
index 7906ca44a88..f5a5bf7b3f6 100644
--- a/packages/extension-base/src/services/earning-service/service.ts
+++ b/packages/extension-base/src/services/earning-service/service.ts
@@ -2,7 +2,7 @@
 // SPDX-License-Identifier: Apache-2.0
 
 import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
-import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
+import { ChainType, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
 import { CRON_REFRESH_CHAIN_STAKING_METADATA, CRON_REFRESH_EARNING_REWARD_HISTORY_INTERVAL, CRON_REFRESH_STAKING_REWARD_FAST_INTERVAL } from '@subwallet/extension-base/constants';
 import KoniState from '@subwallet/extension-base/koni/background/handlers/State';
 import { PersistDataServiceInterface, ServiceStatus, StoppableServiceInterface } from '@subwallet/extension-base/services/base/types';
@@ -13,7 +13,7 @@ import { EventService } from '@subwallet/extension-base/services/event-service';
 import DatabaseService from '@subwallet/extension-base/services/storage-service/DatabaseService';
 import { SWTransaction } from '@subwallet/extension-base/services/transaction-service/types';
 import { BasicTxErrorType, EarningRewardHistoryItem, EarningRewardItem, EarningRewardJson, HandleYieldStepData, HandleYieldStepParams, OptimalYieldPath, OptimalYieldPathParams, RequestEarlyValidateYield, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestYieldLeave, RequestYieldWithdrawal, ResponseEarlyValidateYield, TransactionData, ValidateYieldProcessParams, YieldPoolInfo, YieldPoolTarget, YieldPoolType, YieldPositionInfo } from '@subwallet/extension-base/types';
-import { addLazy, categoryAddresses, createPromiseHandler, PromiseHandler, removeLazy } from '@subwallet/extension-base/utils';
+import { addLazy, createPromiseHandler, getAddressesByChainType, PromiseHandler, removeLazy } from '@subwallet/extension-base/utils';
 import { fetchStaticCache } from '@subwallet/extension-base/utils/fetchStaticCache';
 import { BehaviorSubject } from 'rxjs';
 
@@ -477,7 +477,8 @@ export default class EarningService implements StoppableServiceInterface, Persis
 
     await this.eventService.waitChainReady;
 
-    const { evm: evmAddresses, substrate: substrateAddresses } = categoryAddresses(addresses);
+    const evmAddresses = getAddressesByChainType(addresses, [ChainType.EVM]);
+    const substrateAddresses = getAddressesByChainType(addresses, [ChainType.SUBSTRATE]);
     const activeChains = this.state.activeChainSlugs;
     const unsubList: Array<VoidFunction> = [];
 
@@ -662,7 +663,8 @@ export default class EarningService implements StoppableServiceInterface, Persis
 
     await this.eventService.waitChainReady;
 
-    const { evm: evmAddresses, substrate: substrateAddresses } = categoryAddresses(addresses);
+    const evmAddresses = getAddressesByChainType(addresses, [ChainType.EVM]);
+    const substrateAddresses = getAddressesByChainType(addresses, [ChainType.SUBSTRATE]);
     const activeChains = this.state.activeChainSlugs;
     const unsubList: Array<VoidFunction> = [];
 
@@ -735,7 +737,8 @@ export default class EarningService implements StoppableServiceInterface, Persis
 
     await this.eventService.waitChainReady;
 
-    const { evm: evmAddresses, substrate: substrateAddresses } = categoryAddresses(addresses);
+    const evmAddresses = getAddressesByChainType(addresses, [ChainType.EVM]);
+    const substrateAddresses = getAddressesByChainType(addresses, [ChainType.SUBSTRATE]);
     const activeChains = this.state.activeChainSlugs;
     const unsubList: Array<VoidFunction> = [];
 
diff --git a/packages/extension-base/src/services/history-service/index.ts b/packages/extension-base/src/services/history-service/index.ts
index acf51dc4b04..4855c9a3059 100644
--- a/packages/extension-base/src/services/history-service/index.ts
+++ b/packages/extension-base/src/services/history-service/index.ts
@@ -1,7 +1,7 @@
 // Copyright 2019-2022 @subwallet/extension-base
 // SPDX-License-Identifier: Apache-2.0
 
-import { ExtrinsicStatus, TransactionHistoryItem } from '@subwallet/extension-base/background/KoniTypes';
+import { ChainType, ExtrinsicStatus, TransactionHistoryItem } from '@subwallet/extension-base/background/KoniTypes';
 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';
@@ -13,7 +13,7 @@ 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 { categoryAddresses } from '@subwallet/extension-base/utils';
+import { getAddressesByChainType } from '@subwallet/extension-base/utils';
 import { createPromiseHandler } from '@subwallet/extension-base/utils/promise';
 import { keyring } from '@subwallet/ui-keyring';
 import { BehaviorSubject } from 'rxjs';
@@ -181,7 +181,8 @@ export class HistoryService implements StoppableServiceInterface, PersistDataSer
 
   subscribeHistories (chain: string, proxyId: string, cb: (items: TransactionHistoryItem[]) => void) {
     const addresses = this.keyringService.context.getDecodedAddresses(proxyId, false);
-    const { evm, substrate } = categoryAddresses(addresses);
+    const evmAddresses = getAddressesByChainType(addresses, [ChainType.EVM]);
+    const substrateAddresses = getAddressesByChainType(addresses, [ChainType.SUBSTRATE]);
 
     const subscription = this.historySubject.subscribe((items) => {
       cb(items.filter(filterHistoryItemByAddressAndChain(chain, addresses)));
@@ -191,9 +192,9 @@ export class HistoryService implements StoppableServiceInterface, PersistDataSer
 
     if (_isChainSubstrateCompatible(chainInfo)) {
       if (_isChainEvmCompatible(chainInfo)) {
-        this.fetchSubscanTransactionHistory(chain, evm);
+        this.fetchSubscanTransactionHistory(chain, evmAddresses);
       } else {
-        this.fetchSubscanTransactionHistory(chain, substrate);
+        this.fetchSubscanTransactionHistory(chain, substrateAddresses);
       }
     }
 
diff --git a/packages/extension-base/src/services/inapp-notification-service/index.ts b/packages/extension-base/src/services/inapp-notification-service/index.ts
index dc8095d503b..dd2b6230152 100644
--- a/packages/extension-base/src/services/inapp-notification-service/index.ts
+++ b/packages/extension-base/src/services/inapp-notification-service/index.ts
@@ -3,7 +3,7 @@
 
 import { COMMON_ASSETS, COMMON_CHAIN_SLUGS } from '@subwallet/chain-list';
 import { _ChainAsset } from '@subwallet/chain-list/types';
-import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
+import { ChainType, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
 import { CRON_LISTEN_AVAIL_BRIDGE_CLAIM } from '@subwallet/extension-base/constants';
 import { fetchLastestRemindNotificationTime } from '@subwallet/extension-base/constants/remind-notification-time';
 import { CronServiceInterface, ServiceStatus } from '@subwallet/extension-base/services/base/types';
@@ -15,7 +15,7 @@ import { AvailBridgeSourceChain, AvailBridgeTransaction, fetchAllAvailBridgeClai
 import { KeyringService } from '@subwallet/extension-base/services/keyring-service';
 import DatabaseService from '@subwallet/extension-base/services/storage-service/DatabaseService';
 import { GetNotificationParams, RequestSwitchStatusParams } from '@subwallet/extension-base/types/notification';
-import { categoryAddresses, formatNumber } from '@subwallet/extension-base/utils';
+import { formatNumber, getAddressesByChainType } from '@subwallet/extension-base/utils';
 import { isSubstrateAddress } from '@subwallet/keyring';
 
 export class InappNotificationService implements CronServiceInterface {
@@ -201,12 +201,14 @@ export class InappNotificationService implements CronServiceInterface {
 
   getCategorizedAddresses () {
     const addresses = this.keyringService.context.getAllAddresses();
+    const evmAddresses = getAddressesByChainType(addresses, [ChainType.EVM]);
+    const substrateAddresses = getAddressesByChainType(addresses, [ChainType.SUBSTRATE]);
 
-    return categoryAddresses(addresses);
+    return { evmAddresses: evmAddresses, substrateAddresses: substrateAddresses };
   }
 
   createAvailBridgeClaimNotification () {
-    const { evm: evmAddresses, substrate: substrateAddresses } = this.getCategorizedAddresses();
+    const { evmAddresses, substrateAddresses } = this.getCategorizedAddresses();
 
     const chainAssets = this.chainService.getAssetRegistry();
 
@@ -299,7 +301,7 @@ export class InappNotificationService implements CronServiceInterface {
 
   // Polygon Claimable Handle
   async createPolygonClaimableTransactions () {
-    const { evm: evmAddresses } = this.getCategorizedAddresses();
+    const { evmAddresses } = this.getCategorizedAddresses();
     const etherChains = [COMMON_ASSETS.ETH, COMMON_ASSETS.ETH_SEPOLIA];
 
     const polygonAssets = Object.values(this.chainService.getAssetRegistry()).filter(
@@ -411,4 +413,8 @@ export class InappNotificationService implements CronServiceInterface {
   removeAccountNotifications (proxyId: string) {
     this.dbService.removeAccountNotifications(proxyId).catch(console.error);
   }
+
+  migrateNotificationProxyId (proxyIds: string[], newProxyId: string, newName: string) {
+    this.dbService.updateNotificationProxyId(proxyIds, newProxyId, newName);
+  }
 }
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 ff997e5df1a..1747ff12d79 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,9 +1,10 @@
 // Copyright 2019-2022 @subwallet/extension-base
 // SPDX-License-Identifier: Apache-2.0
 
-import { AccountExternalError, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateWithSecretKey, RequestAccountExportPrivateKey, RequestChangeMasterPassword, RequestMigratePassword, ResponseAccountCreateWithSecretKey, ResponseAccountExportPrivateKey, ResponseChangeMasterPassword, ResponseMigratePassword } from '@subwallet/extension-base/background/KoniTypes';
+import { AccountExternalError, RequestAccountCreateExternalV2, RequestAccountCreateHardwareMultiple, RequestAccountCreateHardwareV2, RequestAccountCreateWithSecretKey, RequestAccountExportPrivateKey, RequestChangeMasterPassword, RequestMigratePassword, RequestMigrateSoloAccount, RequestMigrateUnifiedAndFetchEligibleSoloAccounts, RequestPingSession, 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 { AccountMigrationHandler } from '@subwallet/extension-base/services/keyring-service/context/handlers/Migration';
 import { AccountProxyMap, CurrentAccountInfo, RequestAccountBatchExportV2, RequestAccountCreateSuriV2, RequestAccountNameValidate, RequestAccountProxyEdit, RequestAccountProxyForget, RequestBatchJsonGetAccountInfo, RequestBatchRestoreV2, RequestChangeTonWalletContractVersion, RequestCheckPublicAndSecretKey, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestExportAccountProxyMnemonic, RequestGetAllTonWalletContractVersion, RequestGetDeriveAccounts, RequestGetDeriveSuggestion, RequestJsonGetAccountInfo, RequestJsonRestoreV2, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, ResponseAccountBatchExportV2, ResponseAccountCreateSuriV2, ResponseAccountNameValidate, ResponseBatchJsonGetAccountInfo, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseExportAccountProxyMnemonic, ResponseGetAllTonWalletContractVersion, ResponseGetDeriveAccounts, ResponseGetDeriveSuggestion, ResponseJsonGetAccountInfo, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2 } from '@subwallet/extension-base/types';
 import { InjectedAccountWithMeta } from '@subwallet/extension-inject/types';
 import { SubjectInfo } from '@subwallet/ui-keyring/observable/types';
@@ -20,6 +21,7 @@ export class AccountContext {
   private readonly ledgerHandler: AccountLedgerHandler;
   private readonly modifyHandler: AccountModifyHandler;
   private readonly secretHandler: AccountSecretHandler;
+  private readonly migrationHandler: AccountMigrationHandler;
 
   constructor (private readonly koniState: KoniState, private readonly parentService: KeyringService) {
     this.state = new AccountState(this.koniState);
@@ -30,6 +32,7 @@ export class AccountContext {
     this.ledgerHandler = new AccountLedgerHandler(this.parentService, this.state);
     this.modifyHandler = new AccountModifyHandler(this.parentService, this.state);
     this.secretHandler = new AccountSecretHandler(this.parentService, this.state);
+    this.migrationHandler = new AccountMigrationHandler(this.parentService, this.state);
   }
 
   // TODO: Merge to value
@@ -253,8 +256,8 @@ export class AccountContext {
   }
 
   /* Derive account proxy  */
-  public derivationAccountProxyCreate (request: RequestDeriveCreateV3): boolean {
-    return this.deriveHandler.derivationAccountProxyCreate(request);
+  public derivationAccountProxyCreate (request: RequestDeriveCreateV3, isMigration?: boolean): boolean {
+    return this.deriveHandler.derivationAccountProxyCreate(request, isMigration);
   }
 
   /* Derive */
@@ -271,6 +274,21 @@ export class AccountContext {
 
   /* Inject */
 
+  /* Migration */
+  public async migrateUnifiedAndFetchEligibleSoloAccounts (request: RequestMigrateUnifiedAndFetchEligibleSoloAccounts, setMigratingModeFn: () => void) {
+    return await this.migrationHandler.migrateUnifiedAndFetchEligibleSoloAccounts(request, setMigratingModeFn);
+  }
+
+  public migrateSoloAccount (request: RequestMigrateSoloAccount) {
+    return this.migrationHandler.migrateSoloToUnifiedAccount(request);
+  }
+
+  public pingSession (request: RequestPingSession) {
+    return this.migrationHandler.pingSession(request);
+  }
+
+  /* Migration */
+
   /* Others */
 
   public removeNoneHardwareGenesisHash () {
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 ab01fa6d66f..69fbfce229e 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
@@ -12,7 +12,7 @@ import { assert } from '@polkadot/util';
 
 import { AccountBaseHandler } from './Base';
 
-const validDeriveKeypairTypes: KeypairType[] = [...SubstrateKeypairTypes, ...EthereumKeypairTypes, 'ton'];
+const validDeriveKeypairTypes: KeypairType[] = [...SubstrateKeypairTypes, ...EthereumKeypairTypes, 'ton', 'cardano'];
 
 /**
  * @class AccountDeriveHandler
@@ -227,7 +227,7 @@ export class AccountDeriveHandler extends AccountBaseHandler {
   /**
    * Derive account proxy
    *  */
-  public derivationAccountProxyCreate (request: RequestDeriveCreateV3): boolean {
+  public derivationAccountProxyCreate (request: RequestDeriveCreateV3, isMigration = false): boolean {
     const { name, proxyId: deriveId, suri } = request;
     const isUnified = this.state.isUnifiedAccount(deriveId);
 
@@ -237,7 +237,7 @@ export class AccountDeriveHandler extends AccountBaseHandler {
 
     const nameExists = this.state.checkNameExists(name);
 
-    if (nameExists) {
+    if (nameExists && !isMigration) {
       throw new SWCommonAccountError(CommonAccountErrorType.ACCOUNT_NAME_EXISTED);
     }
 
@@ -366,7 +366,9 @@ export class AccountDeriveHandler extends AccountBaseHandler {
     const addresses = pairs.map((pair) => pair.address);
     const exists = this.state.checkAddressExists(addresses);
 
-    assert(!exists, t('Account already exists under the name "{{name}}"', { replace: { name: exists?.name || exists?.address || '' } }));
+    if (!isMigration) {
+      assert(!exists, t('Account already exists under the name "{{name}}"', { replace: { name: exists?.name || exists?.address || '' } }));
+    }
 
     childAccountProxy && this.state.upsertAccountProxyByKey(childAccountProxy);
     this.state.upsertModifyPairs(modifyPairs);
diff --git a/packages/extension-base/src/services/keyring-service/context/handlers/Migration.ts b/packages/extension-base/src/services/keyring-service/context/handlers/Migration.ts
new file mode 100644
index 00000000000..d64bcfcb9eb
--- /dev/null
+++ b/packages/extension-base/src/services/keyring-service/context/handlers/Migration.ts
@@ -0,0 +1,286 @@
+// Copyright 2019-2022 @subwallet/extension-base
+// SPDX-License-Identifier: Apache-2.0
+
+import { RequestMigrateSoloAccount, RequestMigrateUnifiedAndFetchEligibleSoloAccounts, RequestPingSession, ResponseMigrateSoloAccount, ResponseMigrateUnifiedAndFetchEligibleSoloAccounts, SoloAccountToBeMigrated } from '@subwallet/extension-base/background/KoniTypes';
+import { AccountBaseHandler } from '@subwallet/extension-base/services/keyring-service/context/handlers/Base';
+import { AccountChainType, AccountProxy, SUPPORTED_ACCOUNT_CHAIN_TYPES } from '@subwallet/extension-base/types';
+import { createAccountProxyId, getDefaultKeypairTypeFromAccountChainType, getSuri } from '@subwallet/extension-base/utils';
+import { generateRandomString } from '@subwallet/extension-base/utils/getId';
+import { keyring } from '@subwallet/ui-keyring';
+
+import { keyExtractSuri } from '@polkadot/util-crypto';
+
+export const SESSION_TIMEOUT = 10000;
+
+interface SessionInfo {
+  password: string,
+  timeoutId: NodeJS.Timeout
+}
+
+interface UnifiedAccountGroup {
+  derivedUnifiedAccounts: AccountProxy[],
+  masterUnifiedAccounts: AccountProxy[]
+}
+
+export class AccountMigrationHandler extends AccountBaseHandler {
+  private sessionIdToPassword: Record<string, SessionInfo> = {};
+
+  public pingSession ({ sessionId }: RequestPingSession) {
+    if (!this.sessionIdToPassword[sessionId]) { // todo: if no persistent sessionId, should we jump to enter password again?
+      throw Error(`Session ID ${sessionId} not found.`);
+    }
+
+    clearTimeout(this.sessionIdToPassword[sessionId].timeoutId);
+    this.sessionIdToPassword[sessionId].timeoutId = setTimeout(() => {
+      delete this.sessionIdToPassword[sessionId];
+    }, SESSION_TIMEOUT);
+
+    return true;
+  }
+
+  public async migrateUnifiedAndFetchEligibleSoloAccounts (request: RequestMigrateUnifiedAndFetchEligibleSoloAccounts, setMigratingModeFn: () => void): Promise<ResponseMigrateUnifiedAndFetchEligibleSoloAccounts> {
+    // Migrate unified -> unified
+    const password = request.password;
+    const allAccountProxies = Object.values(this.state.accounts);
+    const UACanBeMigrated = this.getUACanBeMigrated(allAccountProxies);
+    const UACanBeMigratedSortedByParent = this.sortUAByParent(UACanBeMigrated); // master account must be migrated before derived account
+    const migratedUnifiedAccountIds = await this.migrateUnifiedToUnifiedAccount(password, UACanBeMigratedSortedByParent, setMigratingModeFn);
+
+    // Get solo accounts can be migrated
+    const soloAccountsNeedToBeMigrated = this.getSoloAccountsNeedToBeMigrated(allAccountProxies);
+    const soloAccountsNeedToBeMigratedGroup = this.groupSoloAccountByMnemonic(password, soloAccountsNeedToBeMigrated);
+    const eligibleSoloAccountMap = this.accountProxiesToEligibleSoloAccountMap(soloAccountsNeedToBeMigratedGroup);
+
+    // Create persistent mapping sessionId <-> password
+    const uniqueId = Date.now().toString();
+    const timeoutId = setTimeout(() => delete this.sessionIdToPassword[uniqueId], SESSION_TIMEOUT * 2);
+
+    this.sessionIdToPassword[uniqueId] = {
+      password,
+      timeoutId
+    };
+
+    return {
+      migratedUnifiedAccountIds,
+      soloAccounts: eligibleSoloAccountMap,
+      sessionId: uniqueId
+    };
+  }
+
+  public async migrateUnifiedToUnifiedAccount (password: string, accountProxies: AccountProxy[], setMigratingModeFn: () => void): Promise<string[]> {
+    keyring.unlockKeyring(password);
+    this.parentService.updateKeyringState();
+    setMigratingModeFn();
+
+    const unifiedAccountIds: string[] = [];
+    const modifiedPairs = structuredClone(this.state.modifyPairs);
+
+    const { derivedUnifiedAccounts, masterUnifiedAccounts } = accountProxies.reduce((accountInfo, account: AccountProxy) => {
+      const isDerivedAccount = !!account.parentId;
+
+      isDerivedAccount ? accountInfo.derivedUnifiedAccounts.push(account) : accountInfo.masterUnifiedAccounts.push(account);
+
+      return accountInfo;
+    }, { derivedUnifiedAccounts: [], masterUnifiedAccounts: [] } as unknown as UnifiedAccountGroup);
+
+    try {
+      for (const unifiedAccount of masterUnifiedAccounts) {
+        const proxyId = unifiedAccount.id;
+        const mnemonic = this.parentService.context.exportAccountProxyMnemonic({
+          password,
+          proxyId
+        }).result;
+
+        const newChainTypes = Object.values(AccountChainType).filter((type) => !unifiedAccount.chainTypes.includes(type) && SUPPORTED_ACCOUNT_CHAIN_TYPES.includes(type));
+        const keypairTypes = newChainTypes.map((chainType) => getDefaultKeypairTypeFromAccountChainType(chainType));
+
+        keypairTypes.forEach((type) => {
+          const suri = getSuri(mnemonic, type);
+          const pair = keyring.createFromUri(suri, {}, type);
+          const address = pair.address;
+
+          modifiedPairs[address] = { accountProxyId: proxyId, migrated: true, key: address };
+        });
+
+        keypairTypes.forEach((type) => {
+          const suri = getSuri(mnemonic, type);
+          const { derivePath } = keyExtractSuri(suri);
+          const metadata = {
+            name: unifiedAccount.name,
+            derivationPath: derivePath ? derivePath.substring(1) : undefined
+          };
+
+          const rs = keyring.addUri(suri, metadata, type);
+          const address = rs.pair.address;
+
+          this.state._addAddressToAuthList(address, true);
+        });
+
+        this.state.upsertModifyPairs(modifiedPairs);
+
+        unifiedAccountIds.push(proxyId);
+      }
+
+      await new Promise((resolve) => setTimeout(resolve, 1800)); // Wait last master unified account migrated. // todo: can be optimized later by await a promise resolve if master account is migrating
+
+      for (const unifiedAccount of derivedUnifiedAccounts) {
+        this.parentService.context.derivationAccountProxyCreate({
+          name: unifiedAccount.name,
+          suri: unifiedAccount.suri || '',
+          proxyId: unifiedAccount.parentId || ''
+        }, true);
+        unifiedAccountIds.push(unifiedAccount.id);
+      }
+    } catch (error) {
+      console.error('Migration unified account failed with error:', error);
+    } finally {
+      keyring.lockAll(false);
+      this.parentService.updateKeyringState();
+    }
+
+    return unifiedAccountIds;
+  }
+
+  public getUACanBeMigrated (accountProxies: AccountProxy[]): AccountProxy[] {
+    return accountProxies.filter((account) => this.state.isUnifiedAccount(account.id) && account.isNeedMigrateUnifiedAccount);
+  }
+
+  public getSoloAccountsNeedToBeMigrated (accountProxies: AccountProxy[]): AccountProxy[] {
+    return accountProxies.filter((account) => !this.state.isUnifiedAccount(account.id) && account.isNeedMigrateUnifiedAccount);
+  }
+
+  public groupSoloAccountByMnemonic (password: string, accountProxies: AccountProxy[]) {
+    const parentService = this.parentService;
+
+    return accountProxies.reduce(function (rs: Record<string, AccountProxy[]>, item) {
+      const oldProxyId = item.id;
+      const mnemonic = parentService.context.exportAccountProxyMnemonic({
+        password,
+        proxyId: oldProxyId
+      }).result;
+      const upcomingProxyId = createAccountProxyId(mnemonic);
+
+      if (!rs[upcomingProxyId]) {
+        rs[upcomingProxyId] = [];
+      }
+
+      rs[upcomingProxyId].push(item);
+
+      return rs;
+    }, {});
+  }
+
+  public accountProxiesToEligibleSoloAccountMap (accountProxyMap: Record<string, AccountProxy[]>): Record<string, SoloAccountToBeMigrated[]> {
+    const eligibleSoloAccountMap: Record<string, SoloAccountToBeMigrated[]> = {};
+
+    Object.entries(accountProxyMap).forEach(([upcomingProxyId, accounts]) => {
+      eligibleSoloAccountMap[upcomingProxyId] = accounts.map((account) => {
+        return {
+          upcomingProxyId,
+          proxyId: account.accounts[0].proxyId,
+          address: account.accounts[0].address,
+          name: account.name,
+          chainType: account.chainTypes[0]
+        } as SoloAccountToBeMigrated;
+      });
+    });
+
+    return eligibleSoloAccountMap;
+  }
+
+  public sortUAByParent (accountProxies: AccountProxy[]): AccountProxy[] {
+    const undefinedToStr = (str: string | undefined) => str ?? '';
+
+    return accountProxies.sort((a, b) => undefinedToStr(a.parentId) < undefinedToStr(b.parentId) ? -1 : undefinedToStr(a.parentId) > undefinedToStr(b.parentId) ? 1 : 0);
+  }
+
+  public migrateSoloToUnifiedAccount (request: RequestMigrateSoloAccount): ResponseMigrateSoloAccount {
+    const { accountName, sessionId, soloAccounts } = request;
+    const password = this.sessionIdToPassword[sessionId].password;
+
+    keyring.unlockKeyring(password);
+    this.parentService.updateKeyringState();
+    const modifiedPairs = structuredClone(this.state.modifyPairs);
+    const firstAccountInfo = soloAccounts[0];
+    const upcomingProxyId = firstAccountInfo.upcomingProxyId;
+    const firstAccountOldProxyId = firstAccountInfo.proxyId;
+
+    try {
+      const mnemonic = this.parentService.context.exportAccountProxyMnemonic({ password, proxyId: firstAccountOldProxyId }).result;
+
+      const keypairTypes = SUPPORTED_ACCOUNT_CHAIN_TYPES.map((chainType) => getDefaultKeypairTypeFromAccountChainType(chainType as AccountChainType));
+
+      keypairTypes.forEach((type) => {
+        const suri = getSuri(mnemonic, type);
+        const pair = keyring.createFromUri(suri, {}, type);
+        const address = pair.address;
+
+        modifiedPairs[address] = { accountProxyId: upcomingProxyId, migrated: true, key: address };
+      });
+
+      this.state.upsertAccountProxyByKey({ id: upcomingProxyId, name: accountName, isMigrationDone: false });
+
+      const soloAccountProxyIds: string[] = [];
+
+      keypairTypes.forEach((type) => {
+        const suri = getSuri(mnemonic, type);
+        const { derivePath } = keyExtractSuri(suri);
+        const metadata = {
+          name: accountName.concat(' - ').concat(generateRandomString()),
+          derivationPath: derivePath ? derivePath.substring(1) : undefined
+        };
+
+        const rs = keyring.addUri(suri, metadata, type);
+        soloAccountProxyIds.push(rs.json.address);
+        const address = rs.pair.address;
+
+        this.state._addAddressToAuthList(address, true);
+      });
+
+      this.state.upsertModifyPairs(modifiedPairs);
+      this.migrateDerivedSoloAccountRelationship(soloAccounts);
+      this.state.upsertAccountProxyByKey({ id: upcomingProxyId, name: accountName, isMigrationDone: true });
+
+      // Re-update account name
+      soloAccountProxyIds.forEach((oldProxyId) => {
+        const pair = keyring.getPair(oldProxyId);
+
+        keyring.saveAccountMeta(pair, { ...pair.meta, name: accountName });
+      });
+
+      // Update current account after migrating
+      const currentAccountProxyId = this.state.currentAccount.proxyId;
+
+      if (soloAccountProxyIds.includes(currentAccountProxyId)) {
+        this.state.saveCurrentAccountProxyId(upcomingProxyId);
+      }
+    } catch (error) {
+      console.error('Migration solo account failed with error', error);
+    } finally {
+      keyring.lockAll(false);
+      this.parentService.updateKeyringState();
+    }
+
+    return {
+      migratedUnifiedAccountId: upcomingProxyId
+    };
+  }
+
+  public migrateDerivedSoloAccountRelationship (soloAccounts: SoloAccountToBeMigrated[]) {
+    const accountProxies = this.state.accountProxies;
+
+    // Use Set.has & Map.get to optimize search performance
+    const proxyIdsSet = new Set(soloAccounts.map((account) => account.proxyId));
+    const proxyIdToUpcomingProxyIdMap = new Map(soloAccounts.map((account) => [account.proxyId, account.upcomingProxyId]));
+
+    for (const account of Object.values(accountProxies)) {
+      const currentParent = account.parentId;
+
+      if (currentParent && proxyIdsSet.has(currentParent)) {
+        accountProxies[account.id].parentId = proxyIdToUpcomingProxyIdMap.get(currentParent);
+      }
+    }
+
+    this.state.upsertAccountProxy(accountProxies);
+  }
+}
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 98d0ba96851..402321ea543 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
@@ -27,7 +27,7 @@ export class AccountMnemonicHandler extends AccountBaseHandler {
 
   /* Create seed */
   public async mnemonicCreateV2 ({ length = SEED_DEFAULT_LENGTH, mnemonic: _seed, type = 'general' }: RequestMnemonicCreateV2): Promise<ResponseMnemonicCreateV2> {
-    const types: KeypairType[] = type === 'general' ? ['sr25519', 'ethereum', 'ton'] : ['ton-native'];
+    const types: KeypairType[] = type === 'general' ? ['sr25519', 'ethereum', 'ton', 'cardano'] : ['ton-native'];
     const seed = _seed ||
     type === 'general'
       ? mnemonicGenerate(length)
@@ -89,7 +89,7 @@ export class AccountMnemonicHandler extends AccountBaseHandler {
     const addressDict = {} as Record<KeypairType, string>;
     let changedAccount = false;
     const hasMasterPassword = keyring.keyring.hasMasterPassword;
-    const types: KeypairType[] = type ? [type] : ['sr25519', 'ethereum', 'ton'];
+    const types: KeypairType[] = type ? [type] : ['sr25519', 'ethereum', 'ton', 'cardano'];
 
     if (!hasMasterPassword) {
       if (!password) {
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 aa4cc208cfc..b066271d54d 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
@@ -5,7 +5,7 @@ import { AccountExternalError, AccountExternalErrorCode, RequestAccountCreateExt
 import { AccountChainType, CommonAccountErrorType, RequestCheckPublicAndSecretKey, RequestPrivateKeyValidateV2, ResponseCheckPublicAndSecretKey, ResponsePrivateKeyValidateV2, SWCommonAccountError } 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';
+import { BitcoinKeypairTypes, CardanoKeypairTypes, KeypairType, KeyringPair, KeyringPair$Meta, TonKeypairTypes } from '@subwallet/keyring/types';
 import keyring from '@subwallet/ui-keyring';
 import { t } from 'i18next';
 
@@ -51,7 +51,7 @@ export class AccountSecretHandler extends AccountBaseHandler {
         genesisHash: ''
       };
 
-      if ([...BitcoinKeypairTypes, ...TonKeypairTypes].includes(type) && isReadOnly) {
+      if ([...BitcoinKeypairTypes, ...TonKeypairTypes, ...CardanoKeypairTypes].includes(type) && isReadOnly) {
         meta.noPublicKey = true;
       }
 
diff --git a/packages/extension-base/src/services/keyring-service/utils.ts b/packages/extension-base/src/services/keyring-service/utils.ts
new file mode 100644
index 00000000000..a20d08b95a2
--- /dev/null
+++ b/packages/extension-base/src/services/keyring-service/utils.ts
@@ -0,0 +1,14 @@
+// Copyright 2019-2022 @subwallet/extension-base
+// SPDX-License-Identifier: Apache-2.0
+
+import { AccountProxy } from '@subwallet/extension-base/types';
+
+export const hasAnyAccountForMigration = (allAccountProxies: AccountProxy[]) => {
+  for (const account of allAccountProxies) {
+    if (account.isNeedMigrateUnifiedAccount) {
+      return true;
+    }
+  }
+
+  return false;
+};
diff --git a/packages/extension-base/src/services/request-service/handler/CardanoRequestHandler.ts b/packages/extension-base/src/services/request-service/handler/CardanoRequestHandler.ts
new file mode 100644
index 00000000000..2c2d5c04ad3
--- /dev/null
+++ b/packages/extension-base/src/services/request-service/handler/CardanoRequestHandler.ts
@@ -0,0 +1,196 @@
+// Copyright 2019-2022 @subwallet/extension-base authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import { ConfirmationDefinitionsCardano, ConfirmationsQueueCardano, ConfirmationsQueueItemOptions, ConfirmationTypeCardano, RequestConfirmationCompleteCardano } from '@subwallet/extension-base/background/KoniTypes';
+import { ConfirmationRequestBase, Resolver } from '@subwallet/extension-base/background/types';
+import RequestService from '@subwallet/extension-base/services/request-service';
+import { isInternalRequest } from '@subwallet/extension-base/utils/request';
+import { keyring } from '@subwallet/ui-keyring';
+import { t } from 'i18next';
+import { BehaviorSubject } from 'rxjs';
+
+import { logger as createLogger } from '@polkadot/util/logger';
+import { Logger } from '@polkadot/util/types';
+
+export default class CardanoRequestHandler {
+  readonly #requestService: RequestService;
+  readonly #logger: Logger;
+
+  private readonly confirmationsQueueSubjectCardano = new BehaviorSubject<ConfirmationsQueueCardano>({
+    cardanoSignatureRequest: {},
+    cardanoSendTransactionRequest: {},
+    cardanoWatchTransactionRequest: {}
+  });
+
+  private readonly confirmationsPromiseMap: Record<string, { resolver: Resolver<any>, validator?: (rs: any) => Error | undefined }> = {};
+
+  constructor (requestService: RequestService) {
+    this.#requestService = requestService;
+    this.#logger = createLogger('CardanoRequestHandler');
+  }
+
+  public get numCardanoRequests (): number {
+    let count = 0;
+
+    Object.values(this.confirmationsQueueSubjectCardano.getValue()).forEach((x) => {
+      count += Object.keys(x).length;
+    });
+
+    return count;
+  }
+
+  public getConfirmationsQueueSubjectCardano (): BehaviorSubject<ConfirmationsQueueCardano> {
+    return this.confirmationsQueueSubjectCardano;
+  }
+
+  public async addConfirmationCardano<CT extends ConfirmationTypeCardano> (
+    id: string,
+    url: string,
+    type: CT,
+    payload: ConfirmationDefinitionsCardano[CT][0]['payload'],
+    options: ConfirmationsQueueItemOptions = {},
+    validator?: (input: ConfirmationDefinitionsCardano[CT][1]) => Error | undefined
+  ): Promise<ConfirmationDefinitionsCardano[CT][1]> {
+    const confirmations = this.confirmationsQueueSubjectCardano.getValue();
+    const confirmationType = confirmations[type] as Record<string, ConfirmationDefinitionsCardano[CT][0]>;
+    const payloadJson = JSON.stringify({});
+    const isInternal = isInternalRequest(url);
+
+    if (['cardanoSendTransactionRequest', 'cardanoSignatureRequest'].includes(type)) {
+      const isAlwaysRequired = await this.#requestService.settingService.isAlwaysRequired;
+
+      if (isAlwaysRequired) {
+        this.#requestService.keyringService.lock();
+      }
+    }
+
+    // Check duplicate request
+    const duplicated = Object.values(confirmationType).find((c) => (c.url === url) && (c.payloadJson === payloadJson));
+
+    if (duplicated) {
+      throw new Error('Cardano duplicate request'); // update this message.
+    }
+
+    confirmationType[id] = {
+      id,
+      url,
+      isInternal,
+      payload,
+      payloadJson,
+      ...options
+    } as ConfirmationDefinitionsCardano[CT][0];
+
+    const promise = new Promise<ConfirmationDefinitionsCardano[CT][1]>((resolve, reject) => {
+      this.confirmationsPromiseMap[id] = {
+        validator: validator,
+        resolver: {
+          resolve: resolve,
+          reject: reject
+        }
+      };
+    });
+
+    this.confirmationsQueueSubjectCardano.next(confirmations);
+
+    if (!isInternal) {
+      this.#requestService.popupOpen();
+    }
+
+    this.#requestService.updateIconV2();
+
+    return promise;
+  }
+
+  public async completeConfirmationCardano (request: RequestConfirmationCompleteCardano): Promise<boolean> {
+    const confirmations = this.confirmationsQueueSubjectCardano.getValue();
+
+    for (const ct in request) {
+      const type = ct as ConfirmationTypeCardano;
+      const result = request[type] as ConfirmationDefinitionsCardano[typeof type][1];
+
+      const { id } = result;
+      const { resolver, validator } = this.confirmationsPromiseMap[id];
+      const confirmation = confirmations[type][id];
+
+      if (!resolver || !confirmation) {
+        this.#logger.error(t('Unable to proceed. Please try again'), type, id);
+        throw new Error(t('Unable to proceed. Please try again'));
+      }
+
+      // Fill signature for some special type
+      await this.decorateResult(type, confirmation, result);
+
+      // Validate response from confirmation popup some info like password, response format....
+      const error = validator && validator(result);
+
+      if (error) {
+        resolver.reject(error);
+      }
+
+      // Delete confirmations from queue
+      delete this.confirmationsPromiseMap[id];
+      delete confirmations[type][id];
+      this.confirmationsQueueSubjectCardano.next(confirmations);
+
+      // Update icon, and close queue
+      this.#requestService.updateIconV2(this.#requestService.numAllRequests === 0);
+      resolver.resolve(result);
+    }
+
+    // TODO: Review later
+    return true;
+  }
+
+  private async decorateResult<T extends ConfirmationTypeCardano> (t: T, request: ConfirmationDefinitionsCardano[T][0], result: ConfirmationDefinitionsCardano[T][1]) {
+    if (result.payload === '') {
+      if (t === 'cardanoSignatureRequest') {
+        // result.payload = await this.signMessage(request as ConfirmationDefinitions['evmSignatureRequest'][0]);
+      } else if (t === 'cardanoSendTransactionRequest') {
+        result.payload = this.signTransactionCardano(request as ConfirmationDefinitionsCardano['cardanoSendTransactionRequest'][0]);
+      }
+
+      if (t === 'cardanoSignatureRequest' || t === 'cardanoSendTransactionRequest') {
+        const isAlwaysRequired = await this.#requestService.settingService.isAlwaysRequired;
+
+        if (isAlwaysRequired) {
+          this.#requestService.keyringService.lock();
+        }
+      }
+    }
+  }
+
+  private signTransactionCardano (confirmation: ConfirmationDefinitionsCardano['cardanoSendTransactionRequest'][0]): string { // alibaba
+    const transaction = confirmation.payload;
+    const { cardanoPayload, from } = transaction;
+
+    const pair = keyring.getPair(from);
+
+    if (pair.isLocked) {
+      keyring.unlockPair(pair.address);
+    }
+
+    return pair.cardano.sign(cardanoPayload);
+  }
+
+  public resetWallet () {
+    const confirmations = this.confirmationsQueueSubjectCardano.getValue();
+
+    for (const [type, requests] of Object.entries(confirmations)) {
+      for (const confirmation of Object.values(requests)) {
+        const { id } = confirmation as ConfirmationRequestBase;
+        const { resolver } = this.confirmationsPromiseMap[id];
+
+        if (!resolver || !confirmation) {
+          console.error('Not found confirmation', type, id);
+        } else {
+          resolver.reject(new Error('Reset wallet'));
+        }
+
+        delete this.confirmationsPromiseMap[id];
+        delete confirmations[type as ConfirmationTypeCardano][id];
+      }
+    }
+
+    this.confirmationsQueueSubjectCardano.next(confirmations);
+  }
+}
diff --git a/packages/extension-base/src/services/request-service/index.ts b/packages/extension-base/src/services/request-service/index.ts
index a9f9f312e17..8aee8c3cf2f 100644
--- a/packages/extension-base/src/services/request-service/index.ts
+++ b/packages/extension-base/src/services/request-service/index.ts
@@ -1,10 +1,11 @@
 // Copyright 2019-2022 @subwallet/extension-base authors & contributors
 // SPDX-License-Identifier: Apache-2.0
 
-import { AuthRequestV2, ConfirmationDefinitions, ConfirmationDefinitionsTon, ConfirmationsQueue, ConfirmationsQueueItemOptions, ConfirmationsQueueTon, ConfirmationType, ConfirmationTypeTon, RequestConfirmationComplete, RequestConfirmationCompleteTon } from '@subwallet/extension-base/background/KoniTypes';
+import { AuthRequestV2, ConfirmationDefinitions, ConfirmationDefinitionsCardano, ConfirmationDefinitionsTon, ConfirmationsQueue, ConfirmationsQueueCardano, ConfirmationsQueueItemOptions, ConfirmationsQueueTon, ConfirmationType, ConfirmationTypeCardano, ConfirmationTypeTon, RequestConfirmationComplete, RequestConfirmationCompleteCardano, RequestConfirmationCompleteTon } from '@subwallet/extension-base/background/KoniTypes';
 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 CardanoRequestHandler from '@subwallet/extension-base/services/request-service/handler/CardanoRequestHandler';
 import SettingService from '@subwallet/extension-base/services/setting-service/SettingService';
 import { WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types';
 import { MetadataDef } from '@subwallet/extension-inject/types';
@@ -27,6 +28,7 @@ export default class RequestService {
   readonly #substrateRequestHandler: SubstrateRequestHandler;
   readonly #evmRequestHandler: EvmRequestHandler;
   readonly #tonRequestHandler: TonRequestHandler;
+  readonly #cardanoRequestHandler: CardanoRequestHandler;
   readonly #connectWCRequestHandler: ConnectWCRequestHandler;
   readonly #notSupportWCRequestHandler: NotSupportWCRequestHandler;
 
@@ -41,6 +43,7 @@ export default class RequestService {
     this.#substrateRequestHandler = new SubstrateRequestHandler(this);
     this.#evmRequestHandler = new EvmRequestHandler(this);
     this.#tonRequestHandler = new TonRequestHandler(this);
+    this.#cardanoRequestHandler = new CardanoRequestHandler(this);
     this.#connectWCRequestHandler = new ConnectWCRequestHandler(this);
     this.#notSupportWCRequestHandler = new NotSupportWCRequestHandler(this);
 
@@ -49,7 +52,7 @@ export default class RequestService {
   }
 
   public get numAllRequests () {
-    return this.allSubstrateRequests.length + this.numEvmRequests + this.numTonRequests;
+    return this.allSubstrateRequests.length + this.numEvmRequests + this.numTonRequests + this.numCardanoRequests;
   }
 
   public updateIconV2 (shouldClose?: boolean): void {
@@ -178,6 +181,10 @@ export default class RequestService {
     return this.#tonRequestHandler.numTonRequests;
   }
 
+  public get numCardanoRequests (): number {
+    return this.#cardanoRequestHandler.numCardanoRequests;
+  }
+
   public get confirmationsQueueSubject (): BehaviorSubject<ConfirmationsQueue> {
     return this.#evmRequestHandler.getConfirmationsQueueSubject();
   }
@@ -186,6 +193,10 @@ export default class RequestService {
     return this.#tonRequestHandler.getConfirmationsQueueSubjectTon();
   }
 
+  public get confirmationsQueueSubjectCardano (): BehaviorSubject<ConfirmationsQueueCardano> {
+    return this.#cardanoRequestHandler.getConfirmationsQueueSubjectCardano();
+  }
+
   public getSignRequest (id: string) {
     return this.#substrateRequestHandler.getSignRequest(id);
   }
@@ -209,13 +220,24 @@ export default class RequestService {
     id: string,
     url: string,
     type: CT,
-    payload: ConfirmationDefinitionsTon[CT][0]['payload'], // todo: messages <-> payload
+    payload: ConfirmationDefinitionsTon[CT][0]['payload'],
     options: ConfirmationsQueueItemOptions = {},
     validator?: (input: ConfirmationDefinitionsTon[CT][1]) => Error | undefined
   ): Promise<ConfirmationDefinitionsTon[CT][1]> {
     return this.#tonRequestHandler.addConfirmationTon(id, url, type, payload, options, validator);
   }
 
+  public addConfirmationCardano<CT extends ConfirmationTypeCardano> (
+    id: string,
+    url: string,
+    type: CT,
+    payload: ConfirmationDefinitionsCardano[CT][0]['payload'],
+    options: ConfirmationsQueueItemOptions = {},
+    validator?: (input: ConfirmationDefinitionsCardano[CT][1]) => Error | undefined
+  ): Promise<ConfirmationDefinitionsCardano[CT][1]> {
+    return this.#cardanoRequestHandler.addConfirmationCardano(id, url, type, payload, options, validator);
+  }
+
   public async completeConfirmation (request: RequestConfirmationComplete): Promise<boolean> {
     return await this.#evmRequestHandler.completeConfirmation(request);
   }
@@ -224,6 +246,10 @@ export default class RequestService {
     return await this.#tonRequestHandler.completeConfirmationTon(request);
   }
 
+  public async completeConfirmationCardano (request: RequestConfirmationCompleteCardano) {
+    return await this.#cardanoRequestHandler.completeConfirmationCardano(request);
+  }
+
   public updateConfirmation<CT extends ConfirmationType> (
     id: string,
     type: CT,
@@ -278,7 +304,7 @@ export default class RequestService {
 
   // General methods
   public get numRequests (): number {
-    return this.numMetaRequests + this.numAuthRequests + this.numSubstrateRequests + this.numEvmRequests + this.numConnectWCRequests + this.numNotSupportWCRequests + this.numTonRequests;
+    return this.numMetaRequests + this.numAuthRequests + this.numSubstrateRequests + this.numEvmRequests + this.numConnectWCRequests + this.numNotSupportWCRequests + this.numTonRequests + this.numCardanoRequests;
   }
 
   public resetWallet (): void {
@@ -286,6 +312,7 @@ export default class RequestService {
     this.#substrateRequestHandler.resetWallet();
     this.#evmRequestHandler.resetWallet();
     this.#tonRequestHandler.resetWallet();
+    this.#cardanoRequestHandler.resetWallet();
     this.#metadataRequestHandler.resetWallet();
     this.#connectWCRequestHandler.resetWallet();
     this.#notSupportWCRequestHandler.resetWallet();
diff --git a/packages/extension-base/src/services/setting-service/constants.ts b/packages/extension-base/src/services/setting-service/constants.ts
index fd0ea463768..f6041fca012 100644
--- a/packages/extension-base/src/services/setting-service/constants.ts
+++ b/packages/extension-base/src/services/setting-service/constants.ts
@@ -30,6 +30,9 @@ export const DEFAULT_NOTIFICATION_SETUP: NotificationSetup = {
     // isHideAnnouncement: false
   }
 };
+export const DEFAULT_ACKNOWLEDGED_MIGRATION_STATUS = false;
+export const DEFAULT_UNIFIED_ACCOUNT_MIGRATION_IN_PROGRESS = false;
+export const DEFAULT_UNIFIED_ACCOUNT_MIGRATION_IN_DONE = false;
 
 export const DEFAULT_SETTING: UiSettings = {
   language: DEFAULT_LANGUAGE,
@@ -44,5 +47,8 @@ export const DEFAULT_SETTING: UiSettings = {
   timeAutoLock: DEFAULT_AUTO_LOCK_TIME,
   enableChainPatrol: DEFAULT_CHAIN_PATROL_ENABLE,
   notificationSetup: DEFAULT_NOTIFICATION_SETUP,
+  isAcknowledgedUnifiedAccountMigration: DEFAULT_ACKNOWLEDGED_MIGRATION_STATUS,
+  isUnifiedAccountMigrationInProgress: DEFAULT_UNIFIED_ACCOUNT_MIGRATION_IN_PROGRESS,
+  isUnifiedAccountMigrationDone: DEFAULT_UNIFIED_ACCOUNT_MIGRATION_IN_DONE,
   walletReference: ''
 };
diff --git a/packages/extension-base/src/services/storage-service/DatabaseService.ts b/packages/extension-base/src/services/storage-service/DatabaseService.ts
index a91949bf059..ed42683340a 100644
--- a/packages/extension-base/src/services/storage-service/DatabaseService.ts
+++ b/packages/extension-base/src/services/storage-service/DatabaseService.ts
@@ -650,6 +650,10 @@ export default class DatabaseService {
     return this.stores.inappNotification.removeAccountNotifications(proxyId);
   }
 
+  public updateNotificationProxyId (proxyIds: string[], newProxyId: string, newName: string) {
+    return this.stores.inappNotification.updateNotificationProxyId(proxyIds, newProxyId, newName);
+  }
+
   async exportDB () {
     const blob = await exportDB(this._db, {
       filter: (table, value, key) => {
diff --git a/packages/extension-base/src/services/storage-service/db-stores/InappNotification.ts b/packages/extension-base/src/services/storage-service/db-stores/InappNotification.ts
index c953f2e0010..258d30a3817 100644
--- a/packages/extension-base/src/services/storage-service/db-stores/InappNotification.ts
+++ b/packages/extension-base/src/services/storage-service/db-stores/InappNotification.ts
@@ -44,6 +44,15 @@ export default class InappNotificationStore extends BaseStore<_NotificationInfo>
     return filteredTable.toArray();
   }
 
+  updateNotificationProxyId (proxyIds: string[], newProxyId: string, newName: string) {
+    this.table.where('proxyId')
+      .anyOfIgnoreCase(proxyIds)
+      .modify((item) => {
+        item.proxyId = newProxyId;
+        item.title = item.title.replace(/\[.*?\]/, `[${newName}]`);
+      });
+  }
+
   async cleanUpOldNotifications (overdueTime: number) {
     const currentTimestamp = Date.now();
 
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 fc9d21f1a03..86b9c6c1ae4 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
@@ -10,7 +10,7 @@ import { ChainType, ExtrinsicType } from '@subwallet/extension-base/background/K
 import { _getChainflipEarlyValidationError } from '@subwallet/extension-base/core/logic-validation/swap';
 import { BalanceService } from '@subwallet/extension-base/services/balance-service';
 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 { createSubstrateExtrinsic } from '@subwallet/extension-base/services/balance-service/transfer/token';
 import { ChainService } from '@subwallet/extension-base/services/chain-service';
 import { _getAssetDecimals, _getAssetSymbol, _getChainNativeTokenSlug, _getContractAddressOfToken, _isChainSubstrateCompatible, _isNativeToken, _isSmartContractToken } from '@subwallet/extension-base/services/chain-service/utils';
 import { SwapBaseHandler, SwapBaseInterface } from '@subwallet/extension-base/services/swap-service/handler/base-handler';
@@ -430,7 +430,7 @@ export class ChainflipSwapHandler implements SwapBaseInterface {
 
       const substrateApi = await chainApi.isReady;
 
-      const [submittableExtrinsic] = await createTransferExtrinsic({
+      const [submittableExtrinsic] = await createSubstrateExtrinsic({
         from: address,
         networkKey: chainInfo.slug,
         substrateApi,
diff --git a/packages/extension-base/src/services/swap-service/handler/simpleswap-handler.ts b/packages/extension-base/src/services/swap-service/handler/simpleswap-handler.ts
index 58c8ba2180f..7c81bcab2fb 100644
--- a/packages/extension-base/src/services/swap-service/handler/simpleswap-handler.ts
+++ b/packages/extension-base/src/services/swap-service/handler/simpleswap-handler.ts
@@ -15,7 +15,7 @@ import { SubmittableExtrinsic } from '@polkadot/api/types';
 
 import { BalanceService } from '../../balance-service';
 import { getERC20TransactionObject, getEVMTransactionObject } from '../../balance-service/transfer/smart-contract';
-import { createTransferExtrinsic, getTransferMockTxFee } from '../../balance-service/transfer/token';
+import { createSubstrateExtrinsic, getTransferMockTxFee } from '../../balance-service/transfer/token';
 import { ChainService } from '../../chain-service';
 import { EvmApi } from '../../chain-service/handler/EvmApi';
 import { _SubstrateApi } from '../../chain-service/types';
@@ -464,7 +464,7 @@ export class SimpleSwapHandler implements SwapBaseInterface {
       const chainApi = this.chainService.getSubstrateApi(chainInfo.slug);
       const substrateApi = await chainApi.isReady;
 
-      const [submittableExtrinsic] = await createTransferExtrinsic({
+      const [submittableExtrinsic] = await createSubstrateExtrinsic({
         from: address,
         networkKey: chainInfo.slug,
         substrateApi,
diff --git a/packages/extension-base/src/services/transaction-service/balance.spec.ts b/packages/extension-base/src/services/transaction-service/balance.spec.ts
index a3d229b4daa..db52f847297 100644
--- a/packages/extension-base/src/services/transaction-service/balance.spec.ts
+++ b/packages/extension-base/src/services/transaction-service/balance.spec.ts
@@ -4,7 +4,7 @@
 import { ChainAssetMap, ChainInfoMap } from '@subwallet/chain-list';
 import { _AssetType, _ChainAsset } from '@subwallet/chain-list/types';
 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 { createSubstrateExtrinsic } from '@subwallet/extension-base/services/balance-service/transfer/token';
 import { EvmChainHandler } from '@subwallet/extension-base/services/chain-service/handler/EvmChainHandler';
 import { SubstrateChainHandler } from '@subwallet/extension-base/services/chain-service/handler/SubstrateChainHandler';
 import { _getContractAddressOfToken, _isLocalToken, _isTokenEvmSmartContract } from '@subwallet/extension-base/services/chain-service/utils';
@@ -49,7 +49,7 @@ describe('test token transfer', () => {
 
       for (const asset of assets) {
         try {
-          const [extrinsic] = await createTransferExtrinsic({
+          const [extrinsic] = await createSubstrateExtrinsic({
             from: '5DnokDpMdNEH8cApsZoWQnjsggADXQmGWUb6q8ZhHeEwvncL',
             networkKey: networkKey,
             to: '5EhSb8uHkbPRF869wynQ4gh5V7B62YgkEQvMdk6tzHD9bK7b',
diff --git a/packages/extension-base/src/services/transaction-service/helpers/index.ts b/packages/extension-base/src/services/transaction-service/helpers/index.ts
index 427d24b7aee..06103db8e78 100644
--- a/packages/extension-base/src/services/transaction-service/helpers/index.ts
+++ b/packages/extension-base/src/services/transaction-service/helpers/index.ts
@@ -3,6 +3,7 @@
 
 import { _ChainInfo } from '@subwallet/chain-list/types';
 import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
+import { CardanoTransactionConfig } from '@subwallet/extension-base/services/balance-service/transfer/cardano-transfer';
 import { TonTransactionConfig } from '@subwallet/extension-base/services/balance-service/transfer/ton-transfer';
 import { SWTransaction } from '@subwallet/extension-base/services/transaction-service/types';
 
@@ -29,6 +30,12 @@ export const isTonTransaction = (tx: SWTransaction['transaction']): tx is TonTra
   return Boolean(tonTransactionConfig.messagePayload) && tonTransactionConfig.seqno >= 0;
 };
 
+export const isCardanoTransaction = (tx: SWTransaction['transaction']): tx is CardanoTransactionConfig => {
+  const cardanoTransactionConfig = tx as CardanoTransactionConfig;
+
+  return cardanoTransactionConfig.cardanoPayload !== null && cardanoTransactionConfig.cardanoPayload !== undefined;
+};
+
 const typeName = (type: SWTransaction['extrinsicType']) => {
   switch (type) {
     case ExtrinsicType.TRANSFER_BALANCE:
diff --git a/packages/extension-base/src/services/transaction-service/index.ts b/packages/extension-base/src/services/transaction-service/index.ts
index 2249f181183..0493d55560a 100644
--- a/packages/extension-base/src/services/transaction-service/index.ts
+++ b/packages/extension-base/src/services/transaction-service/index.ts
@@ -8,6 +8,7 @@ import { ALL_ACCOUNT_KEY, fetchBlockedConfigObjects, fetchLastestBlockedActionsA
 import { checkBalanceWithTransactionFee, checkSigningAccountForTransaction, checkSupportForAction, checkSupportForFeature, checkSupportForTransaction, estimateFeeForTransaction } from '@subwallet/extension-base/core/logic-validation/transfer';
 import KoniState from '@subwallet/extension-base/koni/background/handlers/State';
 import { cellToBase64Str, externalMessage, getTransferCellPromise } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/utils';
+import { CardanoTransactionConfig } from '@subwallet/extension-base/services/balance-service/transfer/cardano-transfer';
 import { TonTransactionConfig } from '@subwallet/extension-base/services/balance-service/transfer/ton-transfer';
 import { _isPolygonChainBridge } from '@subwallet/extension-base/services/balance-service/transfer/xcm/polygonBridge';
 import { ChainService } from '@subwallet/extension-base/services/chain-service';
@@ -18,7 +19,7 @@ import { ClaimAvailBridgeNotificationMetadata } from '@subwallet/extension-base/
 import { EXTENSION_REQUEST_URL } from '@subwallet/extension-base/services/request-service/constants';
 import { TRANSACTION_TIMEOUT } from '@subwallet/extension-base/services/transaction-service/constants';
 import { parseLiquidStakingEvents, parseLiquidStakingFastUnstakeEvents, parseTransferEventLogs, parseXcmEventLogs } from '@subwallet/extension-base/services/transaction-service/event-parser';
-import { getBaseTransactionInfo, getTransactionId, isSubstrateTransaction, isTonTransaction } from '@subwallet/extension-base/services/transaction-service/helpers';
+import { getBaseTransactionInfo, getTransactionId, isCardanoTransaction, isSubstrateTransaction, isTonTransaction } from '@subwallet/extension-base/services/transaction-service/helpers';
 import { SWTransaction, SWTransactionInput, SWTransactionResponse, TransactionEmitter, TransactionEventMap, TransactionEventResponse, ValidateTransactionResponseInput } from '@subwallet/extension-base/services/transaction-service/types';
 import { getExplorerLink, parseTransactionData } from '@subwallet/extension-base/services/transaction-service/utils';
 import { isWalletConnectRequest } from '@subwallet/extension-base/services/wallet-connect-service/helpers';
@@ -130,10 +131,14 @@ export default class TransactionService {
 
     const evmApi = this.state.chainService.getEvmApi(chainInfo.slug);
     const tonApi = this.state.chainService.getTonApi(chainInfo.slug);
-    const isNoEvmApi = transaction && !isSubstrateTransaction(transaction) && !isTonTransaction(transaction) && !evmApi; // todo: should split isEvmTx && isNoEvmApi. Because other chains type also has no Evm Api
+    const cardanoApi = this.state.chainService.getCardanoApi(chainInfo.slug);
+    // todo: should split into isEvmTx && isNoEvmApi. Because other chains type also has no Evm Api. Same to all blockchain.
+    // todo: refactor check evmTransaction.
+    const isNoEvmApi = transaction && !isSubstrateTransaction(transaction) && !isTonTransaction(transaction) && !isCardanoTransaction(transaction) && !evmApi;
     const isNoTonApi = transaction && isTonTransaction(transaction) && !tonApi;
+    const isNoCardanoApi = transaction && isCardanoTransaction(transaction) && !cardanoApi;
 
-    if (isNoEvmApi || isNoTonApi) {
+    if (isNoEvmApi || isNoTonApi || isNoCardanoApi) {
       validationResponse.errors.push(new TransactionError(BasicTxErrorType.CHAIN_DISCONNECTED, undefined));
     }
 
@@ -264,7 +269,13 @@ export default class TransactionService {
 
   private async sendTransaction (transaction: SWTransaction): Promise<TransactionEmitter> {
     // Send Transaction
-    const emitter = await (transaction.chainType === 'substrate' ? this.signAndSendSubstrateTransaction(transaction) : transaction.chainType === 'evm' ? this.signAndSendEvmTransaction(transaction) : this.signAndSendTonTransaction(transaction));
+    const emitter = await (transaction.chainType === 'substrate'
+      ? this.signAndSendSubstrateTransaction(transaction)
+      : transaction.chainType === 'evm'
+        ? this.signAndSendEvmTransaction(transaction)
+        : transaction.chainType === 'cardano'
+          ? this.signAndSendCardanoTransaction(transaction)
+          : this.signAndSendTonTransaction(transaction));
 
     const { eventsHandler } = transaction;
 
@@ -1228,7 +1239,7 @@ export default class TransactionService {
       });
     };
 
-    const tonTransactionConfig = transaction as TonTransactionConfig;
+    const tonTransactionConfig = transaction as TonTransactionConfig; // todo: is this same as payload?
     const seqno = tonTransactionConfig.seqno;
     const messages = tonTransactionConfig.messages;
 
@@ -1281,6 +1292,77 @@ export default class TransactionService {
     return emitter;
   }
 
+  private signAndSendCardanoTransaction ({ chain, id, transaction, url }: SWTransaction): TransactionEmitter {
+    const emitter = new EventEmitter<TransactionEventMap>();
+    const eventData: TransactionEventResponse = {
+      id,
+      errors: [],
+      warnings: [],
+      extrinsicHash: id
+    };
+
+    const transactionConfig = transaction as CardanoTransactionConfig;
+    const cardanoApi = this.state.chainService.getCardanoApi(chain);
+
+    this.state.requestService.addConfirmationCardano(id, url || EXTENSION_REQUEST_URL, 'cardanoSendTransactionRequest', transactionConfig, {})
+      .then(({ isApproved, 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('Failed to sign');
+          }
+
+          // Emit signed event
+          emitter.emit('signed', eventData);
+
+          // Send transaction
+          this.handleTransactionTimeout(emitter, eventData);
+          emitter.emit('send', eventData);
+
+          // send qua api
+          cardanoApi.sendCardanoTxReturnHash(payload)
+            .then((txHash) => {
+              if (!txHash) {
+                eventData.errors.push(new TransactionError(BasicTxErrorType.SEND_TRANSACTION_FAILED));
+                emitter.emit('error', eventData);
+              }
+
+              eventData.extrinsicHash = txHash;
+              emitter.emit('extrinsicHash', eventData);
+
+              // todo: wait transaction by fetch txHash by API
+              cardanoApi.getStatusByTxHash(txHash, transactionConfig.cardanoTtlOffset).then((status) => {
+                if (!status) {
+                  eventData.errors.push(new TransactionError(BasicTxErrorType.SEND_TRANSACTION_FAILED));
+                  emitter.emit('error', eventData);
+                }
+
+                emitter.emit('success', eventData);
+              })
+                .catch((e: Error) => {
+                  eventData.errors.push(new TransactionError(BasicTxErrorType.SEND_TRANSACTION_FAILED, e.message));
+                  emitter.emit('error', eventData);
+                });
+            })
+            .catch((e: Error) => {
+              eventData.errors.push(new TransactionError(BasicTxErrorType.SEND_TRANSACTION_FAILED, e.message));
+              emitter.emit('error', eventData);
+            });
+        }
+      })
+      .catch((e: Error) => {
+        this.removeTransaction(id);
+        eventData.errors.push(new TransactionError(BasicTxErrorType.UNABLE_TO_SIGN, t(e.message)));
+
+        emitter.emit('error', eventData);
+      });
+
+    return emitter;
+  }
+
   private handleTransactionTimeout (emitter: EventEmitter<TransactionEventMap>, eventData: TransactionEventResponse): void {
     const timeout = setTimeout(() => {
       const transaction = this.getTransaction(eventData.id);
diff --git a/packages/extension-base/src/types/account/info/keyring.ts b/packages/extension-base/src/types/account/info/keyring.ts
index 5891a41ca93..a092645719d 100644
--- a/packages/extension-base/src/types/account/info/keyring.ts
+++ b/packages/extension-base/src/types/account/info/keyring.ts
@@ -123,9 +123,20 @@ export enum AccountChainType {
   SUBSTRATE = 'substrate',
   ETHEREUM = 'ethereum',
   BITCOIN = 'bitcoin',
-  TON = 'ton'
+  TON = 'ton',
+  CARDANO = 'cardano'
 }
 
+export const ACCOUNT_CHAIN_TYPE_ORDINAL_MAP: Record<string, number> = {
+  [AccountChainType.SUBSTRATE]: 1,
+  [AccountChainType.ETHEREUM]: 2,
+  [AccountChainType.TON]: 3,
+  [AccountChainType.CARDANO]: 4,
+  [AccountChainType.BITCOIN]: 5
+};
+
+export const SUPPORTED_ACCOUNT_CHAIN_TYPES = ['substrate', 'ethereum', 'ton', 'cardano'];
+
 export enum AccountActions {
   DERIVE = 'DERIVE',
   EXPORT_MNEMONIC = 'EXPORT_MNEMONIC',
diff --git a/packages/extension-base/src/types/account/info/proxy.ts b/packages/extension-base/src/types/account/info/proxy.ts
index b1757572368..12d905fc3df 100644
--- a/packages/extension-base/src/types/account/info/proxy.ts
+++ b/packages/extension-base/src/types/account/info/proxy.ts
@@ -20,6 +20,7 @@ export interface AccountProxyData {
   name: string;
   parentId?: string;
   suri?: string;
+  isMigrationDone?: boolean;
 }
 
 /**
@@ -63,6 +64,7 @@ export interface AccountProxy extends AccountProxyData {
   children?: string[];
   tokenTypes: _AssetType[];
   accountActions: AccountActions[];
+  isNeedMigrateUnifiedAccount?: boolean;
 }
 
 export type AccountProxyMap = Record<string, AccountProxy>
diff --git a/packages/extension-base/src/types/balance/index.ts b/packages/extension-base/src/types/balance/index.ts
index aa28f78d33b..586591362b3 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, _SubstrateApi, _TonApi } from '@subwallet/extension-base/services/chain-service/types';
+import { _CardanoApi, _EvmApi, _SubstrateApi, _TonApi } from '@subwallet/extension-base/services/chain-service/types';
 
 import { BN } from '@polkadot/util';
 
@@ -68,3 +68,7 @@ export interface SubscribeEvmPalletBalance extends SubscribeBasePalletBalance {
 export interface SubscribeTonPalletBalance extends SubscribeBasePalletBalance {
   tonApi: _TonApi;
 }
+
+export interface SusbcribeCardanoPalletBalance extends SubscribeBasePalletBalance {
+  cardanoApi: _CardanoApi;
+}
diff --git a/packages/extension-base/src/utils/account/analyze.ts b/packages/extension-base/src/utils/account/analyze.ts
index b4dd0da10be..a9f18ea6937 100644
--- a/packages/extension-base/src/utils/account/analyze.ts
+++ b/packages/extension-base/src/utils/account/analyze.ts
@@ -27,7 +27,7 @@ const isStrValidWithAddress = (str: string, account: AddressDataJson, chainInfo:
     } else if (account.address.toLowerCase().includes(str) || reformated.toLowerCase().includes(str)) {
       return 'valid';
     }
-  } else if (account.chainType === AccountChainType.TON) {
+  } else if (account.chainType === AccountChainType.TON || account.chainType === AccountChainType.CARDANO) { // todo: recheck for Cardano
     const isTestnet = chainInfo.isTestnet;
     const reformated = reformatAddress(account.address, isTestnet ? 0 : 1);
 
diff --git a/packages/extension-base/src/utils/account/common.ts b/packages/extension-base/src/utils/account/common.ts
index e871bf39a51..9e1d66f8ef4 100644
--- a/packages/extension-base/src/utils/account/common.ts
+++ b/packages/extension-base/src/utils/account/common.ts
@@ -2,11 +2,12 @@
 // SPDX-License-Identifier: Apache-2.0
 
 import { _ChainInfo } from '@subwallet/chain-list/types';
+import { ChainType } from '@subwallet/extension-base/background/KoniTypes';
 import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants';
 import { _chainInfoToChainType, _getChainSubstrateAddressPrefix } from '@subwallet/extension-base/services/chain-service/utils';
 import { AccountChainType } from '@subwallet/extension-base/types';
-import { getAccountChainType } from '@subwallet/extension-base/utils';
-import { decodeAddress, encodeAddress, getKeypairTypeByAddress, isAddress, isBitcoinAddress, isTonAddress } from '@subwallet/keyring';
+import { getAccountChainTypeFromKeypairType } from '@subwallet/extension-base/utils';
+import { decodeAddress, encodeAddress, getKeypairTypeByAddress, isAddress, isBitcoinAddress, isCardanoAddress, isTonAddress } from '@subwallet/keyring';
 import { KeypairType } from '@subwallet/keyring/types';
 
 import { ethereumEncode, isEthereumAddress } from '@polkadot/util-crypto';
@@ -49,12 +50,12 @@ export function reformatAddress (address: string, networkPrefix = 42, isEthereum
   }
 }
 
-export const _reformatAddressWithChain = (address: string, chainInfo: _ChainInfo): string => {
+export const _reformatAddressWithChain = (address: string, chainInfo: _ChainInfo): string => { // todo: check for cardano
   const chainType = _chainInfoToChainType(chainInfo);
 
   if (chainType === AccountChainType.SUBSTRATE) {
     return reformatAddress(address, _getChainSubstrateAddressPrefix(chainInfo));
-  } else if (chainType === AccountChainType.TON) {
+  } else if (chainType === AccountChainType.TON || chainType === AccountChainType.CARDANO) {
     const isTestnet = chainInfo.isTestnet;
 
     return reformatAddress(address, isTestnet ? 0 : 1);
@@ -66,38 +67,49 @@ export const _reformatAddressWithChain = (address: string, chainInfo: _ChainInfo
 export const getAccountChainTypeForAddress = (address: string): AccountChainType => {
   const type = getKeypairTypeByAddress(address);
 
-  return getAccountChainType(type);
+  return getAccountChainTypeFromKeypairType(type);
 };
 
-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[] = [];
+interface AddressesByChainType {
+  [ChainType.SUBSTRATE]: string[],
+  [ChainType.EVM]: string[],
+  [ChainType.BITCOIN]: string[],
+  [ChainType.TON]: string[],
+  [ChainType.CARDANO]: string[]
+}
+
+export function getAddressesByChainType (addresses: string[], chainTypes: ChainType[]): string[] {
+  const addressByChainTypeMap = getAddressesByChainTypeMap(addresses);
+
+  return chainTypes.map((chainType) => {
+    return addressByChainTypeMap[chainType];
+  }).flat(); // todo: recheck
+}
+
+export function getAddressesByChainTypeMap (addresses: string[]): AddressesByChainType {
+  const addressByChainType: AddressesByChainType = {
+    substrate: [],
+    evm: [],
+    bitcoin: [],
+    ton: [],
+    cardano: []
+  };
 
   addresses.forEach((address) => {
     if (isEthereumAddress(address)) {
-      evm.push(address);
+      addressByChainType.evm.push(address);
     } else if (isTonAddress(address)) {
-      ton.push(address);
+      addressByChainType.ton.push(address);
     } else if (isBitcoinAddress(address)) {
-      bitcoin.push(address);
+      addressByChainType.bitcoin.push(address);
+    } else if (isCardanoAddress(address)) {
+      addressByChainType.cardano.push(address);
     } else {
-      substrate.push(address);
+      addressByChainType.substrate.push(address);
     }
   });
 
-  return {
-    bitcoin,
-    evm,
-    substrate,
-    ton
-  };
+  return addressByChainType;
 }
 
 export function quickFormatAddressToCompare (address?: string) {
diff --git a/packages/extension-base/src/utils/account/derive/info/solo.ts b/packages/extension-base/src/utils/account/derive/info/solo.ts
index dc6523a5ceb..6ec8a1d258a 100644
--- a/packages/extension-base/src/utils/account/derive/info/solo.ts
+++ b/packages/extension-base/src/utils/account/derive/info/solo.ts
@@ -9,7 +9,7 @@ import { t } from 'i18next';
 
 import { assert } from '@polkadot/util';
 
-import { validateEvmDerivationPath, validateOtherSubstrateDerivationPath, validateSr25519DerivationPath, validateTonDerivationPath, validateUnifiedDerivationPath } from '../validate';
+import { validateCardanoDerivationPath, validateEvmDerivationPath, validateOtherSubstrateDerivationPath, validateSr25519DerivationPath, validateTonDerivationPath, validateUnifiedDerivationPath } from '../validate';
 
 export const parseUnifiedSuriToDerivationPath = (suri: string, type: KeypairType): string => {
   const reg = /^\/\/(\d+)(\/\/\d+)?$/;
@@ -25,12 +25,16 @@ export const parseUnifiedSuriToDerivationPath = (suri: string, type: KeypairType
         return `m/44'/60'/0'/0/${first}/${secondIndex}`;
       } else if (type === 'ton') {
         return `m/44'/607'/${first}'/${secondIndex}'`;
+      } else if (type === 'cardano') {
+        return `m/1852'/1815'/${first}'/${secondIndex}'`;
       }
     } else {
       if (type === 'ethereum') {
         return `m/44'/60'/0'/0/${first}`;
       } else if (type === 'ton') {
         return `m/44'/607'/${first}'`;
+      } else if (type === 'cardano') {
+        return `m/1852'/1815'/${first}'`;
       }
     }
 
@@ -51,7 +55,9 @@ export const getSoloDerivationInfo = (type: KeypairType, metadata: AccountDerive
         ? validateEvmDerivationPath
         : type === 'ton'
           ? validateTonDerivationPath
-          : () => undefined;
+          : type === 'cardano'
+            ? validateCardanoDerivationPath
+            : () => undefined;
       const validateTypeRs = validateTypeFunc(derivePath);
 
       if (validateTypeRs) {
@@ -114,7 +120,9 @@ export const getSoloDerivationInfo = (type: KeypairType, metadata: AccountDerive
         ? validateEvmDerivationPath
         : type === 'ton'
           ? validateTonDerivationPath
-          : () => undefined;
+          : type === 'cardano'
+            ? validateCardanoDerivationPath
+            : () => undefined;
       const validateTypeRs = validateTypeFunc(derivePath);
 
       if (validateTypeRs) {
@@ -242,6 +250,7 @@ export const derivePair = (parentPair: KeyringPair, name: string, suri: string,
 
   const isEvm = EthereumKeypairTypes.includes(parentPair.type);
   const isTon = parentPair.type === 'ton';
+  const isCardano = parentPair.type === 'cardano';
 
   const meta = {
     name,
@@ -255,8 +264,8 @@ export const derivePair = (parentPair: KeyringPair, name: string, suri: string,
     meta.tonContractVersion = parentPair.ton.contractVersion;
   }
 
-  if (derivationPath && (isEvm || isTon)) {
-    return isEvm ? parentPair.evm.deriveCustom(derivationPath, meta) : parentPair.ton.deriveCustom(derivationPath, meta);
+  if (derivationPath && (isEvm || isTon || isCardano)) {
+    return isEvm ? parentPair.evm.deriveCustom(derivationPath, meta) : isTon ? parentPair.ton.deriveCustom(derivationPath, meta) : parentPair.cardano.deriveCustom(derivationPath, meta);
   } else {
     return parentPair.substrate.derive(suri, meta);
   }
diff --git a/packages/extension-base/src/utils/account/derive/validate.ts b/packages/extension-base/src/utils/account/derive/validate.ts
index 9185f917cdc..04c36d9d666 100644
--- a/packages/extension-base/src/utils/account/derive/validate.ts
+++ b/packages/extension-base/src/utils/account/derive/validate.ts
@@ -125,6 +125,46 @@ export const validateTonDerivationPath = (raw: string): IDerivePathInfo_ | undef
   }
 };
 
+export const validateCardanoDerivationPath = (raw: string): IDerivePathInfo_ | undefined => {
+  const reg = /^m\/1852'\/1815'\/(\d+)'(\/\d+')?$/;
+
+  if (raw.match(reg)) {
+    const [, firstIndex, secondData] = raw.match(reg) as string[];
+
+    const first = parseInt(firstIndex, 10);
+    const autoIndexes: number[] = [first];
+
+    let depth: number;
+    let suri = `//${first}`;
+
+    if (first === 0) {
+      depth = 0;
+    } else {
+      depth = 1;
+    }
+
+    if (secondData) {
+      const [, secondIndex] = secondData.match(/\/(\d+)/) as string[];
+
+      const second = parseInt(secondIndex, 10);
+
+      autoIndexes.push(second);
+      depth = 2;
+      suri += `//${second}`;
+    }
+
+    return {
+      depth,
+      type: 'cardano',
+      suri,
+      derivationPath: raw,
+      autoIndexes
+    };
+  } else {
+    return undefined;
+  }
+};
+
 export const validateSr25519DerivationPath = (raw: string): IDerivePathInfo_ | undefined => {
   const reg = /\/(\/?)([^/]+)/g;
   const parts = raw.match(reg);
@@ -197,10 +237,12 @@ export const validateDerivationPath = (raw: string, type?: KeypairType): DeriveP
       return validateSr25519DerivationPath(raw);
     } else if (type === 'ed25519' || type === 'ecdsa') {
       return validateOtherSubstrateDerivationPath(raw, type);
+    } else if (type === 'cardano') {
+      return validateCardanoDerivationPath(raw);
     } else {
       return undefined;
     }
   } else {
-    return validateUnifiedDerivationPath(raw) || validateEvmDerivationPath(raw) || validateTonDerivationPath(raw) || validateSr25519DerivationPath(raw);
+    return validateUnifiedDerivationPath(raw) || validateEvmDerivationPath(raw) || validateTonDerivationPath(raw) || validateSr25519DerivationPath(raw) || validateCardanoDerivationPath(raw);
   }
 };
diff --git a/packages/extension-base/src/utils/account/transform.ts b/packages/extension-base/src/utils/account/transform.ts
index d26f22c7977..6f1d6637bb3 100644
--- a/packages/extension-base/src/utils/account/transform.ts
+++ b/packages/extension-base/src/utils/account/transform.ts
@@ -5,9 +5,9 @@ import { _AssetType, _ChainInfo } from '@subwallet/chain-list/types';
 import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
 import { ALL_ACCOUNT_KEY, isProductionMode } 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 { AccountActions, AccountChainType, AccountJson, AccountMetadataData, AccountProxy, AccountProxyMap, AccountProxyStoreData, AccountProxyType, AccountSignMode, AddressJson, ModifyPairStoreData, SUPPORTED_ACCOUNT_CHAIN_TYPES } from '@subwallet/extension-base/types';
 import { getKeypairTypeByAddress, tonMnemonicToEntropy } from '@subwallet/keyring';
-import { BitcoinKeypairTypes, EthereumKeypairTypes, KeypairType, KeyringPair, KeyringPair$Meta, TonKeypairTypes } from '@subwallet/keyring/types';
+import { BitcoinKeypairTypes, CardanoKeypairTypes, 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';
 
@@ -44,7 +44,7 @@ export const createAccountProxyId = (_suri: string, derivationPath?: string) =>
   return blake2AsHex(data, 256);
 };
 
-export const getAccountChainType = (type: KeypairType): AccountChainType => {
+export const getAccountChainTypeFromKeypairType = (type: KeypairType): AccountChainType => {
   return type
     ? EthereumKeypairTypes.includes(type)
       ? AccountChainType.ETHEREUM
@@ -52,10 +52,26 @@ export const getAccountChainType = (type: KeypairType): AccountChainType => {
         ? AccountChainType.TON
         : BitcoinKeypairTypes.includes(type)
           ? AccountChainType.BITCOIN
-          : AccountChainType.SUBSTRATE
+          : CardanoKeypairTypes.includes(type)
+            ? AccountChainType.CARDANO
+            : AccountChainType.SUBSTRATE
     : AccountChainType.SUBSTRATE;
 };
 
+export const getDefaultKeypairTypeFromAccountChainType = (type: AccountChainType): KeypairType => {
+  if (type === AccountChainType.ETHEREUM) {
+    return 'ethereum';
+  } else if (type === AccountChainType.TON) {
+    return 'ton';
+  } else if (type === AccountChainType.BITCOIN) {
+    return 'bitcoin-84';
+  } else if (type === AccountChainType.CARDANO) {
+    return 'cardano';
+  } else {
+    return 'sr25519';
+  }
+};
+
 export const getAccountSignMode = (address: string, _meta?: KeyringPair$Meta): AccountSignMode => {
   const meta = _meta as AccountMetadataData;
 
@@ -92,6 +108,7 @@ export const getAccountActions = (signMode: AccountSignMode, networkType: Accoun
   const result: AccountActions[] = [];
   const meta = _meta as AccountMetadataData;
 
+  // todo: check this function for Cardano
   // JSON
   if (signMode === AccountSignMode.PASSWORD) {
     result.push(AccountActions.EXPORT_JSON);
@@ -253,6 +270,10 @@ export const getAccountTransactionActions = (signMode: AccountSignMode, networkT
         return [
           ...BASE_TRANSFER_ACTIONS
         ];
+      case AccountChainType.CARDANO:
+        return [
+          ...BASE_TRANSFER_ACTIONS
+        ];
     }
   } else if (signMode === AccountSignMode.QR) {
     switch (networkType) {
@@ -287,6 +308,8 @@ export const getAccountTransactionActions = (signMode: AccountSignMode, networkT
         ];
       case AccountChainType.TON:
         return [];
+      case AccountChainType.CARDANO:
+        return [];
     }
   } else if (signMode === AccountSignMode.GENERIC_LEDGER) {
     switch (networkType) {
@@ -316,6 +339,8 @@ export const getAccountTransactionActions = (signMode: AccountSignMode, networkT
         return [
           ...BASE_TRANSFER_ACTIONS
         ];
+      case AccountChainType.CARDANO:
+        return [];
     }
   } else if (signMode === AccountSignMode.LEGACY_LEDGER) { // Only for Substrate
     const result: ExtrinsicType[] = [];
@@ -379,6 +404,8 @@ export const getAccountTokenTypes = (type: KeypairType): _AssetType[] => {
     case 'bitcoin-86':
     case 'bittest-86':
       return [_AssetType.NATIVE, _AssetType.RUNE, _AssetType.BRC20];
+    case 'cardano':
+      return [_AssetType.NATIVE, _AssetType.CIP26];
     default:
       return [];
   }
@@ -403,7 +430,7 @@ export const getAccountTokenTypes = (type: KeypairType): _AssetType[] => {
 export const transformAccount = (address: string, _type?: KeypairType, meta?: KeyringPair$Meta, chainInfoMap?: Record<string, _ChainInfo>, parentAccount?: AccountJson): AccountJson => {
   const signMode = getAccountSignMode(address, meta);
   const type = _type || getKeypairTypeByAddress(address);
-  const chainType: AccountChainType = getAccountChainType(type);
+  const chainType: AccountChainType = getAccountChainTypeFromKeypairType(type);
   let specialChain: string | undefined;
 
   if (!chainInfoMap) {
@@ -464,7 +491,7 @@ export const transformAccounts = (accounts: SubjectInfo): AccountJson[] => Objec
 
 export const transformAddress = (address: string, meta?: KeyringPair$Meta): AddressJson => {
   const type = getKeypairTypeByAddress(address);
-  const chainType: AccountChainType = getAccountChainType(type);
+  const chainType: AccountChainType = getAccountChainTypeFromKeypairType(type);
 
   return {
     address,
@@ -539,6 +566,7 @@ export const _combineAccounts = (accounts: AccountJson[], modifyPairs: ModifyPai
         let tokenTypes: _AssetType[] = [];
         let accountActions: AccountActions[] = [];
         let specialChain: string | undefined;
+        let isNeedMigrateUnifiedAccount: boolean | undefined;
 
         if (value.accounts.length > 1) {
           accountType = AccountProxyType.UNIFIED;
@@ -551,6 +579,10 @@ export const _combineAccounts = (accounts: AccountJson[], modifyPairs: ModifyPai
             return rs;
           }, new Set()));
 
+          if (chainTypes.length < SUPPORTED_ACCOUNT_CHAIN_TYPES.length) {
+            isNeedMigrateUnifiedAccount = true;
+          }
+
           /* Account actions */
 
           // Mnemonic
@@ -584,6 +616,10 @@ export const _combineAccounts = (accounts: AccountJson[], modifyPairs: ModifyPai
             accountActions = accountActions.filter((action) => action !== AccountActions.DERIVE);
           }
 
+          if (chainTypes.length === 1 && accountActions.includes(AccountActions.EXPORT_MNEMONIC) && account.isMasterAccount && account.type !== 'ton-native') {
+            isNeedMigrateUnifiedAccount = true;
+          }
+
           switch (account.signMode) {
             case AccountSignMode.GENERIC_LEDGER:
             case AccountSignMode.LEGACY_LEDGER:
@@ -592,7 +628,7 @@ export const _combineAccounts = (accounts: AccountJson[], modifyPairs: ModifyPai
           }
         }
 
-        return [key, { ...value, accountType, chainTypes, specialChain, tokenTypes, accountActions }];
+        return [key, { ...value, accountType, chainTypes, specialChain, tokenTypes, accountActions, isNeedMigrateUnifiedAccount }];
       })
   );
 
@@ -687,17 +723,10 @@ export const combineAllAccountProxy = (accountProxies: AccountProxy[]): AccountP
   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 (chainTypes.size === 3) {
-      break;
-    }
-
     for (const chainType of accountProxy.chainTypes) {
       chainTypes.add(chainType);
     }
-  }
 
-  for (const accountProxy of accountProxies) {
     for (const tokenType of accountProxy.tokenTypes) {
       tokenTypes.add(tokenType);
     }
diff --git a/packages/extension-base/src/utils/index.ts b/packages/extension-base/src/utils/index.ts
index 63cccdd65da..eb209962ff9 100644
--- a/packages/extension-base/src/utils/index.ts
+++ b/packages/extension-base/src/utils/index.ts
@@ -5,10 +5,10 @@ import { _ChainInfo } from '@subwallet/chain-list/types';
 import { CrowdloanParaState, NetworkJson } from '@subwallet/extension-base/background/KoniTypes';
 import { AccountAuthType } from '@subwallet/extension-base/background/types';
 import { getRandomIpfsGateway, SUBWALLET_IPFS } from '@subwallet/extension-base/koni/api/nft/config';
-import { _isChainEvmCompatible, _isChainSubstrateCompatible, _isChainTonCompatible } from '@subwallet/extension-base/services/chain-service/utils';
+import { _isChainCardanoCompatible, _isChainEvmCompatible, _isChainSubstrateCompatible, _isChainTonCompatible } from '@subwallet/extension-base/services/chain-service/utils';
 import { AccountJson } from '@subwallet/extension-base/types';
 import { reformatAddress } from '@subwallet/extension-base/utils/account';
-import { decodeAddress, encodeAddress, isTonAddress } from '@subwallet/keyring';
+import { decodeAddress, encodeAddress, isCardanoAddress, isTonAddress } from '@subwallet/keyring';
 import { t } from 'i18next';
 
 import { assert, BN, hexToU8a, isHex } from '@polkadot/util';
@@ -304,8 +304,9 @@ export function isAddressAndChainCompatible (address: string, chain: _ChainInfo)
   const isEvmCompatible = isEthereumAddress(address) && _isChainEvmCompatible(chain);
   const isTonCompatible = isTonAddress(address) && _isChainTonCompatible(chain);
   const isSubstrateCompatible = !isEthereumAddress(address) && !isTonAddress(address) && _isChainSubstrateCompatible(chain); // todo: need isSubstrateAddress util function to check exactly
+  const isCardanoCompatible = isCardanoAddress(address) && _isChainCardanoCompatible(chain);
 
-  return isEvmCompatible || isSubstrateCompatible || isTonCompatible;
+  return isEvmCompatible || isSubstrateCompatible || isTonCompatible || isCardanoCompatible;
 }
 
 export function getDomainFromUrl (url: string): string {
diff --git a/packages/extension-base/tsconfig.build.json b/packages/extension-base/tsconfig.build.json
index 8d1ebf4e39d..b60a1d9756d 100644
--- a/packages/extension-base/tsconfig.build.json
+++ b/packages/extension-base/tsconfig.build.json
@@ -11,6 +11,8 @@
     { "path": "../extension-dapp/tsconfig.build.json"
     },
     { "path": "../extension-inject/tsconfig.build.json"
+    },
+    { "path": "../subwallet-api-sdk/tsconfig.build.json"
     }
   ]
 }
diff --git a/packages/extension-base/tsconfig.json b/packages/extension-base/tsconfig.json
index 25e08522878..4451ed53483 100644
--- a/packages/extension-base/tsconfig.json
+++ b/packages/extension-base/tsconfig.json
@@ -8,6 +8,7 @@
   "references": [
     { "path": "../extension-chains" },
     { "path": "../extension-dapp" },
-    { "path": "../extension-inject" }
+    { "path": "../extension-inject" },
+    { "path": "../subwallet-api-sdk" }
   ]
 }
diff --git a/packages/extension-koni-ui/src/Popup/Account/ImportSeedPhrase.tsx b/packages/extension-koni-ui/src/Popup/Account/ImportSeedPhrase.tsx
index 9efc5158ad8..f86b6f53350 100644
--- a/packages/extension-koni-ui/src/Popup/Account/ImportSeedPhrase.tsx
+++ b/packages/extension-koni-ui/src/Popup/Account/ImportSeedPhrase.tsx
@@ -36,7 +36,7 @@ interface FormState extends Record<`seed-phrase-${number}`, string> {
 }
 
 const words = wordlists.english;
-const phraseNumberOptions = [12, 24];
+const phraseNumberOptions = [12, 15, 24];
 
 const Component: React.FC<Props> = ({ className }: Props) => {
   useAutoNavigateToCreatePassword();
diff --git a/packages/extension-koni-ui/src/Popup/Account/RestoreJson/AccountRestoreJsonItem.tsx b/packages/extension-koni-ui/src/Popup/Account/RestoreJson/AccountRestoreJsonItem.tsx
index febc2ac6623..22ae43cee0a 100644
--- a/packages/extension-koni-ui/src/Popup/Account/RestoreJson/AccountRestoreJsonItem.tsx
+++ b/packages/extension-koni-ui/src/Popup/Account/RestoreJson/AccountRestoreJsonItem.tsx
@@ -1,8 +1,8 @@
 // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors
 // SPDX-License-Identifier: Apache-2.0
 
-import { AccountChainType, AccountProxyExtra, AccountProxyType } from '@subwallet/extension-base/types';
-import { AccountProxyAvatar } from '@subwallet/extension-koni-ui/components';
+import { AccountProxyExtra, AccountProxyType } from '@subwallet/extension-base/types';
+import { AccountChainTypeLogos, AccountProxyAvatar } from '@subwallet/extension-koni-ui/components';
 import { useTranslation } from '@subwallet/extension-koni-ui/hooks';
 import { Theme } from '@subwallet/extension-koni-ui/themes';
 import { PhosphorIcon } from '@subwallet/extension-koni-ui/types';
@@ -47,16 +47,7 @@ function Component (props: _AccountCardItem): React.ReactElement<_AccountCardIte
   const { accountType, chainTypes, id: accountProxyId, name: accountName } = useMemo(() => accountProxy, [accountProxy]);
   const { t } = useTranslation();
   const token = useContext<Theme>(ThemeContext as Context<Theme>).token;
-  const logoMap = useContext<Theme>(ThemeContext as Context<Theme>).logoMap;
   const disabledItem = useMemo(() => disabled || accountProxy.isExistAccount, [accountProxy.isExistAccount, disabled]);
-  const chainTypeLogoMap = useMemo(() => {
-    return {
-      [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]);
   const _onSelect = useCallback(() => {
     onClick && onClick(accountProxyId || '');
   },
@@ -150,20 +141,11 @@ function Component (props: _AccountCardItem): React.ReactElement<_AccountCardIte
         <div className='__item-center-part'>
           <div className={'middle-item__name-wrapper'}>
             <div className='__item-name'>{accountName}</div>
-            <div className='__item-chain-types'>
-              {
-                chainTypes.map((nt) => {
-                  return (
-                    <img
-                      alt='Network type'
-                      className={'__item-chain-type-item'}
-                      key={nt}
-                      src={chainTypeLogoMap[nt]}
-                    />
-                  );
-                })
-              }
-            </div>
+
+            <AccountChainTypeLogos
+              chainTypes={chainTypes}
+              className={'__item-chain-type-logos'}
+            />
           </div>
         </div>
 
@@ -268,22 +250,8 @@ const AccountRestoreJsonItem = styled(Component)<_AccountCardItem>(({ theme }) =
       overflow: 'hidden',
       'white-space': 'nowrap'
     },
-    '.__item-chain-types': {
-      display: 'flex',
-      paddingTop: 2,
-
-      '.__item-chain-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-chain-type-item:first-of-type': {
-        marginLeft: 0
-      }
+    '.__item-chain-type-logos': {
+      minHeight: 20
     },
     '.__item-right-part': {
       marginLeft: 'auto',
diff --git a/packages/extension-koni-ui/src/Popup/Confirmations/parts/Sign/Cardano.tsx b/packages/extension-koni-ui/src/Popup/Confirmations/parts/Sign/Cardano.tsx
new file mode 100644
index 00000000000..e9efc5ed827
--- /dev/null
+++ b/packages/extension-koni-ui/src/Popup/Confirmations/parts/Sign/Cardano.tsx
@@ -0,0 +1,148 @@
+// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import { ConfirmationDefinitionsCardano, ConfirmationResult, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
+import { useNotification } from '@subwallet/extension-koni-ui/hooks';
+import useUnlockChecker from '@subwallet/extension-koni-ui/hooks/common/useUnlockChecker';
+import { completeConfirmationCardano } from '@subwallet/extension-koni-ui/messaging';
+import { CardanoSignatureSupportType, PhosphorIcon, ThemeProps } from '@subwallet/extension-koni-ui/types';
+import { removeTransactionPersist } from '@subwallet/extension-koni-ui/utils';
+import { Button, Icon } from '@subwallet/react-ui';
+import CN from 'classnames';
+import { CheckCircle, XCircle } from 'phosphor-react';
+import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import styled from 'styled-components';
+
+interface Props extends ThemeProps {
+  id: string;
+  type: CardanoSignatureSupportType;
+  payload: ConfirmationDefinitionsCardano[CardanoSignatureSupportType][0];
+  extrinsicType?: ExtrinsicType;
+  txExpirationTime?: number;
+}
+
+const handleConfirm = async (type: CardanoSignatureSupportType, id: string, payload: string) => {
+  return await completeConfirmationCardano(type, {
+    id,
+    isApproved: true,
+    payload
+  } as ConfirmationResult<string>);
+};
+
+const handleCancel = async (type: CardanoSignatureSupportType, id: string) => {
+  return await completeConfirmationCardano(type, {
+    id,
+    isApproved: false
+  } as ConfirmationResult<string>);
+};
+
+const Component: React.FC<Props> = (props: Props) => {
+  const { className, extrinsicType, id, txExpirationTime, type } = props;
+
+  const { t } = useTranslation();
+  const notify = useNotification();
+
+  const checkUnlock = useUnlockChecker();
+
+  const [showQuoteExpired, setShowQuoteExpired] = useState<boolean>(false);
+
+  const [loading, setLoading] = useState(false);
+
+  const approveIcon = useMemo((): PhosphorIcon => {
+    return CheckCircle;
+  }, []);
+
+  // Handle buttons actions
+  const onCancel = useCallback(() => {
+    setLoading(true);
+    handleCancel(type, id).finally(() => {
+      setLoading(false);
+    });
+  }, [id, type]);
+
+  const onApprovePassword = useCallback(() => {
+    setLoading(true);
+    setTimeout(() => {
+      handleConfirm(type, id, '').finally(() => {
+        setLoading(false);
+      });
+    }, 1000);
+  }, [id, type]);
+
+  const onConfirm = useCallback(() => {
+    removeTransactionPersist(extrinsicType);
+
+    if (txExpirationTime) {
+      const currentTime = +Date.now();
+
+      if (currentTime >= txExpirationTime) {
+        notify({
+          message: t('Transaction expired'),
+          type: 'error'
+        });
+        onCancel();
+      }
+    }
+
+    checkUnlock().then(() => {
+      onApprovePassword();
+    }).catch(() => {
+      // Unlock is cancelled
+    });
+  }, [extrinsicType, txExpirationTime, notify, t, onCancel, checkUnlock, onApprovePassword]);
+
+  useEffect(() => {
+    let timer: NodeJS.Timer;
+
+    if (txExpirationTime) {
+      timer = setInterval(() => {
+        if (Date.now() >= txExpirationTime) {
+          setShowQuoteExpired(true);
+          clearInterval(timer);
+        }
+      }, 1000);
+    }
+
+    return () => {
+      clearInterval(timer);
+    };
+  }, [txExpirationTime]);
+
+  return (
+    <div className={CN(className, 'confirmation-footer')}>
+      <Button
+        disabled={loading}
+        icon={(
+          <Icon
+            phosphorIcon={XCircle}
+            weight='fill'
+          />
+        )}
+        onClick={onCancel}
+        schema={'secondary'}
+      >
+        {t('Cancel')}
+      </Button>
+      <Button
+        disabled={showQuoteExpired}
+        icon={(
+          <Icon
+            phosphorIcon={approveIcon}
+            weight='fill'
+          />
+        )}
+        loading={loading}
+        onClick={onConfirm}
+      >
+        {t('Approve')}
+      </Button>
+    </div>
+  );
+};
+
+const CardanoSignArea = styled(Component)<Props>(({ theme: { token } }: Props) => {
+  return {};
+});
+
+export default CardanoSignArea;
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 b9ca17b77da..342f3039b65 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, ConfirmationDefinitionsTon, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
+import { ConfirmationDefinitions, ConfirmationDefinitionsCardano, 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 CardanoSignArea from '@subwallet/extension-koni-ui/Popup/Confirmations/parts/Sign/Cardano';
 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';
@@ -172,6 +173,17 @@ const Component: React.FC<Props> = (props: Props) => {
           />
         )
       }
+      {
+        (type === 'cardanoSendTransactionRequest' || type === 'cardanoWatchTransactionRequest') && (
+          <CardanoSignArea
+            extrinsicType={transaction.extrinsicType}
+            id={item.id}
+            payload={(item as ConfirmationDefinitionsCardano['cardanoSendTransactionRequest' | 'cardanoWatchTransactionRequest'][0])}
+            txExpirationTime={txExpirationTime}
+            type={type}
+          />
+        )
+      }
     </>
   );
 };
diff --git a/packages/extension-koni-ui/src/Popup/Home/History/Detail/parts/Layout.tsx b/packages/extension-koni-ui/src/Popup/Home/History/Detail/parts/Layout.tsx
index 8db65e97c38..29214c7dc78 100644
--- a/packages/extension-koni-ui/src/Popup/Home/History/Detail/parts/Layout.tsx
+++ b/packages/extension-koni-ui/src/Popup/Home/History/Detail/parts/Layout.tsx
@@ -9,10 +9,12 @@ import SwapLayout from '@subwallet/extension-koni-ui/Popup/Home/History/Detail/p
 import { ThemeProps, TransactionHistoryDisplayItem } from '@subwallet/extension-koni-ui/types';
 import { formatHistoryDate, isAbleToShowFee, toShort } from '@subwallet/extension-koni-ui/utils';
 import CN from 'classnames';
-import React from 'react';
+import React, { useMemo } from 'react';
 import { useTranslation } from 'react-i18next';
 import styled from 'styled-components';
 
+import { hexAddPrefix, isHex } from '@polkadot/util';
+
 import HistoryDetailAmount from './Amount';
 import HistoryDetailFee from './Fee';
 import HistoryDetailHeader from './Header';
@@ -28,6 +30,12 @@ const Component: React.FC<Props> = (props: Props) => {
 
   const { language } = useSelector((state) => state.settings);
 
+  const extrinsicHash = useMemo(() => {
+    const hash = data.extrinsicHash || '';
+
+    return isHex(hexAddPrefix(hash)) ? toShort(data.extrinsicHash, 8, 9) : '...';
+  }, [data.extrinsicHash]);
+
   if (data.type === ExtrinsicType.SWAP) {
     return (
       <SwapLayout data={data} />
@@ -47,7 +55,7 @@ const Component: React.FC<Props> = (props: Props) => {
         statusName={t(HistoryStatusMap[data.status].name)}
         valueColorSchema={HistoryStatusMap[data.status].schema}
       />
-      <MetaInfo.Default label={t('Extrinsic hash')}>{(data.extrinsicHash || '').startsWith('0x') ? toShort(data.extrinsicHash, 8, 9) : '...'}</MetaInfo.Default>
+      <MetaInfo.Default label={t('Extrinsic hash')}>{extrinsicHash}</MetaInfo.Default>
       <MetaInfo.Default label={t('Transaction time')}>{formatHistoryDate(data.time, language, 'detail')}</MetaInfo.Default>
       <HistoryDetailAmount data={data} />
 
diff --git a/packages/extension-koni-ui/src/Popup/Home/index.tsx b/packages/extension-koni-ui/src/Popup/Home/index.tsx
index d397f660a7f..643e58729b5 100644
--- a/packages/extension-koni-ui/src/Popup/Home/index.tsx
+++ b/packages/extension-koni-ui/src/Popup/Home/index.tsx
@@ -1,7 +1,7 @@
 // Copyright 2019-2022 @polkadot/extension-ui authors & contributors
 // SPDX-License-Identifier: Apache-2.0
 
-import { Layout, RemindUpgradeUnifiedAccount } from '@subwallet/extension-koni-ui/components';
+import { Layout } from '@subwallet/extension-koni-ui/components';
 import { GlobalSearchTokenModal } from '@subwallet/extension-koni-ui/components/Modal/GlobalSearchTokenModal';
 import RemindUpgradeFirefoxVersion from '@subwallet/extension-koni-ui/components/Modal/RemindUpgradeFirefoxVersion';
 import { GeneralTermModal } from '@subwallet/extension-koni-ui/components/Modal/TermsAndConditions/GeneralTermModal';
@@ -131,7 +131,6 @@ function Component ({ className = '' }: Props): React.ReactElement<Props> {
             <Outlet />
             <GeneralTermModal onOk={onAfterConfirmTermModal} />
             <RemindUpgradeFirefoxVersion />
-            <RemindUpgradeUnifiedAccount />
           </Layout.Home>
         </div>
       </HomeContext.Provider>
diff --git a/packages/extension-koni-ui/src/Popup/MigrateAccount/BriefView/index.tsx b/packages/extension-koni-ui/src/Popup/MigrateAccount/BriefView/index.tsx
new file mode 100644
index 00000000000..f11a11533b2
--- /dev/null
+++ b/packages/extension-koni-ui/src/Popup/MigrateAccount/BriefView/index.tsx
@@ -0,0 +1,259 @@
+// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import { LoadingScreen } from '@subwallet/extension-koni-ui/components';
+import ContentGenerator from '@subwallet/extension-koni-ui/components/StaticContent/ContentGenerator';
+import { useFetchMarkdownContentData } from '@subwallet/extension-koni-ui/hooks';
+import { ThemeProps } from '@subwallet/extension-koni-ui/types';
+import { Button, Icon, PageIcon } from '@subwallet/react-ui';
+import CN from 'classnames';
+import { CheckCircle, Warning, XCircle } from 'phosphor-react';
+import React, { useEffect, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import styled from 'styled-components';
+
+type Props = ThemeProps & {
+  isForcedMigration?: boolean;
+  onDismiss: VoidFunction;
+  onMigrateNow: VoidFunction;
+};
+
+type ContentDataType = {
+  content: string,
+  title: string
+};
+
+function Component ({ className = '', isForcedMigration, onDismiss, onMigrateNow }: Props) {
+  const { t } = useTranslation();
+  const [contentData, setContentData] = useState<ContentDataType>({
+    content: '',
+    title: ''
+  });
+  const [isFetchingBriefContent, setIsFetchingBriefContent] = useState<boolean>(true);
+
+  const fetchMarkdownContentData = useFetchMarkdownContentData();
+
+  useEffect(() => {
+    let sync = true;
+
+    if (!isForcedMigration) {
+      setIsFetchingBriefContent(true);
+
+      fetchMarkdownContentData<ContentDataType>('unified_account_migration_content', ['en'])
+        .then((data) => {
+          if (sync) {
+            setContentData(data);
+            setIsFetchingBriefContent(false);
+          }
+        })
+        .catch((e) => console.log('fetch unified_account_migration_content error:', e));
+    }
+
+    return () => {
+      sync = false;
+    };
+  }, [fetchMarkdownContentData, isForcedMigration]);
+
+  useEffect(() => {
+    if (isForcedMigration) {
+      setIsFetchingBriefContent(false);
+    }
+  }, [isForcedMigration]);
+
+  if (isFetchingBriefContent) {
+    return (<LoadingScreen />);
+  }
+
+  return (
+    <div className={CN(className, {
+      '-forced-migration': isForcedMigration
+    })}
+    >
+      <div className='__header-area'>
+        <div className='__view-title'>
+          {
+            !isForcedMigration
+              ? contentData.title
+              : t('Migration incomplete!')
+          }
+        </div>
+      </div>
+
+      <div className='__body-area'>
+        {
+          !isForcedMigration && (
+            <ContentGenerator
+              className={'__content-generator'}
+              content={contentData.content || ''}
+            />
+          )
+        }
+
+        {
+          isForcedMigration && (
+            <>
+              <div className={CN('__warning-icon')}>
+                <PageIcon
+                  color='var(--page-icon-color)'
+                  iconProps={{
+                    phosphorIcon: Warning
+                  }}
+                />
+              </div>
+              <div className={'__forced-migration-content'}>
+                <div className='__content-line'>
+                  {t('Account migration is not yet complete. If this process remains incomplete, you will not be able to perform any action on SubWallet extension.')}
+                </div>
+                <div className='__content-line'>
+                  {t('Make sure to complete the migration to avoid any potential issues with your accounts. Hit “Continue” to resume and complete the process. ')}
+                </div>
+              </div>
+            </>
+          )
+        }
+      </div>
+
+      <div className='__footer-area'>
+        {
+          !isForcedMigration && (
+            <>
+              <Button
+                block={true}
+                icon={(
+                  <Icon
+                    phosphorIcon={XCircle}
+                    weight='fill'
+                  />
+                )}
+                onClick={onDismiss}
+                schema={'secondary'}
+              >
+                {t('Cancel')}
+              </Button>
+              <Button
+                block={true}
+                icon={(
+                  <Icon
+                    phosphorIcon={CheckCircle}
+                    weight='fill'
+                  />
+                )}
+                onClick={onMigrateNow}
+              >
+                {t('Migrate now')}
+              </Button>
+            </>
+          )
+        }
+
+        {
+          isForcedMigration && (
+            <Button
+              block={true}
+              onClick={onMigrateNow}
+            >
+              {t('Continue')}
+            </Button>
+          )
+        }
+      </div>
+    </div>
+  );
+}
+
+export const BriefView = styled(Component)<Props>(({ theme: { extendToken, token } }: Props) => {
+  return ({
+    display: 'flex',
+    flexDirection: 'column',
+    height: '100%',
+
+    '.__header-area': {
+      minHeight: 74,
+      padding: token.padding,
+      color: token.colorTextLight1,
+      borderBottom: '2px solid',
+      borderColor: token.colorBgSecondary,
+      display: 'flex',
+      alignItems: 'center'
+    },
+
+    '.__view-title': {
+      flex: 1,
+      overflow: 'hidden',
+      textOverflow: 'ellipsis',
+      'white-space': 'nowrap',
+      fontSize: token.fontSizeHeading4,
+      lineHeight: token.lineHeightHeading4,
+      textAlign: 'center'
+    },
+
+    '.__body-area': {
+      flex: 1,
+      overflow: 'auto',
+      padding: token.padding,
+      paddingBottom: 0
+    },
+
+    '.__footer-area': {
+      display: 'flex',
+      gap: token.sizeSM,
+      paddingLeft: token.padding,
+      paddingRight: token.padding,
+      paddingTop: token.padding,
+      paddingBottom: 32
+    },
+
+    '.__forced-migration-content': {
+      textAlign: 'center',
+      color: token.colorTextLight4,
+      fontSize: token.fontSize,
+      lineHeight: token.lineHeight
+    },
+
+    '.__warning-icon': {
+      display: 'flex',
+      justifyContent: 'center',
+      marginBottom: 20,
+      '--page-icon-color': token.colorWarning
+    },
+
+    '.__content-line + .__content-line': {
+      marginTop: 20
+    },
+
+    // content generator
+
+    '.md-element + .md-element': {
+      marginTop: 20
+    },
+
+    '.md-subtitle': {
+      fontSize: token.fontSizeHeading5,
+      lineHeight: token.lineHeightHeading5,
+      textAlign: 'center'
+    },
+
+    '.md-banner': {
+      maxWidth: '100%',
+      display: 'block'
+    },
+
+    '.md-text-center': {
+      textAlign: 'center'
+    },
+
+    '.md-p-tag': {
+      color: token.colorTextLight4,
+      fontSize: token.fontSize,
+      lineHeight: token.lineHeight
+    },
+
+    '&.-forced-migration': {
+      '.__body-area': {
+        paddingTop: 40,
+        paddingRight: 32,
+        paddingLeft: 32
+      }
+    }
+  });
+});
diff --git a/packages/extension-koni-ui/src/Popup/MigrateAccount/EnterPasswordModal.tsx b/packages/extension-koni-ui/src/Popup/MigrateAccount/EnterPasswordModal.tsx
new file mode 100644
index 00000000000..c0b135db540
--- /dev/null
+++ b/packages/extension-koni-ui/src/Popup/MigrateAccount/EnterPasswordModal.tsx
@@ -0,0 +1,157 @@
+// Copyright 2019-2022 @polkadot/extension-ui authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import { useTranslation } from '@subwallet/extension-koni-ui/hooks';
+import { FormCallbacks, ThemeProps, VoidFunction } from '@subwallet/extension-koni-ui/types';
+import { Button, Form, Icon, Input, SwModal } from '@subwallet/react-ui';
+import { ArrowCircleRight, XCircle } from 'phosphor-react';
+import React, { useCallback, useState } from 'react';
+import styled from 'styled-components';
+
+import useFocusById from '../../hooks/form/useFocusById';
+
+type Props = ThemeProps & {
+  onClose: VoidFunction;
+  onSubmit: (password: string) => Promise<void>;
+}
+
+export const enterPasswordModalId = 'enterPasswordModalId';
+
+const passwordInputId = 'enter-password-input-id';
+
+enum FormFieldName {
+  PASSWORD = 'password'
+}
+
+interface LoginFormState {
+  [FormFieldName.PASSWORD]: string;
+}
+
+function Component ({ className = '', onClose, onSubmit }: Props): React.ReactElement<Props> {
+  const { t } = useTranslation();
+  const [form] = Form.useForm<LoginFormState>();
+  const [loading, setLoading] = useState(false);
+
+  const onError = useCallback((error: string) => {
+    form.setFields([{ name: FormFieldName.PASSWORD, errors: [error] }]);
+    (document.getElementById(passwordInputId) as HTMLInputElement)?.select();
+  }, [form]);
+
+  const _onSubmit: FormCallbacks<LoginFormState>['onFinish'] = useCallback((values: LoginFormState) => {
+    setLoading(true);
+    setTimeout(() => {
+      onSubmit(values[FormFieldName.PASSWORD])
+        .catch((e: Error) => {
+          onError(e.message);
+        })
+        .finally(() => {
+          setLoading(false);
+        });
+    }, 500);
+  }, [onError, onSubmit]);
+
+  useFocusById(passwordInputId);
+
+  return (
+    <SwModal
+      className={className}
+      closable={false}
+      footer={(
+        <>
+          <Button
+            block={true}
+            disabled={loading}
+            icon={(
+              <Icon
+                phosphorIcon={XCircle}
+                weight='fill'
+              />
+            )}
+            onClick={onClose}
+            schema={'secondary'}
+          >
+            {t('Cancel')}
+          </Button>
+          <Button
+            block={true}
+            disabled={loading}
+            icon={(
+              <Icon
+                phosphorIcon={ArrowCircleRight}
+                weight='fill'
+              />
+            )}
+            loading={loading}
+            onClick={form.submit}
+          >
+            {t('Continue')}
+          </Button>
+        </>
+      )}
+      id={enterPasswordModalId}
+      title={t('Enter password')}
+      zIndex={9999}
+    >
+      <div className='__brief'>
+        {t('Enter your SubWallet password to continue')}
+      </div>
+
+      <Form
+        form={form}
+        initialValues={{ [FormFieldName.PASSWORD]: '' }}
+        onFinish={_onSubmit}
+      >
+        <Form.Item
+          name={FormFieldName.PASSWORD}
+          rules={[
+            {
+              message: t('Password is required'),
+              required: true
+            }
+          ]}
+          statusHelpAsTooltip={true}
+        >
+          <Input.Password
+            containerClassName='__password-input'
+            id={passwordInputId}
+            label={t('Password')}
+            placeholder={t('Enter password')}
+            suffix={<span />}
+          />
+        </Form.Item>
+      </Form>
+    </SwModal>
+  );
+}
+
+export const EnterPasswordModal = styled(Component)<Props>(({ theme: { token } }: Props) => {
+  return ({
+    '.ant-sw-modal-body': {
+      paddingBottom: 0
+    },
+
+    '.ant-sw-modal-footer': {
+      borderTop: 0,
+      display: 'flex',
+      gap: token.sizeXXS
+    },
+
+    '.ant-form-item': {
+      marginBottom: 0
+    },
+
+    '.__brief': {
+      textAlign: 'center',
+      fontSize: token.fontSize,
+      color: token.colorTextLight4,
+      lineHeight: token.lineHeight,
+      marginBottom: token.margin
+    },
+
+    '.__password-input': {
+      '.ant-input-prefix': {
+        display: 'none'
+      }
+    }
+  });
+});
diff --git a/packages/extension-koni-ui/src/Popup/MigrateAccount/SoloAccountMigrationView/ProcessViewItem.tsx b/packages/extension-koni-ui/src/Popup/MigrateAccount/SoloAccountMigrationView/ProcessViewItem.tsx
new file mode 100644
index 00000000000..e552dce756a
--- /dev/null
+++ b/packages/extension-koni-ui/src/Popup/MigrateAccount/SoloAccountMigrationView/ProcessViewItem.tsx
@@ -0,0 +1,280 @@
+// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import { SoloAccountToBeMigrated } from '@subwallet/extension-base/background/KoniTypes';
+import { AccountChainType, AccountProxyType, SUPPORTED_ACCOUNT_CHAIN_TYPES } from '@subwallet/extension-base/types';
+import { AccountChainTypeLogos, AccountProxyTypeTag } from '@subwallet/extension-koni-ui/components';
+import { useTranslation } from '@subwallet/extension-koni-ui/hooks';
+import { validateAccountName } from '@subwallet/extension-koni-ui/messaging';
+import { SoloAccountToBeMigratedItem } from '@subwallet/extension-koni-ui/Popup/MigrateAccount/SoloAccountMigrationView/SoloAccountToBeMigratedItem';
+import { ThemeProps } from '@subwallet/extension-koni-ui/types';
+import { noop, simpleCheckForm } from '@subwallet/extension-koni-ui/utils';
+import { Button, Form, Icon, Input } from '@subwallet/react-ui';
+import CN from 'classnames';
+import { CheckCircle, XCircle } from 'phosphor-react';
+import { Callbacks, FieldData, RuleObject } from 'rc-field-form/lib/interface';
+import React, { useCallback, useMemo, useState } from 'react';
+import styled from 'styled-components';
+
+type Props = ThemeProps & {
+  currentProcessOrdinal: number;
+  totalProcessSteps: number;
+  currentSoloAccountToBeMigratedGroup: SoloAccountToBeMigrated[];
+  onSkip: VoidFunction;
+  onApprove: (soloAccounts: SoloAccountToBeMigrated[], accountName: string) => Promise<void>;
+};
+
+interface FormProps {
+  name: string;
+}
+
+function Component ({ className = '', currentProcessOrdinal, currentSoloAccountToBeMigratedGroup, onApprove, onSkip, totalProcessSteps }: Props) {
+  const { t } = useTranslation();
+  const [loading, setLoading] = useState(false);
+  const [form] = Form.useForm<FormProps>();
+  const defaultValues = useMemo(() => ({
+    name: ''
+  }), []);
+  const [isFormValid, setIsFormValid] = useState<boolean>(false);
+
+  const headerContent = useMemo(() => {
+    return `${t('Accounts migrated')}: ${currentProcessOrdinal}/${totalProcessSteps}`;
+  }, [currentProcessOrdinal, t, totalProcessSteps]);
+
+  const _onApprove = useCallback(() => {
+    const doApprove = () => {
+      setLoading(true);
+
+      const { name } = form.getFieldsValue();
+
+      onApprove(currentSoloAccountToBeMigratedGroup, name.trim())
+        .catch(console.error)
+        .finally(() => {
+          setLoading(false);
+        });
+    };
+
+    form.validateFields(['name']).then(() => {
+      doApprove();
+    }).catch(noop);
+  }, [currentSoloAccountToBeMigratedGroup, form, onApprove]);
+
+  const accountNameValidator = useCallback(async (validate: RuleObject, value: string) => {
+    if (value) {
+      try {
+        const { isValid } = await validateAccountName({ name: value });
+
+        if (!isValid) {
+          return Promise.reject(t('Account name already in use'));
+        }
+      } catch (e) {
+        return Promise.reject(t('Account name invalid'));
+      }
+    }
+
+    return Promise.resolve();
+  }, [t]);
+
+  const onFieldsChange: Callbacks<FormProps>['onFieldsChange'] = useCallback((changes: FieldData[], allFields: FieldData[]) => {
+    const { empty, error } = simpleCheckForm(allFields);
+
+    setIsFormValid(!(error || empty));
+  }, []);
+
+  return (
+    <div className={className}>
+      <div className='__header-area'>
+        {headerContent}
+      </div>
+
+      <div className='__body-area'>
+        <div className='__brief'>
+          {t('Enter a name for this unified account to complete the migration')}
+        </div>
+
+        <div className='__section-label'>
+          {t('Migrate from')}
+        </div>
+
+        <div className='__account-list'>
+          {
+            currentSoloAccountToBeMigratedGroup.map((account) => (
+              <SoloAccountToBeMigratedItem
+                className={'__account-item'}
+                key={account.address}
+                {...account}
+              />
+            ))
+          }
+        </div>
+
+        <div className='__section-label'>
+          {t('To')}
+        </div>
+
+        <Form
+          form={form}
+          initialValues={defaultValues}
+          name='__form-container'
+          onFieldsChange={onFieldsChange}
+        >
+          <div className='__account-name-field-wrapper'>
+            <div className='__account-type-tag-wrapper'>
+              <AccountProxyTypeTag
+                className={'__account-type-tag'}
+                type={AccountProxyType.UNIFIED}
+              />
+            </div>
+
+            <Form.Item
+              className={CN('__account-name-field')}
+              name={'name'}
+              rules={[
+                {
+                  message: t('Account name is required'),
+                  transform: (value: string) => value.trim(),
+                  required: true
+                },
+                {
+                  validator: accountNameValidator
+                }
+              ]}
+              statusHelpAsTooltip={true}
+            >
+              <Input
+                className='__account-name-input'
+                disabled={loading}
+                label={t('Account name')}
+                placeholder={t('Enter the account name')}
+                suffix={(
+                  <AccountChainTypeLogos
+                    chainTypes={SUPPORTED_ACCOUNT_CHAIN_TYPES as AccountChainType[]}
+                    className={'__chain-type-logos'}
+                  />
+                )}
+              />
+            </Form.Item>
+          </div>
+        </Form>
+      </div>
+
+      <div className='__footer-area'>
+        <Button
+          block={true}
+          disabled={loading}
+          icon={(
+            <Icon
+              phosphorIcon={XCircle}
+              weight='fill'
+            />
+          )}
+          onClick={onSkip}
+          schema={'secondary'}
+        >
+          {t('Skip')}
+        </Button>
+        <Button
+          block={true}
+          disabled={!isFormValid || loading}
+          icon={(
+            <Icon
+              phosphorIcon={CheckCircle}
+              weight='fill'
+            />
+          )}
+          loading={loading}
+          onClick={_onApprove}
+        >
+          {t('Approve')}
+        </Button>
+      </div>
+    </div>
+  );
+}
+
+export const ProcessViewItem = styled(Component)<Props>(({ theme: { extendToken, token } }: Props) => {
+  return ({
+    display: 'flex',
+    flexDirection: 'column',
+    height: '100%',
+
+    '.__header-area': {
+      paddingLeft: token.padding,
+      paddingRight: token.padding,
+      paddingTop: 14,
+      paddingBottom: 14,
+      fontSize: token.fontSizeHeading4,
+      lineHeight: token.lineHeightHeading4,
+      textAlign: 'center',
+      color: token.colorTextLight1
+    },
+
+    '.__body-area': {
+      flex: 1,
+      overflow: 'auto',
+      padding: token.padding,
+      paddingBottom: 0
+    },
+
+    '.__footer-area': {
+      display: 'flex',
+      gap: token.sizeSM,
+      paddingLeft: token.padding,
+      paddingRight: token.padding,
+      paddingTop: token.padding,
+      paddingBottom: 32
+    },
+
+    '.__brief': {
+      textAlign: 'center',
+      fontSize: token.fontSize,
+      color: token.colorTextLight4,
+      lineHeight: token.lineHeight,
+      marginBottom: token.margin
+    },
+
+    '.__section-label': {
+      fontSize: token.fontSize,
+      color: token.colorTextLight4,
+      lineHeight: token.lineHeight,
+      marginBottom: token.marginXS,
+      fontWeight: token.headingFontWeight
+    },
+
+    '.__account-list': {
+      marginBottom: token.margin
+    },
+
+    '.__account-item + .__account-item': {
+      marginTop: token.marginXS
+    },
+
+    '.__account-name-field-wrapper': {
+      position: 'relative'
+    },
+
+    '.__account-name-field': {
+      marginBottom: 0
+    },
+
+    '.__account-type-tag-wrapper': {
+      position: 'absolute',
+      zIndex: 1,
+      right: token.sizeSM,
+      top: token.sizeXS,
+      display: 'flex'
+    },
+
+    '.__account-type-tag': {
+      marginRight: 0
+    },
+
+    '.__chain-type-logos': {
+      paddingRight: 10
+    },
+
+    '.__account-name-input .ant-input-suffix': {
+      paddingLeft: token.paddingXS
+    }
+  });
+});
diff --git a/packages/extension-koni-ui/src/Popup/MigrateAccount/SoloAccountMigrationView/SoloAccountToBeMigratedItem.tsx b/packages/extension-koni-ui/src/Popup/MigrateAccount/SoloAccountMigrationView/SoloAccountToBeMigratedItem.tsx
new file mode 100644
index 00000000000..bf04bbd6fc5
--- /dev/null
+++ b/packages/extension-koni-ui/src/Popup/MigrateAccount/SoloAccountMigrationView/SoloAccountToBeMigratedItem.tsx
@@ -0,0 +1,109 @@
+// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import { SoloAccountToBeMigrated } from '@subwallet/extension-base/background/KoniTypes';
+import { AccountProxyAvatar } from '@subwallet/extension-koni-ui/components';
+import { Theme } from '@subwallet/extension-koni-ui/themes';
+import { ThemeProps } from '@subwallet/extension-koni-ui/types';
+import { getChainTypeLogoMap, toShort } from '@subwallet/extension-koni-ui/utils';
+import React, { Context, useContext, useMemo } from 'react';
+import styled, { ThemeContext } from 'styled-components';
+
+type Props = ThemeProps & SoloAccountToBeMigrated;
+
+function Component ({ address,
+  chainType,
+  className,
+  name,
+  proxyId }: Props) {
+  const logoMap = useContext<Theme>(ThemeContext as Context<Theme>).logoMap;
+
+  const chainTypeLogoMap = useMemo(() => {
+    return getChainTypeLogoMap(logoMap);
+  }, [logoMap]);
+
+  return (
+    <div className={className}>
+      <div className='__item-left-part'>
+
+        <div className='__item-account-avatar-wrapper'>
+          <AccountProxyAvatar
+            className={'__item-account-avatar'}
+            size={28}
+            value={proxyId}
+          />
+
+          <img
+            alt='Network type'
+            className={'__item-chain-type-logo'}
+            src={chainTypeLogoMap[chainType]}
+          />
+        </div>
+      </div>
+
+      <div className='__item-center-part'>
+        <div className='__item-account-name'>
+          {name}
+        </div>
+
+        <div className='__item-account-address'>
+          {toShort(address, 4, 5)}
+        </div>
+      </div>
+    </div>
+  );
+}
+
+export const SoloAccountToBeMigratedItem = styled(Component)<Props>(({ theme: { extendToken, token } }: Props) => {
+  return ({
+    minHeight: 52,
+    background: token.colorBgSecondary,
+    paddingLeft: token.paddingSM,
+    paddingRight: token.paddingSM,
+    paddingTop: token.paddingXS,
+    paddingBottom: token.paddingXS,
+    borderRadius: token.borderRadiusLG,
+    alignItems: 'center',
+    display: 'flex',
+    flexDirection: 'row',
+    transition: `background ${token.motionDurationMid} ease-in-out`,
+    gap: 5,
+    'white-space': 'nowrap',
+
+    '.__item-account-avatar-wrapper': {
+      position: 'relative'
+    },
+
+    '.__item-chain-type-logo': {
+      position: 'absolute',
+      right: 0,
+      bottom: 0,
+      display: 'block',
+      width: token.size,
+      height: token.size
+    },
+
+    '.__item-center-part': {
+      display: 'flex',
+      overflow: 'hidden',
+      alignItems: 'flex-end',
+      gap: 5
+    },
+
+    '.__item-account-name': {
+      fontSize: token.fontSize,
+      color: token.colorTextLight1,
+      lineHeight: token.lineHeight,
+      fontWeight: token.headingFontWeight,
+      textOverflow: 'ellipsis',
+      overflow: 'hidden',
+      flexShrink: 1
+    },
+
+    '.__item-account-address': {
+      fontSize: token.fontSizeSM,
+      color: token.colorTextLight4,
+      lineHeight: 1.5
+    }
+  });
+});
diff --git a/packages/extension-koni-ui/src/Popup/MigrateAccount/SoloAccountMigrationView/index.tsx b/packages/extension-koni-ui/src/Popup/MigrateAccount/SoloAccountMigrationView/index.tsx
new file mode 100644
index 00000000000..a3845c6f23d
--- /dev/null
+++ b/packages/extension-koni-ui/src/Popup/MigrateAccount/SoloAccountMigrationView/index.tsx
@@ -0,0 +1,111 @@
+// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import { RequestMigrateSoloAccount, SoloAccountToBeMigrated } from '@subwallet/extension-base/background/KoniTypes';
+import { SESSION_TIMEOUT } from '@subwallet/extension-base/services/keyring-service/context/handlers/Migration';
+import { pingSession } from '@subwallet/extension-koni-ui/messaging/migrate-unified-account';
+import { ThemeProps } from '@subwallet/extension-koni-ui/types';
+import React, { useCallback, useEffect, useState } from 'react';
+import styled from 'styled-components';
+
+import { ProcessViewItem } from './ProcessViewItem';
+
+type Props = ThemeProps & {
+  soloAccountToBeMigratedGroups: SoloAccountToBeMigrated[][];
+  onApprove: (request: RequestMigrateSoloAccount) => Promise<void>;
+  sessionId?: string;
+  onCompleteMigrationProcess: VoidFunction;
+};
+
+function Component ({ onApprove, onCompleteMigrationProcess, sessionId, soloAccountToBeMigratedGroups }: Props) {
+  const [currentProcessOrdinal, setCurrentProcessOrdinal] = useState<number>(1);
+  const [currentToBeMigratedGroupIndex, setCurrentToBeMigratedGroupIndex] = useState<number>(0);
+  const [totalProcessSteps, setTotalProcessSteps] = useState<number>(soloAccountToBeMigratedGroups.length);
+
+  const performNextProcess = useCallback((increaseProcessOrdinal = true) => {
+    if (currentProcessOrdinal === totalProcessSteps) {
+      onCompleteMigrationProcess();
+
+      return;
+    }
+
+    setCurrentToBeMigratedGroupIndex((prev) => prev + 1);
+
+    if (increaseProcessOrdinal) {
+      setCurrentProcessOrdinal((prev) => prev + 1);
+    }
+  }, [currentProcessOrdinal, onCompleteMigrationProcess, totalProcessSteps]);
+
+  const onSkip = useCallback(() => {
+    setTotalProcessSteps((prev) => {
+      if (prev > 0) {
+        return prev - 1;
+      }
+
+      return prev;
+    });
+
+    performNextProcess(false);
+  }, [performNextProcess]);
+
+  const _onApprove = useCallback(async (soloAccounts: SoloAccountToBeMigrated[], accountName: string) => {
+    if (!sessionId) {
+      return;
+    }
+
+    await onApprove({
+      soloAccounts,
+      sessionId,
+      accountName
+    });
+
+    performNextProcess();
+  }, [onApprove, performNextProcess, sessionId]);
+
+  const currentSoloAccountToBeMigratedGroup = soloAccountToBeMigratedGroups[currentToBeMigratedGroupIndex];
+
+  useEffect(() => {
+    // keep the session alive while in this view
+
+    let timer: NodeJS.Timer;
+
+    if (sessionId) {
+      const doPing = () => {
+        pingSession({ sessionId }).catch(console.error);
+      };
+
+      timer = setInterval(() => {
+        doPing();
+      }, SESSION_TIMEOUT / 2);
+
+      doPing();
+    }
+
+    return () => {
+      clearInterval(timer);
+    };
+  }, [sessionId]);
+
+  return (
+    <>
+      {
+        !!currentSoloAccountToBeMigratedGroup && (
+          <ProcessViewItem
+            currentProcessOrdinal={currentProcessOrdinal}
+            currentSoloAccountToBeMigratedGroup={currentSoloAccountToBeMigratedGroup}
+            key={`ProcessViewItem-${currentToBeMigratedGroupIndex}`}
+            onApprove={_onApprove}
+            onSkip={onSkip}
+            totalProcessSteps={totalProcessSteps}
+          />
+        )
+      }
+    </>
+  );
+}
+
+export const SoloAccountMigrationView = styled(Component)<Props>(({ theme: { extendToken, token } }: Props) => {
+  return ({
+
+  });
+});
diff --git a/packages/extension-koni-ui/src/Popup/MigrateAccount/SummaryView/ResultAccountProxyItem.tsx b/packages/extension-koni-ui/src/Popup/MigrateAccount/SummaryView/ResultAccountProxyItem.tsx
new file mode 100644
index 00000000000..6a0443936e6
--- /dev/null
+++ b/packages/extension-koni-ui/src/Popup/MigrateAccount/SummaryView/ResultAccountProxyItem.tsx
@@ -0,0 +1,83 @@
+// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import { AccountChainType, SUPPORTED_ACCOUNT_CHAIN_TYPES } from '@subwallet/extension-base/types';
+import { AccountChainTypeLogos, AccountProxyAvatar } from '@subwallet/extension-koni-ui/components';
+import { ThemeProps } from '@subwallet/extension-koni-ui/types';
+import React from 'react';
+import styled from 'styled-components';
+
+export type ResultAccountProxyItemType = {
+  accountName: string;
+  accountProxyId: string;
+};
+
+type Props = ThemeProps & ResultAccountProxyItemType;
+
+function Component ({ accountName,
+  accountProxyId,
+  className }: Props) {
+  return (
+    <div className={className}>
+      <div className='__item-account-avatar-wrapper'>
+        <AccountProxyAvatar
+          className={'__item-account-avatar'}
+          size={24}
+          value={accountProxyId}
+        />
+      </div>
+
+      <div className='__item-account-name'>
+        {accountName}
+      </div>
+
+      <AccountChainTypeLogos
+        chainTypes={SUPPORTED_ACCOUNT_CHAIN_TYPES as AccountChainType[]}
+        className={'__item-chain-type-logos'}
+      />
+    </div>
+  );
+}
+
+export const ResultAccountProxyItem = styled(Component)<Props>(({ theme: { extendToken, token } }: Props) => {
+  return ({
+    minHeight: 52,
+    background: token.colorBgSecondary,
+    paddingLeft: token.paddingSM,
+    paddingRight: token.paddingSM,
+    paddingTop: token.paddingXS,
+    paddingBottom: token.paddingXS,
+    borderRadius: token.borderRadiusLG,
+    alignItems: 'center',
+    display: 'flex',
+    flexDirection: 'row',
+    transition: `background ${token.motionDurationMid} ease-in-out`,
+    gap: token.sizeSM,
+    'white-space': 'nowrap',
+
+    '.__item-account-avatar-wrapper': {
+      position: 'relative'
+    },
+
+    '.__item-chain-type-logos': {
+
+    },
+
+    '.__item-account-name': {
+      flex: 1,
+      fontSize: token.fontSize,
+      color: token.colorTextLight1,
+      lineHeight: token.lineHeight,
+      fontWeight: token.headingFontWeight,
+      textOverflow: 'ellipsis',
+      overflow: 'hidden',
+      flexShrink: 1
+    },
+
+    '.__item-account-address': {
+      fontSize: token.fontSizeSM,
+      color: token.colorTextLight4,
+      lineHeight: 1.5
+    }
+  });
+});
diff --git a/packages/extension-koni-ui/src/Popup/MigrateAccount/SummaryView/ResultAccountProxyListModal.tsx b/packages/extension-koni-ui/src/Popup/MigrateAccount/SummaryView/ResultAccountProxyListModal.tsx
new file mode 100644
index 00000000000..4c6816a5f70
--- /dev/null
+++ b/packages/extension-koni-ui/src/Popup/MigrateAccount/SummaryView/ResultAccountProxyListModal.tsx
@@ -0,0 +1,68 @@
+// Copyright 2019-2022 @polkadot/extension-ui authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import { useTranslation } from '@subwallet/extension-koni-ui/hooks';
+import { ResultAccountProxyItem, ResultAccountProxyItemType } from '@subwallet/extension-koni-ui/Popup/MigrateAccount/SummaryView/ResultAccountProxyItem';
+import { ThemeProps, VoidFunction } from '@subwallet/extension-koni-ui/types';
+import { Button, SwModal } from '@subwallet/react-ui';
+import React from 'react';
+import styled from 'styled-components';
+
+type Props = ThemeProps & {
+  onClose: VoidFunction;
+  accountProxies: ResultAccountProxyItemType[];
+}
+
+export const resultAccountProxyListModal = 'resultAccountProxyListModal';
+
+function Component ({ accountProxies, className = '', onClose }: Props): React.ReactElement<Props> {
+  const { t } = useTranslation();
+
+  return (
+    <SwModal
+      className={className}
+      footer={(
+        <>
+          <Button
+            block={true}
+            onClick={onClose}
+          >
+            {t('Close')}
+          </Button>
+        </>
+      )}
+      id={resultAccountProxyListModal}
+      onCancel={onClose}
+      title={t('Migrated account list')}
+      zIndex={9999}
+    >
+      {
+        accountProxies.map((ap) => (
+          <ResultAccountProxyItem
+            className={'__account-item'}
+            key={ap.accountProxyId}
+            {...ap}
+          />
+        ))
+      }
+    </SwModal>
+  );
+}
+
+export const ResultAccountProxyListModal = styled(Component)<Props>(({ theme: { token } }: Props) => {
+  return ({
+    '.ant-sw-modal-body': {
+      paddingBottom: 0
+    },
+
+    '.ant-sw-modal-footer': {
+      borderTop: 0,
+      display: 'flex',
+      gap: token.sizeXXS
+    },
+
+    '.__account-item + .__account-item': {
+      marginTop: token.marginXS
+    }
+  });
+});
diff --git a/packages/extension-koni-ui/src/Popup/MigrateAccount/SummaryView/index.tsx b/packages/extension-koni-ui/src/Popup/MigrateAccount/SummaryView/index.tsx
new file mode 100644
index 00000000000..35385e8f7f2
--- /dev/null
+++ b/packages/extension-koni-ui/src/Popup/MigrateAccount/SummaryView/index.tsx
@@ -0,0 +1,313 @@
+// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import { detectTranslate } from '@subwallet/extension-base/utils';
+import { useTranslation } from '@subwallet/extension-koni-ui/hooks';
+import { pingUnifiedAccountMigrationDone } from '@subwallet/extension-koni-ui/messaging';
+import { ResultAccountProxyItem, ResultAccountProxyItemType } from '@subwallet/extension-koni-ui/Popup/MigrateAccount/SummaryView/ResultAccountProxyItem';
+import { ResultAccountProxyListModal, resultAccountProxyListModal } from '@subwallet/extension-koni-ui/Popup/MigrateAccount/SummaryView/ResultAccountProxyListModal';
+import { RootState } from '@subwallet/extension-koni-ui/stores';
+import { ThemeProps } from '@subwallet/extension-koni-ui/types';
+import { Button, Icon, ModalContext, PageIcon } from '@subwallet/react-ui';
+import CN from 'classnames';
+import { CheckCircle } from 'phosphor-react';
+import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
+import { Trans } from 'react-i18next';
+import { useSelector } from 'react-redux';
+import styled from 'styled-components';
+
+type Props = ThemeProps & {
+  resultProxyIds: string[];
+  onClickFinish: VoidFunction;
+};
+
+function Component ({ className = '', onClickFinish, resultProxyIds }: Props) {
+  const { t } = useTranslation();
+  const { activeModal, inactiveModal } = useContext(ModalContext);
+  const [isAccountListModalOpen, setIsAccountListModalOpen] = useState<boolean>(false);
+  const accountProxies = useSelector((root: RootState) => root.accountState.accountProxies);
+
+  const accountProxyNameMapById = useMemo(() => {
+    const result: Record<string, string> = {};
+
+    accountProxies.forEach((ap) => {
+      result[ap.id] = ap.name;
+    });
+
+    return result;
+  }, [accountProxies]);
+
+  const resultAccountProxies = useMemo<ResultAccountProxyItemType[]>(() => {
+    return resultProxyIds.map((id) => ({
+      accountName: accountProxyNameMapById[id] || '',
+      accountProxyId: id
+    }));
+  }, [accountProxyNameMapById, resultProxyIds]);
+
+  const onOpenAccountListModal = useCallback(() => {
+    setIsAccountListModalOpen(true);
+    activeModal(resultAccountProxyListModal);
+  }, [activeModal]);
+
+  const onCloseAccountListModal = useCallback(() => {
+    inactiveModal(resultAccountProxyListModal);
+    setIsAccountListModalOpen(false);
+  }, [inactiveModal]);
+
+  const showAccountListModalTrigger = resultAccountProxies.length > 2;
+
+  const getAccountListModalTriggerLabel = () => {
+    if (resultAccountProxies.length === 3) {
+      return t('And 1 other');
+    }
+
+    return t('And {{number}} others', { replace: { number: resultAccountProxies.length - 2 } });
+  };
+
+  const hasAnyAccountToMigrate = !!resultAccountProxies.length;
+
+  useEffect(() => {
+    // notice to background that account migration is done
+    pingUnifiedAccountMigrationDone().catch(console.error);
+  }, []);
+
+  return (
+    <>
+      <div className={CN(className, {
+        '-no-account': !hasAnyAccountToMigrate
+      })}
+      >
+        <div className='__header-area'>
+          {t('Finish')}
+        </div>
+
+        <div className='__body-area'>
+          <div className='__page-icon'>
+            <PageIcon
+              color='var(--page-icon-color)'
+              iconProps={{
+                weight: 'fill',
+                phosphorIcon: CheckCircle
+              }}
+            />
+          </div>
+
+          <div className='__content-title'>
+            {t('All done!')}
+          </div>
+
+          {
+            !hasAnyAccountToMigrate && (
+              <div className='__brief'>
+                <Trans
+                  components={{
+                    guide: (
+                      <a
+                        className='__link'
+                        href={'https://docs.subwallet.app/main/extension-user-guide/account-management/migrate-solo-accounts-to-unified-accounts'}
+                        target='__blank'
+                      />
+                    )
+                  }}
+                  i18nKey={detectTranslate('All eligible accounts have been migrated. Review <guide>our guide</guide> to learn more about migration eligibility & process')}
+                />
+              </div>
+            )
+          }
+
+          {
+            hasAnyAccountToMigrate && (
+              <>
+                <div className='__brief'>
+                  {
+                    resultAccountProxies.length > 1
+                      ? (
+                        <Trans
+                          components={{
+                            br: (<br />),
+                            highlight: (
+                              <span
+                                className='__highlight'
+                              />
+                            )
+                          }}
+                          i18nKey={detectTranslate('You have successfully migrated to <br/> <highlight>{{number}} unified accounts</highlight>')}
+                          values={{ number: `${resultAccountProxies.length}`.padStart(2, '0') }}
+                        />
+                      )
+                      : (
+                        <Trans
+                          components={{
+                            br: (<br />),
+                            highlight: (
+                              <span
+                                className='__highlight'
+                              />
+                            )
+                          }}
+                          i18nKey={detectTranslate('You have successfully migrated to <br/> <highlight>{{number}} unified account</highlight>')}
+                          values={{ number: `${resultAccountProxies.length}`.padStart(2, '0') }}
+                        />
+                      )
+                  }
+                </div>
+
+                <div className='__account-list-container'>
+                  {
+                    resultAccountProxies.slice(0, 2).map((ap) => (
+                      <ResultAccountProxyItem
+                        className={'__account-item'}
+                        key={ap.accountProxyId}
+                        {...ap}
+                      />
+                    ))
+                  }
+                </div>
+
+                {
+                  showAccountListModalTrigger && (
+                    <div className='__account-list-modal-trigger-wrapper'>
+                      <button
+                        className={'__account-list-modal-trigger'}
+                        onClick={onOpenAccountListModal}
+                      >
+                        {getAccountListModalTriggerLabel()}
+                      </button>
+                    </div>
+                  )
+                }
+              </>
+            )
+          }
+        </div>
+
+        <div className='__footer-area'>
+          <Button
+            block={true}
+            icon={
+              hasAnyAccountToMigrate
+                ? (
+                  <Icon
+                    phosphorIcon={CheckCircle}
+                    weight='fill'
+                  />
+                )
+                : undefined
+            }
+            onClick={onClickFinish}
+          >
+            {hasAnyAccountToMigrate ? t('Finish') : t('Back to home')}
+          </Button>
+        </div>
+      </div>
+
+      {
+        isAccountListModalOpen && showAccountListModalTrigger && (
+          <ResultAccountProxyListModal
+            accountProxies={resultAccountProxies}
+            onClose={onCloseAccountListModal}
+          />
+        )
+      }
+    </>
+  );
+}
+
+export const SummaryView = styled(Component)<Props>(({ theme: { extendToken, token } }: Props) => {
+  return ({
+    display: 'flex',
+    flexDirection: 'column',
+    height: '100%',
+
+    '.__header-area': {
+      paddingLeft: token.padding,
+      paddingRight: token.padding,
+      paddingTop: 14,
+      paddingBottom: 14,
+      fontSize: token.fontSizeHeading4,
+      lineHeight: token.lineHeightHeading4,
+      textAlign: 'center',
+      color: token.colorTextLight1
+    },
+
+    '.__body-area': {
+      flex: 1,
+      overflow: 'auto',
+      padding: token.padding,
+      paddingBottom: 0
+    },
+
+    '.__footer-area': {
+      display: 'flex',
+      gap: token.sizeSM,
+      paddingLeft: token.padding,
+      paddingRight: token.padding,
+      paddingTop: token.padding,
+      paddingBottom: 32
+    },
+
+    '.__page-icon': {
+      display: 'flex',
+      justifyContent: 'center',
+      marginBottom: token.margin,
+      '--page-icon-color': token.colorSecondary
+    },
+
+    '.__content-title': {
+      color: token.colorTextLight2,
+      fontSize: token.fontSizeHeading3,
+      lineHeight: token.lineHeightHeading3,
+      textAlign: 'center',
+      marginBottom: token.margin
+    },
+
+    '.__brief': {
+      color: token.colorTextLight3,
+      fontSize: token.fontSizeHeading5,
+      lineHeight: token.lineHeightHeading5,
+      textAlign: 'center',
+
+      '.__link': {
+        color: token.colorPrimary
+      },
+
+      '.__highlight': {
+        color: token.colorTextLight1
+      }
+    },
+
+    '.__brief + .__account-list-container': {
+      marginTop: 32
+    },
+
+    '.__account-item + .__account-item': {
+      marginTop: token.marginXS
+    },
+
+    '.__account-list-modal-trigger-wrapper': {
+      marginTop: token.marginXS,
+      display: 'flex',
+      justifyContent: 'center'
+    },
+
+    '.__account-list-modal-trigger': {
+      padding: 0,
+      cursor: 'pointer',
+      backgroundColor: 'transparent',
+      paddingLeft: token.padding,
+      paddingRight: token.padding,
+      border: 0,
+      fontSize: token.fontSize,
+      lineHeight: token.lineHeight,
+      color: token.colorTextLight4
+    },
+
+    '&.-no-account': {
+      '.__body-area': {
+        paddingTop: 40,
+        paddingRight: 32,
+        paddingLeft: 32
+      }
+    }
+  });
+});
diff --git a/packages/extension-koni-ui/src/Popup/MigrateAccount/index.tsx b/packages/extension-koni-ui/src/Popup/MigrateAccount/index.tsx
new file mode 100644
index 00000000000..258c763e138
--- /dev/null
+++ b/packages/extension-koni-ui/src/Popup/MigrateAccount/index.tsx
@@ -0,0 +1,174 @@
+// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import { RequestMigrateSoloAccount, SoloAccountToBeMigrated } from '@subwallet/extension-base/background/KoniTypes';
+import { hasAnyAccountForMigration } from '@subwallet/extension-base/services/keyring-service/utils';
+import { useDefaultNavigate, useIsPopup } from '@subwallet/extension-koni-ui/hooks';
+import { saveMigrationAcknowledgedStatus } from '@subwallet/extension-koni-ui/messaging';
+import { migrateSoloAccount, migrateUnifiedAndFetchEligibleSoloAccounts } from '@subwallet/extension-koni-ui/messaging/migrate-unified-account';
+import { BriefView } from '@subwallet/extension-koni-ui/Popup/MigrateAccount/BriefView';
+import { RootState } from '@subwallet/extension-koni-ui/stores';
+import { ThemeProps } from '@subwallet/extension-koni-ui/types';
+import { ModalContext } from '@subwallet/react-ui';
+import React, { useCallback, useContext, useEffect, useState } from 'react';
+import { useSelector } from 'react-redux';
+import { useNavigate, useSearchParams } from 'react-router-dom';
+import styled from 'styled-components';
+
+import { EnterPasswordModal, enterPasswordModalId } from './EnterPasswordModal';
+import { SoloAccountMigrationView } from './SoloAccountMigrationView';
+import { SummaryView } from './SummaryView';
+
+type Props = ThemeProps;
+
+export enum ScreenView {
+  BRIEF= 'brief',
+  SOLO_ACCOUNT_MIGRATION= 'solo-account-migration',
+  SUMMARY='summary'
+}
+
+function Component ({ className = '' }: Props) {
+  const [searchParams] = useSearchParams();
+  const isMigrationNotion = searchParams.has('is-notion');
+  const isForcedMigration = searchParams.has('is-forced-migration');
+  const [currentScreenView, setCurrentScreenView] = useState<ScreenView>(ScreenView.BRIEF);
+  const [isPasswordModalOpen, setIsPasswordModalOpen] = useState<boolean>(false);
+  const { activeModal, inactiveModal } = useContext(ModalContext);
+  const { goHome } = useDefaultNavigate();
+  const navigate = useNavigate();
+  const [sessionId, setSessionId] = useState<string | undefined>();
+  const [resultProxyIds, setResultProxyIds] = useState<string[]>([]);
+  const [soloAccountToBeMigratedGroups, setSoloAccountToBeMigratedGroups] = useState<SoloAccountToBeMigrated[][]>([]);
+  const isAcknowledgedUnifiedAccountMigration = useSelector((state: RootState) => state.settings.isAcknowledgedUnifiedAccountMigration);
+  const isPopup = useIsPopup();
+
+  const accountProxies = useSelector((root: RootState) => root.accountState.accountProxies);
+
+  const onClosePasswordModal = useCallback(() => {
+    inactiveModal(enterPasswordModalId);
+    setIsPasswordModalOpen(false);
+  }, [inactiveModal]);
+
+  const onOpenPasswordModal = useCallback(() => {
+    setIsPasswordModalOpen(true);
+    activeModal(enterPasswordModalId);
+  }, [activeModal]);
+
+  const onInteractAction = useCallback(() => {
+    if (isMigrationNotion && !isAcknowledgedUnifiedAccountMigration) {
+      // flag that user acknowledge the migration
+      saveMigrationAcknowledgedStatus({ isAcknowledgedUnifiedAccountMigration: true }).catch(console.error);
+    }
+
+    // for now, do nothing
+  }, [isAcknowledgedUnifiedAccountMigration, isMigrationNotion]);
+
+  const onClickDismiss = useCallback(() => {
+    onInteractAction();
+
+    // close this screen
+    isMigrationNotion ? goHome() : navigate('/settings/account-settings');
+  }, [goHome, isMigrationNotion, navigate, onInteractAction]);
+
+  const onClickMigrateNow = useCallback(() => {
+    onInteractAction();
+
+    if (!hasAnyAccountForMigration(accountProxies)) {
+      setCurrentScreenView(ScreenView.SUMMARY);
+    } else {
+      onOpenPasswordModal();
+    }
+  }, [accountProxies, onInteractAction, onOpenPasswordModal]);
+
+  const onSubmitPassword = useCallback(async (password: string) => {
+    // migrate all account
+    // open migrate solo chain accounts
+
+    const { sessionId, soloAccounts } = await migrateUnifiedAndFetchEligibleSoloAccounts({ password });
+
+    const soloAccountGroups = Object.values(soloAccounts);
+
+    if (soloAccountGroups.length) {
+      setSessionId(sessionId);
+      setSoloAccountToBeMigratedGroups(soloAccountGroups);
+
+      setCurrentScreenView(ScreenView.SOLO_ACCOUNT_MIGRATION);
+    } else {
+      setCurrentScreenView(ScreenView.SUMMARY);
+    }
+
+    onClosePasswordModal();
+  }, [onClosePasswordModal]);
+
+  const onApproveSoloAccountMigration = useCallback(async (request: RequestMigrateSoloAccount) => {
+    try {
+      const { migratedUnifiedAccountId } = await migrateSoloAccount(request);
+
+      setResultProxyIds((prev) => {
+        return [...prev, migratedUnifiedAccountId];
+      });
+    } catch (e) {
+      console.log('onApproveSoloAccountMigration error:', e);
+    }
+  }, []);
+
+  const onCompleteSoloAccountsMigrationProcess = useCallback(() => {
+    setCurrentScreenView(ScreenView.SUMMARY);
+    setSessionId(undefined);
+  }, []);
+
+  const onClickFinish = useCallback(() => {
+    goHome();
+  }, [goHome]);
+
+  useEffect(() => {
+    if (!isPopup) {
+      goHome();
+    }
+  }, [goHome, isPopup]);
+
+  return (
+    <>
+      {currentScreenView === ScreenView.BRIEF && (
+        <BriefView
+          isForcedMigration={isForcedMigration}
+          onDismiss={onClickDismiss}
+          onMigrateNow={onClickMigrateNow}
+        />
+      )}
+
+      {currentScreenView === ScreenView.SOLO_ACCOUNT_MIGRATION && (
+        <SoloAccountMigrationView
+          onApprove={onApproveSoloAccountMigration}
+          onCompleteMigrationProcess={onCompleteSoloAccountsMigrationProcess}
+          sessionId={sessionId}
+          soloAccountToBeMigratedGroups={soloAccountToBeMigratedGroups}
+        />
+      )}
+
+      {currentScreenView === ScreenView.SUMMARY && (
+        <SummaryView
+          onClickFinish={onClickFinish}
+          resultProxyIds={resultProxyIds}
+        />
+      )}
+
+      {
+        isPasswordModalOpen && (
+          <EnterPasswordModal
+            onClose={onClosePasswordModal}
+            onSubmit={onSubmitPassword}
+          />
+        )
+      }
+    </>
+  );
+}
+
+const MigrateAccount = styled(Component)<Props>(({ theme: { extendToken, token } }: Props) => {
+  return ({
+
+  });
+});
+
+export default MigrateAccount;
diff --git a/packages/extension-koni-ui/src/Popup/Root.tsx b/packages/extension-koni-ui/src/Popup/Root.tsx
index 27df10ddb25..2e02fa6c5ac 100644
--- a/packages/extension-koni-ui/src/Popup/Root.tsx
+++ b/packages/extension-koni-ui/src/Popup/Root.tsx
@@ -10,7 +10,7 @@ import { CURRENT_PAGE, TRANSACTION_STORAGES } from '@subwallet/extension-koni-ui
 import { DEFAULT_ROUTER_PATH } from '@subwallet/extension-koni-ui/constants/router';
 import { DataContext } from '@subwallet/extension-koni-ui/contexts/DataContext';
 import { usePredefinedModal, WalletModalContextProvider } from '@subwallet/extension-koni-ui/contexts/WalletModalContextProvider';
-import { useGetCurrentPage, useSubscribeLanguage } from '@subwallet/extension-koni-ui/hooks';
+import { useGetCurrentPage, useIsPopup, 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';
 import { subscribeNotifications } from '@subwallet/extension-koni-ui/messaging';
@@ -34,6 +34,8 @@ export const RouteState = {
 
 const welcomeUrl = '/welcome';
 const tokenUrl = '/home/tokens';
+const migrateAccountNotionUrl = '/migrate-account?is-notion=true';
+const forcedAccountMigrationUrl = '/migrate-account?is-forced-migration=true';
 const loginUrl = '/keyring/login';
 const phishingUrl = '/phishing-page-detected';
 const mv3MigrationUrl = '/mv3-migration';
@@ -90,7 +92,7 @@ function DefaultRoute ({ children }: { children: React.ReactNode }): React.React
   const [dataLoaded, setDataLoaded] = useState(false);
   const initDataRef = useRef<Promise<boolean>>(dataContext.awaitStores(['accountState', 'chainStore', 'assetRegistry', 'requestState', 'settings', 'mantaPay']));
   const currentPage = useGetCurrentPage();
-  const [, setStorage] = useLocalStorage<string>(CURRENT_PAGE, DEFAULT_ROUTER_PATH);
+  const [, setCurrentPage] = useLocalStorage<string>(CURRENT_PAGE, DEFAULT_ROUTER_PATH);
   const firstRender = useRef(true);
 
   useSubscribeLanguage();
@@ -98,14 +100,17 @@ function DefaultRoute ({ children }: { children: React.ReactNode }): React.React
   const { unlockType } = useSelector((state: RootState) => state.settings);
   const { hasConfirmations, hasInternalConfirmations } = useSelector((state: RootState) => state.requestState);
   const { accounts, currentAccount, hasMasterPassword, isLocked } = useSelector((state: RootState) => state.accountState);
+  const isAcknowledgedUnifiedAccountMigration = useSelector((state: RootState) => state.settings.isAcknowledgedUnifiedAccountMigration);
+  const isUnifiedAccountMigrationInProgress = useSelector((state: RootState) => state.settings.isUnifiedAccountMigrationInProgress);
   const [initAccount, setInitAccount] = useState(currentAccount);
   const noAccount = useMemo(() => isNoAccount(accounts), [accounts]);
   const { isUILocked } = useUILock();
   const needUnlock = isUILocked || (isLocked && unlockType === WalletUnlockType.ALWAYS_REQUIRED);
   const [shouldRedirect, setShouldRedirect] = useState(false);
   const navigate = useNavigate();
+  const isPopup = useIsPopup();
 
-  const needMigrate = useMemo(
+  const needMasterPasswordMigration = useMemo(
     () => !!accounts
       .filter((acc) => acc.address !== ALL_ACCOUNT_KEY && !acc.isExternal && !acc.isInjected && !acc.pendingMigrate)
       .filter((acc) => !acc.isMasterPassword)
@@ -113,49 +118,17 @@ function DefaultRoute ({ children }: { children: React.ReactNode }): React.React
     , [accounts]
   );
 
-  useEffect(() => {
-    initDataRef.current.then(() => {
-      setDataLoaded(true);
-    }).catch(console.error);
-  }, []);
-
-  useEffect(() => {
-    let cancel = false;
-    let lastNotifyTime = new Date().getTime();
-
-    subscribeNotifications((rs) => {
-      rs.sort((a, b) => a.id - b.id)
-        .forEach(({ action, id, message, title, type }) => {
-          if (!cancel && id > lastNotifyTime) {
-            const notificationItem: NotificationProps = { message: title || message, type };
-
-            if (action?.url) {
-              notificationItem.onClick = () => {
-                window.open(action.url);
-              };
-            }
-
-            notify(notificationItem);
-            lastNotifyTime = id;
-          }
-        });
-    }).catch(console.error);
-
-    return () => {
-      cancel = true;
-    };
-  }, [notify]);
+  const activePriorityPath = useMemo(() => {
+    if (isPopup && !isAcknowledgedUnifiedAccountMigration) {
+      return migrateAccountNotionUrl;
+    }
 
-  // Update goBack number
-  useEffect(() => {
-    if (location.pathname === RouteState.lastPathName) {
-      RouteState.prevDifferentPathNum -= 1;
-    } else {
-      RouteState.prevDifferentPathNum = -1;
+    if (isPopup && isUnifiedAccountMigrationInProgress) {
+      return forcedAccountMigrationUrl;
     }
 
-    RouteState.lastPathName = location.pathname;
-  }, [location]);
+    return undefined;
+  }, [isAcknowledgedUnifiedAccountMigration, isPopup, isUnifiedAccountMigrationInProgress]);
 
   const redirectPath = useMemo<string | null>(() => {
     const pathName = location.pathname;
@@ -170,7 +143,7 @@ function DefaultRoute ({ children }: { children: React.ReactNode }): React.React
 
     if (!requireLogin) {
       // Do nothing
-    } else if (needMigrate && hasMasterPassword && !needUnlock) {
+    } else if (needMasterPasswordMigration && hasMasterPassword && !needUnlock) {
       redirectTarget = migratePasswordUrl;
     } else if (hasMasterPassword && needUnlock) {
       redirectTarget = loginUrl;
@@ -191,6 +164,8 @@ function DefaultRoute ({ children }: { children: React.ReactNode }): React.React
     } else if (pathName === DEFAULT_ROUTER_PATH) {
       if (hasConfirmations) {
         openPModal('confirmations');
+      } else if (activePriorityPath) {
+        redirectTarget = activePriorityPath;
       } else if (firstRender.current && currentPage) {
         redirectTarget = currentPage;
       } else {
@@ -200,7 +175,7 @@ function DefaultRoute ({ children }: { children: React.ReactNode }): React.React
       redirectTarget = DEFAULT_ROUTER_PATH;
     } else if (pathName === welcomeUrl && !noAccount) {
       redirectTarget = DEFAULT_ROUTER_PATH;
-    } else if (pathName === migratePasswordUrl && !needMigrate) {
+    } else if (pathName === migratePasswordUrl && !needMasterPasswordMigration) {
       if (noAccount) {
         redirectTarget = welcomeUrl;
       } else {
@@ -231,7 +206,51 @@ function DefaultRoute ({ children }: { children: React.ReactNode }): React.React
     } else {
       return null;
     }
-  }, [location.pathname, dataLoaded, needMigrate, hasMasterPassword, needUnlock, noAccount, hasInternalConfirmations, isOpenPModal, hasConfirmations, currentPage, openPModal]);
+  }, [location.pathname, dataLoaded, needMasterPasswordMigration, hasMasterPassword, needUnlock, noAccount, hasInternalConfirmations, isOpenPModal, hasConfirmations, activePriorityPath, currentPage, openPModal]);
+
+  useEffect(() => {
+    initDataRef.current.then(() => {
+      setDataLoaded(true);
+    }).catch(console.error);
+  }, []);
+
+  useEffect(() => {
+    let cancel = false;
+    let lastNotifyTime = new Date().getTime();
+
+    subscribeNotifications((rs) => {
+      rs.sort((a, b) => a.id - b.id)
+        .forEach(({ action, id, message, title, type }) => {
+          if (!cancel && id > lastNotifyTime) {
+            const notificationItem: NotificationProps = { message: title || message, type };
+
+            if (action?.url) {
+              notificationItem.onClick = () => {
+                window.open(action.url);
+              };
+            }
+
+            notify(notificationItem);
+            lastNotifyTime = id;
+          }
+        });
+    }).catch(console.error);
+
+    return () => {
+      cancel = true;
+    };
+  }, [notify]);
+
+  // Update goBack number
+  useEffect(() => {
+    if (location.pathname === RouteState.lastPathName) {
+      RouteState.prevDifferentPathNum -= 1;
+    } else {
+      RouteState.prevDifferentPathNum = -1;
+    }
+
+    RouteState.lastPathName = location.pathname;
+  }, [location]);
 
   // Remove transaction persist state
   useEffect(() => {
@@ -253,14 +272,14 @@ function DefaultRoute ({ children }: { children: React.ReactNode }): React.React
   useEffect(() => {
     if (rootLoading || redirectPath) {
       if (redirectPath && currentPage !== redirectPath && allowBlackScreenWS.includes(redirectPath)) {
-        setStorage(redirectPath);
+        setCurrentPage(redirectPath);
       }
 
       setShouldRedirect(true);
     } else {
       setShouldRedirect(false);
     }
-  }, [rootLoading, redirectPath, currentPage, setStorage]);
+  }, [rootLoading, redirectPath, currentPage, setCurrentPage]);
 
   useEffect(() => {
     if (shouldRedirect && redirectPath) {
diff --git a/packages/extension-koni-ui/src/Popup/Settings/AccountSettings.tsx b/packages/extension-koni-ui/src/Popup/Settings/AccountSettings.tsx
new file mode 100644
index 00000000000..30874d39d33
--- /dev/null
+++ b/packages/extension-koni-ui/src/Popup/Settings/AccountSettings.tsx
@@ -0,0 +1,192 @@
+// Copyright 2019-2022 @polkadot/extension-ui authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import { Layout, PageWrapper } from '@subwallet/extension-koni-ui/components';
+import useNotification from '@subwallet/extension-koni-ui/hooks/common/useNotification';
+import useTranslation from '@subwallet/extension-koni-ui/hooks/common/useTranslation';
+import { Theme, ThemeProps } from '@subwallet/extension-koni-ui/types';
+import { BackgroundIcon, Icon, SettingItem, SwIconProps } from '@subwallet/react-ui';
+import { CaretRight, CornersOut, Strategy } from 'phosphor-react';
+import React, { useCallback, useMemo } from 'react';
+import { useNavigate } from 'react-router-dom';
+import styled, { useTheme } from 'styled-components';
+
+type Props = ThemeProps
+
+type SettingItemType = {
+  key: string,
+  leftIcon: SwIconProps['phosphorIcon'] | React.ReactNode,
+  leftIconBgColor: string,
+  rightIcon: SwIconProps['phosphorIcon'],
+  title: string,
+  onClick?: () => void,
+  isHidden?: boolean,
+};
+
+type SettingGroupItemType = {
+  key: string,
+  label?: string,
+  items: SettingItemType[],
+};
+
+const isReactNode = (element: unknown): element is React.ReactNode => {
+  return React.isValidElement(element);
+};
+
+function generateLeftIcon (backgroundColor: string, icon: SwIconProps['phosphorIcon'] | React.ReactNode): React.ReactNode {
+  const isNode = isReactNode(icon);
+
+  return (
+    <BackgroundIcon
+      backgroundColor={backgroundColor}
+      customIcon={isNode ? icon : undefined}
+      phosphorIcon={isNode ? undefined : icon}
+      size='sm'
+      type={isNode ? 'customIcon' : 'phosphor'}
+      weight='fill'
+    />
+  );
+}
+
+function generateRightIcon (icon: SwIconProps['phosphorIcon']): React.ReactNode {
+  return (
+    <Icon
+      className='__right-icon'
+      customSize={'20px'}
+      phosphorIcon={icon}
+      type='phosphor'
+    />
+  );
+}
+
+function Component ({ className = '' }: Props): React.ReactElement<Props> {
+  const navigate = useNavigate();
+  const { token } = useTheme() as Theme;
+  const notify = useNotification();
+  const { t } = useTranslation();
+
+  const goBack = useCallback(() => {
+    navigate('/settings/list');
+  }, [navigate]);
+
+  const SettingGroupItemType = useMemo((): SettingGroupItemType[] => ([
+    {
+      key: 'general',
+      items: [
+        {
+          key: 'migrate-account',
+          leftIcon: Strategy,
+          leftIconBgColor: token.colorPrimary,
+          rightIcon: CaretRight,
+          title: t('Migrate to unified account'),
+          onClick: () => {
+            navigate('/migrate-account');
+          }
+        },
+        {
+          key: 'split-account',
+          leftIcon: CornersOut,
+          leftIconBgColor: token['volcano-6'],
+          rightIcon: CaretRight,
+          title: t('Split unified account'),
+          onClick: () => {
+            notify({
+              message: 'Coming soon!'
+            });
+          }
+        }
+      ]
+    }
+  ]), [navigate, notify, t, token]);
+
+  return (
+    <PageWrapper className={`account-settings ${className}`}>
+      <Layout.WithSubHeaderOnly
+        onBack={goBack}
+        title={t('Account settings')}
+      >
+        <div className={'__scroll-container'}>
+          {
+            SettingGroupItemType.map((group) => {
+              return (
+                <div
+                  className={'__group-container'}
+                  key={group.key}
+                >
+                  {!!group.label && (<div className='__group-label'>{group.label}</div>)}
+
+                  <div className={'__group-content'}>
+                    {group.items.map((item) => item.isHidden
+                      ? null
+                      : (
+                        <SettingItem
+                          className={'__setting-item setting-item'}
+                          key={item.key}
+                          leftItemIcon={generateLeftIcon(item.leftIconBgColor, item.leftIcon)}
+                          name={item.title}
+                          onPressItem={item.onClick}
+                          rightItem={
+                            <>
+                              {generateRightIcon(item.rightIcon)}
+                            </>
+                          }
+                        />
+                      ))}
+                  </div>
+                </div>
+              );
+            })
+          }
+        </div>
+      </Layout.WithSubHeaderOnly>
+    </PageWrapper>
+  );
+}
+
+export const AccountSettings = styled(Component)<Props>(({ theme: { token } }: Props) => {
+  return ({
+    height: '100%',
+    backgroundColor: token.colorBgDefault,
+    display: 'flex',
+    flexDirection: 'column',
+    overflow: 'hidden',
+
+    '.__scroll-container': {
+      overflow: 'auto',
+      paddingTop: token.padding,
+      paddingRight: token.padding,
+      paddingLeft: token.padding,
+      paddingBottom: token.paddingLG
+    },
+
+    '.__group-label': {
+      color: token.colorTextLight3,
+      fontSize: token.fontSizeSM,
+      lineHeight: token.lineHeightSM,
+      marginBottom: token.marginXS,
+      textTransform: 'uppercase'
+    },
+
+    '.__group-container': {
+      paddingBottom: token.padding
+    },
+
+    '.__setting-item + .__setting-item': {
+      marginTop: token.marginXS
+    },
+
+    '.ant-web3-block-right-item': {
+      minWidth: 40,
+      display: 'flex',
+      justifyContent: 'center',
+      alignItems: 'center',
+      color: token['gray-4']
+    },
+
+    '.__setting-item:hover .ant-web3-block-right-item': {
+      color: token['gray-6']
+    }
+  });
+});
+
+export default AccountSettings;
diff --git a/packages/extension-koni-ui/src/Popup/Settings/index.tsx b/packages/extension-koni-ui/src/Popup/Settings/index.tsx
index e3eb9fd7fb4..344b77d80a2 100644
--- a/packages/extension-koni-ui/src/Popup/Settings/index.tsx
+++ b/packages/extension-koni-ui/src/Popup/Settings/index.tsx
@@ -16,7 +16,7 @@ import { Theme, ThemeProps } from '@subwallet/extension-koni-ui/types';
 import { computeStatus, openInNewTab } from '@subwallet/extension-koni-ui/utils';
 import { BackgroundIcon, Button, ButtonProps, Icon, Image, ModalContext, SettingItem, SwHeader, SwIconProps, SwModal } from '@subwallet/react-ui';
 import CN from 'classnames';
-import { ArrowsOut, ArrowSquareOut, Book, BookBookmark, CaretRight, ChatTeardropText, Coin, EnvelopeSimple, FrameCorners, Globe, GlobeHemisphereEast, Lock, Rocket, ShareNetwork, ShieldCheck, X } from 'phosphor-react';
+import { ArrowsOut, ArrowSquareOut, Book, BookBookmark, CaretRight, ChatTeardropText, Coin, EnvelopeSimple, FrameCorners, Globe, GlobeHemisphereEast, Lock, Rocket, ShareNetwork, ShieldCheck, UserCircleGear, X } from 'phosphor-react';
 import React, { useCallback, useContext, useMemo, useState } from 'react';
 import { Outlet, useNavigate } from 'react-router-dom';
 import styled, { useTheme } from 'styled-components';
@@ -145,6 +145,17 @@ function Component ({ className = '' }: Props): React.ReactElement<Props> {
             navigate('/settings/security', { state: true });
           }
         },
+        {
+          key: 'account-settings',
+          leftIcon: UserCircleGear,
+          leftIconBgColor: token['purple-8'],
+          rightIcon: CaretRight,
+          title: t('Account settings'),
+          onClick: () => {
+            navigate('/settings/account-settings');
+          },
+          isHidden: !isPopup
+        },
         {
           key: 'crowdloans',
           leftIcon: Rocket,
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 4d6e3c85258..e321fcb4303 100644
--- a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx
+++ b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx
@@ -11,7 +11,7 @@ import { getAvailBridgeGatewayContract, getSnowBridgeGatewayContract } from '@su
 import { isAvailChainBridge } from '@subwallet/extension-base/services/balance-service/transfer/xcm/availBridge';
 import { _isPolygonChainBridge } from '@subwallet/extension-base/services/balance-service/transfer/xcm/polygonBridge';
 import { _isPosChainBridge, _isPosChainL2Bridge } from '@subwallet/extension-base/services/balance-service/transfer/xcm/posBridge';
-import { _getAssetDecimals, _getAssetName, _getAssetOriginChain, _getAssetSymbol, _getContractAddressOfToken, _getMultiChainAsset, _getOriginChainOfAsset, _getTokenMinAmount, _isChainEvmCompatible, _isNativeToken, _isTokenTransferredByEvm } from '@subwallet/extension-base/services/chain-service/utils';
+import { _getAssetDecimals, _getAssetName, _getAssetOriginChain, _getAssetSymbol, _getContractAddressOfToken, _getMultiChainAsset, _getOriginChainOfAsset, _getTokenMinAmount, _isChainCardanoCompatible, _isChainEvmCompatible, _isNativeToken, _isTokenTransferredByEvm } from '@subwallet/extension-base/services/chain-service/utils';
 import { TON_CHAINS } from '@subwallet/extension-base/services/earning-service/constants';
 import { SWTransactionResponse } from '@subwallet/extension-base/services/transaction-service/types';
 import { AccountChainType, AccountProxy, AccountProxyType, AccountSignMode, AnalyzedGroup, BasicTxWarningCode } from '@subwallet/extension-base/types';
@@ -177,7 +177,7 @@ const Component = ({ className = '', isAllAccount, targetAccountProxy }: Compone
       return true;
     }
 
-    return !!chainInfo && !!assetInfo && _isChainEvmCompatible(chainInfo) && destChainValue === chainValue && _isNativeToken(assetInfo);
+    return !!chainInfo && !!assetInfo && destChainValue === chainValue && _isNativeToken(assetInfo) && (_isChainEvmCompatible(chainInfo) || _isChainCardanoCompatible(chainInfo));
   }, [chainInfoMap, chainValue, destChainValue, assetInfo]);
 
   const disabledToAddressInput = useMemo(() => {
diff --git a/packages/extension-koni-ui/src/Popup/router.tsx b/packages/extension-koni-ui/src/Popup/router.tsx
index d5555ef1596..e27656312cb 100644
--- a/packages/extension-koni-ui/src/Popup/router.tsx
+++ b/packages/extension-koni-ui/src/Popup/router.tsx
@@ -76,6 +76,7 @@ const Settings = new LazyLoader('Settings', () => import('@subwallet/extension-k
 const GeneralSetting = new LazyLoader('GeneralSetting', () => import('@subwallet/extension-koni-ui/Popup/Settings/GeneralSetting'));
 const MissionPools = new LazyLoader('MissionPools', () => import('@subwallet/extension-koni-ui/Popup/Settings/MissionPool/index'));
 const ManageAddressBook = new LazyLoader('ManageAddressBook', () => import('@subwallet/extension-koni-ui/Popup/Settings/AddressBook'));
+const AccountSettings = new LazyLoader('ManageAddressBook', () => import('@subwallet/extension-koni-ui/Popup/Settings/AccountSettings'));
 
 const ManageChains = new LazyLoader('ManageChains', () => import('@subwallet/extension-koni-ui/Popup/Settings/Chains/ManageChains'));
 const ChainImport = new LazyLoader('ChainImport', () => import('@subwallet/extension-koni-ui/Popup/Settings/Chains/ChainImport'));
@@ -122,6 +123,7 @@ const CancelUnstake = new LazyLoader('CancelUnstake', () => import('@subwallet/e
 const ClaimReward = new LazyLoader('ClaimReward', () => import('@subwallet/extension-koni-ui/Popup/Transaction/variants/ClaimReward'));
 const Withdraw = new LazyLoader('Withdraw', () => import('@subwallet/extension-koni-ui/Popup/Transaction/variants/Withdraw'));
 const ClaimBridge = new LazyLoader('ClaimBridge', () => import('@subwallet/extension-koni-ui/Popup/Transaction/variants/ClaimBridge'));
+const MigrateAccount = new LazyLoader('MigrateAccount', () => import('@subwallet/extension-koni-ui/Popup/MigrateAccount'));
 
 // Earning
 
@@ -234,6 +236,7 @@ export const router = createHashRouter([
         children: [
           Settings.generateRouterObject('list'),
           GeneralSetting.generateRouterObject('general'),
+          AccountSettings.generateRouterObject('account-settings'),
           Crowdloans.generateRouterObject('crowdloans'),
           ManageAddressBook.generateRouterObject('address-book'),
           SecurityList.generateRouterObject('security'),
@@ -281,6 +284,9 @@ export const router = createHashRouter([
           ExportAllDone.generateRouterObject('export-all-done')
         ]
       },
+      {
+        ...MigrateAccount.generateRouterObject('migrate-account')
+      },
       {
         path: 'wallet-connect',
         element: <Outlet />,
diff --git a/packages/extension-koni-ui/src/assets/logo/index.ts b/packages/extension-koni-ui/src/assets/logo/index.ts
index 26104b2f277..5677b4bfd3f 100644
--- a/packages/extension-koni-ui/src/assets/logo/index.ts
+++ b/packages/extension-koni-ui/src/assets/logo/index.ts
@@ -15,6 +15,7 @@ export const DefaultLogosMap: Record<string, string> = {
   polkadot_vault: './images/projects/polkadot-vault.png',
   walletconnect: './images/projects/walletconnect.png',
   banxa: './images/projects/banxa.png',
+  cardano: './images/projects/cardano.png',
   coinbase: './images/projects/coinbase.png',
   stellaswap: './images/projects/stellaswap.png',
   xtwitter: './images/projects/xtwitter.png',
diff --git a/packages/extension-koni-ui/src/assets/subwallet/index.ts b/packages/extension-koni-ui/src/assets/subwallet/index.ts
index d9ff7d0dbc6..23e2189ef7f 100644
--- a/packages/extension-koni-ui/src/assets/subwallet/index.ts
+++ b/packages/extension-koni-ui/src/assets/subwallet/index.ts
@@ -12,6 +12,10 @@ const SwLogosMap: Record<string, string> = {
   avatar_placeholder: require('./avatar_placeholder.png'),
   default: DefaultLogosMap.default,
   transak: DefaultLogosMap.transak,
+  cardano: DefaultLogosMap.cardano,
+  cardano_preproduction: DefaultLogosMap.cardano,
+  ['cardano-NATIVE-ADA'.toLowerCase()]: DefaultLogosMap.cardano,
+  ['cardano_preproduction-NATIVE-tADA'.toLowerCase()]: DefaultLogosMap.cardano,
   onramper: DefaultLogosMap.onramper,
   moonpay: DefaultLogosMap.moonpay,
   banxa: DefaultLogosMap.banxa,
diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountChainTypeLogos.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountChainTypeLogos.tsx
new file mode 100644
index 00000000000..c7631481a39
--- /dev/null
+++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountChainTypeLogos.tsx
@@ -0,0 +1,65 @@
+// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import { ACCOUNT_CHAIN_TYPE_ORDINAL_MAP, AccountChainType } from '@subwallet/extension-base/types';
+import { Theme } from '@subwallet/extension-koni-ui/themes';
+import { ThemeProps } from '@subwallet/extension-koni-ui/types';
+import { getChainTypeLogoMap } from '@subwallet/extension-koni-ui/utils';
+import React, { Context, useContext, useMemo } from 'react';
+import styled, { ThemeContext } from 'styled-components';
+
+type Props = ThemeProps & {
+  chainTypes: AccountChainType[];
+}
+
+function Component ({ chainTypes, className }: Props): React.ReactElement<Props> {
+  const logoMap = useContext<Theme>(ThemeContext as Context<Theme>).logoMap;
+
+  const chainTypeLogoMap = useMemo(() => {
+    return getChainTypeLogoMap(logoMap);
+  }, [logoMap]);
+
+  const sortedChainTypes = useMemo(() => {
+    const result = [...chainTypes];
+
+    result.sort((a, b) => ACCOUNT_CHAIN_TYPE_ORDINAL_MAP[a] - ACCOUNT_CHAIN_TYPE_ORDINAL_MAP[b]);
+
+    return result;
+  }, [chainTypes]);
+
+  return (
+    <div className={className}>
+      {
+        sortedChainTypes.map((nt) => (
+          <img
+            alt='Chain type'
+            className={'__chain-type-logo'}
+            key={nt}
+            src={chainTypeLogoMap[nt]}
+          />
+        ))
+      }
+    </div>
+  );
+}
+
+const AccountChainTypeLogos = styled(Component)<Props>(({ theme: { token } }: Props) => {
+  return {
+    display: 'flex',
+    alignItems: 'center',
+
+    '.__chain-type-logo': {
+      display: 'block',
+      boxShadow: '-4px 0px 4px 0px rgba(0, 0, 0, 0.40)',
+      width: token.size,
+      height: token.size,
+      borderRadius: '100%'
+    },
+
+    '.__chain-type-logo + .__chain-type-logo': {
+      marginLeft: -token.marginXXS
+    }
+  };
+});
+
+export default AccountChainTypeLogos;
diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxyItem.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxyItem.tsx
index 277acfae3df..de54ef7bf5d 100644
--- a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxyItem.tsx
+++ b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxyItem.tsx
@@ -81,7 +81,10 @@ const AccountProxyItem = styled(Component)<Props>(({ theme }) => {
 
     '.__item-middle-part': {
       flex: 1,
-      textAlign: 'left'
+      textAlign: 'left',
+      'white-space': 'nowrap',
+      overflow: 'hidden',
+      textOverflow: 'ellipsis'
     },
 
     '.__item-right-part': {
diff --git a/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx b/packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx
index 0b3c9c931cf..49b9e350146 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 { AccountChainType, AccountProxy, AccountProxyType } from '@subwallet/extension-base/types';
+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';
@@ -9,9 +9,10 @@ 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, useMemo } from 'react';
+import React, { Context, useContext } from 'react';
 import styled, { ThemeContext } from 'styled-components';
 
+import AccountChainTypeLogos from './AccountChainTypeLogos';
 import AccountProxyAvatar from './AccountProxyAvatar';
 
 type Props = ThemeProps & {
@@ -41,19 +42,9 @@ function Component (props: Props): React.ReactElement<Props> {
     showDerivedPath } = props;
 
   const token = useContext<Theme>(ThemeContext as Context<Theme>).token;
-  const logoMap = useContext<Theme>(ThemeContext as Context<Theme>).logoMap;
 
   const { t } = useTranslation();
 
-  const chainTypeLogoMap = useMemo(() => {
-    return {
-      [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]);
-
   const _onClickDeriveButton: React.MouseEventHandler<HTMLAnchorElement | HTMLButtonElement> = React.useCallback((event) => {
     event.stopPropagation();
     onClickDeriveButton?.();
@@ -157,10 +148,10 @@ function Component (props: Props): React.ReactElement<Props> {
         </div>
         <div className='__item-center-part'>
           <div className='__item-name'>{accountProxy.name}</div>
-          <div className='__item-chain-types'>
-            {
-              showDerivedPath && !!accountProxy.parentId
-                ? <div className={'__item-derived-path'}>
+          {
+            showDerivedPath && !!accountProxy.parentId
+              ? (
+                <div className={'__item-derived-path'}>
                   <Icon
                     className={'__derived-account-flag'}
                     customSize='12px'
@@ -171,18 +162,14 @@ function Component (props: Props): React.ReactElement<Props> {
                     {accountProxy.suri || ''}
                   </div>
                 </div>
-                : accountProxy.chainTypes.map((nt) => {
-                  return (
-                    <img
-                      alt='Network type'
-                      className={'__item-chain-type-item'}
-                      key={nt}
-                      src={chainTypeLogoMap[nt]}
-                    />
-                  );
-                })
-            }
-          </div>
+              )
+              : (
+                <AccountChainTypeLogos
+                  chainTypes={accountProxy.chainTypes}
+                  className={'__item-chain-type-logos'}
+                />
+              )
+          }
         </div>
         <div className='__item-right-part'>
           <div className='__item-actions'>
@@ -314,20 +301,8 @@ const AccountProxySelectorItem = styled(Component)<Props>(({ theme }) => {
       overflow: 'hidden',
       'white-space': 'nowrap'
     },
-    '.__item-chain-types': {
-      display: 'flex',
-      paddingTop: 2
-    },
-    '.__item-chain-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-chain-type-item:first-of-type': {
-      marginLeft: 0
+    '.__item-chain-type-logos': {
+      minHeight: 20
     },
     '.__item-address': {
       fontSize: token.fontSizeSM,
diff --git a/packages/extension-koni-ui/src/components/AccountProxy/index.ts b/packages/extension-koni-ui/src/components/AccountProxy/index.ts
index 375f0f920e0..16d2066e185 100644
--- a/packages/extension-koni-ui/src/components/AccountProxy/index.ts
+++ b/packages/extension-koni-ui/src/components/AccountProxy/index.ts
@@ -1,6 +1,7 @@
 // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors
 // SPDX-License-Identifier: Apache-2.0
 
+export { default as AccountChainTypeLogos } from './AccountChainTypeLogos';
 export { default as AccountProxySelectorItem } from './AccountProxySelectorItem';
 export { default as AccountProxyBriefInfo } from './AccountProxyBriefInfo';
 export { default as AccountProxySelectorAllItem } from './AccountProxySelectorAllItem';
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 c92d0696bdd..b1e7f252a98 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
@@ -10,16 +10,16 @@ import ExportAllSelector from '@subwallet/extension-koni-ui/components/Layout/pa
 import SelectAccountFooter from '@subwallet/extension-koni-ui/components/Layout/parts/SelectAccount/Footer';
 import Search from '@subwallet/extension-koni-ui/components/Search';
 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 { useDefaultNavigate, useIsPopup, 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 { AccountDetailParam, 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 { Button, Icon, ModalContext, SwList, SwModal, Tooltip } from '@subwallet/react-ui';
 import CN from 'classnames';
-import { Circle, Export } from 'phosphor-react';
+import { Circle, Export, Gear } from 'phosphor-react';
 import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
 import { useSelector } from 'react-redux';
 import { useLocation, useNavigate } from 'react-router-dom';
@@ -88,6 +88,7 @@ const Component: React.FC<Props> = ({ className }: Props) => {
   const navigate = useNavigate();
   const { setStateSelectAccount } = useSetSessionLatest();
   const isModalVisible = useMemo(() => checkActive(modalId), [checkActive]);
+  const isPopup = useIsPopup();
 
   const accountProxies = useSelector((state: RootState) => state.accountState.accountProxies);
   const currentAccountProxy = useSelector((state: RootState) => state.accountState.currentAccountProxy);
@@ -338,6 +339,22 @@ const Component: React.FC<Props> = ({ className }: Props) => {
     }
   }, [isModalVisible]);
 
+  const accountSettingButtonProps = useMemo<ButtonProps>(() => {
+    return {
+      icon: (
+        <Icon
+          phosphorIcon={Gear}
+        />
+      ),
+      type: 'ghost',
+      onClick: () => {
+        navigate('/settings/account-settings');
+      },
+      tooltip: t('Account settings'),
+      tooltipPlacement: 'topRight'
+    };
+  }, [navigate, t]);
+
   const rightIconProps = useMemo((): ButtonProps | undefined => {
     if (!enableExtraction) {
       return;
@@ -398,7 +415,19 @@ const Component: React.FC<Props> = ({ className }: Props) => {
         id={modalId}
         onCancel={_onCancel}
         rightIconProps={rightIconProps}
-        title={t('Select account')}
+        title={(
+          <>
+            {t('Select account')}
+
+            {isPopup && (
+              <Button
+                {...accountSettingButtonProps}
+                className={'__account-setting-button -schema-header'}
+                size={'xs'}
+              />
+            )}
+          </>
+        )}
       >
         <Search
           autoFocus={true}
@@ -435,6 +464,23 @@ const Component: React.FC<Props> = ({ className }: Props) => {
 
 export const AccountSelectorModal = styled(Component)<Props>(({ theme: { token } }: Props) => {
   return {
+    '.ant-sw-header-center-part': {
+      position: 'relative',
+      height: 40
+    },
+
+    '.ant-sw-sub-header-title': {
+      fontSize: token.fontSizeXL,
+      lineHeight: token.lineHeightHeading4,
+      fontWeight: token.fontWeightStrong
+    },
+
+    '.ant-sw-header-center-part .__account-setting-button': {
+      position: 'absolute',
+      right: 0,
+      top: 0
+    },
+
     '.ant-sw-modal-content': {
       height: '100vh'
     },
diff --git a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/ExportAllSelectItem.tsx b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/ExportAllSelectItem.tsx
index c500b72e57d..4786221ae9d 100644
--- a/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/ExportAllSelectItem.tsx
+++ b/packages/extension-koni-ui/src/components/Layout/parts/SelectAccount/ExportAllSelectItem.tsx
@@ -1,8 +1,8 @@
 // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors
 // SPDX-License-Identifier: Apache-2.0
 
-import { AccountChainType, AccountProxy, AccountProxyType } from '@subwallet/extension-base/types';
-import { AccountProxyAvatar } from '@subwallet/extension-koni-ui/components';
+import { AccountProxy, AccountProxyType } from '@subwallet/extension-base/types';
+import { AccountChainTypeLogos, AccountProxyAvatar } from '@subwallet/extension-koni-ui/components';
 import { Theme } from '@subwallet/extension-koni-ui/themes';
 import { PhosphorIcon } from '@subwallet/extension-koni-ui/types';
 import { Icon } from '@subwallet/react-ui';
@@ -40,15 +40,6 @@ function Component (props: _AccountCardItem): React.ReactElement<_AccountCardIte
   const { accountType, chainTypes, id: accountProxyId, name: accountName } = useMemo(() => accountProxy, [accountProxy]);
 
   const token = useContext<Theme>(ThemeContext as Context<Theme>).token;
-  const logoMap = useContext<Theme>(ThemeContext as Context<Theme>).logoMap;
-  const chainTypeLogoMap = useMemo(() => {
-    return {
-      [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]);
   const _onSelect = useCallback(() => {
     onClick && onClick(accountProxyId || '');
   },
@@ -142,20 +133,10 @@ function Component (props: _AccountCardItem): React.ReactElement<_AccountCardIte
         <div className='__item-center-part'>
           <div className={'middle-item__name-wrapper'}>
             <div className='__item-name'>{accountName}</div>
-            <div className='__item-chain-types'>
-              {
-                chainTypes.map((nt) => {
-                  return (
-                    <img
-                      alt='Network type'
-                      className={'__item-chain-type-item'}
-                      key={nt}
-                      src={chainTypeLogoMap[nt]}
-                    />
-                  );
-                })
-              }
-            </div>
+            <AccountChainTypeLogos
+              chainTypes={chainTypes}
+              className={'__item-chain-type-logos'}
+            />
           </div>
         </div>
 
@@ -238,22 +219,8 @@ const ExportAllSelectItem = styled(Component)<_AccountCardItem>(({ theme }) => {
       overflow: 'hidden',
       'white-space': 'nowrap'
     },
-    '.__item-chain-types': {
-      display: 'flex',
-      paddingTop: 2,
-
-      '.__item-chain-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-chain-type-item:first-of-type': {
-        marginLeft: 0
-      }
+    '.__item-chain-type-logos': {
+      minHeight: 20
     },
     '.__item-right-part': {
       marginLeft: 'auto',
diff --git a/packages/extension-koni-ui/src/components/Modal/DeriveAccountActionModal.tsx b/packages/extension-koni-ui/src/components/Modal/DeriveAccountActionModal.tsx
index a29696a56e2..08325853879 100644
--- a/packages/extension-koni-ui/src/components/Modal/DeriveAccountActionModal.tsx
+++ b/packages/extension-koni-ui/src/components/Modal/DeriveAccountActionModal.tsx
@@ -37,7 +37,7 @@ interface DeriveFormState {
 
 const modalId = DERIVE_ACCOUNT_ACTION_MODAL;
 
-const alertTypes: DerivePathInfo['type'][] = ['unified', 'ton', 'ethereum'];
+const alertTypes: DerivePathInfo['type'][] = ['unified', 'ton', 'ethereum',  'cardano'];
 
 const Component: React.FC<Props> = (props: Props) => {
   const { className, onCompleteCb, proxyId } = props;
@@ -76,9 +76,10 @@ const Component: React.FC<Props> = (props: Props) => {
       'bitcoin-86': logoMap.network.bitcoin as string,
       'bittest-44': logoMap.network.bitcoin as string,
       'bittest-84': logoMap.network.bitcoin as string,
-      'bittest-86': logoMap.network.bitcoin as string
+      'bittest-86': logoMap.network.bitcoin as string,
+      cardano: logoMap.network.cardano as string
     };
-  }, [logoMap.network.bitcoin, logoMap.network.ethereum, logoMap.network.polkadot, logoMap.network.ton]);
+  }, [logoMap.network.bitcoin, logoMap.network.cardano, logoMap.network.ethereum, logoMap.network.polkadot, logoMap.network.ton]);
 
   const [form] = Form.useForm<DeriveFormState>();
 
diff --git a/packages/extension-koni-ui/src/components/Modal/Global/AccountMigrationInProgressWarningModal.tsx b/packages/extension-koni-ui/src/components/Modal/Global/AccountMigrationInProgressWarningModal.tsx
new file mode 100644
index 00000000000..c8d98b72f91
--- /dev/null
+++ b/packages/extension-koni-ui/src/components/Modal/Global/AccountMigrationInProgressWarningModal.tsx
@@ -0,0 +1,104 @@
+// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import { ACCOUNT_MIGRATION_IN_PROGRESS_WARNING_MODAL } from '@subwallet/extension-koni-ui/constants';
+import { ThemeProps } from '@subwallet/extension-koni-ui/types';
+import { Button, Icon, PageIcon, SwModal } from '@subwallet/react-ui';
+import CN from 'classnames';
+import { ArrowClockwise, Warning } from 'phosphor-react';
+import React, { useCallback } from 'react';
+import { useTranslation } from 'react-i18next';
+import styled from 'styled-components';
+
+type Props = ThemeProps;
+
+const modalId = ACCOUNT_MIGRATION_IN_PROGRESS_WARNING_MODAL;
+
+const Component: React.FC<Props> = (props: Props) => {
+  const { className } = props;
+  const { t } = useTranslation();
+
+  const onClickActionButton = useCallback(() => {
+    window.location.reload();
+  }, []);
+
+  return (
+    <>
+      <SwModal
+        className={CN(className)}
+        closable={false}
+        destroyOnClose={true}
+        footer={
+          <>
+            <Button
+              block={true}
+              className={'__action-button'}
+              icon={(
+                <Icon
+                  phosphorIcon={ArrowClockwise}
+                  weight={'fill'}
+                />
+              )}
+              onClick={onClickActionButton}
+            >
+              {t('Reload view')}
+            </Button>
+          </>
+        }
+        id={modalId}
+        maskClosable={false}
+        title={t('Migration in progress')}
+        zIndex={1000000}
+      >
+        <div className='__modal-content'>
+          <div className={CN('__warning-icon')}>
+            <PageIcon
+              color='var(--page-icon-color)'
+              iconProps={{
+                phosphorIcon: Warning
+              }}
+            />
+          </div>
+
+          {t('You can\'t perform any action in Expand view while account migration is in progress. Reopen SubWallet extension to complete migration, then reload to continue using Expand view')}
+        </div>
+      </SwModal>
+    </>
+  );
+};
+
+const AccountMigrationInProgressWarningModal = styled(Component)<Props>(({ theme: { token } }: Props) => {
+  return {
+    '.ant-sw-modal-body': {},
+
+    '.ant-sw-modal-footer': {
+      display: 'flex',
+      borderTop: 0,
+      gap: token.sizeXXS
+    },
+
+    '.ant-sw-header-center-part': {
+      width: '100%',
+      maxWidth: 292
+    },
+
+    '.__warning-icon': {
+      display: 'flex',
+      justifyContent: 'center',
+      marginBottom: 20,
+      '--page-icon-color': token.colorWarning
+    },
+
+    '.__modal-content': {
+      fontSize: token.fontSize,
+      lineHeight: token.lineHeightHeading6,
+      textAlign: 'center',
+      color: token.colorTextDescription,
+      paddingTop: token.padding,
+      paddingLeft: token.padding,
+      paddingRight: token.padding
+    }
+  };
+});
+
+export default AccountMigrationInProgressWarningModal;
diff --git a/packages/extension-koni-ui/src/components/Modal/Global/index.ts b/packages/extension-koni-ui/src/components/Modal/Global/index.ts
index d429b314b78..5fcc9dce36f 100644
--- a/packages/extension-koni-ui/src/components/Modal/Global/index.ts
+++ b/packages/extension-koni-ui/src/components/Modal/Global/index.ts
@@ -2,3 +2,4 @@
 // SPDX-License-Identifier: Apache-2.0
 
 export { default as AddressQrModal } from './AddressQrModal';
+export { default as AccountMigrationInProgressWarningModal } from './AccountMigrationInProgressWarningModal';
diff --git a/packages/extension-koni-ui/src/components/Modal/RemindDuplicateAccountNameModal.tsx b/packages/extension-koni-ui/src/components/Modal/RemindDuplicateAccountNameModal.tsx
index 1acf25ab4ca..787a52208f2 100644
--- a/packages/extension-koni-ui/src/components/Modal/RemindDuplicateAccountNameModal.tsx
+++ b/packages/extension-koni-ui/src/components/Modal/RemindDuplicateAccountNameModal.tsx
@@ -1,7 +1,7 @@
 // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors
 // SPDX-License-Identifier: Apache-2.0
 
-import { REMIND_DUPLICATE_ACCOUNT_NAME_MODAL, UPGRADE_DUPLICATE_ACCOUNT_NAME } from '@subwallet/extension-koni-ui/constants';
+import { NOTIFICATION_MODAL_WHITELIST_PATHS, REMIND_DUPLICATE_ACCOUNT_NAME_MODAL, UPGRADE_DUPLICATE_ACCOUNT_NAME } from '@subwallet/extension-koni-ui/constants';
 import useTranslation from '@subwallet/extension-koni-ui/hooks/common/useTranslation';
 import { getValueLocalStorageWS, setValueLocalStorageWS } from '@subwallet/extension-koni-ui/messaging';
 import { Theme } from '@subwallet/extension-koni-ui/themes';
@@ -11,6 +11,7 @@ import { Button, ModalContext, PageIcon, SwModal } from '@subwallet/react-ui';
 import CN from 'classnames';
 import { ShieldWarning } from 'phosphor-react';
 import React, { useCallback, useContext, useEffect, useMemo } from 'react';
+import { useLocation } from 'react-router-dom';
 import styled, { useTheme } from 'styled-components';
 
 type Props = ThemeProps;
@@ -19,6 +20,7 @@ const RemindDuplicateAccountNameModalId = REMIND_DUPLICATE_ACCOUNT_NAME_MODAL;
 const CHANGE_ACCOUNT_NAME_URL = 'https://docs.subwallet.app/main/extension-user-guide/account-management/switch-between-accounts-and-change-account-name#change-your-account-name';
 
 function Component ({ className }: Props): React.ReactElement<Props> {
+  const location = useLocation();
   const { t } = useTranslation();
   const { activeModal, inactiveModal } = useContext(ModalContext);
   const { token } = useTheme() as Theme;
@@ -28,13 +30,19 @@ function Component ({ className }: Props): React.ReactElement<Props> {
     setValueLocalStorageWS({ key: UPGRADE_DUPLICATE_ACCOUNT_NAME, value: 'false' }).catch(noop);
   }, [inactiveModal]);
 
+  const isInWhitelistPaths = useMemo(() => {
+    return NOTIFICATION_MODAL_WHITELIST_PATHS.includes(location.pathname);
+  }, [location.pathname]);
+
   useEffect(() => {
-    getValueLocalStorageWS(UPGRADE_DUPLICATE_ACCOUNT_NAME).then((value) => {
-      if (value === 'true') {
-        activeModal(RemindDuplicateAccountNameModalId);
-      }
-    }).catch(noop);
-  }, [activeModal]);
+    if (isInWhitelistPaths) {
+      getValueLocalStorageWS(UPGRADE_DUPLICATE_ACCOUNT_NAME).then((value) => {
+        if (value === 'true') {
+          activeModal(RemindDuplicateAccountNameModalId);
+        }
+      }).catch(noop);
+    }
+  }, [activeModal, isInWhitelistPaths]);
 
   const footerModal = useMemo(() => {
     return (
@@ -54,6 +62,7 @@ function Component ({ className }: Props): React.ReactElement<Props> {
       <SwModal
         className={CN(className)}
         closable={true}
+        destroyOnClose={true}
         footer={footerModal}
         id={RemindDuplicateAccountNameModalId}
         maskClosable={false}
diff --git a/packages/extension-koni-ui/src/components/Modal/index.tsx b/packages/extension-koni-ui/src/components/Modal/index.tsx
index 225db02870b..a3064c4590a 100644
--- a/packages/extension-koni-ui/src/components/Modal/index.tsx
+++ b/packages/extension-koni-ui/src/components/Modal/index.tsx
@@ -6,7 +6,7 @@ export { default as DeriveAccountActionModal } from './DeriveAccountActionModal'
 export { default as DisconnectExtensionModal } from './DisconnectExtensionModal';
 export { default as ReceiveModal } from './ReceiveModalNew';
 export { default as RemindBackupSeedPhraseModal } from './RemindBackupSeedPhraseModal';
-export { default as RemindUpgradeUnifiedAccount } from './RemindDuplicateAccountNameModal';
+export { default as RemindDuplicateAccountNameModal } from './RemindDuplicateAccountNameModal';
 export { default as RemindUpgradeVersionModal } from './RemindUpgradeFirefoxVersion';
 export { default as RequestCameraAccessModal } from './RequestCameraAccessModal';
 export { default as RequestCreatePasswordModal } from './RequestCreatePasswordModal';
diff --git a/packages/extension-koni-ui/src/components/StaticContent/ContentGenerator.tsx b/packages/extension-koni-ui/src/components/StaticContent/ContentGenerator.tsx
index 13932b70959..671b59e3b8a 100644
--- a/packages/extension-koni-ui/src/components/StaticContent/ContentGenerator.tsx
+++ b/packages/extension-koni-ui/src/components/StaticContent/ContentGenerator.tsx
@@ -30,10 +30,20 @@ const Component = ({ className, content }: Props) => {
         img (props) {
           const { children, className, node, src, ...rest } = props;
 
+          if (className?.includes('md-element')) {
+            return (
+              <img
+                {...rest}
+                className={className}
+                src={src}
+              />
+            );
+          }
+
           return (
             <Image
               {...rest}
-              className={'custom-img'}
+              className={className || 'custom-img'}
               onClick={noop}
               src={src}
               width={'100%'}
diff --git a/packages/extension-koni-ui/src/constants/modal.ts b/packages/extension-koni-ui/src/constants/modal.ts
index 0035d0bbebb..18b59f11a65 100644
--- a/packages/extension-koni-ui/src/constants/modal.ts
+++ b/packages/extension-koni-ui/src/constants/modal.ts
@@ -30,7 +30,7 @@ export const ADD_CONNECTION_MODAL = 'add-connection-modal';
 export const DISCONNECT_EXTENSION_MODAL = 'disconnect-extension-modal';
 export const REMIND_BACKUP_SEED_PHRASE_MODAL = 'remind-backup-seed-phrase-modal';
 export const REMIND_UPGRADE_FIREFOX_VERSION = 'remind-update-firefox-version';
-export const REMIND_DUPLICATE_ACCOUNT_NAME_MODAL = 'remind-update-unified-account';
+export const REMIND_DUPLICATE_ACCOUNT_NAME_MODAL = 'remind-duplicate-account-name-modal';
 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';
@@ -39,6 +39,7 @@ export const ACCOUNT_NAME_MODAL = 'account-name-modal';
 export const GLOBAL_ALERT_MODAL = 'global-alert-modal';
 export const TON_WALLET_CONTRACT_SELECTOR_MODAL = 'ton-wallet-contract-selector-modal';
 export const TON_ACCOUNT_SELECTOR_MODAL = 'ton-account-selector-modal';
+export const ACCOUNT_MIGRATION_IN_PROGRESS_WARNING_MODAL = 'account-migration-in-progress-warning-modal';
 
 /* Campaign */
 export const HOME_CAMPAIGN_BANNER_MODAL = 'home-campaign-banner-modal';
diff --git a/packages/extension-koni-ui/src/constants/router.ts b/packages/extension-koni-ui/src/constants/router.ts
index f11a40d8031..97af8a6280a 100644
--- a/packages/extension-koni-ui/src/constants/router.ts
+++ b/packages/extension-koni-ui/src/constants/router.ts
@@ -2,3 +2,8 @@
 // SPDX-License-Identifier: Apache-2.0
 
 export const DEFAULT_ROUTER_PATH = '/';
+
+export const NOTIFICATION_MODAL_WHITELIST_PATHS = [
+  '/migrate-account',
+  '/home/tokens'
+];
diff --git a/packages/extension-koni-ui/src/contexts/DataContext.tsx b/packages/extension-koni-ui/src/contexts/DataContext.tsx
index 17b25a68a25..fffba561b2d 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, subscribeConfirmationRequestsTon, subscribeConnectWCRequests, subscribeCrowdloan, subscribeKeyringState, subscribeLedgerGenericAllowNetworks, subscribeMantaPayConfig, subscribeMantaPaySyncingState, subscribeMetadataRequests, subscribeMultiChainAssetMap, subscribeNftCollections, subscribeNftItems, subscribePrice, subscribeProcessingCampaign, subscribeRewardHistory, subscribeSigningRequests, subscribeStaking, subscribeStakingNominatorMetadata, subscribeStakingReward, subscribeSwapPairs, subscribeTransactionRequests, subscribeTxHistory, subscribeUiSettings, subscribeUnreadNotificationCount, 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, subscribeConfirmationRequestsCardano, subscribeConfirmationRequestsTon, subscribeConnectWCRequests, subscribeCrowdloan, subscribeKeyringState, subscribeLedgerGenericAllowNetworks, subscribeMantaPayConfig, subscribeMantaPaySyncingState, subscribeMetadataRequests, subscribeMultiChainAssetMap, subscribeNftCollections, subscribeNftItems, subscribePrice, subscribeProcessingCampaign, subscribeRewardHistory, subscribeSigningRequests, subscribeStaking, subscribeStakingNominatorMetadata, subscribeStakingReward, subscribeSwapPairs, subscribeTransactionRequests, subscribeTxHistory, subscribeUiSettings, subscribeUnreadNotificationCount, 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';
@@ -227,6 +227,7 @@ export const DataContextProvider = ({ children }: DataContextProviderProps) => {
   _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({ ...subscribeConfirmationRequestsCardano, name: 'subscribeConfirmationRequestsCardano', 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/contexts/WalletModalContextProvider.tsx b/packages/extension-koni-ui/src/contexts/WalletModalContextProvider.tsx
index a11d1efc398..258bdf335bb 100644
--- a/packages/extension-koni-ui/src/contexts/WalletModalContextProvider.tsx
+++ b/packages/extension-koni-ui/src/contexts/WalletModalContextProvider.tsx
@@ -1,11 +1,11 @@
 // Copyright 2019-2022 @polkadot/extension-ui authors & contributors
 // SPDX-License-Identifier: Apache-2.0
 
-import { AddressQrModal, AlertModal, AttachAccountModal, ClaimDappStakingRewardsModal, CreateAccountModal, DeriveAccountActionModal, DeriveAccountListModal, ImportAccountModal, ImportSeedModal, NewSeedModal, RemindBackupSeedPhraseModal, RequestCameraAccessModal, RequestCreatePasswordModal } from '@subwallet/extension-koni-ui/components';
+import { AccountMigrationInProgressWarningModal, AddressQrModal, AlertModal, AttachAccountModal, ClaimDappStakingRewardsModal, CreateAccountModal, DeriveAccountActionModal, DeriveAccountListModal, ImportAccountModal, ImportSeedModal, NewSeedModal, RemindBackupSeedPhraseModal, RemindDuplicateAccountNameModal, RequestCameraAccessModal, RequestCreatePasswordModal } from '@subwallet/extension-koni-ui/components';
 import { CustomizeModal } from '@subwallet/extension-koni-ui/components/Modal/Customize/CustomizeModal';
 import { AccountDeriveActionProps } from '@subwallet/extension-koni-ui/components/Modal/DeriveAccountActionModal';
-import { ADDRESS_QR_MODAL, DERIVE_ACCOUNT_ACTION_MODAL, EARNING_INSTRUCTION_MODAL, GLOBAL_ALERT_MODAL } from '@subwallet/extension-koni-ui/constants';
-import { useAlert, useGetConfig, useSetSessionLatest } from '@subwallet/extension-koni-ui/hooks';
+import { ACCOUNT_MIGRATION_IN_PROGRESS_WARNING_MODAL, ADDRESS_QR_MODAL, DERIVE_ACCOUNT_ACTION_MODAL, EARNING_INSTRUCTION_MODAL, GLOBAL_ALERT_MODAL } from '@subwallet/extension-koni-ui/constants';
+import { useAlert, useGetConfig, useIsPopup, 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 { AlertDialogProps } from '@subwallet/extension-koni-ui/types';
@@ -105,9 +105,12 @@ export const WalletModalContextProvider = ({ children }: Props) => {
   const { getConfig } = useGetConfig();
   const { onHandleSessionLatest, setTimeBackUp } = useSetSessionLatest();
   const { alertProps, closeAlert, openAlert } = useAlert(alertModalId);
+  const isUnifiedAccountMigrationInProgress = useSelector((state: RootState) => state.settings.isUnifiedAccountMigrationInProgress);
+  const isPopup = useIsPopup();
 
   useExcludeModal('confirmations');
   useExcludeModal(EARNING_INSTRUCTION_MODAL);
+  useExcludeModal(ACCOUNT_MIGRATION_IN_PROGRESS_WARNING_MODAL);
 
   const onCloseModal = useCallback(() => {
     setSearchParams((prev) => {
@@ -170,6 +173,12 @@ export const WalletModalContextProvider = ({ children }: Props) => {
     }
   }, [hasMasterPassword, inactiveAll, isLocked]);
 
+  useEffect(() => {
+    if (!isPopup && isUnifiedAccountMigrationInProgress) {
+      activeModal(ACCOUNT_MIGRATION_IN_PROGRESS_WARNING_MODAL);
+    }
+  }, [activeModal, isPopup, isUnifiedAccountMigrationInProgress]);
+
   useEffect(() => {
     const confirmID = searchParams.get('popup');
 
@@ -220,6 +229,8 @@ export const WalletModalContextProvider = ({ children }: Props) => {
     <RequestCameraAccessModal />
     <CustomizeModal />
     <UnlockModal />
+    <AccountMigrationInProgressWarningModal />
+    <RemindDuplicateAccountNameModal />
 
     {
       !!addressQrModalProps && (
diff --git a/packages/extension-koni-ui/src/hooks/staticContent/index.ts b/packages/extension-koni-ui/src/hooks/staticContent/index.ts
index 39e42f50d8e..e98b46dfe08 100644
--- a/packages/extension-koni-ui/src/hooks/staticContent/index.ts
+++ b/packages/extension-koni-ui/src/hooks/staticContent/index.ts
@@ -2,3 +2,4 @@
 // SPDX-License-Identifier: Apache-2.0
 
 export { default as useGetConfig } from './useGetConfig';
+export { default as useFetchMarkdownContentData } from './useFetchMarkdownContentData';
diff --git a/packages/extension-koni-ui/src/hooks/staticContent/useFetchMarkdownContentData.tsx b/packages/extension-koni-ui/src/hooks/staticContent/useFetchMarkdownContentData.tsx
new file mode 100644
index 00000000000..c14ddb6ee32
--- /dev/null
+++ b/packages/extension-koni-ui/src/hooks/staticContent/useFetchMarkdownContentData.tsx
@@ -0,0 +1,27 @@
+// Copyright 2019-2022 @polkadot/extension-ui authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import { LanguageType } from '@subwallet/extension-base/background/KoniTypes';
+import { fetchStaticData } from '@subwallet/extension-base/utils';
+import { isProductionMode } from '@subwallet/extension-koni-ui/constants';
+import { RootState } from '@subwallet/extension-koni-ui/stores';
+import { useCallback } from 'react';
+import { useSelector } from 'react-redux';
+
+const useFetchMarkdownContentData = () => {
+  const currentLanguage = useSelector((state: RootState) => state.settings.language);
+
+  const getJsonFile = useCallback((supportedLanguages: LanguageType[], fallbackLanguage: LanguageType) => {
+    const resultLanguage = supportedLanguages.includes(currentLanguage) ? currentLanguage : fallbackLanguage;
+
+    return isProductionMode ? `list-${resultLanguage}.json` : `preview-${resultLanguage}.json`;
+  }, [currentLanguage]);
+
+  return useCallback(<T = unknown>(folder: string, supportedLanguages: LanguageType[], fallbackLanguage: LanguageType = 'en') => {
+    const jsonFile = getJsonFile(supportedLanguages, fallbackLanguage);
+
+    return fetchStaticData<T>(`markdown-contents/${folder}`, jsonFile, true);
+  }, [getJsonFile]);
+};
+
+export default useFetchMarkdownContentData;
diff --git a/packages/extension-koni-ui/src/messaging/confirmation/base.ts b/packages/extension-koni-ui/src/messaging/confirmation/base.ts
index 5a456901c95..9c7f992e5e5 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, ConfirmationDefinitionsTon, ConfirmationType, ConfirmationTypeTon, RequestSigningApprovePasswordV2 } from '@subwallet/extension-base/background/KoniTypes';
+import { ConfirmationDefinitions, ConfirmationDefinitionsCardano, ConfirmationDefinitionsTon, ConfirmationType, ConfirmationTypeCardano, ConfirmationTypeTon, RequestSigningApprovePasswordV2 } from '@subwallet/extension-base/background/KoniTypes';
 import { ResponseSigningIsLocked } from '@subwallet/extension-base/background/types';
 
 import { HexString } from '@polkadot/util/types';
@@ -35,3 +35,7 @@ export async function completeConfirmation<CT extends ConfirmationType> (type: C
 export async function completeConfirmationTon<CT extends ConfirmationTypeTon> (type: CT, payload: ConfirmationDefinitionsTon[CT][1]): Promise<boolean> {
   return sendMessage('pri(confirmationsTon.complete)', { [type]: payload });
 }
+
+export async function completeConfirmationCardano<CT extends ConfirmationTypeCardano> (type: CT, payload: ConfirmationDefinitionsCardano[CT][1]): Promise<boolean> {
+  return sendMessage('pri(confirmationsCardano.complete)', { [type]: payload });
+}
diff --git a/packages/extension-koni-ui/src/messaging/migrate-unified-account/index.ts b/packages/extension-koni-ui/src/messaging/migrate-unified-account/index.ts
new file mode 100644
index 00000000000..620ab7d7650
--- /dev/null
+++ b/packages/extension-koni-ui/src/messaging/migrate-unified-account/index.ts
@@ -0,0 +1,17 @@
+// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import { RequestMigrateSoloAccount, RequestMigrateUnifiedAndFetchEligibleSoloAccounts, RequestPingSession, ResponseMigrateSoloAccount, ResponseMigrateUnifiedAndFetchEligibleSoloAccounts } from '@subwallet/extension-base/background/KoniTypes';
+import { sendMessage } from '@subwallet/extension-koni-ui/messaging';
+
+export function migrateUnifiedAndFetchEligibleSoloAccounts (request: RequestMigrateUnifiedAndFetchEligibleSoloAccounts): Promise<ResponseMigrateUnifiedAndFetchEligibleSoloAccounts> {
+  return sendMessage('pri(migrate.migrateUnifiedAndFetchEligibleSoloAccounts)', request);
+}
+
+export function migrateSoloAccount (request: RequestMigrateSoloAccount): Promise<ResponseMigrateSoloAccount> {
+  return sendMessage('pri(migrate.migrateSoloAccount)', request);
+}
+
+export function pingSession (request: RequestPingSession) {
+  return sendMessage('pri(migrate.pingSession)', request);
+}
diff --git a/packages/extension-koni-ui/src/messaging/settings/base.ts b/packages/extension-koni-ui/src/messaging/settings/base.ts
index 1fa93af7774..48a0ea7e4e1 100644
--- a/packages/extension-koni-ui/src/messaging/settings/base.ts
+++ b/packages/extension-koni-ui/src/messaging/settings/base.ts
@@ -1,7 +1,7 @@
 // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors
 // SPDX-License-Identifier: Apache-2.0
 
-import { BrowserConfirmationType, CurrencyType, LanguageType, RequestSaveAppConfig, RequestSaveBrowserConfig, RequestSaveOSConfig, RequestSettingsType, RequestSubscribeBalancesVisibility, ThemeNames, UiSettings, WalletUnlockType } from '@subwallet/extension-base/background/KoniTypes';
+import { BrowserConfirmationType, CurrencyType, LanguageType, RequestSaveAppConfig, RequestSaveBrowserConfig, RequestSaveMigrationAcknowledgedStatus, RequestSaveOSConfig, RequestSaveUnifiedAccountMigrationInProgress, RequestSettingsType, RequestSubscribeBalancesVisibility, ThemeNames, UiSettings, WalletUnlockType } from '@subwallet/extension-base/background/KoniTypes';
 import { NotificationSetup } from '@subwallet/extension-base/services/inapp-notification-service/interfaces';
 import { sendMessage } from '@subwallet/extension-koni-ui/messaging';
 
@@ -41,6 +41,18 @@ export async function saveNotificationSetup (request: NotificationSetup): Promis
   return sendMessage('pri(settings.saveNotificationSetup)', request);
 }
 
+export async function saveUnifiedAccountMigrationInProgress (request: RequestSaveUnifiedAccountMigrationInProgress): Promise<boolean> {
+  return sendMessage('pri(settings.saveUnifiedAccountMigrationInProgress)', request);
+}
+
+export async function pingUnifiedAccountMigrationDone (): Promise<boolean> {
+  return sendMessage('pri(settings.pingUnifiedAccountMigrationDone)');
+}
+
+export async function saveMigrationAcknowledgedStatus (request: RequestSaveMigrationAcknowledgedStatus): Promise<boolean> {
+  return sendMessage('pri(settings.saveMigrationAcknowledgedStatus)', request);
+}
+
 export async function saveLanguage (lang: LanguageType): Promise<boolean> {
   return sendMessage('pri(settings.saveLanguage)', { language: lang });
 }
diff --git a/packages/extension-koni-ui/src/stores/base/RequestState.ts b/packages/extension-koni-ui/src/stores/base/RequestState.ts
index b1b2b1039d8..d70a8826bc4 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, ConfirmationsQueueTon } from '@subwallet/extension-base/background/KoniTypes';
+import { ConfirmationsQueue, ConfirmationsQueueCardano, 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';
@@ -30,6 +30,10 @@ const initialState: RequestState = {
   tonSendTransactionRequest: {},
   tonWatchTransactionRequest: {},
 
+  cardanoSignatureRequest: {},
+  cardanoSendTransactionRequest: {},
+  cardanoWatchTransactionRequest: {},
+
   // Summary Info
   reduxStatus: ReduxStatus.INIT,
   hasConfirmations: false,
@@ -50,6 +54,9 @@ export const CONFIRMATIONS_FIELDS: Array<keyof RequestState> = [
   'tonSignatureRequest',
   'tonSendTransactionRequest',
   'tonWatchTransactionRequest',
+  'cardanoSignatureRequest',
+  'cardanoSendTransactionRequest',
+  'tonWatchTransactionRequest',
   'connectWCRequest',
   'notSupportWCRequest'
 ];
@@ -67,6 +74,7 @@ const readyMap = {
   updateSigningRequests: false,
   updateConfirmationRequests: false,
   updateConfirmationRequestsTon: false,
+  updateConfirmationRequestCardano: false,
   updateConnectWalletConnect: false,
   updateNotSupportWalletConnect: false
 };
@@ -130,6 +138,11 @@ const requestStateSlice = createSlice({
       readyMap.updateConfirmationRequestsTon = true;
       computeStateSummary(state as RequestState);
     },
+    updateConfirmationRequestsCardano (state, action: PayloadAction<Partial<ConfirmationsQueueCardano>>) {
+      Object.assign(state, action.payload);
+      readyMap.updateConfirmationRequestCardano = true;
+      computeStateSummary(state as RequestState);
+    },
     updateWCNotSupportRequests (state, { payload }: PayloadAction<Record<string, WalletConnectNotSupportRequest>>) {
       state.notSupportWCRequest = payload;
       readyMap.updateNotSupportWalletConnect = true;
diff --git a/packages/extension-koni-ui/src/stores/types.ts b/packages/extension-koni-ui/src/stores/types.ts
index f339820298d..1f9cc6b1ad4 100644
--- a/packages/extension-koni-ui/src/stores/types.ts
+++ b/packages/extension-koni-ui/src/stores/types.ts
@@ -2,7 +2,7 @@
 // SPDX-License-Identifier: Apache-2.0
 
 import { _AssetRef, _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet/chain-list/types';
-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 { AddressBookState, AllLogoMap, AssetSetting, CampaignBanner, ChainStakingMetadata, ConfirmationDefinitions, ConfirmationsQueue, ConfirmationsQueueCardano, 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, ConfirmationsQueueTon, BaseReduxStore {
+export interface RequestState extends ConfirmationsQueue, ConfirmationsQueueTon, ConfirmationsQueueCardano, BaseReduxStore {
   authorizeRequest: Record<string, AuthorizeRequest>;
   metadataRequest: Record<string, MetadataRequest>;
   signingRequest: Record<string, SigningRequest>;
diff --git a/packages/extension-koni-ui/src/stores/utils/index.ts b/packages/extension-koni-ui/src/stores/utils/index.ts
index a0d892c268c..5109a2b64be 100644
--- a/packages/extension-koni-ui/src/stores/utils/index.ts
+++ b/packages/extension-koni-ui/src/stores/utils/index.ts
@@ -2,7 +2,7 @@
 // SPDX-License-Identifier: Apache-2.0
 
 import { _AssetRef, _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet/chain-list/types';
-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 { AddressBookInfo, AssetSetting, CampaignBanner, ChainStakingMetadata, ConfirmationsQueue, ConfirmationsQueueCardano, 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';
@@ -148,6 +148,12 @@ export const updateConfirmationRequestsTon = (data: ConfirmationsQueueTon) => {
 
 export const subscribeConfirmationRequestsTon = lazySubscribeMessage('pri(confirmationsTon.subscribe)', null, updateConfirmationRequestsTon, updateConfirmationRequestsTon);
 
+export const updateConfirmationRequestsCardano = (data: ConfirmationsQueueCardano) => {
+  store.dispatch({ type: 'requestState/updateConfirmationRequestsCardano', payload: data });
+};
+
+export const subscribeConfirmationRequestsCardano = lazySubscribeMessage('pri(confirmationsCardano.subscribe)', null, updateConfirmationRequestsCardano, updateConfirmationRequestsCardano);
+
 export const updateTransactionRequests = (data: Record<string, SWTransactionResult>) => {
   // 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 ccdf4f6aafb..4a3edcf0ecc 100644
--- a/packages/extension-koni-ui/src/types/confirmation.ts
+++ b/packages/extension-koni-ui/src/types/confirmation.ts
@@ -1,9 +1,11 @@
 // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors
 // SPDX-License-Identifier: Apache-2.0
 
-import { ConfirmationDefinitions, ConfirmationDefinitionsTon } from '@subwallet/extension-base/background/KoniTypes';
+import { ConfirmationDefinitions, ConfirmationDefinitionsCardano, ConfirmationDefinitionsTon } from '@subwallet/extension-base/background/KoniTypes';
 
 export type EvmSignatureSupportType = keyof Pick<ConfirmationDefinitions, 'evmSignatureRequest' | 'evmSendTransactionRequest' | 'evmWatchTransactionRequest'>;
 export type EvmErrorSupportType = keyof Pick<ConfirmationDefinitions, 'errorConnectNetwork'>;
 
 export type TonSignatureSupportType = keyof Pick<ConfirmationDefinitionsTon, 'tonSignatureRequest' | 'tonWatchTransactionRequest' | 'tonSendTransactionRequest'>;
+
+export type CardanoSignatureSupportType = keyof Pick<ConfirmationDefinitionsCardano, 'cardanoSignatureRequest' | 'cardanoWatchTransactionRequest' | 'cardanoSendTransactionRequest'>;
diff --git a/packages/extension-koni-ui/src/utils/account/account.ts b/packages/extension-koni-ui/src/utils/account/account.ts
index ff7a0b65b6e..6b444034250 100644
--- a/packages/extension-koni-ui/src/utils/account/account.ts
+++ b/packages/extension-koni-ui/src/utils/account/account.ts
@@ -15,6 +15,7 @@ import { getNetworkKeyByGenesisHash } from '@subwallet/extension-koni-ui/utils/c
 import { AccountInfoByNetwork } from '@subwallet/extension-koni-ui/utils/types';
 import { isAddress, isSubstrateAddress, isTonAddress } from '@subwallet/keyring';
 import { KeypairType } from '@subwallet/keyring/types';
+import { Web3LogoMap } from '@subwallet/react-ui/es/config-provider/context';
 
 import { decodeAddress, encodeAddress, isEthereumAddress } from '@polkadot/util-crypto';
 
@@ -179,6 +180,8 @@ export function getReformatedAddressRelatedToChain (accountJson: AccountJson, ch
     return accountJson.address;
   } else if (accountJson.chainType === AccountChainType.TON && chainInfo.tonInfo) {
     return reformatAddress(accountJson.address, chainInfo.isTestnet ? 0 : 1);
+  } else if (accountJson.chainType === AccountChainType.CARDANO && chainInfo.cardanoInfo) {
+    return reformatAddress(accountJson.address, chainInfo.isTestnet ? 0 : 1);
   }
 
   return undefined;
@@ -217,3 +220,13 @@ export const isAddressAllowedWithAuthType = (address: string, authAccountTypes?:
 
   return false;
 };
+
+export function getChainTypeLogoMap (logoMap: Web3LogoMap): Record<string, string> {
+  return {
+    [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,
+    [AccountChainType.CARDANO]: logoMap.network.cardano as string
+  };
+}
diff --git a/packages/extension-koni-ui/src/utils/chain/chain.ts b/packages/extension-koni-ui/src/utils/chain/chain.ts
index 9e43f24f5d1..93371a8b53b 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, _isChainTonCompatible, _isPureSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils';
+import { _getSubstrateGenesisHash, _isChainBitcoinCompatible, _isChainCardanoCompatible, _isChainEvmCompatible, _isChainTonCompatible, _isPureSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils';
 import { AccountChainType, AccountProxy } from '@subwallet/extension-base/types';
 import { isAccountAll } from '@subwallet/extension-base/utils';
 
@@ -51,6 +51,10 @@ export const isChainInfoAccordantAccountChainType = (chainInfo: _ChainInfo, chai
     return _isChainBitcoinCompatible(chainInfo);
   }
 
+  if (chainType === AccountChainType.CARDANO) {
+    return _isChainCardanoCompatible(chainInfo);
+  }
+
   return false;
 };
 
diff --git a/packages/extension-koni/package.json b/packages/extension-koni/package.json
index 6697617a061..9a38da2e6a4 100644
--- a/packages/extension-koni/package.json
+++ b/packages/extension-koni/package.json
@@ -17,6 +17,7 @@
   "version": "1.3.15-0",
   "dependencies": {
     "@babel/runtime": "^7.20.6",
+    "@emurgo/cardano-serialization-lib-browser": "^13.2.0",
     "@subwallet/extension-base": "^1.3.15-0",
     "@subwallet/extension-inject": "^1.3.15-0",
     "@subwallet/extension-koni-ui": "^1.3.15-0"
diff --git a/packages/extension-koni/public/images/projects/cardano.png b/packages/extension-koni/public/images/projects/cardano.png
new file mode 100644
index 00000000000..13fd5c628cd
Binary files /dev/null and b/packages/extension-koni/public/images/projects/cardano.png differ
diff --git a/packages/extension-koni/webpack.shared.cjs b/packages/extension-koni/webpack.shared.cjs
index 7a530f5c638..f6264ea6564 100644
--- a/packages/extension-koni/webpack.shared.cjs
+++ b/packages/extension-koni/webpack.shared.cjs
@@ -35,7 +35,8 @@ const packages = [
   'extension-dapp',
   'extension-inject',
   'extension-koni',
-  'extension-koni-ui'
+  'extension-koni-ui',
+  'subwallet-api-sdk'
 ];
 
 const _additionalEnv = {
@@ -57,7 +58,8 @@ const _additionalEnv = {
   BITTENSOR_API_KEY_8: JSON.stringify(process.env.BITTENSOR_API_KEY_8),
   BITTENSOR_API_KEY_9: JSON.stringify(process.env.BITTENSOR_API_KEY_9),
   BITTENSOR_API_KEY_10: JSON.stringify(process.env.BITTENSOR_API_KEY_10),
-  SIMPLE_SWAP_API_KEY: JSON.stringify(process.env.SIMPLE_SWAP_API_KEY)
+  SIMPLE_SWAP_API_KEY: JSON.stringify(process.env.SIMPLE_SWAP_API_KEY),
+  SUBWALLET_API: JSON.stringify(process.env.SUBWALLET_API)
 };
 
 const additionalEnvDict = {
@@ -159,7 +161,11 @@ module.exports = (entry, alias = {}, isFirefox = false) => {
         filename: 'notification.html',
         template: 'public/notification.html',
         chunks: ['extension']
-      })
+      }),
+      new webpack.NormalModuleReplacementPlugin(
+        /@emurgo\/cardano-serialization-lib-nodejs/,
+        '@emurgo/cardano-serialization-lib-browser'
+      )
     ],
     resolve: {
       alias: packages.reduce((alias, p) => ({
diff --git a/packages/subwallet-api-sdk/LICENSE b/packages/subwallet-api-sdk/LICENSE
new file mode 100644
index 00000000000..0d381b2e97d
--- /dev/null
+++ b/packages/subwallet-api-sdk/LICENSE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                    http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+  "License" shall mean the terms and conditions for use, reproduction,
+  and distribution as defined by Sections 1 through 9 of this document.
+
+  "Licensor" shall mean the copyright owner or entity authorized by
+  the copyright owner that is granting the License.
+
+  "Legal Entity" shall mean the union of the acting entity and all
+  other entities that control, are controlled by, or are under common
+  control with that entity. For the purposes of this definition,
+  "control" means (i) the power, direct or indirect, to cause the
+  direction or management of such entity, whether by contract or
+  otherwise, or (ii) ownership of fifty percent (50%) or more of the
+  outstanding shares, or (iii) beneficial ownership of such entity.
+
+  "You" (or "Your") shall mean an individual or Legal Entity
+  exercising permissions granted by this License.
+
+  "Source" form shall mean the preferred form for making modifications,
+  including but not limited to software source code, documentation
+  source, and configuration files.
+
+  "Object" form shall mean any form resulting from mechanical
+  transformation or translation of a Source form, including but
+  not limited to compiled object code, generated documentation,
+  and conversions to other media types.
+
+  "Work" shall mean the work of authorship, whether in Source or
+  Object form, made available under the License, as indicated by a
+  copyright notice that is included in or attached to the work
+  (an example is provided in the Appendix below).
+
+  "Derivative Works" shall mean any work, whether in Source or Object
+  form, that is based on (or derived from) the Work and for which the
+  editorial revisions, annotations, elaborations, or other modifications
+  represent, as a whole, an original work of authorship. For the purposes
+  of this License, Derivative Works shall not include works that remain
+  separable from, or merely link (or bind by name) to the interfaces of,
+  the Work and Derivative Works thereof.
+
+  "Contribution" shall mean any work of authorship, including
+  the original version of the Work and any modifications or additions
+  to that Work or Derivative Works thereof, that is intentionally
+  submitted to Licensor for inclusion in the Work by the copyright owner
+  or by an individual or Legal Entity authorized to submit on behalf of
+  the copyright owner. For the purposes of this definition, "submitted"
+  means any form of electronic, verbal, or written communication sent
+  to the Licensor or its representatives, including but not limited to
+  communication on electronic mailing lists, source code control systems,
+  and issue tracking systems that are managed by, or on behalf of, the
+  Licensor for the purpose of discussing and improving the Work, but
+  excluding communication that is conspicuously marked or otherwise
+  designated in writing by the copyright owner as "Not a Contribution."
+
+  "Contributor" shall mean Licensor and any individual or Legal Entity
+  on behalf of whom a Contribution has been received by Licensor and
+  subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  copyright license to reproduce, prepare Derivative Works of,
+  publicly display, publicly perform, sublicense, and distribute the
+  Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  (except as stated in this section) patent license to make, have made,
+  use, offer to sell, sell, import, and otherwise transfer the Work,
+  where such license applies only to those patent claims licensable
+  by such Contributor that are necessarily infringed by their
+  Contribution(s) alone or by combination of their Contribution(s)
+  with the Work to which such Contribution(s) was submitted. If You
+  institute patent litigation against any entity (including a
+  cross-claim or counterclaim in a lawsuit) alleging that the Work
+  or a Contribution incorporated within the Work constitutes direct
+  or contributory patent infringement, then any patent licenses
+  granted to You under this License for that Work shall terminate
+  as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+  Work or Derivative Works thereof in any medium, with or without
+  modifications, and in Source or Object form, provided that You
+  meet the following conditions:
+
+  (a) You must give any other recipients of the Work or
+      Derivative Works a copy of this License; and
+
+  (b) You must cause any modified files to carry prominent notices
+      stating that You changed the files; and
+
+  (c) You must retain, in the Source form of any Derivative Works
+      that You distribute, all copyright, patent, trademark, and
+      attribution notices from the Source form of the Work,
+      excluding those notices that do not pertain to any part of
+      the Derivative Works; and
+
+  (d) If the Work includes a "NOTICE" text file as part of its
+      distribution, then any Derivative Works that You distribute must
+      include a readable copy of the attribution notices contained
+      within such NOTICE file, excluding those notices that do not
+      pertain to any part of the Derivative Works, in at least one
+      of the following places: within a NOTICE text file distributed
+      as part of the Derivative Works; within the Source form or
+      documentation, if provided along with the Derivative Works; or,
+      within a display generated by the Derivative Works, if and
+      wherever such third-party notices normally appear. The contents
+      of the NOTICE file are for informational purposes only and
+      do not modify the License. You may add Your own attribution
+      notices within Derivative Works that You distribute, alongside
+      or as an addendum to the NOTICE text from the Work, provided
+      that such additional attribution notices cannot be construed
+      as modifying the License.
+
+  You may add Your own copyright statement to Your modifications and
+  may provide additional or different license terms and conditions
+  for use, reproduction, or distribution of Your modifications, or
+  for any such Derivative Works as a whole, provided Your use,
+  reproduction, and distribution of the Work otherwise complies with
+  the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+  any Contribution intentionally submitted for inclusion in the Work
+  by You to the Licensor shall be under the terms and conditions of
+  this License, without any additional terms or conditions.
+  Notwithstanding the above, nothing herein shall supersede or modify
+  the terms of any separate license agreement you may have executed
+  with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+  names, trademarks, service marks, or product names of the Licensor,
+  except as required for reasonable and customary use in describing the
+  origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+  agreed to in writing, Licensor provides the Work (and each
+  Contributor provides its Contributions) on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+  implied, including, without limitation, any warranties or conditions
+  of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+  PARTICULAR PURPOSE. You are solely responsible for determining the
+  appropriateness of using or redistributing the Work and assume any
+  risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+  whether in tort (including negligence), contract, or otherwise,
+  unless required by applicable law (such as deliberate and grossly
+  negligent acts) or agreed to in writing, shall any Contributor be
+  liable to You for damages, including any direct, indirect, special,
+  incidental, or consequential damages of any character arising as a
+  result of this License or out of the use or inability to use the
+  Work (including but not limited to damages for loss of goodwill,
+  work stoppage, computer failure or malfunction, or any and all
+  other commercial damages or losses), even if such Contributor
+  has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+  the Work or Derivative Works thereof, You may choose to offer,
+  and charge a fee for, acceptance of support, warranty, indemnity,
+  or other liability obligations and/or rights consistent with this
+  License. However, in accepting such obligations, You may act only
+  on Your own behalf and on Your sole responsibility, not on behalf
+  of any other Contributor, and only if You agree to indemnify,
+  defend, and hold each Contributor harmless for any liability
+  incurred by, or claims asserted against, such Contributor by reason
+  of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+  To apply the Apache License to your work, attach the following
+  boilerplate notice, with the fields enclosed by brackets "[]"
+  replaced with your own identifying information. (Don't include
+  the brackets!)  The text should be enclosed in the appropriate
+  comment syntax for the file format. We also recommend that a
+  file or class name and description of purpose be included on the
+  same "printed page" as the copyright notice for easier
+  identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/packages/subwallet-api-sdk/README.md b/packages/subwallet-api-sdk/README.md
new file mode 100644
index 00000000000..04a55e38dc6
--- /dev/null
+++ b/packages/subwallet-api-sdk/README.md
@@ -0,0 +1,2 @@
+# TODO
+Update content
diff --git a/packages/subwallet-api-sdk/package.json b/packages/subwallet-api-sdk/package.json
new file mode 100644
index 00000000000..618b4c7b5c1
--- /dev/null
+++ b/packages/subwallet-api-sdk/package.json
@@ -0,0 +1,26 @@
+{
+  "author": "S2kael<laiducminh1002@gmail.com>",
+  "bugs": "https://github.com/Koniverse/Subwallet-V2/issues",
+  "contributors": [],
+  "description": "Sdk for subwallet api",
+  "homepage": "https://github.com/Koniverse/Subwallet-V2/tree/master/packages/subwallet-api-sdk#readme",
+  "license": "Apache-2.0",
+  "maintainers": [],
+  "name": "@subwallet/subwallet-api-sdk",
+  "repository": {
+    "directory": "packages/subwallet-api-sdk",
+    "type": "git",
+    "url": "https://github.com/Koniverse/Subwallet-V2.git"
+  },
+  "sideEffects": [
+    "./detectPackage.js",
+    "./detectPackage.cjs"
+  ],
+  "type": "module",
+  "version": "1.3.12-1",
+  "main": "index.js",
+  "dependencies": {
+    "@polkadot/util": "^13.2.3",
+    "@subwallet/chain-list": "0.2.97"
+  }
+}
diff --git a/packages/subwallet-api-sdk/src/bundle.ts b/packages/subwallet-api-sdk/src/bundle.ts
new file mode 100644
index 00000000000..ab9b2abb372
--- /dev/null
+++ b/packages/subwallet-api-sdk/src/bundle.ts
@@ -0,0 +1,10 @@
+// Copyright 2019-2022 @polkadot/extension-base authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import { SubWalletApiSdk } from './sdk';
+
+export { packageInfo } from './packageInfo';
+
+export const subwalletApiSdk = SubWalletApiSdk.instance();
+
+export { SubWalletApiSdk } from './sdk';
diff --git a/packages/subwallet-api-sdk/src/cardano/index.ts b/packages/subwallet-api-sdk/src/cardano/index.ts
new file mode 100644
index 00000000000..df5cde1bb6b
--- /dev/null
+++ b/packages/subwallet-api-sdk/src/cardano/index.ts
@@ -0,0 +1,52 @@
+// Copyright 2017-2022 @subwallet/subwallet-api-sdk authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import { BuildCardanoTxParams, getFirstNumberAfterSubstring, POPULAR_CARDANO_ERROR_PHRASE, toUnit } from '@subwallet/subwallet-api-sdk/cardano/utils';
+import { SWApiResponse } from '@subwallet/subwallet-api-sdk/types';
+
+export async function fetchUnsignedPayload (baseUrl: string, params: BuildCardanoTxParams) {
+  const searchParams = new URLSearchParams({
+    sender: params.from,
+    receiver: params.to,
+    unit: params.cardanoId,
+    quantity: params.value
+  });
+
+  if (params.cardanoTtlOffset) {
+    searchParams.append('ttl', params.cardanoTtlOffset.toString());
+  }
+
+  try {
+    const rawResponse = await fetch(baseUrl + searchParams.toString(), {
+      method: 'GET',
+      headers: {
+        accept: 'application/json',
+        'Content-Type': 'application/json'
+      }
+    });
+
+    const response = await rawResponse.json() as SWApiResponse<string>;
+
+    if (response.error && response.status === 'error') {
+      throw new Error(response.error.message);
+    }
+
+    return response.data;
+  } catch (error) {
+    const errorMessage = (error as Error).message;
+
+    if (errorMessage.includes(POPULAR_CARDANO_ERROR_PHRASE.NOT_MATCH_MIN_AMOUNT)) {
+      const minAdaRequiredRaw = getFirstNumberAfterSubstring(errorMessage, POPULAR_CARDANO_ERROR_PHRASE.NOT_MATCH_MIN_AMOUNT);
+      const minAdaRequired = minAdaRequiredRaw ? toUnit(minAdaRequiredRaw, params.tokenDecimals) : 1;
+
+      throw new Error(`Amount too low. Increase your amount above ${minAdaRequired} ${params.nativeTokenSymbol} and try again`);
+    }
+
+    if (errorMessage.includes(POPULAR_CARDANO_ERROR_PHRASE.INSUFFICIENT_INPUT)) {
+      throw new Error(`Insufficient ${params.nativeTokenSymbol} balance to perform transaction. Top up ${params.nativeTokenSymbol} and try again`);
+    }
+
+    console.error(`Transaction is not built successfully: ${errorMessage}`);
+    throw new Error('Unable to perform this transaction at the moment. Try again later');
+  }
+}
diff --git a/packages/subwallet-api-sdk/src/cardano/utils.ts b/packages/subwallet-api-sdk/src/cardano/utils.ts
new file mode 100644
index 00000000000..9b73cef85c4
--- /dev/null
+++ b/packages/subwallet-api-sdk/src/cardano/utils.ts
@@ -0,0 +1,36 @@
+// Copyright 2017-2022 @subwallet/subwallet-api-sdk authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+export interface BuildCardanoTxParams {
+  tokenDecimals: number;
+  nativeTokenSymbol: string;
+  cardanoId: string;
+  from: string;
+  to: string;
+  value: string;
+  cardanoTtlOffset: number | null;
+}
+
+export enum POPULAR_CARDANO_ERROR_PHRASE {
+  NOT_MATCH_MIN_AMOUNT = 'less than the minimum UTXO value',
+  INSUFFICIENT_INPUT = 'Insufficient input in transaction'
+}
+
+export function getFirstNumberAfterSubstring (inputStr: string, subStr: string) {
+  const regex = new RegExp(`(${subStr})\\D*(\\d+)`);
+  const match = inputStr.match(regex);
+
+  if (match) {
+    return parseInt(match[2], 10);
+  } else {
+    return null;
+  }
+}
+
+export function toUnit (balance: number, decimals: number) {
+  if (balance === 0) {
+    return 0;
+  }
+
+  return balance / (10 ** decimals);
+}
diff --git a/packages/subwallet-api-sdk/src/detectOther.ts b/packages/subwallet-api-sdk/src/detectOther.ts
new file mode 100644
index 00000000000..8762793e3e6
--- /dev/null
+++ b/packages/subwallet-api-sdk/src/detectOther.ts
@@ -0,0 +1,6 @@
+// Copyright 2017-2022 @subwallet/subwallet-api-sdk authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+// Empty template, auto-generated by @polkadot/dev
+
+export default [];
diff --git a/packages/subwallet-api-sdk/src/detectPackage.ts b/packages/subwallet-api-sdk/src/detectPackage.ts
new file mode 100644
index 00000000000..b6a03e37700
--- /dev/null
+++ b/packages/subwallet-api-sdk/src/detectPackage.ts
@@ -0,0 +1,11 @@
+// Copyright 2017-2022 @subwallet/subwallet-api-sdk authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+// Do not edit, auto-generated by @polkadot/dev
+
+import { detectPackage } from '@polkadot/util';
+
+import others from './detectOther';
+import { packageInfo } from './packageInfo';
+
+detectPackage(packageInfo, null, others);
diff --git a/packages/subwallet-api-sdk/src/index.ts b/packages/subwallet-api-sdk/src/index.ts
new file mode 100644
index 00000000000..11267d9d469
--- /dev/null
+++ b/packages/subwallet-api-sdk/src/index.ts
@@ -0,0 +1,10 @@
+// Copyright 2017-2022 @subwallet/subwallet-api-sdk authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import './detectPackage';
+
+import { subwalletApiSdk } from './bundle';
+
+export * from './bundle';
+
+export default subwalletApiSdk;
diff --git a/packages/subwallet-api-sdk/src/packageInfo.ts b/packages/subwallet-api-sdk/src/packageInfo.ts
new file mode 100644
index 00000000000..2aefee8f9dc
--- /dev/null
+++ b/packages/subwallet-api-sdk/src/packageInfo.ts
@@ -0,0 +1,6 @@
+// Copyright 2017-2022 @subwallet/subwallet-api-sdk authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+// Do not edit, auto-generated by @polkadot/dev
+
+export const packageInfo = { name: '@subwallet/subwallet-api-sdk', path: 'auto', type: 'auto', version: '1.3.12-1' };
diff --git a/packages/subwallet-api-sdk/src/sdk.ts b/packages/subwallet-api-sdk/src/sdk.ts
new file mode 100644
index 00000000000..9a226fde45c
--- /dev/null
+++ b/packages/subwallet-api-sdk/src/sdk.ts
@@ -0,0 +1,31 @@
+// Copyright 2019-2022 @subwallet/extension-base authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+// TODO: NEED TO UPDATE THIS INTERFACE
+import { fetchUnsignedPayload } from '@subwallet/subwallet-api-sdk/cardano';
+import { BuildCardanoTxParams } from '@subwallet/subwallet-api-sdk/cardano/utils';
+
+export class SubWalletApiSdk {
+  private baseUrl = '';
+  private static _instance: SubWalletApiSdk | undefined = undefined;
+
+  public init (url: string) {
+    this.baseUrl = url;
+  }
+
+  async fetchUnsignedPayload (params: BuildCardanoTxParams): Promise<string> {
+    const url = `${this.baseUrl}/cardano/build-cardano-tx?`;
+
+    return fetchUnsignedPayload(url, params);
+  }
+
+  static instance () {
+    if (this._instance) {
+      return this._instance;
+    }
+
+    this._instance = new SubWalletApiSdk();
+
+    return this._instance;
+  }
+}
diff --git a/packages/subwallet-api-sdk/src/types.ts b/packages/subwallet-api-sdk/src/types.ts
new file mode 100644
index 00000000000..81516c82c6f
--- /dev/null
+++ b/packages/subwallet-api-sdk/src/types.ts
@@ -0,0 +1,13 @@
+// Copyright 2019-2022 @subwallet/extension-base authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+export type ApiStatusValue = 'error' | 'success' | 'fail';
+
+export interface SWApiResponse<T> {
+  status: ApiStatusValue,
+  data: T,
+  error?: {
+    message: string;
+    code: number;
+  }
+}
diff --git a/packages/subwallet-api-sdk/tsconfig.build.json b/packages/subwallet-api-sdk/tsconfig.build.json
new file mode 100644
index 00000000000..da24d9f2259
--- /dev/null
+++ b/packages/subwallet-api-sdk/tsconfig.build.json
@@ -0,0 +1,9 @@
+{
+  "extends": "../../tsconfig.base.json",
+  "compilerOptions": {
+    "baseUrl": "..",
+    "outDir": "./build",
+    "rootDir": "./src"
+  },
+  "references": []
+}
diff --git a/packages/subwallet-api-sdk/tsconfig.json b/packages/subwallet-api-sdk/tsconfig.json
new file mode 100644
index 00000000000..da24d9f2259
--- /dev/null
+++ b/packages/subwallet-api-sdk/tsconfig.json
@@ -0,0 +1,9 @@
+{
+  "extends": "../../tsconfig.base.json",
+  "compilerOptions": {
+    "baseUrl": "..",
+    "outDir": "./build",
+    "rootDir": "./src"
+  },
+  "references": []
+}
diff --git a/packages/web-runner/webpack.config.cjs b/packages/web-runner/webpack.config.cjs
index d30b27dd13f..3713ec042dd 100644
--- a/packages/web-runner/webpack.config.cjs
+++ b/packages/web-runner/webpack.config.cjs
@@ -43,7 +43,8 @@ const packages = [
   'extension-dapp',
   'extension-inject',
   'extension-koni',
-  'extension-koni-ui'
+  'extension-koni-ui',
+  'subwallet-api-sdk'
 ];
 
 const polkadotDevOptions = require('@polkadot/dev/config/babel-config-webpack.cjs');
@@ -63,7 +64,8 @@ const _additionalEnv = {
   BITTENSOR_API_KEY_8: JSON.stringify(process.env.BITTENSOR_API_KEY_8),
   BITTENSOR_API_KEY_9: JSON.stringify(process.env.BITTENSOR_API_KEY_9),
   BITTENSOR_API_KEY_10: JSON.stringify(process.env.BITTENSOR_API_KEY_10),
-  SIMPLE_SWAP_API_KEY: JSON.stringify(process.env.SIMPLE_SWAP_API_KEY)
+  SIMPLE_SWAP_API_KEY: JSON.stringify(process.env.SIMPLE_SWAP_API_KEY),
+  SUBWALLET_API: JSON.stringify(process.env.SUBWALLET_API)
 };
 
 // Overwrite babel babel config from polkadot dev
diff --git a/packages/webapp/webpack.config.cjs b/packages/webapp/webpack.config.cjs
index f402d5af366..4aa3aeed397 100644
--- a/packages/webapp/webpack.config.cjs
+++ b/packages/webapp/webpack.config.cjs
@@ -43,7 +43,8 @@ const packages = [
   'extension-dapp',
   'extension-inject',
   'extension-koni',
-  'extension-web-ui'
+  'extension-web-ui',
+  'subwallet-api-sdk'
 ];
 
 const polkadotDevOptions = require('@polkadot/dev/config/babel-config-webpack.cjs');
@@ -68,7 +69,8 @@ const _additionalEnv = {
   BITTENSOR_API_KEY_8: JSON.stringify(process.env.BITTENSOR_API_KEY_8),
   BITTENSOR_API_KEY_9: JSON.stringify(process.env.BITTENSOR_API_KEY_9),
   BITTENSOR_API_KEY_10: JSON.stringify(process.env.BITTENSOR_API_KEY_10),
-  SIMPLE_SWAP_API_KEY: JSON.stringify(process.env.SIMPLE_SWAP_API_KEY)
+  SIMPLE_SWAP_API_KEY: JSON.stringify(process.env.SIMPLE_SWAP_API_KEY),
+  SUBWALLET_API: JSON.stringify(process.env.SUBWALLET_API)
 };
 
 const createConfig = (entry, alias = {}, useSplitChunk = false) => {
diff --git a/tsconfig.base.json b/tsconfig.base.json
index db4b95306f1..94d22d65b27 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -22,7 +22,9 @@
         "@subwallet/web-runner": ["web-runner/src"],
         "@subwallet/web-runner/*": ["web-runner/src/*"],
         "@subwallet/webapp": ["webapp/src"],
-        "@subwallet/webapp/*": ["webapp/src/*"]
+        "@subwallet/webapp/*": ["webapp/src/*"],
+        "@subwallet/subwallet-api-sdk": ["subwallet-api-sdk/src"],
+        "@subwallet/subwallet-api-sdk/*": ["subwallet-api-sdk/src/*"]
     },
     "skipLibCheck": true
 	}
diff --git a/tsconfig.build.json b/tsconfig.build.json
index 5c08d3bbeb1..46f975c6812 100644
--- a/tsconfig.build.json
+++ b/tsconfig.build.json
@@ -12,6 +12,7 @@
     { "path": "./packages/extension-inject/tsconfig.build.json" },
     { "path": "./packages/extension-mocks/tsconfig.build.json" },
     { "path": "./packages/extension-koni-ui/tsconfig.build.json" },
+    { "path": "./packages/subwallet-api-sdk/tsconfig.build.json" },
 //    { "path": "./packages/extension-web-ui/tsconfig.build.json" },
 //    { "path": "./packages/web-runner/tsconfig.build.json" },
 //    { "path": "./packages/webapp/tsconfig.build.json" }
diff --git a/tsconfig.json b/tsconfig.json
index 020908b34ab..c88b445fb1e 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -13,6 +13,7 @@
     { "path": "./packages/extension-koni" },
     { "path": "./packages/extension-koni-ui" },
     { "path": "./packages/extension-web-ui" },
-    { "path": "./packages/web-runner" }
+    { "path": "./packages/web-runner" },
+    { "path": "./packages/subwallet-api-sdk" }
   ]
 }
diff --git a/yarn.lock b/yarn.lock
index 53252659373..1a3bdea4c9a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2125,6 +2125,20 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@emurgo/cardano-serialization-lib-browser@npm:^13.2.0":
+  version: 13.2.0
+  resolution: "@emurgo/cardano-serialization-lib-browser@npm:13.2.0"
+  checksum: 976f8081c7c1ff852463a47da0c8850300af380d0c032d004293c34b557195336a2707c39f24cd98b52de3b379cb770ee6f34107c7f85b3ddac125b2719b17e2
+  languageName: node
+  linkType: hard
+
+"@emurgo/cardano-serialization-lib-nodejs@npm:^13.2.0":
+  version: 13.2.0
+  resolution: "@emurgo/cardano-serialization-lib-nodejs@npm:13.2.0"
+  checksum: 547d41e27af3ec8d66f70d679741d18e38f976474c89566d7465151cd892b6a05170c95877206088c547164ad4ef4a7d00563fd29d5429d75ab49740a6605501
+  languageName: node
+  linkType: hard
+
 "@equilab/api@npm:~1.14.25":
   version: 1.14.25
   resolution: "@equilab/api@npm:1.14.25"
@@ -4510,90 +4524,90 @@ __metadata:
   linkType: hard
 
 "@polkadot/api-augment@npm:^15.0.1":
-  version: 15.0.1
-  resolution: "@polkadot/api-augment@npm:15.0.1"
-  dependencies:
-    "@polkadot/api-base": 15.0.1
-    "@polkadot/rpc-augment": 15.0.1
-    "@polkadot/types": 15.0.1
-    "@polkadot/types-augment": 15.0.1
-    "@polkadot/types-codec": 15.0.1
+  version: 15.0.2
+  resolution: "@polkadot/api-augment@npm:15.0.2"
+  dependencies:
+    "@polkadot/api-base": 15.0.2
+    "@polkadot/rpc-augment": 15.0.2
+    "@polkadot/types": 15.0.2
+    "@polkadot/types-augment": 15.0.2
+    "@polkadot/types-codec": 15.0.2
     "@polkadot/util": ^13.2.3
     tslib: ^2.8.0
-  checksum: 985919f2154f44516cedf6981a15cb993acb84c6a92f2305832d89b4e4174d3183823e280836db71c93e1072697f09e4d469e83ebdf04a567d48700a18acea86
+  checksum: 4262788399081eb37af7757836090cf3ed276871c0765c1cafe57fa6054597686d5959aef125982fb0fdb43e70c3959b29bfd0b5681480dab39dff0d16e5bb86
   languageName: node
   linkType: hard
 
 "@polkadot/api-base@npm:^15.0.1":
-  version: 15.0.1
-  resolution: "@polkadot/api-base@npm:15.0.1"
+  version: 15.0.2
+  resolution: "@polkadot/api-base@npm:15.0.2"
   dependencies:
-    "@polkadot/rpc-core": 15.0.1
-    "@polkadot/types": 15.0.1
+    "@polkadot/rpc-core": 15.0.2
+    "@polkadot/types": 15.0.2
     "@polkadot/util": ^13.2.3
     rxjs: ^7.8.1
     tslib: ^2.8.0
-  checksum: 0d37180b934c1049d1bb2caa7d9cd53bd1882612820664b65b73f43f0de4e85142a8dfe117558e9385924841ec4fc934b5152a5280e8c74834cf541008033286
+  checksum: f46c078e569e147fbcf65a2c055329f2ee3a066c64187f9f6b2fc0dd1b784fffedcd691bd28538f076cddaadd6950eaec4ff2531e382ec0ba020d52395264b3f
   languageName: node
   linkType: hard
 
 "@polkadot/api-contract@npm:^15.0.1":
-  version: 15.0.1
-  resolution: "@polkadot/api-contract@npm:15.0.1"
-  dependencies:
-    "@polkadot/api": 15.0.1
-    "@polkadot/api-augment": 15.0.1
-    "@polkadot/types": 15.0.1
-    "@polkadot/types-codec": 15.0.1
-    "@polkadot/types-create": 15.0.1
+  version: 15.0.2
+  resolution: "@polkadot/api-contract@npm:15.0.2"
+  dependencies:
+    "@polkadot/api": 15.0.2
+    "@polkadot/api-augment": 15.0.2
+    "@polkadot/types": 15.0.2
+    "@polkadot/types-codec": 15.0.2
+    "@polkadot/types-create": 15.0.2
     "@polkadot/util": ^13.2.3
     "@polkadot/util-crypto": ^13.2.3
     rxjs: ^7.8.1
     tslib: ^2.8.0
-  checksum: ca3ac606b54da89efb25523f532fe33304ad85f687e4ac3c685a74e213c19678e0d2b1444de460784d28d2821b39cfd7738a53bec116a8ad616f4375274ab4d3
+  checksum: 7c8a3cac56fc03fbc99604f221168659a516390d63f3ede40a8027e0159094f3a3a277c9d5e4dcdbcf21f31b815b71d51c097a028c84cce0248c7f3fb49b9394
   languageName: node
   linkType: hard
 
 "@polkadot/api-derive@npm:^15.0.1":
-  version: 15.0.1
-  resolution: "@polkadot/api-derive@npm:15.0.1"
-  dependencies:
-    "@polkadot/api": 15.0.1
-    "@polkadot/api-augment": 15.0.1
-    "@polkadot/api-base": 15.0.1
-    "@polkadot/rpc-core": 15.0.1
-    "@polkadot/types": 15.0.1
-    "@polkadot/types-codec": 15.0.1
+  version: 15.0.2
+  resolution: "@polkadot/api-derive@npm:15.0.2"
+  dependencies:
+    "@polkadot/api": 15.0.2
+    "@polkadot/api-augment": 15.0.2
+    "@polkadot/api-base": 15.0.2
+    "@polkadot/rpc-core": 15.0.2
+    "@polkadot/types": 15.0.2
+    "@polkadot/types-codec": 15.0.2
     "@polkadot/util": ^13.2.3
     "@polkadot/util-crypto": ^13.2.3
     rxjs: ^7.8.1
     tslib: ^2.8.0
-  checksum: adc1a74e5a6964d21f11c5fdfd5958d31126c2a5071acde17a1fe604885fd45230d62f1195131a40f9c5347e5101825a515b2baa7fecef12214b0fea792e273d
+  checksum: 23f8fb2f0efae0027a0c9891a46edefea209ed84f25e5145ad023130a20567e5e069d2c98bfb63a073c092683aae083aad614b8a947f5795b13b4c64f2ca8103
   languageName: node
   linkType: hard
 
 "@polkadot/api@npm:^15.0.1":
-  version: 15.0.1
-  resolution: "@polkadot/api@npm:15.0.1"
+  version: 15.0.2
+  resolution: "@polkadot/api@npm:15.0.2"
   dependencies:
-    "@polkadot/api-augment": 15.0.1
-    "@polkadot/api-base": 15.0.1
-    "@polkadot/api-derive": 15.0.1
+    "@polkadot/api-augment": 15.0.2
+    "@polkadot/api-base": 15.0.2
+    "@polkadot/api-derive": 15.0.2
     "@polkadot/keyring": ^13.2.3
-    "@polkadot/rpc-augment": 15.0.1
-    "@polkadot/rpc-core": 15.0.1
-    "@polkadot/rpc-provider": 15.0.1
-    "@polkadot/types": 15.0.1
-    "@polkadot/types-augment": 15.0.1
-    "@polkadot/types-codec": 15.0.1
-    "@polkadot/types-create": 15.0.1
-    "@polkadot/types-known": 15.0.1
+    "@polkadot/rpc-augment": 15.0.2
+    "@polkadot/rpc-core": 15.0.2
+    "@polkadot/rpc-provider": 15.0.2
+    "@polkadot/types": 15.0.2
+    "@polkadot/types-augment": 15.0.2
+    "@polkadot/types-codec": 15.0.2
+    "@polkadot/types-create": 15.0.2
+    "@polkadot/types-known": 15.0.2
     "@polkadot/util": ^13.2.3
     "@polkadot/util-crypto": ^13.2.3
     eventemitter3: ^5.0.1
     rxjs: ^7.8.1
     tslib: ^2.8.0
-  checksum: 0a717efee25f2080ecd8bd1eb79ab3459d0352b4c235aac077563ac74988fdbfdddff80e962e7787df9b4ebb7c3875d4db14540735a6f3cce5ca7f916c879c48
+  checksum: 844e488b2a34f928a72dffd5cb21228eed1fa86f801843a44762f446f781dc18f1920e13da7372d3080d7c619abb9c517aae3832ea98deab62d2139bee5cb169
   languageName: node
   linkType: hard
 
@@ -5032,39 +5046,39 @@ __metadata:
   linkType: hard
 
 "@polkadot/rpc-augment@npm:^15.0.1":
-  version: 15.0.1
-  resolution: "@polkadot/rpc-augment@npm:15.0.1"
+  version: 15.0.2
+  resolution: "@polkadot/rpc-augment@npm:15.0.2"
   dependencies:
-    "@polkadot/rpc-core": 15.0.1
-    "@polkadot/types": 15.0.1
-    "@polkadot/types-codec": 15.0.1
+    "@polkadot/rpc-core": 15.0.2
+    "@polkadot/types": 15.0.2
+    "@polkadot/types-codec": 15.0.2
     "@polkadot/util": ^13.2.3
     tslib: ^2.8.0
-  checksum: 544a0345513edd3f3bcc9132ab49bb8919215a6e5893786cf4e5875ee2ba7beff853c364b92738192d3a08b0e5a8dcc9927d125f71b53faaae75aed8f05a2507
+  checksum: a8c322a2e7ccb0fc3806e804c52f9e532d169f0c6ab17acc2b0434065cfc445eec9ee0dbe905a7b4685a7fae04c37df9d8436de5e3a3823970cf402a892f3c9f
   languageName: node
   linkType: hard
 
 "@polkadot/rpc-core@npm:^15.0.1":
-  version: 15.0.1
-  resolution: "@polkadot/rpc-core@npm:15.0.1"
+  version: 15.0.2
+  resolution: "@polkadot/rpc-core@npm:15.0.2"
   dependencies:
-    "@polkadot/rpc-augment": 15.0.1
-    "@polkadot/rpc-provider": 15.0.1
-    "@polkadot/types": 15.0.1
+    "@polkadot/rpc-augment": 15.0.2
+    "@polkadot/rpc-provider": 15.0.2
+    "@polkadot/types": 15.0.2
     "@polkadot/util": ^13.2.3
     rxjs: ^7.8.1
     tslib: ^2.8.0
-  checksum: eaed371caefa16c22cb36ee183de8f8bd063c50b7565259d76478d5c005b2cd9f919c6740430d7d110548c8cc8a31d02e18ef007dcd269d8d83202bb4b5de9d6
+  checksum: dc282499840d64ab7805ba151ca9d8c932119b8c1d793328dbab00139cc66b29c54e2a0fc135fb69f2319be8e3cc0699b4562c8f2a33c397f0583bf7bdee3bb2
   languageName: node
   linkType: hard
 
 "@polkadot/rpc-provider@npm:^15.0.1":
-  version: 15.0.1
-  resolution: "@polkadot/rpc-provider@npm:15.0.1"
+  version: 15.0.2
+  resolution: "@polkadot/rpc-provider@npm:15.0.2"
   dependencies:
     "@polkadot/keyring": ^13.2.3
-    "@polkadot/types": 15.0.1
-    "@polkadot/types-support": 15.0.1
+    "@polkadot/types": 15.0.2
+    "@polkadot/types-support": 15.0.2
     "@polkadot/util": ^13.2.3
     "@polkadot/util-crypto": ^13.2.3
     "@polkadot/x-fetch": ^13.2.3
@@ -5078,19 +5092,19 @@ __metadata:
   dependenciesMeta:
     "@substrate/connect":
       optional: true
-  checksum: 91fe12ac4f76ab29c6c85d8db3b9097593aa8510e65ecfd2bde62dd5f478b203240b6c6935257cab8fc717bba536b161e1f4050d8db05177d671af70be031715
+  checksum: 5c72d9370cf442d87c476703023e46aafff7414c74d9c01cb4f45c0e65a9a73d2a058c467163428fbc0280a3b7470eb312329fee79e17797e7e05839d65c8373
   languageName: node
   linkType: hard
 
-"@polkadot/types-augment@npm:15.0.1, @polkadot/types-augment@npm:^15.0.1":
-  version: 15.0.1
-  resolution: "@polkadot/types-augment@npm:15.0.1"
+"@polkadot/types-augment@npm:15.0.2, @polkadot/types-augment@npm:^15.0.1":
+  version: 15.0.2
+  resolution: "@polkadot/types-augment@npm:15.0.2"
   dependencies:
-    "@polkadot/types": 15.0.1
-    "@polkadot/types-codec": 15.0.1
+    "@polkadot/types": 15.0.2
+    "@polkadot/types-codec": 15.0.2
     "@polkadot/util": ^13.2.3
     tslib: ^2.8.0
-  checksum: e3b4da599bae7469466b8e6d917c0c470c9e48e23148e31264cdb36d1101c485094a6c5f19bcbb5f587836b4bc8efe79673966903895e6edb3e84cb488dcecd3
+  checksum: 0ecbe404963d0a2f2933a31d278a65ef30eccb0d3fe8df0f686edbd5af31a99f477347cdb192f45ec8e13acb2328a8c9703f15fb713d0af8985741c7bad46ba7
   languageName: node
   linkType: hard
 
@@ -5107,64 +5121,64 @@ __metadata:
   linkType: hard
 
 "@polkadot/types-codec@npm:^15.0.1":
-  version: 15.0.1
-  resolution: "@polkadot/types-codec@npm:15.0.1"
+  version: 15.0.2
+  resolution: "@polkadot/types-codec@npm:15.0.2"
   dependencies:
     "@polkadot/util": ^13.2.3
     "@polkadot/x-bigint": ^13.2.3
     tslib: ^2.8.0
-  checksum: 647e2822e4587241be2c2fe355d8ca2c324be0366e5f274e5a0530d5a74e63c92cc73d4babb778c2913f6f2b191851394c9c5e7005e3eaaa41a52981b3b325e7
+  checksum: 835be95b20bb51913050807becaffa1ab772c6659eb9f57d506aaf63a5cde93f202876a5b5c078fd6978dcfb0a5b9461298b8826e47d0f0ee96f8180ca18c19a
   languageName: node
   linkType: hard
 
-"@polkadot/types-create@npm:15.0.1":
-  version: 15.0.1
-  resolution: "@polkadot/types-create@npm:15.0.1"
+"@polkadot/types-create@npm:15.0.2":
+  version: 15.0.2
+  resolution: "@polkadot/types-create@npm:15.0.2"
   dependencies:
-    "@polkadot/types-codec": 15.0.1
+    "@polkadot/types-codec": 15.0.2
     "@polkadot/util": ^13.2.3
     tslib: ^2.8.0
-  checksum: 20abe0c198400d664a9cb182932054177ba655935955fa50f4a3035c3637d2f24987d5d3fe33f79b72c8bc765413cfaec77190e840d65652b047922ca35d6148
+  checksum: 3972b5d919ffade3b85fc7c7fb79fc90d30151ed7af078a54f218137c8db8799e576cf9b2fc74db97f9a4c28d6e60483be446a2a9b42c0b7e61331efb3615869
   languageName: node
   linkType: hard
 
 "@polkadot/types-known@npm:^15.0.1":
-  version: 15.0.1
-  resolution: "@polkadot/types-known@npm:15.0.1"
+  version: 15.0.2
+  resolution: "@polkadot/types-known@npm:15.0.2"
   dependencies:
     "@polkadot/networks": ^13.2.3
-    "@polkadot/types": 15.0.1
-    "@polkadot/types-codec": 15.0.1
-    "@polkadot/types-create": 15.0.1
+    "@polkadot/types": 15.0.2
+    "@polkadot/types-codec": 15.0.2
+    "@polkadot/types-create": 15.0.2
     "@polkadot/util": ^13.2.3
     tslib: ^2.8.0
-  checksum: 137f76c37dac52ef6e45167074198683ef7d44a72fee0bafc51b902977ac72b5aac880d71915948eaee0ac6bbd629897d45dfbcd9333684cf70858ba35b03977
+  checksum: bbf684baed7f00308e808f4c32ee894d59407cdf947532bb6e1e5e4763b1451d5a684fa76c86c6392721f80b0509987a39664d5ca9b52a9177a35cd4924758fe
   languageName: node
   linkType: hard
 
 "@polkadot/types-support@npm:^15.0.1":
-  version: 15.0.1
-  resolution: "@polkadot/types-support@npm:15.0.1"
+  version: 15.0.2
+  resolution: "@polkadot/types-support@npm:15.0.2"
   dependencies:
     "@polkadot/util": ^13.2.3
     tslib: ^2.8.0
-  checksum: 810d827395982f3b80bcdf01e8b85cbb0808812001c088aa41b8cbf031b2dbb620243c21b6b0e1204273dad022355607257095d0c60763acbe5562a7d6049f37
+  checksum: bad355ee97ce1b8194832b78da7a2bf5c199c4d8eb810a52fcdab1e71b0188c7737f716df9705891f363c029abb8cc9f1c83e8e7b11409a959be03c007274ec9
   languageName: node
   linkType: hard
 
 "@polkadot/types@npm:^15.0.1":
-  version: 15.0.1
-  resolution: "@polkadot/types@npm:15.0.1"
+  version: 15.0.2
+  resolution: "@polkadot/types@npm:15.0.2"
   dependencies:
     "@polkadot/keyring": ^13.2.3
-    "@polkadot/types-augment": 15.0.1
-    "@polkadot/types-codec": 15.0.1
-    "@polkadot/types-create": 15.0.1
+    "@polkadot/types-augment": 15.0.2
+    "@polkadot/types-codec": 15.0.2
+    "@polkadot/types-create": 15.0.2
     "@polkadot/util": ^13.2.3
     "@polkadot/util-crypto": ^13.2.3
     rxjs: ^7.8.1
     tslib: ^2.8.0
-  checksum: 4bf7aa67919df55a2726a163e6640cd12b7e7008f7644cfd4cf53ca30920070bc2782abcb66d8fd6873c64666f03876e3606176260500a3079035d2268c9b493
+  checksum: 6daf5cc97683945055cca1ba33fd4c590c31219de961eb34eff22cf3feea7b809b59766fcc7b9edf6ae8bfc04b6c8bc286c9e496adc650dc6361fb29d03f85f0
   languageName: node
   linkType: hard
 
@@ -6368,9 +6382,9 @@ __metadata:
   linkType: hard
 
 "@substrate/connect-known-chains@npm:^1.1.5":
-  version: 1.8.0
-  resolution: "@substrate/connect-known-chains@npm:1.8.0"
-  checksum: ccf536ca2fb6bdfc9f3a85ff0036eebc403ef743f8fbf6290a25439184375e4e90f9ce20ed414fc9c5231b22cfa3382b135bd865ab61cc3d1378959bef0c9ee4
+  version: 1.8.1
+  resolution: "@substrate/connect-known-chains@npm:1.8.1"
+  checksum: 35ed5ed36c38cc66e3ef48d942c42cf1686e369fa6c21faef2bb318514fa1596c30900d0963498ba7a3bb992b87a80f333b8bbfef14915d0c98edac807125010
   languageName: node
   linkType: hard
 
@@ -6439,15 +6453,14 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@subwallet/chain-list@npm:0.2.98":
-  version: 0.2.98
-  resolution: "@subwallet/chain-list@npm:0.2.98"
+"@subwallet/chain-list@file:../SubWallet-Chainlist/packages/chain-list/build/::locator=root-workspace-0b6124%40workspace%3A.":
+  version: 0.2.91
+  resolution: "@subwallet/chain-list@file:../SubWallet-Chainlist/packages/chain-list/build/#../SubWallet-Chainlist/packages/chain-list/build/::hash=4282d2&locator=root-workspace-0b6124%40workspace%3A."
   dependencies:
     "@polkadot/dev": 0.67.167
     "@polkadot/util": ^12.5.1
     eventemitter3: ^5.0.1
-    ts-md5: ^1.3.1
-  checksum: bf03699ae2f5eb97f49ebbdb92416095230e38b104a0c945884c4f05447adf728c722b57dd145805231433468faa471bd5d6d8b71e7c6fc307a32724897edb71
+  checksum: 09f75a4d785258efce275f7bba01f6b3aa48a7550458354527daa7d3e64d59250b2f07189adfa77dda8e62ab9dbcaf4a204e0027a942414e855a6659cbb3b3ca
   languageName: node
   linkType: hard
 
@@ -6459,6 +6472,7 @@ __metadata:
     "@apollo/client": ^3.7.14
     "@azns/resolver-core": ^1.4.0
     "@chainflip/sdk": ^1.6.0
+    "@emurgo/cardano-serialization-lib-nodejs": ^13.2.0
     "@equilab/api": ~1.14.25
     "@ethereumjs/common": ^4.1.0
     "@ethereumjs/tx": ^5.1.0
@@ -6497,6 +6511,7 @@ __metadata:
     "@subwallet/extension-inject": ^1.3.15-0
     "@subwallet/extension-mocks": ^1.3.15-0
     "@subwallet/keyring": ^0.1.8-beta.0
+    "@subwallet/subwallet-api-sdk": ^1.3.12-1
     "@subwallet/ui-keyring": ^0.1.8-beta.0
     "@ton/core": ^0.56.3
     "@ton/crypto": ^3.2.0
@@ -6706,6 +6721,7 @@ __metadata:
   resolution: "@subwallet/extension-koni@workspace:packages/extension-koni"
   dependencies:
     "@babel/runtime": ^7.20.6
+    "@emurgo/cardano-serialization-lib-browser": ^13.2.0
     "@polkadot/dev": ^0.65.23
     "@subwallet/extension-base": ^1.3.15-0
     "@subwallet/extension-inject": ^1.3.15-0
@@ -6840,10 +6856,11 @@ __metadata:
   languageName: unknown
   linkType: soft
 
-"@subwallet/keyring@npm:^0.1.8-beta.0":
-  version: 0.1.8-beta.0
-  resolution: "@subwallet/keyring@npm:0.1.8-beta.0"
+"@subwallet/keyring@file:../SubWallet-Base/packages/keyring/build/::locator=root-workspace-0b6124%40workspace%3A.":
+  version: 0.1.7
+  resolution: "@subwallet/keyring@file:../SubWallet-Base/packages/keyring/build/#../SubWallet-Base/packages/keyring/build/::hash=92482e&locator=root-workspace-0b6124%40workspace%3A."
   dependencies:
+    "@emurgo/cardano-serialization-lib-nodejs": ^13.2.0
     "@ethereumjs/tx": ^5.0.0
     "@metamask/eth-sig-util": ^7.0.3
     "@metamask/eth-simple-keyring": ^6.0.1
@@ -6862,7 +6879,7 @@ __metadata:
     rxjs: ^7.5.6
     tiny-secp256k1: ^2.2.3
     tslib: ^2.6.2
-  checksum: f29e78fd71ddf09c8e531b682f93b49305580ab2c266d781558322d6af5d0bfae8d80ae21e0c35d7a25711a270991e290cbe49d891b6b47388bb566aa5befb06
+  checksum: 1f49ff91a60e4ee0f8e72a2f8f3d0a3083098ba9aa2d5f0d8b185f74367add12864c1fdfe2666aa87f420642cfa5c36254c561f319b1d91009f8e8129fb7ce13
   languageName: node
   linkType: hard
 
@@ -6944,19 +6961,28 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@subwallet/ui-keyring@npm:0.1.8-beta.0":
-  version: 0.1.8-beta.0
-  resolution: "@subwallet/ui-keyring@npm:0.1.8-beta.0"
+"@subwallet/subwallet-api-sdk@^1.3.12-1, @subwallet/subwallet-api-sdk@workspace:packages/subwallet-api-sdk":
+  version: 0.0.0-use.local
+  resolution: "@subwallet/subwallet-api-sdk@workspace:packages/subwallet-api-sdk"
+  dependencies:
+    "@polkadot/util": ^13.2.3
+    "@subwallet/chain-list": 0.2.97
+  languageName: unknown
+  linkType: soft
+
+"@subwallet/ui-keyring@file:../SubWallet-Base/packages/ui-keyring/build/::locator=root-workspace-0b6124%40workspace%3A.":
+  version: 0.1.7
+  resolution: "@subwallet/ui-keyring@file:../SubWallet-Base/packages/ui-keyring/build/#../SubWallet-Base/packages/ui-keyring/build/::hash=a1c075&locator=root-workspace-0b6124%40workspace%3A."
   dependencies:
     "@babel/runtime": ^7.20.1
     "@polkadot/ui-settings": 2.9.14
     "@polkadot/util": ^12.2.1
     "@polkadot/util-crypto": ^12.2.1
-    "@subwallet/keyring": ^0.1.8-beta.0
+    "@subwallet/keyring": ^0.1.7
     mkdirp: ^1.0.4
     rxjs: ^7.5.7
     store: ^2.0.12
-  checksum: 6ebb69675403eb36300b0aea895364852bff24f05a69ab69f5b7a6734c3f4a2c27ca5a9b5f3d5c1b2a2e970bf17a22a0b8985d90f1d237871f3132425cd6ef70
+  checksum: 590f3230b812b5405b5094da4565e798edfe670efb3839e41670d83ba51e372788dbc523e5365764625ef418b7be6e88ba6a949023e3b7023c7931afea52d946
   languageName: node
   linkType: hard
 
@@ -7056,10 +7082,10 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@thi.ng/api@npm:^8.11.13":
-  version: 8.11.13
-  resolution: "@thi.ng/api@npm:8.11.13"
-  checksum: dc29cd79d8158cdda6766fee2d7fbb34661acc1dfac709f30a58fb062562cbf929cbe3a6ca6f4856a121594acdd7b5292981595bee71cc4dd0fd99e35aa0c1ef
+"@thi.ng/api@npm:^8.11.14":
+  version: 8.11.14
+  resolution: "@thi.ng/api@npm:8.11.14"
+  checksum: 052da7c146c826c2112b236d478a285d1c9da0fb061dac372826232dbbab0541f23a97f1a4410f79e6428a10c56bfce00307481b52a3793e304cb165dd8d3952
   languageName: node
   linkType: hard
 
@@ -7169,11 +7195,11 @@ __metadata:
   linkType: hard
 
 "@thi.ng/memoize@npm:^4.0.2":
-  version: 4.0.3
-  resolution: "@thi.ng/memoize@npm:4.0.3"
+  version: 4.0.4
+  resolution: "@thi.ng/memoize@npm:4.0.4"
   dependencies:
-    "@thi.ng/api": ^8.11.13
-  checksum: ddc13c6a6ed3af467079fca5ad338dc469153228b6b41c302927d2ac38eb68340a1c925b688bb5b75c13fa0df370936b8a57b2cdbe5ed3900e6faf6e4c944e88
+    "@thi.ng/api": ^8.11.14
+  checksum: d3aeb17624f972cdc69a0ede55aef2427e61387b4df8c493c3ae54fa84711a7ac3676bba28fcef1c6b716272ca8b18018653bd6491fa01fb50488387bd57e8d4
   languageName: node
   linkType: hard