import { EncodeObject } from "@cosmjs/proto-signing"; import { Account, calculateFee } from "@cosmjs/stargate"; import { assert } from "@cosmjs/utils"; import { NextRouter, withRouter } from "next/router"; import { useRef, useState } from "react"; import { useChains } from "../../../context/ChainsContext"; import { requestJson } from "../../../lib/request"; import { exportMsgToJson, gasOfTx } from "../../../lib/txMsgHelpers"; import { DbTransaction } from "../../../types"; import { MsgTypeUrl, MsgTypeUrls } from "../../../types/txMsg"; import Button from "../../inputs/Button"; import Input from "../../inputs/Input"; import StackableContainer from "../../layout/StackableContainer"; import MsgForm from "./MsgForm"; export interface MsgGetter { readonly isMsgValid: () => boolean; readonly msg: EncodeObject; } interface CreateTxFormProps { readonly router: NextRouter; readonly senderAddress: string; readonly accountOnChain: Account; } const CreateTxForm = ({ router, senderAddress, accountOnChain }: CreateTxFormProps) => { const { chain } = useChains(); const [processing, setProcessing] = useState(false); const [msgTypes, setMsgTypes] = useState([]); const [msgKeys, setMsgKeys] = useState([]); const msgGetters = useRef([]); const [memo, setMemo] = useState(""); const [gasLimit, setGasLimit] = useState(gasOfTx([])); const [gasLimitError, setGasLimitError] = useState(""); const [showCreateTxError, setShowTxError] = useState(false); const addMsgType = (newMsgType: MsgTypeUrl) => { setMsgKeys((oldMsgKeys) => [...oldMsgKeys, crypto.randomUUID()]); setMsgTypes((oldMsgTypes) => { const newMsgTypes = [...oldMsgTypes, newMsgType]; setGasLimit(gasOfTx(newMsgTypes)); return newMsgTypes; }); }; const createTx = async () => { try { setShowTxError(false); assert(typeof accountOnChain.accountNumber === "number", "accountNumber missing"); assert(msgGetters.current.length, "form filled incorrectly"); const msgs = msgGetters.current .filter(({ isMsgValid }) => isMsgValid()) .map(({ msg }) => exportMsgToJson(msg)); if (!msgs.length || msgs.length !== msgTypes.length) return; if (!Number.isSafeInteger(gasLimit) || gasLimit <= 0) { setGasLimitError("gas limit must be a positive integer"); return; } setProcessing(true); const tx: DbTransaction = { accountNumber: accountOnChain.accountNumber, sequence: accountOnChain.sequence, chainId: chain.chainId, msgs, fee: calculateFee(gasLimit, chain.gasPrice), memo, }; const { transactionID } = await requestJson("/api/transaction", { body: { dataJSON: JSON.stringify(tx) }, }); router.push(`/${chain.registryName}/${senderAddress}/transaction/${transactionID}`); } catch (error) { console.error("Creat transaction error:", error); setShowTxError(true); } finally { setProcessing(false); } }; return (

Create New Transaction

{msgTypes.length ? ( msgTypes.map((msgType, index) => ( { msgGetters.current = [ ...msgGetters.current.slice(0, index), msgGetter, ...msgGetters.current.slice(index + 1), ]; }} deleteMsg={() => { msgGetters.current.splice(index, 1); setMsgKeys((oldMsgKeys) => [ ...oldMsgKeys.slice(0, index), ...oldMsgKeys.slice(index + 1), ]); setMsgTypes((oldMsgTypes) => { const newMsgTypes: MsgTypeUrl[] = oldMsgTypes.slice(); newMsgTypes.splice(index, 1); setGasLimit(gasOfTx(newMsgTypes)); return newMsgTypes; }); }} /> )) ) : (

Add at least one message to this transaction

)}
setGasLimit(Number(target.value))} />
setMemo(target.value)} />

Add New Msg

{showCreateTxError ? (

Error when creating the transaction. See console for more details.

) : null}