@lumiapassport/ui-kit 1.8.0 → 1.9.0

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 CHANGED
@@ -340,6 +340,62 @@ function DirectTransactionExample() {
340
340
  - ✅ Use `useSendTransaction()` hook for React components (automatic session management)
341
341
  - ✅ Use `sendUserOperation()` function for custom logic, utility functions, or non-React code
342
342
 
343
+ ### deployAccount - Deploy Smart Account (Optional)
344
+
345
+ Deploy the smart account contract immediately after registration. This is **optional** - accounts are automatically deployed on first transaction.
346
+
347
+ **Smart behavior:** Automatically checks if account is already deployed and skips transaction to save gas.
348
+
349
+ ```tsx
350
+ import { deployAccount, useLumiaPassportSession } from '@lumiapassport/ui-kit';
351
+
352
+ function DeployAccountExample() {
353
+ const { session } = useLumiaPassportSession();
354
+
355
+ const handleDeploy = async () => {
356
+ if (!session) return;
357
+
358
+ try {
359
+ // Deploy account with minimal gas cost (skips if already deployed)
360
+ const userOpHash = await deployAccount(session, 'economy');
361
+
362
+ if (userOpHash) {
363
+ console.log('Account deployed:', userOpHash);
364
+ } else {
365
+ console.log('Account already deployed, skipped');
366
+ }
367
+ } catch (error) {
368
+ console.error('Deployment failed:', error);
369
+ }
370
+ };
371
+
372
+ return <button onClick={handleDeploy}>Deploy Account</button>;
373
+ }
374
+ ```
375
+
376
+ **Return values:**
377
+ - Returns `userOpHash` (string) - if deployment was needed and executed
378
+ - Returns `null` - if account already deployed (saves gas)
379
+
380
+ **Advanced usage:**
381
+ ```tsx
382
+ // Force deployment even if already deployed (not recommended)
383
+ const hash = await deployAccount(session, 'economy', { force: true });
384
+ ```
385
+
386
+ **Why use this?**
387
+ - ✅ **Pre-deploy** account before first real transaction
388
+ - ✅ **No user consent** required (safe minimal operation)
389
+ - ✅ **Cleaner UX** - separate deployment from first payment
390
+ - ✅ **Smart gas savings** - auto-skips if already deployed
391
+ - ⚠️ **Optional** - accounts auto-deploy on first transaction anyway
392
+
393
+ **How it works:**
394
+ 1. Checks if smart account contract exists on-chain
395
+ 2. If exists: returns `null` immediately (no gas cost)
396
+ 3. If not exists: sends minimal UserOperation (`to=0x0, value=0, data=0x`)
397
+ 4. Factory deploys contract without user confirmation
398
+
343
399
  ### signTypedData - Sign EIP712 Structured Messages
344
400
 
345
401
  Sign structured data according to [EIP-712](https://eips.ethereum.org/EIPS/eip-712) standard. This is commonly used for off-chain signatures in dApps (e.g., NFT marketplace orders, gasless transactions, permit signatures).
@@ -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.8.0</title>
18
+ <title>Lumia Passport Secure Wallet - iframe version 1.9.0</title>
19
19
 
20
20
  <!-- Styles will be injected by build process -->
21
21
  <style>
@@ -1085,7 +1085,6 @@ async function uploadShareToVault(encryptedShare, accessToken) {
1085
1085
  "Authorization": `Bearer ${token}`,
1086
1086
  "Idempotency-Key": idempotencyKey
1087
1087
  },
1088
- credentials: "include",
1089
1088
  body: JSON.stringify(encryptedShare)
1090
1089
  });
1091
1090
  if (!response.ok) {
@@ -1110,8 +1109,7 @@ async function downloadShareFromVault(accessToken) {
1110
1109
  "Authorization": `Bearer ${token}`,
1111
1110
  "X-Client-Device-Id": "lumia-ui-kit",
1112
1111
  "X-Client-Device-Name": "Lumia UI Kit"
1113
- },
1114
- credentials: "include"
1112
+ }
1115
1113
  });
