cyb/src/pages/teleport/bridge/actionBar.bridge.tsx

import { Coin } from '@cosmjs/launchpad';
import { MsgTransferEncodeObject, SigningStargateClient } from '@cosmjs/stargate';
import BigNumber from 'bignumber.js';
import { MsgTransfer } from 'cosmjs-types/ibc/applications/transfer/v1/tx';
import Long from 'long';
import { useCallback, useState } from 'react';
import { DEFAULT_GAS_LIMITS } from 'src/constants/config';
import { useSigningClient } from 'src/contexts/signerClient';
import { Option } from 'src/types';
import { getNowUtcNumber } from 'src/utils/date';
import { ActionBar as ActionBarCenter, LinkWindow } from '../../../components';
import { useIbcHistory } from '../../../features/ibc-history/historyContext';
import { LEDGER } from '../../../utils/config';
import networks from '../../../utils/networkListIbc';
import { convertAmountReverce, fromBech32, trimString } from '../../../utils/utils';
import ActionBarPingTxs from '../components/actionBarPingTxs';
import { TxsType, TypeTxsT } from '../type';
import { friendlyErrorMessage } from 'src/utils/errorMessages';

const { STAGE_INIT, STAGE_ERROR, STAGE_SUBMITTED } = LEDGER;

const STAGE_CONFIRMED_IBC = 7.1;

const TIMEOUT_TIMESTAMP = 2 * 60 * 1000; // 2 min

const fee = {
  amount: [],
  gas: DEFAULT_GAS_LIMITS.toString(),
};

const coinFunc = (amount: number, denom: string): Coin => {
  return { denom, amount: new BigNumber(amount).toString(10) };
};

type Props = {
  tokenAmount: string;
  tokenSelect: string;
  networkB: string;
  updateFunc: () => void;
  isExceeded: boolean;
  typeTxs: TypeTxsT;
  ibcClient: null | SigningStargateClient;
  denomIbc: null | string;
  sourceChannel: string | null;
  coinDecimals: number;
};

