@web3auth/no-modal
Version:
Multi chain wallet aggregator for web3Auth
169 lines (165 loc) • 7.66 kB
JavaScript
;
var client = require('@solana/client');
var vue = require('vue');
require('@babel/runtime/helpers/objectSpread2');
require('@babel/runtime/helpers/defineProperty');
require('@segment/analytics-next');
var loglevel = require('../../base/loglevel.js');
var baseControllers = require('@toruslabs/base-controllers');
require('@toruslabs/session-manager');
require('@web3auth/auth');
require('../../base/errors/index.js');
var utils = require('../../base/utils.js');
require('../../base/wallet/index.js');
require('../../base/connector/connectorStatus.js');
require('../../base/connector/constants.js');
require('jwt-decode');
require('../../base/constants.js');
require('../../base/plugin/errors.js');
require('../../base/plugin/IPlugin.js');
var useChain = require('../composables/useChain.js');
var useWeb3Auth = require('../composables/useWeb3Auth.js');
var constants = require('./constants.js');
const disposeClient = async client => {
client.destroy();
};
const resolveSolanaChain = (web3Auth, connection) => {
var _web3Auth$coreOptions2;
const currentChain = web3Auth === null || web3Auth === void 0 ? void 0 : web3Auth.currentChain;
if ((currentChain === null || currentChain === void 0 ? void 0 : currentChain.chainNamespace) === baseControllers.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$coreOptions;
const connectedChain = web3Auth === null || web3Auth === void 0 || (_web3Auth$coreOptions = web3Auth.coreOptions.chains) === null || _web3Auth$coreOptions === void 0 ? void 0 : _web3Auth$coreOptions.find(chain => {
return chain.chainNamespace === baseControllers.CHAIN_NAMESPACES.SOLANA && utils.getCaipChainId(chain) === connectedScope;
});
if (connectedChain) return connectedChain;
}
return (web3Auth === null || web3Auth === void 0 || (_web3Auth$coreOptions2 = web3Auth.coreOptions.chains) === null || _web3Auth$coreOptions2 === void 0 ? void 0 : _web3Auth$coreOptions2.find(chain => chain.chainNamespace === baseControllers.CHAIN_NAMESPACES.SOLANA)) || null;
};
/**
* Syncs Web3Auth Solana connection with Framework Kit client.
* For multichain wallets, keep the Solana client warm across namespace switches so
* switching back to Solana can reuse the existing wallet session.
*/
const SolanaProvider = vue.defineComponent({
name: "SolanaProvider",
setup(_, {
slots
}) {
const {
isConnected,
connection,
web3Auth
} = useWeb3Auth.useWeb3Auth();
const {
chainId
} = useChain.useChain();
const clientRef = vue.ref(null);
let connectedClient = null;
// let connectedClientKey: string | null = null;
// Holds the token for the newest requested sync run. Older async runs compare against it
// before publishing results so a slower reconnect cannot overwrite a newer chain/account update.
let activeSyncToken = null;
// provide the client to the app
vue.provide(constants.SOLANA_CLIENT_KEY, clientRef);
const syncClient = async () => {
var _web3Auth$value, _web3Auth$value2;
// Only the latest async, `syncing` run should be allowed to attach its client.
// A fresh Symbol gives each run a unique identity without relying on counters.
const syncToken = Symbol("solana-client-sync");
activeSyncToken = syncToken;
const newIsConnected = isConnected.value;
const newConnection = connection.value;
const currentChain = (_web3Auth$value = web3Auth.value) === null || _web3Auth$value === void 0 ? void 0 : _web3Auth$value.currentChain;
if ((currentChain === null || currentChain === void 0 ? void 0 : currentChain.chainNamespace) !== baseControllers.CHAIN_NAMESPACES.SOLANA) {
// Mirror the React provider behavior: hide the live Solana client from injected
// consumers whenever Web3Auth is currently scoped to a non-Solana namespace.
clientRef.value = null;
return;
}
const preferredSolanaChain = resolveSolanaChain(web3Auth.value, newConnection);
const shouldKeepSolanaClient = newIsConnected && Boolean(newConnection === null || newConnection === void 0 ? void 0 : newConnection.solanaWallet) && Boolean(preferredSolanaChain) &&
// only manage the client for the primary connector
(newConnection === null || newConnection === void 0 ? void 0 : newConnection.connectorName) === ((_web3Auth$value2 = web3Auth.value) === null || _web3Auth$value2 === void 0 ? void 0 : _web3Auth$value2.primaryConnectorName);
if (!shouldKeepSolanaClient) {
clientRef.value = null;
const prevClient = connectedClient;
connectedClient = null;
// connectedClientKey = null;
if (prevClient) {
await disposeClient(prevClient);
}
return;
}
let client$1 = null;
try {
// create a wallet standard connector from connected wallet
const solanaWalletId = "wallet-standard:" + newConnection.connectorName;
const connector = client.createWalletStandardConnector(newConnection.solanaWallet, {
id: solanaWalletId,
name: newConnection.connectorName
});
// create a solana client
const {
rpcTarget,
wsTarget
} = preferredSolanaChain;
client$1 = client.createClient({
endpoint: rpcTarget,
websocketEndpoint: wsTarget,
walletConnectors: [connector]
});
// connect the client to the wallet
await client$1.actions.connectWallet(solanaWalletId, {
autoConnect: true
});
// If another sync started while connectWallet was in flight, this client is stale.
if (activeSyncToken !== syncToken) {
await disposeClient(client$1);
return;
}
const prevClient = connectedClient;
connectedClient = client$1;
// connectedClientKey = nextClientKey;
clientRef.value = (currentChain === null || currentChain === void 0 ? void 0 : currentChain.chainNamespace) === baseControllers.CHAIN_NAMESPACES.SOLANA ? client$1 : null;
if (prevClient) {
await disposeClient(prevClient);
}
} catch (err) {
if (client$1) {
await disposeClient(client$1);
}
loglevel.log.error("Failed to create or connect Solana client", err);
// Only clear the shared ref when this failing run is still the newest one.
if (activeSyncToken === syncToken) {
clientRef.value = null;
}
}
};
// watch for changes in the connection and active chain
vue.watch([isConnected, connection, chainId], () => {
void syncClient();
}, {
immediate: true
});
vue.onBeforeUnmount(() => {
const publishedClient = clientRef.value;
clientRef.value = null;
const prevClient = connectedClient;
connectedClient = null;
if (prevClient) {
void disposeClient(prevClient);
} else if (publishedClient) {
void disposeClient(publishedClient);
}
});
return () => {
var _slots$default, _slots$default2;
return vue.h(vue.Fragment, null, (_slots$default = (_slots$default2 = slots.default) === null || _slots$default2 === void 0 ? void 0 : _slots$default2.call(slots)) !== null && _slots$default !== void 0 ? _slots$default : []);
};
}
});
exports.SolanaProvider = SolanaProvider;