@lumiapassport/ui-kit 1.14.15 → 1.14.18

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.
@@ -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.15</title>
18
+ <title>Lumia Passport Secure Wallet - iframe version 1.14.18</title>
19
19
 
20
20
  <!-- Styles will be injected by build process -->
21
21
  <style>
@@ -1270,7 +1270,7 @@ var TemplateEngine = class {
1270
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
1271
 
1272
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';
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 <a\n href="{{fromAddressExplorerUrl}}"\n target="_blank"\n rel="noopener noreferrer"\n style="word-break: break-all; display: block; color: #3b82f6; text-decoration: none"\n title="{{fromAddressFull}}"\n >\n <code>{{fromAddress}}</code>\n </a>\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 <a\n href="{{toAddressExplorerUrl}}"\n target="_blank"\n rel="noopener noreferrer"\n style="word-break: break-all; display: block; color: #3b82f6; text-decoration: none"\n title="{{toAddressFull}}"\n >\n <code>{{toAddress}}</code>\n </a>\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">{{actionDescription}}</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';
1274
1274
 
1275
1275
  // src/iframe/templates/html/ready-indicator.html
1276
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';
@@ -1407,11 +1407,72 @@ function buildSignTxTemplateData(project, origin, typedData, metadata, userProfi
1407
1407
  }
1408
1408
 
1409
1409
  // src/iframe/templates/data/confirm-tx-template-data.ts
1410
+ var ERC20_APPROVE_SELECTOR = "0x095ea7b3";
1411
+ var EXECUTE_SELECTOR = "0xb61d27f6";
1412
+ var DEFAULT_EXPLORER_URL = "https://beam-explorer.lumia.org";
1410
1413
  function formatAddress(address) {
1411
1414
  if (address.length < 10) return address;
1412
1415
  return `${address.slice(0, 6)}...${address.slice(-4)}`;
1413
1416
  }
1414
- function buildConfirmTxTemplateData(project, origin, transaction, risk, metadata, userProfile) {
1417
+ function getAddressExplorerUrl(address, explorerUrl) {
1418
+ if (!address) return "";
1419
+ const baseUrl = explorerUrl.replace(/\/$/, "");
1420
+ return `${baseUrl}/address/${address}`;
1421
+ }
1422
+ function extractInnerCallData(callData) {
1423
+ if (!callData || callData.length < 10) return null;
1424
+ const selector = callData.slice(0, 10).toLowerCase();
1425
+ if (selector !== EXECUTE_SELECTOR) return null;
1426
+ try {
1427
+ const lengthHex = callData.slice(202, 266);
1428
+ const length = parseInt(lengthHex, 16);
1429
+ if (length === 0) return "0x";
1430
+ const innerData = "0x" + callData.slice(266, 266 + length * 2);
1431
+ return innerData;
1432
+ } catch {
1433
+ return null;
1434
+ }
1435
+ }
1436
+ function parseERC20Approve(callData) {
1437
+ if (!callData || callData.length < 10) return null;
1438
+ let dataToCheck = callData;
1439
+ const innerData = extractInnerCallData(callData);
1440
+ if (innerData) {
1441
+ dataToCheck = innerData;
1442
+ }
1443
+ const selector = dataToCheck.slice(0, 10).toLowerCase();
1444
+ if (selector !== ERC20_APPROVE_SELECTOR) return null;
1445
+ if (dataToCheck.length < 138) return null;
1446
+ try {
1447
+ const spender = "0x" + dataToCheck.slice(34, 74);
1448
+ const amountHex = dataToCheck.slice(74, 138);
1449
+ const amount = BigInt("0x" + amountHex);
1450
+ return { spender, amount };
1451
+ } catch {
1452
+ return null;
1453
+ }
1454
+ }
1455
+ function formatApproveAmount(amount) {
1456
+ const MAX_UINT256 = 2n ** 256n - 1n;
1457
+ const NEAR_MAX = 2n ** 255n;
1458
+ if (amount >= NEAR_MAX) {
1459
+ return "Unlimited";
1460
+ }
1461
+ const tokens = Number(amount) / 1e18;
1462
+ if (tokens >= 1e9) {
1463
+ return `${(tokens / 1e9).toFixed(2)}B`;
1464
+ } else if (tokens >= 1e6) {
1465
+ return `${(tokens / 1e6).toFixed(2)}M`;
1466
+ } else if (tokens >= 1e3) {
1467
+ return `${(tokens / 1e3).toFixed(2)}K`;
1468
+ } else if (tokens >= 1) {
1469
+ return tokens.toFixed(4).replace(/\.?0+$/, "");
1470
+ } else if (tokens > 0) {
1471
+ return tokens.toFixed(8).replace(/\.?0+$/, "");
1472
+ }
1473
+ return "0";
1474
+ }
1475
+ function buildConfirmTxTemplateData(project, origin, transaction, risk, metadata, userProfile, explorerUrl) {
1415
1476
  const isVerifiedOrigin = project.domains.includes(origin);
1416
1477
  const isUserOp = !!transaction.userOpDetails;
1417
1478
  const displayName = metadata?.name || project.name;
@@ -1420,8 +1481,13 @@ function buildConfirmTxTemplateData(project, origin, transaction, risk, metadata
1420
1481
  const userName = userProfile?.displayName || "Lumia Passport";
1421
1482
  const domainStatusClass = isVerifiedOrigin ? "verified" : "unverified";
1422
1483
  const domainStatusText = isVerifiedOrigin ? "\u2705" : "\u26A0\uFE0F";
1423
- const fromAddress = formatAddress(transaction.userOpDetails?.sender || "");
1424
- const toAddress = formatAddress(transaction.userOpDetails?.callTarget || transaction.to || "");
1484
+ const fromAddressFull = transaction.userOpDetails?.sender || "";
1485
+ const toAddressFull = transaction.userOpDetails?.callTarget || transaction.to || "";
1486
+ const fromAddress = formatAddress(fromAddressFull);
1487
+ const toAddress = formatAddress(toAddressFull);
1488
+ const baseExplorerUrl = explorerUrl || DEFAULT_EXPLORER_URL;
1489
+ const fromAddressExplorerUrl = getAddressExplorerUrl(fromAddressFull, baseExplorerUrl);
1490
+ const toAddressExplorerUrl = getAddressExplorerUrl(toAddressFull, baseExplorerUrl);
1425
1491
  const formatValue = (valueWei) => {
1426
1492
  try {
1427
1493
  const value = BigInt(valueWei);
@@ -1439,7 +1505,19 @@ function buildConfirmTxTemplateData(project, origin, transaction, risk, metadata
1439
1505
  const transactionValue = transaction.value || "0";
1440
1506
  const formattedValue = formatValue(transactionValue);
1441
1507
  const hasValue = BigInt(transactionValue) > 0n;
1442
- const showContractInteraction = isUserOp && !!transaction.userOpDetails?.callData && transaction.userOpDetails.callData !== "0x";
1508
+ const callData = transaction.userOpDetails?.callData || transaction.data || "";
1509
+ const innerCallData = extractInnerCallData(callData);
1510
+ const effectiveCallData = innerCallData || callData;
1511
+ const hasContractCall = !!effectiveCallData && effectiveCallData !== "0x" && effectiveCallData.length > 2;
1512
+ const showContractInteraction = isUserOp ? hasContractCall : !!callData && callData !== "0x";
1513
+ let actionDescription = "Contract Interaction";
1514
+ if (showContractInteraction) {
1515
+ const approveData = parseERC20Approve(callData);
1516
+ if (approveData) {
1517
+ const formattedAmount = formatApproveAmount(approveData.amount);
1518
+ actionDescription = `Approve ${formattedAmount} tokens`;
1519
+ }
1520
+ }
1443
1521
  const isSponsored = isUserOp && !!transaction.userOpDetails?.paymaster;
1444
1522
  const estimatedCost = isSponsored ? "0 (Sponsored)" : "Free (Sponsored Transaction)";
1445
1523
  const showHighRisk = risk.level !== "LOW";
@@ -1455,9 +1533,14 @@ function buildConfirmTxTemplateData(project, origin, transaction, risk, metadata
1455
1533
  domainStatusText,
1456
1534
  fromAddress,
1457
1535
  toAddress,
1536
+ fromAddressFull,
1537
+ toAddressFull,
1538
+ fromAddressExplorerUrl,
1539
+ toAddressExplorerUrl,
1458
1540
  hasValue,
1459
1541
  formattedValue,
1460
1542
  showContractInteraction,
1543
+ actionDescription,
1461
1544
  estimatedCost,
1462
1545
  isSponsored,
1463
1546
  showHighRisk,
@@ -4042,7 +4125,7 @@ var SigningManager = class extends TokenRefreshApiClient {
4042
4125
  createConfirmationModal(userId, projectId, project, origin, transaction, risk, metadata, userProfile) {
4043
4126
  const modal = document.createElement("div");
4044
4127
  modal.className = "transaction-confirmation-modal";
4045
- const templateData = buildConfirmTxTemplateData(project, origin, transaction, risk, metadata, userProfile);
4128
+ const templateData = buildConfirmTxTemplateData(project, origin, transaction, risk, metadata, userProfile, this.explorerUrl);
4046
4129
  const template = TemplateLoader.getTemplate("confirm-tx");
4047
4130
  modal.innerHTML = TemplateEngine.render(template, templateData);
4048
4131
  return modal;
@@ -4228,7 +4311,7 @@ var SigningManager = class extends TokenRefreshApiClient {
4228
4311
  };
4229
4312
 
4230
4313
  // src/iframe/main.ts
4231
- var IFRAME_VERSION = "1.14.15";
4314
+ var IFRAME_VERSION = "1.14.18";
4232
4315
  var IframeWallet = class {
4233
4316
  constructor() {
4234
4317
  console.log("=".repeat(60));