@web3auth/no-modal
Version:
Multi chain wallet aggregator for web3Auth
192 lines (188 loc) • 7.66 kB
JavaScript
import _objectSpread from '@babel/runtime/helpers/objectSpread2';
import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProperties';
import { createWalletStandardConnector, createClient } from '@solana/client';
import { SolanaProvider as SolanaProvider$1 } from '@solana/react-hooks';
import { createElement, useRef, useState, useEffect } from 'react';
import { useWeb3Auth } from '../hooks/useWeb3Auth.js';
import { useChain } from '../hooks/useChain.js';
import { CHAIN_NAMESPACES } from '@toruslabs/base-controllers';
import { log } from '../../base/loglevel.js';
import { getCaipChainId } from '../../base/utils.js';
const _excluded = ["children"];
const DEVNET_ENDPOINT = "https://api.devnet.solana.com";
function placeholderRpc(isInitialized, web3Auth) {
var _web3Auth$coreOptions;
if (!isInitialized || !(web3Auth !== null && web3Auth !== void 0 && (_web3Auth$coreOptions = web3Auth.coreOptions) !== null && _web3Auth$coreOptions !== void 0 && _web3Auth$coreOptions.chains)) {
return {
rpcTarget: DEVNET_ENDPOINT
};
}
const solanaChains = web3Auth.coreOptions.chains.filter(c => c.chainNamespace === CHAIN_NAMESPACES.SOLANA);
const current = web3Auth.currentChain;
const chain = (current === null || current === void 0 ? void 0 : current.chainNamespace) === CHAIN_NAMESPACES.SOLANA ? current : solanaChains[0];
if (!chain) return {
rpcTarget: DEVNET_ENDPOINT
};
return {
rpcTarget: chain.rpcTarget,
wsTarget: chain.wsTarget
};
}
function makePlaceholder(rpc) {
return createClient({
endpoint: rpc.rpcTarget,
websocketEndpoint: rpc.wsTarget,
walletConnectors: []
});
}
function dispose(client) {
client.destroy();
}
function resolveSolanaChain(web3Auth, connection) {
var _web3Auth$coreOptions3;
const currentChain = web3Auth === null || web3Auth === void 0 ? void 0 : web3Auth.currentChain;
if ((currentChain === null || currentChain === void 0 ? void 0 : currentChain.chainNamespace) === CHAIN_NAMESPACES.SOLANA) {
return currentChain;
}
const connectedScope = connection !== null && connection !== void 0 && connection.solanaWallet && "scope" in connection.solanaWallet && typeof connection.solanaWallet.scope === "string" ? connection.solanaWallet.scope : null;
if (connectedScope) {
var _web3Auth$coreOptions2;
const connectedChain = web3Auth === null || web3Auth === void 0 || (_web3Auth$coreOptions2 = web3Auth.coreOptions.chains) === null || _web3Auth$coreOptions2 === void 0 ? void 0 : _web3Auth$coreOptions2.find(chain => {
return chain.chainNamespace === CHAIN_NAMESPACES.SOLANA && getCaipChainId(chain) === connectedScope;
});
if (connectedChain) return connectedChain;
}
return (web3Auth === null || web3Auth === void 0 || (_web3Auth$coreOptions3 = web3Auth.coreOptions.chains) === null || _web3Auth$coreOptions3 === void 0 ? void 0 : _web3Auth$coreOptions3.find(chain => chain.chainNamespace === CHAIN_NAMESPACES.SOLANA)) || null;
}
/**
* Builds the SolanaClient for Framework Kit React hooks.
* For multichain wallets, keep the Solana client warm across namespace switches so
* switching back to Solana can reuse the existing wallet session.
*/
function useFrameworkKitSolanaClient() {
const {
isConnected,
connection,
web3Auth,
isInitialized
} = useWeb3Auth();
const {
chainId,
chainNamespace
} = useChain();
const solClientRef = useRef(null);
const connectedClientRef = useRef(null);
const [client, setClient] = useState(() => {
const c = makePlaceholder({
rpcTarget: DEVNET_ENDPOINT
});
solClientRef.current = c;
return c;
});
useEffect(() => {
if (isInitialized) web3Auth === null || web3Auth === void 0 || web3Auth.setAnalyticsProperties({
solana_framework_kit_enabled: true
});
}, [isInitialized, web3Auth]);
useEffect(() => () => {
const connectedClient = connectedClientRef.current;
const currentClient = solClientRef.current;
if (currentClient) {
dispose(currentClient);
solClientRef.current = null;
}
if (connectedClient && connectedClient !== currentClient) {
dispose(connectedClient);
}
connectedClientRef.current = null;
}, []);
useEffect(() => {
let stale = false;
const adopt = nextClient => {
if (stale) {
dispose(nextClient);
return;
}
const prevClient = solClientRef.current;
if (prevClient === nextClient) return;
if (prevClient) dispose(prevClient);
solClientRef.current = nextClient;
setClient(nextClient);
};
(async () => {
const rpc = placeholderRpc(isInitialized, web3Auth);
const conn = connection;
const currentChain = web3Auth === null || web3Auth === void 0 ? void 0 : web3Auth.currentChain;
if ((currentChain === null || currentChain === void 0 ? void 0 : currentChain.chainNamespace) !== CHAIN_NAMESPACES.SOLANA) {
adopt(makePlaceholder(rpc));
return;
}
const preferredSolanaChain = resolveSolanaChain(web3Auth, conn);
const shouldKeepSolanaClient = isConnected && Boolean(conn === null || conn === void 0 ? void 0 : conn.solanaWallet) && Boolean(preferredSolanaChain) &&
// only manage the client for the primary connector
(conn === null || conn === void 0 ? void 0 : conn.connectorName) === (web3Auth === null || web3Auth === void 0 ? void 0 : web3Auth.primaryConnectorName);
if (!shouldKeepSolanaClient) {
const connectedClient = connectedClientRef.current;
connectedClientRef.current = null;
if (connectedClient) {
dispose(connectedClient);
}
adopt(makePlaceholder(rpc));
return;
}
try {
const solanaWalletId = "wallet-standard:" + conn.connectorName;
const connector = createWalletStandardConnector(conn.solanaWallet, {
id: solanaWalletId,
name: conn.connectorName
});
const {
rpcTarget,
wsTarget
} = preferredSolanaChain;
const wired = createClient({
endpoint: rpcTarget,
websocketEndpoint: wsTarget,
walletConnectors: [connector]
});
await wired.actions.connectWallet(solanaWalletId, {
autoConnect: true
});
if (stale) {
dispose(wired);
return;
}
const prevConnectedClient = connectedClientRef.current;
connectedClientRef.current = wired;
if (chainNamespace === CHAIN_NAMESPACES.SOLANA && (currentChain === null || currentChain === void 0 ? void 0 : currentChain.chainNamespace) === CHAIN_NAMESPACES.SOLANA) {
adopt(wired);
} else {
adopt(makePlaceholder(rpc));
}
if (prevConnectedClient && prevConnectedClient !== wired) {
dispose(prevConnectedClient);
}
} catch (e) {
log.error("Failed to create or connect Solana client", e);
adopt(makePlaceholder(rpc));
}
})();
return () => {
stale = true;
};
}, [isConnected, connection === null || connection === void 0 ? void 0 : connection.solanaWallet, chainId, chainNamespace, web3Auth, isInitialized, connection === null || connection === void 0 ? void 0 : connection.connectorName]);
return client;
}
function SolanaProvider(_ref) {
let {
children
} = _ref,
props = _objectWithoutProperties(_ref, _excluded);
const client = useFrameworkKitSolanaClient();
return createElement(SolanaProvider$1, _objectSpread(_objectSpread({}, props), {}, {
client,
walletPersistence: false,
children
}));
}
export { SolanaProvider };