From 6ade8684ad94b01e3147fcf2104581021a29a08d Mon Sep 17 00:00:00 2001 From: Paul Chen Date: Fri, 28 Mar 2025 14:53:03 +0800 Subject: [PATCH 1/7] feat: implement sign message --- lib/wallet/account/hot-wallet-account.ts | 5 +++++ lib/wallet/account/hot-wallet-private-key.ts | 5 +++++ lib/wallet/account/ledger-account.ts | 11 +++++++++++ lib/wallet/wallet-interface.ts | 2 ++ 4 files changed, 23 insertions(+) diff --git a/lib/wallet/account/hot-wallet-account.ts b/lib/wallet/account/hot-wallet-account.ts index a2cb839f..ad7ae251 100644 --- a/lib/wallet/account/hot-wallet-account.ts +++ b/lib/wallet/account/hot-wallet-account.ts @@ -15,6 +15,7 @@ import { Transaction, UtxoEntryReference, XPrv, + signMessage, } from "@/wasm/core/kaspa"; import { @@ -211,6 +212,10 @@ export class HotWalletAccount implements IWallet { return this.getPrivateKey().toPublicKey(); } + signMessage(message: string): string { + return signMessage({ message, privateKey: this.getPrivateKey() }); + } + private async commitScript(p2SHAddress: string) { const publicKey = this.getPublicKey(); const address = publicKey.toAddress(this.networkId); diff --git a/lib/wallet/account/hot-wallet-private-key.ts b/lib/wallet/account/hot-wallet-private-key.ts index 657fd116..09d80e30 100644 --- a/lib/wallet/account/hot-wallet-private-key.ts +++ b/lib/wallet/account/hot-wallet-private-key.ts @@ -14,6 +14,7 @@ import { signTransaction, Transaction, UtxoEntryReference, + signMessage, } from "@/wasm/core/kaspa"; import { @@ -188,6 +189,10 @@ export class HotWalletPrivateKey implements IWallet { scriptBuilder.encodePayToScriptHashSignatureScript(signature); } + signMessage(message: string): string { + return signMessage({ message, privateKey: this.privateKey }); + } + private async commitScript(p2SHAddress: string) { const publicKey = this.getPublicKey(); const address = publicKey.toAddress(this.networkId); diff --git a/lib/wallet/account/ledger-account.ts b/lib/wallet/account/ledger-account.ts index 9db43c69..63bf172d 100644 --- a/lib/wallet/account/ledger-account.ts +++ b/lib/wallet/account/ledger-account.ts @@ -198,6 +198,17 @@ export class LedgerAccount implements IWallet { return this.toRpcTransaction(ledgerTx); } + async signMessage(message: string): Promise { + return ( + await this.app.signMessage( + message, + 0, + 0, + this.accountIndex + LEDGER_ACCOUNT_INDEX_OFFSET, + ) + ).signature; + } + private async getUtxos(): Promise { const address = await this.getAddress(); return ( diff --git a/lib/wallet/wallet-interface.ts b/lib/wallet/wallet-interface.ts index c0e71231..ffd10d87 100644 --- a/lib/wallet/wallet-interface.ts +++ b/lib/wallet/wallet-interface.ts @@ -46,6 +46,8 @@ export interface IWallet { signTx(tx: Transaction, scripts?: ScriptOption[]): Promise; + signMessage(message: string): string | Promise; + performCommitReveal( scriptBuilder: ScriptBuilder, revealPriorityFee: string, // KAS From c3060f88e6d98fbf2fb8d871edf871f8c839fb6c Mon Sep 17 00:00:00 2001 From: Paul Chen Date: Mon, 31 Mar 2025 12:46:04 +0800 Subject: [PATCH 2/7] feat: add sign message --- api/background/background-service.ts | 2 + api/background/handlers/signMessage.ts | 46 +++++++ api/browser.ts | 13 ++ api/message.ts | 19 +++ .../browser-api/SignMessageConfirm.tsx | 49 ++++++++ .../sign-message/HotWalletSignMessage.tsx | 59 +++++++++ .../sign-message/LedgerSignMessage.tsx | 44 +++++++ .../browser-api/sign-message/SignMessage.tsx | 112 ++++++++++++++++++ .../screens/browser-api/sign-tx/SignTx.tsx | 3 +- docs/index.html | 6 + docs/index.js | 11 ++ entrypoints/popup/router.tsx | 5 + 12 files changed, 367 insertions(+), 2 deletions(-) create mode 100644 api/background/handlers/signMessage.ts create mode 100644 components/screens/browser-api/SignMessageConfirm.tsx create mode 100644 components/screens/browser-api/sign-message/HotWalletSignMessage.tsx create mode 100644 components/screens/browser-api/sign-message/LedgerSignMessage.tsx create mode 100644 components/screens/browser-api/sign-message/SignMessage.tsx diff --git a/api/background/background-service.ts b/api/background/background-service.ts index eb89dabf..57b8fa0b 100644 --- a/api/background/background-service.ts +++ b/api/background/background-service.ts @@ -2,6 +2,7 @@ import { connectHandler } from "@/api/background/handlers/connect"; import { getAccountHandler } from "@/api/background/handlers/getAccount"; import { signAndBroadcastTxHandler } from "@/api/background/handlers/signAndBroadcastTx"; import { signTxHandler } from "@/api/background/handlers/signTx"; +import { signMessageHandler } from "@/api/background/handlers/signMessage"; import { Action, ApiRequest, ApiResponse } from "@/api/message"; export class BackgroundService { @@ -48,6 +49,7 @@ export class BackgroundService { [Action.GET_ACCOUNT]: getAccountHandler, [Action.SIGN_AND_BROADCAST_TX]: signAndBroadcastTxHandler, [Action.SIGN_TX]: signTxHandler, + [Action.SIGN_MESSAGE]: signMessageHandler, }; return handlers[action]; diff --git a/api/background/handlers/signMessage.ts b/api/background/handlers/signMessage.ts new file mode 100644 index 00000000..8f75f0b8 --- /dev/null +++ b/api/background/handlers/signMessage.ts @@ -0,0 +1,46 @@ +import { Handler } from "@/api/background/utils"; +import { ApiRequest, ApiResponse, SignMessagePayload } from "@/api/message"; +import { ApiUtils } from "@/api/background/utils"; + +/** signMessageHandler to serve BrowserMessageType.SIGN_MESSAGE message */ +export const signMessageHandler: Handler = async ( + tabId: number, + message: ApiRequest, + sendResponse: any, +) => { + if (!message.host) { + sendResponse(new ApiResponse(message.id, null, "Host is required")); + return; + } + + // Check if extension is initialized + if (!(await ApiUtils.isInitialized())) { + sendResponse( + new ApiResponse(message.id, null, "Extension is not initialized"), + ); + return; + } + + // Check if host is connected, if not, return error + if (!(await ApiUtils.isHostConnected(message.host))) { + sendResponse(new ApiResponse(message.id, null, "Host not connected")); + return; + } + + if (!SignMessagePayload.validate(message.payload)) { + sendResponse(new ApiResponse(message.id, null, "Invalid payload")); + return; + } + + // Reconstruct SignMessagePayload from serialized message data to restore methods + const payload = Object.assign(new SignMessagePayload(""), message.payload); + + const url = browser.runtime.getURL( + `/popup.html?requestId=${encodeURIComponent(message.id)}&payload=${payload.toUriString()}#/sign-message`, + ); + + ApiUtils.openPopup(tabId, url); + + const response = await ApiUtils.receiveExtensionMessage(message.id); + sendResponse(response); +}; diff --git a/api/browser.ts b/api/browser.ts index 24ac635f..31ea4019 100644 --- a/api/browser.ts +++ b/api/browser.ts @@ -4,6 +4,7 @@ import { ApiRequest, ApiResponse, ConnectPayload, + SignMessagePayload, SignTxPayload, } from "@/api/message"; import { ScriptOption } from "@/lib/wallet/wallet-interface.ts"; @@ -76,6 +77,18 @@ export class KastleBrowserAPI { return await this.receiveMessage(requestId); } + async signMessage(message: string): Promise { + const requestId = uuid(); + const request = new ApiRequest( + Action.SIGN_MESSAGE, + requestId, + new SignMessagePayload(message), + ); + window.postMessage(request, "*"); + + return await this.receiveMessage(requestId); + } + private async receiveMessage( id: string, timeout = 60_000, // 1 minute diff --git a/api/message.ts b/api/message.ts index 42f8bb8e..bfed58c6 100644 --- a/api/message.ts +++ b/api/message.ts @@ -6,6 +6,7 @@ export enum Action { GET_ACCOUNT, SIGN_AND_BROADCAST_TX, SIGN_TX, + SIGN_MESSAGE, } export class SignTxPayload { @@ -36,6 +37,24 @@ export class SignTxPayload { // ================================================================================================ +export class SignMessagePayload { + constructor(public readonly message: string) {} + + static validate(data: unknown): data is SignMessagePayload { + return typeof data === "object" && !!data && "message" in data; + } + + static fromUriString(uriComponent: string): SignMessagePayload { + return new SignMessagePayload(decodeURIComponent(uriComponent)); + } + + toUriString(): string { + return encodeURIComponent(this.message); + } +} + +// ================================================================================================ + export class ConnectPayload { constructor( public readonly name: string, diff --git a/components/screens/browser-api/SignMessageConfirm.tsx b/components/screens/browser-api/SignMessageConfirm.tsx new file mode 100644 index 00000000..d739dde7 --- /dev/null +++ b/components/screens/browser-api/SignMessageConfirm.tsx @@ -0,0 +1,49 @@ +import { SignMessagePayload } from "@/api/message"; +import HotWalletSignMessage from "@/components/screens/browser-api/sign-message/HotWalletSignMessage"; +import LedgerSignMessage from "@/components/screens/browser-api/sign-message/LedgerSignMessage"; +import useWalletManager from "@/hooks/useWalletManager.ts"; +import { useEffect } from "react"; +import { ApiExtensionUtils } from "@/api/extension"; +import { ApiResponse } from "@/api/message"; +import Splash from "@/components/screens/Splash"; + +export default function SignMessageConfirm() { + const { wallet } = useWalletManager(); + const requestId = + new URLSearchParams(window.location.search).get("requestId") ?? ""; + const encodedPayload = new URLSearchParams(window.location.search).get( + "payload", + ); + + const payload = encodedPayload + ? SignMessagePayload.fromUriString(encodedPayload) + : null; + + const loading = !wallet || !requestId || !payload; + + useEffect(() => { + // Handle beforeunload event + async function beforeunload(event: BeforeUnloadEvent) { + const denyMessage = new ApiResponse(requestId, false, "User denied"); + await ApiExtensionUtils.sendMessage(requestId, denyMessage); + } + + window.addEventListener("beforeunload", beforeunload); + + return () => { + window.removeEventListener("beforeunload", beforeunload); + }; + }, []); + + return ( +
+ {loading && } + {!loading && wallet.type !== "ledger" && ( + + )} + {!loading && wallet.type === "ledger" && ( + + )} +
+ ); +} diff --git a/components/screens/browser-api/sign-message/HotWalletSignMessage.tsx b/components/screens/browser-api/sign-message/HotWalletSignMessage.tsx new file mode 100644 index 00000000..ee84cd92 --- /dev/null +++ b/components/screens/browser-api/sign-message/HotWalletSignMessage.tsx @@ -0,0 +1,59 @@ +import { SignMessagePayload } from "@/api/message"; +import SignMessage from "@/components/screens/browser-api/sign-message/SignMessage"; +import { IWallet } from "@/lib/wallet/wallet-interface.ts"; +import { AccountFactory } from "@/lib/wallet/wallet-factory"; +import useWalletManager from "@/hooks/useWalletManager.ts"; +import useRpcClientStateful from "@/hooks/useRpcClientStateful"; +import Splash from "@/components/screens/Splash.tsx"; + +type HotWalletSignMessageProps = { + requestId: string; + payload: SignMessagePayload; +}; + +export default function HotWalletSignMessage({ + requestId, + payload, +}: HotWalletSignMessageProps) { + const { getWalletSecret } = useKeyring(); + const { wallet: walletInfo, account } = useWalletManager(); + const { rpcClient, networkId: rpcNetworkId } = useRpcClientStateful(); + const [wallet, setWallet] = useState(); + const loading = + !rpcClient || !wallet || !walletInfo || !account || !rpcNetworkId; + + useEffect(() => { + if (!rpcClient || !walletInfo || !rpcNetworkId || !account) return; + if (walletInfo.type !== "mnemonic" && walletInfo.type !== "privateKey") { + throw new Error("Unsupported wallet type"); + } + + getWalletSecret({ walletId: walletInfo.id }).then(({ walletSecret }) => { + const factory = new AccountFactory(rpcClient, rpcNetworkId); + + switch (walletInfo.type) { + case "mnemonic": + setWallet( + factory.createFromMnemonic(walletSecret.value, account.index), + ); + break; + case "privateKey": + setWallet(factory.createFromPrivateKey(walletSecret.value)); + break; + } + }); + }, [rpcClient, walletInfo, account]); + + return ( + <> + {loading && } + {!loading && ( + + )} + + ); +} diff --git a/components/screens/browser-api/sign-message/LedgerSignMessage.tsx b/components/screens/browser-api/sign-message/LedgerSignMessage.tsx new file mode 100644 index 00000000..09de8fb9 --- /dev/null +++ b/components/screens/browser-api/sign-message/LedgerSignMessage.tsx @@ -0,0 +1,44 @@ +import { SignMessagePayload } from "@/api/message"; +import { AccountFactory } from "@/lib/wallet/wallet-factory"; +import useRpcClientStateful from "@/hooks/useRpcClientStateful"; +import { NetworkType } from "@/contexts/SettingsContext"; +import Splash from "@/components/screens/Splash"; +import LedgerConnectForSign from "@/components/screens/ledger-connect/LedgerConnectForSign"; +import SignMessage from "@/components/screens/browser-api/sign-message/SignMessage"; + +type LedgerSignTxProps = { + requestId: string; + payload: SignMessagePayload; +}; + +export default function LedgerSignMessage({ + requestId, + payload, +}: LedgerSignTxProps) { + const { transport, isAppOpen } = useLedgerTransport(); + const { rpcClient, networkId } = useRpcClientStateful(); + + const wallet = + rpcClient && transport + ? new AccountFactory( + rpcClient, + networkId ?? ("mainnet" as NetworkType), + ).createFromLedger(transport) + : null; + + return ( + <> + {(!transport || !isAppOpen) && ( + + )} + {transport && isAppOpen && !wallet && } + {wallet && isAppOpen && ( + + )} + + ); +} diff --git a/components/screens/browser-api/sign-message/SignMessage.tsx b/components/screens/browser-api/sign-message/SignMessage.tsx new file mode 100644 index 00000000..d9148ae4 --- /dev/null +++ b/components/screens/browser-api/sign-message/SignMessage.tsx @@ -0,0 +1,112 @@ +import useWalletManager from "@/hooks/useWalletManager"; +import ledgerSignImage from "@/assets/images/ledger-on-sign.svg"; +import signImage from "@/assets/images/sign.png"; +import Header from "@/components/GeneralHeader"; +import { useBoolean } from "usehooks-ts"; +import { IWallet } from "@/lib/wallet/wallet-interface"; +import { ApiExtensionUtils } from "@/api/extension"; +import { ApiResponse } from "@/api/message"; + +type SignMessageProps = { + requestId: string; + walletSigner: IWallet; + message: string; +}; + +export default function SignMessage({ + requestId, + walletSigner, + message, +}: SignMessageProps) { + const { wallet } = useWalletManager(); + const { value: isSigning, toggle: toggleIsSigning } = useBoolean(false); + + const onConfirm = async () => { + if (isSigning) { + return; + } + + toggleIsSigning(); + try { + // Sign the message + const signed = await walletSigner.signMessage(message); + await ApiExtensionUtils.sendMessage( + requestId, + new ApiResponse(requestId, signed), + ); + toggleIsSigning(); + } catch (err) { + await ApiExtensionUtils.sendMessage( + requestId, + new ApiResponse( + requestId, + null, + "Failed to sign message: " + (err as any).toString(), + ), + ); + } finally { + window.close(); + } + }; + + const cancel = async () => { + await ApiExtensionUtils.sendMessage( + requestId, + new ApiResponse(requestId, null, "User cancelled"), + ); + window.close(); + }; + + return ( +
+
+
+
+ {wallet?.type !== "ledger" && ( + Sign + )} + {wallet?.type === "ledger" && ( + Sign + )} +
+ + {/* Confirm Content */} +
+

Sign Message

+

+ Please confirm the message you are signing +

+
+

{message}

+
+
+
+ + {/* Buttons */} +
+ + +
+
+ ); +} diff --git a/components/screens/browser-api/sign-tx/SignTx.tsx b/components/screens/browser-api/sign-tx/SignTx.tsx index 8c286cbb..b75307b5 100644 --- a/components/screens/browser-api/sign-tx/SignTx.tsx +++ b/components/screens/browser-api/sign-tx/SignTx.tsx @@ -32,8 +32,7 @@ export default function SignTx({ wallet, requestId, payload }: SignTxProps) { new ApiResponse( requestId, null, - "Failed to sign and broadcast transaction: " + - (err as any).toString(), + "Failed to sign transaction: " + (err as any).toString(), ), ); } finally { diff --git a/docs/index.html b/docs/index.html index 23bb01fe..180c265b 100644 --- a/docs/index.html +++ b/docs/index.html @@ -41,6 +41,12 @@

Kastle Basic

Error: None
+
+ +
Signature:
+
Error: None
+
+

KRC20

diff --git a/docs/index.js b/docs/index.js index 84248696..712d7382 100644 --- a/docs/index.js +++ b/docs/index.js @@ -87,6 +87,17 @@ document } }); +document.getElementById("signMessage").addEventListener("click", async () => { + try { + const message = "Hello, World!"; + const signature = await kastle.signMessage(message); + document.getElementById("signature").innerText = signature; + document.getElementById("signMessageError").innerText = "None"; + } catch (error) { + document.getElementById("signMessageError").innerText = error.message; + } +}); + function createKRC20ScriptBuilder(data) { const { Opcodes } = kaspaWasm; const accountPublicKey = document.getElementById("publicKey").innerText; diff --git a/entrypoints/popup/router.tsx b/entrypoints/popup/router.tsx index 1a351493..850820de 100644 --- a/entrypoints/popup/router.tsx +++ b/entrypoints/popup/router.tsx @@ -55,6 +55,7 @@ import { RecentAddressesProvider } from "@/contexts/RecentAddressesContext.tsx"; import KNSAsset from "@/components/screens/KNSAsset"; import KRC721 from "@/components/screens/KRC721"; import OnboardingSuccess from "@/components/onboarding/OnboardingSuccess.tsx"; +import SignMessageConfirm from "@/components/screens/browser-api/SignMessageConfirm"; const loadKaspaWasm = async () => { await init(kaspaModule); @@ -211,6 +212,10 @@ export const router = createHashRouter([ path: "sign-tx", element: , }, + { + path: "sign-message", + element: , + }, ], }, { path: "password-lost", element: }, From e6c9f2596a84ac96a4ffa915b504348dda173dbf Mon Sep 17 00:00:00 2001 From: Paul Chen Date: Mon, 31 Mar 2025 12:47:27 +0800 Subject: [PATCH 3/7] chore: run prettier --- components/screens/browser-api/sign-message/SignMessage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/screens/browser-api/sign-message/SignMessage.tsx b/components/screens/browser-api/sign-message/SignMessage.tsx index d9148ae4..982f9d53 100644 --- a/components/screens/browser-api/sign-message/SignMessage.tsx +++ b/components/screens/browser-api/sign-message/SignMessage.tsx @@ -76,8 +76,8 @@ export default function SignMessage({

Please confirm the message you are signing

-
-

{message}

+
+

{message}

From e1a41dd452aa334e8c3b528d27a30e4bda35f765 Mon Sep 17 00:00:00 2001 From: Paul Chen Date: Mon, 14 Apr 2025 12:45:54 +0800 Subject: [PATCH 4/7] refactor(sign-message): update response handling and payload validation --- api/background/handlers/signMessage.ts | 41 ++++++++++++------- .../browser-api/SignMessageConfirm.tsx | 20 ++------- .../browser-api/sign-message/SignMessage.tsx | 8 ++-- 3 files changed, 34 insertions(+), 35 deletions(-) diff --git a/api/background/handlers/signMessage.ts b/api/background/handlers/signMessage.ts index 8f75f0b8..a4ccda70 100644 --- a/api/background/handlers/signMessage.ts +++ b/api/background/handlers/signMessage.ts @@ -1,45 +1,58 @@ import { Handler } from "@/api/background/utils"; -import { ApiRequest, ApiResponse, SignMessagePayload } from "@/api/message"; +import { + ApiRequestWithHost, + ApiResponse, + SignMessagePayloadSchema, +} from "@/api/message"; import { ApiUtils } from "@/api/background/utils"; /** signMessageHandler to serve BrowserMessageType.SIGN_MESSAGE message */ export const signMessageHandler: Handler = async ( tabId: number, - message: ApiRequest, + message: ApiRequestWithHost, sendResponse: any, ) => { if (!message.host) { - sendResponse(new ApiResponse(message.id, null, "Host is required")); + sendResponse( + ApiUtils.createApiResponse(message.id, null, "Host is required"), + ); return; } // Check if extension is initialized if (!(await ApiUtils.isInitialized())) { sendResponse( - new ApiResponse(message.id, null, "Extension is not initialized"), + ApiUtils.createApiResponse( + message.id, + null, + "Extension is not initialized", + ), ); return; } // Check if host is connected, if not, return error if (!(await ApiUtils.isHostConnected(message.host))) { - sendResponse(new ApiResponse(message.id, null, "Host not connected")); + sendResponse( + ApiUtils.createApiResponse(message.id, null, "Host not connected"), + ); return; } - if (!SignMessagePayload.validate(message.payload)) { - sendResponse(new ApiResponse(message.id, null, "Invalid payload")); + const result = SignMessagePayloadSchema.safeParse(message.payload); + if (!result.success) { + sendResponse( + ApiUtils.createApiResponse(message.id, null, "Invalid transaction data"), + ); return; } - // Reconstruct SignMessagePayload from serialized message data to restore methods - const payload = Object.assign(new SignMessagePayload(""), message.payload); - - const url = browser.runtime.getURL( - `/popup.html?requestId=${encodeURIComponent(message.id)}&payload=${payload.toUriString()}#/sign-message`, - ); + const url = new URL(browser.runtime.getURL("/popup.html")); + url.hash = "/sign-message"; + url.searchParams.set("requestId", message.id); + url.searchParams.set("payload", JSON.stringify(result.data)); - ApiUtils.openPopup(tabId, url); + ApiUtils.openPopup(tabId, url.toString()); const response = await ApiUtils.receiveExtensionMessage(message.id); sendResponse(response); diff --git a/components/screens/browser-api/SignMessageConfirm.tsx b/components/screens/browser-api/SignMessageConfirm.tsx index d739dde7..d75e67de 100644 --- a/components/screens/browser-api/SignMessageConfirm.tsx +++ b/components/screens/browser-api/SignMessageConfirm.tsx @@ -16,25 +16,11 @@ export default function SignMessageConfirm() { ); const payload = encodedPayload - ? SignMessagePayload.fromUriString(encodedPayload) - : null; + ? JSON.parse(decodeURIComponent(encodedPayload)) + : null; const loading = !wallet || !requestId || !payload; - - useEffect(() => { - // Handle beforeunload event - async function beforeunload(event: BeforeUnloadEvent) { - const denyMessage = new ApiResponse(requestId, false, "User denied"); - await ApiExtensionUtils.sendMessage(requestId, denyMessage); - } - - window.addEventListener("beforeunload", beforeunload); - - return () => { - window.removeEventListener("beforeunload", beforeunload); - }; - }, []); - + return (
{loading && } diff --git a/components/screens/browser-api/sign-message/SignMessage.tsx b/components/screens/browser-api/sign-message/SignMessage.tsx index 982f9d53..500453c6 100644 --- a/components/screens/browser-api/sign-message/SignMessage.tsx +++ b/components/screens/browser-api/sign-message/SignMessage.tsx @@ -5,7 +5,7 @@ import Header from "@/components/GeneralHeader"; import { useBoolean } from "usehooks-ts"; import { IWallet } from "@/lib/wallet/wallet-interface"; import { ApiExtensionUtils } from "@/api/extension"; -import { ApiResponse } from "@/api/message"; +import { ApiUtils } from "@/api/background/utils"; type SignMessageProps = { requestId: string; @@ -32,13 +32,13 @@ export default function SignMessage({ const signed = await walletSigner.signMessage(message); await ApiExtensionUtils.sendMessage( requestId, - new ApiResponse(requestId, signed), + ApiUtils.createApiResponse(requestId, signed), ); toggleIsSigning(); } catch (err) { await ApiExtensionUtils.sendMessage( requestId, - new ApiResponse( + ApiUtils.createApiResponse( requestId, null, "Failed to sign message: " + (err as any).toString(), @@ -52,7 +52,7 @@ export default function SignMessage({ const cancel = async () => { await ApiExtensionUtils.sendMessage( requestId, - new ApiResponse(requestId, null, "User cancelled"), + ApiUtils.createApiResponse(requestId, null, "User cancelled"), ); window.close(); }; From 8f09c9fbeccc7c37eb2f7a45c0c6343873fb5488 Mon Sep 17 00:00:00 2001 From: Paul Chen Date: Mon, 14 Apr 2025 12:46:14 +0800 Subject: [PATCH 5/7] style(SignMessageConfirm): format code for better readability --- components/screens/browser-api/SignMessageConfirm.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/screens/browser-api/SignMessageConfirm.tsx b/components/screens/browser-api/SignMessageConfirm.tsx index d75e67de..2caa8fd1 100644 --- a/components/screens/browser-api/SignMessageConfirm.tsx +++ b/components/screens/browser-api/SignMessageConfirm.tsx @@ -16,11 +16,11 @@ export default function SignMessageConfirm() { ); const payload = encodedPayload - ? JSON.parse(decodeURIComponent(encodedPayload)) - : null; + ? JSON.parse(decodeURIComponent(encodedPayload)) + : null; const loading = !wallet || !requestId || !payload; - + return (
{loading && } From b67f93ebad1cb476b09591e5e2b0dc7eb4eda359 Mon Sep 17 00:00:00 2001 From: Paul Chen Date: Mon, 14 Apr 2025 18:03:33 +0800 Subject: [PATCH 6/7] feat: refactor background service and handlers for Kaspa integration --- api/background/background-service.ts | 10 ++-- .../handlers/ethereum/sendTransaction.ts | 20 +++++++- .../handlers/{ => kaspa}/connect.ts | 12 ++++- .../handlers/{ => kaspa}/getAccount.ts | 0 .../{ => kaspa}/signAndBroadcastTx.ts | 4 +- .../handlers/{ => kaspa}/signMessage.ts | 15 ++++-- api/background/handlers/{ => kaspa}/signTx.ts | 7 +-- api/background/handlers/kaspa/utils.ts | 10 ++++ api/browser.ts | 20 ++------ api/message.ts | 48 ------------------- .../screens/browser-api/ConnectConfirm.tsx | 9 ++-- .../browser-api/SignAndBroadcastTxConfirm.tsx | 2 +- .../browser-api/SignMessageConfirm.tsx | 21 +++++--- .../screens/browser-api/SignTxConfirm.tsx | 2 +- .../ethereum/EthereumSignMessageConfirm.tsx | 4 -- .../send-transaction/SendTransaction.tsx | 3 +- .../HotWalletSignAndBroadcast.tsx | 2 +- .../LedgerSignAndBroadcast.tsx | 2 +- .../sign-and-broadcast/SignAndBroadcast.tsx | 2 +- .../sign-message/HotWalletSignMessage.tsx | 2 +- .../sign-message/LedgerSignMessage.tsx | 2 +- .../browser-api/sign-tx/HotWalletSignTx.tsx | 2 +- .../browser-api/sign-tx/LedgerSignTx.tsx | 2 +- .../screens/browser-api/sign-tx/SignTx.tsx | 2 +- .../browser-api/sign/DetailsSelector.tsx | 2 +- .../screens/browser-api/sign/SignConfirm.tsx | 2 +- entrypoints/content.ts | 7 +++ 27 files changed, 105 insertions(+), 109 deletions(-) rename api/background/handlers/{ => kaspa}/connect.ts (82%) rename api/background/handlers/{ => kaspa}/getAccount.ts (100%) rename api/background/handlers/{ => kaspa}/signAndBroadcastTx.ts (93%) rename api/background/handlers/{ => kaspa}/signMessage.ts (81%) rename api/background/handlers/{ => kaspa}/signTx.ts (93%) create mode 100644 api/background/handlers/kaspa/utils.ts diff --git a/api/background/background-service.ts b/api/background/background-service.ts index 38fa2263..fdda0970 100644 --- a/api/background/background-service.ts +++ b/api/background/background-service.ts @@ -1,7 +1,7 @@ -import { connectHandler } from "@/api/background/handlers/connect"; -import { getAccountHandler } from "@/api/background/handlers/getAccount"; -import { signAndBroadcastTxHandler } from "@/api/background/handlers/signAndBroadcastTx"; -import { signTxHandler } from "@/api/background/handlers/signTx"; +import { connectHandler } from "@/api/background/handlers/kaspa/connect"; +import { getAccountHandler } from "@/api/background/handlers/kaspa/getAccount"; +import { signAndBroadcastTxHandler } from "@/api/background/handlers/kaspa/signAndBroadcastTx"; +import { signTxHandler } from "@/api/background/handlers/kaspa/signTx"; import { Action, ApiRequestWithHostSchema, @@ -9,7 +9,7 @@ import { } from "@/api/message"; import { getNetwork } from "@/api/background/handlers/get-network.ts"; import { ethereumRequestHandler } from "@/api/background/handlers/ethereum/request"; -import { signMessageHandler } from "@/api/background/handlers/signMessage"; +import { signMessageHandler } from "@/api/background/handlers/kaspa/signMessage"; export class BackgroundService { public listen(): void { diff --git a/api/background/handlers/ethereum/sendTransaction.ts b/api/background/handlers/ethereum/sendTransaction.ts index ff1e2bb3..302e1692 100644 --- a/api/background/handlers/ethereum/sendTransaction.ts +++ b/api/background/handlers/ethereum/sendTransaction.ts @@ -3,10 +3,28 @@ import { RpcError, RPC_ERRORS, RpcRequestSchema, - ethereumTransactionRequestSchema, } from "@/api/message"; import { ApiUtils } from "@/api/background/utils"; import { isMatchCurrentAddress, isUserDeniedResponse } from "./utils"; +import { isAddress, isHex } from "viem"; +import { z } from "zod"; + +export const ethereumTransactionRequestSchema = z.object({ + from: z.string().refine(isAddress, "Must be a valid Ethereum address"), + to: z.string().refine(isAddress, "Must be a valid Ethereum address"), + value: z.string().refine(isHex, "Value must be a hex string").optional(), + data: z.string().refine(isHex, "Data must be a hex string").optional(), + maxFeePerGas: z + .string() + .refine(isHex, "Max fee per gas must be a hex string") + .optional(), + maxPriorityFeePerGas: z + .string() + .refine(isHex, "Max priority fee must be a hex string") + .optional(), +}); + +// ================================================================================ export const sendTransactionHandler = async ( tabId: number, diff --git a/api/background/handlers/connect.ts b/api/background/handlers/kaspa/connect.ts similarity index 82% rename from api/background/handlers/connect.ts rename to api/background/handlers/kaspa/connect.ts index fb95e2cf..f4f419f6 100644 --- a/api/background/handlers/connect.ts +++ b/api/background/handlers/kaspa/connect.ts @@ -1,5 +1,15 @@ -import { ApiRequestWithHost, ConnectPayloadSchema } from "@/api/message"; +import { ApiRequestWithHost } from "@/api/message"; import { ApiUtils, Handler } from "@/api/background/utils"; +import { NetworkType } from "@/contexts/SettingsContext"; +import { z } from "zod"; + +export const ConnectPayloadSchema = z.object({ + networkId: z.nativeEnum(NetworkType), + name: z.string(), + icon: z.string().optional(), +}); + +export type ConnectPayload = z.infer; /** Connect handler to serve BrowserMessageType.CONNECT message */ export const connectHandler: Handler = async ( diff --git a/api/background/handlers/getAccount.ts b/api/background/handlers/kaspa/getAccount.ts similarity index 100% rename from api/background/handlers/getAccount.ts rename to api/background/handlers/kaspa/getAccount.ts diff --git a/api/background/handlers/signAndBroadcastTx.ts b/api/background/handlers/kaspa/signAndBroadcastTx.ts similarity index 93% rename from api/background/handlers/signAndBroadcastTx.ts rename to api/background/handlers/kaspa/signAndBroadcastTx.ts index e5650cbd..5db72b05 100644 --- a/api/background/handlers/signAndBroadcastTx.ts +++ b/api/background/handlers/kaspa/signAndBroadcastTx.ts @@ -1,6 +1,8 @@ import { Handler } from "@/api/background/utils"; -import { ApiRequestWithHost, SignTxPayloadSchema } from "@/api/message"; +import { ApiRequestWithHost } from "@/api/message"; import { ApiUtils } from "@/api/background/utils"; +import { SignTxPayloadSchema } from "./utils"; + /** signAndBroadcastTx handler to serve BrowserMessageType.SIGN_AND_BROADCAST_TX message */ export const signAndBroadcastTxHandler: Handler = async ( tabId: number, diff --git a/api/background/handlers/signMessage.ts b/api/background/handlers/kaspa/signMessage.ts similarity index 81% rename from api/background/handlers/signMessage.ts rename to api/background/handlers/kaspa/signMessage.ts index a4ccda70..019fc282 100644 --- a/api/background/handlers/signMessage.ts +++ b/api/background/handlers/kaspa/signMessage.ts @@ -1,10 +1,15 @@ import { Handler } from "@/api/background/utils"; -import { - ApiRequestWithHost, - ApiResponse, - SignMessagePayloadSchema, -} from "@/api/message"; +import { ApiRequestWithHost, ApiResponse } from "@/api/message"; import { ApiUtils } from "@/api/background/utils"; +import { z } from "zod"; + +export const SignMessagePayloadSchema = z.object({ + message: z.string(), +}); + +export type SignMessagePayload = z.infer; + +// ================================================================================ /** signMessageHandler to serve BrowserMessageType.SIGN_MESSAGE message */ export const signMessageHandler: Handler = async ( diff --git a/api/background/handlers/signTx.ts b/api/background/handlers/kaspa/signTx.ts similarity index 93% rename from api/background/handlers/signTx.ts rename to api/background/handlers/kaspa/signTx.ts index c47abe73..a4fcb246 100644 --- a/api/background/handlers/signTx.ts +++ b/api/background/handlers/kaspa/signTx.ts @@ -1,10 +1,7 @@ import { Handler } from "@/api/background/utils"; -import { - ApiRequestWithHost, - ApiResponse, - SignTxPayloadSchema, -} from "@/api/message"; +import { ApiRequestWithHost } from "@/api/message"; import { ApiUtils } from "@/api/background/utils"; +import { SignTxPayloadSchema } from "./utils"; /** signTxHandler to serve BrowserMessageType.SIGN_TX message */ export const signTxHandler: Handler = async ( diff --git a/api/background/handlers/kaspa/utils.ts b/api/background/handlers/kaspa/utils.ts new file mode 100644 index 00000000..bf43f8c8 --- /dev/null +++ b/api/background/handlers/kaspa/utils.ts @@ -0,0 +1,10 @@ +import { z } from "zod"; +import { ScriptOption } from "@/lib/wallet/wallet-interface.ts"; + +export const SignTxPayloadSchema = z.object({ + networkId: z.string(), + txJson: z.string(), + scripts: z.array(z.custom()).optional(), +}); + +export type SignTxPayload = z.infer; diff --git a/api/browser.ts b/api/browser.ts index 625816a8..fe35b512 100644 --- a/api/browser.ts +++ b/api/browser.ts @@ -1,15 +1,10 @@ import { v4 as uuid } from "uuid"; -import { - Action, - ApiRequest, - ApiResponseSchema, - ConnectPayloadSchema, - SignTxPayloadSchema, - SignMessagePayloadSchema, -} from "@/api/message"; +import { Action, ApiRequest, ApiResponseSchema } from "@/api/message"; import { ScriptOption } from "@/lib/wallet/wallet-interface.ts"; import { EthereumBrowserAPI } from "./ethereum"; -import { ApiUtils } from "@/api/background/utils.ts"; +import { ConnectPayloadSchema } from "@/api/background/handlers/kaspa/connect"; +import { SignTxPayloadSchema } from "@/api/background/handlers/kaspa/utils"; +import { SignMessagePayloadSchema } from "@/api/background/handlers/kaspa/signMessage"; function createApiRequest( action: Action, @@ -28,12 +23,7 @@ function createApiRequest( export class KastleBrowserAPI { public readonly ethereum = new EthereumBrowserAPI(); - constructor() { - window.postMessage( - ApiUtils.createApiResponse("kastle_installed", []), - window.location.origin, - ); - } + constructor() {} async connect( networkId: "mainnet" | "testnet-10" = "mainnet", diff --git a/api/message.ts b/api/message.ts index b600f07f..ecf3b14b 100644 --- a/api/message.ts +++ b/api/message.ts @@ -1,7 +1,4 @@ -import { ScriptOption } from "@/lib/wallet/wallet-interface.ts"; import { z } from "zod"; -import { NetworkType } from "@/contexts/SettingsContext.tsx"; -import { isAddress, isHex } from "viem"; export enum Action { CONNECT, @@ -15,31 +12,11 @@ export enum Action { // ================================================================================================ -export const SignMessagePayloadSchema = z.object({ - message: z.string(), -}); - -export type SignMessagePayload = z.infer; - -// ================================================================================================ - -export const SignTxPayloadSchema = z.object({ - networkId: z.string(), - txJson: z.string(), - scripts: z.array(z.custom()).optional(), -}); - -export type SignTxPayload = z.infer; - -// ================================================================================================ - export const RpcRequestSchema = z.object({ method: z.string(), params: z.array(z.unknown()).optional(), }); -// ================================================================================================ - export type RpcRequest = z.infer; export const RpcErrorSchema = z.object({ @@ -96,31 +73,6 @@ export enum ETHEREUM_METHODS { WALLET_SWITCH_ETHEREUM_NETWORK = "wallet_switchEthereumChain", } -export const ethereumTransactionRequestSchema = z.object({ - from: z.string().refine(isAddress, "Must be a valid Ethereum address"), - to: z.string().refine(isAddress, "Must be a valid Ethereum address"), - value: z.string().refine(isHex, "Value must be a hex string").optional(), - data: z.string().refine(isHex, "Data must be a hex string").optional(), - maxFeePerGas: z - .string() - .refine(isHex, "Max fee per gas must be a hex string") - .optional(), - maxPriorityFeePerGas: z - .string() - .refine(isHex, "Max priority fee must be a hex string") - .optional(), -}); - -// ================================================================================================ - -export const ConnectPayloadSchema = z.object({ - networkId: z.nativeEnum(NetworkType), - name: z.string(), - icon: z.string().optional(), -}); - -export type ConnectPayload = z.infer; - // ================================================================================================ export const ApiRequestSchema = z.object({ diff --git a/components/screens/browser-api/ConnectConfirm.tsx b/components/screens/browser-api/ConnectConfirm.tsx index ab8e3989..a37f9604 100644 --- a/components/screens/browser-api/ConnectConfirm.tsx +++ b/components/screens/browser-api/ConnectConfirm.tsx @@ -1,6 +1,5 @@ import { ApiExtensionUtils } from "@/api/extension"; import { useSettings } from "@/hooks/useSettings"; -import { useEffect } from "react"; import { NetworkType } from "@/contexts/SettingsContext.tsx"; import Header from "@/components/GeneralHeader"; import Link from "@/assets/images/link.svg"; @@ -23,7 +22,7 @@ export default function ConnectConfirm() { const urlSearchParams = new URLSearchParams(window.location.search); const requestId = urlSearchParams.get("requestId") ?? ""; const host = urlSearchParams.get("host") ?? ""; - const network = urlSearchParams.get("network") ?? ""; + const network = urlSearchParams.get("network") ?? settings?.networkId; const tabName = urlSearchParams.get("name") ?? "Unknown"; const icon = urlSearchParams.get("icon") ?? undefined; @@ -47,7 +46,9 @@ export default function ConnectConfirm() { } const walletConnections = settings.walletConnections ?? {}; - const targetNetwork = (network as NetworkType) ?? settings.networkId; + const targetNetwork = (network ?? settings.networkId) as NetworkType; + console.log(targetNetwork, settings.networkId); + const connections = walletConnections[selectedWalletId]?.[selectedAccountIndex]?.[ targetNetwork @@ -84,7 +85,6 @@ export default function ConnectConfirm() { ), ); } finally { - window.close(); } }; @@ -110,6 +110,7 @@ export default function ConnectConfirm() { background: "bg-yellow-800", }, ]; + const selectedNetwork = networks.find( (n) => n.id === (network ?? settings?.networkId), ); diff --git a/components/screens/browser-api/SignAndBroadcastTxConfirm.tsx b/components/screens/browser-api/SignAndBroadcastTxConfirm.tsx index 2e9ec98d..61285886 100644 --- a/components/screens/browser-api/SignAndBroadcastTxConfirm.tsx +++ b/components/screens/browser-api/SignAndBroadcastTxConfirm.tsx @@ -1,4 +1,4 @@ -import { SignTxPayloadSchema } from "@/api/message"; +import { SignTxPayloadSchema } from "@/api/background/handlers/kaspa/utils"; import HotWalletSignAndBroadcast from "@/components/screens/browser-api/sign-and-broadcast/HotWalletSignAndBroadcast"; import LedgerSignAndBroadcast from "@/components/screens/browser-api/sign-and-broadcast/LedgerSignAndBroadcast"; import useWalletManager from "@/hooks/useWalletManager.ts"; diff --git a/components/screens/browser-api/SignMessageConfirm.tsx b/components/screens/browser-api/SignMessageConfirm.tsx index 2caa8fd1..0f8ea06f 100644 --- a/components/screens/browser-api/SignMessageConfirm.tsx +++ b/components/screens/browser-api/SignMessageConfirm.tsx @@ -1,10 +1,7 @@ -import { SignMessagePayload } from "@/api/message"; +import { SignMessagePayloadSchema } from "@/api/background/handlers/kaspa/signMessage"; import HotWalletSignMessage from "@/components/screens/browser-api/sign-message/HotWalletSignMessage"; import LedgerSignMessage from "@/components/screens/browser-api/sign-message/LedgerSignMessage"; import useWalletManager from "@/hooks/useWalletManager.ts"; -import { useEffect } from "react"; -import { ApiExtensionUtils } from "@/api/extension"; -import { ApiResponse } from "@/api/message"; import Splash from "@/components/screens/Splash"; export default function SignMessageConfirm() { @@ -19,16 +16,26 @@ export default function SignMessageConfirm() { ? JSON.parse(decodeURIComponent(encodedPayload)) : null; - const loading = !wallet || !requestId || !payload; + const parsedPayload = payload + ? SignMessagePayloadSchema.parse(payload) + : null; + + const loading = !wallet || !requestId || !parsedPayload; return (
{loading && } {!loading && wallet.type !== "ledger" && ( - + )} {!loading && wallet.type === "ledger" && ( - + )}
); diff --git a/components/screens/browser-api/SignTxConfirm.tsx b/components/screens/browser-api/SignTxConfirm.tsx index ee18b4b9..843efebb 100644 --- a/components/screens/browser-api/SignTxConfirm.tsx +++ b/components/screens/browser-api/SignTxConfirm.tsx @@ -1,4 +1,4 @@ -import { SignTxPayloadSchema } from "@/api/message"; +import { SignTxPayloadSchema } from "@/api/background/handlers/kaspa/utils"; import HotWalletSignTx from "@/components/screens/browser-api/sign-tx/HotWalletSignTx"; import LedgerSignTx from "@/components/screens/browser-api/sign-tx/LedgerSignTx"; import useWalletManager from "@/hooks/useWalletManager.ts"; diff --git a/components/screens/browser-api/ethereum/EthereumSignMessageConfirm.tsx b/components/screens/browser-api/ethereum/EthereumSignMessageConfirm.tsx index 54da8917..2702414e 100644 --- a/components/screens/browser-api/ethereum/EthereumSignMessageConfirm.tsx +++ b/components/screens/browser-api/ethereum/EthereumSignMessageConfirm.tsx @@ -1,10 +1,6 @@ import HotWalletSignMessage from "@/components/screens/browser-api/ethereum/sign-message/HotWalletSignMessage"; import useWalletManager from "@/hooks/useWalletManager.ts"; -import { useEffect } from "react"; -import { ApiExtensionUtils } from "@/api/extension"; -import { RPC_ERRORS } from "@/api/message"; import Splash from "@/components/screens/Splash"; -import { ApiUtils } from "@/api/background/utils"; export default function EthereumSignMessageConfirm() { const { wallet } = useWalletManager(); diff --git a/components/screens/browser-api/ethereum/send-transaction/SendTransaction.tsx b/components/screens/browser-api/ethereum/send-transaction/SendTransaction.tsx index 7cbce3b4..bebb12a4 100644 --- a/components/screens/browser-api/ethereum/send-transaction/SendTransaction.tsx +++ b/components/screens/browser-api/ethereum/send-transaction/SendTransaction.tsx @@ -6,7 +6,7 @@ import Header from "@/components/GeneralHeader"; import { useBoolean } from "usehooks-ts"; import { ApiExtensionUtils } from "@/api/extension"; import { ApiUtils } from "@/api/background/utils"; -import { RPC_ERRORS, ethereumTransactionRequestSchema } from "@/api/message"; +import { RPC_ERRORS } from "@/api/message"; import { TransactionSerializable, hexToBigInt, @@ -15,6 +15,7 @@ import { } from "viem"; import { kairos } from "viem/chains"; import { estimateFeesPerGas } from "viem/actions"; +import { ethereumTransactionRequestSchema } from "@/api/background/handlers/ethereum/sendTransaction"; type SignTransactionProps = { walletSigner: IWallet; diff --git a/components/screens/browser-api/sign-and-broadcast/HotWalletSignAndBroadcast.tsx b/components/screens/browser-api/sign-and-broadcast/HotWalletSignAndBroadcast.tsx index 121ee1ae..c0446dbd 100644 --- a/components/screens/browser-api/sign-and-broadcast/HotWalletSignAndBroadcast.tsx +++ b/components/screens/browser-api/sign-and-broadcast/HotWalletSignAndBroadcast.tsx @@ -1,4 +1,4 @@ -import { SignTxPayload } from "@/api/message"; +import { SignTxPayload } from "@/api/background/handlers/kaspa/utils"; import SignAndBroadcast from "@/components/screens/browser-api/sign-and-broadcast/SignAndBroadcast"; import { IWallet } from "@/lib/wallet/wallet-interface.ts"; import { AccountFactory } from "@/lib/wallet/wallet-factory"; diff --git a/components/screens/browser-api/sign-and-broadcast/LedgerSignAndBroadcast.tsx b/components/screens/browser-api/sign-and-broadcast/LedgerSignAndBroadcast.tsx index dca93a5a..c4f4742e 100644 --- a/components/screens/browser-api/sign-and-broadcast/LedgerSignAndBroadcast.tsx +++ b/components/screens/browser-api/sign-and-broadcast/LedgerSignAndBroadcast.tsx @@ -1,4 +1,4 @@ -import { SignTxPayload } from "@/api/message"; +import { SignTxPayload } from "@/api/background/handlers/kaspa/utils"; import LedgerNotSupported from "@/components/screens/browser-api/sign/LedgerNotSupported"; import SignAndBroadcast from "@/components/screens/browser-api/sign-and-broadcast/SignAndBroadcast"; import { AccountFactory } from "@/lib/wallet/wallet-factory"; diff --git a/components/screens/browser-api/sign-and-broadcast/SignAndBroadcast.tsx b/components/screens/browser-api/sign-and-broadcast/SignAndBroadcast.tsx index e8a1f7b4..390468be 100644 --- a/components/screens/browser-api/sign-and-broadcast/SignAndBroadcast.tsx +++ b/components/screens/browser-api/sign-and-broadcast/SignAndBroadcast.tsx @@ -1,4 +1,4 @@ -import { SignTxPayload } from "@/api/message"; +import { SignTxPayload } from "@/api/background/handlers/kaspa/utils"; import { ApiExtensionUtils } from "@/api/extension"; import { IWallet } from "@/lib/wallet/wallet-interface.ts"; import useWalletManager from "@/hooks/useWalletManager"; diff --git a/components/screens/browser-api/sign-message/HotWalletSignMessage.tsx b/components/screens/browser-api/sign-message/HotWalletSignMessage.tsx index ee84cd92..df10b767 100644 --- a/components/screens/browser-api/sign-message/HotWalletSignMessage.tsx +++ b/components/screens/browser-api/sign-message/HotWalletSignMessage.tsx @@ -1,4 +1,4 @@ -import { SignMessagePayload } from "@/api/message"; +import { SignMessagePayload } from "@/api/background/handlers/kaspa/signMessage"; import SignMessage from "@/components/screens/browser-api/sign-message/SignMessage"; import { IWallet } from "@/lib/wallet/wallet-interface.ts"; import { AccountFactory } from "@/lib/wallet/wallet-factory"; diff --git a/components/screens/browser-api/sign-message/LedgerSignMessage.tsx b/components/screens/browser-api/sign-message/LedgerSignMessage.tsx index 09de8fb9..2dbd59da 100644 --- a/components/screens/browser-api/sign-message/LedgerSignMessage.tsx +++ b/components/screens/browser-api/sign-message/LedgerSignMessage.tsx @@ -1,4 +1,4 @@ -import { SignMessagePayload } from "@/api/message"; +import { SignMessagePayload } from "@/api/background/handlers/kaspa/signMessage"; import { AccountFactory } from "@/lib/wallet/wallet-factory"; import useRpcClientStateful from "@/hooks/useRpcClientStateful"; import { NetworkType } from "@/contexts/SettingsContext"; diff --git a/components/screens/browser-api/sign-tx/HotWalletSignTx.tsx b/components/screens/browser-api/sign-tx/HotWalletSignTx.tsx index 1ad78035..34286072 100644 --- a/components/screens/browser-api/sign-tx/HotWalletSignTx.tsx +++ b/components/screens/browser-api/sign-tx/HotWalletSignTx.tsx @@ -1,4 +1,4 @@ -import { SignTxPayload } from "@/api/message"; +import { SignTxPayload } from "@/api/background/handlers/kaspa/utils"; import SignTx from "@/components/screens/browser-api/sign-tx/SignTx"; import { IWallet } from "@/lib/wallet/wallet-interface.ts"; import { AccountFactory } from "@/lib/wallet/wallet-factory"; diff --git a/components/screens/browser-api/sign-tx/LedgerSignTx.tsx b/components/screens/browser-api/sign-tx/LedgerSignTx.tsx index 6a517572..5a8ce990 100644 --- a/components/screens/browser-api/sign-tx/LedgerSignTx.tsx +++ b/components/screens/browser-api/sign-tx/LedgerSignTx.tsx @@ -1,4 +1,4 @@ -import { SignTxPayload } from "@/api/message"; +import { SignTxPayload } from "@/api/background/handlers/kaspa/utils"; import LedgerNotSupported from "@/components/screens/browser-api/sign/LedgerNotSupported"; import SignTx from "@/components/screens/browser-api/sign-tx/SignTx"; import { AccountFactory } from "@/lib/wallet/wallet-factory"; diff --git a/components/screens/browser-api/sign-tx/SignTx.tsx b/components/screens/browser-api/sign-tx/SignTx.tsx index a701c2a4..9867e172 100644 --- a/components/screens/browser-api/sign-tx/SignTx.tsx +++ b/components/screens/browser-api/sign-tx/SignTx.tsx @@ -1,4 +1,4 @@ -import { ApiResponse, SignTxPayload } from "@/api/message"; +import { SignTxPayload } from "@/api/background/handlers/kaspa/utils"; import { ApiExtensionUtils } from "@/api/extension"; import { IWallet } from "@/lib/wallet/wallet-interface.ts"; import useRpcClientStateful from "@/hooks/useRpcClientStateful"; diff --git a/components/screens/browser-api/sign/DetailsSelector.tsx b/components/screens/browser-api/sign/DetailsSelector.tsx index 604faa73..57abf577 100644 --- a/components/screens/browser-api/sign/DetailsSelector.tsx +++ b/components/screens/browser-api/sign/DetailsSelector.tsx @@ -1,5 +1,5 @@ import React, { useState } from "react"; -import { SignTxPayload } from "@/api/message"; +import { SignTxPayload } from "@/api/background/handlers/kaspa/utils"; import TransactionDetailsBox from "@/components/screens/browser-api/sign/TransactionBox"; import ScriptItem from "@/components/screens/browser-api/sign/ScriptItem"; import { twMerge } from "tailwind-merge"; diff --git a/components/screens/browser-api/sign/SignConfirm.tsx b/components/screens/browser-api/sign/SignConfirm.tsx index 1e9d2aad..e5a7e796 100644 --- a/components/screens/browser-api/sign/SignConfirm.tsx +++ b/components/screens/browser-api/sign/SignConfirm.tsx @@ -1,4 +1,4 @@ -import { SignTxPayload } from "@/api/message"; +import { SignTxPayload } from "@/api/background/handlers/kaspa/utils"; import { NetworkType } from "@/contexts/SettingsContext.tsx"; import useWalletManager from "@/hooks/useWalletManager"; import { diff --git a/entrypoints/content.ts b/entrypoints/content.ts index fdac4010..2c184311 100644 --- a/entrypoints/content.ts +++ b/entrypoints/content.ts @@ -2,6 +2,7 @@ import { ApiRequestSchema, ApiRequestWithHostSchema } from "@/api/message"; import { EthereumAccountsChangedListener } from "@/api/content-script/listeners/ethereum/accountsChanged"; import { watchSettingsUpdated } from "@/api/content-script/listeners/settings-updated.ts"; import { watchWalletSettingsUpdated } from "@/api/content-script/listeners/wallet-settings-updated.ts"; +import { ApiUtils } from "@/api/background/utils"; export default defineContentScript({ matches: ["*://*/*"], @@ -11,6 +12,12 @@ export default defineContentScript({ keepInDom: true, }); + // Emit the kastle_installed event to the page to notify that the extension is installed + window.postMessage( + ApiUtils.createApiResponse("kastle_installed", []), + window.location.origin, + ); + // TODO: implement tabs connections manager and authentication for listeners new EthereumAccountsChangedListener().start(); From 5a9a6e7973299f86492df5133ab74ac483aa32c1 Mon Sep 17 00:00:00 2001 From: Paul Chen Date: Mon, 14 Apr 2025 18:06:56 +0800 Subject: [PATCH 7/7] fix: remove unnecessary console log and ensure window closes after connection attempt --- components/screens/browser-api/ConnectConfirm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/screens/browser-api/ConnectConfirm.tsx b/components/screens/browser-api/ConnectConfirm.tsx index a37f9604..747e9bdc 100644 --- a/components/screens/browser-api/ConnectConfirm.tsx +++ b/components/screens/browser-api/ConnectConfirm.tsx @@ -47,7 +47,6 @@ export default function ConnectConfirm() { const walletConnections = settings.walletConnections ?? {}; const targetNetwork = (network ?? settings.networkId) as NetworkType; - console.log(targetNetwork, settings.networkId); const connections = walletConnections[selectedWalletId]?.[selectedAccountIndex]?.[ @@ -85,6 +84,7 @@ export default function ConnectConfirm() { ), ); } finally { + window.close(); } };