UNPKG

@hyperlane-xyz/widgets

Version:

Common react components for Hyperlane projects

299 lines 13.6 kB
import { useMemo } from 'react'; import { cosmoshub } from '@hyperlane-xyz/registry'; import { ProtocolType } from '@hyperlane-xyz/utils'; import { widgetLogger } from '../logger.js'; import { useCosmosAccount, useCosmosActiveChain, useCosmosConnectFn, useCosmosDisconnectFn, useCosmosTransactionFns, useCosmosWalletDetails, useCosmosWatchAsset, } from './cosmos.js'; import { useEthereumAccount, useEthereumActiveChain, useEthereumConnectFn, useEthereumDisconnectFn, useEthereumTransactionFns, useEthereumWalletDetails, useEthereumWatchAsset, } from './ethereum.js'; import { useRadixAccount, useRadixActiveChain, useRadixConnectFn, useRadixDisconnectFn, useRadixTransactionFns, useRadixWalletDetails, useRadixWatchAsset, } from './radix.js'; import { useSolanaAccount, useSolanaActiveChain, useSolanaConnectFn, useSolanaDisconnectFn, useSolanaTransactionFns, useSolanaWalletDetails, useSolanaWatchAsset, } from './solana.js'; import { useStarknetAccount, useStarknetActiveChain, useStarknetConnectFn, useStarknetDisconnectFn, useStarknetTransactionFns, useStarknetWalletDetails, useStarknetWatchAsset, } from './starknet.js'; const logger = widgetLogger.child({ module: 'walletIntegrations/multiProtocol', }); export function useAccounts(multiProvider, blacklistedAddresses = []) { const evmAccountInfo = useEthereumAccount(multiProvider); const solAccountInfo = useSolanaAccount(multiProvider); const cosmAccountInfo = useCosmosAccount(multiProvider); const starknetAccountInfo = useStarknetAccount(multiProvider); const radixAccountInfo = useRadixAccount(multiProvider); // Filtered ready accounts const readyAccounts = useMemo(() => [ evmAccountInfo, solAccountInfo, cosmAccountInfo, starknetAccountInfo, radixAccountInfo, ].filter((a) => a.isReady), [ evmAccountInfo, solAccountInfo, cosmAccountInfo, starknetAccountInfo, radixAccountInfo, ]); // Check if any of the ready accounts are blacklisted const readyAddresses = readyAccounts .map((a) => a.addresses) .flat() .map((a) => a.address.toLowerCase()); if (readyAddresses.some((a) => blacklistedAddresses.includes(a))) { throw new Error('Wallet address is blacklisted'); } return useMemo(() => ({ accounts: { [ProtocolType.Ethereum]: evmAccountInfo, [ProtocolType.Sealevel]: solAccountInfo, [ProtocolType.Cosmos]: cosmAccountInfo, [ProtocolType.CosmosNative]: cosmAccountInfo, [ProtocolType.Starknet]: starknetAccountInfo, [ProtocolType.Radix]: radixAccountInfo, [ProtocolType.Aleo]: evmAccountInfo, // TODO: implement this once we have a Aleo wallet connection }, readyAccounts, }), [ evmAccountInfo, solAccountInfo, cosmAccountInfo, starknetAccountInfo, radixAccountInfo, readyAccounts, ]); } export function useAccountForChain(multiProvider, chainName) { const { accounts } = useAccounts(multiProvider); const protocol = chainName ? multiProvider.getProtocol(chainName) : undefined; if (!chainName || !protocol) return undefined; return accounts?.[protocol]; } export function useAccountAddressForChain(multiProvider, chainName) { const { accounts } = useAccounts(multiProvider); return getAccountAddressForChain(multiProvider, chainName, accounts); } export function getAccountAddressForChain(multiProvider, chainName, accounts) { if (!chainName || !accounts) return undefined; const protocol = multiProvider.getProtocol(chainName); const account = accounts[protocol]; if (protocol === ProtocolType.Cosmos || protocol === ProtocolType.CosmosNative) { return account?.addresses.find((a) => a.chainName === chainName)?.address; } else { // Use first because only cosmos has the notion of per-chain addresses return account?.addresses[0]?.address; } } export function getAddressFromAccountAndChain(account, chainName) { if (!account) { return 'Unknown'; } // only in cosmos there are multiple addresses per account, in this // case we display the cosmos hub address by default. If the user // selects a cosmos based origin chain in the swap form that cosmos // address is displayed instead if (account.protocol === ProtocolType.Cosmos) { // chainName can be an EVM chain here, therefore if no // cosmos address was found we search for the cosmos hub // address below const cosmosAddress = account?.addresses?.find((a) => a.chainName === chainName)?.address; // if no cosmos address was found for the chain name we search // for the cosmos hub address as fallback return (cosmosAddress ?? account?.addresses?.find((a) => a.chainName === cosmoshub.name) ?.address ?? 'Unknown'); } // by default display the first address of the account return account.addresses[0]?.address ?? 'Unknown'; } export function getAccountAddressAndPubKey(multiProvider, chainName, accounts) { const address = getAccountAddressForChain(multiProvider, chainName, accounts); if (!accounts || !chainName || !address) return {}; const protocol = multiProvider.getProtocol(chainName); const publicKey = accounts[protocol]?.publicKey; return { address, publicKey }; } export function useWalletDetails() { const evmWallet = useEthereumWalletDetails(); const solWallet = useSolanaWalletDetails(); const cosmosWallet = useCosmosWalletDetails(); const starknetWallet = useStarknetWalletDetails(); const radixWallet = useRadixWalletDetails(); return useMemo(() => ({ [ProtocolType.Ethereum]: evmWallet, [ProtocolType.Sealevel]: solWallet, [ProtocolType.Cosmos]: cosmosWallet, [ProtocolType.CosmosNative]: cosmosWallet, [ProtocolType.Starknet]: starknetWallet, [ProtocolType.Radix]: radixWallet, [ProtocolType.Aleo]: evmWallet, // TODO: implement this once we have a Aleo wallet connection }), [evmWallet, solWallet, cosmosWallet, starknetWallet, radixWallet]); } export function useConnectFns() { const onConnectEthereum = useEthereumConnectFn(); const onConnectSolana = useSolanaConnectFn(); const onConnectCosmos = useCosmosConnectFn(); const onConnectStarknet = useStarknetConnectFn(); const onConnectRadix = useRadixConnectFn(); return useMemo(() => ({ [ProtocolType.Ethereum]: onConnectEthereum, [ProtocolType.Sealevel]: onConnectSolana, [ProtocolType.Cosmos]: onConnectCosmos, [ProtocolType.CosmosNative]: onConnectCosmos, [ProtocolType.Starknet]: onConnectStarknet, [ProtocolType.Radix]: onConnectRadix, [ProtocolType.Aleo]: () => { }, // TODO: implement this once we have a Aleo wallet connection }), [ onConnectEthereum, onConnectSolana, onConnectCosmos, onConnectStarknet, onConnectRadix, ]); } export function useDisconnectFns() { const disconnectEvm = useEthereumDisconnectFn(); const disconnectSol = useSolanaDisconnectFn(); const disconnectCosmos = useCosmosDisconnectFn(); const disconnectStarknet = useStarknetDisconnectFn(); const disconnectRadix = useRadixDisconnectFn(); const onClickDisconnect = (env, disconnectFn) => async () => { try { if (!disconnectFn) throw new Error('Disconnect function is null'); await disconnectFn(); } catch (error) { logger.error(`Error disconnecting from ${env} wallet`, error); } }; return useMemo(() => ({ [ProtocolType.Ethereum]: onClickDisconnect(ProtocolType.Ethereum, disconnectEvm), [ProtocolType.Sealevel]: onClickDisconnect(ProtocolType.Sealevel, disconnectSol), [ProtocolType.Cosmos]: onClickDisconnect(ProtocolType.Cosmos, disconnectCosmos), [ProtocolType.CosmosNative]: onClickDisconnect(ProtocolType.CosmosNative, disconnectCosmos), [ProtocolType.Starknet]: onClickDisconnect(ProtocolType.Starknet, disconnectStarknet), [ProtocolType.Radix]: onClickDisconnect(ProtocolType.Radix, disconnectRadix), [ProtocolType.Aleo]: onClickDisconnect(ProtocolType.Aleo, () => { }), // TODO: implement once we have Aleo wallet connection }), [ disconnectEvm, disconnectSol, disconnectCosmos, disconnectStarknet, disconnectRadix, ]); } export function useActiveChains(multiProvider) { const evmChain = useEthereumActiveChain(multiProvider); const solChain = useSolanaActiveChain(multiProvider); const cosmChain = useCosmosActiveChain(multiProvider); const starknetChain = useStarknetActiveChain(multiProvider); const radixChain = useRadixActiveChain(multiProvider); const readyChains = useMemo(() => [evmChain, solChain, cosmChain, starknetChain, radixChain].filter((c) => !!c.chainDisplayName), [evmChain, solChain, cosmChain, starknetChain, radixChain]); return useMemo(() => ({ chains: { [ProtocolType.Ethereum]: evmChain, [ProtocolType.Sealevel]: solChain, [ProtocolType.Cosmos]: cosmChain, [ProtocolType.CosmosNative]: cosmChain, [ProtocolType.Starknet]: starknetChain, [ProtocolType.Radix]: radixChain, [ProtocolType.Aleo]: evmChain, // TODO: replace this once we have a Aleo implementation }, readyChains, }), [evmChain, solChain, cosmChain, readyChains, starknetChain, radixChain]); } export function useTransactionFns(multiProvider) { const { switchNetwork: onSwitchEvmNetwork, sendTransaction: onSendEvmTx, sendMultiTransaction: onSendMultiEvmTx, } = useEthereumTransactionFns(multiProvider); const { switchNetwork: onSwitchSolNetwork, sendTransaction: onSendSolTx, sendMultiTransaction: onSendMultiSolTx, } = useSolanaTransactionFns(multiProvider); const { switchNetwork: onSwitchCosmNetwork, sendTransaction: onSendCosmTx, sendMultiTransaction: onSendMultiCosmTx, } = useCosmosTransactionFns(multiProvider); const { switchNetwork: onSwitchStarknetNetwork, sendTransaction: onSendStarknetTx, sendMultiTransaction: onSendMultiStarknetTx, } = useStarknetTransactionFns(multiProvider); const { switchNetwork: onSwitchRadixNetwork, sendTransaction: onSendRadixTx, sendMultiTransaction: onSendMultiRadixTx, } = useRadixTransactionFns(multiProvider); return useMemo(() => ({ [ProtocolType.Ethereum]: { sendTransaction: onSendEvmTx, sendMultiTransaction: onSendMultiEvmTx, switchNetwork: onSwitchEvmNetwork, }, [ProtocolType.Sealevel]: { sendTransaction: onSendSolTx, sendMultiTransaction: onSendMultiSolTx, switchNetwork: onSwitchSolNetwork, }, [ProtocolType.Cosmos]: { sendTransaction: onSendCosmTx, sendMultiTransaction: onSendMultiCosmTx, switchNetwork: onSwitchCosmNetwork, }, [ProtocolType.CosmosNative]: { sendTransaction: onSendCosmTx, sendMultiTransaction: onSendMultiCosmTx, switchNetwork: onSwitchCosmNetwork, }, [ProtocolType.Starknet]: { sendTransaction: onSendStarknetTx, sendMultiTransaction: onSendMultiStarknetTx, switchNetwork: onSwitchStarknetNetwork, }, [ProtocolType.Radix]: { sendTransaction: onSendRadixTx, sendMultiTransaction: onSendMultiRadixTx, switchNetwork: onSwitchRadixNetwork, }, [ProtocolType.Aleo]: { // TODO: implement once we have Aleo wallet connection sendTransaction: () => { }, sendMultiTransaction: () => { }, switchNetwork: () => { }, }, }), [ onSendEvmTx, onSendSolTx, onSwitchEvmNetwork, onSwitchSolNetwork, onSendCosmTx, onSwitchCosmNetwork, onSendStarknetTx, onSwitchStarknetNetwork, onSendRadixTx, onSwitchRadixNetwork, ]); } export function useWatchAsset(multiProvider) { const { addAsset: evmAddAsset } = useEthereumWatchAsset(multiProvider); const { addAsset: solanaAddAsset } = useSolanaWatchAsset(multiProvider); const { addAsset: cosmosAddAsset } = useCosmosWatchAsset(multiProvider); const { addAsset: starknetAddAsset } = useStarknetWatchAsset(multiProvider); const { addAsset: radixAddAsset } = useRadixWatchAsset(multiProvider); return useMemo(() => ({ [ProtocolType.Ethereum]: { addAsset: evmAddAsset, }, [ProtocolType.Sealevel]: { addAsset: solanaAddAsset, }, [ProtocolType.Cosmos]: { addAsset: cosmosAddAsset, }, [ProtocolType.CosmosNative]: { addAsset: cosmosAddAsset, }, [ProtocolType.Starknet]: { addAsset: starknetAddAsset, }, [ProtocolType.Radix]: { addAsset: radixAddAsset, }, [ProtocolType.Aleo]: { addAsset: () => { }, // TODO: implement once we have Aleo wallet connection }, }), [ evmAddAsset, solanaAddAsset, cosmosAddAsset, starknetAddAsset, radixAddAsset, ]); } //# sourceMappingURL=multiProtocol.js.map