Skip to content

Commit 2a85a36

Browse files
authored
Merge pull request #240 from argentlabs/develop
Release latest
2 parents 8949c94 + 3ab5926 commit 2a85a36

File tree

12 files changed

+182
-10
lines changed

12 files changed

+182
-10
lines changed

package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "starknetkit",
3-
"version": "3.2.0",
3+
"version": "3.4.1",
44
"repository": "github:argentlabs/starknetkit",
55
"private": false,
66
"browser": {
@@ -62,6 +62,11 @@
6262
"import": "./dist/keplr.js",
6363
"require": "./dist/keplr.cjs"
6464
},
65+
"./keplrMobile": {
66+
"types": "./dist/keplrMobile.d.ts",
67+
"import": "./dist/keplrMobile.js",
68+
"require": "./dist/keplrMobile.cjs"
69+
},
6570
"./fordefi": {
6671
"types": "./dist/fordefi.d.ts",
6772
"import": "./dist/fordefi.js",
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const KEPLR_MOBILE_APP_ICON = `<svg width="32" height="32" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
2+
<path d="M0 64C0 41.5979 0 30.3969 4.35974 21.8404C8.19467 14.3139 14.3139 8.19467 21.8404 4.35974C30.3969 0 41.5979 0 64 0C86.4021 0 97.6031 0 106.16 4.35974C113.686 8.19467 119.805 14.3139 123.64 21.8404C128 30.3969 128 41.5979 128 64C128 86.4021 128 97.6031 123.64 106.16C119.805 113.686 113.686 119.805 106.16 123.64C97.6031 128 86.4021 128 64 128C41.5979 128 30.3969 128 21.8404 123.64C14.3139 119.805 8.19467 113.686 4.35974 106.16C0 97.6031 0 86.4021 0 64Z" fill="#14AFEB"/>
3+
<path d="M66.6672 41.3438C67.3936 48.7672 67.7565 52.4791 69.7022 55.201C70.5359 56.3673 71.5642 57.3817 72.7418 58.1994C75.4899 60.1076 79.2063 60.4202 86.6387 61.0451L89.7812 61.3091V66.6909L86.6387 66.9549C79.2063 67.5798 75.4899 67.8924 72.7418 69.8006C71.5642 70.6183 70.5359 71.6327 69.7022 72.799C67.7565 75.5209 67.3936 79.2328 66.6672 86.6562H61.3328C60.6064 79.2328 60.2435 75.5209 58.2978 72.799C57.4641 71.6327 56.4358 70.6183 55.2582 69.8006C52.5101 67.8924 48.7937 67.5798 41.3613 66.9549L38.2187 66.6909V61.3091L41.3613 61.0451C48.7937 60.4202 52.5101 60.1076 55.2582 58.1994C56.4358 57.3817 57.4641 56.3673 58.2978 55.201C60.2435 52.4791 60.6064 48.7672 61.3328 41.3438H66.6672Z" fill="white"/>
4+
<path fill-rule="evenodd" clip-rule="evenodd" d="M64 14C105.175 14 114 22.825 114 64C114 105.175 105.175 114 64 114C22.825 114 14 105.175 14 64C14 22.825 22.825 14 64 14ZM96.6782 31.2798C84.5687 19.1705 60.1124 23.9936 42.0533 42.0525C23.9941 60.1117 19.171 84.5687 31.2806 96.6782C43.3902 108.788 67.8464 103.965 85.9055 85.9055C103.965 67.8463 108.788 43.3894 96.6782 31.2798Z" fill="white"/>
5+
</svg>`
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export const isInKeplrMobileAppBrowser = (): boolean => {
2+
if (typeof window === "undefined") {
3+
return false
4+
}
5+
6+
const userAgent = navigator.userAgent
7+
const isKeplrMobileApp = userAgent.includes("KeplrWalletMobile")
8+
9+
if (!isKeplrMobileApp) {
10+
return false
11+
}
12+
13+
return isKeplrMobileApp
14+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./inAppBrowser"
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import { type AccountChangeEventHandler } from "@starknet-io/get-starknet-core"
2+
import type {
3+
RequestFnCall,
4+
RpcMessage,
5+
RpcTypeToMessageMap,
6+
StarknetWindowObject,
7+
} from "@starknet-io/types-js"
8+
import type {
9+
AccountInterface,
10+
ProviderInterface,
11+
ProviderOptions,
12+
} from "starknet"
13+
import {
14+
Connector,
15+
type ConnectArgs,
16+
type ConnectorData,
17+
type ConnectorIcons,
18+
} from "../connector"
19+
import { Keplr } from "../injected/keplr"
20+
import { type InjectedConnectorOptions } from "../injected"
21+
import { KEPLR_MOBILE_APP_ICON } from "./constants"
22+
import { isInKeplrMobileAppBrowser } from "./helpers/inAppBrowser"
23+
24+
export class KeplrMobileBaseConnector extends Connector {
25+
private _wallet: StarknetWindowObject | null = null
26+
27+
constructor() {
28+
super()
29+
}
30+
31+
available(): boolean {
32+
return true
33+
}
34+
35+
async ready(): Promise<boolean> {
36+
// return true to be compatible with starknet-react
37+
// will need to be implemented
38+
return true
39+
}
40+
41+
get id(): string {
42+
return "keplrMobile"
43+
}
44+
45+
get name(): string {
46+
return "Keplr (mobile)"
47+
}
48+
49+
get icon(): ConnectorIcons {
50+
return {
51+
dark: KEPLR_MOBILE_APP_ICON,
52+
light: KEPLR_MOBILE_APP_ICON,
53+
}
54+
}
55+
56+
get wallet(): StarknetWindowObject {
57+
throw new Error("not implemented")
58+
}
59+
60+
async connect(_args: ConnectArgs = {}): Promise<ConnectorData> {
61+
await this.ensureWallet()
62+
63+
// will return empty data, connect will only open keplr mobile app
64+
// will require to implement the wallet connection
65+
return {
66+
account: "",
67+
chainId: BigInt(0),
68+
}
69+
}
70+
71+
async disconnect(): Promise<void> {
72+
throw new Error("not implemented")
73+
}
74+
75+
async account(
76+
_: ProviderOptions | ProviderInterface,
77+
): Promise<AccountInterface> {
78+
throw new Error("not implemented")
79+
}
80+
81+
async chainId(): Promise<bigint> {
82+
throw new Error("not implemented")
83+
}
84+
85+
async request<T extends RpcMessage["type"]>(
86+
call: RequestFnCall<T>,
87+
): Promise<RpcTypeToMessageMap[T]["result"]> {
88+
throw new Error("not implemented")
89+
}
90+
91+
// needed, methods required by starknet-react. Otherwise an exception is throwd
92+
async initEventListener(_: AccountChangeEventHandler) {
93+
throw new Error("not implemented")
94+
}
95+
96+
// needed, methods required by starknet-react. Otherwise an exception is throwd
97+
async removeEventListener(_: AccountChangeEventHandler) {
98+
throw new Error("not implemented")
99+
}
100+
101+
private async ensureWallet(): Promise<void> {
102+
window.open(
103+
`https://deeplink.keplr.app/web-browser?url=${encodeURIComponent(window.origin)}`,
104+
"_blank",
105+
)
106+
}
107+
}
108+
109+
export interface KeplrMobileConnectorInitParams {
110+
inAppBrowserOptions?: Omit<InjectedConnectorOptions, "id">
111+
}
112+
113+
export class KeplrMobileConnector {
114+
static init(params?: KeplrMobileConnectorInitParams): Connector {
115+
const { inAppBrowserOptions } = params || {}
116+
if (isInKeplrMobileAppBrowser()) {
117+
return new Keplr(inAppBrowserOptions)
118+
} else {
119+
return new KeplrMobileBaseConnector()
120+
}
121+
}
122+
}
123+
124+
export { isInKeplrMobileAppBrowser }

src/helpers/defaultConnectors.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { StarknetkitConnector } from "../connectors"
22
import { type ArgentMobileConnectorOptions } from "../connectors/argent/argentMobile"
33
import { BraavosMobileBaseConnector } from "../connectors/braavosMobile"
4+
import { KeplrMobileBaseConnector } from "../connectors/keplrMobile"
45
import { ControllerConnector } from "../connectors/controller"
56
import { Braavos } from "../connectors/injected/braavos"
67
import { Fordefi } from "../connectors/injected/fordefi"
@@ -40,6 +41,7 @@ export const defaultConnectors = (): StarknetkitConnector[] => {
4041

4142
if (isMobileDevice()) {
4243
defaultConnectors.push(new BraavosMobileBaseConnector())
44+
defaultConnectors.push(new KeplrMobileBaseConnector())
4345
}
4446

4547
return defaultConnectors

src/helpers/mapModalWallets.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export function getModalWallet(
5454
id: connector.id,
5555
icon: isCompound ? connectorOrCompoundConnector.icon : connector.icon,
5656
connector: connectorOrCompoundConnector,
57-
installed: true,
57+
installed: connector.id === "argentMobile",
5858
title:
5959
"title" in connector && isString(connector.title)
6060
? connector.title
@@ -156,7 +156,7 @@ export const mapModalWallets = ({
156156
id: discovery.id,
157157
icon: { light: discoveryIcon, dark: discoveryIcon },
158158
connector: _c,
159-
installed: false,
159+
installed: discovery.id === "argentMobile",
160160
download: downloads[storeVersion as keyof typeof downloads],
161161
downloads: downloads,
162162
}

src/main.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import type {
1414
StarknetkitConnector,
1515
ConnectorData,
1616
} from "./connectors"
17-
import { DEFAULT_WEBWALLET_URL } from "./connectors/webwallet/constants"
1817

1918
import { ArgentMobileBaseConnector } from "./connectors/argent/argentMobile"
2019
import { defaultConnectors } from "./helpers/defaultConnectors"
@@ -73,9 +72,6 @@ export const connect = async ({
7372
skipEmit = false,
7473
...restOptions
7574
}: ConnectOptionsWithConnectors | ConnectOptions): Promise<ModalResult> => {
76-
const { webWalletUrl = DEFAULT_WEBWALLET_URL, argentMobileOptions } =
77-
restOptions as ConnectOptions
78-
7975
const { connectors } = restOptions as ConnectOptionsWithConnectors
8076

8177
// force null in case it was disconnected from mobile app
@@ -248,6 +244,7 @@ export const connect = async ({
248244
},
249245
theme: modalTheme === "system" ? null : (modalTheme ?? null),
250246
modalWallets,
247+
discoveryWallets,
251248
},
252249
}) as unknown as ModalInstance // Prevents vite build errors
253250
})

src/modal/Modal.svelte

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script lang="ts">
22
import { onMount } from "svelte"
3+
import type { WalletProvider } from "@starknet-io/get-starknet-core"
34
45
import {
56
type Callback,
@@ -39,6 +40,7 @@
3940
return layout
4041
}
4142
43+
export let discoveryWallets: WalletProvider[]
4244
export let modalWallets: ModalWallet[] = []
4345
export let selectedWallet: ModalWallet | null = null
4446
$: selectedConnector =
@@ -98,7 +100,9 @@
98100
99101
if (modalWallets.length === 1) {
100102
try {
101-
await callback(modalWallets[0])
103+
setTimeout(() => {
104+
void callback(modalWallets[0])
105+
})
102106
} catch (e) {
103107
console.error(e)
104108
}
@@ -174,6 +178,8 @@
174178
extensionName={selectedWallet?.name.includes("Ready")
175179
? "Ready Wallet (formerly Argent)"
176180
: selectedConnector?.name}
181+
extensionId={selectedWallet?.id}
182+
discoveryWallets={discoveryWallets}
177183
/>
178184
{/if}
179185
</main>

src/modal/layouts/DownloadWallet/DownloadWallet.svelte

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script lang="ts">
2-
import { StoreVersion } from "../../../types/modal"
2+
import type { WalletProvider } from "@starknet-io/get-starknet-core"
3+
import type { StoreVersion } from "../../../types/modal"
34
45
import AppleIcon from "../../components/icons/brands/AppleIcon.svelte"
56
import PlayStore from "../../components/icons/brands/PlayStore.svelte"
@@ -16,9 +17,14 @@
1617
import HorizontalLine from "../../components/HorizontalLine.svelte"
1718
1819
export let isArgent: boolean = false
20+
export let extensionId: string = ""
1921
export let extensionName: string = ""
2022
export let store: StoreVersion | null
2123
export let storeLink: string | undefined
24+
export let discoveryWallets: WalletProvider[]
25+
26+
const discoveredWallet = discoveryWallets.find((w: WalletProvider) => w.id.toLowerCase() === extensionId.toLowerCase())
27+
const discoveredWalletDownloads = Object.entries(discoveredWallet?.downloads || {})
2228
2329
const storeData = {
2430
// @dev - Be mindful of name property length, it might break the UI
@@ -39,6 +45,7 @@
3945

4046
<section class="flex flex-col flex-grow justify-between">
4147
<div class="flex flex-col gap-2">
48+
<!-- Upon removal of Argent mobile, remove and code else `!isArgent` if case from line 84 -->
4249
{#if isArgent}
4350
<ArgentDownloadItem
4451
title="Ready mobile"
@@ -80,6 +87,16 @@
8087
{/if}
8188
</svelte:fragment>
8289
</ArgentDownloadItem>
90+
{:else if !isArgent}
91+
<p class="text-[16px] text-primary">
92+
<span class="capitalize">{extensionName}</span> is not available on your browser.<br/><br/>
93+
{#if discoveredWalletDownloads.length > 0}
94+
Try on other browsers:{" "}
95+
{#each discoveredWalletDownloads as discovery, i}
96+
<Link as="a" className="capitalize" href={discovery[1]}>{discovery[0]}</Link>{i + 1 === discoveredWalletDownloads.length ? "." : ", "}
97+
{/each}
98+
{/if}
99+
</p>
83100
{/if}
84101
</div>
85102

0 commit comments

Comments
 (0)