@lumiapassport/ui-kit 1.14.9 → 1.14.11

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
@@ -162,7 +162,6 @@ That's it! The `ConnectWalletButton` provides a complete authentication UI with
162
162
  },
163
163
  social: {
164
164
  enabled: true,
165
- gridColumns: 2,
166
165
  providers: [
167
166
  { id: 'Discord', name: 'Discord', enabled: true, comingSoon: false },
168
167
  { id: 'telegram', name: 'Telegram', enabled: true, comingSoon: false },
@@ -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.14.9</title>
18
+ <title>Lumia Passport Secure Wallet - iframe version 1.14.11</title>
19
19
 
20
20
  <!-- Styles will be injected by build process -->
21
21
  <style>
@@ -108,9 +108,9 @@
108
108
  justify-content: center;
109
109
  font-size: 20px;
110
110
  font-weight: 600;
111
- width: 64px;
112
- height: 64px;
113
- border-radius: 32px;
111
+ width: 48px;
112
+ height: 48px;
113
+ border-radius: 24px;
114
114
  background: var(--iframe-success);
115
115
  color: #000000;
116
116
  }
@@ -608,39 +608,46 @@
608
608
  }
609
609
 
610
610
  /* Trust app checkbox section */
611
+ /* OK */
611
612
  .trust-app-section {
612
- margin: 1.5rem 2rem;
613
- padding: 0.75rem;
614
- background: #f9fafb;
615
- border-radius: 6px;
616
- border: 1px solid #e5e7eb;
613
+ width: 100%;
614
+ padding: var(--iframe-gap);
615
+ background: var(--iframe-info);
616
+ border-radius: var(--iframe-el-bdrs);
617
+ border: 1px solid var(--iframe-bd);
618
+ transition: opacity 0.2s ease;
619
+ }
620
+ .trust-app-section:hover {
621
+ opacity: 0.6;
622
+ }
623
+ .trust-app-section:active {
624
+ opacity: 0.4;
617
625
  }
618
626
 
627
+ /* OK */
619
628
  .trust-app-label {
620
629
  display: flex;
621
- align-items: center;
622
- gap: 0.5rem;
630
+ align-items: flex-start;
631
+ gap: var(--iframe-gap);
623
632
  cursor: pointer;
624
633
  font-size: 0.9rem;
625
- color: #374151;
626
634
  }
627
635
 
636
+ /* OK */
628
637
  .trust-app-checkbox {
629
- width: 18px;
630
- height: 18px;
638
+ width: 24px;
639
+ height: 24px;
631
640
  cursor: pointer;
632
641
  flex-shrink: 0;
633
642
  }
634
643
 
635
644
  .trust-app-label span {
636
- line-height: 1.4;
645
+ font-weight: 600;
646
+ font-size: 14px;
647
+ line-height: 1.2;
637
648
  user-select: none;
638
649
  }
639
650
 
640
- .trust-app-label:hover {
641
- color: #111827;
642
- }
643
-
644
651
  /* EIP712 Signature Request Modal Styles */
