@hyperlane-xyz/widgets
Version:
Common react components for Hyperlane projects
299 lines • 13.6 kB
JavaScript
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