boolean,
- recentWalletName?: string
-) => {
- const { get } = getWallets()
- const windowWallets = get()
-
- const walletsData: Record
= {}
-
- presetList.forEach((wallet) => {
- walletsData[wallet.name] = {
- ...wallet,
- recent: recentWalletName === wallet.name
- }
- })
-
- windowWallets.filter(walletsFilterCb).forEach((wallet) => {
- walletsData[wallet.name] = {
- ...(walletsData?.[wallet.name] ?? {
- name: wallet.name,
- icon: wallet.icon,
- link: '',
- deeplink: null,
- recent: recentWalletName === wallet.name,
- walletType: 'hybrid'
- }),
- detected: true,
- standardWallet: wallet
- }
- })
-
- return Object.values(walletsData)
-}
diff --git a/sdk/packages/selector-base/src/index.ts b/sdk/packages/selector-base/src/index.ts
index 62a90dd8..e31ac429 100644
--- a/sdk/packages/selector-base/src/index.ts
+++ b/sdk/packages/selector-base/src/index.ts
@@ -1,7 +1,6 @@
-export * from './detection'
export * from './persistence'
export * from './utils'
export * from './types'
export * from './logoBase64'
export * from './modal'
-export { type XMLOptions } from '@nightlylabs/wallet-selector-modal'
\ No newline at end of file
+export { type XMLOptions } from '@nightlylabs/wallet-selector-modal'
diff --git a/sdk/packages/selector-base/src/modal.ts b/sdk/packages/selector-base/src/modal.ts
index 44daf443..1b3aa243 100644
--- a/sdk/packages/selector-base/src/modal.ts
+++ b/sdk/packages/selector-base/src/modal.ts
@@ -1,6 +1,9 @@
-import { type XMLOptions, type NightlySelector } from '@nightlylabs/wallet-selector-modal'
+import {
+ type XMLOptions,
+ type NightlySelector,
+ WalletSelectorItem
+} from '@nightlylabs/wallet-selector-modal'
import { type IWalletListItem, type NetworkData } from './types'
-import { isMobileBrowser } from './utils'
export class NightlyConnectSelectorModal {
_modal: NightlySelector | undefined
@@ -40,12 +43,13 @@ export class NightlyConnectSelectorModal {
}
set walletsList(list: IWalletListItem[]) {
- const filtered = list.filter((w) =>
- isMobileBrowser() ? w.walletType !== 'extension' : w.walletType !== 'mobile'
- )
- this._walletsList = filtered
+ this._walletsList = list
if (this._modal) {
- this._modal.selectorItems = filtered
+ this._modal.selectorItems = list.map((item) => ({
+ ...item,
+ icon: item.image.default,
+ link: item.homepage
+ })) as WalletSelectorItem[]
}
}
@@ -53,6 +57,10 @@ export class NightlyConnectSelectorModal {
if (this._modal && id) this._modal.sessionId = id
}
+ set timeoutError(error: string) {
+ if (this._modal && error) this._modal.timeoutError = error
+ }
+
createSelectorElement = (
variablesOverride?: object,
stylesOverride?: string,
@@ -65,7 +73,11 @@ export class NightlyConnectSelectorModal {
this._modal.relay = this._relay
this._modal.chainIcon = this._networkData.icon
this._modal.chainName = this._networkData.name
- this._modal.selectorItems = this.walletsList
+ this._modal.selectorItems = this.walletsList.map((item) => ({
+ ...item,
+ icon: item.image.default,
+ link: item.homepage
+ })) as WalletSelectorItem[]
})
}
diff --git a/sdk/packages/selector-base/src/types.ts b/sdk/packages/selector-base/src/types.ts
index 0a14a253..39676310 100644
--- a/sdk/packages/selector-base/src/types.ts
+++ b/sdk/packages/selector-base/src/types.ts
@@ -2,6 +2,8 @@ import { type AppBaseInitialize } from '@nightlylabs/nightly-connect-base'
import { type Deeplink } from '@nightlylabs/nightly-connect-base/dist/types/bindings/Deeplink'
import { type Wallet } from '@wallet-standard/core'
import { type WalletType } from '../../../bindings/WalletType'
+import { WalletMetadata } from '../../../bindings/WalletMetadata'
+export { type WalletMetadata } from '../../../bindings/WalletMetadata'
export interface Adapter {
connect: () => Promise
@@ -17,7 +19,11 @@ export interface MetadataWallet {
walletType: WalletType
}
-export interface IWalletListItem extends MetadataWallet {
+export interface IWalletListItem
+ extends Pick<
+ WalletMetadata,
+ 'name' | 'slug' | 'walletType' | 'mobile' | 'desktop' | 'image' | 'homepage'
+ > {
recent?: boolean
detected?: boolean
standardWallet?: Wallet
diff --git a/sdk/packages/selector-polkadot/package.json b/sdk/packages/selector-polkadot/package.json
index 014cd889..b1feef76 100644
--- a/sdk/packages/selector-polkadot/package.json
+++ b/sdk/packages/selector-polkadot/package.json
@@ -1,6 +1,6 @@
{
"name": "@nightlylabs/wallet-selector-polkadot",
- "version": "0.2.1",
+ "version": "0.2.2",
"description": "",
"type": "module",
"exports": {
@@ -25,10 +25,11 @@
"license": "ISC",
"dependencies": {
"@nightlylabs/nightly-connect-polkadot": "^0.0.15",
- "@nightlylabs/wallet-selector-base": "^0.3.1",
- "@polkadot/extension-inject": "0.46.5",
+ "@nightlylabs/wallet-selector-base": "^0.4.0",
"@polkadot/api": "10.10.1",
- "@wallet-standard/core": "^1.0.3"
+ "@polkadot/extension-inject": "0.46.5",
+ "@wallet-standard/core": "^1.0.3",
+ "eventemitter3": "^5.0.1"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^25.0.0",
diff --git a/sdk/packages/selector-polkadot/src/adapter.ts b/sdk/packages/selector-polkadot/src/adapter.ts
index 99b5a253..4ec9cb49 100644
--- a/sdk/packages/selector-polkadot/src/adapter.ts
+++ b/sdk/packages/selector-polkadot/src/adapter.ts
@@ -1,13 +1,11 @@
/* eslint-disable @typescript-eslint/no-empty-function */
-import {
- AppPolkadot,
- AppPolkadotInitialize,
- WalletMetadata
-} from '@nightlylabs/nightly-connect-polkadot'
+import { AppPolkadot, AppPolkadotInitialize } from '@nightlylabs/nightly-connect-polkadot'
import {
ConnectionOptions,
ConnectionType,
+ IWalletListItem,
NightlyConnectSelectorModal,
+ WalletMetadata,
XMLOptions,
clearRecentWalletForNetwork,
clearSessionIdForNetwork,
@@ -21,13 +19,24 @@ import {
} from '@nightlylabs/wallet-selector-base'
import { type Signer as InjectedSigner } from '@polkadot/api/types'
-import { type Injected } from '@polkadot/extension-inject/types'
+import { InjectedAccount, type Injected } from '@polkadot/extension-inject/types'
import { IPolkadotWalletListItem, getPolkadotWalletsList } from './detection'
import { networkToData, SupportedNetworks } from './utils'
+import EventEmitter from 'eventemitter3'
+
export type AppSelectorInitialize = Omit & {
network: SupportedNetworks
}
-export class NightlyConnectAdapter implements Injected {
+
+type NightlyConnectAdapterEvents = {
+ connect(publicKey: InjectedAccount[]): void
+ disconnect(): void
+}
+
+export class NightlyConnectAdapter
+ extends EventEmitter
+ implements Injected
+{
name = 'Nightly Connect'
url = 'https://nightly.app'
icon = logoBase64
@@ -50,6 +59,7 @@ export class NightlyConnectAdapter implements Injected {
private _loading: boolean
constructor(appInitData: AppSelectorInitialize, connectionOptions?: ConnectionOptions) {
+ super()
this._connecting = false
this._connected = false
this._appInitData = appInitData
@@ -181,7 +191,26 @@ export class NightlyConnectAdapter implements Injected {
metadataWallets,
getRecentWalletForNetwork(adapter.network)?.walletName ?? undefined
)
+ // Add event listener for userConnected
+ app.on('userConnected', async () => {
+ try {
+ persistRecentWalletForNetwork(adapter.network, {
+ walletName: adapter._chosenMobileWalletName || '',
+ walletType: ConnectionType.Nightly
+ })
+ if (!adapter._app || adapter._app.accounts.activeAccounts.length <= 0) {
+ adapter._connected = false
+ // If user does not pass any accounts, we should disconnect
+ adapter.disconnect()
+ return
+ }
+ adapter._connected = true
+ adapter.emit('connect', await adapter.accounts.get())
+ } catch {
+ adapter.disconnect()
+ }
+ })
return adapter
}
@@ -212,7 +241,7 @@ export class NightlyConnectAdapter implements Injected {
if (!adapter._connectionOptions.disableModal) {
adapter._modal = new NightlyConnectSelectorModal(
- adapter.walletsList,
+ adapter.walletsList as IWalletListItem[],
appInitData.url ?? 'https://nc2.nightly.app',
networkToData(adapter.network),
anchorRef,
@@ -235,6 +264,26 @@ export class NightlyConnectAdapter implements Injected {
)
adapter._loading = false
+ // Add event listener for userConnected
+ app.on('userConnected', async () => {
+ try {
+ persistRecentWalletForNetwork(adapter.network, {
+ walletName: adapter._chosenMobileWalletName || '',
+ walletType: ConnectionType.Nightly
+ })
+
+ if (!adapter._app || adapter._app.accounts.activeAccounts.length <= 0) {
+ adapter._connected = false
+ // If user does not pass any accounts, we should disconnect
+ adapter.disconnect()
+ return
+ }
+ adapter._connected = true
+ adapter.emit('connect', await adapter.accounts.get())
+ } catch {
+ adapter.disconnect()
+ }
+ })
})
.catch(() => {
adapter._loading = false
@@ -309,21 +358,21 @@ export class NightlyConnectAdapter implements Injected {
throw new Error('Wallet not found')
}
- if (wallet.deeplink === null) {
+ if (wallet.mobile === null) {
throw new Error('Deeplink not found')
}
// If we have a native deeplink, we should use it
- if (wallet.deeplink.native !== null) {
+ if (wallet.mobile.native !== null) {
this._app.connectDeeplink({
walletName: wallet.name,
- url: wallet.deeplink.native
+ url: wallet.mobile.native
})
this._chosenMobileWalletName = walletName
triggerConnect(
- wallet.deeplink.native,
+ wallet.mobile.native,
this._app.sessionId,
this._appInitData.url ?? 'https://nc2.nightly.app'
)
@@ -331,16 +380,16 @@ export class NightlyConnectAdapter implements Injected {
}
// If we have a universal deeplink, we should use it
- if (wallet.deeplink.universal !== null) {
+ if (wallet.mobile.universal !== null) {
this._app.connectDeeplink({
walletName: wallet.name,
- url: wallet.deeplink.universal
+ url: wallet.mobile.universal
})
this._chosenMobileWalletName = walletName
triggerConnect(
- wallet.deeplink.universal,
+ wallet.mobile.universal,
this._app.sessionId,
this._appInitData.url ?? 'https://nc2.nightly.app'
)
@@ -348,8 +397,8 @@ export class NightlyConnectAdapter implements Injected {
}
// Fallback to redirecting to app browser
// aka browser inside the app
- if (!wallet.deeplink.redirectToAppBrowser) {
- const redirectToAppBrowser = wallet.deeplink.redirectToAppBrowser
+ if (!wallet.mobile.redirectToAppBrowser) {
+ const redirectToAppBrowser = wallet.mobile.redirectToAppBrowser
if (redirectToAppBrowser !== null && redirectToAppBrowser.indexOf('{{url}}') > -1) {
const url = redirectToAppBrowser.replace(
'{{url}}',
@@ -407,6 +456,7 @@ export class NightlyConnectAdapter implements Injected {
this._connected = true
this._connecting = false
+ this.emit('connect', await this.accounts.get())
persistRecentWalletForNetwork(this.network, {
walletName,
@@ -458,6 +508,7 @@ export class NightlyConnectAdapter implements Injected {
try {
this._connected = true
this._connecting = false
+ this.emit('connect', await this.accounts.get())
resolve()
return
} catch (error) {
@@ -484,11 +535,33 @@ export class NightlyConnectAdapter implements Injected {
metadataWallets,
getRecentWalletForNetwork(this.network)?.walletName ?? undefined
)
+
+ // Add event listener for userConnected
+ app.on('userConnected', async () => {
+ try {
+ persistRecentWalletForNetwork(this.network, {
+ walletName: this._chosenMobileWalletName || '',
+ walletType: ConnectionType.Nightly
+ })
+
+ if (!this._app || this._app.accounts.activeAccounts.length <= 0) {
+ this._connected = false
+ // If user does not pass any accounts, we should disconnect
+ this.disconnect()
+ return
+ }
+ this._connected = true
+ this.emit('connect', await this.accounts.get())
+ } catch {
+ this.disconnect()
+ }
+ })
this._loading = false
})
.catch(() => {
this._loading = false
- throw new Error('Failed to initialize adapter')
+ reject('Failed to initialize adapter')
+ return
})
}
// Interval that checks if app has connected
@@ -513,8 +586,12 @@ export class NightlyConnectAdapter implements Injected {
) {
this.connectToMobileWallet(walletName)
} else {
- await this.connectToStandardWallet(walletName)
- resolve()
+ try {
+ await this.connectToStandardWallet(walletName)
+ resolve()
+ } catch (error) {
+ reject(error)
+ }
}
})
@@ -526,26 +603,20 @@ export class NightlyConnectAdapter implements Injected {
// Clear interval if app is connected
clearInterval(loadingInterval)
if (this._modal) this._modal.sessionId = this._app.sessionId
- this._app.on('userConnected', () => {
+ // We already have hook for userConnected
+ // This is just for resolving promise
+ this._app.on('userConnected', async () => {
try {
- persistRecentWalletForNetwork(this.network, {
- walletName: this._chosenMobileWalletName || '',
- walletType: ConnectionType.Nightly
- })
-
if (!this._app || this._app.accounts.activeAccounts.length <= 0) {
- this._connecting = false
- this._connected = false
- // If user does not pass any accounts, we should disconnect
- this.disconnect()
- return
+ reject(new Error('No accounts found'))
}
this._connected = true
- this._connecting = false
this._modal?.closeModal()
resolve()
- } catch {
- this.disconnect()
+ } catch (error) {
+ reject(error)
+ } finally {
+ this._connecting = false
}
})
return
@@ -555,7 +626,7 @@ export class NightlyConnectAdapter implements Injected {
if (checks > 500) {
clearInterval(loadingInterval)
// reject(new Error('Connecting takes too long'))
- // TODO we need to have a way to show error on modal
+ if (this._modal) this._modal.timeoutError = 'Connecting is taking too long'
}
}, 10)
}
@@ -563,8 +634,6 @@ export class NightlyConnectAdapter implements Injected {
} catch (error: any) {
this._connecting = false
reject(error)
- } finally {
- this._connecting = false
}
}
@@ -599,11 +668,12 @@ export class NightlyConnectAdapter implements Injected {
getRecentWalletForNetwork(this.network)?.walletName ?? undefined
)
if (this._modal) {
- this._modal.walletsList = this.walletsList
+ this._modal.walletsList = this.walletsList as IWalletListItem[]
}
this._connected = false
} finally {
this._connecting = false
+ this.emit('disconnect')
}
}
}
diff --git a/sdk/packages/selector-polkadot/src/detection.ts b/sdk/packages/selector-polkadot/src/detection.ts
index 829a04aa..30615deb 100644
--- a/sdk/packages/selector-polkadot/src/detection.ts
+++ b/sdk/packages/selector-polkadot/src/detection.ts
@@ -1,8 +1,8 @@
-import { type Injected, type InjectedExtension } from '@polkadot/extension-inject/types'
-import { type WalletIcon } from '@wallet-standard/core'
+import { Injected, InjectedExtension } from '@polkadot/extension-inject/types'
+import { WalletIcon } from '@wallet-standard/core'
import { appToIcon } from './tempIcons'
-import { IWalletListItem } from '@nightlylabs/wallet-selector-base'
-import { WalletMetadata } from '@nightlylabs/nightly-connect-polkadot'
+import { WalletMetadata } from '@nightlylabs/wallet-selector-base'
+
export interface PolkadotWalletInjected {
// Default Polkadot standard
connect?: (origin: string) => Promise // Is this even used ?
@@ -32,7 +32,13 @@ export const getPolkadotWallets = (): PolkadotWalletInjected[] => {
}
}
-export interface IPolkadotWalletListItem extends Omit {
+export interface IPolkadotWalletListItem
+ extends Pick<
+ WalletMetadata,
+ 'name' | 'slug' | 'walletType' | 'mobile' | 'desktop' | 'image' | 'homepage'
+ > {
+ recent?: boolean
+ detected?: boolean
injectedWallet?: PolkadotWalletInjected
}
@@ -43,12 +49,7 @@ export const getPolkadotWalletsList = (presetList: WalletMetadata[], recentWalle
presetList.forEach((wallet) => {
walletsData[wallet.slug.toLocaleLowerCase()] = {
- slug: wallet.slug,
- name: wallet.name,
- icon: wallet.image.default,
- deeplink: wallet.mobile,
- link: wallet.homepage,
- walletType: wallet.walletType,
+ ...wallet,
recent: recentWalletName === wallet.name
}
})
@@ -57,48 +58,42 @@ export const getPolkadotWalletsList = (presetList: WalletMetadata[], recentWalle
// by namespace
if (walletsData[wallet.slug.toLocaleLowerCase()]) {
walletsData[wallet.slug.toLocaleLowerCase()] = {
- ...(walletsData?.[wallet.slug.toLocaleLowerCase()] ?? {
- name: wallet.name,
- icon: wallet.icon,
- link: '',
- deeplink: null,
- recent: recentWalletName === wallet.name,
- walletType: 'hybrid'
- }),
+ ...walletsData?.[wallet.slug.toLocaleLowerCase()],
+ recent: recentWalletName === wallet.name,
detected: true,
- injectedWallet: wallet
+ injectedWallet: wallet,
+ walletType: 'hybrid'
}
- continue
}
// Check if wallet is already in the list
// by name
- if (walletsData[wallet.name.toLocaleLowerCase()]) {
+ else if (walletsData[wallet.name.toLocaleLowerCase()]) {
walletsData[wallet.name.toLocaleLowerCase()] = {
- ...(walletsData?.[wallet.name.toLocaleLowerCase()] ?? {
- name: wallet.name,
- icon: wallet.icon,
- link: '',
- deeplink: null,
- recent: recentWalletName === wallet.name,
- walletType: 'hybrid'
- }),
+ ...walletsData[wallet.name.toLocaleLowerCase()],
+ recent: recentWalletName === wallet.name,
detected: true,
- injectedWallet: wallet
+ injectedWallet: wallet,
+ walletType: 'hybrid'
+ }
+ } else
+ walletsData[wallet.name.toLocaleLowerCase()] = {
+ slug: wallet.name,
+ name: wallet.name,
+ image: {
+ default: wallet.icon as string,
+ sm: wallet.icon as string,
+ md: wallet.icon as string,
+ lg: wallet.icon as string
+ },
+ desktop: null,
+ mobile: null,
+ recent: recentWalletName === wallet.name,
+ detected: true,
+ injectedWallet: wallet,
+ walletType: 'hybrid',
+ homepage: 'https://nightly.app/download'
}
- continue
- }
- walletsData[wallet.name.toLocaleLowerCase()] = {
- slug: wallet.name,
- name: wallet.name,
- icon: wallet.icon as string,
- link: '',
- deeplink: null,
- recent: recentWalletName === wallet.name,
- detected: true,
- injectedWallet: wallet,
- walletType: 'hybrid'
- }
}
return Object.values(walletsData)
diff --git a/sdk/packages/selector-solana/package.json b/sdk/packages/selector-solana/package.json
index bed9c9cb..a63cdc6b 100644
--- a/sdk/packages/selector-solana/package.json
+++ b/sdk/packages/selector-solana/package.json
@@ -1,6 +1,6 @@
{
"name": "@nightlylabs/wallet-selector-solana",
- "version": "0.2.7",
+ "version": "0.3.0",
"description": "",
"type": "module",
"exports": {
@@ -25,7 +25,7 @@
"license": "ISC",
"dependencies": {
"@nightlylabs/nightly-connect-solana": "^0.0.29",
- "@nightlylabs/wallet-selector-base": "^0.2.4",
+ "@nightlylabs/wallet-selector-base": "^0.4.0",
"@solana/wallet-adapter-base": "^0.9.22",
"@solana/wallet-standard": "^1.0.2",
"@solana/web3.js": "^1.77.2",
@@ -41,4 +41,4 @@
"tslib": "^2.5.3",
"typescript": "^5.1.3"
}
-}
\ No newline at end of file
+}
diff --git a/sdk/packages/selector-solana/src/adapter.ts b/sdk/packages/selector-solana/src/adapter.ts
index 18f1e848..911c0c62 100644
--- a/sdk/packages/selector-solana/src/adapter.ts
+++ b/sdk/packages/selector-solana/src/adapter.ts
@@ -1,26 +1,27 @@
import { AppSolana, SOLANA_NETWORK } from '@nightlylabs/nightly-connect-solana'
import {
AppInitData,
- clearRecentStandardWalletForNetwork,
+ clearRecentWalletForNetwork,
clearSessionIdForNetwork,
- getRecentStandardWalletForNetwork,
- getWalletsList,
+ getRecentWalletForNetwork,
isMobileBrowser,
- IWalletListItem,
logoBase64,
- MetadataWallet,
NightlyConnectSelectorModal,
- persistRecentStandardWalletForNetwork,
- persistStandardConnectForNetwork,
- isStandardConnectedForNetwork,
+ persistRecentWalletForNetwork,
triggerConnect,
- persistStandardDisconnectForNetwork,
sleep,
- XMLOptions
+ XMLOptions,
+ ConnectionType,
+ ConnectionOptions,
+ defaultConnectionOptions,
+ WalletMetadata,
+ IWalletListItem
} from '@nightlylabs/wallet-selector-base'
import {
BaseMessageSignerWalletAdapter,
WalletAdapterCompatibleStandardWallet,
+ WalletAdapterEvents,
+ WalletError,
WalletName,
WalletNotConnectedError,
WalletNotReadyError,
@@ -32,7 +33,12 @@ import {
} from '@solana/wallet-adapter-base'
import { StandardWalletAdapter } from '@solana/wallet-standard'
import { PublicKey, Transaction, TransactionVersion, VersionedTransaction } from '@solana/web3.js'
-import { solanaWalletsFilter } from './detection'
+import { getSolanaWalletsList } from './detection'
+import { StandardEventsChangeProperties } from '@wallet-standard/core'
+
+type NightlyConnectAdapterEvents = WalletAdapterEvents & {
+ change(properties: StandardEventsChangeProperties): void
+}
export class NightlyConnectAdapter extends BaseMessageSignerWalletAdapter {
name = 'Nightly Connect' as WalletName<'Nightly Connect'>
@@ -55,31 +61,31 @@ export class NightlyConnectAdapter extends BaseMessageSignerWalletAdapter {
private _modal: NightlyConnectSelectorModal | undefined
private _appInitData: AppInitData
- private _eagerConnectForStandardWallets: boolean
- private _metadataWallets: MetadataWallet[] = []
+ private _metadataWallets: WalletMetadata[] = []
private _walletsList: IWalletListItem[] = []
private _chosenMobileWalletName: string | undefined
private _loading: boolean
- private _initOnConnect: boolean
+ private _connectionOptions: ConnectionOptions = defaultConnectionOptions
- constructor(
- appInitData: AppInitData,
- eagerConnectForStandardWallets?: boolean,
- initOnConnect = false
- ) {
+ constructor(appInitData: AppInitData, connectionOptions?: ConnectionOptions) {
super()
this._connecting = false
this._connected = false
this._publicKey = null
this._appInitData = appInitData
- this._eagerConnectForStandardWallets = !!eagerConnectForStandardWallets
+ if (appInitData.persistent !== false) this._appInitData.persistent = true
+
this._appSessionActive = false
this._loading = false
- this._initOnConnect = initOnConnect
+ this._connectionOptions = { ...this._connectionOptions, ...connectionOptions }
+ // If not persistent, clear session id
+ if (!this._appInitData.persistent) {
+ clearSessionIdForNetwork(SOLANA_NETWORK)
+ }
}
get connecting() {
@@ -109,26 +115,23 @@ export class NightlyConnectAdapter extends BaseMessageSignerWalletAdapter {
}
}
+ get sessionId() {
+ return this._app?.sessionId
+ }
+
+ get qrCode() {
+ return this._modal?.qrCode
+ }
+
public static initApp = async (
appInitData: AppInitData
- ): Promise<[AppSolana, MetadataWallet[]]> => {
+ ): Promise<[AppSolana, WalletMetadata[]]> => {
try {
return await Promise.all([
AppSolana.build(appInitData),
AppSolana.getWalletsMetadata(
`${appInitData.url ?? 'https://nc2.nightly.app'}/get_wallets_metadata`
)
- .then((list) =>
- list.map((wallet) => ({
- slug: wallet.slug,
- name: wallet.name,
- icon: wallet.image.default,
- deeplink: wallet.mobile,
- link: wallet.homepage,
- walletType: wallet.walletType
- }))
- )
- .catch(() => [] as MetadataWallet[])
])
} catch {
clearSessionIdForNetwork(SOLANA_NETWORK)
@@ -137,24 +140,40 @@ export class NightlyConnectAdapter extends BaseMessageSignerWalletAdapter {
AppSolana.getWalletsMetadata(
`${appInitData.url ?? 'https://nc2.nightly.app'}/get_wallets_metadata`
)
- .then((list) =>
- list.map((wallet) => ({
- slug: wallet.slug,
- name: wallet.name,
- icon: wallet.image.default,
- deeplink: wallet.mobile,
- link: wallet.homepage,
- walletType: wallet.walletType
- }))
- )
- .catch(() => [] as MetadataWallet[])
])
}
}
+ on(
+ event: T,
+ fn: NightlyConnectAdapterEvents[T] extends (...args: infer Args) => void
+ ? (...args: Args) => void
+ : never,
+ context?: any
+ ): this {
+ if (event === 'change') {
+ // TODO implement on change listener
+ return this
+ } else {
+ return super.on(event, fn, context)
+ }
+ }
+
+ emit(
+ event: T,
+ ...args: [publicKey: PublicKey] | [] | [error: WalletError] | [readyState: WalletReadyState]
+ ): boolean {
+ if (event === 'change') {
+ // TODO implement change event emitter
+ } else {
+ super.emit(event, ...args)
+ }
+ return true
+ }
+
public static build = async (
appInitData: AppInitData,
- eagerConnectForStandardWallets?: boolean,
+ connectionOptions?: ConnectionOptions,
anchorRef?: HTMLElement | null,
uiOverrides?: {
variablesOverride?: object
@@ -162,48 +181,69 @@ export class NightlyConnectAdapter extends BaseMessageSignerWalletAdapter {
qrConfigOverride?: Partial
}
) => {
- const adapter = new NightlyConnectAdapter(appInitData, eagerConnectForStandardWallets)
+ const adapter = new NightlyConnectAdapter(appInitData, connectionOptions)
if (adapter._readyState === WalletReadyState.Unsupported) {
return adapter
}
- adapter.walletsList = getWalletsList(
+ adapter.walletsList = getSolanaWalletsList(
[],
- solanaWalletsFilter,
- getRecentStandardWalletForNetwork(SOLANA_NETWORK) ?? undefined
+ getRecentWalletForNetwork(SOLANA_NETWORK)?.walletName ?? undefined
)
- adapter._modal = new NightlyConnectSelectorModal(
- adapter.walletsList,
- appInitData.url ?? 'https://nc2.nightly.app',
- {
- name: SOLANA_NETWORK,
- icon: 'https://assets.coingecko.com/coins/images/4128/small/solana.png'
- },
- anchorRef,
- uiOverrides?.variablesOverride,
- uiOverrides?.stylesOverride,
- uiOverrides?.qrConfigOverride
- )
+ if (!adapter._connectionOptions.disableModal)
+ adapter._modal = new NightlyConnectSelectorModal(
+ adapter.walletsList,
+ appInitData.url ?? 'https://nc2.nightly.app',
+ {
+ name: SOLANA_NETWORK,
+ icon: 'https://assets.coingecko.com/coins/images/4128/small/solana.png'
+ },
+ anchorRef,
+ uiOverrides?.variablesOverride,
+ uiOverrides?.stylesOverride,
+ uiOverrides?.qrConfigOverride
+ )
const [app, metadataWallets] = await NightlyConnectAdapter.initApp(appInitData)
adapter._app = app
adapter._metadataWallets = metadataWallets
- adapter.walletsList = getWalletsList(
+ adapter.walletsList = getSolanaWalletsList(
metadataWallets,
- solanaWalletsFilter,
- getRecentStandardWalletForNetwork(SOLANA_NETWORK) ?? undefined
+ getRecentWalletForNetwork(SOLANA_NETWORK)?.walletName ?? undefined
)
+ // Add event listener for userConnected
+ app.on('userConnected', async () => {
+ try {
+ persistRecentWalletForNetwork(SOLANA_NETWORK, {
+ walletName: adapter._chosenMobileWalletName || '',
+ walletType: ConnectionType.Nightly
+ })
+
+ if (!adapter._app || adapter._app.connectedPublicKeys.length <= 0) {
+ adapter._connected = false
+ // If user does not pass any accounts, we should disconnect
+ adapter.disconnect()
+ return
+ }
+ adapter._publicKey = adapter._app.connectedPublicKeys[0]
+ adapter._connected = true
+ adapter.emit('connect', adapter._publicKey)
+ } catch {
+ adapter.disconnect()
+ }
+ })
+
return adapter
}
public static buildLazy = (
appInitData: AppInitData,
- eagerConnectForStandardWallets?: boolean,
+ connectionOptions?: ConnectionOptions,
anchorRef?: HTMLElement | null,
uiOverrides?: {
variablesOverride?: object
@@ -211,226 +251,247 @@ export class NightlyConnectAdapter extends BaseMessageSignerWalletAdapter {
qrConfigOverride?: Partial
}
) => {
- const adapter = new NightlyConnectAdapter(appInitData, eagerConnectForStandardWallets)
+ const adapter = new NightlyConnectAdapter(appInitData, connectionOptions)
if (adapter._readyState === WalletReadyState.Unsupported) {
return adapter
}
- adapter.walletsList = getWalletsList(
+ adapter.walletsList = getSolanaWalletsList(
[],
- solanaWalletsFilter,
- getRecentStandardWalletForNetwork(SOLANA_NETWORK) ?? undefined
- )
-
- adapter._modal = new NightlyConnectSelectorModal(
- adapter.walletsList,
- appInitData.url ?? 'https://nc2.nightly.app',
- {
- name: SOLANA_NETWORK,
- icon: 'https://assets.coingecko.com/coins/images/4128/small/solana.png'
- },
- anchorRef,
- uiOverrides?.variablesOverride,
- uiOverrides?.stylesOverride,
- uiOverrides?.qrConfigOverride
+ getRecentWalletForNetwork(SOLANA_NETWORK)?.walletName ?? undefined
)
- adapter._loading = true
-
- NightlyConnectAdapter.initApp(appInitData).then(([app, metadataWallets]) => {
- adapter._app = app
+ // Fetch wallets from registry
+ adapter.fetchWalletsFromRegistry().then((metadataWallets) => {
adapter._metadataWallets = metadataWallets
- adapter.walletsList = getWalletsList(
+ adapter.walletsList = getSolanaWalletsList(
metadataWallets,
- solanaWalletsFilter,
- getRecentStandardWalletForNetwork(SOLANA_NETWORK) ?? undefined
+ getRecentWalletForNetwork(SOLANA_NETWORK)?.walletName ?? undefined
)
-
- adapter._loading = false
})
- return adapter
- }
+ if (!adapter._connectionOptions.disableModal)
+ adapter._modal = new NightlyConnectSelectorModal(
+ adapter.walletsList,
+ appInitData.url ?? 'https://nc2.nightly.app',
+ {
+ name: SOLANA_NETWORK,
+ icon: 'https://assets.coingecko.com/coins/images/4128/small/solana.png'
+ },
+ anchorRef,
+ uiOverrides?.variablesOverride,
+ uiOverrides?.stylesOverride,
+ uiOverrides?.qrConfigOverride
+ )
- public static buildWithInitOnConnect = (
- appInitData: AppInitData,
- eagerConnectForStandardWallets?: boolean,
- anchorRef?: HTMLElement | null,
- uiOverrides?: {
- variablesOverride?: object
- stylesOverride?: string
- qrConfigOverride?: Partial
- }
- ) => {
- const adapter = new NightlyConnectAdapter(appInitData, eagerConnectForStandardWallets, true)
+ // If init on connect is not enabled, we should initialize app
+ if (!adapter._connectionOptions.initOnConnect) {
+ adapter._loading = true
- if (adapter._readyState === WalletReadyState.Unsupported) {
- return adapter
- }
+ NightlyConnectAdapter.initApp(appInitData)
+ .then(([app, metadataWallets]) => {
+ adapter._app = app
+ adapter._metadataWallets = metadataWallets
- adapter.walletsList = getWalletsList(
- [],
- solanaWalletsFilter,
- getRecentStandardWalletForNetwork(SOLANA_NETWORK) ?? undefined
- )
+ adapter.walletsList = getSolanaWalletsList(
+ metadataWallets,
+ getRecentWalletForNetwork(SOLANA_NETWORK)?.walletName ?? undefined
+ )
- adapter._modal = new NightlyConnectSelectorModal(
- adapter.walletsList,
- appInitData.url ?? 'https://nc2.nightly.app',
- {
- name: SOLANA_NETWORK,
- icon: 'https://assets.coingecko.com/coins/images/4128/small/solana.png'
- },
- anchorRef,
- uiOverrides?.variablesOverride,
- uiOverrides?.stylesOverride,
- uiOverrides?.qrConfigOverride
- )
+ // Add event listener for userConnected
+ app.on('userConnected', async () => {
+ try {
+ persistRecentWalletForNetwork(SOLANA_NETWORK, {
+ walletName: adapter._chosenMobileWalletName || '',
+ walletType: ConnectionType.Nightly
+ })
+
+ if (!adapter._app || adapter._app.connectedPublicKeys.length <= 0) {
+ adapter._connected = false
+ // If user does not pass any accounts, we should disconnect
+ adapter.disconnect()
+ return
+ }
+ adapter._publicKey = adapter._app.connectedPublicKeys[0]
+ adapter._connected = true
+ adapter.emit('connect', adapter._publicKey)
+ } catch {
+ adapter.disconnect()
+ }
+ })
+
+ adapter._loading = false
+ })
+ .catch(() => {
+ adapter._loading = false
+ throw new Error('Failed to initialize adapter')
+ })
+ }
return adapter
}
+ // Checks if we can restore user session
canEagerConnect = async () => {
- // utility for case if somebody wants to fire connect asap, but doesn't want to show modal if e. g. there was no user connected on the device yet
- if (this._loading) {
- for (let i = 0; i < 200; i++) {
- await sleep(10)
+ // If eager connect is disabled, we can't eager connect
+ if (this._connectionOptions.disableEagerConnect) return false
- if (!this._loading) {
- break
- }
- }
- }
-
- if (this._loading) {
- false
- }
+ // Get recent wallet for network
+ const recentWallet = getRecentWalletForNetwork(SOLANA_NETWORK)
- if (this._app && this._app.hasBeenRestored() && this._app.connectedPublicKeys.length > 0) {
- return true
- }
+ // If there is no recent wallet, we can't eager connect
+ if (recentWallet === null) return false
+ // If we use wallet standard, we can eager connect
if (
- this._eagerConnectForStandardWallets &&
- getRecentStandardWalletForNetwork(SOLANA_NETWORK) !== null &&
- isStandardConnectedForNetwork(SOLANA_NETWORK)
+ recentWallet.walletName !== null &&
+ recentWallet.walletType === ConnectionType.WalletStandard
) {
return true
}
+ // If we use nightly connect we need to make sure app is restored
+ if (recentWallet.walletType === ConnectionType.Nightly) {
+ if (this._connectionOptions.initOnConnect) {
+ return false
+ }
+ // Wait for app to be restored
+ if (this._loading) {
+ for (let i = 0; i < 2000; i++) {
+ await sleep(10)
+ if (!this._loading) {
+ break
+ }
+ }
+ }
+
+ if (this._loading) {
+ return false
+ }
+
+ // If app is restored and has connected public keys, we can eager connect
+
+ if (this._app && this._app.hasBeenRestored() && this._app.connectedPublicKeys.length > 0) {
+ return true
+ }
+ }
return false
}
- eagerConnectDeeplink = () => {
- if (isMobileBrowser() && this._app) {
- const mobileWalletName = getRecentStandardWalletForNetwork(SOLANA_NETWORK)
- const wallet = this.walletsList.find((w) => w.name === mobileWalletName)
+ connectToMobileWallet = (walletName: string) => {
+ try {
+ if (this._modal) {
+ this._modal.setStandardWalletConnectProgress(true)
+ }
+
+ const wallet = this.walletsList.find((w) => w.name === walletName)
+
+ if (!this._app) {
+ throw new Error('Wallet not ready')
+ }
if (typeof wallet === 'undefined') {
- return
+ throw new Error('Wallet not found')
}
- if (wallet.deeplink === null) {
- return
+ if (wallet.mobile === null) {
+ throw new Error('Deeplink not found')
}
- if (wallet.deeplink.native !== null) {
+
+ // If we have a native deeplink, we should use it
+ if (wallet.mobile.native !== null) {
this._app.connectDeeplink({
walletName: wallet.name,
- url: wallet.deeplink.native
+ url: wallet.mobile.native
})
+
+ this._chosenMobileWalletName = walletName
+
+ triggerConnect(
+ wallet.mobile.native,
+ this._app.sessionId,
+ this._appInitData.url ?? 'https://nc2.nightly.app'
+ )
return
}
- if (wallet.deeplink.universal !== null) {
+
+ // If we have a universal deeplink, we should use it
+ if (wallet.mobile.universal !== null) {
this._app.connectDeeplink({
walletName: wallet.name,
- url: wallet.deeplink.universal
+ url: wallet.mobile.universal
})
- return
- }
- }
- }
-
- connectToMobileWallet = (walletName: string) => {
- if (this._modal) {
- this._modal.setStandardWalletConnectProgress(true)
- }
-
- const wallet = this.walletsList.find((w) => w.name === walletName)
-
- if (!this._app || typeof wallet === 'undefined') {
- return
- }
-
- if (wallet.deeplink === null) {
- return
- }
-
- if (wallet.deeplink.native !== null) {
- this._app.connectDeeplink({
- walletName: wallet.name,
- url: wallet.deeplink.native
- })
- this._chosenMobileWalletName = walletName
+ this._chosenMobileWalletName = walletName
- triggerConnect(
- wallet.deeplink.native,
- this._app.sessionId,
- this._appInitData.url ?? 'https://nc2.nightly.app'
- )
- return
- }
-
- if (wallet.deeplink.universal !== null) {
- this._app.connectDeeplink({
- walletName: wallet.name,
- url: wallet.deeplink.universal
- })
-
- this._chosenMobileWalletName = walletName
-
- triggerConnect(
- wallet.deeplink.universal,
- this._app.sessionId,
- this._appInitData.url ?? 'https://nc2.nightly.app'
- )
- return
+ triggerConnect(
+ wallet.mobile.universal,
+ this._app.sessionId,
+ this._appInitData.url ?? 'https://nc2.nightly.app'
+ )
+ return
+ }
+ } catch (err) {
+ clearRecentWalletForNetwork(SOLANA_NETWORK)
+ if (this._modal) {
+ this._modal.setStandardWalletConnectProgress(false)
+ }
+ throw err
}
}
- connectToStandardWallet = async (walletName: string, onSuccess: () => void) => {
+ // Generic connect to standard wallet
+ connectToStandardWallet = async (walletName: string) => {
try {
if (this._modal) {
this._modal.setStandardWalletConnectProgress(true)
}
- const wallet = this.walletsList.find((w) => w.name === walletName)
- if (typeof wallet?.standardWallet === 'undefined') {
+ const wallet = this.walletsList.find((w) => w.name === walletName)?.standardWallet
+ if (typeof wallet === 'undefined') {
+ if (this._modal) {
+ this._modal.setStandardWalletConnectProgress(false)
+ }
throw new Error('Wallet not found')
}
const adapter = new StandardWalletAdapter({
- wallet: wallet.standardWallet as WalletAdapterCompatibleStandardWallet
+ wallet: wallet as WalletAdapterCompatibleStandardWallet
})
await adapter.connect()
- persistRecentStandardWalletForNetwork(walletName, SOLANA_NETWORK)
- persistStandardConnectForNetwork(SOLANA_NETWORK)
+
this._innerStandardAdapter = adapter
this._publicKey = adapter.publicKey
+
this._connected = true
this._connecting = false
this.emit('connect', this._publicKey!)
+
+ persistRecentWalletForNetwork(SOLANA_NETWORK, {
+ walletName,
+ walletType: ConnectionType.WalletStandard
+ })
+
this._modal?.closeModal()
- onSuccess()
- } catch {
+ } catch (err) {
// clear recent wallet
- persistStandardDisconnectForNetwork(SOLANA_NETWORK)
+ clearRecentWalletForNetwork(SOLANA_NETWORK)
if (this._modal) {
this._modal.setStandardWalletConnectProgress(false)
}
+
+ throw err
+ }
+ }
+
+ connectToWallet = async (walletName: string) => {
+ if (isMobileBrowser() && !this.walletsList.find((w) => w.name === walletName)?.standardWallet) {
+ this.connectToMobileWallet(walletName)
+ } else {
+ await this.connectToStandardWallet(walletName)
}
}
@@ -438,132 +499,158 @@ export class NightlyConnectAdapter extends BaseMessageSignerWalletAdapter {
new Promise((resolve, reject) => {
const innerConnect = async () => {
try {
- if (this.connected || this.connecting) {
+ if (this.connecting) {
+ reject('Cannot connect while connecting')
+ return
+ }
+
+ if (this.connected) {
resolve()
return
}
if (this._readyState !== WalletReadyState.Loadable) throw new WalletNotReadyError()
- if (this._initOnConnect) {
- this._connecting = true
-
- if (!this._app) {
- try {
- const [app, metadataWallets] = await NightlyConnectAdapter.initApp(
- this._appInitData
- )
-
- this._app = app
- this._metadataWallets = metadataWallets
-
- this.walletsList = getWalletsList(
- metadataWallets,
- solanaWalletsFilter,
- getRecentStandardWalletForNetwork(SOLANA_NETWORK) ?? undefined
- )
- } catch {
- if (!this._app) {
- this._connecting = false
- throw new WalletNotReadyError()
- }
- }
+ const recentWallet = getRecentWalletForNetwork(SOLANA_NETWORK)
+ if (!this._connectionOptions.disableEagerConnect && recentWallet !== null) {
+ // Eager connect standard if possible
+ if (recentWallet.walletType === ConnectionType.WalletStandard) {
+ await this.connectToStandardWallet(recentWallet.walletName)
+ resolve()
+ return
}
- } else {
- if (this._loading) {
- // we do it to ensure proper connect flow in case if adapter is lazily built, but e. g. solana wallets selector uses its own eager connect
- for (let i = 0; i < 200; i++) {
- await sleep(10)
- if (!this._loading) {
- break
+ // Eager connect remote if possible
+ if (recentWallet.walletType === ConnectionType.Nightly) {
+ if (this._app?.hasBeenRestored() && this._app.connectedPublicKeys.length > 0) {
+ // Try to eager connect if session is restored
+ try {
+ this._publicKey = this._app.connectedPublicKeys[0]
+ this._connected = true
+ this._connecting = false
+ this._appSessionActive = true
+ this.emit('connect', this._publicKey)
+ resolve()
+ return
+ } catch (error) {
+ // If we fail because of whatever reason
+ // Reset session since it might be corrupted
+ const [app] = await NightlyConnectAdapter.initApp(this._appInitData)
+ this._app = app
}
}
-
- if (this._loading) {
- throw new WalletNotReadyError()
- }
- }
-
- if (!this._app) {
- throw new WalletNotReadyError()
}
-
- this._connecting = true
}
- if (this._app.hasBeenRestored() && this._app.connectedPublicKeys.length > 0) {
- // Try to eager connect if session is restored
- try {
- this.eagerConnectDeeplink()
- this._publicKey = this._app.connectedPublicKeys[0]
- this._connected = true
- this._connecting = false
- this._appSessionActive = true
- this.emit('connect', this._publicKey)
- resolve()
- return
- } catch (error) {
- // If we fail because of whatever reason
- // Reset session since it might be corrupted
- const [app] = await NightlyConnectAdapter.initApp(this._appInitData)
- this._app = app
- }
+ if (this._connectionOptions.disableModal) {
+ reject('Modal is disabled')
+ return
}
- const recentName = getRecentStandardWalletForNetwork(SOLANA_NETWORK)
- if (
- this._eagerConnectForStandardWallets &&
- recentName !== null &&
- isStandardConnectedForNetwork(SOLANA_NETWORK)
- ) {
- await this.connectToStandardWallet(recentName, resolve)
-
- if (this._connected) {
- return
- }
+ if (this._connectionOptions.initOnConnect) {
+ this._loading = true
+ NightlyConnectAdapter.initApp(this._appInitData)
+ .then(([app, metadataWallets]) => {
+ this._app = app
+ this._metadataWallets = metadataWallets
+ this.walletsList = getSolanaWalletsList(
+ metadataWallets,
+ getRecentWalletForNetwork(SOLANA_NETWORK)?.walletName ?? undefined
+ )
+ // Add event listener for userConnected
+ app.on('userConnected', async () => {
+ try {
+ persistRecentWalletForNetwork(SOLANA_NETWORK, {
+ walletName: this._chosenMobileWalletName || '',
+ walletType: ConnectionType.Nightly
+ })
+
+ if (!this._app || this._app.connectedPublicKeys.length <= 0) {
+ this._connected = false
+ // If user does not pass any accounts, we should disconnect
+ this.disconnect()
+ return
+ }
+ this._publicKey = this._app.connectedPublicKeys[0]
+ this._connected = true
+ this.emit('connect', this._publicKey)
+ } catch {
+ this.disconnect()
+ }
+ })
+ this._loading = false
+ })
+ .catch(() => {
+ this._loading = false
+ throw new Error('Failed to initialize adapter')
+ })
}
- this._app.on('userConnected', (e) => {
- try {
- if (this._chosenMobileWalletName) {
- persistRecentStandardWalletForNetwork(this._chosenMobileWalletName, SOLANA_NETWORK)
- } else {
- clearRecentStandardWalletForNetwork(SOLANA_NETWORK)
- }
- this._publicKey = new PublicKey(e.publicKeys[0])
- this._connected = true
- this._connecting = false
- this._appSessionActive = true
- this.emit('connect', this._publicKey)
- this._modal?.closeModal()
- resolve()
- } catch {
- this.disconnect()
- }
- })
+ // Interval that checks if app has connected
+ let loadingInterval: NodeJS.Timeout
+
if (this._modal) {
+ this._connecting = true
this._modal.onClose = () => {
+ clearInterval(loadingInterval)
if (this._connecting) {
this._connecting = false
-
const error = new WalletWindowClosedError()
-
this.emit('error', error)
reject(error)
}
}
- this._modal.openModal(this._app.sessionId, (walletName) => {
+ this._modal.openModal(this._app?.sessionId ?? undefined, async (walletName) => {
+ // If we are on mobile and wallet is not injected, we should connect to mobile wallet
if (
isMobileBrowser() &&
!this.walletsList.find((w) => w.name === walletName)?.standardWallet
) {
this.connectToMobileWallet(walletName)
} else {
- this.connectToStandardWallet(walletName, resolve)
+ try {
+ await this.connectToStandardWallet(walletName)
+ resolve()
+ } catch (error) {
+ reject(error)
+ }
}
})
+
+ // loop until app is connected or we timeout
+ let checks = 0
+ loadingInterval = setInterval(async (): Promise => {
+ checks++
+ if (this._app) {
+ // Clear interval if app is connected
+ clearInterval(loadingInterval)
+ if (this._modal) this._modal.sessionId = this._app.sessionId
+
+ this._app.on('userConnected', async () => {
+ try {
+ if (!this._app || this._app.connectedPublicKeys.length <= 0) {
+ reject(new Error('No accounts found'))
+ }
+ this._connected = true
+ this._modal?.closeModal()
+ resolve()
+ } catch (error) {
+ reject(error)
+ } finally {
+ this._connecting = false
+ }
+ })
+ return
+ }
+ // timeout after 5 seconds
+ if (checks > 500) {
+ clearInterval(loadingInterval)
+ // reject(new Error('Connecting takes too long'))
+ if (this._modal) this._modal.timeoutError = 'Connecting is taking too long'
+ }
+ }, 10)
}
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
this._connecting = false
@@ -576,6 +663,22 @@ export class NightlyConnectAdapter extends BaseMessageSignerWalletAdapter {
innerConnect()
})
+ fetchWalletsFromRegistry: () => Promise = async () => {
+ this._metadataWallets = await AppSolana.getWalletsMetadata(
+ `${this._appInitData.url ?? 'https://nc2.nightly.app'}/get_wallets_metadata`
+ )
+ return this._metadataWallets
+ }
+
+ fetchAllWallets = async () => {
+ const metadataWallets = await this.fetchWalletsFromRegistry()
+ this.walletsList = getSolanaWalletsList(
+ metadataWallets,
+ getRecentWalletForNetwork(SOLANA_NETWORK)?.walletName ?? undefined
+ )
+ return this.walletsList
+ }
+
disconnect = async () => {
if (this.connected) {
if (this._appSessionActive) {
@@ -584,6 +687,27 @@ export class NightlyConnectAdapter extends BaseMessageSignerWalletAdapter {
this._loading = true
try {
this._app = await AppSolana.build(this._appInitData)
+ // Add event listener for userConnected
+ this._app.on('userConnected', async () => {
+ try {
+ persistRecentWalletForNetwork(SOLANA_NETWORK, {
+ walletName: this._chosenMobileWalletName || '',
+ walletType: ConnectionType.Nightly
+ })
+
+ if (!this._app || this._app.connectedPublicKeys.length <= 0) {
+ this._connected = false
+ // If user does not pass any accounts, we should disconnect
+ this.disconnect()
+ return
+ }
+ this._publicKey = this._app.connectedPublicKeys[0]
+ this._connected = true
+ this.emit('connect', this._publicKey)
+ } catch {
+ this.disconnect()
+ }
+ })
} catch (err) {
console.log(err)
} finally {
@@ -593,12 +717,11 @@ export class NightlyConnectAdapter extends BaseMessageSignerWalletAdapter {
if (this._innerStandardAdapter) {
await this._innerStandardAdapter.disconnect()
this._innerStandardAdapter = undefined
- persistStandardDisconnectForNetwork(SOLANA_NETWORK)
+ clearRecentWalletForNetwork(SOLANA_NETWORK)
}
- this.walletsList = getWalletsList(
+ this.walletsList = getSolanaWalletsList(
this._metadataWallets,
- solanaWalletsFilter,
- getRecentStandardWalletForNetwork(SOLANA_NETWORK) ?? undefined
+ getRecentWalletForNetwork(SOLANA_NETWORK)?.walletName ?? undefined
)
this._publicKey = null
this._connected = false
diff --git a/sdk/packages/selector-solana/src/detection.ts b/sdk/packages/selector-solana/src/detection.ts
index 423a9b50..8ea2a19c 100644
--- a/sdk/packages/selector-solana/src/detection.ts
+++ b/sdk/packages/selector-solana/src/detection.ts
@@ -1,5 +1,52 @@
-import { type Wallet } from '@wallet-standard/core'
+import { getWallets, Wallet } from '@wallet-standard/core'
import { isWalletAdapterCompatibleStandardWallet } from '@solana/wallet-adapter-base'
+import { IWalletListItem, WalletMetadata } from '@nightlylabs/wallet-selector-base'
export const solanaWalletsFilter = (wallet: Wallet) =>
isWalletAdapterCompatibleStandardWallet(wallet)
+
+export const getSolanaWalletsList = (presetList: WalletMetadata[], recentWalletName?: string) => {
+ const { get } = getWallets()
+ const windowWallets = get()
+
+ const walletsData: Record = {}
+
+ presetList.forEach((wallet) => {
+ walletsData[wallet.name] = {
+ ...wallet,
+ recent: recentWalletName === wallet.name
+ }
+ })
+
+ windowWallets.filter(solanaWalletsFilter).forEach((wallet) => {
+ if (walletsData[wallet.name]) {
+ walletsData[wallet.name] = {
+ ...walletsData[wallet.name],
+ recent: recentWalletName === wallet.name,
+ detected: true,
+ standardWallet: wallet,
+ walletType: 'hybrid'
+ }
+ } else {
+ walletsData[wallet.name] = {
+ name: wallet.name,
+ image: {
+ default: wallet.icon as string,
+ lg: wallet.icon as string,
+ md: wallet.icon as string,
+ sm: wallet.icon as string
+ },
+ desktop: null,
+ homepage: 'https://nightly.app/download', // Fall back to nightly.app
+ mobile: null,
+ slug: wallet.name,
+ recent: recentWalletName === wallet.name,
+ walletType: 'hybrid',
+ detected: true,
+ standardWallet: wallet
+ }
+ }
+ })
+
+ return Object.values(walletsData)
+}
diff --git a/sdk/pnpm-lock.yaml b/sdk/pnpm-lock.yaml
index 2af1fe5a..8aad36e0 100644
--- a/sdk/pnpm-lock.yaml
+++ b/sdk/pnpm-lock.yaml
@@ -140,11 +140,14 @@ importers:
'@nightlylabs/nightly-connect-sui':
specifier: 0.0.29
version: link:../sui
+ '@nightlylabs/wallet-selector-base':
+ specifier: ^0.4.0
+ version: link:../../packages/selector-base
'@nightlylabs/wallet-selector-polkadot':
- specifier: 0.2.0
- version: 0.2.0(@polkadot/util@12.5.1)
+ specifier: 0.2.2
+ version: link:../../packages/selector-polkadot
'@nightlylabs/wallet-selector-solana':
- specifier: 0.2.7
+ specifier: 0.3.0
version: link:../../packages/selector-solana
'@nightlylabs/wallet-selector-sui':
specifier: 0.2.7
@@ -592,7 +595,7 @@ importers:
specifier: 0.0.27
version: link:../../apps/base
'@nightlylabs/wallet-selector-modal':
- specifier: 0.2.0
+ specifier: 0.2.1
version: link:../modal
'@wallet-standard/core':
specifier: ^1.0.3
@@ -632,7 +635,7 @@ importers:
specifier: ^0.0.15
version: link:../../apps/polkadot
'@nightlylabs/wallet-selector-base':
- specifier: ^0.3.1
+ specifier: ^0.4.0
version: link:../selector-base
'@polkadot/api':
specifier: 10.10.1
@@ -643,6 +646,9 @@ importers:
'@wallet-standard/core':
specifier: ^1.0.3
version: 1.0.3
+ eventemitter3:
+ specifier: ^5.0.1
+ version: 5.0.1
devDependencies:
'@rollup/plugin-commonjs':
specifier: ^25.0.0
@@ -675,8 +681,8 @@ importers:
specifier: ^0.0.29
version: link:../../apps/solana
'@nightlylabs/wallet-selector-base':
- specifier: ^0.2.4
- version: 0.2.4
+ specifier: ^0.4.0
+ version: link:../selector-base
'@solana/wallet-adapter-base':
specifier: ^0.9.22
version: 0.9.22(@solana/web3.js@1.77.2)
@@ -5090,24 +5096,6 @@ packages:
- utf-8-validate
dev: false
- /@nightlylabs/nightly-connect-polkadot@0.0.15:
- resolution: {integrity: sha512-WCsumvHwhPipbxPQoswKCwHykwJ48Dffwb9hCf7zjCgEysIBCnA6Dzj/2G80drLqYYpS285nMa8z+3NaXVu2dA==}
- dependencies:
- '@nightlylabs/nightly-connect-base': 0.0.27
- '@polkadot/api': 10.10.1
- '@polkadot/extension-inject': 0.46.5(@polkadot/api@10.10.1)(@polkadot/util@12.5.1)
- '@polkadot/types': 10.10.1
- '@polkadot/util': 12.5.1
- '@polkadot/util-crypto': 12.5.1(@polkadot/util@12.5.1)
- eventemitter3: 5.0.1
- uuid: 9.0.0
- transitivePeerDependencies:
- - bufferutil
- - encoding
- - supports-color
- - utf-8-validate
- dev: false
-
/@nightlylabs/nightly-connect-solana@0.0.28:
resolution: {integrity: sha512-8PBkmuXzWZNPqu6SGT2tsGK4DgD3yswQsUVb3L+GgFGCdQI7eUqyHd2ofWFWzEgj4a1XuixA29ZcSyw20ajgzw==}
dependencies:
@@ -5158,21 +5146,6 @@ packages:
- utf-8-validate
dev: false
- /@nightlylabs/wallet-selector-base@0.3.1:
- resolution: {integrity: sha512-m2hdNkOrQNS52xXYSvko8YvbI60miCU9AHO8HHKfGXiuYgUjAmQSeTm1wLP8LZI4+Mygqbr8Oq9na+HMEgq2XA==}
- dependencies:
- '@nightlylabs/nightly-connect-base': 0.0.27
- '@nightlylabs/wallet-selector-modal': 0.2.0
- '@wallet-standard/core': 1.0.3
- isomorphic-localstorage: 1.0.2
- transitivePeerDependencies:
- - bufferutil
- - encoding
- - supports-color
- - ts-node
- - utf-8-validate
- dev: false
-
/@nightlylabs/wallet-selector-modal@0.1.2:
resolution: {integrity: sha512-vxy9S2dEf3NARW6LDq2ZKpWMlk5JJFIuwUfSxkuJlgUg2OVSlnDS7vdho3h4DmluRU5GM9vVhaXUGHAVp5sDQg==}
dependencies:
@@ -5187,37 +5160,6 @@ packages:
- ts-node
dev: false
- /@nightlylabs/wallet-selector-modal@0.2.0:
- resolution: {integrity: sha512-BdEk3FhL65z/X0N9ygPjk7uQvV0GGHTWSwXBVob/l48Nok4ikFcV30Dtxk6iSSbErDZ8U4zV3/78cK+m+4lt8A==}
- dependencies:
- '@nightlylabs/qr-code': 2.0.4
- autoprefixer: 10.4.14(postcss@8.4.24)
- lit: 2.7.2
- postcss: 8.4.24
- postcss-lit: 1.1.0(postcss@8.4.24)
- tailwindcss: 3.3.2
- transitivePeerDependencies:
- - supports-color
- - ts-node
- dev: false
-
- /@nightlylabs/wallet-selector-polkadot@0.2.0(@polkadot/util@12.5.1):
- resolution: {integrity: sha512-T4C6J+RVBif8H742LdeZfIRZyFZV79CAWL6/w3keQmyi8ZmTfmmxdVaXkSE5Va11j3xt2A298mugbbujluW6bw==}
- dependencies:
- '@nightlylabs/nightly-connect-polkadot': 0.0.15
- '@nightlylabs/wallet-selector-base': 0.3.1
- '@polkadot/api': 10.10.1
- '@polkadot/extension-inject': 0.46.5(@polkadot/api@10.10.1)(@polkadot/util@12.5.1)
- '@wallet-standard/core': 1.0.3
- transitivePeerDependencies:
- - '@polkadot/util'
- - bufferutil
- - encoding
- - supports-color
- - ts-node
- - utf-8-validate
- dev: false
-
/@nightlylabs/wallet-selector-solana@0.2.6(bs58@4.0.1)(react@18.2.0):
resolution: {integrity: sha512-cVTKk+c6tGv4GeSQMlUaZ2si4A6ySKj41emkGJ8OtuwmtzwUym4Xuh3chXZYgGrMQgvPrX5+erIR4oq2GmGIPg==}
dependencies: