UNPKG

enclave-wallet-sdk

Version:

A simple enclave wallet SDK for React applications

564 lines (563 loc) 28.8 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.WalletModal = void 0; var react_1 = __importStar(require("react")); var enclavemoney_web_experimental_1 = require("enclavemoney-web-experimental"); var SwapToken_1 = require("./SwapToken"); var Dashboard_1 = require("./Dashboard"); var TransferToken_1 = __importDefault(require("./Transfer/TransferToken")); var CryptoBalanceContext_1 = require("../context/CryptoBalanceContext"); var ActivityDetails_1 = __importDefault(require("./ActivityDetails")); var enclaveLogo = "https://firebasestorage.googleapis.com/v0/b/enclave-wallet.appspot.com/o/enclave_black.png?alt=media&token=6e32e0d1-4ef5-44a5-9ba6-339852ba0359"; var StartStep = function (_a) { var onNext = _a.onNext; return (react_1.default.createElement(react_1.default.Fragment, null, react_1.default.createElement("div", { style: { fontSize: 36, marginBottom: 10 } }, react_1.default.createElement("img", { src: "https://firebasestorage.googleapis.com/v0/b/enclave-wallet.appspot.com/o/wallet-sdk%2FpassKey.png?alt=media&token=00244583-8acf-4805-9fb3-c0fd9f103cfa", alt: "passkey Logo", style: { width: 84 } })), react_1.default.createElement("div", { style: { color: "#4B5563", fontSize: 17, textAlign: "center", marginBottom: 10, } }, "Authenticate securely using your device's passkey"), react_1.default.createElement("button", { style: { marginTop: 10, width: "100%", background: "#3662E3", color: "white", fontWeight: 600, fontSize: 18, border: "none", borderRadius: 10, padding: "14px 0", cursor: "pointer", boxShadow: "0 2px 8px rgba(70,100,233,0.10)", transition: "background 0.2s", }, onClick: onNext }, "Use my passkey"))); }; var SignupStep = function (_a) { var username = _a.username, onUsernameChange = _a.onUsernameChange, usernameStatus = _a.usernameStatus, checking = _a.checking, error = _a.error, actionLoading = _a.actionLoading, onLogin = _a.onLogin, onSignup = _a.onSignup; return (react_1.default.createElement("div", { style: { width: "100%" } }, react_1.default.createElement("label", { style: { fontWeight: 600, fontSize: 14, marginBottom: 6, display: "block", } }, "Choose a username"), react_1.default.createElement("input", { type: "text", value: username, onChange: function (e) { return onUsernameChange(e.target.value); }, placeholder: "Enter username", style: { width: "100%", padding: "10px", borderRadius: 8, border: "1px solid #ccc", fontSize: 16, marginBottom: 8, }, disabled: actionLoading }), checking && (react_1.default.createElement("div", { style: { color: "#888", fontSize: 14 } }, "Searching username...")), usernameStatus === "exists" && (react_1.default.createElement("div", { style: { color: "green", fontSize: 14 } }, "Username found. You can log in.")), usernameStatus === "not-exists" && (react_1.default.createElement("div", { style: { color: "blue", fontSize: 14 } }, "Username is available. You can sign up.")), error && react_1.default.createElement("div", { style: { color: "red", fontSize: 14 } }, error), react_1.default.createElement("button", { style: { marginTop: 16, width: "100%", background: usernameStatus && !checking ? "#4664E9" : "#bfc8e6", color: "white", fontWeight: 600, fontSize: 16, border: "none", borderRadius: 10, padding: "14px 0", cursor: usernameStatus && !checking ? "pointer" : "not-allowed", boxShadow: "0 2px 8px rgba(70,100,233,0.10)", transition: "background 0.2s", }, disabled: !usernameStatus || checking || actionLoading, onClick: function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: if (!(usernameStatus === "exists")) return [3 /*break*/, 2]; return [4 /*yield*/, onLogin()]; case 1: _a.sent(); return [3 /*break*/, 4]; case 2: if (!(usernameStatus === "not-exists")) return [3 /*break*/, 4]; return [4 /*yield*/, onSignup()]; case 3: _a.sent(); _a.label = 4; case 4: return [2 /*return*/]; } }); }); } }, checking ? "Searching username..." : actionLoading ? usernameStatus === "exists" ? "Logging in..." : "Signing up..." : usernameStatus === "exists" ? "Login" : usernameStatus === "not-exists" ? "Sign Up" : "Continue"))); }; var WalletModalContent = function (_a) { var _b; var isOpen = _a.isOpen, onClose = _a.onClose, walletSDKKey = _a.walletSDKKey, swapParams = _a.swapParams; var _c = (0, react_1.useState)("start"), step = _c[0], setStep = _c[1]; var _d = (0, react_1.useState)(""), username = _d[0], setUsername = _d[1]; var _e = (0, react_1.useState)(false), checking = _e[0], setChecking = _e[1]; var _f = (0, react_1.useState)(null), usernameStatus = _f[0], setUsernameStatus = _f[1]; var _g = (0, react_1.useState)(null), error = _g[0], setError = _g[1]; var _h = (0, react_1.useState)(false), actionLoading = _h[0], setActionLoading = _h[1]; var _j = (0, react_1.useState)(null), result = _j[0], setResult = _j[1]; var _k = (0, react_1.useState)(null), balance = _k[0], setBalance = _k[1]; var _l = (0, react_1.useState)(false), showSwap = _l[0], setShowSwap = _l[1]; var _m = (0, react_1.useState)(false), showTransfer = _m[0], setShowTransfer = _m[1]; var debounceRef = (0, react_1.useRef)(null); var _o = (0, CryptoBalanceContext_1.useCryptoBalance)(), cryptoBalance = _o.cryptoBalance, refreshBalance = _o.refreshBalance; var _p = (0, react_1.useState)(null), combinedBalance = _p[0], setCombinedBalance = _p[1]; var _q = (0, CryptoBalanceContext_1.useCryptoBalance)(), showActivity = _q.showActivity, setShowActivity = _q.setShowActivity, activity = _q.activity, setActivity = _q.setActivity, setLoading = _q.setLoading; var enclave = new enclavemoney_web_experimental_1.Enclave(walletSDKKey); (0, react_1.useEffect)(function () { if (isOpen) { var saved = localStorage.getItem("enclave_wallet_login"); if (saved) { var parsed = JSON.parse(saved); setResult(parsed.result); setBalance(parsed.balance); // Trigger immediate balance refresh when modal opens with existing session refreshBalance(); } } }, [isOpen, swapParams]); (0, react_1.useEffect)(function () { if (result) { localStorage.setItem("enclave_wallet_login", JSON.stringify({ result: result, balance: balance })); setLoading(true); } }, [result, balance]); (0, react_1.useEffect)(function () { if (swapParams) { setShowSwap(true); } if (result && swapParams && cryptoBalance) { setCombinedBalance({ data: __spreadArray(__spreadArray(__spreadArray([], (cryptoBalance.data.some(function (token) { return token.chainIds.some(function (chain) { return chain.address.toLowerCase() === swapParams.fromToken.tokenAddress.toLowerCase() && chain.chainId === swapParams.fromToken.chainId; }); }) ? [] : [swapParams.fromToken]), true), (cryptoBalance.data.some(function (token) { return token.chainIds.some(function (chain) { return chain.address.toLowerCase() === swapParams.toToken.tokenAddress.toLowerCase() && chain.chainId === swapParams.toToken.chainId; }); }) ? [] : [swapParams.toToken]), true), cryptoBalance.data, true), }); } if (!swapParams && cryptoBalance) { setCombinedBalance(cryptoBalance); } }, [result, swapParams, cryptoBalance]); var handleUsernameChange = function (value) { setUsername(value); setUsernameStatus(null); setError(null); if (debounceRef.current) clearTimeout(debounceRef.current); if (!value) return; setChecking(true); debounceRef.current = setTimeout(function () { checkUserName(value); }, 500); }; var checkUserName = function (username) { return __awaiter(void 0, void 0, void 0, function () { var resp, e_1; return __generator(this, function (_a) { switch (_a.label) { case 0: setChecking(true); setError(null); _a.label = 1; case 1: _a.trys.push([1, 3, 4, 5]); return [4 /*yield*/, enclave.checkUserName(username)]; case 2: resp = _a.sent(); if (resp.value === true) { setUsernameStatus("exists"); } else if (resp.value === false) { setUsernameStatus("not-exists"); } else { setUsernameStatus(null); } return [3 /*break*/, 5]; case 3: e_1 = _a.sent(); setError("Error checking username"); setUsernameStatus(null); return [3 /*break*/, 5]; case 4: setChecking(false); return [7 /*endfinally*/]; case 5: return [2 /*return*/]; } }); }); }; var signInAccount = function () { return __awaiter(void 0, void 0, void 0, function () { var resp, attResp, error_1, verificationResp, sdkInstance, balanceData, e_2; return __generator(this, function (_a) { switch (_a.label) { case 0: setActionLoading(true); setError(null); _a.label = 1; case 1: _a.trys.push([1, 13, 14, 15]); return [4 /*yield*/, enclave.getPasskeyAccountRegisteredOptions(username)]; case 2: resp = _a.sent(); attResp = void 0; _a.label = 3; case 3: _a.trys.push([3, 5, , 6]); return [4 /*yield*/, enclave.startPasskeyAccountAuthentication(resp)]; case 4: attResp = _a.sent(); return [3 /*break*/, 6]; case 5: error_1 = _a.sent(); throw error_1; case 6: return [4 /*yield*/, enclave.submitPasskeyAccountRegisteredResponse({ username: username, attResp: attResp, })]; case 7: verificationResp = _a.sent(); if (!verificationResp) return [3 /*break*/, 11]; if (!verificationResp.error) return [3 /*break*/, 8]; setError(verificationResp.message); return [3 /*break*/, 10]; case 8: setResult(verificationResp); sdkInstance = window.__walletSDKInstance; if (!sdkInstance) return [3 /*break*/, 10]; return [4 /*yield*/, sdkInstance.getUserCryptoBalance()]; case 9: balanceData = _a.sent(); setBalance(balanceData); sdkInstance.setUserSession({ result: verificationResp, balance: balanceData, }); _a.label = 10; case 10: return [3 /*break*/, 12]; case 11: setError("Login failed"); _a.label = 12; case 12: return [3 /*break*/, 15]; case 13: e_2 = _a.sent(); setError(e_2.message || "Login failed"); return [3 /*break*/, 15]; case 14: setActionLoading(false); return [7 /*endfinally*/]; case 15: return [2 /*return*/]; } }); }); }; var createAccount = function () { return __awaiter(void 0, void 0, void 0, function () { var resp, attResp, error_2, verificationResp, sdkInstance, balanceData, e_3; return __generator(this, function (_a) { switch (_a.label) { case 0: setActionLoading(true); setError(null); _a.label = 1; case 1: _a.trys.push([1, 13, 14, 15]); return [4 /*yield*/, enclave.getPasskeyAccountRegistrationOptions(username)]; case 2: resp = _a.sent(); attResp = void 0; _a.label = 3; case 3: _a.trys.push([3, 5, , 6]); return [4 /*yield*/, enclave.startPasskeyAccountRegistration(resp)]; case 4: attResp = _a.sent(); return [3 /*break*/, 6]; case 5: error_2 = _a.sent(); throw error_2; case 6: return [4 /*yield*/, enclave.submitPasskeyAccountRegistrationResponse({ username: username, attResp: attResp, })]; case 7: verificationResp = _a.sent(); if (!verificationResp) return [3 /*break*/, 11]; if (!verificationResp.error) return [3 /*break*/, 8]; setError(verificationResp.message); return [3 /*break*/, 10]; case 8: setResult(verificationResp); sdkInstance = window.__walletSDKInstance; if (!sdkInstance) return [3 /*break*/, 10]; return [4 /*yield*/, sdkInstance.getUserCryptoBalance()]; case 9: balanceData = _a.sent(); setBalance(balanceData); sdkInstance.setUserSession({ result: verificationResp, balance: balanceData, }); _a.label = 10; case 10: return [3 /*break*/, 12]; case 11: setError("Signup failed"); _a.label = 12; case 12: return [3 /*break*/, 15]; case 13: e_3 = _a.sent(); setError(e_3.message || "Signup failed"); return [3 /*break*/, 15]; case 14: setActionLoading(false); return [7 /*endfinally*/]; case 15: return [2 /*return*/]; } }); }); }; var handleLogout = function () { setResult(null); setUsername(""); setUsernameStatus(null); setError(null); setStep("start"); localStorage.removeItem("enclave_wallet_login"); }; var getMatchingTokenFromCryptoBalance = function (tokenAddress, chainId) { return cryptoBalance === null || cryptoBalance === void 0 ? void 0 : cryptoBalance.data.find(function (token) { return token.chainIds.some(function (chain) { return chain.address.toLowerCase() === tokenAddress.toLowerCase() && chain.chainId === chainId; }); }); }; var formatTokenForSwap = function (matchingToken, chainId) { var _a; if (!matchingToken) return undefined; var matchingChain = matchingToken.chainIds.find(function (chain) { return chain.chainId === chainId; }); if (!matchingChain) return undefined; return { symbol: matchingToken.symbol, name: matchingToken.name, icon: matchingToken.logoURI, address: matchingChain.address, chainId: matchingChain.chainId, chainIds: matchingToken.chainIds, decimals: matchingToken.decimals, balance: matchingChain.balance, amount: (_a = matchingToken.amount) === null || _a === void 0 ? void 0 : _a.toString(), }; }; var getInitialFromToken = function () { if (!(swapParams === null || swapParams === void 0 ? void 0 : swapParams.fromToken)) return undefined; var matchingToken = getMatchingTokenFromCryptoBalance(swapParams.fromToken.tokenAddress, swapParams.fromToken.chainId); return formatTokenForSwap(matchingToken, swapParams.fromToken.chainId); }; var getInitialToToken = function () { if (!(swapParams === null || swapParams === void 0 ? void 0 : swapParams.toToken)) return undefined; var matchingToken = getMatchingTokenFromCryptoBalance(swapParams.toToken.tokenAddress, swapParams.toToken.chainId); console.log(matchingToken, "matchingToken", swapParams.toToken, cryptoBalance, "cryptoBalance"); return formatTokenForSwap(matchingToken, swapParams.toToken.chainId); }; if (!isOpen) return null; return (react_1.default.createElement("div", { style: { position: "fixed", top: 0, left: 0, right: 0, bottom: 0, backgroundColor: "rgba(0, 0, 0, 0.5)", display: "flex", justifyContent: "center", alignItems: "center", zIndex: 1000, }, onClick: onClose }, react_1.default.createElement("div", { style: { backgroundColor: "white", maxHeight: "95vh", overflowY: "auto", padding: "32px 24px 24px 24px", borderRadius: "20px", minWidth: "440px", color: "#222", boxShadow: "0 4px 24px rgba(0,0,0,0.10)", position: "relative", fontFamily: "Inter, sans-serif", }, onClick: function (e) { return e.stopPropagation(); } }, !result && (react_1.default.createElement("div", null, react_1.default.createElement("div", { style: { display: "flex", justifyContent: "center", marginBottom: 16, } }, react_1.default.createElement("img", { src: enclaveLogo, alt: "Enclave Logo", style: { height: 48, objectFit: "contain" } })), react_1.default.createElement("button", { onClick: onClose, style: { position: "absolute", top: 18, right: 18, background: "none", border: "none", fontSize: 22, cursor: "pointer", color: "#888", }, "aria-label": "Close" }, "\u00D7"))), !result && (react_1.default.createElement("h2", { style: { fontSize: 26, fontWeight: 700, margin: 0, textAlign: "center", } }, "Log In or Sign Up")), !result && (react_1.default.createElement("p", { style: { color: "#6B7280", fontSize: 16, margin: "10px 0 24px 0", textAlign: "center", } }, "Sign into your wallet with one click")), !result && (react_1.default.createElement("div", { style: { background: "#F6F8FE", borderRadius: 16, padding: "24px 16px 20px 16px", flexDirection: "column", alignItems: "center", marginBottom: 24, display: showSwap ? "none" : "flex", } }, step === "start" && !result && (react_1.default.createElement(StartStep, { onNext: function () { return setStep("signup"); } })), step === "signup" && !result && (react_1.default.createElement(SignupStep, { username: username, onUsernameChange: handleUsernameChange, usernameStatus: usernameStatus, checking: checking, error: error, actionLoading: actionLoading, onLogin: signInAccount, onSignup: createAccount })))), showSwap && !showTransfer && (react_1.default.createElement(SwapToken_1.SwapToken, { onBack: function () { setShowSwap(false); if (swapParams) { onClose(); } }, walletSDKKey: walletSDKKey, combinedBalance: combinedBalance, initialFromToken: cryptoBalance && getInitialFromToken(), initialToToken: cryptoBalance && getInitialToToken(), initialAmount: ((_b = swapParams === null || swapParams === void 0 ? void 0 : swapParams.fromToken) === null || _b === void 0 ? void 0 : _b.amount) || "" })), showTransfer && (react_1.default.createElement(TransferToken_1.default, { onBack: function () { return setShowTransfer(false); }, onClose: function () { return setShowTransfer(false); }, walletSdkKey: walletSDKKey, username: (result === null || result === void 0 ? void 0 : result.username) || "" })), result && !showSwap && !swapParams && !showTransfer && !showActivity && (react_1.default.createElement(Dashboard_1.Dashboard, { result: result, onLogout: handleLogout, onShowSwap: function () { return setShowSwap(true); }, onShowTransfer: function () { return setShowTransfer(true); }, sdkKey: walletSDKKey })), showActivity && (react_1.default.createElement(ActivityDetails_1.default, { onBack: function () { return setShowActivity(false); }, activity: activity })), react_1.default.createElement("div", { style: { display: "flex", justifyContent: "center", alignItems: "center", gap: 8, } }, react_1.default.createElement("span", { style: { fontSize: 12, color: "#B4B4B6" } }, "Secured by"), react_1.default.createElement("img", { src: "https://firebasestorage.googleapis.com/v0/b/enclave-wallet.appspot.com/o/wallet-sdk%2FLogoNameGray.png?alt=media&token=10a251a9-3dc9-441f-bf41-d4e60704cc33", alt: "Enclave text Logo", style: { width: 84 } }))))); }; var WalletModal = function (props) { return (react_1.default.createElement(CryptoBalanceContext_1.CryptoBalanceProvider, { walletSDKKey: props.walletSDKKey }, react_1.default.createElement(WalletModalContent, __assign({}, props)))); }; exports.WalletModal = WalletModal;