diff --git a/components/dataViews/TransactionInfo/TxMsgVoteDetails.tsx b/components/dataViews/TransactionInfo/TxMsgVoteDetails.tsx new file mode 100644 index 00000000..9f3e4c71 --- /dev/null +++ b/components/dataViews/TransactionInfo/TxMsgVoteDetails.tsx @@ -0,0 +1,51 @@ +import { printVoteOption } from "@/lib/gov"; +import { MsgVote } from "cosmjs-types/cosmos/gov/v1beta1/tx"; + +interface TxMsgVoteDetailsProps { + readonly msgValue: MsgVote; +} + +const TxMsgVoteDetails = ({ msgValue }: TxMsgVoteDetailsProps) => { + return ( + <> +
  • +

    MsgVote

    +
  • +
  • + +
    {msgValue.proposalId.toString()}
    +
  • +
  • + +
    {printVoteOption(msgValue.option)}
    +
  • + + + ); +}; + +export default TxMsgVoteDetails; diff --git a/components/dataViews/TransactionInfo/index.tsx b/components/dataViews/TransactionInfo/index.tsx index d0737fa9..344b7e50 100644 --- a/components/dataViews/TransactionInfo/index.tsx +++ b/components/dataViews/TransactionInfo/index.tsx @@ -17,6 +17,7 @@ import TxMsgSetWithdrawAddressDetails from "./TxMsgSetWithdrawAddressDetails"; import TxMsgTransferDetails from "./TxMsgTransferDetails"; import TxMsgUndelegateDetails from "./TxMsgUndelegateDetails"; import TxMsgUpdateAdminDetails from "./TxMsgUpdateAdminDetails"; +import TxMsgVoteDetails from "./TxMsgVoteDetails"; const TxMsgDetails = ({ typeUrl, value: msgValue }: EncodeObject) => { switch (typeUrl) { @@ -34,6 +35,8 @@ const TxMsgDetails = ({ typeUrl, value: msgValue }: EncodeObject) => { return ; case MsgTypeUrls.CreateVestingAccount: return ; + case MsgTypeUrls.Vote: + return ; case MsgTypeUrls.Transfer: return ; case MsgTypeUrls.Execute: diff --git a/components/forms/CreateTxForm/MsgForm/MsgVoteForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgVoteForm.tsx new file mode 100644 index 00000000..7618e25e --- /dev/null +++ b/components/forms/CreateTxForm/MsgForm/MsgVoteForm.tsx @@ -0,0 +1,137 @@ +import { printVoteOption, voteOptions } from "@/lib/gov"; +import { MsgVoteEncodeObject } from "@cosmjs/stargate"; +import { longify } from "@cosmjs/stargate/build/queryclient"; +import { voteOptionFromJSON } from "cosmjs-types/cosmos/gov/v1beta1/gov"; +import { useEffect, useState } from "react"; +import { MsgGetter } from ".."; +import { trimStringsObj } from "../../../../lib/displayHelpers"; +import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; +import Input from "../../../inputs/Input"; +import Select from "../../../inputs/Select"; +import StackableContainer from "../../../layout/StackableContainer"; + +const selectVoteOptions = voteOptions.map((opt) => { + const voteOptionObj = voteOptionFromJSON(opt); + + return { + label: printVoteOption(voteOptionObj), + value: voteOptionObj, + }; +}); + +interface MsgVoteFormProps { + readonly fromAddress: string; + readonly setMsgGetter: (msgGetter: MsgGetter) => void; + readonly deleteMsg: () => void; +} + +const MsgVoteForm = ({ fromAddress, setMsgGetter, deleteMsg }: MsgVoteFormProps) => { + const [proposalId, setProposalId] = useState("0"); + const [selectedVote, setSelectedVote] = useState(selectVoteOptions[0]); + + const [proposalIdError, setProposalIdError] = useState(""); + + const trimmedInputs = trimStringsObj({ proposalId }); + + useEffect(() => { + // eslint-disable-next-line no-shadow + const { proposalId } = trimmedInputs; + + const isMsgValid = (): boolean => { + setProposalIdError(""); + + if (!proposalId || Number(proposalId) <= 0 || !Number.isSafeInteger(Number(proposalId))) { + setProposalIdError("Proposal ID must be an integer greater than 0"); + return false; + } + + try { + longify(proposalId); + } catch (e: unknown) { + setProposalIdError(e instanceof Error ? e.message : "Proposal ID is not a valid Big Int"); + return false; + } + + return true; + }; + + const proposalIdBigInt = (() => { + try { + return longify(proposalId); + } catch { + return 0n; + } + })(); + + const msgValue = MsgCodecs[MsgTypeUrls.Vote].fromPartial({ + voter: fromAddress, + proposalId: proposalIdBigInt, + option: selectedVote.value, + }); + + const msg: MsgVoteEncodeObject = { typeUrl: MsgTypeUrls.Vote, value: msgValue }; + + setMsgGetter({ isMsgValid, msg }); + }, [fromAddress, selectedVote.value, setMsgGetter, trimmedInputs]); + + return ( + + +

    MsgVote

    +
    + { + setProposalId(target.value); + setProposalIdError(""); + }} + error={proposalIdError} + /> +
    +
    + +