645
652
  .eip712-confirmation-modal {
646
653
  position: fixed;
@@ -1267,11 +1267,17 @@ var TemplateEngine = class {
1267
1267
  };
1268
1268
 
1269
1269
  // src/iframe/templates/html/authorization.html
1270
- var authorization_default = '<div\n style="\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n background: #000000;\n "\n>\n <div\n style="\n display: flex;\n flex-direction: column;\n gap: var(--iframe-gap);\n align-items: center;\n background: var(--iframe-modal-bg);\n border-radius: 20px;\n padding: 20px;\n max-width: 320px;\n width: calc(100% - 40px);\n max-height: 90vh;\n overflow-y: auto;\n "\n >\n <div style="display: flex; align-items: center; gap: var(--iframe-gap); justify-content: center">\n {{#if userAvatar}}\n <img\n src="{{userAvatar}}"\n alt="{{userName}}"\n style="width: 48px; height: 48px; border-radius: 24px; object-fit: cover"\n />\n {{else}}\n <span\n style="\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n border-radius: 24px;\n background-color: var(--iframe-button-bg);\n color: var(--iframe-button-text);\n font-size: 14px;\n font-weight: 600;\n "\n >U</span\n >\n {{/if}}\n\n <!-- ------------------------------------------------------------ -->\n <svg\n xmlns="http://www.w3.org/2000/svg"\n width="24"\n height="24"\n viewBox="0 0 24 24"\n fill="none"\n stroke="var(--iframe-text-secondary)"\n stroke-width="2"\n stroke-linecap="round"\n stroke-linejoin="round"\n >\n <path d="M5 12h14" />\n <path d="m12 5 7 7-7 7" />\n </svg>\n <!-- ------------------------------------------------------------ -->\n\n {{#if displayLogo}}\n <img\n src="{{displayLogo}}"\n alt="{{displayName}}"\n style="width: 48px; height: 48px; border-radius: 24px; object-fit: cover"\n />\n {{else}}\n <span\n style="\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n border-radius: 24px;\n background-color: var(--iframe-button-bg);\n color: var(--iframe-button-text);\n font-size: 14px;\n font-weight: 600;\n "\n >A</span\n >\n {{/if}}\n </div>\n\n <div style="display: flex; align-items: center; gap: var(--iframe-gap); justify-content: center">\n <span\n style="\n width: fit-content;\n font-size: var(--iframe-h2-fz);\n font-weight: var(--iframe-heading-fw);\n line-height: 150%;\n text-align: center;\n "\n >{{displayName}}</span\n >\n </div>\n\n <div class="domain-info {{domainStatusClass}}">\n <span style="display: block; width: 100%; font-size: 12px; text-align: center; font-family: monospace"\n >{{domainStatusIcon}} {{origin}}</span\n >\n </div>\n\n <!-- Permissions box -->\n <div\n id="data-auth-permissions-block"\n aria-expanded="false"\n style="display: flex; flex-direction: column; width: 100%"\n >\n <div\n id="data-auth-permissions-toggler"\n style="\n cursor: pointer;\n text-align: center;\n list-style: none;\n padding: 0 var(--iframe-pd);\n user-select: none;\n font-size: 12px;\n line-height: 20px;\n "\n >\n Show Permissions \u25BC\n </div>\n\n <div\n id="data-auth-permissions-content"\n style="width: 100%; height: var(--iframe-permissions-h, 0); overflow: hidden; transition: height 300ms ease"\n >\n <div\n style="\n width: 100%;\n padding: var(--iframe-gap);\n border-radius: var(--iframe-el-bdrs);\n background: var(--iframe-info);\n font-size: 10px;\n "\n >\n <div style="margin-bottom: var(--iframe-gap)">\n <strong>{{displayName}}</strong> by <span class="project-owner">{{displayName}}</span> wants to access your\n <strong>Lumia Passport</strong> account\n </div>\n\n <div style="margin-bottom: var(--iframe-gap)">\n <strong style="margin-bottom: var(--iframe-gap)">Personal user data</strong>\n <ul style="list-style: none">\n <li style="padding-left: var(--iframe-pd)">Wallet address (read-only)</li>\n <li style="padding-left: var(--iframe-pd)">Public transaction history (read-only)</li>\n </ul>\n </div>\n\n <div style="width: 100%">\n <strong style="margin-bottom: var(--iframe-gap)">Permissions</strong>\n <ul style="list-style: none">\n <li style="padding-left: var(--iframe-pd)">Request transaction signatures</li>\n <li style="padding-left: var(--iframe-pd)">Initiate blockchain operations</li>\n </ul>\n </div>\n </div>\n </div>\n </div>\n\n {{#if showSecurityWarning}}\n <div class="security-warning">\n <strong>\u26A0\uFE0F Warning:</strong> This domain is not verified for {{displayName}}\n <div>Expected: {{expectedDomains}}</div>\n <div>Actual: {{origin}}</div>\n </div>\n {{else}}\n <span style="display: block; text-align: center; font-size: 10px; color: var(--iframe-text-secondary)"\n >By continuing you allow the app to use these permissions, you can revoke access at any time.</span\n >\n {{/if}}\n\n <!-- Action buttons -->\n <div style="display: flex; gap: var(--iframe-gap); width: 100%; align-items: center">\n <button class="cancel-btn">Cancel</button>\n <button class="authorize-btn" {{authorizeButtonState}}>Continue</button>\n </div>\n </div>\n</div>\n';
1270
+ var authorization_default = '<div\n style="\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n background: #000000;\n "\n>\n <div\n style="\n display: flex;\n flex-direction: column;\n gap: var(--iframe-gap);\n align-items: center;\n background: var(--iframe-modal-bg);\n border-radius: 20px;\n padding: 20px;\n max-width: 320px;\n width: calc(100% - 40px);\n max-height: 90vh;\n overflow-y: auto;\n "\n >\n <div style="display: flex; align-items: center; gap: 0; justify-content: center">\n <!-- 10px overlap -->\n <div style="width: 38px; height: 48px; z-index: 10; overflow: visible">\n {{#if userAvatar}}\n <img\n src="{{userAvatar}}"\n alt="{{userName}}"\n style="width: 48px; height: 48px; border-radius: 24px; object-fit: cover"\n />\n {{else}}\n <span\n style="\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n border-radius: 24px;\n background-color: var(--iframe-button-bg);\n color: var(--iframe-button-text);\n font-size: 14px;\n font-weight: 600;\n "\n >U</span\n >\n {{/if}}\n </div>\n\n <!-- ------------------------------------------------------------ -->\n\n <div style="width: 38px; height: 48px; z-index: 5; overflow: visible">\n {{#if displayLogo}}\n <img\n src="{{displayLogo}}"\n alt="{{displayName}}"\n style="width: 48px; height: 48px; border-radius: 24px; object-fit: cover"\n />\n {{else}}\n <span\n style="\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n border-radius: 24px;\n background-color: var(--iframe-button-bg);\n color: var(--iframe-button-text);\n font-size: 14px;\n font-weight: 600;\n "\n >A</span\n >\n {{/if}}\n </div>\n </div>\n\n <div style="display: flex; align-items: center; gap: var(--iframe-gap); justify-content: center">\n <span\n style="\n width: fit-content;\n font-size: var(--iframe-h2-fz);\n font-weight: var(--iframe-heading-fw);\n line-height: 150%;\n text-align: center;\n "\n >{{displayName}}</span\n >\n </div>\n\n <div class="domain-info {{domainStatusClass}}">\n <span style="display: block; width: 100%; font-size: 12px; text-align: center; font-family: monospace"\n >{{domainStatusIcon}} {{origin}}</span\n >\n </div>\n\n <!-- Permissions box -->\n <div\n id="data-auth-permissions-block"\n aria-expanded="false"\n style="display: flex; flex-direction: column; width: 100%"\n >\n <div\n id="data-auth-permissions-toggler"\n style="\n cursor: pointer;\n text-align: center;\n list-style: none;\n padding: 0 var(--iframe-pd);\n user-select: none;\n font-size: 12px;\n line-height: 20px;\n "\n >\n Show Permissions \u25BC\n </div>\n\n <div\n id="data-auth-permissions-content"\n style="width: 100%; height: var(--iframe-permissions-h, 0); overflow: hidden; transition: height 300ms ease"\n >\n <div\n style="\n width: 100%;\n padding: var(--iframe-gap);\n border-radius: var(--iframe-el-bdrs);\n background: var(--iframe-info);\n font-size: 10px;\n "\n >\n <div style="margin-bottom: var(--iframe-gap)">\n <strong>{{displayName}}</strong> by <span class="project-owner">{{displayName}}</span> wants to access your\n <strong>Lumia Passport</strong> account\n </div>\n\n <div style="margin-bottom: var(--iframe-gap)">\n <strong style="margin-bottom: var(--iframe-gap)">Personal user data</strong>\n <ul style="list-style: none">\n <li style="padding-left: var(--iframe-pd)">Wallet address (read-only)</li>\n <li style="padding-left: var(--iframe-pd)">Public transaction history (read-only)</li>\n </ul>\n </div>\n\n <div style="width: 100%">\n <strong style="margin-bottom: var(--iframe-gap)">Permissions</strong>\n <ul style="list-style: none">\n <li style="padding-left: var(--iframe-pd)">Request transaction signatures</li>\n <li style="padding-left: var(--iframe-pd)">Initiate blockchain operations</li>\n </ul>\n </div>\n </div>\n </div>\n </div>\n\n {{#if showSecurityWarning}}\n <div class="security-warning">\n <strong>\u26A0\uFE0F Warning:</strong> This domain is not verified for {{displayName}}\n <div>Expected: {{expectedDomains}}</div>\n <div>Actual: {{origin}}</div>\n </div>\n {{else}}\n <span style="display: block; text-align: center; font-size: 10px; color: var(--iframe-text-secondary)"\n >By continuing you allow the app to use these permissions, you can revoke access at any time.</span\n >\n {{/if}}\n\n <!-- Action buttons -->\n <div style="display: flex; gap: var(--iframe-gap); width: 100%; align-items: center">\n <button class="cancel-btn">Cancel</button>\n <button class="authorize-btn" {{authorizeButtonState}}>Continue</button>\n </div>\n </div>\n</div>\n';
1271
+
1272
+ // src/iframe/templates/html/confirm-tx.html
1273
+ var confirm_tx_default = '<div\n style="\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n background: #000000;\n "\n>\n <div\n style="\n display: flex;\n flex-direction: column;\n gap: var(--iframe-gap);\n align-items: center;\n background: var(--iframe-modal-bg);\n border-radius: 20px;\n padding: 20px;\n max-width: 320px;\n width: calc(100% - 40px);\n max-height: 90vh;\n overflow-y: auto;\n "\n >\n <!-- Header with logos -->\n <div style="display: flex; align-items: center; gap: 0; justify-content: center">\n <div style="width: 38px; height: 48px; z-index: 10; overflow: visible">\n {{#if displayLogo}}\n <img\n src="{{displayLogo}}"\n alt="{{displayName}}"\n style="width: 48px; height: 48px; border-radius: 24px; object-fit: cover"\n />\n {{else}}\n <span\n style="\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n border-radius: 24px;\n background-color: var(--iframe-button-bg);\n color: var(--iframe-button-text);\n font-size: 14px;\n font-weight: 600;\n "\n >A</span\n >\n {{/if}}\n </div>\n\n <!-- ------------------------------------------------------------ -->\n\n <div style="width: 38px; height: 48px; z-index: 5; overflow: visible">\n {{#if userAvatar}}\n <img\n src="{{userAvatar}}"\n alt="{{userName}}"\n style="width: 48px; height: 48px; border-radius: 24px; object-fit: cover"\n />\n {{else}}\n <span\n style="\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n border-radius: 24px;\n background-color: var(--iframe-button-bg);\n color: var(--iframe-button-text);\n font-size: 14px;\n font-weight: 600;\n "\n >U</span\n >\n {{/if}}\n </div>\n </div>\n\n <!-- Transaction title -->\n\n <div style="display: flex; align-items: center; gap: var(--iframe-gap); justify-content: center">\n <span\n style="\n width: fit-content;\n font-size: var(--iframe-h1-fz);\n font-weight: var(--iframe-heading-fw);\n line-height: 150%;\n text-align: center;\n "\n >Confirm Transaction</span\n >\n </div>\n\n <!-- Application info -->\n <div class="domain-info {{domainStatusClass}}">\n <span style="display: block; width: 100%; font-size: 12px; text-align: center; font-family: monospace"\n >{{domainStatusText}} {{origin}}</span\n >\n </div>\n\n <!-- Transaction details box -->\n <div\n id="confirm-transaction-details-block"\n aria-expanded="false"\n style="display: flex; flex-direction: column; width: 100%"\n >\n <div\n id="confirm-transaction-details-toggler"\n style="\n cursor: pointer;\n text-align: center;\n list-style: none;\n padding: 0 var(--iframe-pd);\n user-select: none;\n font-size: 12px;\n line-height: 20px;\n "\n >\n Show Transaction Details \u25BC\n </div>\n\n <div\n id="confirm-transaction-details-content"\n style="\n display: flex;\n flex-direction: column;\n gap: var(--iframe-gap);\n width: 100%;\n max-height: var(--confirm-transaction-details-h, 0px);\n overflow: hidden;\n transition: max-height 300ms ease;\n "\n >\n <div\n style="\n display: flex;\n flex-direction: column;\n gap: var(--iframe-gap);\n width: 100%;\n padding: var(--iframe-gap);\n border-radius: var(--iframe-el-bdrs);\n background: var(--iframe-info);\n font-size: 10px;\n "\n >\n {{#if fromAddress}}\n <div style="display: flex; justify-content: space-between">\n <strong style="color: var(--iframe-text-secondary); display: block">From:</strong>\n <code style="word-break: break-all; display: block">{{fromAddress}}</code>\n </div>\n {{/if}}\n\n <!-- ------------------------------------------------------------ -->\n\n {{#if toAddress}}\n <div style="display: flex; justify-content: space-between">\n <strong style="color: var(--iframe-text-secondary); display: block">To:</strong>\n <code style="word-break: break-all; display: block">{{toAddress}}</code>\n </div>\n {{/if}}\n\n <!-- ------------------------------------------------------------ -->\n\n {{#if hasValue}}\n <div style="display: flex; justify-content: space-between">\n <strong style="color: var(--iframe-text-secondary); display: block">Amount:</strong>\n <code style="word-break: break-all; display: block">{{formattedValue}} LUMIA</code>\n </div>\n {{/if}}\n\n <!-- ------------------------------------------------------------ -->\n\n {{#if showContractInteraction}}\n <div style="display: flex; justify-content: space-between">\n <strong style="color: var(--iframe-text-secondary); display: block">Action:</strong>\n <code style="word-break: break-all; display: block">Contract Interaction</code>\n </div>\n {{/if}}\n\n <!-- ------------------------------------------------------------ -->\n\n <div style="display: flex; justify-content: space-between">\n <strong style="color: var(--iframe-text-secondary); display: block">Estimated Cost:</strong>\n <code style="word-break: break-all; display: block; color: #10b981">{{estimatedCost}}</code>\n </div>\n\n <!-- ------------------------------------------------------------ -->\n\n {{#if isSponsored}}\n <div\n style="\n display: flex;\n justify-content: space-between;\n background: var(--iframe-success);\n border-radius: var(--iframe-el-bdrs);\n padding: var(--iframe-gap);\n "\n >\n <span>Gas fees will be paid by the application (no cost to you)</span>\n </div>\n {{/if}}\n </div>\n </div>\n </div>\n\n <!-- ------------------------------------------------------------ -->\n\n {{#if showHighRisk}}\n <div class="security-warning">\n <strong>\u26A0\uFE0F {{riskLevel}} RISK</strong>\n {{riskReasons}}\n </div>\n {{else}}\n <div class="security-warning">Please verify this transaction carefully before confirming.</div>\n {{/if}}\n\n <!-- ------------------------------------------------------------ -->\n\n <div class="trust-app-section">\n <label class="trust-app-label">\n <input type="checkbox" class="trust-app-checkbox" />\n <span>Add this application to trusted list and skip confirmation for future transactions</span>\n </label>\n </div>\n\n <!-- Action buttons -->\n <div style="display: flex; gap: var(--iframe-gap); width: 100%; align-items: center">\n <button class="cancel-btn">Reject</button>\n <button class="confirm-btn">Confirm</button>\n </div>\n\n <!-- Footer notice -->\n <span\n style="\n display: block;\n padding: var(--iframe-gap);\n text-align: center;\n font-size: 10px;\n color: var(--iframe-text-secondary);\n "\n >\n You can manage trusted applications in your Lumia Passport settings.\n </span>\n </div>\n</div>\n';
1271
1274
 
1272
1275
  // src/iframe/templates/html/ready-indicator.html
1273
1276
  var ready_indicator_default = '<div class="ready-indicator">\n <div class="status-icon">\u2713</div>\n <h2>Secure Wallet Ready</h2>\n <p>Lumia Passport is ready for secure operations</p>\n <div class="info">\n <div class="info-row">\n <strong>Origin:</strong>\n <span>{{origin}}</span>\n </div>\n <div class="info-row">\n <strong>Status:</strong>\n <span class="status-active">Active</span>\n </div>\n <div class="info-row">\n <strong>Version:</strong>\n <span>{{iframeVersion}}</span>\n </div>\n <div class="info-row">\n <strong>Documentation:</strong>\n <a\n href="https://docs.lumiapassport.com/"\n target="_blank"\n rel="noopener noreferrer"\n style="color: #667eea; text-decoration: none"\n >docs.lumiapassport.com</a\n >\n </div>\n </div>\n</div>\n';
1274
1277
 
1278
+ // src/iframe/templates/html/sign-eip712-tx.html
1279
+ var sign_eip712_tx_default = '<div\n style="\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n background: #000000;\n "\n>\n <div\n style="\n display: flex;\n flex-direction: column;\n gap: var(--iframe-gap);\n align-items: center;\n background: var(--iframe-modal-bg);\n border-radius: 20px;\n padding: 20px;\n max-width: 320px;\n width: calc(100% - 40px);\n max-height: 90vh;\n overflow-y: auto;\n "\n >\n <!-- Header -->\n <div style="display: flex; align-items: center; gap: var(--iframe-gap); justify-content: center">\n {{#if metadataLogo}}\n <img\n src="{{metadataLogo}}"\n alt="{{metadataName}}"\n style="width: 48px; height: 48px; border-radius: 24px; object-fit: cover"\n />\n {{else}}\n <span\n style="\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n border-radius: 24px;\n background-color: var(--iframe-button-bg);\n color: var(--iframe-button-text);\n font-size: 14px;\n font-weight: 600;\n "\n >\u{1F510}</span\n >\n {{/if}}\n\n <!-- ------------------------------------------------------------ -->\n <svg\n xmlns="http://www.w3.org/2000/svg"\n width="24"\n height="24"\n viewBox="0 0 24 24"\n fill="none"\n stroke="var(--iframe-text-secondary)"\n stroke-width="2"\n stroke-linecap="round"\n stroke-linejoin="round"\n >\n <path d="M5 12h14" />\n <path d="m12 5 7 7-7 7" />\n </svg>\n <!-- ------------------------------------------------------------ -->\n\n {{#if userAvatar}}\n <img\n src="{{userAvatar}}"\n alt="{{userName}}"\n style="width: 48px; height: 48px; border-radius: 24px; object-fit: cover"\n />\n {{else}}\n <span\n style="\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n border-radius: 24px;\n background-color: var(--iframe-button-bg);\n color: var(--iframe-button-text);\n font-size: 14px;\n font-weight: 600;\n "\n >U</span\n >\n {{/if}}\n </div>\n\n <div style="display: flex; align-items: center; gap: var(--iframe-gap); justify-content: center">\n <span\n style="\n width: fit-content;\n font-size: var(--iframe-h2-fz);\n font-weight: var(--iframe-heading-fw);\n line-height: 150%;\n text-align: center;\n "\n >Signature Request</span\n >\n </div>\n\n <div class="domain-info verified">\n <span style="display: block; width: 100%; font-size: 12px; text-align: center; font-family: monospace">\n {{#if isVerifiedOrigin}}\n <span>\u2713</span>\n {{/if}} {{origin}}</span\n >\n </div>\n\n <!-- EIP712 Message Content -->\n <div class="eip712-content">\n <details class="eip712-details">\n <summary>Advanced details</summary>\n\n <div class="section-title">\u{1F4DD} Message</div>\n <div class="eip712-section">\n <div class="section-subtitle">{{primaryType}}</div>\n {{messageFields}}\n </div>\n\n <div class="section-title" style="margin-top: 16px">\u{1F50D} Domain</div>\n <div class="eip712-section">{{domainFields}}</div>\n\n <div class="section-title" style="margin-top: 16px">\u{1F4CB} Full Message</div>\n <pre class="eip712-raw"><code>{{fullMessageJson}}</code></pre>\n </details>\n </div>\n\n <!-- Trust App Option -->\n <div class="trust-app-section">\n <label class="trust-app-label">\n <input type="checkbox" class="trust-app-checkbox" />\n <span>Trust this application and skip confirmation for future signatures</span>\n </label>\n </div>\n\n <!-- Action Buttons -->\n <div class="actions">\n <button class="cancel-btn">Reject</button>\n <button class="confirm-btn">Sign</button>\n </div>\n\n <!-- Footer Notice -->\n <div class="footer-notice">\n <p class="footer-note">Only sign messages from applications you trust.</p>\n </div>\n </div>\n</div>\n';
1280
+
1275
1281
  // src/iframe/templates/template-loader.ts
1276
1282
  var TemplateLoader = class {
1277
1283
  /** Get template by name */
@@ -1293,6 +1299,10 @@ var TemplateLoader = class {
1293
1299
  return authorization_default;
1294
1300
  case "ready-indicator":
1295
1301
  return ready_indicator_default;
1302
+ case "sign-eip712-tx":
1303
+ return sign_eip712_tx_default;
1304
+ case "confirm-tx":
1305
+ return confirm_tx_default;
1296
1306
  default:
1297
1307
  return null;
1298
1308
  }
@@ -1347,6 +1357,115 @@ function buildReadyIndicatorData(input) {
1347
1357
  };
1348
1358
  }
1349
1359
 
1360
+ // src/iframe/templates/data/sign-tx-template-data.ts
1361
+ function buildSignTxTemplateData(project, origin, typedData, metadata, userProfile) {
1362
+ const isVerifiedOrigin = project.domains.includes(origin);
1363
+ const metadataName = metadata?.name || project.name;
1364
+ const metadataLogo = metadata?.logo || project.logoUrl || "";
1365
+ const userAvatar = userProfile?.avatar || "";
1366
+ const userName = userProfile?.displayName || "Lumia Passport";
1367
+ const formatFieldValue = (value) => {
1368
+ if (Array.isArray(value)) {
1369
+ return `[${value.map((v) => formatFieldValue(v)).join(", ")}]`;
1370
+ }
1371
+ if (typeof value === "bigint") {
1372
+ return value.toString();
1373
+ }
1374
+ if (typeof value === "object" && value !== null) {
1375
+ return JSON.stringify(value, null, 2);
1376
+ }
1377
+ return String(value);
1378
+ };
1379
+ const messageFields = Object.entries(typedData.message).map(
1380
+ ([key, value]) => `
1381
+ <div class="eip712-field">
1382
+ <div class="field-name">${key}:</div>
1383
+ <div class="field-value">${formatFieldValue(value)}</div>
1384
+ </div>
1385
+ `
1386
+ ).join("");
1387
+ const domainFields = Object.entries(typedData.domain).filter(([_, value]) => value !== void 0).map(
1388
+ ([key, value]) => `
1389
+ <div class="eip712-field">
1390
+ <div class="field-name">${key}:</div>
1391
+ <div class="field-value">${formatFieldValue(value)}</div>
1392
+ </div>
1393
+ `
1394
+ ).join("");
1395
+ return {
1396
+ metadataLogo,
1397
+ metadataName,
1398
+ userAvatar,
1399
+ userName,
1400
+ origin,
1401
+ isVerifiedOrigin,
1402
+ primaryType: typedData.primaryType,
1403
+ messageFields,
1404
+ domainFields,
1405
+ fullMessageJson: JSON.stringify(typedData.message, null, 2)
1406
+ };
1407
+ }
1408
+
1409
+ // src/iframe/templates/data/confirm-tx-template-data.ts
1410
+ function formatAddress(address) {
1411
+ if (address.length < 10) return address;
1412
+ return `${address.slice(0, 6)}...${address.slice(-4)}`;
1413
+ }
1414
+ function buildConfirmTxTemplateData(project, origin, transaction, risk, metadata, userProfile) {
1415
+ const isVerifiedOrigin = project.domains.includes(origin);
1416
+ const isUserOp = !!transaction.userOpDetails;
1417
+ const displayName = metadata?.name || project.name;
1418
+ const displayLogo = metadata?.logo || project.logoUrl || "";
1419
+ const userAvatar = userProfile?.avatar || "";
1420
+ const userName = userProfile?.displayName || "Lumia Passport";
1421
+ const domainStatusClass = isVerifiedOrigin ? "verified" : "unverified";
1422
+ const domainStatusText = isVerifiedOrigin ? "\u2705" : "\u26A0\uFE0F";
1423
+ const fromAddress = formatAddress(transaction.userOpDetails?.sender || "");
1424
+ const toAddress = formatAddress(transaction.userOpDetails?.callTarget || transaction.to || "");
1425
+ const formatValue = (valueWei) => {
1426
+ try {
1427
+ const value = BigInt(valueWei);
1428
+ if (value === 0n) return "0";
1429
+ const tokens = Number(value) / 1e18;
1430
+ if (tokens >= 1) {
1431
+ return tokens.toFixed(4).replace(/\.?0+$/, "");
1432
+ } else {
1433
+ return tokens.toFixed(8).replace(/\.?0+$/, "");
1434
+ }
1435
+ } catch {
1436
+ return "0";
1437
+ }
1438
+ };
1439
+ const transactionValue = transaction.value || "0";
1440
+ const formattedValue = formatValue(transactionValue);
1441
+ const hasValue = BigInt(transactionValue) > 0n;
1442
+ const showContractInteraction = isUserOp && !!transaction.userOpDetails?.callData && transaction.userOpDetails.callData !== "0x";
1443
+ const isSponsored = isUserOp && !!transaction.userOpDetails?.paymaster;
1444
+ const estimatedCost = isSponsored ? "0 (Sponsored)" : "Free (Sponsored Transaction)";
1445
+ const showHighRisk = risk.level !== "LOW";
1446
+ const riskLevel = risk.level;
1447
+ const riskReasons = risk.reasons.map((r) => `<div>\u2022 ${r}</div>`).join("");
1448
+ return {
1449
+ displayName,
1450
+ displayLogo,
1451
+ userAvatar,
1452
+ userName,
1453
+ origin,
1454
+ domainStatusClass,
1455
+ domainStatusText,
1456
+ fromAddress,
1457
+ toAddress,
1458
+ hasValue,
1459
+ formattedValue,
1460
+ showContractInteraction,
1461
+ estimatedCost,
1462
+ isSponsored,
1463
+ showHighRisk,
1464
+ riskLevel,
1465
+ riskReasons
1466
+ };
1467
+ }
1468
+
1350
1469
  // src/iframe/lib/authorization-manager.ts
1351
1470
  var AuthorizationManager = class {
1352
1471
  constructor() {
@@ -1504,7 +1623,6 @@ var AuthorizationManager = class {
1504
1623
  */
1505
1624
  createAuthorizationModal(project, origin, metadata, userProfile) {
1506
1625
  const modal = document.createElement("div");
1507
- modal.className = "authorization-modal";
1508
1626
  const templateData = buildAuthorizationTemplateData(project, origin, metadata, userProfile);
1509
1627
  const template = TemplateLoader.getTemplate("authorization");
1510
1628
  const populatedHTML = TemplateEngine.render(template, templateData);
@@ -3888,135 +4006,9 @@ var SigningManager = class extends TokenRefreshApiClient {
3888
4006
  createConfirmationModal(userId, projectId, project, origin, transaction, risk, metadata, userProfile) {
3889
4007
  const modal = document.createElement("div");
3890
4008
  modal.className = "transaction-confirmation-modal";
3891
- const isVerifiedOrigin = project.domains.includes(origin);
3892
- const isUserOp = !!transaction.userOpDetails;
3893
- const userAvatar = userProfile?.avatar;
3894
- const userName = userProfile?.displayName || "Lumia Passport";
3895
- const isSponsored = isUserOp && !!transaction.userOpDetails?.paymaster;
3896
- const estimatedCost = isSponsored ? "0 (Sponsored)" : "Free (Sponsored Transaction)";
3897
- const displayName = metadata?.name || project.name;
3898
- const displayLogo = metadata?.logo || project.logoUrl;
3899
- const fromAddress = transaction.userOpDetails?.sender;
3900
- const toAddress = transaction.userOpDetails?.callTarget || transaction.to;
3901
- const formatValue = (valueWei) => {
3902
- try {
3903
- const value = BigInt(valueWei);
3904
- if (value === 0n) return "0";
3905
- const tokens = Number(value) / 1e18;
3906
- if (tokens >= 1) {
3907
- return tokens.toFixed(4).replace(/\.?0+$/, "");
3908
- } else {
3909
- return tokens.toFixed(8).replace(/\.?0+$/, "");
3910
- }
3911
- } catch {
3912
- return "0";
3913
- }
3914
- };
3915
- const transactionValue = transaction.value || "0";
3916
- const formattedValue = formatValue(transactionValue);
3917
- const hasValue = BigInt(transactionValue) > 0n;
3918
- modal.innerHTML = `
3919
- <div class="modal-overlay">
3920
- <div class="modal-content">
3921
- <!-- Header with logos -->
3922
- <div class="auth-header">
3923
- <div class="logo-container">
3924
- ${displayLogo ? `<img src="${displayLogo}" alt="${displayName}" class="app-logo" />` : '<div class="app-logo-placeholder"></div>'}
3925
- <div class="logo-connector">
3926
- <svg width="24" height="16" viewBox="0 0 24 16" fill="currentColor">
3927
- <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"/>
3928
- </svg>
3929
- </div>
3930
- ${userAvatar ? `<img src="${userAvatar}" alt="${userName}" class="lumia-logo user-avatar" />` : '<img src="./lumia-logo.svg" alt="Lumia Passport" class="lumia-logo" />'}
3931
- </div>
3932
- </div>
3933
-
3934
- <!-- Transaction title -->
3935
- <h2 class="auth-title">Confirm Transaction</h2>
3936
-
3937
- <!-- Application info -->
3938
- <div class="auth-description">
3939
- <div class="domain-info ${isVerifiedOrigin ? "verified" : "unverified"}">
3940
- <span class="domain-label">
3941
- ${isVerifiedOrigin ? "\u2713 Verified:" : "\u26A0\uFE0F Unverified:"}
3942
- </span>
3943
- <span class="domain-value">${origin}</span>
3944
- </div>
3945
- </div>
3946
-
3947
- <!-- Transaction details box -->
3948
- <div class="permissions-box">
3949
- ${fromAddress ? `
3950
- <div class="detail-row" style="margin-bottom: 0.5rem;">
3951
- <div style="color: var(--iframe-text-secondary); font-size: 0.875rem; margin-bottom: 0.25rem;"><strong>From:</strong></div>
3952
- <code style="font-size: 0.75rem; word-break: break-all; display: block; color: var(--iframe-text);">${fromAddress}</code>
3953
- </div>
3954
- ` : ""}
3955
-
3956
- ${toAddress ? `
3957
- <div class="detail-row" style="margin-bottom: 0.5rem;">
3958
- <div style="color: var(--iframe-text-secondary); font-size: 0.875rem; margin-bottom: 0.25rem;"><strong>To:</strong></div>
3959
- <code style="font-size: 0.75rem; word-break: break-all; display: block; color: var(--iframe-text);">${toAddress}</code>
3960
- </div>
3961
- ` : ""}
3962
-
3963
- ${hasValue ? `
3964
- <div class="detail-row" style="margin-bottom: 0.5rem;">
3965
- <span style="color: var(--iframe-text-secondary);"><strong>Amount:</strong></span>
3966
- <strong style="color: var(--iframe-text); font-size: 1rem;">${formattedValue} LUMIA</strong>
3967
- </div>
3968
- ` : ""}
3969
-
3970
- ${isUserOp && transaction.userOpDetails?.callData && transaction.userOpDetails.callData !== "0x" ? `
3971
- <div class="detail-row" style="margin-bottom: 0.5rem;">
3972
- <span style="color: var(--iframe-text-secondary);"><strong>Action:</strong></span>
3973
- <span style="color: var(--iframe-text);">Contract Interaction</span>
3974
- </div>
3975
- ` : ""}
3976
-
3977
- <div class="detail-row" style="margin-bottom: 0.5rem;">
3978
- <span style="color: var(--iframe-text-secondary);"><strong>Estimated Cost:</strong></span>
3979
- <strong style="color: #10b981;">${estimatedCost}</strong>
3980
- </div>
3981
-
3982
- ${isSponsored ? `
3983
- <div class="detail-row" style="background: #d1fae5; border-radius: 6px; padding: 0.75rem; margin-top: 0.5rem;">
3984
- <span style="color: #047857;">\u2713 Gas fees will be paid by the application (no cost to you)</span>
3985
- </div>
3986
- ` : ""}
3987
- </div>
3988
-
3989
- ${risk.level !== "LOW" ? `
3990
- <div class="security-warning">
3991
- <strong>\u26A0\uFE0F ${risk.level} RISK</strong>
3992
- ${risk.reasons.map((r) => `<div>\u2022 ${r}</div>`).join("")}
3993
- </div>
3994
- ` : `
3995
- <div class="security-warning">
3996
- <strong>\u26A0\uFE0F Warning:</strong> Please verify this transaction carefully before confirming.
3997
- </div>
3998
- `}
3999
-
4000
- <div class="trust-app-section">
4001
- <label class="trust-app-label">
4002
- <input type="checkbox" class="trust-app-checkbox" />
4003
- <span>Trust this application and skip confirmation for future transactions</span>
4004
- </label>
4005
- </div>
4006
-
4007
- <!-- Action buttons -->
4008
- <div class="actions">
4009
- <button class="cancel-btn">Reject</button>
4010
- <button class="confirm-btn">Confirm</button>
4011
- </div>
4012
-
4013
- <!-- Footer notice -->
4014
- <div class="auth-footer">
4015
- <p class="footer-note">You can manage trusted applications in your Lumia Passport settings.</p>
4016
- </div>
4017
- </div>
4018
- </div>
4019
- `;
4009
+ const templateData = buildConfirmTxTemplateData(project, origin, transaction, risk, metadata, userProfile);
4010
+ const template = TemplateLoader.getTemplate("confirm-tx");
4011
+ modal.innerHTML = TemplateEngine.render(template, templateData);
4020
4012
  return modal;
4021
4013
  }
4022
4014
  /**
@@ -4176,97 +4168,9 @@ var SigningManager = class extends TokenRefreshApiClient {
4176
4168
  */
4177
4169
  createEIP712ConfirmationModal(userId, projectId, project, origin, typedData, metadata, userProfile) {
4178
4170
  const modal = document.createElement("div");
4179
- modal.className = "eip712-confirmation-modal";
4180
- const isVerifiedOrigin = project.domains.includes(origin);
4181
- const userAvatar = userProfile?.avatar;
4182
- const userName = userProfile?.displayName || "Lumia Passport";
4183
- const formatFieldValue = (value) => {
4184
- if (Array.isArray(value)) {
4185
- return `[${value.map((v) => formatFieldValue(v)).join(", ")}]`;
4186
- }
4187
- if (typeof value === "bigint") {
4188
- return value.toString();
4189
- }
4190
- if (typeof value === "object" && value !== null) {
4191
- return JSON.stringify(value, null, 2);
4192
- }
4193
- return String(value);
4194
- };
4195
- const messageFields = Object.entries(typedData.message).map(
4196
- ([key, value]) => `
4197
- <div class="eip712-field">
4198
- <div class="field-name">${key}:</div>
4199
- <div class="field-value">${formatFieldValue(value)}</div>
4200
- </div>
4201
- `
4202
- ).join("");
4203
- const domainFields = Object.entries(typedData.domain).filter(([_, value]) => value !== void 0).map(
4204
- ([key, value]) => `
4205
- <div class="eip712-field">
4206
- <div class="field-name">${key}:</div>
4207
- <div class="field-value">${formatFieldValue(value)}</div>
4208
- </div>
4209
- `
4210
- ).join("");
4211
- modal.innerHTML = `
4212
- <div class="modal-overlay">
4213
- <div class="modal-content eip712-modal">
4214
- <!-- Header -->
4215
- <div class="auth-header">
4216
- <div class="logo-container">
4217
- ${metadata?.logo ? `<img src="${metadata.logo}" alt="${metadata.name}" class="project-logo" />` : '<div class="project-logo-placeholder">\u{1F510}</div>'}
4218
- <span class="arrow-icon">\u2192</span>
4219
- ${userAvatar ? `<img src="${userAvatar}" alt="${userName}" class="lumia-logo user-avatar" style="width: 40px; height: 40px;" />` : '<div class="lumia-logo">L</div>'}
4220
- </div>
4221
- <h2 class="modal-title">Signature Request</h2>
4222
- <p class="origin-text">
4223
- ${isVerifiedOrigin ? '<span class="verified-badge">\u2713</span>' : ""}
4224
- ${origin}
4225
- </p>
4226
- </div>
4227
-
4228
- <!-- EIP712 Message Content -->
4229
- <div class="eip712-content">
4230
- <details class="eip712-details">
4231
- <summary>Advanced details</summary>
4232
-
4233
- <div class="section-title">\u{1F4DD} Message</div>
4234
- <div class="eip712-section">
4235
- <div class="section-subtitle">${typedData.primaryType}</div>
4236
- ${messageFields}
4237
- </div>
4238
-
4239
- <div class="section-title" style="margin-top: 16px;">\u{1F50D} Domain</div>
4240
- <div class="eip712-section">
4241
- ${domainFields}
4242
- </div>
4243
-
4244
- <div class="section-title" style="margin-top: 16px;">\u{1F4CB} Full Message</div>
4245
- <pre class="eip712-raw"><code>${JSON.stringify(typedData.message, null, 2)}</code></pre>
4246
- </details>
4247
- </div>
4248
-
4249
- <!-- Trust App Option -->
4250
- <div class="trust-app-section">
4251
- <label class="trust-app-label">
4252
- <input type="checkbox" class="trust-app-checkbox" />
4253
- <span>Trust this application and skip confirmation for future signatures</span>
4254
- </label>
4255
- </div>
4256
-
4257
- <!-- Action Buttons -->
4258
- <div class="actions">
4259
- <button class="cancel-btn">Reject</button>
4260
- <button class="confirm-btn">Sign</button>
4261
- </div>
4262
-
4263
- <!-- Footer Notice -->
4264
- <div class="footer-notice">
4265
- <p class="footer-note">Only sign messages from applications you trust.</p>
4266
- </div>
4267
- </div>
4268
- </div>
4269
- `;
4171
+ const templateData = buildSignTxTemplateData(project, origin, typedData, metadata, userProfile);
4172
+ const template = TemplateLoader.getTemplate("sign-eip712-tx");
4173
+ modal.innerHTML = TemplateEngine.render(template, templateData);
4270
4174
  return modal;
4271
4175
  }
4272
4176
  /**
@@ -4288,7 +4192,7 @@ var SigningManager = class extends TokenRefreshApiClient {
4288
4192
  };
4289
4193
 
4290
4194
  // src/iframe/main.ts
4291
- var IFRAME_VERSION = "1.14.9";
4195
+ var IFRAME_VERSION = "1.14.11";
4292
4196
  var IframeWallet = class {
4293
4197
  constructor() {
4294
4198
  console.log("=".repeat(60));
@@ -4941,7 +4845,7 @@ var IframeWallet = class {
4941
4845
  }
4942
4846
  };
4943
4847
  function toggleAuthPermissions(e) {
4944
- const isToggler = e.target.id === "data-auth-permissions-toggler";
4848
+ const isToggler = e.target?.id === "data-auth-permissions-toggler";
4945
4849
  if (!isToggler) return;
4946
4850
  const details = document.getElementById("data-auth-permissions-block");
4947
4851
  const isOpen = details.hasAttribute("aria-expanded") && details.getAttribute("aria-expanded") === "true";
@@ -4956,6 +4860,22 @@ function toggleAuthPermissions(e) {
4956
4860
  toggler.innerHTML = "Hide Permissions \u25B2";
4957
4861
  }
4958
4862
  }
4863
+ function toggleConfirmTransactionDetails(e) {
4864
+ const isToggler = e.target?.id === "confirm-transaction-details-toggler";
4865
+ if (!isToggler) return;
4866
+ const details = document.getElementById("confirm-transaction-details-block");
4867
+ const isOpen = details.hasAttribute("aria-expanded") && details.getAttribute("aria-expanded") === "true";
4868
+ const toggler = details.querySelector("#confirm-transaction-details-toggler");
4869
+ if (isOpen) {
4870
+ details.setAttribute("aria-expanded", "false");
4871
+ details.style.setProperty("--confirm-transaction-details-h", "0px");
4872
+ toggler.innerHTML = "Show Transaction Details \u25BC";
4873
+ } else {
4874
+ details.setAttribute("aria-expanded", "true");
4875
+ details.style.setProperty("--confirm-transaction-details-h", "200px");
4876
+ toggler.innerHTML = "Hide Transaction Details \u25B2";
4877
+ }
4878
+ }
4959
4879
  function initWallet() {
4960
4880
  const wallet = new IframeWallet();
4961
4881
  wallet.initialize().catch((error) => {
@@ -4971,7 +4891,10 @@ function initWallet() {
4971
4891
  `;
4972
4892
  }
4973
4893
  });
4974
- document.addEventListener("click", toggleAuthPermissions);
4894
+ document.addEventListener("click", (e) => {
4895
+ toggleAuthPermissions(e);
4896
+ toggleConfirmTransactionDetails(e);
4897
+ });
4975
4898
  }
4976
4899
  if (document.readyState === "loading") {
4977
4900
  document.addEventListener("DOMContentLoaded", initWallet);