1116
1114
  if (!response.ok) {
1117
1115
  if (response.status === 404) {
@@ -2620,6 +2618,34 @@ var SigningManager = class extends TokenRefreshApiClient {
2620
2618
  throw new Error("Failed to initialize signing WASM module");
2621
2619
  }
2622
2620
  }
2621
+ /**
2622
+ * Check if transaction is a minimal safe operation (account deployment)
2623
+ *
2624
+ * Minimal operations are safe to auto-approve without user consent:
2625
+ * - to: 0x0000000000000000000000000000000000000000 (burn address)
2626
+ * - value: 0 (no funds transfer)
2627
+ * - data: 0x (no contract call)
2628
+ *
2629
+ * This is used for smart account deployment without spending any funds.
2630
+ */
2631
+ isMinimalSafeOperation(transaction) {
2632
+ const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
2633
+ const ZERO_VALUE = "0";
2634
+ const EMPTY_DATA = "0x";
2635
+ const to = transaction.to?.toLowerCase();
2636
+ const value = transaction.value?.toString() || "0";
2637
+ const data = transaction.data?.toLowerCase() || "0x";
2638
+ const isMinimal = to === ZERO_ADDRESS.toLowerCase() && (value === ZERO_VALUE || value === "0x0") && (data === EMPTY_DATA || data === "0x0");
2639
+ if (isMinimal) {
2640
+ console.log("[iframe][Sign] Detected minimal safe operation:", {
2641
+ to,
2642
+ value,
2643
+ data,
2644
+ reason: "Account deployment - no funds at risk"
2645
+ });
2646
+ }
2647
+ return isMinimal;
2648
+ }
2623
2649
  /**
2624
2650
  * Fetch project metadata from public API (with caching)
2625
2651
  */
@@ -2631,9 +2657,7 @@ var SigningManager = class extends TokenRefreshApiClient {
2631
2657
  return cached.data;
2632
2658
  }
2633
2659
  try {
2634
- const response = await fetch(`${this.METADATA_API_URL}/${projectId}/metadata`, {
2635
- credentials: "include"
2636
- });
2660
+ const response = await fetch(`${this.METADATA_API_URL}/${projectId}/metadata`);
2637
2661
  if (!response.ok) {
2638
2662
  console.warn(`[iframe][Sign] Failed to fetch project metadata: ${response.status}`);
2639
2663
  return null;
@@ -2668,8 +2692,9 @@ var SigningManager = class extends TokenRefreshApiClient {
2668
2692
  website: origin,
2669
2693
  domains: [origin]
2670
2694
  };
2695
+ const isMinimalOperation = this.isMinimalSafeOperation(transaction);
2671
2696
  const isTrusted = this.trustedApps.isTrusted(userId, projectId, origin);
2672
- if (!isTrusted) {
2697
+ if (!isTrusted && !isMinimalOperation) {
2673
2698
  const risk = await this.assessRisk(transaction);
2674
2699
  const confirmResult = await this.showConfirmationDialog(
2675
2700
  userId,
@@ -2685,6 +2710,8 @@ var SigningManager = class extends TokenRefreshApiClient {
2685
2710
  if (confirmResult.trustApp) {
2686
2711
  this.trustedApps.addTrustedApp(userId, projectId, origin);
2687
2712
  }
2713
+ } else if (isMinimalOperation) {
2714
+ console.log("[iframe][Sign] Auto-approving minimal safe operation (account deployment)");
2688
2715
  }
2689
2716
  const digest32 = transaction.digest32 || this.computeTransactionHash(transaction);
2690
2717
  const signature = await this.performMPCSigning(userId, keyshareData, digest32, projectId, accessToken);
@@ -3191,9 +3218,7 @@ var AuthorizationManager = class {
3191
3218
  return cached.data;
3192
3219
  }
3193
3220
  try {
3194
- const response = await fetch(`${this.METADATA_API_URL}/${projectId}/metadata`, {
3195
- credentials: "include"
3196
- });
3221
+ const response = await fetch(`${this.METADATA_API_URL}/${projectId}/metadata`);
3197
3222
  if (!response.ok) {
3198
3223
  console.warn(`[iframe][Auth] Failed to fetch project metadata: ${response.status}`);
3199
3224
  return null;
@@ -3930,7 +3955,7 @@ var BackupManager = class {
3930
3955
  };
3931
3956
 
3932
3957
  // src/iframe/main.ts
3933
- var IFRAME_VERSION = "1.8.0";
3958
+ var IFRAME_VERSION = "1.9.0";
3934
3959
  var IframeWallet = class {
3935
3960
  constructor() {
3936
3961
  console.log("=".repeat(60));