pussy-ts/src/contexts/relayer.tsx

import { Decimal } from '@cosmjs/math';
import { GasPrice } from '@cosmjs/stargate';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import loadConnections from 'src/services/relayer/loadConnections';
import relay from 'src/services/relayer/relay';
import { useChannels } from 'src/hooks/useHub';
import { ObjectKey } from 'src/types/data';
import { Channel } from 'src/types/hub';
import { getKeplr } from 'src/utils/keplrUtils';
import networkList from 'src/utils/networkListIbc';

const RelayerContext = React.createContext<{
  channels: undefined | ObjectKey<Channel>;
  relayerLog: any[];
  isRelaying: boolean;
  selectChain: string;
  setSelectChain: (key: string) => void;
  stop: () => void;
}>({
  channels: undefined,
  relayerLog: [],
  isRelaying: false,
  selectChain: '',
  setSelectChain: () => undefined,
  stop: () => undefined,
});

function findNetwork(chainId: string) {
  return networkList[chainId];
}

const logMap = ['log', 'info', 'error', 'warn', 'verbose', 'debug'];

export const useRelayer = () => React.useContext(RelayerContext);

function RelayerContextProvider({ children }: { children: React.ReactNode }) {
  const { channels } = useChannels();

  const stopFn = useRef<() => void>();

  const [selectChain, setSelectChain] = useState('');
  const [isRelaying, setIsRelaying] = useState(false);
  const [relayerLog, setRelayerLog] = useState<string[]>([]);

  const logger = () => {
    return logMap.reduce(
      (obj, item) => ({
        ...obj,
        [item]: (msg: string) => {
          setRelayerLog((state) => [...state, `${item}:  ${msg}`]);
        },
      }),
      {}
    );
  };

  useEffect(() => {
    return () => {
      stopFn.current?.();
    };
  }, []);

  useEffect(() => {
    (async () => {
      if (selectChain.length > 0) {
        setIsRelaying(true);
        const keplrWindow = await getKeplr();

        stopFn.current?.();

        if (!channels || !keplrWindow) {
          return;
        }

        const chainInfos = await keplrWindow.getChainInfosWithoutEndpoints();

        const { source_chain_id: chainIdA, destination_chain_id: chainIdB } =
          channels[selectChain];

        const chainInfoA = chainInfos.find((item) => item.chainId === chainIdA);
        const chainInfoB = chainInfos.find((item) => item.chainId === chainIdB);

        if (!chainInfoA || !chainInfoB) {
          return;
        }

        const feeCurrenciesA = chainInfoA.feeCurrencies[0];
        const feeCurrenciesB = chainInfoB.feeCurrencies[0];

        const GasPriceA = new GasPrice(
          Decimal.fromUserInput(
            feeCurrenciesA.gasPriceStep?.average.toString() || '0',
            3
          ),
          feeCurrenciesA?.coinMinimalDenom
        );

        const GasPriceB = new GasPrice(
          Decimal.fromUserInput(
            feeCurrenciesB.gasPriceStep?.average.toString() || '0',
            3
          ),
          feeCurrenciesB?.coinMinimalDenom
        );

        const { rpc: rpcA } = findNetwork(chainIdA);
        const { rpc: rpcB } = findNetwork(chainIdB);

        const signerA = await keplrWindow.getOfflineSignerAuto(chainIdA);
        const signerB = await keplrWindow.getOfflineSignerAuto(chainIdB);

        const [{ address: addressSignerA }] = await signerA.getAccounts();
        const [{ address: addressSignerB }] = await signerB.getAccounts();

        const cxns = await loadConnections(channels[selectChain]);

        if (!cxns.length) {
          return;
        }

        console.debug('cxns', cxns);

        const [{ cxnA, cxnB }] = cxns;

        (async () => {
          const config = await relay(
            signerA,
            signerB,
            rpcA,
            rpcB,
            addressSignerA,
            addressSignerB,
            GasPriceA,
            GasPriceB,
            cxnA,
            cxnB,
            addressSignerA,
            addressSignerB,
            0,
            0,
            logger()
          );

          stopFn.current = () => {
            config.stop();
            setIsRelaying(false);
            setSelectChain('');
            setRelayerLog([]);
            stopFn.current = undefined;
          };
        })();
      }
    })();

    return () => {
      stopFn.current?.();
    };
  }, [selectChain, channels]);

  const stop = () => {
    stopFn.current?.();
  };

  const contextValue = useMemo(
    () => ({
      channels,
      relayerLog,
      isRelaying,
      selectChain,
      setSelectChain,
      stop,
    }),
    [channels, relayerLog, isRelaying, selectChain]
  );

  return (
    <RelayerContext.Provider value={contextValue}>
      {children}
    </RelayerContext.Provider>
  );
}

export default RelayerContextProvider;

Synonyms

cyb/src/contexts/relayer.tsx
pussy-ts/src/pages/teleport/relayer/Relayer.tsx
cyb/src/pages/teleport/relayer/Relayer.tsx

Neighbours