@lukso/up-connector 0.4.0-dev.a8c9315
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +280 -0
- package/dist/account-modal.cjs +9 -0
- package/dist/account-modal.cjs.map +1 -0
- package/dist/account-modal.d.cts +16 -0
- package/dist/account-modal.d.ts +16 -0
- package/dist/account-modal.js +9 -0
- package/dist/account-modal.js.map +1 -0
- package/dist/auto-setup.cjs +17 -0
- package/dist/auto-setup.cjs.map +1 -0
- package/dist/auto-setup.d.cts +123 -0
- package/dist/auto-setup.d.ts +123 -0
- package/dist/auto-setup.js +17 -0
- package/dist/auto-setup.js.map +1 -0
- package/dist/avatar-CmUCtW_w.d.cts +205 -0
- package/dist/avatar-CmUCtW_w.d.ts +205 -0
- package/dist/avatar.cjs +12 -0
- package/dist/avatar.cjs.map +1 -0
- package/dist/avatar.d.cts +1 -0
- package/dist/avatar.d.ts +1 -0
- package/dist/avatar.js +12 -0
- package/dist/avatar.js.map +1 -0
- package/dist/backup-modal.cjs +9 -0
- package/dist/backup-modal.cjs.map +1 -0
- package/dist/backup-modal.d.cts +41 -0
- package/dist/backup-modal.d.ts +41 -0
- package/dist/backup-modal.js +9 -0
- package/dist/backup-modal.js.map +1 -0
- package/dist/chunk-3SGSPHOZ.js +595 -0
- package/dist/chunk-3SGSPHOZ.js.map +1 -0
- package/dist/chunk-6AYZOIFY.js +181 -0
- package/dist/chunk-6AYZOIFY.js.map +1 -0
- package/dist/chunk-6N35TCFT.js +852 -0
- package/dist/chunk-6N35TCFT.js.map +1 -0
- package/dist/chunk-7ETKG6KR.cjs +387 -0
- package/dist/chunk-7ETKG6KR.cjs.map +1 -0
- package/dist/chunk-EUXUH3YW.js +15 -0
- package/dist/chunk-EUXUH3YW.js.map +1 -0
- package/dist/chunk-GFVUWAG4.cjs +158 -0
- package/dist/chunk-GFVUWAG4.cjs.map +1 -0
- package/dist/chunk-IAKQFHFD.cjs +595 -0
- package/dist/chunk-IAKQFHFD.cjs.map +1 -0
- package/dist/chunk-MH7MP7XK.cjs +181 -0
- package/dist/chunk-MH7MP7XK.cjs.map +1 -0
- package/dist/chunk-NWCNJSG3.js +387 -0
- package/dist/chunk-NWCNJSG3.js.map +1 -0
- package/dist/chunk-NXU2DQAV.js +1128 -0
- package/dist/chunk-NXU2DQAV.js.map +1 -0
- package/dist/chunk-ORJK2YGG.cjs +852 -0
- package/dist/chunk-ORJK2YGG.cjs.map +1 -0
- package/dist/chunk-RFA6SEIS.cjs +1128 -0
- package/dist/chunk-RFA6SEIS.cjs.map +1 -0
- package/dist/chunk-XGIT7YUY.js +31 -0
- package/dist/chunk-XGIT7YUY.js.map +1 -0
- package/dist/chunk-XOKG3KIL.cjs +31 -0
- package/dist/chunk-XOKG3KIL.cjs.map +1 -0
- package/dist/chunk-YIWSPI4I.js +158 -0
- package/dist/chunk-YIWSPI4I.js.map +1 -0
- package/dist/chunk-ZBDE64SD.cjs +15 -0
- package/dist/chunk-ZBDE64SD.cjs.map +1 -0
- package/dist/connect-modal/index.cjs +20 -0
- package/dist/connect-modal/index.cjs.map +1 -0
- package/dist/connect-modal/index.d.cts +9 -0
- package/dist/connect-modal/index.d.ts +9 -0
- package/dist/connect-modal/index.js +20 -0
- package/dist/connect-modal/index.js.map +1 -0
- package/dist/index-D2orHGFi.d.cts +8 -0
- package/dist/index-D2orHGFi.d.ts +8 -0
- package/dist/index.cjs +793 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +189 -0
- package/dist/index.d.ts +189 -0
- package/dist/index.js +793 -0
- package/dist/index.js.map +1 -0
- package/dist/restore-modal.cjs +9 -0
- package/dist/restore-modal.cjs.map +1 -0
- package/dist/restore-modal.d.cts +68 -0
- package/dist/restore-modal.d.ts +68 -0
- package/dist/restore-modal.js +9 -0
- package/dist/restore-modal.js.map +1 -0
- package/dist/wagmi-CVuDs_0h.d.cts +386 -0
- package/dist/wagmi-CVuDs_0h.d.ts +386 -0
- package/package.json +158 -0
- package/src/account-modal.ts +142 -0
- package/src/auto-setup.ts +362 -0
- package/src/avatar.ts +1135 -0
- package/src/backup-modal.ts +439 -0
- package/src/connect-modal/components/connection-view.ts +398 -0
- package/src/connect-modal/components/eoa-connection-view.ts +408 -0
- package/src/connect-modal/components/qr-code-view.ts +71 -0
- package/src/connect-modal/connect-modal.base.ts +18 -0
- package/src/connect-modal/connect-modal.config.ts +27 -0
- package/src/connect-modal/connect-modal.templates.ts +21 -0
- package/src/connect-modal/connect-modal.ts +270 -0
- package/src/connect-modal/connect-modal.types.ts +104 -0
- package/src/connect-modal/images/up-cube-glass.png +0 -0
- package/src/connect-modal/index.ts +23 -0
- package/src/connect-modal/services/wagmi.ts +266 -0
- package/src/connect-modal/styles/styles.css +1 -0
- package/src/connect-modal/utils/walletConnectDeepLinkUrl.ts +43 -0
- package/src/connector.ts +544 -0
- package/src/index.ts +62 -0
- package/src/popup-instance.ts +537 -0
- package/src/restore-modal.ts +702 -0
- package/src/styles/index.ts +28 -0
- package/src/styles/styles.css +1 -0
- package/src/types/css-raw.d.ts +4 -0
- package/src/types/images.d.ts +4 -0
- package/src/types.ts +168 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connect Modal - Lit Component
|
|
3
|
+
*
|
|
4
|
+
* Framework-agnostic connection modal for wallet/profile connections.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { withDeviceService } from '@lukso/core/mixins'
|
|
8
|
+
import debug from 'debug'
|
|
9
|
+
import { html, type TemplateResult } from 'lit'
|
|
10
|
+
import { property, state } from 'lit/decorators.js'
|
|
11
|
+
|
|
12
|
+
import { ConnectModalBase } from './connect-modal.base.js'
|
|
13
|
+
import type {
|
|
14
|
+
ConnectionModalView,
|
|
15
|
+
ConnectModalTheme,
|
|
16
|
+
WalletConnector,
|
|
17
|
+
} from './connect-modal.types'
|
|
18
|
+
import { fromWagmiConnectors, getWagmiSetup } from './services/wagmi'
|
|
19
|
+
|
|
20
|
+
import '@lukso/web-components/dist/components/lukso-modal'
|
|
21
|
+
import './components/eoa-connection-view'
|
|
22
|
+
import './components/connection-view'
|
|
23
|
+
import './components/qr-code-view'
|
|
24
|
+
|
|
25
|
+
const logInfo = debug('connect-modal:info')
|
|
26
|
+
|
|
27
|
+
export class ConnectModal extends withDeviceService(ConnectModalBase) {
|
|
28
|
+
// Public properties
|
|
29
|
+
@property({ type: Boolean, reflect: true }) open = false
|
|
30
|
+
@property({ type: String, reflect: true }) theme: ConnectModalTheme = 'light'
|
|
31
|
+
|
|
32
|
+
// Private state
|
|
33
|
+
@state() private connectors: WalletConnector[] = []
|
|
34
|
+
@state() private isDark = false
|
|
35
|
+
@state() private modalView: ConnectionModalView = 'up_connection'
|
|
36
|
+
@state() private qrCodeData: string | undefined = undefined
|
|
37
|
+
|
|
38
|
+
private mediaQueryList: MediaQueryList | null = null
|
|
39
|
+
|
|
40
|
+
updated(changedProperties: Map<string, any>): void {
|
|
41
|
+
// Reset view and load connectors when modal opens
|
|
42
|
+
if (changedProperties.has('open') && this.open) {
|
|
43
|
+
this.modalView = 'up_connection' // Reset to main view when modal opens
|
|
44
|
+
this.loadConnectors()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Handle theme changes
|
|
48
|
+
if (changedProperties.has('theme')) {
|
|
49
|
+
this.updateTheme()
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
connectedCallback(): void {
|
|
54
|
+
super.connectedCallback()
|
|
55
|
+
this.updateTheme()
|
|
56
|
+
|
|
57
|
+
// Listen for system theme changes when in 'auto' mode
|
|
58
|
+
if (this.theme === 'auto') {
|
|
59
|
+
this.mediaQueryList = window.matchMedia('(prefers-color-scheme: dark)')
|
|
60
|
+
this.mediaQueryList.addEventListener(
|
|
61
|
+
'change',
|
|
62
|
+
this.handleMediaQueryChange
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
disconnectedCallback(): void {
|
|
68
|
+
super.disconnectedCallback()
|
|
69
|
+
|
|
70
|
+
if (this.mediaQueryList) {
|
|
71
|
+
this.mediaQueryList.removeEventListener(
|
|
72
|
+
'change',
|
|
73
|
+
this.handleMediaQueryChange
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Handle system theme changes
|
|
80
|
+
*
|
|
81
|
+
* @param event
|
|
82
|
+
*/
|
|
83
|
+
private handleMediaQueryChange = (event: MediaQueryListEvent): void => {
|
|
84
|
+
this.isDark = event.matches
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Close modal
|
|
89
|
+
*/
|
|
90
|
+
handleClose(): void {
|
|
91
|
+
this.open = false
|
|
92
|
+
|
|
93
|
+
this.dispatchEvent(
|
|
94
|
+
new CustomEvent('on-close', { bubbles: true, composed: true })
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Update isDark state based on theme property
|
|
100
|
+
*/
|
|
101
|
+
private updateTheme(): void {
|
|
102
|
+
if (this.theme === 'auto') {
|
|
103
|
+
this.isDark = window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
104
|
+
} else {
|
|
105
|
+
this.isDark = this.theme === 'dark'
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private async loadConnectors(): Promise<void> {
|
|
110
|
+
const globalWagmiSetup = getWagmiSetup()
|
|
111
|
+
logInfo('Global wagmi setup:', globalWagmiSetup)
|
|
112
|
+
|
|
113
|
+
if (!globalWagmiSetup) {
|
|
114
|
+
console.warn(
|
|
115
|
+
'No global wagmi setup found! Call setupConnectModal() first.'
|
|
116
|
+
)
|
|
117
|
+
this.connectors = []
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
const { wagmiConfig, chainId, embeddedWalletId } = globalWagmiSetup
|
|
123
|
+
|
|
124
|
+
// Get connectors from wagmi config
|
|
125
|
+
const wagmiConnectors = wagmiConfig?.connectors || []
|
|
126
|
+
logInfo('Initial connectors:', wagmiConnectors)
|
|
127
|
+
|
|
128
|
+
// Dynamically import wagmi's connect function to avoid bundling if not used
|
|
129
|
+
// Use dynamic import to keep @wagmi/core as an optional peer dependency
|
|
130
|
+
const wagmiCore = await import('@wagmi/core').catch((error) => {
|
|
131
|
+
throw new Error('@wagmi/core is required when using wagmi connectors', {
|
|
132
|
+
cause: error,
|
|
133
|
+
})
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
// Convert to WalletConnector format using the adapter
|
|
137
|
+
this.connectors = fromWagmiConnectors(
|
|
138
|
+
wagmiConnectors,
|
|
139
|
+
async (options: any) => {
|
|
140
|
+
await wagmiCore.connect(wagmiConfig, {
|
|
141
|
+
connector: options.connector,
|
|
142
|
+
chainId: options.chainId || chainId,
|
|
143
|
+
})
|
|
144
|
+
},
|
|
145
|
+
chainId,
|
|
146
|
+
embeddedWalletId
|
|
147
|
+
)
|
|
148
|
+
logInfo('Converted connectors:', this.connectors)
|
|
149
|
+
} catch (error) {
|
|
150
|
+
console.warn('Failed to load connectors', error)
|
|
151
|
+
this.connectors = []
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Successful connection handler
|
|
157
|
+
*
|
|
158
|
+
* @param connector
|
|
159
|
+
*/
|
|
160
|
+
private handleOnConnectSuccess(event: CustomEvent): void {
|
|
161
|
+
event.stopPropagation() // Prevent event bubbling
|
|
162
|
+
const connector = event.detail.connector as WalletConnector
|
|
163
|
+
logInfo('Connection success:', connector)
|
|
164
|
+
this.open = false
|
|
165
|
+
|
|
166
|
+
// Dispatch connect event
|
|
167
|
+
this.dispatchEvent(
|
|
168
|
+
new CustomEvent('on-connect', {
|
|
169
|
+
detail: { connector },
|
|
170
|
+
bubbles: true,
|
|
171
|
+
composed: true,
|
|
172
|
+
})
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Error connection handler
|
|
178
|
+
*
|
|
179
|
+
* @param error
|
|
180
|
+
*/
|
|
181
|
+
private handleOnConnectError(event: CustomEvent): void {
|
|
182
|
+
event.stopPropagation() // Prevent event bubbling
|
|
183
|
+
const error = event.detail.error as Error
|
|
184
|
+
logInfo('Connection error:', error)
|
|
185
|
+
|
|
186
|
+
// Dispatch error event
|
|
187
|
+
this.dispatchEvent(
|
|
188
|
+
new CustomEvent('on-error', {
|
|
189
|
+
detail: { error },
|
|
190
|
+
bubbles: true,
|
|
191
|
+
composed: true,
|
|
192
|
+
})
|
|
193
|
+
)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private handleBackToConnectionView(event: CustomEvent): void {
|
|
197
|
+
event.stopPropagation() // Prevent event bubbling
|
|
198
|
+
this.modalView = 'up_connection'
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
private handleShowEoaConnectionsView = (event: CustomEvent): void => {
|
|
202
|
+
event.stopPropagation() // Prevent event bubbling
|
|
203
|
+
this.modalView = 'eoa_connection'
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
private handleShowQrCodeView = (event: CustomEvent): void => {
|
|
207
|
+
event.stopPropagation() // Prevent event bubbling
|
|
208
|
+
this.qrCodeData = event.detail.data
|
|
209
|
+
this.modalView = 'qr_code'
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// ===== Template Methods =====
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Render modal content based on current view flag
|
|
216
|
+
*/
|
|
217
|
+
private renderModalContent(): TemplateResult<1> {
|
|
218
|
+
switch (this.modalView) {
|
|
219
|
+
case 'qr_code':
|
|
220
|
+
return html`<qr-code-view .data=${this.qrCodeData} @on-back=${this.handleBackToConnectionView}
|
|
221
|
+
@on-close=${this.handleClose}></qr-code-view>`
|
|
222
|
+
case 'eoa_connection':
|
|
223
|
+
return html`
|
|
224
|
+
<eoa-connection-view
|
|
225
|
+
.connectors=${this.connectors}
|
|
226
|
+
@on-back=${this.handleBackToConnectionView}
|
|
227
|
+
@on-close=${this.handleClose}
|
|
228
|
+
@on-connect=${this.handleOnConnectSuccess}
|
|
229
|
+
@on-error=${this.handleOnConnectError}
|
|
230
|
+
></eoa-connection-view>
|
|
231
|
+
`
|
|
232
|
+
default: // up_connection
|
|
233
|
+
return html`
|
|
234
|
+
<connection-view
|
|
235
|
+
.connectors=${this.connectors}
|
|
236
|
+
@on-back=${this.handleBackToConnectionView}
|
|
237
|
+
@on-close=${this.handleClose}
|
|
238
|
+
@on-connect=${this.handleOnConnectSuccess}
|
|
239
|
+
@on-error=${this.handleOnConnectError}
|
|
240
|
+
@on-show-eoa-connections-view=${this.handleShowEoaConnectionsView}
|
|
241
|
+
@on-show-qr-code=${this.handleShowQrCodeView}
|
|
242
|
+
></connection-view>
|
|
243
|
+
`
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
render(): TemplateResult<1> {
|
|
248
|
+
return html`
|
|
249
|
+
<lukso-modal
|
|
250
|
+
?is-open=${this.open}
|
|
251
|
+
?has-bottom-padding=${!!(this.device?.isIOS && this.device?.isSafari)}
|
|
252
|
+
size="auto"
|
|
253
|
+
@on-backdrop-click=${this.handleClose}
|
|
254
|
+
>
|
|
255
|
+
<div class="p-6 ${this.isDark ? 'dark' : ''} w-full sm:w-[372px] text-neutral-20">
|
|
256
|
+
${this.renderModalContent()}
|
|
257
|
+
</div>
|
|
258
|
+
</lukso-modal>
|
|
259
|
+
`
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Register custom element
|
|
264
|
+
customElements.define('connect-modal', ConnectModal as any)
|
|
265
|
+
|
|
266
|
+
declare global {
|
|
267
|
+
interface HTMLElementTagNameMap {
|
|
268
|
+
'connect-modal': ConnectModal
|
|
269
|
+
}
|
|
270
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
export interface WalletConnector {
|
|
2
|
+
id: string
|
|
3
|
+
name?: string
|
|
4
|
+
rdns?: string // Reverse DNS identifier (e.g., 'io.metamask')
|
|
5
|
+
slug?: string
|
|
6
|
+
type: 'embedded' | 'extension' | 'mobile' | 'injected' | 'walletconnect'
|
|
7
|
+
connect: () => Promise<void>
|
|
8
|
+
getProvider?: () => Promise<any>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ConnectModalSetup {
|
|
12
|
+
/**
|
|
13
|
+
* Wagmi config instance
|
|
14
|
+
*/
|
|
15
|
+
wagmiConfig: any
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Optional chain ID to use for connections (defaults to first chain in config)
|
|
19
|
+
*/
|
|
20
|
+
chainId?: number
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Optional embedded wallet ID (to identify it in wagmi connectors)
|
|
24
|
+
* If provided, this connector will be shown first as "Create Passkey Wallet"
|
|
25
|
+
* Example: 'dev.lukso.auth'
|
|
26
|
+
*/
|
|
27
|
+
embeddedWalletId?: string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Minimal wagmi Connector interface (to avoid importing @wagmi/core)
|
|
31
|
+
export interface WagmiConnector {
|
|
32
|
+
uid: string
|
|
33
|
+
name: string
|
|
34
|
+
id: string
|
|
35
|
+
type: string
|
|
36
|
+
icon?: string
|
|
37
|
+
// Other wagmi connector properties...
|
|
38
|
+
[key: string]: any
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type ConnectModalTheme = 'light' | 'dark' | 'auto'
|
|
42
|
+
|
|
43
|
+
export type ConnectionModalView = 'up_connection' | 'qr_code' | 'eoa_connection'
|
|
44
|
+
|
|
45
|
+
export type WalletResponse = {
|
|
46
|
+
listings: {
|
|
47
|
+
[key in string]: Wallet
|
|
48
|
+
}
|
|
49
|
+
count: number
|
|
50
|
+
total: number
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type Wallet = {
|
|
54
|
+
id: string
|
|
55
|
+
name: string
|
|
56
|
+
slug: string
|
|
57
|
+
description: string
|
|
58
|
+
homepage: string
|
|
59
|
+
chains: string[]
|
|
60
|
+
versions: string[]
|
|
61
|
+
sdks: string[]
|
|
62
|
+
app_type: string
|
|
63
|
+
category: string
|
|
64
|
+
image_id: string
|
|
65
|
+
image_url: WalletImageUrl
|
|
66
|
+
app: WalletApp
|
|
67
|
+
rdns: string
|
|
68
|
+
mobile: WalletMobile
|
|
69
|
+
desktop: WalletDesktop
|
|
70
|
+
isInstalled: boolean
|
|
71
|
+
connector: WalletConnector | undefined
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export type WalletImageUrl = {
|
|
75
|
+
sm: string
|
|
76
|
+
md: string
|
|
77
|
+
lg: string
|
|
78
|
+
}
|
|
79
|
+
export type WalletAppType =
|
|
80
|
+
| 'browser'
|
|
81
|
+
| 'ios'
|
|
82
|
+
| 'android'
|
|
83
|
+
| 'mac'
|
|
84
|
+
| 'windows'
|
|
85
|
+
| 'linux'
|
|
86
|
+
| 'chrome'
|
|
87
|
+
| 'firefox'
|
|
88
|
+
| 'safari'
|
|
89
|
+
| 'edge'
|
|
90
|
+
| 'opera'
|
|
91
|
+
|
|
92
|
+
export type WalletApp = {
|
|
93
|
+
[key in WalletAppType]?: string
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface WalletMobile {
|
|
97
|
+
native?: string
|
|
98
|
+
universal?: string
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface WalletDesktop {
|
|
102
|
+
native?: string
|
|
103
|
+
universal?: string
|
|
104
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connect Modal - Barrel Export
|
|
3
|
+
*
|
|
4
|
+
* Exports the connect modal component and all related types and utilities
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export { ConnectModalBase } from './connect-modal.base.js'
|
|
8
|
+
export { ConnectModal } from './connect-modal.js'
|
|
9
|
+
export type {
|
|
10
|
+
ConnectionModalView,
|
|
11
|
+
ConnectModalSetup,
|
|
12
|
+
ConnectModalTheme,
|
|
13
|
+
WagmiConnector,
|
|
14
|
+
Wallet,
|
|
15
|
+
WalletConnector,
|
|
16
|
+
} from './connect-modal.types'
|
|
17
|
+
export {
|
|
18
|
+
disconnectWagmi,
|
|
19
|
+
getWagmiAccount,
|
|
20
|
+
getWagmiSetup,
|
|
21
|
+
setupConnectModal,
|
|
22
|
+
watchWagmiAccount,
|
|
23
|
+
} from './services/wagmi'
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wagmi Connector Adapter
|
|
3
|
+
* Converts wagmi/viem connectors to our WalletConnector format
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { slug } from '@lukso/core/utils'
|
|
7
|
+
import type {
|
|
8
|
+
ConnectModalSetup,
|
|
9
|
+
WagmiConnector,
|
|
10
|
+
} from '../connect-modal.types.js'
|
|
11
|
+
import type { WalletConnector } from '../index.js'
|
|
12
|
+
|
|
13
|
+
// UP Extension ID
|
|
14
|
+
const UP_EXTENSION_ID = 'cloud.universalprofile'
|
|
15
|
+
|
|
16
|
+
// Global wagmi setup storage
|
|
17
|
+
let globalWagmiSetup: ConnectModalSetup | null = null
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Convert a wagmi connector to our WalletConnector format
|
|
21
|
+
* @param connector - Wagmi connector instance
|
|
22
|
+
* @param connectFn - Function to call connect (from wagmi's useConnect)
|
|
23
|
+
* @param chainId - Optional chain ID to use for connection
|
|
24
|
+
*/
|
|
25
|
+
export function fromWagmiConnector(
|
|
26
|
+
connector: WagmiConnector,
|
|
27
|
+
connectFn: (options: {
|
|
28
|
+
connector: WagmiConnector
|
|
29
|
+
chainId?: number
|
|
30
|
+
}) => Promise<any>,
|
|
31
|
+
chainId?: number
|
|
32
|
+
): WalletConnector {
|
|
33
|
+
// Determine connector type based on connector.id
|
|
34
|
+
let type: WalletConnector['type'] = 'injected'
|
|
35
|
+
|
|
36
|
+
// Extract rdns from connector (EIP-6963 providers expose this)
|
|
37
|
+
const rdns: string | undefined = connector.id
|
|
38
|
+
|
|
39
|
+
// Map wagmi connector types to our types
|
|
40
|
+
if (connector.id === 'walletConnect' || connector.type === 'walletConnect') {
|
|
41
|
+
type = 'walletconnect'
|
|
42
|
+
} else if (connector.id === 'injected' || connector.type === 'injected') {
|
|
43
|
+
type = 'injected'
|
|
44
|
+
|
|
45
|
+
// Check if this is UP Extension via ID
|
|
46
|
+
if (
|
|
47
|
+
connector.id === UP_EXTENSION_ID ||
|
|
48
|
+
connector.id.includes(UP_EXTENSION_ID)
|
|
49
|
+
) {
|
|
50
|
+
type = 'extension'
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
id: connector.uid || connector.id,
|
|
56
|
+
name: connector.name,
|
|
57
|
+
rdns,
|
|
58
|
+
type,
|
|
59
|
+
slug: slug(connector.name),
|
|
60
|
+
connect: async () => {
|
|
61
|
+
await connectFn({ connector, chainId })
|
|
62
|
+
},
|
|
63
|
+
getProvider: connector.getProvider
|
|
64
|
+
? () => connector.getProvider()
|
|
65
|
+
: undefined,
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Convert array of wagmi connectors to WalletConnector array
|
|
71
|
+
* @param connectors - Array of wagmi connectors
|
|
72
|
+
* @param connectFn - Function to call connect (from wagmi's useConnect)
|
|
73
|
+
* @param chainId - Optional chain ID to use for connection
|
|
74
|
+
* @param embeddedWalletId - Optional embedded wallet ID to identify it (e.g., 'dev.lukso.auth')
|
|
75
|
+
*/
|
|
76
|
+
export function fromWagmiConnectors(
|
|
77
|
+
connectors: WagmiConnector[],
|
|
78
|
+
connectFn: (options: {
|
|
79
|
+
connector: WagmiConnector
|
|
80
|
+
chainId?: number
|
|
81
|
+
}) => Promise<any>,
|
|
82
|
+
chainId?: number,
|
|
83
|
+
embeddedWalletId?: string
|
|
84
|
+
): WalletConnector[] {
|
|
85
|
+
const result: WalletConnector[] = []
|
|
86
|
+
|
|
87
|
+
// 1. Find and add embedded wallet first (if ID provided)
|
|
88
|
+
// Check against original wagmi connector.id (not the converted UID)
|
|
89
|
+
let embeddedWalletConnector: WagmiConnector | undefined
|
|
90
|
+
let embeddedWallet: WalletConnector | undefined
|
|
91
|
+
if (embeddedWalletId) {
|
|
92
|
+
embeddedWalletConnector = connectors.find(
|
|
93
|
+
(connector) =>
|
|
94
|
+
connector.id === embeddedWalletId ||
|
|
95
|
+
connector.id.includes(embeddedWalletId)
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
if (embeddedWalletConnector) {
|
|
99
|
+
embeddedWallet = fromWagmiConnector(
|
|
100
|
+
embeddedWalletConnector,
|
|
101
|
+
connectFn,
|
|
102
|
+
chainId
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
// Customize for embedded wallet display
|
|
106
|
+
result.push({
|
|
107
|
+
...embeddedWallet,
|
|
108
|
+
type: 'embedded',
|
|
109
|
+
slug: 'passkey-wallet',
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 2. Find and add UP Extension next (using ID)
|
|
115
|
+
const UP_EXTENSION_ID = 'cloud.universalprofile'
|
|
116
|
+
const upExtensionConnector = connectors.find(
|
|
117
|
+
(connector) =>
|
|
118
|
+
connector !== embeddedWalletConnector &&
|
|
119
|
+
(connector.id === UP_EXTENSION_ID ||
|
|
120
|
+
connector.id.includes(UP_EXTENSION_ID))
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
let upExtension: WalletConnector | undefined
|
|
124
|
+
if (upExtensionConnector) {
|
|
125
|
+
upExtension = fromWagmiConnector(upExtensionConnector, connectFn, chainId)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Convert remaining wagmi connectors
|
|
129
|
+
const walletConnectors = connectors
|
|
130
|
+
.filter(
|
|
131
|
+
(connector) =>
|
|
132
|
+
connector !== embeddedWalletConnector &&
|
|
133
|
+
connector !== upExtensionConnector
|
|
134
|
+
)
|
|
135
|
+
.map((connector) => fromWagmiConnector(connector, connectFn, chainId))
|
|
136
|
+
|
|
137
|
+
if (upExtension) {
|
|
138
|
+
result.push(upExtension)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// 3. Find and add WalletConnect (for mobile)
|
|
142
|
+
const walletConnect = walletConnectors.find(
|
|
143
|
+
(connector) => connector.type === 'walletconnect'
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
if (walletConnect) {
|
|
147
|
+
result.push({
|
|
148
|
+
...walletConnect,
|
|
149
|
+
type: 'mobile',
|
|
150
|
+
slug: 'up-mobile',
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 4. Add other wallets
|
|
155
|
+
const others = walletConnectors.filter(
|
|
156
|
+
(connector) =>
|
|
157
|
+
connector !== embeddedWallet &&
|
|
158
|
+
connector !== upExtension &&
|
|
159
|
+
connector !== walletConnect
|
|
160
|
+
)
|
|
161
|
+
result.push(...others)
|
|
162
|
+
|
|
163
|
+
return result
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Setup wagmi for connect modal
|
|
168
|
+
* Call this once from your app initialization with wagmi config
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```typescript
|
|
172
|
+
* import { setupConnectModal } from '@lukso/up-connector'
|
|
173
|
+
* import { wagmiConfig } from './wagmi-config'
|
|
174
|
+
*
|
|
175
|
+
* setupConnectModal({
|
|
176
|
+
* wagmiConfig,
|
|
177
|
+
* chainId: 42, // Optional: LUKSO mainnet
|
|
178
|
+
* embeddedWalletConnect: async () => {
|
|
179
|
+
* // Your passkey wallet logic
|
|
180
|
+
* }
|
|
181
|
+
* })
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
export function setupConnectModal(setup: ConnectModalSetup): void {
|
|
185
|
+
globalWagmiSetup = setup
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Get the current wagmi setup (for internal use by connector)
|
|
190
|
+
*/
|
|
191
|
+
export function getWagmiSetup(): ConnectModalSetup | null {
|
|
192
|
+
return globalWagmiSetup
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Get current wagmi account state
|
|
197
|
+
* Returns null if wagmi is not set up
|
|
198
|
+
*/
|
|
199
|
+
export async function getWagmiAccount(): Promise<{
|
|
200
|
+
isConnected: boolean
|
|
201
|
+
address?: string
|
|
202
|
+
chainId?: number
|
|
203
|
+
connector?: any
|
|
204
|
+
} | null> {
|
|
205
|
+
if (!globalWagmiSetup) {
|
|
206
|
+
return null
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
try {
|
|
210
|
+
const { getAccount } = await import('@wagmi/core')
|
|
211
|
+
const account = getAccount(globalWagmiSetup.wagmiConfig)
|
|
212
|
+
return account
|
|
213
|
+
} catch (_error) {
|
|
214
|
+
return null
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Subscribe to wagmi account changes
|
|
220
|
+
* Returns unsubscribe function
|
|
221
|
+
*/
|
|
222
|
+
export async function watchWagmiAccount(
|
|
223
|
+
callback: (account: {
|
|
224
|
+
isConnected: boolean
|
|
225
|
+
address?: string
|
|
226
|
+
chainId?: number
|
|
227
|
+
connector?: any
|
|
228
|
+
}) => void
|
|
229
|
+
): Promise<(() => void) | null> {
|
|
230
|
+
if (!globalWagmiSetup) {
|
|
231
|
+
return null
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
const { watchAccount } = await import('@wagmi/core')
|
|
236
|
+
|
|
237
|
+
const unsubscribe = watchAccount(globalWagmiSetup.wagmiConfig, {
|
|
238
|
+
onChange: (account) => {
|
|
239
|
+
callback(account)
|
|
240
|
+
},
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
return unsubscribe
|
|
244
|
+
} catch (_error) {
|
|
245
|
+
return null
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Disconnect from wagmi
|
|
251
|
+
* Returns true if disconnect was successful
|
|
252
|
+
*/
|
|
253
|
+
export async function disconnectWagmi(): Promise<boolean> {
|
|
254
|
+
if (!globalWagmiSetup) {
|
|
255
|
+
return false
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
try {
|
|
259
|
+
const { disconnect } = await import('@wagmi/core')
|
|
260
|
+
await disconnect(globalWagmiSetup.wagmiConfig)
|
|
261
|
+
return true
|
|
262
|
+
} catch (error) {
|
|
263
|
+
console.warn('Failed to disconnect from wagmi', error)
|
|
264
|
+
return false
|
|
265
|
+
}
|
|
266
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import "@lukso/web-components/dist/styles/main.css";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { MOBILE_APP_DEEP_LINK_PREFIX } from '../connect-modal.config'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* URL to Mobile App deep link used by Wallet Connect
|
|
5
|
+
*
|
|
6
|
+
* @param data
|
|
7
|
+
*/
|
|
8
|
+
export const walletConnectDeepLinkUrl = (
|
|
9
|
+
data?: string,
|
|
10
|
+
options?: {
|
|
11
|
+
withRedirectUrl?: boolean
|
|
12
|
+
}
|
|
13
|
+
) => {
|
|
14
|
+
try {
|
|
15
|
+
if (!data || typeof data !== 'string') {
|
|
16
|
+
return ''
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const dataUrl = new URL(data)
|
|
20
|
+
|
|
21
|
+
// add redirectUrl to deep link
|
|
22
|
+
if (options?.withRedirectUrl) {
|
|
23
|
+
const redirectUrl = new URL(location.href)
|
|
24
|
+
|
|
25
|
+
// remove modal query params so we don't re-open the modal
|
|
26
|
+
redirectUrl.searchParams.delete('modalTemplate')
|
|
27
|
+
redirectUrl.searchParams.delete('modalSize')
|
|
28
|
+
|
|
29
|
+
// add redirectUrl to dataUrl
|
|
30
|
+
dataUrl.searchParams.append(
|
|
31
|
+
'redirectUrl',
|
|
32
|
+
`${redirectUrl.origin}${redirectUrl.pathname}${redirectUrl.search}`
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const deepLink = `${MOBILE_APP_DEEP_LINK_PREFIX}://wallet-connect/${dataUrl.pathname}${dataUrl.search}`
|
|
37
|
+
|
|
38
|
+
return deepLink
|
|
39
|
+
} catch (error: unknown) {
|
|
40
|
+
console.warn(error)
|
|
41
|
+
return ''
|
|
42
|
+
}
|
|
43
|
+
}
|