function ActionBar({ stateActionBar }: { stateActionBar: Props }) {
  const { pingTxsIbc } = useIbcHistory();
  const { signingClient, signer } = useSigningClient();
  const [stage, setStage] = useState(STAGE_INIT);
  const [txHash, setTxHash] = useState<Option<string>>(undefined);
  const [txHashIbc, setTxHashIbc] = useState(null);
  const [linkIbcTxs, setLinkIbcTxs] = useState<Option<string>>(undefined);
  const [errorMessage, setErrorMessage] = useState<Option<string | JSX.Element>>(undefined);

  const {
    tokenAmount,
    tokenSelect,
    updateFunc,
    isExceeded,
    typeTxs,
    ibcClient,
    denomIbc,
    sourceChannel,
    networkB,
    coinDecimals,
  } = stateActionBar;

  const clearState = () => {
    setStage(STAGE_INIT);
    setTxHash(undefined);
    setErrorMessage(undefined);
    setTxHashIbc(null);
    setLinkIbcTxs(undefined);
  };

  const depositOnClick = useCallback(async () => {
    if (!ibcClient || !denomIbc || !signer) {
      return;
    }

    const [{ address }] = await ibcClient.signer.getAccounts();
    const [{ address: counterpartyAccount }] = await signer.getAccounts();
    const responseChainId = await ibcClient.getChainId();

    setStage(STAGE_SUBMITTED);

    const sourcePort = 'transfer';

    const timeoutTimestamp = Long.fromString(`${Date.now() + TIMEOUT_TIMESTAMP}000000`);

    const amount = convertAmountReverce(tokenAmount, coinDecimals);

    const transferAmount = coinFunc(amount, denomIbc);
    const msg: MsgTransferEncodeObject = {
      typeUrl: '/ibc.applications.transfer.v1.MsgTransfer',
      value: MsgTransfer.fromPartial({
        sourcePort,
        sourceChannel: sourceChannel || '',
        sender: address,
        receiver: counterpartyAccount,
        timeoutTimestamp: BigInt(timeoutTimestamp.toNumber()),
        token: transferAmount,
      }),
    };

    try {
      const response = await ibcClient.signAndBroadcast(address, [msg], 1.5, '');

      console.log('response', response);

      if (response.code === 0) {
        setTxHashIbc(response.transactionHash);
        setLinkIbcTxs(
          `${networks[responseChainId].explorerUrlToTx.replace(
            '{txHash}',
            response.transactionHash.toUpperCase()
          )}`
        );

        const transferData = {
          txHash: response.transactionHash,
          address: counterpartyAccount,
          sourceChainId: responseChainId,
          destChainId: networkB,
          sender: address,
          recipient: counterpartyAccount,
          createdAt: getNowUtcNumber(),
          amount: coinFunc(amount, tokenSelect),
        };
        pingTxsIbc(ibcClient, transferData);
        updateFunc();
        setStage(STAGE_CONFIRMED_IBC);
        // if (response.rawLog.length > 0) {
        //   parseRawLog(response.rawLog);
        // }
      } else {
        setTxHashIbc(null);
        setErrorMessage(friendlyErrorMessage(response.rawLog));
        setStage(STAGE_ERROR);
      }
    } catch (e) {
      console.error(`error: `, e);
      setTxHashIbc(null);
      setErrorMessage(friendlyErrorMessage(e?.message || e));
      setStage(STAGE_ERROR);
    }

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [
    ibcClient,
    tokenAmount,
    denomIbc,
    networkB,
    coinDecimals,
    pingTxsIbc,
    signer,
    sourceChannel,
    tokenSelect,
    updateFunc,
  ]);

  const withdrawOnClick = useCallback(async () => {
    if (!signer || !signingClient) {
      return;
    }

    let prefix;
    setStage(STAGE_SUBMITTED);
    if (networks[networkB]) {
      prefix = networks[networkB].prefix;
    }
    const [{ address }] = await signer.getAccounts();
    const sourcePort = 'transfer';
    const counterpartyAccount = fromBech32(address, prefix);
    const timeoutTimestamp = Long.fromString(`${Date.now() + TIMEOUT_TIMESTAMP}000000`);

    const amount = convertAmountReverce(tokenAmount, coinDecimals);
    const transferAmount = coinFunc(amount, tokenSelect);
    const msg: MsgTransferEncodeObject = {
      typeUrl: '/ibc.applications.transfer.v1.MsgTransfer',
      value: MsgTransfer.fromPartial({
        sourcePort,
        sourceChannel,
        sender: address,
        receiver: counterpartyAccount,
        timeoutTimestamp: BigInt(timeoutTimestamp.toNumber()),
        token: transferAmount,
      }),
    };
    try {
      const response = await signingClient.signAndBroadcast(address, [msg], fee, '');
      if (response.code === 0) {
        setTxHash(response.transactionHash);
        const ChainId = await signingClient.getChainId();
        const transferData = {
          txHash: response.transactionHash,
          address,
          sourceChainId: ChainId,
          destChainId: networkB,
          sender: address,
          recipient: counterpartyAccount,
          createdAt: getNowUtcNumber(),
          amount: transferAmount,
        };
        pingTxsIbc(signingClient, transferData);
      } else {
        setTxHash(undefined);
        setErrorMessage(friendlyErrorMessage(response.rawLog));
        setStage(STAGE_ERROR);
      }
    } catch (e) {
      console.error(`error: `, e);
      setTxHash(undefined);
      setErrorMessage(friendlyErrorMessage(e?.message || e));
      setStage(STAGE_ERROR);
    }

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [
    tokenSelect,
    signer,
    tokenAmount,
    sourceChannel,
    networkB,
    coinDecimals,
    pingTxsIbc,
    signingClient,
  ]);

  const buttonConfigs = {
    [TxsType.Deposit]: {
      text: 'transfer',
      // onClick: () => addHistoriesItem(testItem),
      onClick: depositOnClick,
      disabled: isExceeded,
    },
    [TxsType.Withdraw]: {
      text: 'transfer',
      onClick: withdrawOnClick,
      disabled: isExceeded,
    },
  };

  if (stage === STAGE_INIT) {
    return <ActionBarCenter button={buttonConfigs[typeTxs]} />;
  }

  if (stage === STAGE_CONFIRMED_IBC) {
    return (
      <ActionBarCenter button={{ text: 'Grow', onClick: clearState }}>
        <span>
          Transaction successful:{' '}
          <LinkWindow to={linkIbcTxs}>{trimString(txHashIbc, 6, 6)}</LinkWindow>
        </span>
      </ActionBarCenter>
    );
  }

  const stageActionBarStaps = {
    stage,
    setStage,
    updateFunc,
    clearState,
    txHash,
    errorMessageProps: errorMessage,
  };

  return <ActionBarPingTxs stageActionBarStaps={stageActionBarStaps} />;
}

export default ActionBar;

Synonyms

pussy-ts/src/pages/teleport/bridge/actionBar.bridge.tsx

Neighbours