diff --git a/apps/extension/src/Approvals/Approvals.tsx b/apps/extension/src/Approvals/Approvals.tsx index 9a839dd2b..74a6359fa 100644 --- a/apps/extension/src/Approvals/Approvals.tsx +++ b/apps/extension/src/Approvals/Approvals.tsx @@ -10,6 +10,7 @@ import { ApproveConnection } from "./ApproveConnection"; import { ApproveDisconnection } from "./ApproveDisconnection"; import { ApproveSignArbitrary } from "./ApproveSignArbitrary"; import { ApproveSignTx } from "./ApproveSignTx"; +import { ApproveUpdateDefaultAccount } from "./ApproveUpdateDefaultAccount"; import { ConfirmSignature } from "./ConfirmSignArbitrary"; import { ConfirmSignLedgerTx } from "./ConfirmSignLedgerTx"; import { ConfirmSignTx } from "./ConfirmSignTx"; @@ -70,6 +71,10 @@ export const Approvals: React.FC = () => { path={TopLevelRoute.ApproveDisconnection} element={} /> + } + /> { + const requester = useRequester(); + const params = useQuery(); + const address = params.get("address"); + const alias = params.get("alias"); + + const handleResponse = async (approved: boolean): Promise => { + if (address && approved) { + await requester.sendMessage( + Ports.Background, + new SubmitUpdateDefaultAccountMsg(address) + ); + } + await closeCurrentTab(); + }; + + return ( + + + +
+ Approve update default account? +
+
+ +
+
+
{alias}
+

+ {address && shortenAddress(address, 24)} +

+
+
+
+ + handleResponse(true)}> + Approve + + handleResponse(false)} + > + Reject + + +
+
+ ); +}; diff --git a/apps/extension/src/Approvals/types.ts b/apps/extension/src/Approvals/types.ts index 5b4380cfb..9ba99e128 100644 --- a/apps/extension/src/Approvals/types.ts +++ b/apps/extension/src/Approvals/types.ts @@ -7,6 +7,9 @@ export enum TopLevelRoute { ApproveConnection = "/approve-connection", ApproveDisconnection = "/approve-disconnection", + // Update default account approval + ApproveUpdateDefaultAccount = "/approve-update-default-account", + // Sign Tx approval ApproveSignTx = "/approve-sign-tx", ApproveSignTxDetails = "/approve-sign-tx-details", diff --git a/apps/extension/src/background/approvals/handler.ts b/apps/extension/src/background/approvals/handler.ts index f81f8b27b..f2e253eae 100644 --- a/apps/extension/src/background/approvals/handler.ts +++ b/apps/extension/src/background/approvals/handler.ts @@ -3,6 +3,7 @@ import { ApproveDisconnectInterfaceMsg, ApproveSignArbitraryMsg, ApproveSignTxMsg, + ApproveUpdateDefaultAccountMsg, IsConnectionApprovedMsg, } from "provider"; import { Env, Handler, InternalHandler, Message } from "router"; @@ -18,6 +19,7 @@ import { SubmitApprovedSignArbitraryMsg, SubmitApprovedSignLedgerTxMsg, SubmitApprovedSignTxMsg, + SubmitUpdateDefaultAccountMsg, } from "./messages"; import { ApprovalsService } from "./service"; @@ -54,6 +56,16 @@ export const getHandler: (service: ApprovalsService) => Handler = (service) => { env, msg as RevokeConnectionMsg ); + case ApproveUpdateDefaultAccountMsg: + return handleApproveUpdateDefaultAccountMsg(service)( + env, + msg as ApproveUpdateDefaultAccountMsg + ); + case SubmitUpdateDefaultAccountMsg: + return handleSubmitUpdateDefaultAccountMsg(service)( + env, + msg as SubmitUpdateDefaultAccountMsg + ); case ApproveSignTxMsg: return handleApproveSignTxMsg(service)(env, msg as ApproveSignTxMsg); case RejectSignTxMsg: @@ -164,6 +176,22 @@ const handleRevokeConnectionMsg: ( }; }; +const handleApproveUpdateDefaultAccountMsg: ( + service: ApprovalsService +) => InternalHandler = (service) => { + return async (_, { address }) => { + return await service.approveUpdateDefaultAccount(address); + }; +}; + +const handleSubmitUpdateDefaultAccountMsg: ( + service: ApprovalsService +) => InternalHandler = (service) => { + return async ({ senderTabId: popupTabId }, { address }) => { + return await service.submitUpdateDefaultAccount(popupTabId, address); + }; +}; + const handleApproveSignTxMsg: ( service: ApprovalsService ) => InternalHandler = (service) => { diff --git a/apps/extension/src/background/approvals/init.ts b/apps/extension/src/background/approvals/init.ts index f9065dca4..1341aecd0 100644 --- a/apps/extension/src/background/approvals/init.ts +++ b/apps/extension/src/background/approvals/init.ts @@ -3,6 +3,7 @@ import { ApproveDisconnectInterfaceMsg, ApproveSignArbitraryMsg, ApproveSignTxMsg, + ApproveUpdateDefaultAccountMsg, IsConnectionApprovedMsg, } from "provider"; import { Router } from "router"; @@ -18,6 +19,7 @@ import { SubmitApprovedSignArbitraryMsg, SubmitApprovedSignLedgerTxMsg, SubmitApprovedSignTxMsg, + SubmitUpdateDefaultAccountMsg, } from "./messages"; import { ROUTE } from "./constants"; @@ -38,6 +40,8 @@ export function init(router: Router, service: ApprovalsService): void { router.registerMessage(ApproveDisconnectInterfaceMsg); router.registerMessage(DisconnectInterfaceResponseMsg); router.registerMessage(RevokeConnectionMsg); + router.registerMessage(ApproveUpdateDefaultAccountMsg); + router.registerMessage(SubmitUpdateDefaultAccountMsg); router.registerMessage(QueryTxDetailsMsg); router.registerMessage(QuerySignArbitraryDataMsg); router.registerMessage(QueryPendingTxBytesMsg); diff --git a/apps/extension/src/background/approvals/messages.ts b/apps/extension/src/background/approvals/messages.ts index d4b8057e3..9fad70aad 100644 --- a/apps/extension/src/background/approvals/messages.ts +++ b/apps/extension/src/background/approvals/messages.ts @@ -14,6 +14,7 @@ export enum MessageType { ConnectInterfaceResponse = "connect-interface-response", DisconnectInterfaceResponse = "disconnect-interface-response", RevokeConnection = "revoke-connection", + SubmitUpdateDefaultAccount = "submit-update-default-account", QueryTxDetails = "query-tx-details", QuerySignArbitraryData = "query-sign-arbitrary-data", QueryPendingTxBytes = "query-pending-tx-bytes", @@ -211,6 +212,28 @@ export class RevokeConnectionMsg extends Message { } } +export class SubmitUpdateDefaultAccountMsg extends Message { + public static type(): MessageType { + return MessageType.SubmitUpdateDefaultAccount; + } + + constructor(public readonly address: string) { + super(); + } + + validate(): void { + validateProps(this, ["address"]); + } + + route(): string { + return ROUTE; + } + + type(): string { + return SubmitUpdateDefaultAccountMsg.type(); + } +} + export class QueryTxDetailsMsg extends Message { public static type(): MessageType { return MessageType.QueryTxDetails; diff --git a/apps/extension/src/background/approvals/service.ts b/apps/extension/src/background/approvals/service.ts index ca167473d..338e70a14 100644 --- a/apps/extension/src/background/approvals/service.ts +++ b/apps/extension/src/background/approvals/service.ts @@ -39,7 +39,12 @@ export class ApprovalsService { protected readonly broadcaster: ExtensionBroadcaster ) { browser.tabs.onRemoved.addListener((tabId) => { - const resolver = this.getResolver(tabId); + let resolver: Resolver | undefined; + try { + resolver = this.getResolver(tabId); + } catch { + // do nothing if not found as it was resolved by the event handler + } if (resolver) { resolver.reject(new Error("Window closed")); this.removeResolver(tabId); @@ -255,6 +260,29 @@ export class ApprovalsService { await this.broadcaster.revokeConnection(); } + async approveUpdateDefaultAccount(address: string): Promise { + const account = await this.keyRingService.queryAccountDetails(address); + + return this.launchApprovalPopup(TopLevelRoute.ApproveUpdateDefaultAccount, { + address, + alias: account?.alias ?? "", + }); + } + + async submitUpdateDefaultAccount( + popupTabId: number, + address: string + ): Promise { + const resolvers = this.getResolver(popupTabId); + + try { + await this.keyRingService.updateDefaultAccount(address); + } catch (e) { + resolvers.reject(e); + } + resolvers.resolve(); + } + async queryTxDetails(msgId: string): Promise { const pendingTx = await this.txStore.get(msgId); diff --git a/apps/extension/src/background/keyring/handler.ts b/apps/extension/src/background/keyring/handler.ts index b8f95b1d2..a39b6fd21 100644 --- a/apps/extension/src/background/keyring/handler.ts +++ b/apps/extension/src/background/keyring/handler.ts @@ -2,7 +2,6 @@ import { CheckDurabilityMsg, QueryAccountsMsg, QueryDefaultAccountMsg, - UpdateDefaultAccountMsg, VerifyArbitraryMsg, } from "provider/messages"; import { Env, Handler, InternalHandler, Message } from "router"; @@ -64,11 +63,6 @@ export const getHandler: (service: KeyRingService) => Handler = (service) => { env, msg as QueryDefaultAccountMsg ); - case UpdateDefaultAccountMsg: - return handleUpdateDefaultAccountMsg(service)( - env, - msg as UpdateDefaultAccountMsg - ); case QueryParentAccountsMsg: return handleQueryParentAccountsMsg(service)( env, @@ -187,15 +181,6 @@ const handleQueryDefaultAccountMsg: ( }; }; -const handleUpdateDefaultAccountMsg: ( - service: KeyRingService -) => InternalHandler = (service) => { - return async (_, msg) => { - const { address } = msg; - return await service.updateDefaultAccount(address); - }; -}; - const handleQueryParentAccountsMsg: ( service: KeyRingService ) => InternalHandler = (service) => { diff --git a/apps/extension/src/background/keyring/init.ts b/apps/extension/src/background/keyring/init.ts index 0ccf914e2..75c363238 100644 --- a/apps/extension/src/background/keyring/init.ts +++ b/apps/extension/src/background/keyring/init.ts @@ -2,7 +2,6 @@ import { CheckDurabilityMsg, QueryAccountsMsg, QueryDefaultAccountMsg, - UpdateDefaultAccountMsg, VerifyArbitraryMsg, } from "provider/messages"; import { Router } from "router"; @@ -30,7 +29,6 @@ export function init(router: Router, service: KeyRingService): void { router.registerMessage(GetActiveAccountMsg); router.registerMessage(QueryAccountsMsg); router.registerMessage(QueryDefaultAccountMsg); - router.registerMessage(UpdateDefaultAccountMsg); router.registerMessage(QueryParentAccountsMsg); router.registerMessage(QueryAccountDetailsMsg); router.registerMessage(SaveAccountSecretMsg); diff --git a/apps/extension/src/background/keyring/keyring.ts b/apps/extension/src/background/keyring/keyring.ts index cdfe5419f..119733106 100644 --- a/apps/extension/src/background/keyring/keyring.ts +++ b/apps/extension/src/background/keyring/keyring.ts @@ -409,8 +409,7 @@ export class KeyRing { } public async updateDefaultAccount(address: string): Promise { - const accounts = await this.queryAllAccounts(); - const account = accounts.find((acc) => acc.address === address); + const account = await this.queryAccountDetails(address); if (!account) { throw new Error(`Account with address ${address} not found.`); } diff --git a/apps/extension/src/provider/Namada.ts b/apps/extension/src/provider/Namada.ts index 6735fa520..8f31f095b 100644 --- a/apps/extension/src/provider/Namada.ts +++ b/apps/extension/src/provider/Namada.ts @@ -15,12 +15,12 @@ import { ApproveDisconnectInterfaceMsg, ApproveSignArbitraryMsg, ApproveSignTxMsg, + ApproveUpdateDefaultAccountMsg, CheckDurabilityMsg, GetChainMsg, IsConnectionApprovedMsg, QueryAccountsMsg, QueryDefaultAccountMsg, - UpdateDefaultAccountMsg, VerifyArbitraryMsg, } from "./messages"; @@ -72,7 +72,7 @@ export class Namada implements INamada { public async updateDefaultAccount(address: string): Promise { return await this.requester?.sendMessage( Ports.Background, - new UpdateDefaultAccountMsg(address) + new ApproveUpdateDefaultAccountMsg(address) ); } diff --git a/apps/extension/src/provider/messages.ts b/apps/extension/src/provider/messages.ts index d53f3f7ee..0a157cf6f 100644 --- a/apps/extension/src/provider/messages.ts +++ b/apps/extension/src/provider/messages.ts @@ -23,7 +23,7 @@ enum MessageType { ApproveDisconnectInterface = "approve-disconnect-interface", QueryAccounts = "query-accounts", QueryDefaultAccount = "query-default-account", - UpdateDefaultAccount = "update-default-account", + ApproveUpdateDefaultAccount = "approve-update-default-account", EncodeRevealPublicKey = "encode-reveal-public-key", GetChain = "get-chain", GetChains = "get-chains", @@ -231,9 +231,9 @@ export class QueryDefaultAccountMsg extends Message< } } -export class UpdateDefaultAccountMsg extends Message { +export class ApproveUpdateDefaultAccountMsg extends Message { public static type(): MessageType { - return MessageType.UpdateDefaultAccount; + return MessageType.ApproveUpdateDefaultAccount; } constructor(public readonly address: string) { @@ -245,11 +245,11 @@ export class UpdateDefaultAccountMsg extends Message { } route(): string { - return Route.KeyRing; + return Route.Approvals; } type(): string { - return UpdateDefaultAccountMsg.type(); + return ApproveUpdateDefaultAccountMsg.type(); } } diff --git a/apps/namadillo/src/App/SwitchAccount/SwitchAccountPanel.tsx b/apps/namadillo/src/App/SwitchAccount/SwitchAccountPanel.tsx index 9e230817a..62107c24b 100644 --- a/apps/namadillo/src/App/SwitchAccount/SwitchAccountPanel.tsx +++ b/apps/namadillo/src/App/SwitchAccount/SwitchAccountPanel.tsx @@ -29,7 +29,7 @@ export const SwitchAccountPanel = (): JSX.Element => {
@@ -51,18 +51,23 @@ export const SwitchAccountPanel = (): JSX.Element => { className={twMerge( "flex gap-2 w-full py-1", "whitespace-nowrap text-left", - "cursor-pointer hover:text-yellow transition-colors" + "cursor-pointer hover:text-yellow transition-colors", + address === defaultAccount?.address && "text-yellow" )} onClick={async () => { updateAccount(address); onCloseModal(); }} > - - {alias} + + + + + {alias} + ))}