@dynamic-labs/sdk-react-core
Version:
A React SDK for implementing wallet web3 authentication and authorization to your website.
276 lines (271 loc) • 14.8 kB
JavaScript
'use client'
;
Object.defineProperty(exports, '__esModule', { value: true });
var _tslib = require('../../../../../_virtual/_tslib.cjs');
var React = require('react');
var utils = require('@dynamic-labs/utils');
var walletConnectorCore = require('@dynamic-labs/wallet-connector-core');
var sdkApiCore = require('@dynamic-labs/sdk-api-core');
var UserWalletsContext = require('../../../context/UserWalletsContext/UserWalletsContext.cjs');
require('../../../config/ApiEndpoint.cjs');
require('../../../store/state/projectSettings/projectSettings.cjs');
require('../../constants/values.cjs');
require('@dynamic-labs/multi-wallet');
require('../../../shared/logger.cjs');
require('../../constants/colors.cjs');
require('react-international-phone');
require('@dynamic-labs/iconic');
require('react/jsx-runtime');
require('../../../context/ViewContext/ViewContext.cjs');
require('@dynamic-labs/wallet-book');
require('../../../shared/consts/index.cjs');
require('../../../store/state/nonce/nonce.cjs');
var shouldManuallyReconnectOnRefresh = require('../../functions/shouldManuallyReconnectOnRefresh/shouldManuallyReconnectOnRefresh.cjs');
var updatePrimaryWalletId = require('../../functions/updatePrimaryWalletId/updatePrimaryWalletId.cjs');
var getWalletUniqueId = require('../../functions/getWalletUniqueId/getWalletUniqueId.cjs');
var connectedWalletsInfo = require('../../../store/state/connectedWalletsInfo/connectedWalletsInfo.cjs');
require('../../../store/state/dynamicContextProps/dynamicContextProps.cjs');
var primaryWalletId = require('../../../store/state/primaryWalletId/primaryWalletId.cjs');
require('../../../store/state/user/user.cjs');
var session = require('../../../data/api/session/session.cjs');
require('../../../locale/locale.cjs');
var isConnectOnly = require('../authenticationHooks/helpers/isConnectOnly.cjs');
var getWalletConnectorForWallet = require('../../functions/getWalletConnectorForWallet/getWalletConnectorForWallet.cjs');
var useDebounce = require('../useDebounce/useDebounce.cjs');
var authMode = require('../../../store/state/authMode/authMode.cjs');
var updateUserWalletsFromConnectedWallets = require('./updateUserWalletsFromConnectedWallets/updateUserWalletsFromConnectedWallets.cjs');
const useConnectWallet = ({ enableVisitTrackingOnConnectOnly, environmentId, primaryWalletId: primaryWalletId$1, walletConnectorOptions, handleConnectedWallet, setShowAuthFlow, isBridgeFlow, }) => {
const connectedWalletsInfo$1 = connectedWalletsInfo.useConnectedWalletsInfo();
const [connectedWallets, _setConnectedWallets] = React.useState([]);
const { setUserWallets, addedWalletsIds, removedWalletsIds } = UserWalletsContext.useInternalUserWallets();
/** This wrapper is to ensure userWallets is always properly updated alongside connectedWallets */
const setConnectedWallets = React.useCallback((newWallets) => {
// Prevent unnecessary re-renders when state is empty
_setConnectedWallets((prevWallets) => {
if (prevWallets.length === 0 && newWallets.length === 0) {
return prevWallets;
}
return newWallets;
});
setUserWallets((userWallets) => updateUserWalletsFromConnectedWallets.updateUserWalletsFromConnectedWallets(userWallets, newWallets));
}, [setUserWallets]);
const disconnectWallet = React.useCallback((walletId) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
const walletToDisconnect = connectedWallets.find((wallet) => wallet.id === walletId);
yield (walletToDisconnect === null || walletToDisconnect === void 0 ? void 0 : walletToDisconnect.connector.endSession());
const updatedConnectedWalletsInfo = connectedWalletsInfo$1.filter((wallet) => wallet.id !== walletId);
connectedWalletsInfo.setConnectedWalletsInfo(updatedConnectedWalletsInfo);
removedWalletsIds.current.push(walletId);
if (walletId !== primaryWalletId$1) {
return;
}
const hasConnectedWallet = updatedConnectedWalletsInfo.length > 0;
if (isBridgeFlow || !hasConnectedWallet) {
primaryWalletId.resetPrimaryWalletId();
}
else {
updatePrimaryWalletId.updatePrimaryWalletId(updatedConnectedWalletsInfo[0].id);
}
}), [
connectedWallets,
connectedWalletsInfo$1,
isBridgeFlow,
primaryWalletId$1,
removedWalletsIds,
]);
// The function to update and define the connectedWallets list.
// It should be called on the first render, when connectedWalletsInfo updates and when walletConnectorOptions updates.
// To avoid unnecessary updates that are causing issues with connectors added asynchronously,
// we're debouncing this function
const updateConnectedWalletsList = useDebounce.useDebounce(() => _tslib.__awaiter(void 0, void 0, void 0, function* () {
const walletConnectors = walletConnectorOptions.map((wallet) => wallet.walletConnector);
if (!walletConnectors.length) {
return;
}
const updatedConnectedWallets = (yield Promise.all(connectedWalletsInfo$1.map((storedConnectedWalletInfo) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
const walletConnector = walletConnectorCore.getWalletConnectorByKey(walletConnectors, storedConnectedWalletInfo.walletConnectorKey);
if (!walletConnector) {
walletConnectorCore.logger.error('Could not find walletConnector: ' +
storedConnectedWalletInfo.walletConnectorKey);
yield disconnectWallet(storedConnectedWalletInfo.id);
return null;
}
if (walletConnectorCore.isHardwareWalletConnector(walletConnector) &&
storedConnectedWalletInfo.hardwareWallet ===
sdkApiCore.HardwareWalletEnum.Ledger) {
walletConnector.isHardwareWalletEnabled = true;
}
const [walletAddress] = yield walletConnector.getConnectedAccounts();
if (!walletAddress) {
yield disconnectWallet(storedConnectedWalletInfo.id);
return null;
}
const additionalAddresses = yield walletConnector.getAdditionalAddresses(walletAddress);
const walletChain = walletConnector.connectedChain;
const walletObject = walletConnector.createWallet({
additionalAddresses,
address: walletAddress,
chain: walletChain,
connector: walletConnector,
id: storedConnectedWalletInfo.id,
isAuthenticated: false,
key: walletConnector.key,
});
return walletObject;
})))).filter((wallet) => Boolean(wallet));
setConnectedWallets(updatedConnectedWallets);
}), 300);
// Generate the connectedWallets list when connectedWalletsInfo (localStorage) or memoized wallet connector updates
React.useEffect(() => {
updateConnectedWalletsList();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [connectedWalletsInfo$1, walletConnectorOptions]);
const updateConnectedWalletById = React.useCallback((walletId, walletObject) => {
var _a;
const clonedConnectedWalletsList = [...connectedWallets];
const connectedWalletIndex = clonedConnectedWalletsList.findIndex((connectedWallet) => connectedWallet.id === walletId);
if (connectedWalletIndex < 0) {
return;
}
clonedConnectedWalletsList[connectedWalletIndex] =
clonedConnectedWalletsList[connectedWalletIndex].connector.createWallet(Object.assign(Object.assign({}, clonedConnectedWalletsList[connectedWalletIndex]), { address: (_a = walletObject.address) !== null && _a !== void 0 ? _a : clonedConnectedWalletsList[connectedWalletIndex].address, connector: getWalletConnectorForWallet.getWalletConnectorForWallet(clonedConnectedWalletsList[connectedWalletIndex]) }));
setConnectedWallets(clonedConnectedWalletsList);
}, [connectedWallets, setConnectedWallets]);
// Keeps connected wallet data inside localStorage
const applyConnectedWalletToStore = React.useCallback(({ walletId, walletConnectorKey, walletChain, provider, }) => {
const updatedConnectedWalletsInfo = [...connectedWalletsInfo$1];
const walletConnectors = walletConnectorOptions.map((wallet) => wallet.walletConnector);
const walletConnector = walletConnectorCore.getWalletConnectorByKey(walletConnectors, walletConnectorKey);
const hardwareWallet = walletConnector &&
walletConnectorCore.isHardwareWalletConnector(walletConnector) &&
walletConnector.isHardwareWalletEnabled
? sdkApiCore.HardwareWalletEnum.Ledger
: undefined;
updatedConnectedWalletsInfo.push({
hardwareWallet,
id: walletId,
provider,
walletChain,
walletConnectorKey,
});
connectedWalletsInfo.setConnectedWalletsInfo(updatedConnectedWalletsInfo);
}, [connectedWalletsInfo$1, walletConnectorOptions]);
// Updates connected wallet (network and address) and verifies connected wallet connection
const refreshConnectedWallet = (walletId, walletConnector) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
if (shouldManuallyReconnectOnRefresh.shouldManuallyReconnectOnRefresh(walletConnector)) {
yield walletConnector.connect();
}
const currentWalletConnectorAddress = yield walletConnector.getAddress();
if (currentWalletConnectorAddress && handleConnectedWallet) {
const shouldProceedWithConnection = yield handleConnectedWallet({
address: currentWalletConnectorAddress,
chain: walletConnector.connectedChain,
connector: walletConnector,
});
if (!shouldProceedWithConnection) {
walletConnectorCore.logger.info('Connection was not established because handleConnectedWallet returned false');
disconnectWallet(walletId);
setShowAuthFlow(false, { emitCancelAuth: true });
return;
}
}
updateConnectedWalletById(walletId, {
address: currentWalletConnectorAddress,
});
});
const connectWallet = React.useCallback((walletConnector, getAddressOpts, options) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
const { applyHandleConnectedWallet = true } = options !== null && options !== void 0 ? options : {};
let walletAddress;
try {
walletAddress = yield walletConnector.getAddress(getAddressOpts);
}
catch (error) {
if (error instanceof utils.CustomError) {
throw error;
}
}
// Throw a generic error for any errors we're not processing above
if (!walletAddress) {
throw new utils.MissingPublicAddressError();
}
if (handleConnectedWallet && applyHandleConnectedWallet) {
const shouldProceedWithConnection = yield handleConnectedWallet({
address: walletAddress,
chain: walletConnector.connectedChain,
connector: walletConnector,
});
if (!shouldProceedWithConnection) {
walletConnectorCore.logger.info('Connection was not established because handleConnectedWallet returned false');
setShowAuthFlow(false);
return;
}
}
const isWalletStored = connectedWalletsInfo$1.some(({ walletConnectorKey: storedWalletConnectorKey }) => storedWalletConnectorKey === walletConnector.key);
const walletChain = walletConnector.connectedChain;
const authMode$1 = authMode.getAuthMode();
const shouldCreateVisit = !isWalletStored &&
(authMode$1 !== 'connect-only' || enableVisitTrackingOnConnectOnly);
if (shouldCreateVisit) {
// send information to backend to kick off background jobs
// so verify/sign on the next step could go by more quickly
// this is async work, but DO NOT AWAIT
session.createVisit({
authMode: authMode$1,
chain: walletChain || '',
environmentId,
publicWalletAddress: walletAddress,
walletName: walletConnector.key,
walletProvider: walletConnectorCore.getWalletProvider(walletConnector),
});
}
// On connect and sign, we don't want to add this wallet to userWallets
// until it has been signed. Therefore, we don't add it to
// the connectedWallets array because userWallets draws from it.
// In this scenario we only need the wallet address, since the id will come from somewhere else.
// In fact, there is a refactor planned to never use the connect-wallet-X ids anymore:
// https://linear.app/dynamic-labs/issue/QNTM-784/rework-the-way-we-compute-wallet-ids
if (!isConnectOnly.isConnectOnly())
return { address: walletAddress, id: '' };
const walletId = getWalletUniqueId.getWalletUniqueId({
address: walletAddress,
chain: walletConnector.connectedChain,
connectorKey: walletConnector.key,
});
if (!primaryWalletId$1) {
updatePrimaryWalletId.updatePrimaryWalletId(walletId);
}
addedWalletsIds.current.push(walletId);
if (isWalletStored) {
yield updateConnectedWalletsList();
}
else {
applyConnectedWalletToStore({
provider: walletConnectorCore.getWalletProvider(walletConnector),
walletAddress: walletAddress,
walletChain,
walletConnectorKey: walletConnector.key,
walletId,
});
}
return { address: walletAddress, id: walletId };
}), [
addedWalletsIds,
applyConnectedWalletToStore,
connectedWalletsInfo$1,
enableVisitTrackingOnConnectOnly,
environmentId,
handleConnectedWallet,
primaryWalletId$1,
setShowAuthFlow,
updateConnectedWalletsList,
]);
const getConnectedWalletById = React.useCallback((walletId) => connectedWallets.find((wallet) => wallet.id === walletId), [connectedWallets]);
return {
connectWallet,
connectedWallets,
connectedWalletsInfo: connectedWalletsInfo$1,
disconnectWallet,
getConnectedWalletById,
refreshConnectedWallet,
};
};
exports.useConnectWallet = useConnectWallet;