UNPKG

@hyperlane-xyz/widgets

Version:

Common react components for Hyperlane projects

157 lines 7.08 kB
import { GasPrice } from '@cosmjs/stargate'; import { useChain, useChains } from '@cosmos-kit/react'; import { useCallback, useMemo } from 'react'; import { SigningHyperlaneModuleClient } from '@hyperlane-xyz/cosmos-sdk'; import { cosmoshub } from '@hyperlane-xyz/registry'; import { ProviderType, chainMetadataToCosmosChain, } from '@hyperlane-xyz/sdk'; import { ProtocolType, assert } from '@hyperlane-xyz/utils'; import { widgetLogger } from '../logger.js'; import { getChainsForProtocol } from './utils.js'; // Used because the CosmosKit hooks always require a chain name const PLACEHOLDER_COSMOS_CHAIN = cosmoshub.name; const logger = widgetLogger.child({ module: 'widgets/walletIntegrations/cosmos', }); export function useCosmosAccount(multiProvider) { const cosmosChains = getCosmosChainNames(multiProvider); const chainToContext = useChains(cosmosChains); return useMemo(() => { const addresses = []; let publicKey = undefined; let connectorName = undefined; let isReady = false; for (const [chainName, context] of Object.entries(chainToContext)) { if (!context.address) continue; addresses.push({ address: context.address, chainName }); publicKey = context .getAccount() .then((acc) => Buffer.from(acc.pubkey).toString('hex')); isReady = true; connectorName ||= context.wallet?.prettyName; } return { protocol: ProtocolType.Cosmos, addresses, publicKey, isReady, }; }, [chainToContext]); } export function useCosmosWalletDetails() { const { wallet } = useChain(PLACEHOLDER_COSMOS_CHAIN); const { logo, prettyName } = wallet || {}; return useMemo(() => ({ name: prettyName, logoUrl: typeof logo === 'string' ? logo : undefined, }), [prettyName, logo]); } export function useCosmosConnectFn() { const { openView } = useChain(PLACEHOLDER_COSMOS_CHAIN); return openView; } export function useCosmosDisconnectFn() { const { disconnect, address } = useChain(PLACEHOLDER_COSMOS_CHAIN); const safeDisconnect = async () => { if (address) await disconnect(); }; return safeDisconnect; } export function useCosmosActiveChain(_multiProvider) { // Cosmoskit doesn't have the concept of an active chain return useMemo(() => ({}), []); } export function useCosmosSwitchNetwork(multiProvider) { const onSwitchNetwork = useCallback(async (chainName) => { const displayName = multiProvider.getChainMetadata(chainName).displayName || chainName; // CosmosKit does not have switch capability throw new Error(`Cosmos wallet must be connected to origin chain ${displayName}}`); }, [multiProvider]); return { switchNetwork: onSwitchNetwork }; } export function useCosmosWatchAsset(_multiProvider) { const onAddAsset = useCallback(async (_token, _activeChainName) => { throw new Error('Watch asset not available for cosmos'); }, []); return { addAsset: onAddAsset }; } export function useCosmosTransactionFns(multiProvider) { const cosmosChains = getCosmosChainNames(multiProvider); const chainToContext = useChains(cosmosChains); const { switchNetwork } = useCosmosSwitchNetwork(multiProvider); const onSendTx = useCallback(async ({ tx, chainName, activeChainName, }) => { const chainContext = chainToContext[chainName]; if (!chainContext?.address) throw new Error(`Cosmos wallet not connected for ${chainName}`); if (activeChainName && activeChainName !== chainName) await switchNetwork(chainName); logger.debug(`Sending tx on chain ${chainName}`); const { getSigningCosmWasmClient, getSigningStargateClient, getOfflineSigner, chain, } = chainContext; let result; let txDetails; if (tx.type === ProviderType.CosmJsWasm) { const client = await getSigningCosmWasmClient(); result = await client.executeMultiple(chainContext.address, [tx.transaction], 'auto'); txDetails = await client.getTx(result.transactionHash); } else if (tx.type === ProviderType.CosmJs) { const client = await getSigningStargateClient(); // The fee param of 'auto' here stopped working for Neutron-based IBC transfers // It seems the signAndBroadcast method uses a default fee multiplier of 1.4 // https://github.com/cosmos/cosmjs/blob/e819a1fc0e99a3e5320d8d6667a08d3b92e5e836/packages/stargate/src/signingstargateclient.ts#L115 // A multiplier of 1.6 was insufficient for Celestia -> Neutron|Cosmos -> XXX transfers, but 2 worked. result = await client.signAndBroadcast(chainContext.address, [tx.transaction], 2); txDetails = await client.getTx(result.transactionHash); } else if (tx.type === ProviderType.CosmJsNative) { const signer = getOfflineSigner(); const client = await SigningHyperlaneModuleClient.connectWithSigner(chain.apis.rpc[0].address, signer, { // set zero gas price here so it does not error. actual gas price // will be injected from the wallet registry like Keplr or Leap gasPrice: GasPrice.fromString('0token'), }); result = await client.signAndBroadcast(chainContext.address, [tx.transaction], 2); txDetails = await client.getTx(result.transactionHash); } else { throw new Error(`Invalid cosmos provider type ${tx.type}`); } const confirm = async () => { assert(txDetails, `Cosmos tx failed: ${JSON.stringify(result)}`); return { type: tx.type, receipt: { ...txDetails, transactionHash: result.transactionHash }, }; }; return { hash: result.transactionHash, confirm }; }, [switchNetwork, chainToContext]); const onMultiSendTx = useCallback(async ({ txs: _, chainName: __, activeChainName: ___, }) => { throw new Error('Multi Transactions not supported on Cosmos'); }, []); return { sendTransaction: onSendTx, sendMultiTransaction: onMultiSendTx, switchNetwork, }; } function getCosmosChains(multiProvider) { return [ ...getChainsForProtocol(multiProvider, ProtocolType.Cosmos), ...getChainsForProtocol(multiProvider, ProtocolType.CosmosNative), cosmoshub, ]; } function getCosmosChainNames(multiProvider) { return getCosmosChains(multiProvider).map((c) => c.name); } // Metadata formatted for use in Wagmi config export function getCosmosKitChainConfigs(multiProvider) { const chains = getCosmosChains(multiProvider); const configList = chains.map(chainMetadataToCosmosChain); return { chains: configList.map((c) => c.chain), assets: configList.map((c) => c.assets), }; } //# sourceMappingURL=cosmos.js.map