@lumiapassport/ui-kit 1.14.14 → 1.14.16
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/dist/iframe/index.html +1 -1
- package/dist/iframe/main.js +94 -20
- package/dist/iframe/main.js.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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.14.
|
|
18
|
+
<title>Lumia Passport Secure Wallet - iframe version 1.14.16</title>
|
|
19
19
|
|
|
20
20
|
<!-- Styles will be injected by build process -->
|
|
21
21
|
<style>
|
package/dist/iframe/main.js
CHANGED
|
@@ -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 <
|
|
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,52 @@ 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 DEFAULT_EXPLORER_URL = "https://beam-explorer.lumia.org";
|
|
1410
1412
|
function formatAddress(address) {
|
|
1411
1413
|
if (address.length < 10) return address;
|
|
1412
1414
|
return `${address.slice(0, 6)}...${address.slice(-4)}`;
|
|
1413
1415
|
}
|
|
1414
|
-
function
|
|
1416
|
+
function getAddressExplorerUrl(address, explorerUrl) {
|
|
1417
|
+
if (!address) return "";
|
|
1418
|
+
const baseUrl = explorerUrl.replace(/\/$/, "");
|
|
1419
|
+
return `${baseUrl}/address/${address}`;
|
|
1420
|
+
}
|
|
1421
|
+
function parseERC20Approve(callData) {
|
|
1422
|
+
if (!callData || callData.length < 10) return null;
|
|
1423
|
+
const selector = callData.slice(0, 10).toLowerCase();
|
|
1424
|
+
if (selector !== ERC20_APPROVE_SELECTOR) return null;
|
|
1425
|
+
if (callData.length < 138) return null;
|
|
1426
|
+
try {
|
|
1427
|
+
const spender = "0x" + callData.slice(34, 74);
|
|
1428
|
+
const amountHex = callData.slice(74, 138);
|
|
1429
|
+
const amount = BigInt("0x" + amountHex);
|
|
1430
|
+
return { spender, amount };
|
|
1431
|
+
} catch {
|
|
1432
|
+
return null;
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
function formatApproveAmount(amount) {
|
|
1436
|
+
const MAX_UINT256 = 2n ** 256n - 1n;
|
|
1437
|
+
const NEAR_MAX = 2n ** 255n;
|
|
1438
|
+
if (amount >= NEAR_MAX) {
|
|
1439
|
+
return "Unlimited";
|
|
1440
|
+
}
|
|
1441
|
+
const tokens = Number(amount) / 1e18;
|
|
1442
|
+
if (tokens >= 1e9) {
|
|
1443
|
+
return `${(tokens / 1e9).toFixed(2)}B`;
|
|
1444
|
+
} else if (tokens >= 1e6) {
|
|
1445
|
+
return `${(tokens / 1e6).toFixed(2)}M`;
|
|
1446
|
+
} else if (tokens >= 1e3) {
|
|
1447
|
+
return `${(tokens / 1e3).toFixed(2)}K`;
|
|
1448
|
+
} else if (tokens >= 1) {
|
|
1449
|
+
return tokens.toFixed(4).replace(/\.?0+$/, "");
|
|
1450
|
+
} else if (tokens > 0) {
|
|
1451
|
+
return tokens.toFixed(8).replace(/\.?0+$/, "");
|
|
1452
|
+
}
|
|
1453
|
+
return "0";
|
|
1454
|
+
}
|
|
1455
|
+
function buildConfirmTxTemplateData(project, origin, transaction, risk, metadata, userProfile, explorerUrl) {
|
|
1415
1456
|
const isVerifiedOrigin = project.domains.includes(origin);
|
|
1416
1457
|
const isUserOp = !!transaction.userOpDetails;
|
|
1417
1458
|
const displayName = metadata?.name || project.name;
|
|
@@ -1420,8 +1461,13 @@ function buildConfirmTxTemplateData(project, origin, transaction, risk, metadata
|
|
|
1420
1461
|
const userName = userProfile?.displayName || "Lumia Passport";
|
|
1421
1462
|
const domainStatusClass = isVerifiedOrigin ? "verified" : "unverified";
|
|
1422
1463
|
const domainStatusText = isVerifiedOrigin ? "\u2705" : "\u26A0\uFE0F";
|
|
1423
|
-
const
|
|
1424
|
-
const
|
|
1464
|
+
const fromAddressFull = transaction.userOpDetails?.sender || "";
|
|
1465
|
+
const toAddressFull = transaction.userOpDetails?.callTarget || transaction.to || "";
|
|
1466
|
+
const fromAddress = formatAddress(fromAddressFull);
|
|
1467
|
+
const toAddress = formatAddress(toAddressFull);
|
|
1468
|
+
const baseExplorerUrl = explorerUrl || DEFAULT_EXPLORER_URL;
|
|
1469
|
+
const fromAddressExplorerUrl = getAddressExplorerUrl(fromAddressFull, baseExplorerUrl);
|
|
1470
|
+
const toAddressExplorerUrl = getAddressExplorerUrl(toAddressFull, baseExplorerUrl);
|
|
1425
1471
|
const formatValue = (valueWei) => {
|
|
1426
1472
|
try {
|
|
1427
1473
|
const value = BigInt(valueWei);
|
|
@@ -1439,7 +1485,16 @@ function buildConfirmTxTemplateData(project, origin, transaction, risk, metadata
|
|
|
1439
1485
|
const transactionValue = transaction.value || "0";
|
|
1440
1486
|
const formattedValue = formatValue(transactionValue);
|
|
1441
1487
|
const hasValue = BigInt(transactionValue) > 0n;
|
|
1442
|
-
const
|
|
1488
|
+
const callData = transaction.userOpDetails?.callData || transaction.data || "";
|
|
1489
|
+
const showContractInteraction = isUserOp && !!callData && callData !== "0x";
|
|
1490
|
+
let actionDescription = "Contract Interaction";
|
|
1491
|
+
if (showContractInteraction) {
|
|
1492
|
+
const approveData = parseERC20Approve(callData);
|
|
1493
|
+
if (approveData) {
|
|
1494
|
+
const formattedAmount = formatApproveAmount(approveData.amount);
|
|
1495
|
+
actionDescription = `Approve ${formattedAmount} tokens`;
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1443
1498
|
const isSponsored = isUserOp && !!transaction.userOpDetails?.paymaster;
|
|
1444
1499
|
const estimatedCost = isSponsored ? "0 (Sponsored)" : "Free (Sponsored Transaction)";
|
|
1445
1500
|
const showHighRisk = risk.level !== "LOW";
|
|
@@ -1455,9 +1510,14 @@ function buildConfirmTxTemplateData(project, origin, transaction, risk, metadata
|
|
|
1455
1510
|
domainStatusText,
|
|
1456
1511
|
fromAddress,
|
|
1457
1512
|
toAddress,
|
|
1513
|
+
fromAddressFull,
|
|
1514
|
+
toAddressFull,
|
|
1515
|
+
fromAddressExplorerUrl,
|
|
1516
|
+
toAddressExplorerUrl,
|
|
1458
1517
|
hasValue,
|
|
1459
1518
|
formattedValue,
|
|
1460
1519
|
showContractInteraction,
|
|
1520
|
+
actionDescription,
|
|
1461
1521
|
estimatedCost,
|
|
1462
1522
|
isSponsored,
|
|
1463
1523
|
showHighRisk,
|
|
@@ -1476,6 +1536,13 @@ var AuthorizationManager = class {
|
|
|
1476
1536
|
this.metadataCache = /* @__PURE__ */ new Map();
|
|
1477
1537
|
console.log("[iframe][Auth] Initialized");
|
|
1478
1538
|
}
|
|
1539
|
+
/**
|
|
1540
|
+
* Check if project is a trusted authorized app (auto-skip auth dialog)
|
|
1541
|
+
*/
|
|
1542
|
+
async isTrustedAuthorizedApp(projectId) {
|
|
1543
|
+
const metadata = await this.fetchProjectMetadata(projectId);
|
|
1544
|
+
return metadata?.trustedAuthorizedApp === true;
|
|
1545
|
+
}
|
|
1479
1546
|
/**
|
|
1480
1547
|
* Fetch project metadata from public API (with caching)
|
|
1481
1548
|
*/
|
|
@@ -4035,7 +4102,7 @@ var SigningManager = class extends TokenRefreshApiClient {
|
|
|
4035
4102
|
createConfirmationModal(userId, projectId, project, origin, transaction, risk, metadata, userProfile) {
|
|
4036
4103
|
const modal = document.createElement("div");
|
|
4037
4104
|
modal.className = "transaction-confirmation-modal";
|
|
4038
|
-
const templateData = buildConfirmTxTemplateData(project, origin, transaction, risk, metadata, userProfile);
|
|
4105
|
+
const templateData = buildConfirmTxTemplateData(project, origin, transaction, risk, metadata, userProfile, this.explorerUrl);
|
|
4039
4106
|
const template = TemplateLoader.getTemplate("confirm-tx");
|
|
4040
4107
|
modal.innerHTML = TemplateEngine.render(template, templateData);
|
|
4041
4108
|
return modal;
|
|
@@ -4221,7 +4288,7 @@ var SigningManager = class extends TokenRefreshApiClient {
|
|
|
4221
4288
|
};
|
|
4222
4289
|
|
|
4223
4290
|
// src/iframe/main.ts
|
|
4224
|
-
var IFRAME_VERSION = "1.14.
|
|
4291
|
+
var IFRAME_VERSION = "1.14.16";
|
|
4225
4292
|
var IframeWallet = class {
|
|
4226
4293
|
constructor() {
|
|
4227
4294
|
console.log("=".repeat(60));
|
|
@@ -4355,20 +4422,27 @@ var IframeWallet = class {
|
|
|
4355
4422
|
console.log(`[iframe] AUTHENTICATE: userId=${userId}, projectId=${projectId}`);
|
|
4356
4423
|
const isAuthorized = await this.authManager.checkAuthorization(userId, projectId);
|
|
4357
4424
|
if (!isAuthorized) {
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4425
|
+
const isTrustedApp = await this.authManager.isTrustedAuthorizedApp(projectId);
|
|
4426
|
+
if (isTrustedApp) {
|
|
4427
|
+
console.log(`[iframe] Project ${projectId} is a trusted authorized app, auto-authorizing`);
|
|
4428
|
+
await this.authManager.storeAuthorization(userId, projectId, origin);
|
|
4429
|
+
console.log(`[iframe] \u2705 Auto-authorization granted for trusted app: ${userId} -> ${projectId}`);
|
|
4430
|
+
} else {
|
|
4431
|
+
console.log(`[iframe] Authorization needed for project: ${projectId}`);
|
|
4432
|
+
const projectInfo = {
|
|
4433
|
+
id: projectId,
|
|
4434
|
+
name: "Application",
|
|
4435
|
+
logoUrl: "",
|
|
4436
|
+
website: origin,
|
|
4437
|
+
domains: [origin]
|
|
4438
|
+
};
|
|
4439
|
+
const consent = await this.authManager.requestAuthorization(projectInfo, origin, { avatar, displayName });
|
|
4440
|
+
if (!consent) {
|
|
4441
|
+
throw new Error("User denied authorization");
|
|
4442
|
+
}
|
|
4443
|
+
await this.authManager.storeAuthorization(userId, projectId, origin);
|
|
4444
|
+
console.log(`[iframe] \u2705 Authorization granted: ${userId} -> ${projectId}`);
|
|
4369
4445
|
}
|
|
4370
|
-
await this.authManager.storeAuthorization(userId, projectId, origin);
|
|
4371
|
-
console.log(`[iframe] \u2705 Authorization granted: ${userId} -> ${projectId}`);
|
|
4372
4446
|
}
|
|
4373
4447
|
const address = this.storage.getOwnerAddress(userId);
|
|
4374
4448
|
this.messenger.sendResponse(
|