@ton-pay/ui-react 0.2.0-beta.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -41
- package/dist/index.d.mts +6 -176
- package/dist/index.d.ts +6 -176
- package/dist/index.js +180 -1827
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +156 -1803
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/components/ton-pay-button/TonPayButton.tsx
|
|
2
|
-
var _react = require('react'); var React6 = _interopRequireWildcard(_react); var React8 = _interopRequireWildcard(_react);
|
|
2
|
+
var _react = require('react'); var React6 = _interopRequireWildcard(_react); var React8 = _interopRequireWildcard(_react);
|
|
3
3
|
|
|
4
4
|
var _uireact = require('@tonconnect/ui-react');
|
|
5
5
|
|
|
@@ -139,8 +139,24 @@ var CloseIcon = ({
|
|
|
139
139
|
"aria-hidden": true,
|
|
140
140
|
children: [
|
|
141
141
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "rect", { width: "32", height: "32", rx: "8", fill: "#F4F4F4" }),
|
|
142
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
143
|
-
|
|
142
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
143
|
+
"path",
|
|
144
|
+
{
|
|
145
|
+
d: "M8.99933 22.251L22.2501 9.00026",
|
|
146
|
+
stroke: "#7A7A7A",
|
|
147
|
+
strokeWidth: "1.5",
|
|
148
|
+
strokeLinecap: "round"
|
|
149
|
+
}
|
|
150
|
+
),
|
|
151
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
152
|
+
"path",
|
|
153
|
+
{
|
|
154
|
+
d: "M8.99933 9.08296L22.2501 22.3337",
|
|
155
|
+
stroke: "#7A7A7A",
|
|
156
|
+
strokeWidth: "1.5",
|
|
157
|
+
strokeLinecap: "round"
|
|
158
|
+
}
|
|
159
|
+
)
|
|
144
160
|
]
|
|
145
161
|
}
|
|
146
162
|
);
|
|
@@ -273,10 +289,7 @@ var ErrorDotIcon = ({
|
|
|
273
289
|
]
|
|
274
290
|
}
|
|
275
291
|
);
|
|
276
|
-
var CardIcon = ({
|
|
277
|
-
size = 20,
|
|
278
|
-
className
|
|
279
|
-
}) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
292
|
+
var CardIcon = ({ size = 20, className }) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
280
293
|
"svg",
|
|
281
294
|
{
|
|
282
295
|
width: size,
|
|
@@ -287,15 +300,24 @@ var CardIcon = ({
|
|
|
287
300
|
className,
|
|
288
301
|
"aria-hidden": true,
|
|
289
302
|
children: [
|
|
290
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
291
|
-
|
|
303
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
304
|
+
"path",
|
|
305
|
+
{
|
|
306
|
+
d: "M15.4688 5H4.53125C3.68693 5 3 5.71369 3 6.59091V13.4091C3 14.2863 3.68693 15 4.53125 15H15.4688C16.3131 15 17 14.2863 17 13.4091V6.59091C17 5.71369 16.3131 5 15.4688 5ZM4.53125 5.90909H15.4688C15.8306 5.90909 16.125 6.21497 16.125 6.59091V7.5H3.875V6.59091C3.875 6.21497 4.16941 5.90909 4.53125 5.90909ZM15.4688 14.0909H4.53125C4.16941 14.0909 3.875 13.785 3.875 13.4091V8.40909H16.125V13.4091C16.125 13.785 15.8306 14.0909 15.4688 14.0909Z",
|
|
307
|
+
fill: "white"
|
|
308
|
+
}
|
|
309
|
+
),
|
|
310
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
311
|
+
"path",
|
|
312
|
+
{
|
|
313
|
+
d: "M6.33333 13H5.66667C5.2985 13 5 12.7015 5 12.3333V11.6667C5 11.2985 5.2985 11 5.66667 11H6.33333C6.7015 11 7 11.2985 7 11.6667V12.3333C7 12.7015 6.7015 13 6.33333 13Z",
|
|
314
|
+
fill: "white"
|
|
315
|
+
}
|
|
316
|
+
)
|
|
292
317
|
]
|
|
293
318
|
}
|
|
294
319
|
);
|
|
295
|
-
var CryptoIcon = ({
|
|
296
|
-
size = 20,
|
|
297
|
-
className
|
|
298
|
-
}) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
320
|
+
var CryptoIcon = ({ size = 20, className }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
299
321
|
"svg",
|
|
300
322
|
{
|
|
301
323
|
width: size,
|
|
@@ -305,40 +327,38 @@ var CryptoIcon = ({
|
|
|
305
327
|
xmlns: "http://www.w3.org/2000/svg",
|
|
306
328
|
className,
|
|
307
329
|
"aria-hidden": true,
|
|
308
|
-
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
330
|
+
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
331
|
+
"path",
|
|
332
|
+
{
|
|
333
|
+
d: "M14.3896 3.5H5.61006C3.99582 3.5 2.97267 5.24122 3.7848 6.64885L9.20318 16.0401C9.55683 16.6533 10.4429 16.6533 10.7965 16.0401L16.216 6.64885C17.027 5.24347 16.0028 3.5 14.3896 3.5ZM9.19879 13.2238L8.01872 10.9401L5.17144 5.84782C4.98361 5.52189 5.21561 5.10422 5.60896 5.10422H9.19772V13.225L9.19879 13.2238ZM14.826 5.84671L11.9798 10.9412L10.7998 13.2238V5.10312H14.3885C14.7818 5.10312 15.0138 5.52078 14.826 5.84671Z",
|
|
334
|
+
fill: "white"
|
|
335
|
+
}
|
|
336
|
+
)
|
|
309
337
|
}
|
|
310
338
|
);
|
|
311
|
-
var
|
|
312
|
-
|
|
313
|
-
color = "currentColor",
|
|
314
|
-
className
|
|
315
|
-
}) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
316
|
-
"svg",
|
|
339
|
+
var TonPayLogo = ({ className }) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
340
|
+
"div",
|
|
317
341
|
{
|
|
318
|
-
width: size,
|
|
319
|
-
height: size,
|
|
320
|
-
viewBox: "0 0 24 24",
|
|
321
|
-
fill: "none",
|
|
322
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
323
342
|
className,
|
|
324
|
-
"
|
|
343
|
+
style: { display: "flex", alignItems: "center", gap: "4px" },
|
|
325
344
|
children: [
|
|
326
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
327
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
328
|
-
|
|
345
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, TonIconBlue, { size: 26 }),
|
|
346
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
347
|
+
"span",
|
|
348
|
+
{
|
|
349
|
+
style: {
|
|
350
|
+
fontWeight: 600,
|
|
351
|
+
fontSize: "18px",
|
|
352
|
+
lineHeight: "24px",
|
|
353
|
+
color: "#000000",
|
|
354
|
+
letterSpacing: "-0.5px"
|
|
355
|
+
},
|
|
356
|
+
children: "Pay"
|
|
357
|
+
}
|
|
358
|
+
)
|
|
329
359
|
]
|
|
330
360
|
}
|
|
331
361
|
);
|
|
332
|
-
var TonPayLogo = ({ className }) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className, style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
|
|
333
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, TonIconBlue, { size: 26 }),
|
|
334
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { style: {
|
|
335
|
-
fontWeight: 600,
|
|
336
|
-
fontSize: "18px",
|
|
337
|
-
lineHeight: "24px",
|
|
338
|
-
color: "#000000",
|
|
339
|
-
letterSpacing: "-0.5px"
|
|
340
|
-
}, children: "Pay" })
|
|
341
|
-
] });
|
|
342
362
|
|
|
343
363
|
// src/components/notification/Notification.tsx
|
|
344
364
|
|
|
@@ -415,7 +435,7 @@ var ErrorTransactionNotification = ({ text, className, style }) => {
|
|
|
415
435
|
|
|
416
436
|
// src/components/bottom-sheet/BottomSheet.css
|
|
417
437
|
var _styleinject = require('#style-inject'); var _styleinject2 = _interopRequireDefault(_styleinject);
|
|
418
|
-
_styleinject2.default.call(void 0, ".bottom-sheet-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n z-index: 1000;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n animation: fadeIn 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n.bottom-sheet-backdrop.closing {\n animation: fadeOut 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n@keyframes fadeIn {\n from {\n opacity: 0;\n backdrop-filter: blur(0px);\n -webkit-backdrop-filter: blur(0px);\n }\n to {\n opacity: 1;\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n }\n}\n@keyframes fadeOut {\n from {\n opacity: 1;\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n }\n to {\n opacity: 0;\n backdrop-filter: blur(0px);\n -webkit-backdrop-filter: blur(0px);\n }\n}\n.bottom-sheet {\n position: relative;\n width: 100%;\n max-width: 100%;\n background-color: #ffffff;\n border-radius: 20px 20px 0 0;\n box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.15);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n touch-action: none;\n transition: height 0.3s cubic-bezier(0.4, 0, 0.2, 1), transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n will-change: height, transform;\n transform: translateY(0);\n}\n.bottom-sheet.dragging {\n transition: none;\n}\n.bottom-sheet.closing {\n animation: slideDown 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;\n transition: height 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n@keyframes slideDown {\n from {\n transform: translateY(0);\n }\n to {\n transform: translateY(100%);\n }\n}\n.bottom-sheet-handle-container {\n width: 100%;\n padding: 12px 0 8px;\n display: flex;\n justify-content: center;\n align-items: center;\n flex-shrink: 0;\n cursor: grab;\n}\n.bottom-sheet-handle-container:active {\n cursor: grabbing;\n}\n.bottom-sheet-handle {\n width: 80px;\n height: 4px;\n background-color: #d1d5db;\n border-radius: 2px;\n cursor: pointer;\n}\n.bottom-sheet-content {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n overscroll-behavior: contain;\n padding: 0;\n min-height: 0;\n}\n.bottom-sheet-content.scrolling {\n touch-action: pan-y;\n}\n@media (prefers-color-scheme: dark) {\n .bottom-sheet {\n background-color: #
|
|
438
|
+
_styleinject2.default.call(void 0, ".bottom-sheet-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n z-index: 1000;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n animation: fadeIn 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n.bottom-sheet-backdrop.closing {\n animation: fadeOut 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n@keyframes fadeIn {\n from {\n opacity: 0;\n backdrop-filter: blur(0px);\n -webkit-backdrop-filter: blur(0px);\n }\n to {\n opacity: 1;\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n }\n}\n@keyframes fadeOut {\n from {\n opacity: 1;\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n }\n to {\n opacity: 0;\n backdrop-filter: blur(0px);\n -webkit-backdrop-filter: blur(0px);\n }\n}\n.bottom-sheet {\n position: relative;\n width: 100%;\n max-width: 100%;\n background-color: #ffffff;\n border-radius: 20px 20px 0 0;\n box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.15);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n touch-action: none;\n transition: height 0.3s cubic-bezier(0.4, 0, 0.2, 1), transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n will-change: height, transform;\n transform: translateY(0);\n}\n.bottom-sheet.dragging {\n transition: none;\n}\n.bottom-sheet.closing {\n animation: slideDown 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;\n transition: height 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n@keyframes slideDown {\n from {\n transform: translateY(0);\n }\n to {\n transform: translateY(100%);\n }\n}\n.bottom-sheet-handle-container {\n width: 100%;\n padding: 12px 0 8px;\n display: flex;\n justify-content: center;\n align-items: center;\n flex-shrink: 0;\n cursor: grab;\n}\n.bottom-sheet-handle-container:active {\n cursor: grabbing;\n}\n.bottom-sheet-handle {\n width: 80px;\n height: 4px;\n background-color: #d1d5db;\n border-radius: 2px;\n cursor: pointer;\n}\n.bottom-sheet-content {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n overscroll-behavior: contain;\n padding: 0;\n min-height: 0;\n}\n.bottom-sheet-content.scrolling {\n touch-action: pan-y;\n}\n@media (prefers-color-scheme: dark) {\n .bottom-sheet {\n background-color: #1c2633;\n box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.4);\n }\n .bottom-sheet-handle {\n background-color: #4b5563;\n }\n}\n");
|
|
419
439
|
|
|
420
440
|
// src/components/bottom-sheet/BottomSheet.tsx
|
|
421
441
|
|
|
@@ -534,7 +554,10 @@ var BottomSheet = ({
|
|
|
534
554
|
);
|
|
535
555
|
const snapToDetent = _react.useCallback.call(void 0,
|
|
536
556
|
(detentIndex) => {
|
|
537
|
-
const clampedIndex = Math.max(
|
|
557
|
+
const clampedIndex = Math.max(
|
|
558
|
+
0,
|
|
559
|
+
Math.min(detentIndex, detents.length - 1)
|
|
560
|
+
);
|
|
538
561
|
isSnappingRef.current = true;
|
|
539
562
|
targetDetentRef.current = clampedIndex;
|
|
540
563
|
const viewportHeight = window.innerHeight;
|
|
@@ -583,10 +606,16 @@ var BottomSheet = ({
|
|
|
583
606
|
if (isDraggingDown && enableSwipeToClose) {
|
|
584
607
|
newHeight = Math.max(0, Math.min(maxDetentHeight, newHeight));
|
|
585
608
|
} else {
|
|
586
|
-
newHeight = Math.max(
|
|
609
|
+
newHeight = Math.max(
|
|
610
|
+
minDetentHeight,
|
|
611
|
+
Math.min(maxDetentHeight, newHeight)
|
|
612
|
+
);
|
|
587
613
|
}
|
|
588
614
|
} else {
|
|
589
|
-
newHeight = Math.max(
|
|
615
|
+
newHeight = Math.max(
|
|
616
|
+
minDetentHeight,
|
|
617
|
+
Math.min(maxDetentHeight, newHeight)
|
|
618
|
+
);
|
|
590
619
|
}
|
|
591
620
|
return newHeight;
|
|
592
621
|
},
|
|
@@ -598,7 +627,7 @@ var BottomSheet = ({
|
|
|
598
627
|
const touch = e.touches[0];
|
|
599
628
|
if (!touch) return;
|
|
600
629
|
const deltaY = touch.clientY - touchStartYRef.current;
|
|
601
|
-
const currentScrollTop = _nullishCoalesce(_optionalChain([contentRef, 'access',
|
|
630
|
+
const currentScrollTop = _nullishCoalesce(_optionalChain([contentRef, 'access', _ => _.current, 'optionalAccess', _2 => _2.scrollTop]), () => ( 0));
|
|
602
631
|
const isContentScrollable = contentRef.current ? contentRef.current.scrollHeight > contentRef.current.clientHeight : false;
|
|
603
632
|
if (!contentRef.current) return;
|
|
604
633
|
const touchTarget = e.target;
|
|
@@ -722,14 +751,28 @@ var BottomSheet = ({
|
|
|
722
751
|
if (isAtMaxDetent) {
|
|
723
752
|
newHeight = Math.max(0, Math.min(maxDetentHeight, newHeight));
|
|
724
753
|
} else if (isAtMinDetent) {
|
|
725
|
-
newHeight = Math.max(
|
|
754
|
+
newHeight = Math.max(
|
|
755
|
+
minDetentHeight,
|
|
756
|
+
Math.min(maxDetentHeight, newHeight)
|
|
757
|
+
);
|
|
726
758
|
} else {
|
|
727
|
-
newHeight = Math.max(
|
|
759
|
+
newHeight = Math.max(
|
|
760
|
+
minDetentHeight,
|
|
761
|
+
Math.min(maxDetentHeight, newHeight)
|
|
762
|
+
);
|
|
728
763
|
}
|
|
729
764
|
setSheetHeight(newHeight);
|
|
730
765
|
setCurrentY(e.clientY);
|
|
731
766
|
},
|
|
732
|
-
[
|
|
767
|
+
[
|
|
768
|
+
isOpen,
|
|
769
|
+
isDragging,
|
|
770
|
+
startY,
|
|
771
|
+
currentDetent,
|
|
772
|
+
detents,
|
|
773
|
+
getDetentValue,
|
|
774
|
+
isClosing
|
|
775
|
+
]
|
|
733
776
|
);
|
|
734
777
|
const handleMouseUp = _react.useCallback.call(void 0, () => {
|
|
735
778
|
if (!isOpen || !isDragging || isClosing) return;
|
|
@@ -912,7 +955,7 @@ var BottomSheet_default = BottomSheet;
|
|
|
912
955
|
|
|
913
956
|
// src/components/payment-modal/PaymentModal.css
|
|
914
957
|
|
|
915
|
-
_styleinject2.default.call(void 0, '.pm-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n font-family: "Inter", sans-serif;\n color: #000000;\n --pm-bg: #FFFFFF;\n --pm-text: #000000;\n --pm-text-secondary: #666666;\n --pm-text-muted: #8C8C8C;\n --pm-border: rgba(0, 0, 0, 0.1);\n --pm-order-bg: #E9F5FA;\n --pm-order-border: rgba(0, 100, 153, 0.03);\n --pm-order-text: #004062;\n --pm-hover-bg: #F9F9F9;\n --pm-iframe-bg: #f9f9f9;\n --pm-spinner-track: #E5E7EB;\n}\n@media (prefers-color-scheme: dark) {\n .pm-content {\n color: #FFFFFF;\n --pm-bg: #1f2937;\n --pm-text: #FFFFFF;\n --pm-text-secondary: #9CA3AF;\n --pm-text-muted: #6B7280;\n --pm-border: rgba(255, 255, 255, 0.1);\n --pm-order-bg: rgba(0, 152, 234, 0.15);\n --pm-order-border: rgba(0, 152, 234, 0.2);\n --pm-order-text: #7DD3FC;\n --pm-hover-bg: rgba(255, 255, 255, 0.05);\n --pm-iframe-bg: #111827;\n --pm-spinner-track: #374151;\n }\n}\n.pm-header {\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n padding: 16px;\n box-sizing: border-box;\n position: relative;\n}\n.bottom-sheet .pm-header {\n padding: 0 16px;\n}\n.pm-header-left,\n.pm-header-right {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 40px;\n}\n.pm-header-right {\n justify-content: flex-end;\n}\n.pm-title {\n font-weight: 600;\n font-size: 18px;\n line-height: 22px;\n text-align: center;\n flex: 1;\n}\n.pm-close-btn,\n.pm-back-btn {\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--pm-text, #000000);\n opacity: 0.6;\n}\n.pm-close-btn:hover,\n.pm-back-btn:hover {\n opacity: 1;\n}\n.pm-body-main {\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n padding: 0;\n gap: 0;\n box-sizing: border-box;\n}\n.pm-main-container {\n display: flex;\n flex-direction: column;\n gap: 8px;\n width: 100%;\n padding: 0 16px;\n}\n.pm-main-title {\n font-size: 18px;\n font-weight: 600;\n line-height: 20px;\n text-align: center;\n margin: 0 0 8px;\n color: var(--pm-text, #000000);\n}\n.pm-amount-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n margin-bottom: 16px;\n}\n.pm-amount-label {\n font-weight: 500;\n font-size: 12px;\n line-height: 15px;\n color: var(--pm-text-muted, #8C8C8C);\n}\n.pm-amount-value {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n font-size: 24px;\n line-height: 29px;\n color: var(--pm-text, #000000);\n}\n.pm-order-info {\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n width: 100%;\n height: 36px;\n padding: 8px 16px;\n margin-bottom: 24px;\n gap: 4px;\n background: #E9F5FA;\n border-radius: 9px;\n box-sizing: border-box;\n border: none;\n}\n.pm-order-text {\n font-family: "Inter", sans-serif;\n font-style: normal;\n font-weight: 400;\n font-size: 12px;\n line-height: 15px;\n text-align: center;\n color: #004062;\n flex: none;\n}\n.pm-info-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n cursor: help;\n opacity: 1;\n}\n.pm-info-icon:hover {\n opacity: 1;\n}\n.pm-actions-card {\n width: 100%;\n background: #F9F9F9;\n border-top: 1px solid hsl(0, 0%, 92%);\n padding: 16px;\n box-sizing: border-box;\n}\n@media (prefers-color-scheme: dark) {\n .pm-actions-card {\n background: var(--pm-hover-bg, rgba(255, 255, 255, 0.05));\n }\n}\n.pm-actions {\n display: flex;\n flex-direction: column;\n gap: 8px;\n width: 100%;\n}\n.pm-btn {\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n padding: 13px 10px;\n gap: 4px;\n width: 100%;\n height: 44px;\n border-radius: 8px;\n border: none;\n cursor: pointer;\n font-weight: 500;\n font-size: 14px;\n line-height: 19px;\n transition: opacity 0.2s;\n}\n.pm-btn:hover {\n opacity: 0.9;\n}\n.pm-btn-primary {\n background: #0098EA;\n color: #FFFFFF;\n}\n.pm-btn-black {\n background: #000000;\n color: #FFFFFF;\n}\n.pm-btn.processing {\n background: #E6E6E6;\n color: #7A7A7A;\n cursor: default;\n}\n.pm-btn.processing:hover {\n opacity: 1;\n}\n.pm-footer {\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n gap: 8px;\n margin-top: 12px;\n font-size: 12px;\n line-height: 15px;\n}\n.pm-footer-text {\n color: var(--pm-text-muted, #808080);\n}\n.pm-footer-link {\n color: #0098EA;\n cursor: pointer;\n text-decoration: none;\n}\n.pm-footer-link:hover {\n text-decoration: underline;\n}\n.pm-desktop-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.44);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n animation: fadeIn 0.2s ease-out;\n}\n.pm-desktop-modal {\n width: 100%;\n max-width: 414px;\n margin: 16px;\n background: var(--pm-bg, #FFFFFF);\n border-radius: 32px;\n box-shadow: 0px 4px 24px rgba(0, 0, 0, 0.25);\n overflow: hidden;\n position: relative;\n animation: scaleIn 0.2s ease-out;\n}\n@media (prefers-color-scheme: dark) {\n .pm-desktop-modal {\n box-shadow: 0px 4px 32px rgba(0, 0, 0, 0.5);\n }\n}\n@keyframes scaleIn {\n from {\n transform: scale(0.95);\n opacity: 0;\n }\n to {\n transform: scale(1);\n opacity: 1;\n }\n}\n.pm-iframe-container {\n width: 100%;\n height: 100%;\n min-height: 400px;\n display: flex;\n flex-direction: column;\n background: var(--pm-iframe-bg, #f9f9f9);\n position: relative;\n}\n.pm-iframe-container iframe {\n flex: 1;\n width: 100%;\n height: 100%;\n border: none;\n display: block;\n}\n.pm-menu-dropdown {\n position: absolute;\n top: 100%;\n right: 0;\n background: var(--pm-bg, #FFFFFF);\n border: 1px solid var(--pm-border, rgba(0, 0, 0, 0.1));\n border-radius: 8px;\n box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.15);\n z-index: 1001;\n min-width: 150px;\n overflow: hidden;\n}\n@media (prefers-color-scheme: dark) {\n .pm-menu-dropdown {\n box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.4);\n }\n}\n.pm-menu-item {\n padding: 10px 16px;\n font-size: 14px;\n cursor: pointer;\n color: var(--pm-text, #000000);\n}\n.pm-menu-item:hover {\n background: var(--pm-hover-bg, #F9F9F9);\n}\n.pm-menu-item.danger {\n color: #E74C3C;\n}\n.pm-menu-item.disabled {\n cursor: default;\n color: var(--pm-text-muted, #8C8C8C);\n}\n.pm-menu-item.disabled:hover {\n background: transparent;\n}\n.icon-moonpay {\n background: #7D00FF;\n color: white;\n}\n.icon-onramper {\n background: #000000;\n color: white;\n}\n.icon-transak {\n background:\n linear-gradient(\n 120deg,\n #348BED 22.91%,\n #2B80E8 36.09%,\n #1461DB 60.25%,\n #0E57D7 66.11%);\n color: white;\n}\n.icon-mercurio {\n background: #000000;\n color: white;\n}\n.pm-success-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 24px;\n text-align: center;\n}\n.pm-success-icon {\n width: 64px;\n height: 64px;\n background: #0098EA;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 20px;\n color: white;\n}\n.pm-success-icon svg {\n width: 32px;\n height: 32px;\n}\n.pm-success-title {\n font-size: 24px;\n font-weight: 600;\n color: var(--pm-text, #000000);\n margin: 0 0 8px;\n}\n.pm-success-text {\n font-size: 16px;\n color: var(--pm-text-secondary, #666666);\n margin: 0;\n}\n.pm-error-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 24px;\n text-align: center;\n}\n.pm-error-icon {\n width: 64px;\n height: 64px;\n background: #E74C3C;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 20px;\n color: white;\n}\n.pm-error-icon svg {\n width: 32px;\n height: 32px;\n}\n.pm-error-title {\n font-size: 24px;\n font-weight: 600;\n color: var(--pm-text, #000000);\n margin: 0 0 8px;\n}\n.pm-error-text {\n font-size: 16px;\n color: var(--pm-text-secondary, #666666);\n margin: 0 0 24px;\n max-width: 300px;\n}\n.pm-error-actions {\n display: flex;\n flex-direction: column;\n gap: 12px;\n width: 100%;\n max-width: 280px;\n}\n.pm-error-inline {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 40px 20px;\n text-align: center;\n color: #E74C3C;\n}\n.pm-error-inline svg {\n width: 48px;\n height: 48px;\n margin-bottom: 16px;\n}\n.pm-error-inline p {\n margin: 0 0 20px;\n color: var(--pm-text-secondary, #666666);\n font-size: 14px;\n}\n.pm-btn-outline {\n background: transparent;\n color: #0098EA;\n border: 1px solid #0098EA;\n}\n.pm-btn-outline:hover {\n background: rgba(0, 152, 234, 0.08);\n}\n.pm-loading-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--pm-text-muted, #6b7280);\n}\n.pm-loading-container p {\n margin: 16px 0 0;\n font-size: 14px;\n}\n.pm-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--pm-iframe-bg, #f9f9f9);\n z-index: 1;\n}\n.pm-spinner {\n width: 32px;\n height: 32px;\n border: 3px solid var(--pm-spinner-track, #E5E7EB);\n border-top-color: #0098EA;\n border-radius: 50%;\n animation: pm-spin 0.8s linear infinite;\n}\n.pm-btn-spinner {\n width: 16px;\n height: 16px;\n border: 2px solid rgba(122, 122, 122, 0.3);\n border-top-color: #7A7A7A;\n border-radius: 50%;\n animation: pm-spin 0.8s linear infinite;\n}\n@keyframes pm-spin {\n to {\n transform: rotate(360deg);\n }\n}\n.pm-retry-link {\n font-family: "Inter Variable", sans-serif;\n font-style: normal;\n font-weight: 400;\n font-size: 12px;\n line-height: 15px;\n text-align: center;\n color: #004062;\n margin-top: 0px;\n}\n.pm-retry-action {\n cursor: pointer;\n text-decoration: underline;\n color: #0098EA;\n}\n');
|
|
958
|
+
_styleinject2.default.call(void 0, ':where(.pm-content, .pm-desktop-modal) {\n color: #000000;\n --pm-bg: #ffffff;\n --pm-text: #000000;\n --pm-text-secondary: #666666;\n --pm-text-muted: #8c8c8c;\n --pm-border: rgba(0, 0, 0, 0.1);\n --pm-order-bg: #e9f5fa;\n --pm-order-border: rgba(0, 100, 153, 0.03);\n --pm-order-text: #004062;\n --pm-hover-bg: #f9f9f9;\n --pm-iframe-bg: #f9f9f9;\n --pm-spinner-track: #e5e7eb;\n --pm-actions-border: hsl(0, 0%, 92%);\n}\n.pm-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n font-family: "Inter", sans-serif;\n}\n@media (prefers-color-scheme: dark) {\n :where(.pm-content, .pm-desktop-modal) {\n color: #ffffff;\n --pm-bg: #1f2937;\n --pm-text: #ffffff;\n --pm-text-secondary: #9ca3af;\n --pm-text-muted: #6b7280;\n --pm-border: rgba(255, 255, 255, 0.1);\n --pm-order-bg: rgba(255, 255, 255, 0.05);\n --pm-order-border: rgba(255, 255, 255, 0.1);\n --pm-order-text: #ffffff;\n --pm-hover-bg: rgba(255, 255, 255, 0.05);\n --pm-iframe-bg: #111827;\n --pm-spinner-track: #374151;\n --pm-actions-border: rgba(255, 255, 255, 0.1);\n }\n}\n.pm-header {\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n padding: 16px;\n box-sizing: border-box;\n position: relative;\n}\n.bottom-sheet .pm-header {\n padding: 0 16px;\n}\n.pm-header-left,\n.pm-header-right {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 40px;\n}\n.pm-header-right {\n justify-content: flex-end;\n}\n.pm-title {\n font-weight: 600;\n font-size: 18px;\n line-height: 22px;\n text-align: center;\n flex: 1;\n}\n.pm-close-btn,\n.pm-back-btn {\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--pm-text, #000000);\n opacity: 0.6;\n}\n.pm-close-btn:hover,\n.pm-back-btn:hover {\n opacity: 1;\n}\n.pm-body-main {\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n padding: 0;\n gap: 0;\n box-sizing: border-box;\n}\n.pm-main-container {\n display: flex;\n flex-direction: column;\n gap: 8px;\n width: 100%;\n padding: 0 16px;\n}\n.pm-main-title {\n font-size: 18px;\n font-weight: 600;\n line-height: 20px;\n text-align: center;\n margin: 0 0 8px;\n color: var(--pm-text, #000000);\n}\n.pm-amount-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n margin-bottom: 16px;\n}\n.pm-amount-label {\n font-weight: 500;\n font-size: 12px;\n line-height: 15px;\n color: var(--pm-text-muted, #8c8c8c);\n}\n.pm-amount-value {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n font-size: 24px;\n line-height: 29px;\n color: var(--pm-text, #000000);\n}\n.pm-order-info {\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n width: 100%;\n height: 36px;\n padding: 8px 16px;\n margin-bottom: 24px;\n gap: 4px;\n background: var(--pm-order-bg, #e9f5fa);\n border-radius: 9px;\n box-sizing: border-box;\n border: 1px solid var(--pm-order-border, rgba(0, 100, 153, 0.03));\n}\n.pm-order-text {\n font-family: "Inter", sans-serif;\n font-style: normal;\n font-weight: 400;\n font-size: 12px;\n line-height: 15px;\n text-align: center;\n color: var(--pm-order-text, #004062);\n flex: none;\n}\n.pm-actions-card {\n width: 100%;\n background: #f9f9f9;\n border-top: 1px solid var(--pm-actions-border, hsl(0, 0%, 92%));\n padding: 16px;\n box-sizing: border-box;\n}\n@media (prefers-color-scheme: dark) {\n .pm-actions-card {\n background: var(--pm-hover-bg, rgba(255, 255, 255, 0.05));\n }\n}\n.pm-actions {\n display: flex;\n flex-direction: column;\n gap: 8px;\n width: 100%;\n}\n.pm-btn {\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n padding: 13px 10px 10px;\n gap: 4px;\n width: 100%;\n height: 44px;\n border-radius: 8px;\n border: none;\n cursor: pointer;\n font-weight: 500;\n font-size: 14px;\n line-height: 19px;\n transition: opacity 0.2s;\n}\n.pm-btn:hover {\n opacity: 0.9;\n}\n.pm-btn-primary {\n background: #0098ea;\n color: #ffffff;\n}\n.pm-btn-black {\n background: #000000;\n color: #ffffff;\n}\n.pm-btn.processing {\n background: #e6e6e6;\n color: #7a7a7a;\n cursor: default;\n}\n.pm-btn.processing:hover {\n opacity: 1;\n}\n.pm-footer {\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n gap: 8px;\n margin-top: 12px;\n font-size: 12px;\n line-height: 15px;\n}\n.pm-footer-text {\n color: var(--pm-text-muted, #808080);\n}\n.pm-footer-link {\n color: #0098ea;\n cursor: pointer;\n text-decoration: none;\n}\n.pm-footer-link:hover {\n text-decoration: underline;\n}\n.pm-desktop-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.44);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n animation: fadeIn 0.2s ease-out;\n}\n.pm-desktop-modal {\n width: 100%;\n max-width: 414px;\n margin: 16px;\n background: var(--pm-bg, #ffffff);\n border-radius: 32px;\n box-shadow: 0px 4px 24px rgba(0, 0, 0, 0.25);\n overflow: hidden;\n position: relative;\n animation: scaleIn 0.2s ease-out;\n}\n@media (prefers-color-scheme: dark) {\n .pm-desktop-modal {\n box-shadow: 0px 4px 32px rgba(0, 0, 0, 0.5);\n }\n}\n@keyframes scaleIn {\n from {\n transform: scale(0.95);\n opacity: 0;\n }\n to {\n transform: scale(1);\n opacity: 1;\n }\n}\n.pm-iframe-container {\n width: 100%;\n height: 100%;\n min-height: 400px;\n display: flex;\n flex-direction: column;\n background: var(--pm-iframe-bg, #f9f9f9);\n position: relative;\n}\n.pm-iframe-container iframe {\n flex: 1;\n width: 100%;\n height: 100%;\n border: none;\n display: block;\n}\n.pm-menu-dropdown {\n position: absolute;\n top: 100%;\n right: 0;\n background: var(--pm-bg, #ffffff);\n border: 1px solid var(--pm-border, rgba(0, 0, 0, 0.1));\n border-radius: 8px;\n box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.15);\n z-index: 1001;\n min-width: 150px;\n overflow: hidden;\n}\n@media (prefers-color-scheme: dark) {\n .pm-menu-dropdown {\n box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.4);\n }\n}\n.pm-menu-item {\n padding: 10px 16px;\n font-size: 14px;\n cursor: pointer;\n color: var(--pm-text, #000000);\n}\n.pm-menu-item:hover {\n background: var(--pm-hover-bg, #f9f9f9);\n}\n.pm-menu-item.danger {\n color: #e74c3c;\n}\n.pm-menu-item.disabled {\n cursor: default;\n color: var(--pm-text-muted, #8c8c8c);\n}\n.pm-menu-item.disabled:hover {\n background: transparent;\n}\n.icon-moonpay {\n background: #7d00ff;\n color: white;\n}\n.icon-onramper {\n background: #000000;\n color: white;\n}\n.icon-transak {\n background:\n linear-gradient(\n 120deg,\n #348bed 22.91%,\n #2b80e8 36.09%,\n #1461db 60.25%,\n #0e57d7 66.11%);\n color: white;\n}\n.icon-mercurio {\n background: #000000;\n color: white;\n}\n.pm-success-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 24px;\n text-align: center;\n}\n.pm-success-icon {\n width: 64px;\n height: 64px;\n background: #0098ea;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 20px;\n color: white;\n}\n.pm-success-icon svg {\n width: 32px;\n height: 32px;\n}\n.pm-success-title {\n font-size: 24px;\n font-weight: 600;\n color: var(--pm-text, #000000);\n margin: 0 0 8px;\n}\n.pm-success-text {\n font-size: 16px;\n color: var(--pm-text-secondary, #666666);\n margin: 0;\n}\n.pm-error-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 24px;\n text-align: center;\n}\n.pm-error-icon {\n width: 64px;\n height: 64px;\n background: #e74c3c;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 20px;\n color: white;\n}\n.pm-error-icon svg {\n width: 32px;\n height: 32px;\n}\n.pm-error-title {\n font-size: 24px;\n font-weight: 600;\n color: var(--pm-text, #000000);\n margin: 0 0 8px;\n}\n.pm-error-text {\n font-size: 16px;\n color: var(--pm-text-secondary, #666666);\n margin: 0 0 24px;\n max-width: 300px;\n}\n.pm-error-actions {\n display: flex;\n flex-direction: column;\n gap: 12px;\n width: 100%;\n max-width: 280px;\n}\n.pm-error-inline {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 40px 20px;\n text-align: center;\n color: #e74c3c;\n}\n.pm-error-inline svg {\n width: 48px;\n height: 48px;\n margin-bottom: 16px;\n}\n.pm-error-inline p {\n margin: 0 0 20px;\n color: var(--pm-text-secondary, #666666);\n font-size: 14px;\n}\n.pm-btn-outline {\n background: transparent;\n color: #0098ea;\n border: 1px solid #0098ea;\n}\n.pm-btn-outline:hover {\n background: rgba(0, 152, 234, 0.08);\n}\n.pm-loading-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--pm-text-muted, #6b7280);\n}\n.pm-loading-container p {\n margin: 16px 0 0;\n font-size: 14px;\n}\n.pm-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--pm-iframe-bg, #f9f9f9);\n z-index: 1;\n}\n.pm-spinner {\n width: 32px;\n height: 32px;\n border: 3px solid var(--pm-spinner-track, #e5e7eb);\n border-top-color: #0098ea;\n border-radius: 50%;\n animation: pm-spin 0.8s linear infinite;\n}\n.pm-btn-spinner {\n width: 16px;\n height: 16px;\n border: 2px solid rgba(122, 122, 122, 0.3);\n border-top-color: #7a7a7a;\n border-radius: 50%;\n animation: pm-spin 0.8s linear infinite;\n}\n@keyframes pm-spin {\n to {\n transform: rotate(360deg);\n }\n}\n.pm-retry-link {\n font-family: "Inter", sans-serif;\n font-style: normal;\n font-weight: 400;\n font-size: 12px;\n line-height: 15px;\n text-align: center;\n color: #004062;\n margin-top: 0px;\n}\n.pm-retry-action {\n cursor: pointer;\n text-decoration: underline;\n color: #0098ea;\n}\n@media (prefers-color-scheme: dark) {\n .pm-header-left span {\n color: #ffffff !important;\n }\n .pm-close-btn svg rect {\n fill: rgba(255, 255, 255, 0.1) !important;\n }\n .pm-close-btn svg path {\n stroke: #ffffff !important;\n }\n .pm-retry-link {\n color: var(--pm-text-muted, #8c8c8c) !important;\n }\n .pm-btn.processing {\n background: rgba(255, 255, 255, 0.1) !important;\n color: var(--pm-text-muted, #8c8c8c) !important;\n }\n}\n');
|
|
916
959
|
|
|
917
960
|
// src/components/payment-modal/PaymentModal.tsx
|
|
918
961
|
|
|
@@ -924,7 +967,7 @@ var PaymentModal = ({
|
|
|
924
967
|
onPayWithCrypto,
|
|
925
968
|
amount = "0.1",
|
|
926
969
|
currency = "TON",
|
|
927
|
-
itemTitle
|
|
970
|
+
itemTitle,
|
|
928
971
|
walletAddress,
|
|
929
972
|
onDisconnect,
|
|
930
973
|
fetchOnRampLink,
|
|
@@ -949,7 +992,7 @@ var PaymentModal = ({
|
|
|
949
992
|
clearTimeout(iframeTimeoutRef.current);
|
|
950
993
|
}
|
|
951
994
|
setView("success");
|
|
952
|
-
_optionalChain([onPaymentSuccess, 'optionalCall',
|
|
995
|
+
_optionalChain([onPaymentSuccess, 'optionalCall', _3 => _3()]);
|
|
953
996
|
setTimeout(() => {
|
|
954
997
|
onClose();
|
|
955
998
|
}, 2e3);
|
|
@@ -971,26 +1014,26 @@ var PaymentModal = ({
|
|
|
971
1014
|
}, []);
|
|
972
1015
|
_react.useEffect.call(void 0, () => {
|
|
973
1016
|
const handleMessage = (event) => {
|
|
974
|
-
if (_optionalChain([event, 'access',
|
|
1017
|
+
if (_optionalChain([event, 'access', _4 => _4.data, 'optionalAccess', _5 => _5.type]) === "TONPAY_PAYMENT_SUCCESS") {
|
|
975
1018
|
handlePaymentSuccess();
|
|
976
1019
|
}
|
|
977
|
-
if (_optionalChain([event, 'access',
|
|
1020
|
+
if (_optionalChain([event, 'access', _6 => _6.data, 'optionalAccess', _7 => _7.type]) === "TONPAY_PAYMENT_ERROR") {
|
|
978
1021
|
const payload = event.data.payload;
|
|
979
|
-
handlePaymentError(_optionalChain([payload, 'optionalAccess',
|
|
1022
|
+
handlePaymentError(_optionalChain([payload, 'optionalAccess', _8 => _8.message]) || "Payment failed");
|
|
980
1023
|
}
|
|
981
|
-
if (_optionalChain([event, 'access',
|
|
1024
|
+
if (_optionalChain([event, 'access', _9 => _9.data, 'optionalAccess', _10 => _10.type]) === "TONPAY_IFRAME_LOADED") {
|
|
982
1025
|
setIframeLoaded(true);
|
|
983
1026
|
if (iframeTimeoutRef.current) {
|
|
984
1027
|
clearTimeout(iframeTimeoutRef.current);
|
|
985
1028
|
}
|
|
986
1029
|
}
|
|
987
|
-
if (_optionalChain([event, 'access',
|
|
1030
|
+
if (_optionalChain([event, 'access', _11 => _11.data, 'optionalAccess', _12 => _12.type]) === "TONPAY_MOONPAY_EVENT") {
|
|
988
1031
|
const payload = event.data.payload;
|
|
989
|
-
if (_optionalChain([payload, 'optionalAccess',
|
|
1032
|
+
if (_optionalChain([payload, 'optionalAccess', _13 => _13.type]) === "onTransactionCompleted" || _optionalChain([payload, 'optionalAccess', _14 => _14.eventName]) === "transactionCompleted") {
|
|
990
1033
|
handlePaymentSuccess();
|
|
991
1034
|
}
|
|
992
|
-
if (_optionalChain([payload, 'optionalAccess',
|
|
993
|
-
handlePaymentError(_optionalChain([payload, 'optionalAccess',
|
|
1035
|
+
if (_optionalChain([payload, 'optionalAccess', _15 => _15.type]) === "onTransactionFailed" || _optionalChain([payload, 'optionalAccess', _16 => _16.eventName]) === "transactionFailed") {
|
|
1036
|
+
handlePaymentError(_optionalChain([payload, 'optionalAccess', _17 => _17.message]) || "Transaction failed");
|
|
994
1037
|
}
|
|
995
1038
|
}
|
|
996
1039
|
};
|
|
@@ -1019,7 +1062,7 @@ var PaymentModal = ({
|
|
|
1019
1062
|
}
|
|
1020
1063
|
}, IFRAME_LOAD_TIMEOUT);
|
|
1021
1064
|
}).catch((err) => {
|
|
1022
|
-
const errorMsg = _optionalChain([err, 'optionalAccess',
|
|
1065
|
+
const errorMsg = _optionalChain([err, 'optionalAccess', _18 => _18.message]) || "Failed to initialize payment";
|
|
1023
1066
|
setOnRampError(errorMsg);
|
|
1024
1067
|
fetchStartedRef.current = false;
|
|
1025
1068
|
}).finally(() => setIsOnRampLoading(false));
|
|
@@ -1029,7 +1072,14 @@ var PaymentModal = ({
|
|
|
1029
1072
|
clearTimeout(iframeTimeoutRef.current);
|
|
1030
1073
|
}
|
|
1031
1074
|
};
|
|
1032
|
-
}, [
|
|
1075
|
+
}, [
|
|
1076
|
+
view,
|
|
1077
|
+
onRampLink,
|
|
1078
|
+
onRampError,
|
|
1079
|
+
fetchOnRampLink,
|
|
1080
|
+
iframeLoaded,
|
|
1081
|
+
handlePaymentError
|
|
1082
|
+
]);
|
|
1033
1083
|
_react.useEffect.call(void 0, () => {
|
|
1034
1084
|
const checkMobile = () => {
|
|
1035
1085
|
setIsMobile(window.innerWidth < 768);
|
|
@@ -1055,14 +1105,16 @@ var PaymentModal = ({
|
|
|
1055
1105
|
if (!isMobile || !isOpen) return;
|
|
1056
1106
|
const updateHeight = () => {
|
|
1057
1107
|
if (view === "card") {
|
|
1058
|
-
setSheetDetent([0.9]);
|
|
1108
|
+
setSheetDetent((prev) => prev[0] === 0.9 ? prev : [0.9]);
|
|
1059
1109
|
return;
|
|
1060
1110
|
}
|
|
1061
1111
|
if (contentRef.current) {
|
|
1062
1112
|
const height = contentRef.current.scrollHeight;
|
|
1063
1113
|
const windowHeight = window.innerHeight;
|
|
1064
1114
|
const detent = Math.min((height + 40) / windowHeight, 0.95);
|
|
1065
|
-
setSheetDetent(
|
|
1115
|
+
setSheetDetent(
|
|
1116
|
+
(prev) => Math.abs(prev[0] - detent) < 0.01 ? prev : [detent]
|
|
1117
|
+
);
|
|
1066
1118
|
}
|
|
1067
1119
|
};
|
|
1068
1120
|
setTimeout(updateHeight, 50);
|
|
@@ -1087,7 +1139,14 @@ var PaymentModal = ({
|
|
|
1087
1139
|
view !== "main" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "pm-title", children: "New Purchase" }),
|
|
1088
1140
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "pm-header-right", children: [
|
|
1089
1141
|
walletAddress && view === "main" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { position: "relative" }, children: [
|
|
1090
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1142
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1143
|
+
"button",
|
|
1144
|
+
{
|
|
1145
|
+
className: "pm-close-btn",
|
|
1146
|
+
onClick: () => setShowMenu(!showMenu),
|
|
1147
|
+
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, MenuIcon, {})
|
|
1148
|
+
}
|
|
1149
|
+
),
|
|
1091
1150
|
showMenu && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "pm-menu-dropdown", children: [
|
|
1092
1151
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "pm-menu-item disabled", children: [
|
|
1093
1152
|
walletAddress.slice(0, 4),
|
|
@@ -1099,7 +1158,7 @@ var PaymentModal = ({
|
|
|
1099
1158
|
{
|
|
1100
1159
|
className: "pm-menu-item danger",
|
|
1101
1160
|
onClick: () => {
|
|
1102
|
-
_optionalChain([onDisconnect, 'optionalCall',
|
|
1161
|
+
_optionalChain([onDisconnect, 'optionalCall', _19 => _19()]);
|
|
1103
1162
|
setShowMenu(false);
|
|
1104
1163
|
},
|
|
1105
1164
|
children: "Disconnect"
|
|
@@ -1123,10 +1182,7 @@ var PaymentModal = ({
|
|
|
1123
1182
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, TonIconBlue, {})
|
|
1124
1183
|
] })
|
|
1125
1184
|
] }),
|
|
1126
|
-
/* @__PURE__ */ _jsxruntime.
|
|
1127
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "pm-order-text", children: itemTitle }),
|
|
1128
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "pm-info-icon", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, InfoIcon, { size: 14, color: "#004062" }) })
|
|
1129
|
-
] })
|
|
1185
|
+
itemTitle && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "pm-order-info", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "pm-order-text", children: itemTitle }) })
|
|
1130
1186
|
] }),
|
|
1131
1187
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "pm-actions-card", children: [
|
|
1132
1188
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "pm-actions", children: [
|
|
@@ -1136,13 +1192,25 @@ var PaymentModal = ({
|
|
|
1136
1192
|
className: `pm-btn ${isLoading ? "processing" : "pm-btn-primary"}`,
|
|
1137
1193
|
onClick: isLoading ? void 0 : onPayWithCrypto,
|
|
1138
1194
|
disabled: isLoading,
|
|
1139
|
-
children: isLoading ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1195
|
+
children: isLoading ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1196
|
+
"div",
|
|
1197
|
+
{
|
|
1198
|
+
style: { display: "flex", alignItems: "center", gap: "4px" },
|
|
1199
|
+
children: [
|
|
1200
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "pm-btn-spinner" }),
|
|
1201
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Processing" })
|
|
1202
|
+
]
|
|
1203
|
+
}
|
|
1204
|
+
) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1205
|
+
"div",
|
|
1206
|
+
{
|
|
1207
|
+
style: { display: "flex", alignItems: "center", gap: "4px" },
|
|
1208
|
+
children: [
|
|
1209
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, CryptoIcon, {}),
|
|
1210
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Pay with Crypto" })
|
|
1211
|
+
]
|
|
1212
|
+
}
|
|
1213
|
+
)
|
|
1146
1214
|
}
|
|
1147
1215
|
),
|
|
1148
1216
|
isLoading && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "pm-retry-link", children: [
|
|
@@ -1151,10 +1219,17 @@ var PaymentModal = ({
|
|
|
1151
1219
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "pm-retry-action", onClick: onPayWithCrypto, children: "Click here" }),
|
|
1152
1220
|
"."
|
|
1153
1221
|
] }),
|
|
1154
|
-
onRampAvailable && !isLoading && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1222
|
+
onRampAvailable && !isLoading && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1223
|
+
"button",
|
|
1224
|
+
{
|
|
1225
|
+
className: "pm-btn pm-btn-black",
|
|
1226
|
+
onClick: () => setView("card"),
|
|
1227
|
+
children: [
|
|
1228
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, CardIcon, {}),
|
|
1229
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Pay with Card" })
|
|
1230
|
+
]
|
|
1231
|
+
}
|
|
1232
|
+
)
|
|
1158
1233
|
] }),
|
|
1159
1234
|
onRampAvailable && !isLoading && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "pm-footer", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "pm-footer-text", children: [
|
|
1160
1235
|
"Processed by ",
|
|
@@ -1250,8 +1325,8 @@ var PaymentModal = ({
|
|
|
1250
1325
|
|
|
1251
1326
|
|
|
1252
1327
|
// ../api/src/common/const.ts
|
|
1253
|
-
var BASE_URL = "https://
|
|
1254
|
-
var TESTNET_BASE_URL = "https://testnet.
|
|
1328
|
+
var BASE_URL = "https://pay.ton.org";
|
|
1329
|
+
var TESTNET_BASE_URL = "https://testnet.pay.ton.org";
|
|
1255
1330
|
|
|
1256
1331
|
// ../api/src/common/get-base-url.ts
|
|
1257
1332
|
var getBaseUrl = (chain) => {
|
|
@@ -1266,7 +1341,7 @@ var getBaseUrl = (chain) => {
|
|
|
1266
1341
|
|
|
1267
1342
|
// ../api/src/create-moonpay-transfer/create-moonpay-transfer.ts
|
|
1268
1343
|
var createMoonpayTransfer = async (params, options) => {
|
|
1269
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
1344
|
+
if (!_optionalChain([options, 'optionalAccess', _20 => _20.apiKey])) {
|
|
1270
1345
|
throw new Error("API key is required for MoonPay transfers");
|
|
1271
1346
|
}
|
|
1272
1347
|
const baseUrl = getBaseUrl(options.chain);
|
|
@@ -1295,44 +1370,21 @@ var createMoonpayTransfer = async (params, options) => {
|
|
|
1295
1370
|
return data;
|
|
1296
1371
|
};
|
|
1297
1372
|
|
|
1298
|
-
// ../api/src/check-moonpay-
|
|
1299
|
-
var
|
|
1300
|
-
const baseUrl = getBaseUrl(_optionalChain([options, 'optionalAccess',
|
|
1301
|
-
const headers = {
|
|
1302
|
-
"Content-Type": "application/json",
|
|
1303
|
-
..._optionalChain([options, 'optionalAccess', _23 => _23.apiKey]) ? { "x-api-key": options.apiKey } : {}
|
|
1304
|
-
};
|
|
1305
|
-
const response = await fetch(
|
|
1306
|
-
`${baseUrl}/api/external/moonpay/check-geo?ipAddress=${encodeURIComponent(params.ipAddress)}`,
|
|
1307
|
-
{
|
|
1308
|
-
method: "GET",
|
|
1309
|
-
headers
|
|
1310
|
-
}
|
|
1311
|
-
);
|
|
1312
|
-
if (!response.ok) {
|
|
1313
|
-
const errorText = await response.text();
|
|
1314
|
-
throw new Error(`Failed to check MoonPay geo: ${errorText}`, {
|
|
1315
|
-
cause: response.statusText
|
|
1316
|
-
});
|
|
1317
|
-
}
|
|
1318
|
-
return response.json();
|
|
1319
|
-
};
|
|
1320
|
-
|
|
1321
|
-
// ../api/src/check-moonpay-limits/check-moonpay-limits.ts
|
|
1322
|
-
var checkMoonpayLimits = async (params, options) => {
|
|
1323
|
-
const baseUrl = getBaseUrl(_optionalChain([options, 'optionalAccess', _24 => _24.chain]));
|
|
1373
|
+
// ../api/src/check-moonpay-availability/check-moonpay-availability.ts
|
|
1374
|
+
var checkMoonpayAvailability = async (params, options) => {
|
|
1375
|
+
const baseUrl = getBaseUrl(_optionalChain([options, 'optionalAccess', _21 => _21.chain]));
|
|
1324
1376
|
const headers = {
|
|
1325
1377
|
"Content-Type": "application/json",
|
|
1326
|
-
..._optionalChain([options, 'optionalAccess',
|
|
1378
|
+
..._optionalChain([options, 'optionalAccess', _22 => _22.apiKey]) ? { "x-api-key": options.apiKey } : {}
|
|
1327
1379
|
};
|
|
1328
|
-
const response = await fetch(`${baseUrl}/api/external/moonpay/
|
|
1380
|
+
const response = await fetch(`${baseUrl}/api/external/moonpay/check`, {
|
|
1329
1381
|
method: "POST",
|
|
1330
1382
|
body: JSON.stringify(params),
|
|
1331
1383
|
headers
|
|
1332
1384
|
});
|
|
1333
1385
|
if (!response.ok) {
|
|
1334
1386
|
const errorText = await response.text();
|
|
1335
|
-
throw new Error(`Failed to check MoonPay
|
|
1387
|
+
throw new Error(`Failed to check MoonPay availability: ${errorText}`, {
|
|
1336
1388
|
cause: response.statusText
|
|
1337
1389
|
});
|
|
1338
1390
|
}
|
|
@@ -1360,18 +1412,17 @@ function useMoonPayIframe({
|
|
|
1360
1412
|
setLoading(true);
|
|
1361
1413
|
setError(null);
|
|
1362
1414
|
try {
|
|
1363
|
-
const
|
|
1364
|
-
|
|
1365
|
-
if (!geo.isBuyAllowed) {
|
|
1366
|
-
return false;
|
|
1367
|
-
}
|
|
1368
|
-
const limitRes = await checkMoonpayLimits(
|
|
1369
|
-
{ asset },
|
|
1415
|
+
const availability = await checkMoonpayAvailability(
|
|
1416
|
+
{ asset, ipAddress },
|
|
1370
1417
|
{ apiKey, chain }
|
|
1371
1418
|
);
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
if (!
|
|
1419
|
+
setGeoResult(availability.geo);
|
|
1420
|
+
setLimits(availability.limits);
|
|
1421
|
+
if (!availability.geo.isBuyAllowed) {
|
|
1422
|
+
return false;
|
|
1423
|
+
}
|
|
1424
|
+
const limitsData = availability.limits;
|
|
1425
|
+
if (!_optionalChain([limitsData, 'optionalAccess', _23 => _23.quoteCurrency])) {
|
|
1375
1426
|
return false;
|
|
1376
1427
|
}
|
|
1377
1428
|
const { minBuyAmount, maxBuyAmount } = limitsData.quoteCurrency;
|
|
@@ -1575,7 +1626,7 @@ var TonPayButton = ({
|
|
|
1575
1626
|
setRedirectToWallet(null);
|
|
1576
1627
|
await handlePay((redirect) => setRedirectToWallet(() => redirect));
|
|
1577
1628
|
} catch (err) {
|
|
1578
|
-
_optionalChain([onError, 'optionalCall',
|
|
1629
|
+
_optionalChain([onError, 'optionalCall', _24 => _24(err)]);
|
|
1579
1630
|
if (showErrorNotification) {
|
|
1580
1631
|
const raw = typeof err === "object" && err && "message" in err ? String(err.message) : String(_nullishCoalesce(err, () => ( "")));
|
|
1581
1632
|
setErrorMessage(raw || "Wallet connection modal closed");
|
|
@@ -1605,8 +1656,8 @@ var TonPayButton = ({
|
|
|
1605
1656
|
[fetchOnRampLink, amount, currency, address, userIp]
|
|
1606
1657
|
);
|
|
1607
1658
|
const presetConfig = preset ? PRESETS[preset] : null;
|
|
1608
|
-
const finalBgColor = _nullishCoalesce(_nullishCoalesce(bgColor, () => ( _optionalChain([presetConfig, 'optionalAccess',
|
|
1609
|
-
const finalTextColor = _nullishCoalesce(_nullishCoalesce(textColor, () => ( _optionalChain([presetConfig, 'optionalAccess',
|
|
1659
|
+
const finalBgColor = _nullishCoalesce(_nullishCoalesce(bgColor, () => ( _optionalChain([presetConfig, 'optionalAccess', _25 => _25.bgColor]))), () => ( PRESETS.default.bgColor));
|
|
1660
|
+
const finalTextColor = _nullishCoalesce(_nullishCoalesce(textColor, () => ( _optionalChain([presetConfig, 'optionalAccess', _26 => _26.textColor]))), () => ( PRESETS.default.textColor));
|
|
1610
1661
|
const cssVars = {
|
|
1611
1662
|
"--tp-bg": finalBgColor,
|
|
1612
1663
|
"--tp-text": finalTextColor,
|
|
@@ -1686,9 +1737,9 @@ var TonPayButton = ({
|
|
|
1686
1737
|
showMenu && showDropdown && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "tp-menu", children: [
|
|
1687
1738
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "tp-menu-arrow" }),
|
|
1688
1739
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "tp-menu-address", children: [
|
|
1689
|
-
_optionalChain([address, 'optionalAccess',
|
|
1740
|
+
_optionalChain([address, 'optionalAccess', _27 => _27.slice, 'call', _28 => _28(0, 4)]),
|
|
1690
1741
|
"...",
|
|
1691
|
-
_optionalChain([address, 'optionalAccess',
|
|
1742
|
+
_optionalChain([address, 'optionalAccess', _29 => _29.slice, 'call', _30 => _30(-4)])
|
|
1692
1743
|
] }),
|
|
1693
1744
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1694
1745
|
"button",
|
|
@@ -1749,7 +1800,7 @@ function useTonPay() {
|
|
|
1749
1800
|
}
|
|
1750
1801
|
modal.open();
|
|
1751
1802
|
const unsubscribe = tonConnectUI.onStatusChange((wallet) => {
|
|
1752
|
-
if (_optionalChain([wallet, 'optionalAccess',
|
|
1803
|
+
if (_optionalChain([wallet, 'optionalAccess', _31 => _31.account])) {
|
|
1753
1804
|
unsubscribe();
|
|
1754
1805
|
unsubscribeModal();
|
|
1755
1806
|
resolve(wallet.account.address);
|
|
@@ -1781,7 +1832,7 @@ function useTonPay() {
|
|
|
1781
1832
|
from: walletAddress
|
|
1782
1833
|
},
|
|
1783
1834
|
{
|
|
1784
|
-
onRequestSent: _optionalChain([options, 'optionalAccess',
|
|
1835
|
+
onRequestSent: _optionalChain([options, 'optionalAccess', _32 => _32.onRequestSent])
|
|
1785
1836
|
}
|
|
1786
1837
|
);
|
|
1787
1838
|
return { ...messageResult, txResult };
|
|
@@ -1791,1704 +1842,6 @@ function useTonPay() {
|
|
|
1791
1842
|
return { pay, address };
|
|
1792
1843
|
}
|
|
1793
1844
|
|
|
1794
|
-
// src/signless/context.tsx
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
// src/signless/crypto/ed25519.ts
|
|
1799
|
-
var ALGORITHM = "Ed25519";
|
|
1800
|
-
function arrayBufferToUint8Array(buffer) {
|
|
1801
|
-
return new Uint8Array(buffer);
|
|
1802
|
-
}
|
|
1803
|
-
async function generateKeyPair() {
|
|
1804
|
-
const keyPair = await crypto.subtle.generateKey(ALGORITHM, true, [
|
|
1805
|
-
"sign",
|
|
1806
|
-
"verify"
|
|
1807
|
-
]);
|
|
1808
|
-
const privateKeyBuffer = await crypto.subtle.exportKey(
|
|
1809
|
-
"pkcs8",
|
|
1810
|
-
keyPair.privateKey
|
|
1811
|
-
);
|
|
1812
|
-
const publicKeyBuffer = await crypto.subtle.exportKey(
|
|
1813
|
-
"spki",
|
|
1814
|
-
keyPair.publicKey
|
|
1815
|
-
);
|
|
1816
|
-
return {
|
|
1817
|
-
publicKey: arrayBufferToUint8Array(publicKeyBuffer),
|
|
1818
|
-
privateKey: arrayBufferToUint8Array(privateKeyBuffer)
|
|
1819
|
-
};
|
|
1820
|
-
}
|
|
1821
|
-
async function signMessage(privateKey, message) {
|
|
1822
|
-
const importedKey = await crypto.subtle.importKey(
|
|
1823
|
-
"pkcs8",
|
|
1824
|
-
privateKey,
|
|
1825
|
-
ALGORITHM,
|
|
1826
|
-
false,
|
|
1827
|
-
["sign"]
|
|
1828
|
-
);
|
|
1829
|
-
const signature = await crypto.subtle.sign(ALGORITHM, importedKey, message);
|
|
1830
|
-
return arrayBufferToUint8Array(signature);
|
|
1831
|
-
}
|
|
1832
|
-
async function verifySignlessSignature(publicKey, message, signature) {
|
|
1833
|
-
const importedKey = await crypto.subtle.importKey(
|
|
1834
|
-
"spki",
|
|
1835
|
-
publicKey,
|
|
1836
|
-
ALGORITHM,
|
|
1837
|
-
false,
|
|
1838
|
-
["verify"]
|
|
1839
|
-
);
|
|
1840
|
-
return crypto.subtle.verify(ALGORITHM, importedKey, signature, message);
|
|
1841
|
-
}
|
|
1842
|
-
|
|
1843
|
-
// src/signless/crypto/encryption.ts
|
|
1844
|
-
var PBKDF2_ITERATIONS = 1e5;
|
|
1845
|
-
var SALT_LENGTH = 16;
|
|
1846
|
-
var IV_LENGTH = 12;
|
|
1847
|
-
var KEY_LENGTH = 256;
|
|
1848
|
-
function arrayBufferToBase64(buffer) {
|
|
1849
|
-
const bytes = new Uint8Array(buffer);
|
|
1850
|
-
let binary = "";
|
|
1851
|
-
for (let i = 0; i < bytes.byteLength; i++) {
|
|
1852
|
-
binary += String.fromCharCode(bytes[i]);
|
|
1853
|
-
}
|
|
1854
|
-
return btoa(binary);
|
|
1855
|
-
}
|
|
1856
|
-
function base64ToArrayBuffer(base64) {
|
|
1857
|
-
const binary = atob(base64);
|
|
1858
|
-
const bytes = new Uint8Array(binary.length);
|
|
1859
|
-
for (let i = 0; i < binary.length; i++) {
|
|
1860
|
-
bytes[i] = binary.charCodeAt(i);
|
|
1861
|
-
}
|
|
1862
|
-
return bytes.buffer;
|
|
1863
|
-
}
|
|
1864
|
-
function generateSalt() {
|
|
1865
|
-
return crypto.getRandomValues(new Uint8Array(SALT_LENGTH));
|
|
1866
|
-
}
|
|
1867
|
-
function generateIv() {
|
|
1868
|
-
return crypto.getRandomValues(new Uint8Array(IV_LENGTH));
|
|
1869
|
-
}
|
|
1870
|
-
async function deriveKeyFromPin(pin, salt) {
|
|
1871
|
-
const encoder = new TextEncoder();
|
|
1872
|
-
const pinData = encoder.encode(pin);
|
|
1873
|
-
const baseKey = await crypto.subtle.importKey(
|
|
1874
|
-
"raw",
|
|
1875
|
-
pinData,
|
|
1876
|
-
"PBKDF2",
|
|
1877
|
-
false,
|
|
1878
|
-
["deriveKey"]
|
|
1879
|
-
);
|
|
1880
|
-
return crypto.subtle.deriveKey(
|
|
1881
|
-
{
|
|
1882
|
-
name: "PBKDF2",
|
|
1883
|
-
salt,
|
|
1884
|
-
iterations: PBKDF2_ITERATIONS,
|
|
1885
|
-
hash: "SHA-256"
|
|
1886
|
-
},
|
|
1887
|
-
baseKey,
|
|
1888
|
-
{ name: "AES-GCM", length: KEY_LENGTH },
|
|
1889
|
-
false,
|
|
1890
|
-
["encrypt", "decrypt"]
|
|
1891
|
-
);
|
|
1892
|
-
}
|
|
1893
|
-
async function encryptPrivateKey(privateKey, publicKey, pin) {
|
|
1894
|
-
const salt = generateSalt();
|
|
1895
|
-
const iv = generateIv();
|
|
1896
|
-
const derivedKey = await deriveKeyFromPin(pin, salt);
|
|
1897
|
-
const encryptedBuffer = await crypto.subtle.encrypt(
|
|
1898
|
-
{ name: "AES-GCM", iv },
|
|
1899
|
-
derivedKey,
|
|
1900
|
-
privateKey
|
|
1901
|
-
);
|
|
1902
|
-
return {
|
|
1903
|
-
salt: arrayBufferToBase64(salt.buffer),
|
|
1904
|
-
iv: arrayBufferToBase64(iv.buffer),
|
|
1905
|
-
encryptedBlob: arrayBufferToBase64(encryptedBuffer),
|
|
1906
|
-
publicKey: arrayBufferToBase64(publicKey.buffer),
|
|
1907
|
-
version: 1
|
|
1908
|
-
};
|
|
1909
|
-
}
|
|
1910
|
-
async function decryptPrivateKey(vault, pin) {
|
|
1911
|
-
const salt = new Uint8Array(base64ToArrayBuffer(vault.salt));
|
|
1912
|
-
const iv = new Uint8Array(base64ToArrayBuffer(vault.iv));
|
|
1913
|
-
const encryptedBlob = base64ToArrayBuffer(vault.encryptedBlob);
|
|
1914
|
-
const derivedKey = await deriveKeyFromPin(pin, salt);
|
|
1915
|
-
try {
|
|
1916
|
-
const decryptedBuffer = await crypto.subtle.decrypt(
|
|
1917
|
-
{ name: "AES-GCM", iv },
|
|
1918
|
-
derivedKey,
|
|
1919
|
-
encryptedBlob
|
|
1920
|
-
);
|
|
1921
|
-
return new Uint8Array(decryptedBuffer);
|
|
1922
|
-
} catch (e4) {
|
|
1923
|
-
throw new Error("Invalid PIN or corrupted vault");
|
|
1924
|
-
}
|
|
1925
|
-
}
|
|
1926
|
-
|
|
1927
|
-
// src/signless/crypto/webauthn.ts
|
|
1928
|
-
var WEBAUTHN_RP_NAME = "TON Pay";
|
|
1929
|
-
var WEBAUTHN_RP_ID_FALLBACK = "tonpay.io";
|
|
1930
|
-
var STATIC_CHALLENGE = new Uint8Array([
|
|
1931
|
-
1,
|
|
1932
|
-
2,
|
|
1933
|
-
3,
|
|
1934
|
-
4,
|
|
1935
|
-
5,
|
|
1936
|
-
6,
|
|
1937
|
-
7,
|
|
1938
|
-
8,
|
|
1939
|
-
9,
|
|
1940
|
-
10,
|
|
1941
|
-
11,
|
|
1942
|
-
12,
|
|
1943
|
-
13,
|
|
1944
|
-
14,
|
|
1945
|
-
15,
|
|
1946
|
-
16
|
|
1947
|
-
]);
|
|
1948
|
-
function arrayBufferToBase64Url(buffer) {
|
|
1949
|
-
const bytes = new Uint8Array(buffer);
|
|
1950
|
-
let binary = "";
|
|
1951
|
-
for (let i = 0; i < bytes.byteLength; i++) {
|
|
1952
|
-
binary += String.fromCharCode(bytes[i]);
|
|
1953
|
-
}
|
|
1954
|
-
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
1955
|
-
}
|
|
1956
|
-
function base64UrlToArrayBuffer(base64Url) {
|
|
1957
|
-
const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
|
|
1958
|
-
const padding = "=".repeat((4 - base64.length % 4) % 4);
|
|
1959
|
-
const binary = atob(base64 + padding);
|
|
1960
|
-
const bytes = new Uint8Array(binary.length);
|
|
1961
|
-
for (let i = 0; i < binary.length; i++) {
|
|
1962
|
-
bytes[i] = binary.charCodeAt(i);
|
|
1963
|
-
}
|
|
1964
|
-
return bytes.buffer;
|
|
1965
|
-
}
|
|
1966
|
-
function isWebAuthnSupported() {
|
|
1967
|
-
return typeof window !== "undefined" && !!window.PublicKeyCredential && typeof window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable === "function";
|
|
1968
|
-
}
|
|
1969
|
-
function getRpId() {
|
|
1970
|
-
if (typeof window === "undefined") return WEBAUTHN_RP_ID_FALLBACK;
|
|
1971
|
-
return window.location.hostname || WEBAUTHN_RP_ID_FALLBACK;
|
|
1972
|
-
}
|
|
1973
|
-
async function createWebAuthnCredential(walletAddress) {
|
|
1974
|
-
if (!isWebAuthnSupported()) {
|
|
1975
|
-
throw new Error("WebAuthn is not supported in this browser");
|
|
1976
|
-
}
|
|
1977
|
-
const userId = new TextEncoder().encode(walletAddress);
|
|
1978
|
-
const createOptions = {
|
|
1979
|
-
challenge: STATIC_CHALLENGE,
|
|
1980
|
-
rp: {
|
|
1981
|
-
name: WEBAUTHN_RP_NAME,
|
|
1982
|
-
id: getRpId()
|
|
1983
|
-
},
|
|
1984
|
-
user: {
|
|
1985
|
-
id: userId,
|
|
1986
|
-
name: `TON Pay - ${walletAddress.slice(0, 8)}...`,
|
|
1987
|
-
displayName: "TON Pay Signless"
|
|
1988
|
-
},
|
|
1989
|
-
pubKeyCredParams: [
|
|
1990
|
-
{ type: "public-key", alg: -7 },
|
|
1991
|
-
{ type: "public-key", alg: -257 }
|
|
1992
|
-
],
|
|
1993
|
-
timeout: 6e4,
|
|
1994
|
-
authenticatorSelection: {
|
|
1995
|
-
authenticatorAttachment: "platform",
|
|
1996
|
-
userVerification: "required",
|
|
1997
|
-
residentKey: "preferred"
|
|
1998
|
-
},
|
|
1999
|
-
attestation: "none"
|
|
2000
|
-
};
|
|
2001
|
-
const credential = await navigator.credentials.create({
|
|
2002
|
-
publicKey: createOptions
|
|
2003
|
-
});
|
|
2004
|
-
if (!credential) {
|
|
2005
|
-
throw new Error("Failed to create WebAuthn credential");
|
|
2006
|
-
}
|
|
2007
|
-
const response = credential.response;
|
|
2008
|
-
return {
|
|
2009
|
-
credentialId: arrayBufferToBase64Url(credential.rawId),
|
|
2010
|
-
publicKey: arrayBufferToBase64Url(_nullishCoalesce(_optionalChain([response, 'access', _37 => _37.getPublicKey, 'optionalCall', _38 => _38()]), () => ( new ArrayBuffer(0)))),
|
|
2011
|
-
transports: _optionalChain([response, 'access', _39 => _39.getTransports, 'optionalCall', _40 => _40()])
|
|
2012
|
-
};
|
|
2013
|
-
}
|
|
2014
|
-
async function getWebAuthnCredential(credentialInfo) {
|
|
2015
|
-
if (!isWebAuthnSupported()) {
|
|
2016
|
-
throw new Error("WebAuthn is not supported in this browser");
|
|
2017
|
-
}
|
|
2018
|
-
const credentialId = base64UrlToArrayBuffer(credentialInfo.credentialId);
|
|
2019
|
-
const getOptions = {
|
|
2020
|
-
challenge: STATIC_CHALLENGE,
|
|
2021
|
-
rpId: getRpId(),
|
|
2022
|
-
timeout: 6e4,
|
|
2023
|
-
userVerification: "required",
|
|
2024
|
-
allowCredentials: [
|
|
2025
|
-
{
|
|
2026
|
-
type: "public-key",
|
|
2027
|
-
id: credentialId,
|
|
2028
|
-
transports: credentialInfo.transports
|
|
2029
|
-
}
|
|
2030
|
-
]
|
|
2031
|
-
};
|
|
2032
|
-
const assertion = await navigator.credentials.get({
|
|
2033
|
-
publicKey: getOptions
|
|
2034
|
-
});
|
|
2035
|
-
if (!assertion) {
|
|
2036
|
-
throw new Error("WebAuthn authentication failed");
|
|
2037
|
-
}
|
|
2038
|
-
const response = assertion.response;
|
|
2039
|
-
return response.signature;
|
|
2040
|
-
}
|
|
2041
|
-
|
|
2042
|
-
// src/signless/storage.ts
|
|
2043
|
-
var DEFAULT_STORAGE_KEY = "tonpay_signless_vault";
|
|
2044
|
-
var SignlessStorage = class {
|
|
2045
|
-
|
|
2046
|
-
constructor(storageKey = DEFAULT_STORAGE_KEY) {
|
|
2047
|
-
this.storageKey = storageKey;
|
|
2048
|
-
}
|
|
2049
|
-
getStorage() {
|
|
2050
|
-
if (typeof window === "undefined") return null;
|
|
2051
|
-
return window.localStorage;
|
|
2052
|
-
}
|
|
2053
|
-
async saveVault(walletAddress, vault, authMethod, webauthnCredential) {
|
|
2054
|
-
const storage = this.getStorage();
|
|
2055
|
-
if (!storage) return;
|
|
2056
|
-
const data = {
|
|
2057
|
-
vault,
|
|
2058
|
-
authMethod,
|
|
2059
|
-
walletAddress,
|
|
2060
|
-
webauthnCredential,
|
|
2061
|
-
createdAt: Date.now(),
|
|
2062
|
-
updatedAt: Date.now()
|
|
2063
|
-
};
|
|
2064
|
-
const key = this.getStorageKeyForWallet(walletAddress);
|
|
2065
|
-
storage.setItem(key, JSON.stringify(data));
|
|
2066
|
-
}
|
|
2067
|
-
async loadVault(walletAddress) {
|
|
2068
|
-
const storage = this.getStorage();
|
|
2069
|
-
if (!storage) return null;
|
|
2070
|
-
const key = this.getStorageKeyForWallet(walletAddress);
|
|
2071
|
-
const data = storage.getItem(key);
|
|
2072
|
-
if (!data) return null;
|
|
2073
|
-
try {
|
|
2074
|
-
return JSON.parse(data);
|
|
2075
|
-
} catch (e5) {
|
|
2076
|
-
return null;
|
|
2077
|
-
}
|
|
2078
|
-
}
|
|
2079
|
-
async deleteVault(walletAddress) {
|
|
2080
|
-
const storage = this.getStorage();
|
|
2081
|
-
if (!storage) return;
|
|
2082
|
-
const key = this.getStorageKeyForWallet(walletAddress);
|
|
2083
|
-
storage.removeItem(key);
|
|
2084
|
-
}
|
|
2085
|
-
async hasVault(walletAddress) {
|
|
2086
|
-
const vault = await this.loadVault(walletAddress);
|
|
2087
|
-
return vault !== null;
|
|
2088
|
-
}
|
|
2089
|
-
async updateVaultTimestamp(walletAddress) {
|
|
2090
|
-
const storage = this.getStorage();
|
|
2091
|
-
if (!storage) return;
|
|
2092
|
-
const vault = await this.loadVault(walletAddress);
|
|
2093
|
-
if (!vault) return;
|
|
2094
|
-
vault.updatedAt = Date.now();
|
|
2095
|
-
const key = this.getStorageKeyForWallet(walletAddress);
|
|
2096
|
-
storage.setItem(key, JSON.stringify(vault));
|
|
2097
|
-
}
|
|
2098
|
-
async getAllWalletsWithVaults() {
|
|
2099
|
-
const storage = this.getStorage();
|
|
2100
|
-
if (!storage) return [];
|
|
2101
|
-
const wallets = [];
|
|
2102
|
-
const prefix = `${this.storageKey}_`;
|
|
2103
|
-
for (let i = 0; i < storage.length; i++) {
|
|
2104
|
-
const key = storage.key(i);
|
|
2105
|
-
if (_optionalChain([key, 'optionalAccess', _41 => _41.startsWith, 'call', _42 => _42(prefix)])) {
|
|
2106
|
-
const walletAddress = key.slice(prefix.length);
|
|
2107
|
-
wallets.push(walletAddress);
|
|
2108
|
-
}
|
|
2109
|
-
}
|
|
2110
|
-
return wallets;
|
|
2111
|
-
}
|
|
2112
|
-
getStorageKeyForWallet(walletAddress) {
|
|
2113
|
-
return `${this.storageKey}_${walletAddress}`;
|
|
2114
|
-
}
|
|
2115
|
-
};
|
|
2116
|
-
var signlessStorage = new SignlessStorage();
|
|
2117
|
-
|
|
2118
|
-
// src/signless/context.tsx
|
|
2119
|
-
|
|
2120
|
-
var DEFAULT_CONFIG = {
|
|
2121
|
-
enabled: false,
|
|
2122
|
-
authMethod: "none",
|
|
2123
|
-
autoLockTimeout: 5 * 60 * 1e3,
|
|
2124
|
-
storageKey: "tonpay_signless_vault"
|
|
2125
|
-
};
|
|
2126
|
-
var DEFAULT_STATE = {
|
|
2127
|
-
status: "disabled",
|
|
2128
|
-
isEnabled: false,
|
|
2129
|
-
isSetup: false,
|
|
2130
|
-
isUnlocked: false,
|
|
2131
|
-
authMethod: "none",
|
|
2132
|
-
publicKey: null,
|
|
2133
|
-
walletAddress: null
|
|
2134
|
-
};
|
|
2135
|
-
var SignlessContext = React9.createContext(null);
|
|
2136
|
-
function SignlessProvider({ children, config }) {
|
|
2137
|
-
const walletAddress = _uireact.useTonAddress.call(void 0, true);
|
|
2138
|
-
const [state, setState] = React9.useState(DEFAULT_STATE);
|
|
2139
|
-
const [currentConfig, setCurrentConfig] = React9.useState({
|
|
2140
|
-
...DEFAULT_CONFIG,
|
|
2141
|
-
...config
|
|
2142
|
-
});
|
|
2143
|
-
const storageRef = React9.useRef(
|
|
2144
|
-
new SignlessStorage(currentConfig.storageKey)
|
|
2145
|
-
);
|
|
2146
|
-
const privateKeyRef = React9.useRef(null);
|
|
2147
|
-
const lockTimeoutRef = React9.useRef(
|
|
2148
|
-
null
|
|
2149
|
-
);
|
|
2150
|
-
const webauthnCredentialRef = React9.useRef(
|
|
2151
|
-
null
|
|
2152
|
-
);
|
|
2153
|
-
const [isBiometricAvailable, setIsBiometricAvailable] = React9.useState(false);
|
|
2154
|
-
React9.useEffect(() => {
|
|
2155
|
-
async function checkBiometric() {
|
|
2156
|
-
if (!isWebAuthnSupported()) {
|
|
2157
|
-
setIsBiometricAvailable(false);
|
|
2158
|
-
return;
|
|
2159
|
-
}
|
|
2160
|
-
try {
|
|
2161
|
-
const available = await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();
|
|
2162
|
-
setIsBiometricAvailable(available);
|
|
2163
|
-
} catch (e6) {
|
|
2164
|
-
setIsBiometricAvailable(false);
|
|
2165
|
-
}
|
|
2166
|
-
}
|
|
2167
|
-
checkBiometric();
|
|
2168
|
-
}, []);
|
|
2169
|
-
React9.useEffect(() => {
|
|
2170
|
-
async function loadVaultState() {
|
|
2171
|
-
if (!walletAddress) {
|
|
2172
|
-
setState({ ...DEFAULT_STATE });
|
|
2173
|
-
return;
|
|
2174
|
-
}
|
|
2175
|
-
if (!currentConfig.enabled) {
|
|
2176
|
-
setState({
|
|
2177
|
-
...DEFAULT_STATE,
|
|
2178
|
-
status: "disabled",
|
|
2179
|
-
walletAddress
|
|
2180
|
-
});
|
|
2181
|
-
return;
|
|
2182
|
-
}
|
|
2183
|
-
const vaultData = await storageRef.current.loadVault(walletAddress);
|
|
2184
|
-
if (!vaultData) {
|
|
2185
|
-
setState({
|
|
2186
|
-
...DEFAULT_STATE,
|
|
2187
|
-
status: "not_setup",
|
|
2188
|
-
isEnabled: true,
|
|
2189
|
-
walletAddress
|
|
2190
|
-
});
|
|
2191
|
-
return;
|
|
2192
|
-
}
|
|
2193
|
-
webauthnCredentialRef.current = vaultData.webauthnCredential || null;
|
|
2194
|
-
setState({
|
|
2195
|
-
status: "locked",
|
|
2196
|
-
isEnabled: true,
|
|
2197
|
-
isSetup: true,
|
|
2198
|
-
isUnlocked: false,
|
|
2199
|
-
authMethod: vaultData.authMethod,
|
|
2200
|
-
publicKey: vaultData.vault.publicKey,
|
|
2201
|
-
walletAddress
|
|
2202
|
-
});
|
|
2203
|
-
}
|
|
2204
|
-
loadVaultState();
|
|
2205
|
-
}, [walletAddress, currentConfig.enabled]);
|
|
2206
|
-
const resetLockTimeout = React9.useCallback(() => {
|
|
2207
|
-
if (lockTimeoutRef.current) {
|
|
2208
|
-
clearTimeout(lockTimeoutRef.current);
|
|
2209
|
-
}
|
|
2210
|
-
if (currentConfig.autoLockTimeout && currentConfig.autoLockTimeout > 0) {
|
|
2211
|
-
lockTimeoutRef.current = setTimeout(() => {
|
|
2212
|
-
if (privateKeyRef.current) {
|
|
2213
|
-
privateKeyRef.current.fill(0);
|
|
2214
|
-
privateKeyRef.current = null;
|
|
2215
|
-
}
|
|
2216
|
-
setState((prev) => ({
|
|
2217
|
-
...prev,
|
|
2218
|
-
status: "locked",
|
|
2219
|
-
isUnlocked: false
|
|
2220
|
-
}));
|
|
2221
|
-
}, currentConfig.autoLockTimeout);
|
|
2222
|
-
}
|
|
2223
|
-
}, [currentConfig.autoLockTimeout]);
|
|
2224
|
-
const setup = React9.useCallback(
|
|
2225
|
-
async (params) => {
|
|
2226
|
-
if (!walletAddress) {
|
|
2227
|
-
throw new Error("Wallet not connected");
|
|
2228
|
-
}
|
|
2229
|
-
setState((prev) => ({ ...prev, status: "setting_up" }));
|
|
2230
|
-
try {
|
|
2231
|
-
const keyPair = await generateKeyPair();
|
|
2232
|
-
let webauthnCredential;
|
|
2233
|
-
if (params.authMethod === "biometric") {
|
|
2234
|
-
webauthnCredential = await createWebAuthnCredential(walletAddress);
|
|
2235
|
-
webauthnCredentialRef.current = webauthnCredential;
|
|
2236
|
-
const signature = await getWebAuthnCredential(webauthnCredential);
|
|
2237
|
-
const signatureBytes = new Uint8Array(signature);
|
|
2238
|
-
const biometricPin = Array.from(signatureBytes.slice(0, 32)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
2239
|
-
const vault = await encryptPrivateKey(
|
|
2240
|
-
keyPair.privateKey,
|
|
2241
|
-
keyPair.publicKey,
|
|
2242
|
-
biometricPin
|
|
2243
|
-
);
|
|
2244
|
-
await storageRef.current.saveVault(
|
|
2245
|
-
walletAddress,
|
|
2246
|
-
vault,
|
|
2247
|
-
"biometric",
|
|
2248
|
-
webauthnCredential
|
|
2249
|
-
);
|
|
2250
|
-
privateKeyRef.current = keyPair.privateKey;
|
|
2251
|
-
} else if (params.authMethod === "pin") {
|
|
2252
|
-
if (!params.pin) {
|
|
2253
|
-
throw new Error("PIN is required for PIN authentication");
|
|
2254
|
-
}
|
|
2255
|
-
const vault = await encryptPrivateKey(
|
|
2256
|
-
keyPair.privateKey,
|
|
2257
|
-
keyPair.publicKey,
|
|
2258
|
-
params.pin
|
|
2259
|
-
);
|
|
2260
|
-
await storageRef.current.saveVault(walletAddress, vault, "pin");
|
|
2261
|
-
privateKeyRef.current = keyPair.privateKey;
|
|
2262
|
-
} else {
|
|
2263
|
-
throw new Error("Invalid authentication method");
|
|
2264
|
-
}
|
|
2265
|
-
setState({
|
|
2266
|
-
status: "unlocked",
|
|
2267
|
-
isEnabled: true,
|
|
2268
|
-
isSetup: true,
|
|
2269
|
-
isUnlocked: true,
|
|
2270
|
-
authMethod: params.authMethod,
|
|
2271
|
-
publicKey: arrayBufferToBase642(keyPair.publicKey.buffer),
|
|
2272
|
-
walletAddress
|
|
2273
|
-
});
|
|
2274
|
-
resetLockTimeout();
|
|
2275
|
-
} catch (error) {
|
|
2276
|
-
setState((prev) => ({
|
|
2277
|
-
...prev,
|
|
2278
|
-
status: prev.isSetup ? "locked" : "not_setup"
|
|
2279
|
-
}));
|
|
2280
|
-
throw error;
|
|
2281
|
-
}
|
|
2282
|
-
},
|
|
2283
|
-
[walletAddress, resetLockTimeout]
|
|
2284
|
-
);
|
|
2285
|
-
const unlock = React9.useCallback(
|
|
2286
|
-
async (params) => {
|
|
2287
|
-
if (!walletAddress) {
|
|
2288
|
-
throw new Error("Wallet not connected");
|
|
2289
|
-
}
|
|
2290
|
-
const vaultData = await storageRef.current.loadVault(walletAddress);
|
|
2291
|
-
if (!vaultData) {
|
|
2292
|
-
throw new Error("No signless vault found");
|
|
2293
|
-
}
|
|
2294
|
-
try {
|
|
2295
|
-
let pin;
|
|
2296
|
-
if (vaultData.authMethod === "biometric") {
|
|
2297
|
-
if (!vaultData.webauthnCredential) {
|
|
2298
|
-
throw new Error("WebAuthn credential not found");
|
|
2299
|
-
}
|
|
2300
|
-
const signature = await getWebAuthnCredential(
|
|
2301
|
-
vaultData.webauthnCredential
|
|
2302
|
-
);
|
|
2303
|
-
const signatureBytes = new Uint8Array(signature);
|
|
2304
|
-
pin = Array.from(signatureBytes.slice(0, 32)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
2305
|
-
} else if (vaultData.authMethod === "pin") {
|
|
2306
|
-
if (!params.pin) {
|
|
2307
|
-
throw new Error("PIN is required");
|
|
2308
|
-
}
|
|
2309
|
-
pin = params.pin;
|
|
2310
|
-
} else {
|
|
2311
|
-
throw new Error("Invalid authentication method");
|
|
2312
|
-
}
|
|
2313
|
-
const privateKey = await decryptPrivateKey(vaultData.vault, pin);
|
|
2314
|
-
privateKeyRef.current = privateKey;
|
|
2315
|
-
setState((prev) => ({
|
|
2316
|
-
...prev,
|
|
2317
|
-
status: "unlocked",
|
|
2318
|
-
isUnlocked: true
|
|
2319
|
-
}));
|
|
2320
|
-
resetLockTimeout();
|
|
2321
|
-
} catch (error) {
|
|
2322
|
-
throw new Error("Failed to unlock vault");
|
|
2323
|
-
}
|
|
2324
|
-
},
|
|
2325
|
-
[walletAddress, resetLockTimeout]
|
|
2326
|
-
);
|
|
2327
|
-
const lock = React9.useCallback(() => {
|
|
2328
|
-
if (lockTimeoutRef.current) {
|
|
2329
|
-
clearTimeout(lockTimeoutRef.current);
|
|
2330
|
-
}
|
|
2331
|
-
if (privateKeyRef.current) {
|
|
2332
|
-
privateKeyRef.current.fill(0);
|
|
2333
|
-
privateKeyRef.current = null;
|
|
2334
|
-
}
|
|
2335
|
-
setState((prev) => ({
|
|
2336
|
-
...prev,
|
|
2337
|
-
status: "locked",
|
|
2338
|
-
isUnlocked: false
|
|
2339
|
-
}));
|
|
2340
|
-
}, []);
|
|
2341
|
-
const reset = React9.useCallback(async () => {
|
|
2342
|
-
if (!walletAddress) return;
|
|
2343
|
-
if (lockTimeoutRef.current) {
|
|
2344
|
-
clearTimeout(lockTimeoutRef.current);
|
|
2345
|
-
}
|
|
2346
|
-
if (privateKeyRef.current) {
|
|
2347
|
-
privateKeyRef.current.fill(0);
|
|
2348
|
-
privateKeyRef.current = null;
|
|
2349
|
-
}
|
|
2350
|
-
webauthnCredentialRef.current = null;
|
|
2351
|
-
await storageRef.current.deleteVault(walletAddress);
|
|
2352
|
-
setState({
|
|
2353
|
-
...DEFAULT_STATE,
|
|
2354
|
-
status: currentConfig.enabled ? "not_setup" : "disabled",
|
|
2355
|
-
isEnabled: currentConfig.enabled,
|
|
2356
|
-
walletAddress
|
|
2357
|
-
});
|
|
2358
|
-
}, [walletAddress, currentConfig.enabled]);
|
|
2359
|
-
const signPayload = React9.useCallback(
|
|
2360
|
-
async (params) => {
|
|
2361
|
-
if (!privateKeyRef.current) {
|
|
2362
|
-
throw new Error("Signless is locked. Please unlock first.");
|
|
2363
|
-
}
|
|
2364
|
-
if (!state.publicKey) {
|
|
2365
|
-
throw new Error("Public key not available");
|
|
2366
|
-
}
|
|
2367
|
-
resetLockTimeout();
|
|
2368
|
-
const reference = params.reference || generateReference();
|
|
2369
|
-
const validUntil = params.validUntil || Math.floor(Date.now() / 1e3) + 300;
|
|
2370
|
-
const payloadData = {
|
|
2371
|
-
recipient: params.recipient,
|
|
2372
|
-
amount: params.amount,
|
|
2373
|
-
token: params.token || "TON",
|
|
2374
|
-
payload: params.payload || "",
|
|
2375
|
-
reference,
|
|
2376
|
-
validUntil
|
|
2377
|
-
};
|
|
2378
|
-
const encoder = new TextEncoder();
|
|
2379
|
-
const payloadBytes = encoder.encode(JSON.stringify(payloadData));
|
|
2380
|
-
const signature = await signMessage(privateKeyRef.current, payloadBytes);
|
|
2381
|
-
return {
|
|
2382
|
-
payload: payloadBytes,
|
|
2383
|
-
signature,
|
|
2384
|
-
publicKey: state.publicKey,
|
|
2385
|
-
reference,
|
|
2386
|
-
validUntil
|
|
2387
|
-
};
|
|
2388
|
-
},
|
|
2389
|
-
[state.publicKey, resetLockTimeout]
|
|
2390
|
-
);
|
|
2391
|
-
const updateConfig = React9.useCallback(
|
|
2392
|
-
(newConfig) => {
|
|
2393
|
-
setCurrentConfig((prev) => ({ ...prev, ...newConfig }));
|
|
2394
|
-
},
|
|
2395
|
-
[]
|
|
2396
|
-
);
|
|
2397
|
-
React9.useEffect(() => {
|
|
2398
|
-
return () => {
|
|
2399
|
-
if (lockTimeoutRef.current) {
|
|
2400
|
-
clearTimeout(lockTimeoutRef.current);
|
|
2401
|
-
}
|
|
2402
|
-
if (privateKeyRef.current) {
|
|
2403
|
-
privateKeyRef.current.fill(0);
|
|
2404
|
-
privateKeyRef.current = null;
|
|
2405
|
-
}
|
|
2406
|
-
};
|
|
2407
|
-
}, []);
|
|
2408
|
-
const contextValue = {
|
|
2409
|
-
state,
|
|
2410
|
-
config: currentConfig,
|
|
2411
|
-
setup,
|
|
2412
|
-
unlock,
|
|
2413
|
-
lock,
|
|
2414
|
-
reset,
|
|
2415
|
-
signPayload,
|
|
2416
|
-
updateConfig,
|
|
2417
|
-
isBiometricAvailable
|
|
2418
|
-
};
|
|
2419
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SignlessContext.Provider, { value: contextValue, children });
|
|
2420
|
-
}
|
|
2421
|
-
function useSignless() {
|
|
2422
|
-
const context = React9.useContext(SignlessContext);
|
|
2423
|
-
if (!context) {
|
|
2424
|
-
throw new Error("useSignless must be used within a SignlessProvider");
|
|
2425
|
-
}
|
|
2426
|
-
return context;
|
|
2427
|
-
}
|
|
2428
|
-
function generateReference() {
|
|
2429
|
-
const bytes = new Uint8Array(16);
|
|
2430
|
-
crypto.getRandomValues(bytes);
|
|
2431
|
-
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
2432
|
-
}
|
|
2433
|
-
function arrayBufferToBase642(buffer) {
|
|
2434
|
-
const bytes = new Uint8Array(buffer);
|
|
2435
|
-
let binary = "";
|
|
2436
|
-
for (let i = 0; i < bytes.byteLength; i++) {
|
|
2437
|
-
binary += String.fromCharCode(bytes[i]);
|
|
2438
|
-
}
|
|
2439
|
-
return btoa(binary);
|
|
2440
|
-
}
|
|
2441
|
-
|
|
2442
|
-
// src/signless/hooks/useTonPaySignless.ts
|
|
2443
|
-
|
|
2444
|
-
function useTonPaySignless() {
|
|
2445
|
-
const { pay, address } = useTonPay();
|
|
2446
|
-
const signlessContext = useSignless();
|
|
2447
|
-
const {
|
|
2448
|
-
state,
|
|
2449
|
-
config,
|
|
2450
|
-
setup,
|
|
2451
|
-
unlock,
|
|
2452
|
-
lock,
|
|
2453
|
-
reset,
|
|
2454
|
-
signPayload,
|
|
2455
|
-
updateConfig,
|
|
2456
|
-
isBiometricAvailable
|
|
2457
|
-
} = signlessContext;
|
|
2458
|
-
const paySignless = React10.useCallback(
|
|
2459
|
-
async (params) => {
|
|
2460
|
-
if (!config.enabled) {
|
|
2461
|
-
throw new Error("Signless is not enabled");
|
|
2462
|
-
}
|
|
2463
|
-
if (!state.isSetup) {
|
|
2464
|
-
throw new Error("Signless is not set up. Please complete setup first.");
|
|
2465
|
-
}
|
|
2466
|
-
if (!state.isUnlocked) {
|
|
2467
|
-
throw new Error("Signless is locked. Please unlock first.");
|
|
2468
|
-
}
|
|
2469
|
-
return signPayload(params);
|
|
2470
|
-
},
|
|
2471
|
-
[config.enabled, state.isSetup, state.isUnlocked, signPayload]
|
|
2472
|
-
);
|
|
2473
|
-
const requiresUnlock = React10.useMemo(() => {
|
|
2474
|
-
return config.enabled && state.isSetup && !state.isUnlocked;
|
|
2475
|
-
}, [config.enabled, state.isSetup, state.isUnlocked]);
|
|
2476
|
-
return {
|
|
2477
|
-
pay,
|
|
2478
|
-
paySignless,
|
|
2479
|
-
address,
|
|
2480
|
-
signless: {
|
|
2481
|
-
state,
|
|
2482
|
-
config,
|
|
2483
|
-
setup,
|
|
2484
|
-
unlock,
|
|
2485
|
-
lock,
|
|
2486
|
-
reset,
|
|
2487
|
-
updateConfig,
|
|
2488
|
-
isBiometricAvailable,
|
|
2489
|
-
isEnabled: config.enabled,
|
|
2490
|
-
isSetup: state.isSetup,
|
|
2491
|
-
isUnlocked: state.isUnlocked,
|
|
2492
|
-
requiresUnlock
|
|
2493
|
-
}
|
|
2494
|
-
};
|
|
2495
|
-
}
|
|
2496
|
-
|
|
2497
|
-
// src/signless/hooks/useSignlessModal.ts
|
|
2498
|
-
|
|
2499
|
-
function useSignlessModal() {
|
|
2500
|
-
const { state, config } = useSignless();
|
|
2501
|
-
const [modalType, setModalType] = React11.useState(null);
|
|
2502
|
-
const openSetup = React11.useCallback(() => {
|
|
2503
|
-
if (!config.enabled) {
|
|
2504
|
-
console.warn("Signless is not enabled");
|
|
2505
|
-
return;
|
|
2506
|
-
}
|
|
2507
|
-
setModalType("setup");
|
|
2508
|
-
}, [config.enabled]);
|
|
2509
|
-
const openUnlock = React11.useCallback(() => {
|
|
2510
|
-
if (!config.enabled) {
|
|
2511
|
-
console.warn("Signless is not enabled");
|
|
2512
|
-
return;
|
|
2513
|
-
}
|
|
2514
|
-
if (!state.isSetup) {
|
|
2515
|
-
console.warn("Signless is not set up");
|
|
2516
|
-
return;
|
|
2517
|
-
}
|
|
2518
|
-
setModalType("unlock");
|
|
2519
|
-
}, [config.enabled, state.isSetup]);
|
|
2520
|
-
const close = React11.useCallback(() => {
|
|
2521
|
-
setModalType(null);
|
|
2522
|
-
}, []);
|
|
2523
|
-
const onSetupComplete = React11.useCallback(() => {
|
|
2524
|
-
setModalType(null);
|
|
2525
|
-
}, []);
|
|
2526
|
-
const onUnlockComplete = React11.useCallback(() => {
|
|
2527
|
-
setModalType(null);
|
|
2528
|
-
}, []);
|
|
2529
|
-
return {
|
|
2530
|
-
modalType,
|
|
2531
|
-
isOpen: modalType !== null,
|
|
2532
|
-
openSetup,
|
|
2533
|
-
openUnlock,
|
|
2534
|
-
close,
|
|
2535
|
-
onSetupComplete,
|
|
2536
|
-
onUnlockComplete
|
|
2537
|
-
};
|
|
2538
|
-
}
|
|
2539
|
-
|
|
2540
|
-
// src/signless/components/PinInput.tsx
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
// src/signless/components/styles.ts
|
|
2544
|
-
var pinInputStyles = {
|
|
2545
|
-
container: {
|
|
2546
|
-
display: "flex",
|
|
2547
|
-
flexDirection: "column",
|
|
2548
|
-
alignItems: "center",
|
|
2549
|
-
padding: "24px",
|
|
2550
|
-
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
2551
|
-
color: "#ffffff",
|
|
2552
|
-
minWidth: "280px"
|
|
2553
|
-
},
|
|
2554
|
-
header: {
|
|
2555
|
-
textAlign: "center",
|
|
2556
|
-
marginBottom: "32px"
|
|
2557
|
-
},
|
|
2558
|
-
title: {
|
|
2559
|
-
fontSize: "20px",
|
|
2560
|
-
fontWeight: 600,
|
|
2561
|
-
margin: "0 0 8px 0",
|
|
2562
|
-
color: "#ffffff"
|
|
2563
|
-
},
|
|
2564
|
-
subtitle: {
|
|
2565
|
-
fontSize: "14px",
|
|
2566
|
-
color: "rgba(255, 255, 255, 0.6)",
|
|
2567
|
-
margin: 0
|
|
2568
|
-
},
|
|
2569
|
-
hiddenInput: {
|
|
2570
|
-
position: "absolute",
|
|
2571
|
-
opacity: 0,
|
|
2572
|
-
pointerEvents: "none"
|
|
2573
|
-
},
|
|
2574
|
-
dotsContainer: {
|
|
2575
|
-
display: "flex",
|
|
2576
|
-
gap: "16px",
|
|
2577
|
-
marginBottom: "32px",
|
|
2578
|
-
cursor: "pointer"
|
|
2579
|
-
},
|
|
2580
|
-
dotsContainerShake: {
|
|
2581
|
-
animation: "tonpay-pin-shake 0.5s ease-in-out"
|
|
2582
|
-
},
|
|
2583
|
-
dot: {
|
|
2584
|
-
width: "14px",
|
|
2585
|
-
height: "14px",
|
|
2586
|
-
borderRadius: "50%",
|
|
2587
|
-
backgroundColor: "rgba(255, 255, 255, 0.2)",
|
|
2588
|
-
border: "2px solid rgba(255, 255, 255, 0.3)",
|
|
2589
|
-
transition: "all 0.15s ease"
|
|
2590
|
-
},
|
|
2591
|
-
dotFilled: {
|
|
2592
|
-
backgroundColor: "#0098EA",
|
|
2593
|
-
borderColor: "#0098EA",
|
|
2594
|
-
transform: "scale(1.1)"
|
|
2595
|
-
},
|
|
2596
|
-
dotLoading: {
|
|
2597
|
-
animation: "tonpay-pin-pulse 1s ease-in-out infinite"
|
|
2598
|
-
},
|
|
2599
|
-
error: {
|
|
2600
|
-
fontSize: "14px",
|
|
2601
|
-
color: "#FF5252",
|
|
2602
|
-
margin: "-16px 0 24px 0",
|
|
2603
|
-
textAlign: "center"
|
|
2604
|
-
},
|
|
2605
|
-
keypad: {
|
|
2606
|
-
display: "grid",
|
|
2607
|
-
gridTemplateColumns: "repeat(3, 1fr)",
|
|
2608
|
-
gap: "8px",
|
|
2609
|
-
width: "100%",
|
|
2610
|
-
maxWidth: "260px"
|
|
2611
|
-
},
|
|
2612
|
-
keypadButton: {
|
|
2613
|
-
width: "72px",
|
|
2614
|
-
height: "56px",
|
|
2615
|
-
fontSize: "24px",
|
|
2616
|
-
fontWeight: 500,
|
|
2617
|
-
color: "#ffffff",
|
|
2618
|
-
backgroundColor: "transparent",
|
|
2619
|
-
border: "none",
|
|
2620
|
-
borderRadius: "12px",
|
|
2621
|
-
cursor: "pointer",
|
|
2622
|
-
transition: "background-color 0.15s ease",
|
|
2623
|
-
display: "flex",
|
|
2624
|
-
alignItems: "center",
|
|
2625
|
-
justifyContent: "center"
|
|
2626
|
-
},
|
|
2627
|
-
keypadButtonEmpty: {
|
|
2628
|
-
width: "72px",
|
|
2629
|
-
height: "56px",
|
|
2630
|
-
display: "flex",
|
|
2631
|
-
alignItems: "center",
|
|
2632
|
-
justifyContent: "center"
|
|
2633
|
-
},
|
|
2634
|
-
biometricButton: {
|
|
2635
|
-
width: "56px",
|
|
2636
|
-
height: "56px",
|
|
2637
|
-
fontSize: "24px",
|
|
2638
|
-
color: "#0098EA",
|
|
2639
|
-
backgroundColor: "transparent",
|
|
2640
|
-
border: "none",
|
|
2641
|
-
borderRadius: "12px",
|
|
2642
|
-
cursor: "pointer",
|
|
2643
|
-
transition: "background-color 0.15s ease",
|
|
2644
|
-
display: "flex",
|
|
2645
|
-
alignItems: "center",
|
|
2646
|
-
justifyContent: "center"
|
|
2647
|
-
},
|
|
2648
|
-
backspaceButton: {
|
|
2649
|
-
width: "72px",
|
|
2650
|
-
height: "56px",
|
|
2651
|
-
fontSize: "24px",
|
|
2652
|
-
color: "rgba(255, 255, 255, 0.6)",
|
|
2653
|
-
backgroundColor: "transparent",
|
|
2654
|
-
border: "none",
|
|
2655
|
-
borderRadius: "12px",
|
|
2656
|
-
cursor: "pointer",
|
|
2657
|
-
transition: "all 0.15s ease",
|
|
2658
|
-
display: "flex",
|
|
2659
|
-
alignItems: "center",
|
|
2660
|
-
justifyContent: "center"
|
|
2661
|
-
},
|
|
2662
|
-
cancelButton: {
|
|
2663
|
-
marginTop: "24px",
|
|
2664
|
-
padding: "12px 32px",
|
|
2665
|
-
fontSize: "16px",
|
|
2666
|
-
fontWeight: 500,
|
|
2667
|
-
color: "rgba(255, 255, 255, 0.6)",
|
|
2668
|
-
backgroundColor: "transparent",
|
|
2669
|
-
border: "none",
|
|
2670
|
-
borderRadius: "8px",
|
|
2671
|
-
cursor: "pointer",
|
|
2672
|
-
transition: "color 0.15s ease"
|
|
2673
|
-
}
|
|
2674
|
-
};
|
|
2675
|
-
var setupModalStyles = {
|
|
2676
|
-
container: {
|
|
2677
|
-
display: "flex",
|
|
2678
|
-
flexDirection: "column",
|
|
2679
|
-
alignItems: "center",
|
|
2680
|
-
padding: "24px",
|
|
2681
|
-
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
2682
|
-
color: "#ffffff"
|
|
2683
|
-
},
|
|
2684
|
-
header: {
|
|
2685
|
-
textAlign: "center",
|
|
2686
|
-
marginBottom: "24px"
|
|
2687
|
-
},
|
|
2688
|
-
title: {
|
|
2689
|
-
fontSize: "22px",
|
|
2690
|
-
fontWeight: 600,
|
|
2691
|
-
margin: "0 0 8px 0",
|
|
2692
|
-
color: "#ffffff"
|
|
2693
|
-
},
|
|
2694
|
-
subtitle: {
|
|
2695
|
-
fontSize: "14px",
|
|
2696
|
-
color: "rgba(255, 255, 255, 0.6)",
|
|
2697
|
-
margin: 0,
|
|
2698
|
-
lineHeight: 1.5,
|
|
2699
|
-
maxWidth: "280px"
|
|
2700
|
-
},
|
|
2701
|
-
methodSelector: {
|
|
2702
|
-
display: "flex",
|
|
2703
|
-
flexDirection: "column",
|
|
2704
|
-
gap: "12px",
|
|
2705
|
-
width: "100%",
|
|
2706
|
-
marginBottom: "24px"
|
|
2707
|
-
},
|
|
2708
|
-
methodButton: {
|
|
2709
|
-
display: "flex",
|
|
2710
|
-
alignItems: "center",
|
|
2711
|
-
gap: "16px",
|
|
2712
|
-
padding: "16px",
|
|
2713
|
-
backgroundColor: "rgba(255, 255, 255, 0.05)",
|
|
2714
|
-
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
2715
|
-
borderRadius: "12px",
|
|
2716
|
-
cursor: "pointer",
|
|
2717
|
-
transition: "all 0.15s ease",
|
|
2718
|
-
textAlign: "left",
|
|
2719
|
-
width: "100%"
|
|
2720
|
-
},
|
|
2721
|
-
methodButtonSelected: {
|
|
2722
|
-
backgroundColor: "rgba(0, 152, 234, 0.15)",
|
|
2723
|
-
borderColor: "#0098EA"
|
|
2724
|
-
},
|
|
2725
|
-
methodIcon: {
|
|
2726
|
-
width: "48px",
|
|
2727
|
-
height: "48px",
|
|
2728
|
-
borderRadius: "12px",
|
|
2729
|
-
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
|
2730
|
-
display: "flex",
|
|
2731
|
-
alignItems: "center",
|
|
2732
|
-
justifyContent: "center",
|
|
2733
|
-
color: "#0098EA",
|
|
2734
|
-
flexShrink: 0
|
|
2735
|
-
},
|
|
2736
|
-
methodContent: {
|
|
2737
|
-
flex: 1,
|
|
2738
|
-
minWidth: 0
|
|
2739
|
-
},
|
|
2740
|
-
methodTitle: {
|
|
2741
|
-
fontSize: "16px",
|
|
2742
|
-
fontWeight: 600,
|
|
2743
|
-
color: "#ffffff",
|
|
2744
|
-
margin: "0 0 4px 0"
|
|
2745
|
-
},
|
|
2746
|
-
methodDescription: {
|
|
2747
|
-
fontSize: "13px",
|
|
2748
|
-
color: "rgba(255, 255, 255, 0.5)",
|
|
2749
|
-
margin: 0,
|
|
2750
|
-
lineHeight: 1.4
|
|
2751
|
-
},
|
|
2752
|
-
continueButton: {
|
|
2753
|
-
width: "100%",
|
|
2754
|
-
padding: "14px 24px",
|
|
2755
|
-
fontSize: "16px",
|
|
2756
|
-
fontWeight: 600,
|
|
2757
|
-
color: "#ffffff",
|
|
2758
|
-
backgroundColor: "#0098EA",
|
|
2759
|
-
border: "none",
|
|
2760
|
-
borderRadius: "12px",
|
|
2761
|
-
cursor: "pointer",
|
|
2762
|
-
transition: "opacity 0.15s ease"
|
|
2763
|
-
},
|
|
2764
|
-
continueButtonDisabled: {
|
|
2765
|
-
opacity: 0.5,
|
|
2766
|
-
cursor: "not-allowed"
|
|
2767
|
-
},
|
|
2768
|
-
stepIndicator: {
|
|
2769
|
-
display: "flex",
|
|
2770
|
-
gap: "8px",
|
|
2771
|
-
marginBottom: "24px"
|
|
2772
|
-
},
|
|
2773
|
-
stepDot: {
|
|
2774
|
-
width: "8px",
|
|
2775
|
-
height: "8px",
|
|
2776
|
-
borderRadius: "50%",
|
|
2777
|
-
backgroundColor: "rgba(255, 255, 255, 0.2)"
|
|
2778
|
-
},
|
|
2779
|
-
stepDotActive: {
|
|
2780
|
-
backgroundColor: "#0098EA"
|
|
2781
|
-
}
|
|
2782
|
-
};
|
|
2783
|
-
var unlockModalStyles = {
|
|
2784
|
-
container: {
|
|
2785
|
-
display: "flex",
|
|
2786
|
-
flexDirection: "column",
|
|
2787
|
-
alignItems: "center",
|
|
2788
|
-
padding: "24px",
|
|
2789
|
-
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
2790
|
-
color: "#ffffff"
|
|
2791
|
-
},
|
|
2792
|
-
biometricPrompt: {
|
|
2793
|
-
display: "flex",
|
|
2794
|
-
flexDirection: "column",
|
|
2795
|
-
alignItems: "center",
|
|
2796
|
-
padding: "32px",
|
|
2797
|
-
textAlign: "center"
|
|
2798
|
-
},
|
|
2799
|
-
biometricIcon: {
|
|
2800
|
-
width: "80px",
|
|
2801
|
-
height: "80px",
|
|
2802
|
-
borderRadius: "20px",
|
|
2803
|
-
backgroundColor: "rgba(0, 152, 234, 0.15)",
|
|
2804
|
-
display: "flex",
|
|
2805
|
-
alignItems: "center",
|
|
2806
|
-
justifyContent: "center",
|
|
2807
|
-
color: "#0098EA",
|
|
2808
|
-
marginBottom: "24px"
|
|
2809
|
-
},
|
|
2810
|
-
biometricTitle: {
|
|
2811
|
-
fontSize: "20px",
|
|
2812
|
-
fontWeight: 600,
|
|
2813
|
-
margin: "0 0 8px 0",
|
|
2814
|
-
color: "#ffffff"
|
|
2815
|
-
},
|
|
2816
|
-
biometricSubtitle: {
|
|
2817
|
-
fontSize: "14px",
|
|
2818
|
-
color: "rgba(255, 255, 255, 0.6)",
|
|
2819
|
-
margin: "0 0 24px 0"
|
|
2820
|
-
},
|
|
2821
|
-
usePinButton: {
|
|
2822
|
-
padding: "12px 24px",
|
|
2823
|
-
fontSize: "14px",
|
|
2824
|
-
fontWeight: 500,
|
|
2825
|
-
color: "#0098EA",
|
|
2826
|
-
backgroundColor: "transparent",
|
|
2827
|
-
border: "none",
|
|
2828
|
-
cursor: "pointer",
|
|
2829
|
-
transition: "opacity 0.15s ease"
|
|
2830
|
-
}
|
|
2831
|
-
};
|
|
2832
|
-
|
|
2833
|
-
// src/signless/components/PinInput.tsx
|
|
2834
|
-
|
|
2835
|
-
var PIN_LENGTH = 6;
|
|
2836
|
-
var PinInput = ({
|
|
2837
|
-
length = PIN_LENGTH,
|
|
2838
|
-
onComplete,
|
|
2839
|
-
onCancel,
|
|
2840
|
-
title = "Enter PIN",
|
|
2841
|
-
subtitle,
|
|
2842
|
-
error,
|
|
2843
|
-
isLoading = false,
|
|
2844
|
-
showBiometric = false,
|
|
2845
|
-
onBiometricPress
|
|
2846
|
-
}) => {
|
|
2847
|
-
const [pin, setPin] = React12.useState("");
|
|
2848
|
-
const [shake, setShake] = React12.useState(false);
|
|
2849
|
-
const inputRef = React12.useRef(null);
|
|
2850
|
-
React12.useEffect(() => {
|
|
2851
|
-
if (error) {
|
|
2852
|
-
setShake(true);
|
|
2853
|
-
setPin("");
|
|
2854
|
-
const timer = setTimeout(() => setShake(false), 500);
|
|
2855
|
-
return () => clearTimeout(timer);
|
|
2856
|
-
}
|
|
2857
|
-
}, [error]);
|
|
2858
|
-
React12.useEffect(() => {
|
|
2859
|
-
_optionalChain([inputRef, 'access', _43 => _43.current, 'optionalAccess', _44 => _44.focus, 'call', _45 => _45()]);
|
|
2860
|
-
}, []);
|
|
2861
|
-
const handleChange = (e) => {
|
|
2862
|
-
const value = e.target.value.replace(/\D/g, "").slice(0, length);
|
|
2863
|
-
setPin(value);
|
|
2864
|
-
if (value.length === length) {
|
|
2865
|
-
onComplete(value);
|
|
2866
|
-
}
|
|
2867
|
-
};
|
|
2868
|
-
const handleKeyDown = (e) => {
|
|
2869
|
-
if (e.key === "Escape" && onCancel) {
|
|
2870
|
-
onCancel();
|
|
2871
|
-
}
|
|
2872
|
-
};
|
|
2873
|
-
const handleDotClick = () => {
|
|
2874
|
-
_optionalChain([inputRef, 'access', _46 => _46.current, 'optionalAccess', _47 => _47.focus, 'call', _48 => _48()]);
|
|
2875
|
-
};
|
|
2876
|
-
const handleKeyPress = (digit) => {
|
|
2877
|
-
if (pin.length >= length || isLoading) return;
|
|
2878
|
-
const newPin = pin + digit;
|
|
2879
|
-
setPin(newPin);
|
|
2880
|
-
if (newPin.length === length) {
|
|
2881
|
-
onComplete(newPin);
|
|
2882
|
-
}
|
|
2883
|
-
};
|
|
2884
|
-
const handleBackspace = () => {
|
|
2885
|
-
if (isLoading) return;
|
|
2886
|
-
setPin((prev) => prev.slice(0, -1));
|
|
2887
|
-
};
|
|
2888
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: pinInputStyles.container, children: [
|
|
2889
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "style", { children: keyframes }),
|
|
2890
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: pinInputStyles.header, children: [
|
|
2891
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { style: pinInputStyles.title, children: title }),
|
|
2892
|
-
subtitle && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: pinInputStyles.subtitle, children: subtitle })
|
|
2893
|
-
] }),
|
|
2894
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2895
|
-
"input",
|
|
2896
|
-
{
|
|
2897
|
-
ref: inputRef,
|
|
2898
|
-
type: "text",
|
|
2899
|
-
inputMode: "numeric",
|
|
2900
|
-
pattern: "[0-9]*",
|
|
2901
|
-
value: pin,
|
|
2902
|
-
onChange: handleChange,
|
|
2903
|
-
onKeyDown: handleKeyDown,
|
|
2904
|
-
maxLength: length,
|
|
2905
|
-
autoComplete: "off",
|
|
2906
|
-
style: pinInputStyles.hiddenInput,
|
|
2907
|
-
disabled: isLoading
|
|
2908
|
-
}
|
|
2909
|
-
),
|
|
2910
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2911
|
-
"div",
|
|
2912
|
-
{
|
|
2913
|
-
style: {
|
|
2914
|
-
...pinInputStyles.dotsContainer,
|
|
2915
|
-
...shake ? pinInputStyles.dotsContainerShake : {}
|
|
2916
|
-
},
|
|
2917
|
-
onClick: handleDotClick,
|
|
2918
|
-
children: Array.from({ length }, (_, i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2919
|
-
"div",
|
|
2920
|
-
{
|
|
2921
|
-
style: {
|
|
2922
|
-
...pinInputStyles.dot,
|
|
2923
|
-
...i < pin.length ? pinInputStyles.dotFilled : {},
|
|
2924
|
-
...isLoading ? pinInputStyles.dotLoading : {}
|
|
2925
|
-
}
|
|
2926
|
-
},
|
|
2927
|
-
i
|
|
2928
|
-
))
|
|
2929
|
-
}
|
|
2930
|
-
),
|
|
2931
|
-
error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: pinInputStyles.error, children: error }),
|
|
2932
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: pinInputStyles.keypad, children: [
|
|
2933
|
-
[1, 2, 3, 4, 5, 6, 7, 8, 9].map((digit) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2934
|
-
"button",
|
|
2935
|
-
{
|
|
2936
|
-
type: "button",
|
|
2937
|
-
style: pinInputStyles.keypadButton,
|
|
2938
|
-
onClick: () => handleKeyPress(String(digit)),
|
|
2939
|
-
disabled: isLoading,
|
|
2940
|
-
onMouseEnter: (e) => {
|
|
2941
|
-
e.target.style.backgroundColor = "rgba(255, 255, 255, 0.1)";
|
|
2942
|
-
},
|
|
2943
|
-
onMouseLeave: (e) => {
|
|
2944
|
-
e.target.style.backgroundColor = "transparent";
|
|
2945
|
-
},
|
|
2946
|
-
children: digit
|
|
2947
|
-
},
|
|
2948
|
-
digit
|
|
2949
|
-
)),
|
|
2950
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: pinInputStyles.keypadButtonEmpty, children: showBiometric && onBiometricPress && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2951
|
-
"button",
|
|
2952
|
-
{
|
|
2953
|
-
type: "button",
|
|
2954
|
-
style: pinInputStyles.biometricButton,
|
|
2955
|
-
onClick: onBiometricPress,
|
|
2956
|
-
disabled: isLoading,
|
|
2957
|
-
"aria-label": "Use biometric authentication",
|
|
2958
|
-
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BiometricIcon, {})
|
|
2959
|
-
}
|
|
2960
|
-
) }),
|
|
2961
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2962
|
-
"button",
|
|
2963
|
-
{
|
|
2964
|
-
type: "button",
|
|
2965
|
-
style: pinInputStyles.keypadButton,
|
|
2966
|
-
onClick: () => handleKeyPress("0"),
|
|
2967
|
-
disabled: isLoading,
|
|
2968
|
-
onMouseEnter: (e) => {
|
|
2969
|
-
e.target.style.backgroundColor = "rgba(255, 255, 255, 0.1)";
|
|
2970
|
-
},
|
|
2971
|
-
onMouseLeave: (e) => {
|
|
2972
|
-
e.target.style.backgroundColor = "transparent";
|
|
2973
|
-
},
|
|
2974
|
-
children: "0"
|
|
2975
|
-
}
|
|
2976
|
-
),
|
|
2977
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2978
|
-
"button",
|
|
2979
|
-
{
|
|
2980
|
-
type: "button",
|
|
2981
|
-
style: pinInputStyles.backspaceButton,
|
|
2982
|
-
onClick: handleBackspace,
|
|
2983
|
-
disabled: isLoading || pin.length === 0,
|
|
2984
|
-
"aria-label": "Backspace",
|
|
2985
|
-
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BackspaceIcon, {})
|
|
2986
|
-
}
|
|
2987
|
-
)
|
|
2988
|
-
] }),
|
|
2989
|
-
onCancel && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2990
|
-
"button",
|
|
2991
|
-
{
|
|
2992
|
-
type: "button",
|
|
2993
|
-
style: pinInputStyles.cancelButton,
|
|
2994
|
-
onClick: onCancel,
|
|
2995
|
-
disabled: isLoading,
|
|
2996
|
-
children: "Cancel"
|
|
2997
|
-
}
|
|
2998
|
-
)
|
|
2999
|
-
] });
|
|
3000
|
-
};
|
|
3001
|
-
var BiometricIcon = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
3002
|
-
"svg",
|
|
3003
|
-
{
|
|
3004
|
-
width: "28",
|
|
3005
|
-
height: "28",
|
|
3006
|
-
viewBox: "0 0 24 24",
|
|
3007
|
-
fill: "none",
|
|
3008
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
3009
|
-
children: [
|
|
3010
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3011
|
-
"path",
|
|
3012
|
-
{
|
|
3013
|
-
d: "M12 14.5V16.5M7 10.5C7 7.73858 9.23858 5.5 12 5.5C14.7614 5.5 17 7.73858 17 10.5V11.5M12 11.5C10.6193 11.5 9.5 12.6193 9.5 14C9.5 15.3807 10.6193 16.5 12 16.5C13.3807 16.5 14.5 15.3807 14.5 14C14.5 12.6193 13.3807 11.5 12 11.5Z",
|
|
3014
|
-
stroke: "currentColor",
|
|
3015
|
-
strokeWidth: "1.5",
|
|
3016
|
-
strokeLinecap: "round",
|
|
3017
|
-
strokeLinejoin: "round"
|
|
3018
|
-
}
|
|
3019
|
-
),
|
|
3020
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3021
|
-
"path",
|
|
3022
|
-
{
|
|
3023
|
-
d: "M3 7V5C3 3.89543 3.89543 3 5 3H7M17 3H19C20.1046 3 21 3.89543 21 5V7M21 17V19C21 20.1046 20.1046 21 19 21H17M7 21H5C3.89543 21 3 20.1046 3 19V17",
|
|
3024
|
-
stroke: "currentColor",
|
|
3025
|
-
strokeWidth: "1.5",
|
|
3026
|
-
strokeLinecap: "round",
|
|
3027
|
-
strokeLinejoin: "round"
|
|
3028
|
-
}
|
|
3029
|
-
)
|
|
3030
|
-
]
|
|
3031
|
-
}
|
|
3032
|
-
);
|
|
3033
|
-
var BackspaceIcon = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
3034
|
-
"svg",
|
|
3035
|
-
{
|
|
3036
|
-
width: "24",
|
|
3037
|
-
height: "24",
|
|
3038
|
-
viewBox: "0 0 24 24",
|
|
3039
|
-
fill: "none",
|
|
3040
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
3041
|
-
children: [
|
|
3042
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3043
|
-
"path",
|
|
3044
|
-
{
|
|
3045
|
-
d: "M9.00195 7L4.00195 12L9.00195 17M19.002 7H8.00195L4.00195 12L8.00195 17H19.002C19.5325 17 20.0412 16.7893 20.4163 16.4142C20.7914 16.0391 21.002 15.5304 21.002 15V9C21.002 8.46957 20.7914 7.96086 20.4163 7.58579C20.0412 7.21071 19.5325 7 19.002 7Z",
|
|
3046
|
-
stroke: "currentColor",
|
|
3047
|
-
strokeWidth: "1.5",
|
|
3048
|
-
strokeLinecap: "round",
|
|
3049
|
-
strokeLinejoin: "round"
|
|
3050
|
-
}
|
|
3051
|
-
),
|
|
3052
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3053
|
-
"path",
|
|
3054
|
-
{
|
|
3055
|
-
d: "M14 10L10 14M10 10L14 14",
|
|
3056
|
-
stroke: "currentColor",
|
|
3057
|
-
strokeWidth: "1.5",
|
|
3058
|
-
strokeLinecap: "round",
|
|
3059
|
-
strokeLinejoin: "round"
|
|
3060
|
-
}
|
|
3061
|
-
)
|
|
3062
|
-
]
|
|
3063
|
-
}
|
|
3064
|
-
);
|
|
3065
|
-
var keyframes = `
|
|
3066
|
-
@keyframes tonpay-pin-shake {
|
|
3067
|
-
0%, 100% { transform: translateX(0); }
|
|
3068
|
-
10%, 30%, 50%, 70%, 90% { transform: translateX(-4px); }
|
|
3069
|
-
20%, 40%, 60%, 80% { transform: translateX(4px); }
|
|
3070
|
-
}
|
|
3071
|
-
@keyframes tonpay-pin-pulse {
|
|
3072
|
-
0%, 100% { opacity: 1; }
|
|
3073
|
-
50% { opacity: 0.5; }
|
|
3074
|
-
}
|
|
3075
|
-
`;
|
|
3076
|
-
|
|
3077
|
-
// src/signless/components/SignlessSetupModal.tsx
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
var SignlessSetupModal = ({
|
|
3081
|
-
isOpen,
|
|
3082
|
-
onClose,
|
|
3083
|
-
onComplete,
|
|
3084
|
-
showBiometric = true
|
|
3085
|
-
}) => {
|
|
3086
|
-
const { setup, isBiometricAvailable, state } = useSignless();
|
|
3087
|
-
const [step, setStep] = React13.useState("select_method");
|
|
3088
|
-
const [selectedMethod, setSelectedMethod] = React13.useState(null);
|
|
3089
|
-
const [pin, setPin] = React13.useState("");
|
|
3090
|
-
const [error, setError] = React13.useState(null);
|
|
3091
|
-
const [isLoading, setIsLoading] = React13.useState(false);
|
|
3092
|
-
React13.useEffect(() => {
|
|
3093
|
-
if (isOpen) {
|
|
3094
|
-
setStep("select_method");
|
|
3095
|
-
setSelectedMethod(null);
|
|
3096
|
-
setPin("");
|
|
3097
|
-
setError(null);
|
|
3098
|
-
setIsLoading(false);
|
|
3099
|
-
}
|
|
3100
|
-
}, [isOpen]);
|
|
3101
|
-
const handleMethodSelect = (method) => {
|
|
3102
|
-
setSelectedMethod(method);
|
|
3103
|
-
};
|
|
3104
|
-
const handleContinue = async () => {
|
|
3105
|
-
if (!selectedMethod) return;
|
|
3106
|
-
if (selectedMethod === "biometric") {
|
|
3107
|
-
setIsLoading(true);
|
|
3108
|
-
setError(null);
|
|
3109
|
-
try {
|
|
3110
|
-
await setup({ authMethod: "biometric" });
|
|
3111
|
-
onComplete();
|
|
3112
|
-
onClose();
|
|
3113
|
-
} catch (err) {
|
|
3114
|
-
setError(
|
|
3115
|
-
err instanceof Error ? err.message : "Biometric setup failed"
|
|
3116
|
-
);
|
|
3117
|
-
} finally {
|
|
3118
|
-
setIsLoading(false);
|
|
3119
|
-
}
|
|
3120
|
-
} else if (selectedMethod === "pin") {
|
|
3121
|
-
setStep("create_pin");
|
|
3122
|
-
}
|
|
3123
|
-
};
|
|
3124
|
-
const handlePinCreate = (newPin) => {
|
|
3125
|
-
setPin(newPin);
|
|
3126
|
-
setError(null);
|
|
3127
|
-
setStep("confirm_pin");
|
|
3128
|
-
};
|
|
3129
|
-
const handlePinConfirm = async (confirmPin) => {
|
|
3130
|
-
if (confirmPin !== pin) {
|
|
3131
|
-
setError("PINs do not match. Please try again.");
|
|
3132
|
-
setStep("create_pin");
|
|
3133
|
-
setPin("");
|
|
3134
|
-
return;
|
|
3135
|
-
}
|
|
3136
|
-
setIsLoading(true);
|
|
3137
|
-
setError(null);
|
|
3138
|
-
try {
|
|
3139
|
-
await setup({ authMethod: "pin", pin });
|
|
3140
|
-
onComplete();
|
|
3141
|
-
onClose();
|
|
3142
|
-
} catch (err) {
|
|
3143
|
-
setError(err instanceof Error ? err.message : "Setup failed");
|
|
3144
|
-
setStep("create_pin");
|
|
3145
|
-
setPin("");
|
|
3146
|
-
} finally {
|
|
3147
|
-
setIsLoading(false);
|
|
3148
|
-
}
|
|
3149
|
-
};
|
|
3150
|
-
const handleBack = () => {
|
|
3151
|
-
if (step === "confirm_pin") {
|
|
3152
|
-
setStep("create_pin");
|
|
3153
|
-
setError(null);
|
|
3154
|
-
} else if (step === "create_pin") {
|
|
3155
|
-
setStep("select_method");
|
|
3156
|
-
setPin("");
|
|
3157
|
-
setError(null);
|
|
3158
|
-
}
|
|
3159
|
-
};
|
|
3160
|
-
if (!isOpen) return null;
|
|
3161
|
-
const renderStepIndicator = () => {
|
|
3162
|
-
const steps = selectedMethod === "pin" ? 3 : 2;
|
|
3163
|
-
const currentStep = step === "select_method" ? 1 : step === "create_pin" ? 2 : 3;
|
|
3164
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: setupModalStyles.stepIndicator, children: Array.from({ length: steps }, (_, i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3165
|
-
"div",
|
|
3166
|
-
{
|
|
3167
|
-
style: {
|
|
3168
|
-
...setupModalStyles.stepDot,
|
|
3169
|
-
...i < currentStep ? setupModalStyles.stepDotActive : {}
|
|
3170
|
-
}
|
|
3171
|
-
},
|
|
3172
|
-
i
|
|
3173
|
-
)) });
|
|
3174
|
-
};
|
|
3175
|
-
const renderMethodSelection = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
3176
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: setupModalStyles.header, children: [
|
|
3177
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { style: setupModalStyles.title, children: "Setup Signless" }),
|
|
3178
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: setupModalStyles.subtitle, children: "Enable fast payments without wallet confirmations. Choose your preferred authentication method." })
|
|
3179
|
-
] }),
|
|
3180
|
-
renderStepIndicator(),
|
|
3181
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: setupModalStyles.methodSelector, children: [
|
|
3182
|
-
showBiometric && isBiometricAvailable && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
3183
|
-
"button",
|
|
3184
|
-
{
|
|
3185
|
-
type: "button",
|
|
3186
|
-
style: {
|
|
3187
|
-
...setupModalStyles.methodButton,
|
|
3188
|
-
...selectedMethod === "biometric" ? setupModalStyles.methodButtonSelected : {}
|
|
3189
|
-
},
|
|
3190
|
-
onClick: () => handleMethodSelect("biometric"),
|
|
3191
|
-
children: [
|
|
3192
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: setupModalStyles.methodIcon, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FaceIdIcon, {}) }),
|
|
3193
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: setupModalStyles.methodContent, children: [
|
|
3194
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { style: setupModalStyles.methodTitle, children: "Face ID / Touch ID" }),
|
|
3195
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: setupModalStyles.methodDescription, children: "Use biometric authentication for quick and secure access" })
|
|
3196
|
-
] })
|
|
3197
|
-
]
|
|
3198
|
-
}
|
|
3199
|
-
),
|
|
3200
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
3201
|
-
"button",
|
|
3202
|
-
{
|
|
3203
|
-
type: "button",
|
|
3204
|
-
style: {
|
|
3205
|
-
...setupModalStyles.methodButton,
|
|
3206
|
-
...selectedMethod === "pin" ? setupModalStyles.methodButtonSelected : {}
|
|
3207
|
-
},
|
|
3208
|
-
onClick: () => handleMethodSelect("pin"),
|
|
3209
|
-
children: [
|
|
3210
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: setupModalStyles.methodIcon, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PinIcon, {}) }),
|
|
3211
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: setupModalStyles.methodContent, children: [
|
|
3212
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { style: setupModalStyles.methodTitle, children: "PIN Code" }),
|
|
3213
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: setupModalStyles.methodDescription, children: "Create a 6-digit PIN for payment authorization" })
|
|
3214
|
-
] })
|
|
3215
|
-
]
|
|
3216
|
-
}
|
|
3217
|
-
)
|
|
3218
|
-
] }),
|
|
3219
|
-
error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: { color: "#FF5252", fontSize: "14px", marginBottom: "16px" }, children: error }),
|
|
3220
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3221
|
-
"button",
|
|
3222
|
-
{
|
|
3223
|
-
type: "button",
|
|
3224
|
-
style: {
|
|
3225
|
-
...setupModalStyles.continueButton,
|
|
3226
|
-
...!selectedMethod ? setupModalStyles.continueButtonDisabled : {}
|
|
3227
|
-
},
|
|
3228
|
-
onClick: handleContinue,
|
|
3229
|
-
disabled: !selectedMethod || isLoading,
|
|
3230
|
-
children: isLoading ? "Setting up..." : "Continue"
|
|
3231
|
-
}
|
|
3232
|
-
)
|
|
3233
|
-
] });
|
|
3234
|
-
const renderPinCreation = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
3235
|
-
renderStepIndicator(),
|
|
3236
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3237
|
-
PinInput,
|
|
3238
|
-
{
|
|
3239
|
-
title: "Create PIN",
|
|
3240
|
-
subtitle: "Enter a 6-digit PIN to secure your signless payments",
|
|
3241
|
-
onComplete: handlePinCreate,
|
|
3242
|
-
onCancel: handleBack,
|
|
3243
|
-
error,
|
|
3244
|
-
isLoading
|
|
3245
|
-
}
|
|
3246
|
-
)
|
|
3247
|
-
] });
|
|
3248
|
-
const renderPinConfirmation = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
3249
|
-
renderStepIndicator(),
|
|
3250
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3251
|
-
PinInput,
|
|
3252
|
-
{
|
|
3253
|
-
title: "Confirm PIN",
|
|
3254
|
-
subtitle: "Re-enter your PIN to confirm",
|
|
3255
|
-
onComplete: handlePinConfirm,
|
|
3256
|
-
onCancel: handleBack,
|
|
3257
|
-
error,
|
|
3258
|
-
isLoading
|
|
3259
|
-
}
|
|
3260
|
-
)
|
|
3261
|
-
] });
|
|
3262
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: setupModalStyles.container, children: [
|
|
3263
|
-
step === "select_method" && renderMethodSelection(),
|
|
3264
|
-
step === "create_pin" && renderPinCreation(),
|
|
3265
|
-
step === "confirm_pin" && renderPinConfirmation()
|
|
3266
|
-
] });
|
|
3267
|
-
};
|
|
3268
|
-
var FaceIdIcon = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
3269
|
-
"svg",
|
|
3270
|
-
{
|
|
3271
|
-
width: "28",
|
|
3272
|
-
height: "28",
|
|
3273
|
-
viewBox: "0 0 24 24",
|
|
3274
|
-
fill: "none",
|
|
3275
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
3276
|
-
children: [
|
|
3277
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3278
|
-
"path",
|
|
3279
|
-
{
|
|
3280
|
-
d: "M12 14.5V16.5M7 10.5C7 7.73858 9.23858 5.5 12 5.5C14.7614 5.5 17 7.73858 17 10.5V11.5M12 11.5C10.6193 11.5 9.5 12.6193 9.5 14C9.5 15.3807 10.6193 16.5 12 16.5C13.3807 16.5 14.5 15.3807 14.5 14C14.5 12.6193 13.3807 11.5 12 11.5Z",
|
|
3281
|
-
stroke: "currentColor",
|
|
3282
|
-
strokeWidth: "1.5",
|
|
3283
|
-
strokeLinecap: "round",
|
|
3284
|
-
strokeLinejoin: "round"
|
|
3285
|
-
}
|
|
3286
|
-
),
|
|
3287
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3288
|
-
"path",
|
|
3289
|
-
{
|
|
3290
|
-
d: "M3 7V5C3 3.89543 3.89543 3 5 3H7M17 3H19C20.1046 3 21 3.89543 21 5V7M21 17V19C21 20.1046 20.1046 21 19 21H17M7 21H5C3.89543 21 3 20.1046 3 19V17",
|
|
3291
|
-
stroke: "currentColor",
|
|
3292
|
-
strokeWidth: "1.5",
|
|
3293
|
-
strokeLinecap: "round",
|
|
3294
|
-
strokeLinejoin: "round"
|
|
3295
|
-
}
|
|
3296
|
-
)
|
|
3297
|
-
]
|
|
3298
|
-
}
|
|
3299
|
-
);
|
|
3300
|
-
var PinIcon = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
3301
|
-
"svg",
|
|
3302
|
-
{
|
|
3303
|
-
width: "28",
|
|
3304
|
-
height: "28",
|
|
3305
|
-
viewBox: "0 0 24 24",
|
|
3306
|
-
fill: "none",
|
|
3307
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
3308
|
-
children: [
|
|
3309
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3310
|
-
"rect",
|
|
3311
|
-
{
|
|
3312
|
-
x: "3",
|
|
3313
|
-
y: "6",
|
|
3314
|
-
width: "18",
|
|
3315
|
-
height: "12",
|
|
3316
|
-
rx: "2",
|
|
3317
|
-
stroke: "currentColor",
|
|
3318
|
-
strokeWidth: "1.5"
|
|
3319
|
-
}
|
|
3320
|
-
),
|
|
3321
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "7", cy: "12", r: "1.5", fill: "currentColor" }),
|
|
3322
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "12", cy: "12", r: "1.5", fill: "currentColor" }),
|
|
3323
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "17", cy: "12", r: "1.5", fill: "currentColor" })
|
|
3324
|
-
]
|
|
3325
|
-
}
|
|
3326
|
-
);
|
|
3327
|
-
|
|
3328
|
-
// src/signless/components/SignlessUnlockModal.tsx
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
var SignlessUnlockModal = ({
|
|
3332
|
-
isOpen,
|
|
3333
|
-
onClose,
|
|
3334
|
-
onUnlock,
|
|
3335
|
-
showBiometric = true
|
|
3336
|
-
}) => {
|
|
3337
|
-
const { unlock, state, isBiometricAvailable } = useSignless();
|
|
3338
|
-
const [view, setView] = React14.useState("biometric");
|
|
3339
|
-
const [error, setError] = React14.useState(null);
|
|
3340
|
-
const [isLoading, setIsLoading] = React14.useState(false);
|
|
3341
|
-
const shouldShowBiometric = showBiometric && isBiometricAvailable && state.authMethod === "biometric";
|
|
3342
|
-
React14.useEffect(() => {
|
|
3343
|
-
if (isOpen) {
|
|
3344
|
-
setError(null);
|
|
3345
|
-
setIsLoading(false);
|
|
3346
|
-
setView(shouldShowBiometric ? "biometric" : "pin");
|
|
3347
|
-
}
|
|
3348
|
-
}, [isOpen, shouldShowBiometric]);
|
|
3349
|
-
React14.useEffect(() => {
|
|
3350
|
-
if (isOpen && view === "biometric" && shouldShowBiometric) {
|
|
3351
|
-
handleBiometricAuth();
|
|
3352
|
-
}
|
|
3353
|
-
}, [isOpen, view]);
|
|
3354
|
-
const handleBiometricAuth = async () => {
|
|
3355
|
-
setIsLoading(true);
|
|
3356
|
-
setError(null);
|
|
3357
|
-
try {
|
|
3358
|
-
await unlock({});
|
|
3359
|
-
onUnlock();
|
|
3360
|
-
onClose();
|
|
3361
|
-
} catch (err) {
|
|
3362
|
-
setError(
|
|
3363
|
-
err instanceof Error ? err.message : "Biometric authentication failed"
|
|
3364
|
-
);
|
|
3365
|
-
setView("pin");
|
|
3366
|
-
} finally {
|
|
3367
|
-
setIsLoading(false);
|
|
3368
|
-
}
|
|
3369
|
-
};
|
|
3370
|
-
const handlePinSubmit = async (pin) => {
|
|
3371
|
-
setIsLoading(true);
|
|
3372
|
-
setError(null);
|
|
3373
|
-
try {
|
|
3374
|
-
await unlock({ pin });
|
|
3375
|
-
onUnlock();
|
|
3376
|
-
onClose();
|
|
3377
|
-
} catch (err) {
|
|
3378
|
-
setError("Invalid PIN. Please try again.");
|
|
3379
|
-
} finally {
|
|
3380
|
-
setIsLoading(false);
|
|
3381
|
-
}
|
|
3382
|
-
};
|
|
3383
|
-
const handleUsePinInstead = () => {
|
|
3384
|
-
setView("pin");
|
|
3385
|
-
setError(null);
|
|
3386
|
-
};
|
|
3387
|
-
if (!isOpen) return null;
|
|
3388
|
-
const renderBiometricPrompt = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: unlockModalStyles.biometricPrompt, children: [
|
|
3389
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: unlockModalStyles.biometricIcon, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BiometricLargeIcon, {}) }),
|
|
3390
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { style: unlockModalStyles.biometricTitle, children: "Unlock Signless" }),
|
|
3391
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: unlockModalStyles.biometricSubtitle, children: isLoading ? "Authenticating..." : "Use Face ID or Touch ID to continue" }),
|
|
3392
|
-
error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: { color: "#FF5252", fontSize: "14px", marginBottom: "16px" }, children: error }),
|
|
3393
|
-
!isLoading && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
3394
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3395
|
-
"button",
|
|
3396
|
-
{
|
|
3397
|
-
type: "button",
|
|
3398
|
-
style: {
|
|
3399
|
-
padding: "14px 32px",
|
|
3400
|
-
fontSize: "16px",
|
|
3401
|
-
fontWeight: 600,
|
|
3402
|
-
color: "#ffffff",
|
|
3403
|
-
backgroundColor: "#0098EA",
|
|
3404
|
-
border: "none",
|
|
3405
|
-
borderRadius: "12px",
|
|
3406
|
-
cursor: "pointer",
|
|
3407
|
-
marginBottom: "16px"
|
|
3408
|
-
},
|
|
3409
|
-
onClick: handleBiometricAuth,
|
|
3410
|
-
children: "Try Again"
|
|
3411
|
-
}
|
|
3412
|
-
),
|
|
3413
|
-
state.authMethod === "biometric" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3414
|
-
"button",
|
|
3415
|
-
{
|
|
3416
|
-
type: "button",
|
|
3417
|
-
style: unlockModalStyles.usePinButton,
|
|
3418
|
-
onClick: handleUsePinInstead,
|
|
3419
|
-
children: "Use PIN instead"
|
|
3420
|
-
}
|
|
3421
|
-
)
|
|
3422
|
-
] })
|
|
3423
|
-
] });
|
|
3424
|
-
const renderPinInput = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3425
|
-
PinInput,
|
|
3426
|
-
{
|
|
3427
|
-
title: "Enter PIN",
|
|
3428
|
-
subtitle: "Enter your PIN to unlock signless payments",
|
|
3429
|
-
onComplete: handlePinSubmit,
|
|
3430
|
-
onCancel: onClose,
|
|
3431
|
-
error,
|
|
3432
|
-
isLoading,
|
|
3433
|
-
showBiometric: shouldShowBiometric,
|
|
3434
|
-
onBiometricPress: () => {
|
|
3435
|
-
setView("biometric");
|
|
3436
|
-
setError(null);
|
|
3437
|
-
}
|
|
3438
|
-
}
|
|
3439
|
-
);
|
|
3440
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: unlockModalStyles.container, children: view === "biometric" && shouldShowBiometric ? renderBiometricPrompt() : renderPinInput() });
|
|
3441
|
-
};
|
|
3442
|
-
var BiometricLargeIcon = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
3443
|
-
"svg",
|
|
3444
|
-
{
|
|
3445
|
-
width: "48",
|
|
3446
|
-
height: "48",
|
|
3447
|
-
viewBox: "0 0 24 24",
|
|
3448
|
-
fill: "none",
|
|
3449
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
3450
|
-
children: [
|
|
3451
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3452
|
-
"path",
|
|
3453
|
-
{
|
|
3454
|
-
d: "M12 14.5V16.5M7 10.5C7 7.73858 9.23858 5.5 12 5.5C14.7614 5.5 17 7.73858 17 10.5V11.5M12 11.5C10.6193 11.5 9.5 12.6193 9.5 14C9.5 15.3807 10.6193 16.5 12 16.5C13.3807 16.5 14.5 15.3807 14.5 14C14.5 12.6193 13.3807 11.5 12 11.5Z",
|
|
3455
|
-
stroke: "currentColor",
|
|
3456
|
-
strokeWidth: "1.5",
|
|
3457
|
-
strokeLinecap: "round",
|
|
3458
|
-
strokeLinejoin: "round"
|
|
3459
|
-
}
|
|
3460
|
-
),
|
|
3461
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3462
|
-
"path",
|
|
3463
|
-
{
|
|
3464
|
-
d: "M3 7V5C3 3.89543 3.89543 3 5 3H7M17 3H19C20.1046 3 21 3.89543 21 5V7M21 17V19C21 20.1046 20.1046 21 19 21H17M7 21H5C3.89543 21 3 20.1046 3 19V17",
|
|
3465
|
-
stroke: "currentColor",
|
|
3466
|
-
strokeWidth: "1.5",
|
|
3467
|
-
strokeLinecap: "round",
|
|
3468
|
-
strokeLinejoin: "round"
|
|
3469
|
-
}
|
|
3470
|
-
)
|
|
3471
|
-
]
|
|
3472
|
-
}
|
|
3473
|
-
);
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
1845
|
|
|
3493
1846
|
|
|
3494
1847
|
|
|
@@ -3497,5 +1850,5 @@ var BiometricLargeIcon = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
|
3497
1850
|
|
|
3498
1851
|
|
|
3499
1852
|
|
|
3500
|
-
exports.BottomSheet = BottomSheet_default; exports.ErrorTransactionNotification = ErrorTransactionNotification; exports.NotificationCard = NotificationCard; exports.NotificationRoot = NotificationRoot; exports.PaymentModal = PaymentModal; exports.
|
|
1853
|
+
exports.BottomSheet = BottomSheet_default; exports.ErrorTransactionNotification = ErrorTransactionNotification; exports.NotificationCard = NotificationCard; exports.NotificationRoot = NotificationRoot; exports.PaymentModal = PaymentModal; exports.TonPayButton = TonPayButton; exports.useMoonPayIframe = useMoonPayIframe; exports.useTonPay = useTonPay;
|
|
3501
1854
|
//# sourceMappingURL=index.js.map
|