@lumiapassport/ui-kit 1.5.1 → 1.5.3
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/README.md +179 -54
- package/dist/iframe/index.html +12 -17
- package/dist/iframe/main.js +114 -49
- package/dist/iframe/main.js.map +1 -1
- package/dist/index.cjs +5 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,43 +13,57 @@ React UI components and hooks for Lumia Passport - a secure, user-friendly authe
|
|
|
13
13
|
## Installation
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
npm install @lumiapassport/ui-kit
|
|
16
|
+
npm install @lumiapassport/ui-kit
|
|
17
17
|
# or
|
|
18
|
-
pnpm add @lumiapassport/ui-kit
|
|
18
|
+
pnpm add @lumiapassport/ui-kit
|
|
19
19
|
# or
|
|
20
|
-
yarn add @lumiapassport/ui-kit
|
|
20
|
+
yarn add @lumiapassport/ui-kit
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
## Quick Start
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
### 1. Setup QueryClient (Required)
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
npm install react react-dom viem wagmi @tanstack/react-query
|
|
29
|
-
```
|
|
27
|
+
The UI Kit requires `@tanstack/react-query` for state management. First, create a query client:
|
|
30
28
|
|
|
31
|
-
|
|
29
|
+
```tsx
|
|
30
|
+
// queryClient.ts
|
|
31
|
+
import { QueryClient } from '@tanstack/react-query';
|
|
32
|
+
|
|
33
|
+
export const queryClient = new QueryClient({
|
|
34
|
+
defaultOptions: {
|
|
35
|
+
queries: {
|
|
36
|
+
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
37
|
+
gcTime: 1000 * 60 * 10, // 10 minutes
|
|
38
|
+
refetchOnWindowFocus: false,
|
|
39
|
+
retry: false,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
```
|
|
32
44
|
|
|
33
|
-
###
|
|
45
|
+
### 2. Wrap your app with providers
|
|
34
46
|
|
|
35
47
|
```tsx
|
|
48
|
+
import { QueryClientProvider } from '@tanstack/react-query';
|
|
36
49
|
import { LumiaPassportProvider } from '@lumiapassport/ui-kit';
|
|
37
50
|
import '@lumiapassport/ui-kit/dist/styles.css';
|
|
51
|
+
import { queryClient } from './queryClient';
|
|
38
52
|
|
|
39
|
-
function
|
|
53
|
+
function Root() {
|
|
40
54
|
return (
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
projectId
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
</
|
|
55
|
+
<QueryClientProvider client={queryClient}>
|
|
56
|
+
<LumiaPassportProvider
|
|
57
|
+
projectId="your-project-id" // Get from Lumia Passport Dashboard
|
|
58
|
+
>
|
|
59
|
+
<YourApp />
|
|
60
|
+
</LumiaPassportProvider>
|
|
61
|
+
</QueryClientProvider>
|
|
48
62
|
);
|
|
49
63
|
}
|
|
50
64
|
```
|
|
51
65
|
|
|
52
|
-
###
|
|
66
|
+
### 3. Add the Connect Button
|
|
53
67
|
|
|
54
68
|
```tsx
|
|
55
69
|
import { ConnectWalletButton } from '@lumiapassport/ui-kit';
|
|
@@ -58,7 +72,7 @@ function YourApp() {
|
|
|
58
72
|
return (
|
|
59
73
|
<div>
|
|
60
74
|
<h1>My App</h1>
|
|
61
|
-
<ConnectWalletButton />
|
|
75
|
+
<ConnectWalletButton label="Sign in" mode="compact"/>
|
|
62
76
|
</div>
|
|
63
77
|
);
|
|
64
78
|
}
|
|
@@ -66,22 +80,24 @@ function YourApp() {
|
|
|
66
80
|
|
|
67
81
|
That's it! The `ConnectWalletButton` provides a complete authentication UI with wallet management.
|
|
68
82
|
|
|
83
|
+
> **Note:** Don't forget to wrap your app with `QueryClientProvider` from `@tanstack/react-query` before using `LumiaPassportProvider`, otherwise you'll get an error: "No QueryClient set, use QueryClientProvider to set one"
|
|
84
|
+
|
|
69
85
|
## Configuration Options
|
|
70
86
|
|
|
71
87
|
### Basic Configuration
|
|
72
88
|
|
|
73
89
|
```tsx
|
|
74
90
|
<LumiaPassportProvider
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
91
|
+
projectId="your-project-id" // Required
|
|
92
|
+
initialConfig={{
|
|
93
|
+
network: {
|
|
94
|
+
name: 'Lumia Beam',
|
|
95
|
+
symbol: 'LUMIA',
|
|
96
|
+
chainId: 2030232745,
|
|
97
|
+
rpcUrl: 'https://beam-rpc.lumia.org',
|
|
98
|
+
explorerUrl: 'https://beam-explorer.lumia.org',
|
|
99
|
+
testnet: true,
|
|
100
|
+
},
|
|
85
101
|
}}
|
|
86
102
|
>
|
|
87
103
|
```
|
|
@@ -90,27 +106,134 @@ That's it! The `ConnectWalletButton` provides a complete authentication UI with
|
|
|
90
106
|
|
|
91
107
|
```tsx
|
|
92
108
|
<LumiaPassportProvider
|
|
93
|
-
|
|
94
|
-
|
|
109
|
+
projectId="your-project-id"
|
|
110
|
+
initialConfig={{
|
|
111
|
+
// UI customization
|
|
112
|
+
ui: {
|
|
113
|
+
theme: 'dark', // 'light' | 'dark' | 'auto'
|
|
114
|
+
title: 'Welcome to MyApp',
|
|
115
|
+
subtitle: 'Sign in to continue',
|
|
116
|
+
authOrder: ['email', 'passkey', 'social'],
|
|
117
|
+
modal: {
|
|
118
|
+
width: '420px',
|
|
119
|
+
borderRadius: '24px'
|
|
120
|
+
},
|
|
121
|
+
branding: {
|
|
122
|
+
tagline: 'Powered by MPC',
|
|
123
|
+
link: { text: 'Learn More', url: 'https://example.com/docs' },
|
|
124
|
+
},
|
|
125
|
+
// Custom colors
|
|
126
|
+
colors: {
|
|
127
|
+
dark: {
|
|
128
|
+
background: '#060117',
|
|
129
|
+
text: '#fefdff',
|
|
130
|
+
textSecondary: '#c4c2c7',
|
|
131
|
+
textMuted: '#8a8890',
|
|
132
|
+
border: '#2a1a3a',
|
|
133
|
+
buttonBackground: '#ff6b35',
|
|
134
|
+
buttonBackgroundEnd: '#f7931e',
|
|
135
|
+
buttonText: '#ffffff',
|
|
136
|
+
buttonBackgroundHover: '#e55a2b',
|
|
137
|
+
buttonBackgroundHoverEnd: '#d67d1a',
|
|
138
|
+
connectedButtonBackground: 'rgba(27, 90, 226, 0.6)',
|
|
139
|
+
connectedButtonBorder: '#4a5568'
|
|
140
|
+
},
|
|
141
|
+
light: {
|
|
142
|
+
background: '#fefdff',
|
|
143
|
+
text: '#060117',
|
|
144
|
+
textSecondary: '#4a4754',
|
|
145
|
+
textMuted: '#6b6a70',
|
|
146
|
+
border: '#e0dde6',
|
|
147
|
+
buttonBackground: '#9333ea',
|
|
148
|
+
buttonBackgroundEnd: '#2563eb',
|
|
149
|
+
buttonText: '#fefdff',
|
|
150
|
+
buttonBackgroundHover: '#7e22ce',
|
|
151
|
+
buttonBackgroundHoverEnd: '#1d4ed8',
|
|
152
|
+
connectedButtonBackground: '#f3f4f6',
|
|
153
|
+
connectedButtonBorder: '#d1d5db'
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
},
|
|
95
157
|
|
|
96
158
|
// Authentication providers
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
159
|
+
email: {
|
|
160
|
+
enabled: true,
|
|
161
|
+
placeholder: 'Enter your email',
|
|
162
|
+
buttonText: 'Continue',
|
|
163
|
+
verificationTitle: 'Check your email',
|
|
102
164
|
},
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
165
|
+
passkey: {
|
|
166
|
+
enabled: true,
|
|
167
|
+
showCreateButton: true,
|
|
168
|
+
primaryButtonText: 'Sign in with Passkey',
|
|
169
|
+
},
|
|
170
|
+
social: {
|
|
171
|
+
enabled: true,
|
|
172
|
+
gridColumns: 2,
|
|
173
|
+
providers: [
|
|
174
|
+
{ id: 'Discord', name: 'Discord', enabled: true, comingSoon: false },
|
|
175
|
+
{ id: 'telegram', name: 'Telegram', enabled: true, comingSoon: false },
|
|
176
|
+
],
|
|
177
|
+
},
|
|
178
|
+
wallet: {
|
|
179
|
+
enabled: true,
|
|
180
|
+
supportedChains: [994873017, 2030232745],
|
|
181
|
+
requireSignature: true,
|
|
182
|
+
walletConnectProjectId: 'your-walletconnect-id',
|
|
108
183
|
},
|
|
109
184
|
|
|
110
185
|
// Features
|
|
111
186
|
features: {
|
|
112
|
-
|
|
113
|
-
|
|
187
|
+
mpcSecurity: true,
|
|
188
|
+
strictMode: false,
|
|
189
|
+
requestDeduplication: true,
|
|
190
|
+
kycNeeded: false,
|
|
191
|
+
displayNameNeeded: false,
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
// KYC configuration (if needed)
|
|
195
|
+
kyc: {
|
|
196
|
+
provider: 'sumsub',
|
|
197
|
+
options: { levelName: 'basic-kyc', flowName: 'default' }
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
// Warnings
|
|
201
|
+
warnings: {
|
|
202
|
+
backupWarning: true,
|
|
203
|
+
emailNotConnectedWarning: true,
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
// Network configuration
|
|
207
|
+
network: {
|
|
208
|
+
name: 'Lumia Beam',
|
|
209
|
+
symbol: 'LUMIA',
|
|
210
|
+
chainId: 2030232745,
|
|
211
|
+
rpcUrl: 'https://beam-rpc.lumia.org',
|
|
212
|
+
explorerUrl: 'https://beam-explorer.lumia.org',
|
|
213
|
+
testnet: true,
|
|
214
|
+
},
|
|
215
|
+
}}
|
|
216
|
+
callbacks={{
|
|
217
|
+
onLumiaPassportConnecting: ({ method, provider }) => {
|
|
218
|
+
console.log('Connecting with:', method, provider);
|
|
219
|
+
},
|
|
220
|
+
onLumiaPassportConnect: ({ address, session }) => {
|
|
221
|
+
console.log('Connected:', address);
|
|
222
|
+
},
|
|
223
|
+
onLumiaPassportAccount: ({ userId, address, session, hasKeyshare }) => {
|
|
224
|
+
console.log('Account ready:', userId);
|
|
225
|
+
},
|
|
226
|
+
onLumiaPassportUpdate: ({ providers }) => {
|
|
227
|
+
console.log('Profile updated:', providers);
|
|
228
|
+
},
|
|
229
|
+
onLumiaPassportDisconnect: ({ address, userId }) => {
|
|
230
|
+
console.log('Disconnected:', address);
|
|
231
|
+
},
|
|
232
|
+
onLumiaPassportError: ({ error, message }) => {
|
|
233
|
+
console.error('Error:', message);
|
|
234
|
+
},
|
|
235
|
+
onWalletReady: (status) => {
|
|
236
|
+
console.log('Wallet ready:', status.ready);
|
|
114
237
|
},
|
|
115
238
|
}}
|
|
116
239
|
>
|
|
@@ -348,12 +471,14 @@ Secure biometric authentication with device passkeys.
|
|
|
348
471
|
Authentication via Telegram for mini apps.
|
|
349
472
|
|
|
350
473
|
```tsx
|
|
351
|
-
//
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
474
|
+
// Configure via social providers:
|
|
475
|
+
initialConfig={{
|
|
476
|
+
social: {
|
|
477
|
+
enabled: true,
|
|
478
|
+
providers: [
|
|
479
|
+
{ id: 'telegram', name: 'Telegram', enabled: true },
|
|
480
|
+
],
|
|
481
|
+
},
|
|
357
482
|
}}
|
|
358
483
|
```
|
|
359
484
|
|
|
@@ -374,10 +499,10 @@ Connect existing wallets (MetaMask, WalletConnect, etc.).
|
|
|
374
499
|
import '@lumiapassport/ui-kit/dist/styles.css';
|
|
375
500
|
|
|
376
501
|
<LumiaPassportProvider
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
502
|
+
projectId="your-project-id"
|
|
503
|
+
initialConfig={{
|
|
504
|
+
ui: {
|
|
505
|
+
theme: 'dark', // or 'light', 'auto'
|
|
381
506
|
}
|
|
382
507
|
}}
|
|
383
508
|
>
|
package/dist/iframe/index.html
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
<meta http-equiv="X-Content-Type-Options" content="nosniff" />
|
|
16
16
|
<meta http-equiv="Referrer-Policy" content="strict-origin-when-cross-origin" />
|
|
17
17
|
|
|
18
|
-
<title>Lumia Passport Secure Wallet - iframe version 1.5.
|
|
18
|
+
<title>Lumia Passport Secure Wallet - iframe version 1.5.3</title>
|
|
19
19
|
|
|
20
20
|
<!-- Styles will be injected by build process -->
|
|
21
21
|
<style>
|
|
@@ -203,7 +203,7 @@
|
|
|
203
203
|
|
|
204
204
|
.app-logo {
|
|
205
205
|
width: 64px;
|
|
206
|
-
height: 64px;
|
|
206
|
+
/* height: 64px; */
|
|
207
207
|
border-radius: 12px;
|
|
208
208
|
border: 1px solid var(--iframe-border);
|
|
209
209
|
object-fit: cover;
|
|
@@ -284,20 +284,20 @@
|
|
|
284
284
|
.permissions-box {
|
|
285
285
|
margin: 1.5rem 2rem;
|
|
286
286
|
padding: 1rem;
|
|
287
|
-
border: 1px solid
|
|
287
|
+
border: 1px solid var(--iframe-text);
|
|
288
288
|
border-radius: 8px;
|
|
289
|
-
background:
|
|
289
|
+
background: transparent;
|
|
290
290
|
}
|
|
291
291
|
|
|
292
292
|
.permissions-header {
|
|
293
293
|
font-size: 0.875rem;
|
|
294
|
-
color:
|
|
294
|
+
color: var(--iframe-text);
|
|
295
295
|
margin-bottom: 1rem;
|
|
296
296
|
line-height: 1.5;
|
|
297
297
|
}
|
|
298
298
|
|
|
299
299
|
.project-owner {
|
|
300
|
-
color:
|
|
300
|
+
color: var(--iframe-text-secondary);
|
|
301
301
|
}
|
|
302
302
|
|
|
303
303
|
.permission-group {
|
|
@@ -311,7 +311,7 @@
|
|
|
311
311
|
.permission-group-title {
|
|
312
312
|
font-size: 0.8125rem;
|
|
313
313
|
font-weight: 600;
|
|
314
|
-
color:
|
|
314
|
+
color: var(--iframe-text);
|
|
315
315
|
margin-bottom: 0.5rem;
|
|
316
316
|
}
|
|
317
317
|
|
|
@@ -323,7 +323,7 @@
|
|
|
323
323
|
|
|
324
324
|
.permissions-list li {
|
|
325
325
|
font-size: 0.8125rem;
|
|
326
|
-
color:
|
|
326
|
+
color: var(--iframe-text);
|
|
327
327
|
padding: 0.25rem 0;
|
|
328
328
|
padding-left: 1.25rem;
|
|
329
329
|
position: relative;
|
|
@@ -333,7 +333,7 @@
|
|
|
333
333
|
content: "•";
|
|
334
334
|
position: absolute;
|
|
335
335
|
left: 0.5rem;
|
|
336
|
-
color:
|
|
336
|
+
color: var(--iframe-text-secondary);
|
|
337
337
|
}
|
|
338
338
|
|
|
339
339
|
/* Actions Section */
|
|
@@ -423,19 +423,14 @@
|
|
|
423
423
|
font-size: 0.9rem;
|
|
424
424
|
}
|
|
425
425
|
|
|
426
|
-
.detail-row:not(:last-child) {
|
|
427
|
-
border-bottom: 1px solid #e5e7eb;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
426
|
.detail-row code {
|
|
431
427
|
font-family: 'Courier New', monospace;
|
|
432
|
-
font-size: 0.85rem;
|
|
433
|
-
color: #6b7280;
|
|
434
428
|
}
|
|
435
429
|
|
|
430
|
+
|
|
436
431
|
/* Security Warning */
|
|
437
432
|
.security-warning {
|
|
438
|
-
margin:
|
|
433
|
+
margin: 1.5rem 2rem;
|
|
439
434
|
padding: 1rem;
|
|
440
435
|
background: #fff8c5;
|
|
441
436
|
border: 1px solid #d29922;
|
|
@@ -516,7 +511,7 @@
|
|
|
516
511
|
|
|
517
512
|
/* Trust app checkbox section */
|
|
518
513
|
.trust-app-section {
|
|
519
|
-
margin:
|
|
514
|
+
margin: 1.5rem 2rem;
|
|
520
515
|
padding: 0.75rem;
|
|
521
516
|
background: #f9fafb;
|
|
522
517
|
border-radius: 6px;
|
package/dist/iframe/main.js
CHANGED
|
@@ -2595,6 +2595,11 @@ var SigningManager = class extends TokenRefreshApiClient {
|
|
|
2595
2595
|
constructor() {
|
|
2596
2596
|
super();
|
|
2597
2597
|
this.wasmLoaded = false;
|
|
2598
|
+
this.explorerUrl = "https://beam-explorer.lumia.org";
|
|
2599
|
+
this.METADATA_API_URL = "https://dashboard.lumiapassport.com/api/public/project";
|
|
2600
|
+
this.METADATA_CACHE_TTL = 36e5;
|
|
2601
|
+
// 1 hour in milliseconds
|
|
2602
|
+
this.metadataCache = /* @__PURE__ */ new Map();
|
|
2598
2603
|
this.storage = new StorageManager();
|
|
2599
2604
|
this.trustedApps = new TrustedAppsManager();
|
|
2600
2605
|
}
|
|
@@ -2612,6 +2617,34 @@ var SigningManager = class extends TokenRefreshApiClient {
|
|
|
2612
2617
|
throw new Error("Failed to initialize signing WASM module");
|
|
2613
2618
|
}
|
|
2614
2619
|
}
|
|
2620
|
+
/**
|
|
2621
|
+
* Fetch project metadata from public API (with caching)
|
|
2622
|
+
*/
|
|
2623
|
+
async fetchProjectMetadata(projectId) {
|
|
2624
|
+
const cached = this.metadataCache.get(projectId);
|
|
2625
|
+
const now = Date.now();
|
|
2626
|
+
if (cached && now - cached.timestamp < this.METADATA_CACHE_TTL) {
|
|
2627
|
+
console.log(`[iframe][Sign] Using cached metadata for project: ${cached.data.name}`);
|
|
2628
|
+
return cached.data;
|
|
2629
|
+
}
|
|
2630
|
+
try {
|
|
2631
|
+
const response = await fetch(`${this.METADATA_API_URL}/${projectId}/metadata`);
|
|
2632
|
+
if (!response.ok) {
|
|
2633
|
+
console.warn(`[iframe][Sign] Failed to fetch project metadata: ${response.status}`);
|
|
2634
|
+
return null;
|
|
2635
|
+
}
|
|
2636
|
+
const metadata = await response.json();
|
|
2637
|
+
console.log(`[iframe][Sign] Fetched metadata for project: ${metadata.name}`);
|
|
2638
|
+
this.metadataCache.set(projectId, {
|
|
2639
|
+
data: metadata,
|
|
2640
|
+
timestamp: now
|
|
2641
|
+
});
|
|
2642
|
+
return metadata;
|
|
2643
|
+
} catch (error) {
|
|
2644
|
+
console.error("[iframe][Sign] Error fetching project metadata:", error);
|
|
2645
|
+
return null;
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2615
2648
|
/**
|
|
2616
2649
|
* Sign transaction with user confirmation
|
|
2617
2650
|
*/
|
|
@@ -2719,8 +2752,9 @@ var SigningManager = class extends TokenRefreshApiClient {
|
|
|
2719
2752
|
*/
|
|
2720
2753
|
async showConfirmationDialog(userId, projectId, project, origin, transaction, risk) {
|
|
2721
2754
|
this.showIframe();
|
|
2755
|
+
const metadata = await this.fetchProjectMetadata(projectId);
|
|
2722
2756
|
return new Promise((resolve) => {
|
|
2723
|
-
const modal = this.createConfirmationModal(userId, projectId, project, origin, transaction, risk);
|
|
2757
|
+
const modal = this.createConfirmationModal(userId, projectId, project, origin, transaction, risk, metadata);
|
|
2724
2758
|
const confirmBtn = modal.querySelector(".confirm-btn");
|
|
2725
2759
|
const cancelBtn = modal.querySelector(".cancel-btn");
|
|
2726
2760
|
const trustCheckbox = modal.querySelector(".trust-app-checkbox");
|
|
@@ -2743,79 +2777,91 @@ var SigningManager = class extends TokenRefreshApiClient {
|
|
|
2743
2777
|
/**
|
|
2744
2778
|
* Create confirmation modal UI
|
|
2745
2779
|
*/
|
|
2746
|
-
createConfirmationModal(userId, projectId, project, origin, transaction, risk) {
|
|
2780
|
+
createConfirmationModal(userId, projectId, project, origin, transaction, risk, metadata) {
|
|
2747
2781
|
const modal = document.createElement("div");
|
|
2748
2782
|
modal.className = "transaction-confirmation-modal";
|
|
2749
|
-
const
|
|
2783
|
+
const isVerifiedOrigin = project.domains.includes(origin);
|
|
2750
2784
|
const isUserOp = !!transaction.userOpDetails;
|
|
2751
|
-
const formatHex = (value, maxLength = 20) => {
|
|
2752
|
-
if (!value) return "N/A";
|
|
2753
|
-
if (value.length > maxLength) {
|
|
2754
|
-
return `${value.substring(0, maxLength)}...`;
|
|
2755
|
-
}
|
|
2756
|
-
return value;
|
|
2757
|
-
};
|
|
2758
|
-
const formatGas = (gasLimit, gasPrice) => {
|
|
2759
|
-
if (!gasLimit || !gasPrice) return "N/A";
|
|
2760
|
-
try {
|
|
2761
|
-
const gas = BigInt(gasLimit);
|
|
2762
|
-
const price = BigInt(gasPrice);
|
|
2763
|
-
const totalWei = gas * price;
|
|
2764
|
-
const totalEth = Number(totalWei) / 1e18;
|
|
2765
|
-
return totalEth.toFixed(9) + " ETH";
|
|
2766
|
-
} catch {
|
|
2767
|
-
return "N/A";
|
|
2768
|
-
}
|
|
2769
|
-
};
|
|
2770
2785
|
const isSponsored = isUserOp && !!transaction.userOpDetails?.paymaster;
|
|
2771
2786
|
const estimatedCost = isSponsored ? "0 (Sponsored)" : "Free (Sponsored Transaction)";
|
|
2787
|
+
const displayName = metadata?.name || project.name;
|
|
2788
|
+
const displayLogo = metadata?.logo || project.logoUrl;
|
|
2789
|
+
const fromAddress = transaction.userOpDetails?.sender;
|
|
2790
|
+
const toAddress = transaction.userOpDetails?.callTarget || transaction.to;
|
|
2772
2791
|
modal.innerHTML = `
|
|
2773
2792
|
<div class="modal-overlay">
|
|
2774
2793
|
<div class="modal-content">
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
<
|
|
2794
|
+
<!-- Header with logos -->
|
|
2795
|
+
<div class="auth-header">
|
|
2796
|
+
<div class="logo-container">
|
|
2797
|
+
${displayLogo ? `<img src="${displayLogo}" alt="${displayName}" class="app-logo" />` : '<div class="app-logo-placeholder"></div>'}
|
|
2798
|
+
<div class="logo-connector">
|
|
2799
|
+
<svg width="24" height="16" viewBox="0 0 24 16" fill="currentColor">
|
|
2800
|
+
<path d="M23.7071 8.70711C24.0976 8.31658 24.0976 7.68342 23.7071 7.29289L17.3431 0.928932C16.9526 0.538408 16.3195 0.538408 15.9289 0.928932C15.5384 1.31946 15.5384 1.95262 15.9289 2.34315L21.5858 8L15.9289 13.6569C15.5384 14.0474 15.5384 14.6805 15.9289 15.0711C16.3195 15.4616 16.9526 15.4616 17.3431 15.0711L23.7071 8.70711ZM0 9H23V7H0V9Z"/>
|
|
2801
|
+
</svg>
|
|
2802
|
+
</div>
|
|
2803
|
+
<img src="./lumia-logo.svg" alt="Lumia Passport" class="lumia-logo" />
|
|
2779
2804
|
</div>
|
|
2780
2805
|
</div>
|
|
2781
2806
|
|
|
2782
|
-
|
|
2807
|
+
<!-- Transaction title -->
|
|
2808
|
+
<h2 class="auth-title">Confirm Transaction</h2>
|
|
2783
2809
|
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2810
|
+
<!-- Application info -->
|
|
2811
|
+
<div class="auth-description">
|
|
2812
|
+
<div class="domain-info ${isVerifiedOrigin ? "verified" : "unverified"}">
|
|
2813
|
+
<span class="domain-label">
|
|
2814
|
+
${isVerifiedOrigin ? "\u2713 Verified:" : "\u26A0\uFE0F Unverified:"}
|
|
2815
|
+
</span>
|
|
2816
|
+
<span class="domain-value">${origin}</span>
|
|
2788
2817
|
</div>
|
|
2789
|
-
|
|
2818
|
+
</div>
|
|
2790
2819
|
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
<
|
|
2795
|
-
|
|
2820
|
+
<!-- Transaction details box -->
|
|
2821
|
+
<div class="permissions-box">
|
|
2822
|
+
${fromAddress ? `
|
|
2823
|
+
<div class="detail-row" style="margin-bottom: 0.5rem;">
|
|
2824
|
+
<div style="color: var(--iframe-text-secondary); font-size: 0.875rem; margin-bottom: 0.25rem;"><strong>From:</strong></div>
|
|
2825
|
+
<code style="font-size: 0.75rem; word-break: break-all; display: block; color: var(--iframe-text);">${fromAddress}</code>
|
|
2826
|
+
</div>
|
|
2827
|
+
` : ""}
|
|
2828
|
+
|
|
2829
|
+
${toAddress ? `
|
|
2830
|
+
<div class="detail-row" style="margin-bottom: 0.5rem;">
|
|
2831
|
+
<div style="color: var(--iframe-text-secondary); font-size: 0.875rem; margin-bottom: 0.25rem;"><strong>To:</strong></div>
|
|
2832
|
+
<code style="font-size: 0.75rem; word-break: break-all; display: block; color: var(--iframe-text);">${toAddress}</code>
|
|
2833
|
+
</div>
|
|
2834
|
+
` : ""}
|
|
2796
2835
|
|
|
2797
2836
|
${isUserOp && transaction.userOpDetails?.callData && transaction.userOpDetails.callData !== "0x" ? `
|
|
2798
|
-
<div class="detail-row">
|
|
2799
|
-
<span><strong>Action:</strong></span>
|
|
2800
|
-
<span>Contract Interaction</span>
|
|
2837
|
+
<div class="detail-row" style="margin-bottom: 0.5rem;">
|
|
2838
|
+
<span style="color: var(--iframe-text-secondary);"><strong>Action:</strong></span>
|
|
2839
|
+
<span style="color: var(--iframe-text);">Contract Interaction</span>
|
|
2801
2840
|
</div>
|
|
2802
2841
|
` : ""}
|
|
2803
2842
|
|
|
2804
|
-
<div class="detail-row">
|
|
2805
|
-
<span><strong>Estimated Cost:</strong></span>
|
|
2843
|
+
<div class="detail-row" style="margin-bottom: 0.5rem;">
|
|
2844
|
+
<span style="color: var(--iframe-text-secondary);"><strong>Estimated Cost:</strong></span>
|
|
2806
2845
|
<strong style="color: #10b981;">${estimatedCost}</strong>
|
|
2807
2846
|
</div>
|
|
2808
2847
|
|
|
2809
2848
|
${isSponsored ? `
|
|
2810
|
-
<div class="
|
|
2811
|
-
<
|
|
2849
|
+
<div class="detail-row" style="background: #d1fae5; border-radius: 6px; padding: 0.75rem; margin-top: 0.5rem;">
|
|
2850
|
+
<span style="color: #047857;">\u2713 Gas fees will be paid by the application (no cost to you)</span>
|
|
2812
2851
|
</div>
|
|
2813
2852
|
` : ""}
|
|
2814
2853
|
</div>
|
|
2815
2854
|
|
|
2816
|
-
|
|
2817
|
-
<
|
|
2818
|
-
|
|
2855
|
+
${risk.level !== "LOW" ? `
|
|
2856
|
+
<div class="security-warning">
|
|
2857
|
+
<strong>\u26A0\uFE0F ${risk.level} RISK</strong>
|
|
2858
|
+
${risk.reasons.map((r) => `<div>\u2022 ${r}</div>`).join("")}
|
|
2859
|
+
</div>
|
|
2860
|
+
` : `
|
|
2861
|
+
<div class="security-warning">
|
|
2862
|
+
<strong>\u26A0\uFE0F Warning:</strong> Please verify this transaction carefully before confirming.
|
|
2863
|
+
</div>
|
|
2864
|
+
`}
|
|
2819
2865
|
|
|
2820
2866
|
<div class="trust-app-section">
|
|
2821
2867
|
<label class="trust-app-label">
|
|
@@ -2824,10 +2870,16 @@ var SigningManager = class extends TokenRefreshApiClient {
|
|
|
2824
2870
|
</label>
|
|
2825
2871
|
</div>
|
|
2826
2872
|
|
|
2873
|
+
<!-- Action buttons -->
|
|
2827
2874
|
<div class="actions">
|
|
2828
2875
|
<button class="cancel-btn">Reject</button>
|
|
2829
2876
|
<button class="confirm-btn">Confirm</button>
|
|
2830
2877
|
</div>
|
|
2878
|
+
|
|
2879
|
+
<!-- Footer notice -->
|
|
2880
|
+
<div class="auth-footer">
|
|
2881
|
+
<p class="footer-note">You can manage trusted applications in your Lumia Passport settings.</p>
|
|
2882
|
+
</div>
|
|
2831
2883
|
</div>
|
|
2832
2884
|
</div>
|
|
2833
2885
|
`;
|
|
@@ -2922,12 +2974,21 @@ var AuthorizationManager = class {
|
|
|
2922
2974
|
constructor() {
|
|
2923
2975
|
this.STORAGE_KEY_PREFIX = "auth";
|
|
2924
2976
|
this.METADATA_API_URL = "https://dashboard.lumiapassport.com/api/public/project";
|
|
2977
|
+
this.METADATA_CACHE_TTL = 36e5;
|
|
2978
|
+
// 1 hour in milliseconds
|
|
2979
|
+
this.metadataCache = /* @__PURE__ */ new Map();
|
|
2925
2980
|
console.log("[iframe][Auth] Initialized");
|
|
2926
2981
|
}
|
|
2927
2982
|
/**
|
|
2928
|
-
* Fetch project metadata from public API
|
|
2983
|
+
* Fetch project metadata from public API (with caching)
|
|
2929
2984
|
*/
|
|
2930
2985
|
async fetchProjectMetadata(projectId) {
|
|
2986
|
+
const cached = this.metadataCache.get(projectId);
|
|
2987
|
+
const now = Date.now();
|
|
2988
|
+
if (cached && now - cached.timestamp < this.METADATA_CACHE_TTL) {
|
|
2989
|
+
console.log(`[iframe][Auth] Using cached metadata for project: ${cached.data.name}`);
|
|
2990
|
+
return cached.data;
|
|
2991
|
+
}
|
|
2931
2992
|
try {
|
|
2932
2993
|
const response = await fetch(`${this.METADATA_API_URL}/${projectId}/metadata`);
|
|
2933
2994
|
if (!response.ok) {
|
|
@@ -2936,6 +2997,10 @@ var AuthorizationManager = class {
|
|
|
2936
2997
|
}
|
|
2937
2998
|
const metadata = await response.json();
|
|
2938
2999
|
console.log(`[iframe][Auth] Fetched metadata for project: ${metadata.name}`);
|
|
3000
|
+
this.metadataCache.set(projectId, {
|
|
3001
|
+
data: metadata,
|
|
3002
|
+
timestamp: now
|
|
3003
|
+
});
|
|
2939
3004
|
return metadata;
|
|
2940
3005
|
} catch (error) {
|
|
2941
3006
|
console.error("[iframe][Auth] Error fetching project metadata:", error);
|
|
@@ -3659,7 +3724,7 @@ var BackupManager = class {
|
|
|
3659
3724
|
};
|
|
3660
3725
|
|
|
3661
3726
|
// src/iframe/main.ts
|
|
3662
|
-
var IFRAME_VERSION = "1.5.
|
|
3727
|
+
var IFRAME_VERSION = "1.5.3";
|
|
3663
3728
|
var IframeWallet = class {
|
|
3664
3729
|
constructor() {
|
|
3665
3730
|
console.log("=".repeat(60));
|