@avalabs/avacloud-waas-react
Version:
React SDK for AvaCloud Wallet as a Service
1,439 lines (1,418 loc) • 192 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
AvaCloudWalletProvider: () => AvaCloudWalletProvider,
ExportView: () => ExportView,
GaslessProvider: () => GaslessProvider,
LoginButton: () => LoginButton,
ReceiveView: () => ReceiveView,
SendView: () => SendView,
ThemeProvider: () => ThemeProvider,
TokensView: () => TokensView,
UserProfile: () => UserProfile,
VM: () => VM,
WalletButton: () => WalletButton,
WalletCard: () => WalletCard,
WalletDisplay: () => WalletDisplay,
avaCloudWallet: () => avaCloudWallet,
useAuth: () => useAuth,
useAvaCloudWallet: () => useAvaCloudWallet,
useBlockchain: () => useBlockchain,
useChainId: () => useChainId,
useGaslessTransaction: () => useGaslessTransaction,
useGlacier: () => useGlacier,
usePostMessage: () => usePostMessage,
useSignMessage: () => useSignMessage,
useSignTransaction: () => useSignTransaction,
useThemeMode: () => useThemeMode,
useTransferTokens: () => useTransferTokens,
useUserWallets: () => useUserWallets
});
module.exports = __toCommonJS(index_exports);
// src/AvaCloudWalletProvider.tsx
var import_react9 = require("react");
var import_react_query2 = require("@tanstack/react-query");
var import_cubesigner_sdk = require("@cubist-labs/cubesigner-sdk");
// src/types/vm.ts
var VM = /* @__PURE__ */ ((VM2) => {
VM2["EVM"] = "EVM";
VM2["AVM"] = "AVM";
VM2["PVM"] = "PVM";
return VM2;
})(VM || {});
// src/utils/derivationPath.ts
var getCoinIndexForVm = (vm) => {
switch (vm) {
case "EVM" /* EVM */:
return 60;
case "AVM" /* AVM */:
case "PVM" /* PVM */:
return 9e3;
default:
throw new Error(`Unknown coin index for vm: ${vm}`);
}
};
function getDerivationPath(vm, accountIndex) {
if (accountIndex < 0 || Math.round(accountIndex) !== accountIndex) {
throw new Error("Account index must be a non-negative integer");
}
const coinIndex = getCoinIndexForVm(vm);
return `m/44'/${coinIndex}'/0'/0/${accountIndex}`;
}
// src/hooks/usePostMessage.ts
var import_react = require("react");
// src/constants/storage.ts
var OIDC_TOKEN_KEY = "avacloud-auth-oidc-token";
var AUTH_TOKENS_KEY = "auth_tokens";
var AUTH0_STORAGE_KEYS = {
IS_AUTHENTICATED: "auth0.is.authenticated",
ACCESS_TOKEN: "auth0.access_token",
ID_TOKEN: "auth0.id_token",
EXPIRES_AT: "auth0.expires_at"
};
var CUBIST_USER_ID_KEY = "cubist_user_id";
var ORG_CONFIG_CACHE_KEY = "avacloud-org-config-cache";
// src/hooks/usePostMessage.ts
var globalAuthState = {
signupInProgress: false,
loginInProgress: false,
lastSignupTimestamp: 0,
lastLoginTimestamp: 0,
processingMessageIds: /* @__PURE__ */ new Set()
};
function cleanupProcessedMessageIds() {
if (globalAuthState.processingMessageIds.size > 100) {
const messageIds = Array.from(globalAuthState.processingMessageIds);
globalAuthState.processingMessageIds = new Set(messageIds.slice(-50));
}
}
function usePostMessage({
authServiceUrl,
orgId,
environment,
iframe,
isIframeReady,
onAuthSuccess,
onAuthError,
onOidcReceived,
onOrgConfigUpdate,
setIsAuthenticated,
setUser,
setIsLoading,
setIsIframeReady,
cubistClient
}) {
const lastAuthStateRef = (0, import_react.useRef)({
isAuthenticated: false,
userId: null,
lastUpdateTime: 0
});
const hasRequestedOidcRef = (0, import_react.useRef)(false);
const isHandlingMessageRef = (0, import_react.useRef)(false);
const hasLoadedCacheRef = (0, import_react.useRef)(false);
(0, import_react.useEffect)(() => {
if (orgId && onOrgConfigUpdate && !hasLoadedCacheRef.current) {
hasLoadedCacheRef.current = true;
try {
const cachedConfigKey = `${ORG_CONFIG_CACHE_KEY}-${orgId}-${environment}`;
const cachedConfigJson = localStorage.getItem(cachedConfigKey);
if (cachedConfigJson) {
const cachedConfig = JSON.parse(cachedConfigJson);
const timestamp = cachedConfig._timestamp || 0;
const isExpired = Date.now() - timestamp > 30 * 60 * 1e3;
if (!isExpired) {
const { _timestamp, ...configWithoutTimestamp } = cachedConfig;
onOrgConfigUpdate(configWithoutTimestamp);
}
}
} catch (error) {
}
}
}, [orgId, environment, onOrgConfigUpdate]);
const sendMessage = (0, import_react.useCallback)((message) => {
if (iframe == null ? void 0 : iframe.contentWindow) {
try {
if (message.type === "SIGNUP_REQUEST") {
if (globalAuthState.signupInProgress) {
return;
}
const now = Date.now();
if (now - globalAuthState.lastSignupTimestamp < 3e3) {
return;
}
globalAuthState.signupInProgress = true;
globalAuthState.lastSignupTimestamp = now;
let finalMessage = message;
if (!message.requestId) {
finalMessage = {
...message,
requestId: `signup-${now}`
};
}
let messageToSend = finalMessage;
if (finalMessage.payload && typeof finalMessage.payload.email === "string" && typeof finalMessage.payload.password === "string") {
messageToSend = {
type: "SIGNUP_REQUEST",
email: finalMessage.payload.email,
password: finalMessage.payload.password,
requestId: finalMessage.requestId || `signup-${now}`
};
}
if ("requestId" in messageToSend && messageToSend.requestId) {
globalAuthState.processingMessageIds.add(messageToSend.requestId);
}
iframe.contentWindow.postMessage(messageToSend, authServiceUrl);
return;
}
if (message.type === "LOGIN_REQUEST") {
if (globalAuthState.loginInProgress) {
return;
}
const now = Date.now();
if (now - globalAuthState.lastLoginTimestamp < 3e3) {
return;
}
globalAuthState.loginInProgress = true;
globalAuthState.lastLoginTimestamp = now;
let finalMessage = message;
if (!message.requestId) {
finalMessage = {
...message,
requestId: `login-${now}`
};
}
if (finalMessage.requestId) {
globalAuthState.processingMessageIds.add(finalMessage.requestId);
}
iframe.contentWindow.postMessage(finalMessage, authServiceUrl);
return;
}
iframe.contentWindow.postMessage(message, authServiceUrl);
} catch (error) {
if (message.type === "SIGNUP_REQUEST") {
globalAuthState.signupInProgress = false;
}
if (message.type === "LOGIN_REQUEST") {
globalAuthState.loginInProgress = false;
}
}
}
}, [iframe, authServiceUrl]);
(0, import_react.useEffect)(() => {
const handleMessage = async (event) => {
var _a, _b, _c, _d, _e, _f, _g;
if (isHandlingMessageRef.current) {
return;
}
if (event.origin !== new URL(authServiceUrl).origin) {
return;
}
if (typeof ((_a = event.data) == null ? void 0 : _a.type) !== "string") {
return;
}
if (event.data.requestId && globalAuthState.processingMessageIds.has(event.data.requestId)) {
return;
}
try {
isHandlingMessageRef.current = true;
if (event.data.type === "ERROR") {
globalAuthState.signupInProgress = false;
globalAuthState.loginInProgress = false;
} else if (event.data.type === "AUTH_STATUS" && event.data.isAuthenticated) {
globalAuthState.signupInProgress = false;
globalAuthState.loginInProgress = false;
cleanupProcessedMessageIds();
} else if (event.data.type === "RECEIVE_OIDC") {
globalAuthState.signupInProgress = false;
globalAuthState.loginInProgress = false;
}
switch (event.data.type) {
case "IFRAME_READY":
setIsIframeReady(true);
break;
case "RECEIVE_OIDC":
if (typeof ((_b = event.data.payload) == null ? void 0 : _b.idToken) === "string") {
const oidcToken = event.data.payload.idToken;
hasRequestedOidcRef.current = false;
onOidcReceived == null ? void 0 : onOidcReceived(oidcToken);
} else {
hasRequestedOidcRef.current = false;
}
break;
case "AUTH_STATUS": {
const newIsAuthenticated = !!event.data.isAuthenticated;
const newUserId = (_d = (_c = event.data.user) == null ? void 0 : _c.sub) != null ? _d : null;
const now = Date.now();
if (now - lastAuthStateRef.current.lastUpdateTime < 500) {
return;
}
const authStateChanged = lastAuthStateRef.current.isAuthenticated !== newIsAuthenticated || lastAuthStateRef.current.userId !== newUserId;
if (authStateChanged) {
setIsAuthenticated(newIsAuthenticated);
if (event.data.user) {
const userInfo = {
email: event.data.user.email,
sub: event.data.user.sub,
configured_mfa: [],
displayName: event.data.user.nickname || event.data.user.name || ((_e = event.data.user.email) == null ? void 0 : _e.split("@")[0]) || "User",
rawUserData: event.data.user
};
setUser(userInfo);
if (newIsAuthenticated && !cubistClient && !hasRequestedOidcRef.current) {
hasRequestedOidcRef.current = true;
sendMessage({ type: "GET_OIDC" });
return;
}
} else {
setUser(null);
localStorage.removeItem(AUTH_TOKENS_KEY);
localStorage.removeItem(AUTH0_STORAGE_KEYS.IS_AUTHENTICATED);
sessionStorage.removeItem(OIDC_TOKEN_KEY);
}
lastAuthStateRef.current = {
isAuthenticated: newIsAuthenticated,
userId: newUserId,
lastUpdateTime: now
};
if (newIsAuthenticated && event.data.user) {
if (!hasRequestedOidcRef.current) {
if (event.data.tokens) {
localStorage.setItem(AUTH_TOKENS_KEY, JSON.stringify(event.data.tokens));
}
onAuthSuccess == null ? void 0 : onAuthSuccess();
}
}
}
if (event.data.orgConfig && onOrgConfigUpdate) {
onOrgConfigUpdate(event.data.orgConfig);
if (orgId) {
try {
const cachedConfigKey = `${ORG_CONFIG_CACHE_KEY}-${orgId}-${environment}`;
const configWithTimestamp = {
...event.data.orgConfig,
_timestamp: Date.now()
};
localStorage.setItem(cachedConfigKey, JSON.stringify(configWithTimestamp));
} catch (error) {
}
}
}
if (!hasRequestedOidcRef.current) {
setIsLoading(false);
}
break;
}
case "REGISTER_SUCCESS": {
const userId = (_f = event.data.payload) == null ? void 0 : _f.userId;
if (userId) {
localStorage.setItem(CUBIST_USER_ID_KEY, userId);
if (!hasRequestedOidcRef.current) {
hasRequestedOidcRef.current = true;
sendMessage({ type: "GET_OIDC" });
}
}
break;
}
case "ERROR":
if (event.data.error === "User not authenticated in iframe") {
isHandlingMessageRef.current = false;
return;
}
onAuthError == null ? void 0 : onAuthError(new Error((_g = event.data.error) != null ? _g : "Unknown error"));
setIsLoading(false);
break;
}
} finally {
isHandlingMessageRef.current = false;
}
};
window.addEventListener("message", handleMessage);
return () => window.removeEventListener("message", handleMessage);
}, [
authServiceUrl,
onAuthError,
onAuthSuccess,
onOidcReceived,
onOrgConfigUpdate,
setIsAuthenticated,
setIsIframeReady,
setIsLoading,
setUser,
sendMessage,
cubistClient,
orgId,
environment
]);
(0, import_react.useEffect)(() => {
if (isIframeReady && (iframe == null ? void 0 : iframe.contentWindow)) {
sendMessage({
type: "CHECK_AUTH_STATUS",
payload: {
orgId,
environment
}
});
}
}, [isIframeReady, iframe, sendMessage, orgId, environment]);
return {
sendMessage
};
}
// src/AuthModalContext.tsx
var import_react4 = require("react");
var import_core_k2_components4 = require("@avalabs/core-k2-components");
// src/components/Modal.tsx
var import_react3 = require("react");
var import_core_k2_components3 = require("@avalabs/core-k2-components");
// src/components/SignInContent.tsx
var import_react2 = require("react");
var import_core_k2_components2 = require("@avalabs/core-k2-components");
// src/components/PoweredByAvaCloud.tsx
var import_core_k2_components = require("@avalabs/core-k2-components");
var import_jsx_runtime = require("react/jsx-runtime");
function PoweredByAvaCloud() {
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_core_k2_components.Stack, { direction: "row", alignItems: "center", justifyContent: "center", spacing: 1, children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_core_k2_components.Typography, { variant: "body2", children: "Powered by" }),
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_core_k2_components.Stack, { direction: "row", alignItems: "center", spacing: 0.5, children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_core_k2_components.AvaCloudConnectIcon, {}),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_core_k2_components.Typography, { variant: "body2", children: "AvaCloud" })
] })
] });
}
// src/constants/legal.ts
var TERMS_OF_SERVICE_URL = "https://app.avacloud.io/legal/waas/user-terms";
var PRIVACY_POLICY_URL = "https://www.avalabs.org/privacy-policy";
// src/components/SignInContent.tsx
var import_jsx_runtime2 = require("react/jsx-runtime");
function SignInContent({
onEmailLogin,
onEmailSignup,
onProviderLogin,
error,
isSubmitting,
socialLogins = ["google", "x", "apple"]
}) {
const [email, setEmail] = (0, import_react2.useState)("");
const [password, setPassword] = (0, import_react2.useState)("");
const [isPasswordStep, setIsPasswordStep] = (0, import_react2.useState)(false);
const [isSignupMode, setIsSignupMode] = (0, import_react2.useState)(false);
const providerConnectionMap = {
"google": "google-oauth2",
"x": "twitter",
"twitter": "twitter",
"facebook": "facebook",
"apple": "apple"
};
const renderSocialLoginButton = (loginType) => {
if (!providerConnectionMap[loginType]) return null;
const connectionName = providerConnectionMap[loginType];
let LoginIcon;
switch (loginType) {
case "google":
LoginIcon = import_core_k2_components2.GoogleIcon;
break;
case "x":
case "twitter":
LoginIcon = import_core_k2_components2.XTwitterIcon;
break;
case "facebook":
LoginIcon = import_core_k2_components2.FacebookIcon;
break;
case "apple":
LoginIcon = import_core_k2_components2.AppleIcon;
break;
default:
return null;
}
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_core_k2_components2.IconButton,
{
color: "default",
variant: "contained",
onClick: () => onProviderLogin(connectionName),
disabled: isSubmitting,
sx: {
display: "flex",
padding: "16px",
alignItems: "center",
gap: "8px",
borderRadius: "8px",
background: "rgba(0, 0, 0, 0.02)",
boxShadow: "2px 1px 4px 0px rgba(0, 0, 0, 0.20)",
width: 72,
height: 72,
"&:hover": {
background: "rgba(0, 0, 0, 0.04)"
}
},
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LoginIcon, { sx: { width: 24, height: 24 } })
},
loginType
);
};
const handleEmailSubmit = (e) => {
e.preventDefault();
if (!email) return;
setIsPasswordStep(true);
};
const handlePasswordSubmit = (e) => {
e.preventDefault();
if (!password) return;
onEmailLogin(email, password);
};
const handleSignupSubmit = (e) => {
e.preventDefault();
if (!email || !password) return;
onEmailSignup(email, password);
};
const handleForgotPassword = () => {
};
const handleToggleSignup = () => {
setIsSignupMode(!isSignupMode);
setIsPasswordStep(false);
};
const titleTypography = {
alignSelf: "stretch",
color: (theme) => theme.palette.mode === "dark" ? "#FFFFFF" : "rgba(0, 0, 0, 0.80)",
fontFamily: "Inter",
fontSize: "16px",
fontStyle: "normal",
fontWeight: 700,
lineHeight: "150%"
};
if (isSignupMode) {
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core_k2_components2.Stack, { gap: 3, children: [
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core_k2_components2.Typography, { variant: "h6", sx: titleTypography, children: "Sign up with" }),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core_k2_components2.Stack, { direction: "row", spacing: 3, sx: { justifyContent: "center" }, children: socialLogins.map((loginType) => renderSocialLoginButton(loginType)) }),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core_k2_components2.Divider, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core_k2_components2.Typography, { variant: "body2", color: "text.secondary", children: "or" }) }),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("form", { onSubmit: handleSignupSubmit, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core_k2_components2.Stack, { gap: 2, children: [
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_core_k2_components2.TextField,
{
placeholder: "Enter email",
type: "email",
value: email,
onChange: (e) => setEmail(e.target.value),
fullWidth: true,
required: true,
disabled: isSubmitting,
error: !!error,
helperText: error,
sx: {
"& .MuiOutlinedInput-root": {
backgroundColor: (theme) => theme.palette.mode === "dark" ? "rgba(255, 255, 255, 0.05)" : "grey.50"
}
}
}
),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_core_k2_components2.TextField,
{
placeholder: "Create password",
type: "password",
value: password,
onChange: (e) => setPassword(e.target.value),
fullWidth: true,
required: true,
disabled: isSubmitting,
sx: {
"& .MuiOutlinedInput-root": {
backgroundColor: (theme) => theme.palette.mode === "dark" ? "rgba(255, 255, 255, 0.05)" : "grey.50"
}
}
}
),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_core_k2_components2.Button,
{
type: "submit",
variant: "contained",
fullWidth: true,
disabled: isSubmitting || !email || !password,
sx: {
height: 48,
backgroundColor: "#3A65FF",
borderRadius: 24,
textTransform: "none",
"&:hover": {
backgroundColor: "#2952E6"
}
},
children: "Sign up"
}
),
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
import_core_k2_components2.Typography,
{
variant: "body2",
sx: {
textAlign: "center",
"& a": {
color: "#3A65FF",
textDecoration: "none",
cursor: "pointer",
"&:hover": {
textDecoration: "underline"
}
}
},
children: [
"Already have an account?",
" ",
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_core_k2_components2.Button,
{
variant: "text",
onClick: handleToggleSignup,
sx: {
color: "#3A65FF",
textTransform: "none",
padding: "0 4px",
minWidth: "auto",
fontWeight: 600,
"&:hover": {
textDecoration: "underline",
backgroundColor: "transparent"
}
},
children: "Sign in"
}
)
]
}
)
] }) }),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PoweredByAvaCloud, {}),
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
import_core_k2_components2.Typography,
{
variant: "body2",
sx: {
textAlign: "center",
color: "text.secondary",
fontSize: "0.75rem",
"& a": {
color: "inherit",
textDecoration: "none",
"&:hover": {
textDecoration: "underline"
}
}
},
children: [
"By connecting, you agree to the",
" ",
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_core_k2_components2.Button,
{
variant: "text",
component: "a",
href: TERMS_OF_SERVICE_URL,
target: "_blank",
rel: "noopener noreferrer",
sx: {
color: "inherit",
p: 0,
minWidth: "auto",
textTransform: "none",
fontSize: "inherit",
fontWeight: "inherit",
"&:hover": {
textDecoration: "underline",
backgroundColor: "transparent"
}
},
children: "Terms of Service"
}
),
" ",
"and",
" ",
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_core_k2_components2.Button,
{
variant: "text",
component: "a",
href: PRIVACY_POLICY_URL,
target: "_blank",
rel: "noopener noreferrer",
sx: {
color: "inherit",
p: 0,
minWidth: "auto",
textTransform: "none",
fontSize: "inherit",
fontWeight: "inherit",
"&:hover": {
textDecoration: "underline",
backgroundColor: "transparent"
}
},
children: "Privacy Policy"
}
)
]
}
)
] });
}
if (isPasswordStep) {
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core_k2_components2.Stack, { gap: 3, children: [
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core_k2_components2.Typography, { variant: "h6", sx: titleTypography, children: "Sign in with" }),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("form", { onSubmit: handlePasswordSubmit, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core_k2_components2.Stack, { gap: 2, children: [
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_core_k2_components2.TextField,
{
placeholder: "Enter password",
type: "password",
value: password,
onChange: (e) => setPassword(e.target.value),
fullWidth: true,
required: true,
disabled: isSubmitting,
error: !!error,
helperText: error,
sx: {
"& .MuiOutlinedInput-root": {
backgroundColor: (theme) => theme.palette.mode === "dark" ? "rgba(255, 255, 255, 0.05)" : "grey.50"
}
}
}
),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_core_k2_components2.Button,
{
type: "submit",
variant: "contained",
fullWidth: true,
disabled: isSubmitting || !password,
sx: {
height: 48,
backgroundColor: "#3A65FF",
borderRadius: 24,
textTransform: "none",
"&:hover": {
backgroundColor: "#2952E6"
}
},
children: "Continue"
}
),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_core_k2_components2.Typography,
{
variant: "body2",
sx: {
textAlign: "center",
"& a": {
color: "#3A65FF",
textDecoration: "none",
cursor: "pointer",
"&:hover": {
textDecoration: "underline"
}
}
},
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_core_k2_components2.Button,
{
variant: "text",
onClick: handleForgotPassword,
sx: {
color: "#3A65FF",
textTransform: "none",
"&:hover": {
textDecoration: "underline",
backgroundColor: "transparent"
}
},
children: "Forget password?"
}
)
}
)
] }) }),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PoweredByAvaCloud, {}),
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
import_core_k2_components2.Typography,
{
variant: "body2",
sx: {
textAlign: "center",
color: "text.secondary",
fontSize: "0.75rem",
"& a": {
color: "inherit",
textDecoration: "none",
"&:hover": {
textDecoration: "underline"
}
}
},
children: [
"By continuing, you agree to our",
" ",
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_core_k2_components2.Button,
{
variant: "text",
component: "a",
href: TERMS_OF_SERVICE_URL,
target: "_blank",
rel: "noopener noreferrer",
sx: {
color: "inherit",
p: 0,
minWidth: "auto",
textTransform: "none",
fontSize: "inherit",
fontWeight: "inherit",
"&:hover": {
textDecoration: "underline",
backgroundColor: "transparent"
}
},
children: "Terms of Use"
}
),
" ",
"and",
" ",
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_core_k2_components2.Button,
{
variant: "text",
component: "a",
href: PRIVACY_POLICY_URL,
target: "_blank",
rel: "noopener noreferrer",
sx: {
color: "inherit",
p: 0,
minWidth: "auto",
textTransform: "none",
fontSize: "inherit",
fontWeight: "inherit",
"&:hover": {
textDecoration: "underline",
backgroundColor: "transparent"
}
},
children: "Privacy Policy"
}
)
]
}
)
] });
}
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core_k2_components2.Stack, { gap: 3, children: [
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core_k2_components2.Typography, { variant: "h6", sx: titleTypography, children: "Sign in with" }),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core_k2_components2.Stack, { direction: "row", spacing: 3, sx: { justifyContent: "center" }, children: socialLogins.map((loginType) => renderSocialLoginButton(loginType)) }),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core_k2_components2.Divider, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core_k2_components2.Typography, { variant: "body2", color: "text.secondary", children: "or" }) }),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("form", { onSubmit: handleEmailSubmit, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core_k2_components2.Stack, { gap: 2, children: [
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_core_k2_components2.TextField,
{
placeholder: "Enter email",
type: "email",
value: email,
onChange: (e) => setEmail(e.target.value),
fullWidth: true,
required: true,
disabled: isSubmitting,
error: !!error,
helperText: error,
sx: {
"& .MuiOutlinedInput-root": {
backgroundColor: (theme) => theme.palette.mode === "dark" ? "rgba(255, 255, 255, 0.05)" : "grey.50"
}
}
}
),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_core_k2_components2.Button,
{
type: "submit",
variant: "contained",
fullWidth: true,
disabled: isSubmitting || !email,
sx: {
height: 48,
backgroundColor: "#3A65FF",
borderRadius: 24,
textTransform: "none",
"&:hover": {
backgroundColor: "#2952E6"
}
},
children: "Continue"
}
),
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
import_core_k2_components2.Typography,
{
variant: "body2",
sx: {
textAlign: "center",
"& a": {
color: "#3A65FF",
textDecoration: "none",
cursor: "pointer",
"&:hover": {
textDecoration: "underline"
}
}
},
children: [
"Don't have an account?",
" ",
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_core_k2_components2.Button,
{
variant: "text",
onClick: handleToggleSignup,
sx: {
color: "#3A65FF",
textTransform: "none",
padding: "0 4px",
minWidth: "auto",
fontWeight: 600,
"&:hover": {
textDecoration: "underline",
backgroundColor: "transparent"
}
},
children: "Sign up"
}
)
]
}
)
] }) }),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PoweredByAvaCloud, {}),
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
import_core_k2_components2.Typography,
{
variant: "body2",
sx: {
textAlign: "center",
color: "text.secondary",
fontSize: "0.75rem",
"& a": {
color: "inherit",
textDecoration: "none",
"&:hover": {
textDecoration: "underline"
}
}
},
children: [
"By connecting, you agree to the",
" ",
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_core_k2_components2.Button,
{
variant: "text",
component: "a",
href: TERMS_OF_SERVICE_URL,
target: "_blank",
rel: "noopener noreferrer",
sx: {
color: "inherit",
p: 0,
minWidth: "auto",
textTransform: "none",
fontSize: "inherit",
fontWeight: "inherit",
"&:hover": {
textDecoration: "underline",
backgroundColor: "transparent"
}
},
children: "Terms of Service"
}
),
" ",
"and",
" ",
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_core_k2_components2.Button,
{
variant: "text",
component: "a",
href: PRIVACY_POLICY_URL,
target: "_blank",
rel: "noopener noreferrer",
sx: {
color: "inherit",
p: 0,
minWidth: "auto",
textTransform: "none",
fontSize: "inherit",
fontWeight: "inherit",
"&:hover": {
textDecoration: "underline",
backgroundColor: "transparent"
}
},
children: "Privacy Policy"
}
)
]
}
)
] });
}
// src/components/Modal.tsx
var import_jsx_runtime3 = require("react/jsx-runtime");
function LoginModal({ open, onClose }) {
var _a;
const { iframe, orgConfig, signup } = useAvaCloudWallet();
const [isSubmitting, setIsSubmitting] = (0, import_react3.useState)(false);
const [error, setError] = (0, import_react3.useState)("");
const timeoutIdRef = (0, import_react3.useRef)(null);
const signupInProgressRef = (0, import_react3.useRef)(false);
const lastSignupAttemptRef = (0, import_react3.useRef)(0);
const socialLogins = (_a = orgConfig == null ? void 0 : orgConfig.adminPortalSettings) == null ? void 0 : _a.socialLogins;
(0, import_react3.useEffect)(() => {
let requestInProgress = false;
const handleMessage = (event) => {
if (!event.data || typeof event.data.type !== "string") {
return;
}
if (event.data.type === "ERROR") {
if (event.data.payload === "User not authenticated in iframe") {
return;
}
setError(event.data.payload);
setIsSubmitting(false);
signupInProgressRef.current = false;
if (timeoutIdRef.current) {
clearTimeout(timeoutIdRef.current);
timeoutIdRef.current = null;
}
} else if (event.data.type === "AUTH_STATUS" && event.data.isAuthenticated) {
setIsSubmitting(false);
signupInProgressRef.current = false;
requestInProgress = false;
if (timeoutIdRef.current) {
clearTimeout(timeoutIdRef.current);
timeoutIdRef.current = null;
}
onClose();
} else if (event.data.type === "RECEIVE_OIDC") {
signupInProgressRef.current = false;
requestInProgress = false;
}
};
window.addEventListener("message", handleMessage);
return () => {
window.removeEventListener("message", handleMessage);
if (timeoutIdRef.current) {
clearTimeout(timeoutIdRef.current);
timeoutIdRef.current = null;
}
};
}, [onClose]);
const handleProviderLogin = (provider) => {
var _a2;
setError("");
if (!iframe) {
setError("Authentication service not available");
return;
}
(_a2 = iframe.contentWindow) == null ? void 0 : _a2.postMessage({
type: "LOGIN_REQUEST",
connection: provider,
requestId: `login-${Date.now()}`
}, "*");
onClose();
};
const handleEmailLogin = (email, password) => {
var _a2;
setError("");
setIsSubmitting(true);
if (!iframe) {
setError("Authentication service not available");
setIsSubmitting(false);
return;
}
if (timeoutIdRef.current) {
clearTimeout(timeoutIdRef.current);
timeoutIdRef.current = null;
}
(_a2 = iframe.contentWindow) == null ? void 0 : _a2.postMessage({
type: "LOGIN_REQUEST",
email,
password,
requestId: `login-${Date.now()}`
}, "*");
timeoutIdRef.current = setTimeout(() => {
setError("Authentication service timed out");
setIsSubmitting(false);
timeoutIdRef.current = null;
}, 1e4);
};
const handleEmailSignup = (email, password) => {
if (signupInProgressRef.current) {
return;
}
const now = Date.now();
if (now - lastSignupAttemptRef.current < 2e3) {
return;
}
lastSignupAttemptRef.current = now;
setError("");
setIsSubmitting(true);
signupInProgressRef.current = true;
if (timeoutIdRef.current) {
clearTimeout(timeoutIdRef.current);
timeoutIdRef.current = null;
}
try {
signup(email, password);
} catch (error2) {
setError("Failed to initiate signup");
setIsSubmitting(false);
signupInProgressRef.current = false;
return;
}
timeoutIdRef.current = setTimeout(() => {
setError("Authentication service timed out");
setIsSubmitting(false);
signupInProgressRef.current = false;
timeoutIdRef.current = null;
}, 1e4);
};
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
import_core_k2_components3.Dialog,
{
open,
maxWidth: "xs",
PaperProps: {
sx: {
borderRadius: "8px",
width: "100%",
maxWidth: 400,
maxHeight: "calc(100% - 64px)",
m: 2,
overflow: "visible",
bgcolor: (theme) => theme.palette.mode === "dark" ? "#1A1A1A" : "#ffffff",
backgroundImage: "none",
display: "flex",
flexDirection: "column",
position: "relative",
boxShadow: (theme) => theme.palette.mode === "dark" ? "0px 4px 6px 0px rgba(0, 0, 0, 0.3), 0px 15px 15px 0px rgba(0, 0, 0, 0.25)" : "0px 4px 6px 0px rgba(0, 0, 0, 0.16), 0px 15px 15px 0px rgba(0, 0, 0, 0.15)",
transition: "all 0.2s ease-in-out"
}
},
children: [
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
import_core_k2_components3.Stack,
{
direction: "row",
sx: {
display: "flex",
justifyContent: "space-between",
alignItems: "flex-start",
alignSelf: "stretch",
p: 3,
pb: 0
},
children: [
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
"img",
{
src: "https://images.ctfassets.net/9bazykntljf6/58QaXZf2yQ7MqI9A8MrKiX/d8f986355c6e321e1dee79f6e91575ec/avacloud.png",
alt: "AvaCloud",
style: {
height: 24,
objectFit: "contain"
}
}
),
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
import_core_k2_components3.IconButton,
{
onClick: onClose,
size: "small",
sx: {
color: (theme) => theme.palette.mode === "dark" ? "rgba(255, 255, 255, 0.54)" : "rgba(0, 0, 0, 0.54)",
padding: "4px",
marginTop: "-4px",
marginRight: "-4px",
"&:hover": {
backgroundColor: (theme) => theme.palette.mode === "dark" ? "rgba(255, 255, 255, 0.04)" : "rgba(0, 0, 0, 0.04)"
}
},
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_core_k2_components3.XIcon, { sx: { fontSize: 20 } })
}
)
]
}
),
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_core_k2_components3.DialogContent, { sx: { p: 3 }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
SignInContent,
{
onEmailLogin: handleEmailLogin,
onEmailSignup: handleEmailSignup,
onProviderLogin: handleProviderLogin,
error,
isSubmitting,
socialLogins
}
) })
]
}
);
}
// src/AuthModalContext.tsx
var import_jsx_runtime4 = require("react/jsx-runtime");
var AuthModalContext = (0, import_react4.createContext)(void 0);
function AuthModalProvider({ children }) {
const [isModalOpen, setIsModalOpen] = (0, import_react4.useState)(false);
const openLoginModal = (0, import_react4.useCallback)(() => setIsModalOpen(true), []);
const closeLoginModal = (0, import_react4.useCallback)(() => setIsModalOpen(false), []);
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(AuthModalContext.Provider, { value: { openLoginModal, closeLoginModal, isModalOpen }, children: [
children,
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
import_core_k2_components4.Dialog,
{
open: isModalOpen,
onClose: closeLoginModal,
maxWidth: "xs",
children: [
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core_k2_components4.DialogTitle, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("img", { src: "", alt: "AvaCloud Connect", style: { height: "32px" } }) }),
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core_k2_components4.DialogContent, { sx: { padding: 4 }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
LoginModal,
{
open: isModalOpen,
onClose: closeLoginModal
}
) })
]
}
)
] });
}
function useAuthModal() {
const context = (0, import_react4.useContext)(AuthModalContext);
if (context === void 0) {
throw new Error("useAuthModal must be used within an AuthModalProvider");
}
return context;
}
// src/AvaCloudWalletProvider.tsx
var import_cubesigner_sdk2 = require("@cubist-labs/cubesigner-sdk");
// src/providers/ViemContext.tsx
var import_react6 = require("react");
var import_viem = require("viem");
// src/hooks/useAuth.ts
var import_react5 = require("react");
function useAuth() {
const {
isAuthenticated,
isLoading,
user,
wallet,
logout,
loginWithCubist,
cubistClient,
cubistError
} = useAvaCloudWallet();
const { openLoginModal } = useAuthModal();
const login = (0, import_react5.useCallback)(() => {
openLoginModal();
}, [openLoginModal]);
return {
isAuthenticated,
isLoading,
user,
wallet,
login,
logout,
loginWithCubist,
cubistClient,
cubistError
};
}
// src/providers/ViemContext.tsx
var import_jsx_runtime5 = require("react/jsx-runtime");
var ViemContext = (0, import_react6.createContext)(null);
function ViemProvider({ children, rpcUrl, chainId, explorerUrl }) {
var _a, _b;
const [publicClient, setPublicClient] = (0, import_react6.useState)(null);
const [walletClient, setWalletClient] = (0, import_react6.useState)(null);
const [isConnected, setIsConnected] = (0, import_react6.useState)(false);
const [error, setError] = (0, import_react6.useState)(null);
const { cubistClient, wallet: authWallet } = useAuth();
(0, import_react6.useEffect)(() => {
const initClient = async () => {
var _a2;
try {
const transport = (0, import_viem.http)(rpcUrl);
const customChain = {
id: chainId,
name: `Chain ${chainId}`,
nativeCurrency: {
name: "AVAX",
symbol: "AVAX",
decimals: 18
},
rpcUrls: {
default: { http: [rpcUrl] },
public: { http: [rpcUrl] }
},
blockExplorers: explorerUrl ? {
default: {
name: "Explorer",
url: explorerUrl
}
} : void 0
};
const client = (0, import_viem.createPublicClient)({
transport,
chain: customChain
});
if ((_a2 = authWallet == null ? void 0 : authWallet.cubistWallet) == null ? void 0 : _a2.address) {
const walletInstance = (0, import_viem.createWalletClient)({
transport,
chain: customChain,
account: authWallet.cubistWallet.address
});
setWalletClient(walletInstance);
}
await client.getBlockNumber();
setPublicClient(client);
setIsConnected(true);
setError(null);
} catch (err) {
setError(err instanceof Error ? err : new Error("Failed to connect"));
setIsConnected(false);
}
};
initClient();
}, [rpcUrl, chainId, explorerUrl, (_a = authWallet == null ? void 0 : authWallet.cubistWallet) == null ? void 0 : _a.address]);
(0, import_react6.useEffect)(() => {
var _a2;
if (((_a2 = authWallet == null ? void 0 : authWallet.cubistWallet) == null ? void 0 : _a2.address) && publicClient && walletClient) {
setIsConnected(true);
} else {
setIsConnected(false);
}
}, [(_b = authWallet == null ? void 0 : authWallet.cubistWallet) == null ? void 0 : _b.address, publicClient, walletClient]);
const clearError = () => setError(null);
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
ViemContext.Provider,
{
value: {
publicClient,
walletClient,
setPublicClient,
setWalletClient,
chainId,
explorerUrl,
isConnected,
error,
clearError
},
children
}
);
}
function useViem() {
const context = (0, import_react6.useContext)(ViemContext);
if (!context) {
throw new Error("useViem must be used within a ViemProvider");
}
return context;
}
// src/hooks/useGlacier.ts
var import_react_query = require("@tanstack/react-query");
// src/services/glacier/client.ts
var GLACIER_API_BASE_URL = "https://glacier-api.avax.network";
var GlacierApiClient = class {
constructor() {
this.baseUrl = GLACIER_API_BASE_URL;
}
async getBlockchains() {
const response = await fetch(`${this.baseUrl}/v1/chains`);
if (!response.ok) {
throw new Error("Failed to fetch blockchains");
}
return response.json();
}
async getValidators(subnetId) {
const response = await fetch(`${this.baseUrl}/v1/subnets/${subnetId}/validators`);
if (!response.ok) {
throw new Error("Failed to fetch validators");
}
return response.json();
}
async getSubnets() {
const response = await fetch(`${this.baseUrl}/v1/subnets`);
if (!response.ok) {
throw new Error("Failed to fetch subnets");
}
return response.json();
}
async getBlockchain(chainId) {
const response = await fetch(`${this.baseUrl}/v1/chains/${chainId}`);
if (!response.ok) {
throw new Error("Failed to fetch blockchain");
}
return response.json();
}
async getBalance(address, chainId) {
const chain = await this.getBlockchain(chainId);
const response = await fetch(chain.rpcUrl, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "eth_getBalance",
params: [address, "latest"]
})
});
if (!response.ok) {
throw new Error("Failed to fetch balance");
}
const data = await response.json();
return data.result;
}
async getERC20Balances(address, chainId) {
const response = await fetch(`${this.baseUrl}/v1/chains/${chainId}/addresses/${address}/balances:listErc20`);
if (!response.ok) {
throw new Error("Fa