diff --git a/package.json b/package.json index ab2b060..95abbbd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "starknetkit", - "version": "3.2.0", + "version": "3.4.0", "repository": "github:argentlabs/starknetkit", "private": false, "browser": { @@ -62,6 +62,11 @@ "import": "./dist/keplr.js", "require": "./dist/keplr.cjs" }, + "./keplrMobile": { + "types": "./dist/keplrMobile.d.ts", + "import": "./dist/keplrMobile.js", + "require": "./dist/keplrMobile.cjs" + }, "./fordefi": { "types": "./dist/fordefi.d.ts", "import": "./dist/fordefi.js", diff --git a/src/connectors/keplrMobile/constants.ts b/src/connectors/keplrMobile/constants.ts new file mode 100644 index 0000000..ef85ab9 --- /dev/null +++ b/src/connectors/keplrMobile/constants.ts @@ -0,0 +1,5 @@ +export const KEPLR_MOBILE_APP_ICON = ` + + + +` diff --git a/src/connectors/keplrMobile/helpers/inAppBrowser.ts b/src/connectors/keplrMobile/helpers/inAppBrowser.ts new file mode 100644 index 0000000..856534f --- /dev/null +++ b/src/connectors/keplrMobile/helpers/inAppBrowser.ts @@ -0,0 +1,14 @@ +export const isInKeplrMobileAppBrowser = (): boolean => { + if (typeof window === "undefined") { + return false + } + + const userAgent = navigator.userAgent + const isKeplrMobileApp = userAgent.includes("KeplrWalletMobile") + + if (!isKeplrMobileApp) { + return false + } + + return isKeplrMobileApp +} diff --git a/src/connectors/keplrMobile/helpers/index.ts b/src/connectors/keplrMobile/helpers/index.ts new file mode 100644 index 0000000..bfe3f22 --- /dev/null +++ b/src/connectors/keplrMobile/helpers/index.ts @@ -0,0 +1 @@ +export * from "./inAppBrowser" diff --git a/src/connectors/keplrMobile/index.ts b/src/connectors/keplrMobile/index.ts new file mode 100644 index 0000000..b96891e --- /dev/null +++ b/src/connectors/keplrMobile/index.ts @@ -0,0 +1,124 @@ +import { type AccountChangeEventHandler } from "@starknet-io/get-starknet-core" +import type { + RequestFnCall, + RpcMessage, + RpcTypeToMessageMap, + StarknetWindowObject, +} from "@starknet-io/types-js" +import type { + AccountInterface, + ProviderInterface, + ProviderOptions, +} from "starknet" +import { + Connector, + type ConnectArgs, + type ConnectorData, + type ConnectorIcons, +} from "../connector" +import { Keplr } from "../injected/keplr" +import { type InjectedConnectorOptions } from "../injected" +import { KEPLR_MOBILE_APP_ICON } from "./constants" +import { isInKeplrMobileAppBrowser } from "./helpers/inAppBrowser" + +export class KeplrMobileBaseConnector extends Connector { + private _wallet: StarknetWindowObject | null = null + + constructor() { + super() + } + + available(): boolean { + return true + } + + async ready(): Promise { + // return true to be compatible with starknet-react + // will need to be implemented + return true + } + + get id(): string { + return "keplrMobile" + } + + get name(): string { + return "Keplr (mobile)" + } + + get icon(): ConnectorIcons { + return { + dark: KEPLR_MOBILE_APP_ICON, + light: KEPLR_MOBILE_APP_ICON, + } + } + + get wallet(): StarknetWindowObject { + throw new Error("not implemented") + } + + async connect(_args: ConnectArgs = {}): Promise { + await this.ensureWallet() + + // will return empty data, connect will only open keplr mobile app + // will require to implement the wallet connection + return { + account: "", + chainId: BigInt(0), + } + } + + async disconnect(): Promise { + throw new Error("not implemented") + } + + async account( + _: ProviderOptions | ProviderInterface, + ): Promise { + throw new Error("not implemented") + } + + async chainId(): Promise { + throw new Error("not implemented") + } + + async request( + call: RequestFnCall, + ): Promise { + throw new Error("not implemented") + } + + // needed, methods required by starknet-react. Otherwise an exception is throwd + async initEventListener(_: AccountChangeEventHandler) { + throw new Error("not implemented") + } + + // needed, methods required by starknet-react. Otherwise an exception is throwd + async removeEventListener(_: AccountChangeEventHandler) { + throw new Error("not implemented") + } + + private async ensureWallet(): Promise { + window.open( + `https://deeplink.keplr.app/web-browser?url=${encodeURIComponent(window.origin)}`, + "_blank", + ) + } +} + +export interface KeplrMobileConnectorInitParams { + inAppBrowserOptions?: Omit +} + +export class KeplrMobileConnector { + static init(params?: KeplrMobileConnectorInitParams): Connector { + const { inAppBrowserOptions } = params || {} + if (isInKeplrMobileAppBrowser()) { + return new Keplr(inAppBrowserOptions) + } else { + return new KeplrMobileBaseConnector() + } + } +} + +export { isInKeplrMobileAppBrowser } diff --git a/src/helpers/defaultConnectors.ts b/src/helpers/defaultConnectors.ts index 4ab5ee2..9bb2937 100644 --- a/src/helpers/defaultConnectors.ts +++ b/src/helpers/defaultConnectors.ts @@ -1,6 +1,7 @@ import type { StarknetkitConnector } from "../connectors" import { type ArgentMobileConnectorOptions } from "../connectors/argent/argentMobile" import { BraavosMobileBaseConnector } from "../connectors/braavosMobile" +import { KeplrMobileBaseConnector } from "../connectors/keplrMobile" import { ControllerConnector } from "../connectors/controller" import { Braavos } from "../connectors/injected/braavos" import { Fordefi } from "../connectors/injected/fordefi" @@ -40,6 +41,7 @@ export const defaultConnectors = (): StarknetkitConnector[] => { if (isMobileDevice()) { defaultConnectors.push(new BraavosMobileBaseConnector()) + defaultConnectors.push(new KeplrMobileBaseConnector()) } return defaultConnectors diff --git a/src/helpers/mapModalWallets.ts b/src/helpers/mapModalWallets.ts index ecd921c..4962d8f 100644 --- a/src/helpers/mapModalWallets.ts +++ b/src/helpers/mapModalWallets.ts @@ -54,7 +54,7 @@ export function getModalWallet( id: connector.id, icon: isCompound ? connectorOrCompoundConnector.icon : connector.icon, connector: connectorOrCompoundConnector, - installed: true, + installed: false, title: "title" in connector && isString(connector.title) ? connector.title diff --git a/src/main.ts b/src/main.ts index 4678bf4..6bac091 100644 --- a/src/main.ts +++ b/src/main.ts @@ -14,7 +14,6 @@ import type { StarknetkitConnector, ConnectorData, } from "./connectors" -import { DEFAULT_WEBWALLET_URL } from "./connectors/webwallet/constants" import { ArgentMobileBaseConnector } from "./connectors/argent/argentMobile" import { defaultConnectors } from "./helpers/defaultConnectors" @@ -73,9 +72,6 @@ export const connect = async ({ skipEmit = false, ...restOptions }: ConnectOptionsWithConnectors | ConnectOptions): Promise => { - const { webWalletUrl = DEFAULT_WEBWALLET_URL, argentMobileOptions } = - restOptions as ConnectOptions - const { connectors } = restOptions as ConnectOptionsWithConnectors // force null in case it was disconnected from mobile app @@ -248,6 +244,7 @@ export const connect = async ({ }, theme: modalTheme === "system" ? null : (modalTheme ?? null), modalWallets, + discoveryWallets, }, }) as unknown as ModalInstance // Prevents vite build errors }) diff --git a/src/modal/Modal.svelte b/src/modal/Modal.svelte index 2ade26f..3d99806 100644 --- a/src/modal/Modal.svelte +++ b/src/modal/Modal.svelte @@ -1,5 +1,6 @@