diff --git a/components/forms/CreateTxForm/MsgForm/MsgClaimRewardsForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgClaimRewardsForm.tsx index 88b8580..46f6dc4 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgClaimRewardsForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgClaimRewardsForm.tsx @@ -2,7 +2,7 @@ import { MsgWithdrawDelegatorRewardEncodeObject } from "@cosmjs/stargate"; import { useEffect, useState } from "react"; import { MsgGetter } from ".."; import { useChains } from "../../../../context/ChainsContext"; -import { checkAddress, exampleAddress } from "../../../../lib/displayHelpers"; +import { checkAddress, exampleAddress, trimStringsObj } from "../../../../lib/displayHelpers"; import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; import Input from "../../../inputs/Input"; import StackableContainer from "../../../layout/StackableContainer"; @@ -23,35 +23,38 @@ const MsgClaimRewardsForm = ({ const [validatorAddress, setValidatorAddress] = useState(""); const [validatorAddressError, setValidatorAddressError] = useState(""); + const trimmedInputs = trimStringsObj({ validatorAddress }); + useEffect(() => { - try { + // eslint-disable-next-line no-shadow + const { validatorAddress } = trimmedInputs; + + const isMsgValid = (): boolean => { setValidatorAddressError(""); - const isMsgValid = (): boolean => { - const addressErrorMsg = checkAddress(validatorAddress, chain.addressPrefix); - if (addressErrorMsg) { - setValidatorAddressError( - `Invalid address for network ${chain.chainId}: ${addressErrorMsg}`, - ); - return false; - } + const addressErrorMsg = checkAddress(validatorAddress, chain.addressPrefix); + if (addressErrorMsg) { + setValidatorAddressError( + `Invalid address for network ${chain.chainId}: ${addressErrorMsg}`, + ); + return false; + } - return true; - }; + return true; + }; - const msgValue = MsgCodecs[MsgTypeUrls.WithdrawDelegatorReward].fromPartial({ - delegatorAddress, - validatorAddress, - }); + const msgValue = MsgCodecs[MsgTypeUrls.WithdrawDelegatorReward].fromPartial({ + delegatorAddress, + validatorAddress, + }); - const msg: MsgWithdrawDelegatorRewardEncodeObject = { - typeUrl: MsgTypeUrls.WithdrawDelegatorReward, - value: msgValue, - }; + const msg: MsgWithdrawDelegatorRewardEncodeObject = { + typeUrl: MsgTypeUrls.WithdrawDelegatorReward, + value: msgValue, + }; - setMsgGetter({ isMsgValid, msg }); - } catch {} - }, [chain.addressPrefix, chain.chainId, delegatorAddress, setMsgGetter, validatorAddress]); + setMsgGetter({ isMsgValid, msg }); + }, [chain.addressPrefix, chain.chainId, delegatorAddress, setMsgGetter, trimmedInputs]); return ( @@ -64,7 +67,10 @@ const MsgClaimRewardsForm = ({ label="Validator Address" name="validator-address" value={validatorAddress} - onChange={({ target }) => setValidatorAddress(target.value)} + onChange={({ target }) => { + setValidatorAddress(target.value); + setValidatorAddressError(""); + }} error={validatorAddressError} placeholder={`E.g. ${exampleAddress(0, chain.addressPrefix)}`} /> diff --git a/components/forms/CreateTxForm/MsgForm/MsgCreateVestingAccountForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgCreateVestingAccountForm.tsx index 21cae4c..3db83b0 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgCreateVestingAccountForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgCreateVestingAccountForm.tsx @@ -1,13 +1,13 @@ -import { Decimal } from "@cosmjs/math"; import { EncodeObject } from "@cosmjs/proto-signing"; import { useEffect, useState } from "react"; import { MsgGetter } from ".."; import { useChains } from "../../../../context/ChainsContext"; +import { macroCoinToMicroCoin } from "../../../../lib/coinHelpers"; import { datetimeLocalFromTimestamp, timestampFromDatetimeLocal, } from "../../../../lib/dateHelpers"; -import { checkAddress, exampleAddress } from "../../../../lib/displayHelpers"; +import { checkAddress, exampleAddress, trimStringsObj } from "../../../../lib/displayHelpers"; import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; import Input from "../../../inputs/Input"; import StackableContainer from "../../../layout/StackableContainer"; @@ -36,60 +36,65 @@ const MsgCreateVestingAccountForm = ({ const [amountError, setAmountError] = useState(""); const [endTimeError, setEndTimeError] = useState(""); + const trimmedInputs = trimStringsObj({ toAddress, amount, endTime }); + useEffect(() => { - try { + // eslint-disable-next-line no-shadow + const { toAddress, amount, endTime } = trimmedInputs; + + const isMsgValid = (): boolean => { setToAddressError(""); setAmountError(""); setEndTimeError(""); - const isMsgValid = (): boolean => { - const addressErrorMsg = checkAddress(toAddress, chain.addressPrefix); - if (addressErrorMsg) { - setToAddressError(`Invalid address for network ${chain.chainId}: ${addressErrorMsg}`); - return false; - } + const addressErrorMsg = checkAddress(toAddress, chain.addressPrefix); + if (addressErrorMsg) { + setToAddressError(`Invalid address for network ${chain.chainId}: ${addressErrorMsg}`); + return false; + } - if (!amount || Number(amount) <= 0) { - setAmountError("Amount must be greater than 0"); - return false; - } + if (!amount || Number(amount) <= 0) { + setAmountError("Amount must be greater than 0"); + return false; + } - const timeoutDate = new Date(timestampFromDatetimeLocal(endTime).toNumber()); - if (timeoutDate <= new Date()) { - setEndTimeError("End time must be a date in the future"); - return false; - } + const timeoutDate = new Date(timestampFromDatetimeLocal(endTime).toNumber()); + if (timeoutDate <= new Date()) { + setEndTimeError("End time must be a date in the future"); + return false; + } - return true; - }; + return true; + }; - const amountInAtomics = amount - ? Decimal.fromUserInput(amount, Number(chain.displayDenomExponent)).atomics - : "0"; + const microCoin = (() => { + try { + return macroCoinToMicroCoin({ denom: chain.displayDenom, amount }, chain.assets); + } catch { + return { denom: chain.displayDenom, amount: "0" }; + } + })(); - const msgValue = MsgCodecs[MsgTypeUrls.CreateVestingAccount].fromPartial({ - fromAddress, - toAddress, - amount: [{ amount: amountInAtomics, denom: chain.denom }], - endTime: timestampFromDatetimeLocal(endTime, "s"), - delayed, - }); + const msgValue = MsgCodecs[MsgTypeUrls.CreateVestingAccount].fromPartial({ + fromAddress, + toAddress, + amount: [microCoin], + endTime: timestampFromDatetimeLocal(endTime, "s"), + delayed, + }); - const msg: EncodeObject = { typeUrl: MsgTypeUrls.CreateVestingAccount, value: msgValue }; + const msg: EncodeObject = { typeUrl: MsgTypeUrls.CreateVestingAccount, value: msgValue }; - setMsgGetter({ isMsgValid, msg }); - } catch {} + setMsgGetter({ isMsgValid, msg }); }, [ - amount, chain.addressPrefix, + chain.assets, chain.chainId, - chain.denom, - chain.displayDenomExponent, + chain.displayDenom, delayed, - endTime, fromAddress, setMsgGetter, - toAddress, + trimmedInputs, ]); return ( @@ -103,7 +108,10 @@ const MsgCreateVestingAccountForm = ({ label="Recipient Address" name="recipient-address" value={toAddress} - onChange={({ target }) => setToAddress(target.value)} + onChange={({ target }) => { + setToAddress(target.value); + setToAddressError(""); + }} error={toAddressError} placeholder={`E.g. ${exampleAddress(0, chain.addressPrefix)}`} /> @@ -114,7 +122,10 @@ const MsgCreateVestingAccountForm = ({ label={`Amount (${chain.displayDenom})`} name="amount" value={amount} - onChange={({ target }) => setAmount(target.value)} + onChange={({ target }) => { + setAmount(target.value); + setAmountError(""); + }} error={amountError} /> @@ -124,7 +135,10 @@ const MsgCreateVestingAccountForm = ({ label="End time" name="end-time" value={endTime} - onChange={({ target }) => setEndTime(target.value)} + onChange={({ target }) => { + setEndTime(target.value); + setEndTimeError(""); + }} error={endTimeError} /> diff --git a/components/forms/CreateTxForm/MsgForm/MsgDelegateForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgDelegateForm.tsx index f4cffb2..65bb303 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgDelegateForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgDelegateForm.tsx @@ -1,9 +1,9 @@ -import { Decimal } from "@cosmjs/math"; import { MsgDelegateEncodeObject } from "@cosmjs/stargate"; import { useEffect, useState } from "react"; import { MsgGetter } from ".."; import { useChains } from "../../../../context/ChainsContext"; -import { checkAddress, exampleAddress } from "../../../../lib/displayHelpers"; +import { macroCoinToMicroCoin } from "../../../../lib/coinHelpers"; +import { checkAddress, exampleAddress, trimStringsObj } from "../../../../lib/displayHelpers"; import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; import Input from "../../../inputs/Input"; import StackableContainer from "../../../layout/StackableContainer"; @@ -23,52 +23,57 @@ const MsgDelegateForm = ({ delegatorAddress, setMsgGetter, deleteMsg }: MsgDeleg const [validatorAddressError, setValidatorAddressError] = useState(""); const [amountError, setAmountError] = useState(""); + const trimmedInputs = trimStringsObj({ validatorAddress, amount }); + useEffect(() => { - try { + // eslint-disable-next-line no-shadow + const { validatorAddress, amount } = trimmedInputs; + + const isMsgValid = (): boolean => { setValidatorAddressError(""); setAmountError(""); - const isMsgValid = (): boolean => { - const addressErrorMsg = checkAddress(validatorAddress, chain.addressPrefix); - if (addressErrorMsg) { - setValidatorAddressError( - `Invalid address for network ${chain.chainId}: ${addressErrorMsg}`, - ); - return false; - } + const addressErrorMsg = checkAddress(validatorAddress, chain.addressPrefix); + if (addressErrorMsg) { + setValidatorAddressError( + `Invalid address for network ${chain.chainId}: ${addressErrorMsg}`, + ); + return false; + } - if (!amount || Number(amount) <= 0) { - setAmountError("Amount must be greater than 0"); - return false; - } + if (!amount || Number(amount) <= 0) { + setAmountError("Amount must be greater than 0"); + return false; + } - return true; - }; + return true; + }; - const amountInAtomics = Decimal.fromUserInput( - amount || "0", - Number(chain.displayDenomExponent), - ).atomics; + const microCoin = (() => { + try { + return macroCoinToMicroCoin({ denom: chain.displayDenom, amount }, chain.assets); + } catch { + return { denom: chain.displayDenom, amount: "0" }; + } + })(); - const msgValue = MsgCodecs[MsgTypeUrls.Delegate].fromPartial({ - delegatorAddress, - validatorAddress, - amount: { amount: amountInAtomics, denom: chain.denom }, - }); + const msgValue = MsgCodecs[MsgTypeUrls.Delegate].fromPartial({ + delegatorAddress, + validatorAddress, + amount: microCoin, + }); - const msg: MsgDelegateEncodeObject = { typeUrl: MsgTypeUrls.Delegate, value: msgValue }; + const msg: MsgDelegateEncodeObject = { typeUrl: MsgTypeUrls.Delegate, value: msgValue }; - setMsgGetter({ isMsgValid, msg }); - } catch {} + setMsgGetter({ isMsgValid, msg }); }, [ - amount, chain.addressPrefix, + chain.assets, chain.chainId, - chain.denom, - chain.displayDenomExponent, + chain.displayDenom, delegatorAddress, setMsgGetter, - validatorAddress, + trimmedInputs, ]); return ( @@ -82,7 +87,10 @@ const MsgDelegateForm = ({ delegatorAddress, setMsgGetter, deleteMsg }: MsgDeleg label="Validator Address" name="validator-address" value={validatorAddress} - onChange={({ target }) => setValidatorAddress(target.value)} + onChange={({ target }) => { + setValidatorAddress(target.value); + setValidatorAddressError(""); + }} error={validatorAddressError} placeholder={`E.g. ${exampleAddress(0, chain.addressPrefix)}`} /> @@ -93,7 +101,10 @@ const MsgDelegateForm = ({ delegatorAddress, setMsgGetter, deleteMsg }: MsgDeleg label={`Amount (${chain.displayDenom})`} name="amount" value={amount} - onChange={({ target }) => setAmount(target.value)} + onChange={({ target }) => { + setAmount(target.value); + setAmountError(""); + }} error={amountError} /> diff --git a/components/forms/CreateTxForm/MsgForm/MsgExecuteContractForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgExecuteContractForm.tsx index f085dc2..f689478 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgExecuteContractForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgExecuteContractForm.tsx @@ -6,7 +6,7 @@ import { MsgGetter } from ".."; import { useChains } from "../../../../context/ChainsContext"; import { ChainInfo } from "../../../../context/ChainsContext/types"; import { macroCoinToMicroCoin } from "../../../../lib/coinHelpers"; -import { checkAddress, exampleAddress } from "../../../../lib/displayHelpers"; +import { checkAddress, exampleAddress, trimStringsObj } from "../../../../lib/displayHelpers"; import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; import Input from "../../../inputs/Input"; import Select from "../../../inputs/Select"; @@ -50,12 +50,17 @@ const MsgExecuteContractForm = ({ const [customDenomError, setCustomDenomError] = useState(""); const [amountError, setAmountError] = useState(""); + const trimmedInputs = trimStringsObj({ contractAddress, customDenom, amount }); + useEffect(() => { - setContractAddressError(""); - setCustomDenomError(""); - setAmountError(""); + // eslint-disable-next-line no-shadow + const { contractAddress, customDenom, amount } = trimmedInputs; const isMsgValid = (): boolean => { + setContractAddressError(""); + setCustomDenomError(""); + setAmountError(""); + if (jsonError.current) { return false; } @@ -115,16 +120,14 @@ const MsgExecuteContractForm = ({ setMsgGetter({ isMsgValid, msg }); }, [ - amount, chain.addressPrefix, chain.assets, chain.chainId, - contractAddress, - customDenom, fromAddress, msgContent, selectedDenom.value, setMsgGetter, + trimmedInputs, ]); return ( @@ -138,7 +141,10 @@ const MsgExecuteContractForm = ({ label="Contract Address" name="contract-address" value={contractAddress} - onChange={({ target }) => setContractAddress(target.value)} + onChange={({ target }) => { + setContractAddress(target.value); + setContractAddressError(""); + }} error={contractAddressError} placeholder={`E.g. ${exampleAddress(0, chain.addressPrefix)}`} /> @@ -165,6 +171,7 @@ const MsgExecuteContractForm = ({ if (option.value !== customDenomOption.value) { setCustomDenom(""); } + setCustomDenomError(""); }} /> @@ -174,7 +181,10 @@ const MsgExecuteContractForm = ({ label="Custom denom" name="custom-denom" value={customDenom} - onChange={({ target }) => setCustomDenom(target.value)} + onChange={({ target }) => { + setCustomDenom(target.value); + setCustomDenomError(""); + }} placeholder={ selectedDenom.value === customDenomOption.value ? "Enter custom denom" @@ -191,7 +201,10 @@ const MsgExecuteContractForm = ({ label="Amount" name="amount" value={amount} - onChange={({ target }) => setAmount(target.value)} + onChange={({ target }) => { + setAmount(target.value); + setAmountError(""); + }} error={amountError} /> diff --git a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx index 6253686..8e0fbb5 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx @@ -6,7 +6,7 @@ import { MsgGetter } from ".."; import { useChains } from "../../../../context/ChainsContext"; import { ChainInfo } from "../../../../context/ChainsContext/types"; import { macroCoinToMicroCoin } from "../../../../lib/coinHelpers"; -import { checkAddress, exampleAddress } from "../../../../lib/displayHelpers"; +import { checkAddress, exampleAddress, trimStringsObj } from "../../../../lib/displayHelpers"; import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; import Input from "../../../inputs/Input"; import Select from "../../../inputs/Select"; @@ -56,15 +56,20 @@ const MsgInstantiateContract2Form = ({ const [customDenomError, setCustomDenomError] = useState(""); const [amountError, setAmountError] = useState(""); + const trimmedInputs = trimStringsObj({ codeId, label, adminAddress, salt, customDenom, amount }); + useEffect(() => { - setCodeIdError(""); - setLabelError(""); - setAdminAddressError(""); - setSaltError(""); - setCustomDenomError(""); - setAmountError(""); + // eslint-disable-next-line no-shadow + const { codeId, label, adminAddress, salt, customDenom, amount } = trimmedInputs; const isMsgValid = (): boolean => { + setCodeIdError(""); + setLabelError(""); + setAdminAddressError(""); + setSaltError(""); + setCustomDenomError(""); + setAmountError(""); + if (jsonError.current) { return false; } @@ -160,19 +165,14 @@ const MsgInstantiateContract2Form = ({ setMsgGetter({ isMsgValid, msg }); }, [ - adminAddress, - amount, chain.addressPrefix, chain.assets, chain.chainId, - codeId, - customDenom, fromAddress, - label, msgContent, - salt, selectedDenom.value, setMsgGetter, + trimmedInputs, ]); return ( @@ -186,7 +186,10 @@ const MsgInstantiateContract2Form = ({ label="Code ID" name="code-id" value={codeId} - onChange={({ target }) => setCodeId(target.value)} + onChange={({ target }) => { + setCodeId(target.value); + setCodeIdError(""); + }} error={codeIdError} /> @@ -195,7 +198,10 @@ const MsgInstantiateContract2Form = ({ label="Label" name="label" value={label} - onChange={({ target }) => setLabel(target.value)} + onChange={({ target }) => { + setLabel(target.value); + setLabelError(""); + }} error={labelError} /> @@ -204,7 +210,10 @@ const MsgInstantiateContract2Form = ({ label="Admin Address" name="admin-address" value={adminAddress} - onChange={({ target }) => setAdminAddress(target.value)} + onChange={({ target }) => { + setAdminAddress(target.value); + setAdminAddressError(""); + }} error={adminAddressError} placeholder={`E.g. ${exampleAddress(0, chain.addressPrefix)}`} /> @@ -215,7 +224,10 @@ const MsgInstantiateContract2Form = ({ name="salt" placeholder="E.g. 1bac68" value={salt} - onChange={({ target }) => setSalt(target.value)} + onChange={({ target }) => { + setSalt(target.value); + setSaltError(""); + }} error={saltError} /> @@ -241,6 +253,7 @@ const MsgInstantiateContract2Form = ({ if (option.value !== customDenomOption.value) { setCustomDenom(""); } + setCustomDenomError(""); }} /> @@ -250,7 +263,10 @@ const MsgInstantiateContract2Form = ({ label="Custom denom" name="custom-denom" value={customDenom} - onChange={({ target }) => setCustomDenom(target.value)} + onChange={({ target }) => { + setCustomDenom(target.value); + setCustomDenomError(""); + }} placeholder={ selectedDenom.value === customDenomOption.value ? "Enter custom denom" @@ -267,7 +283,10 @@ const MsgInstantiateContract2Form = ({ label="Amount" name="amount" value={amount} - onChange={({ target }) => setAmount(target.value)} + onChange={({ target }) => { + setAmount(target.value); + setAmountError(""); + }} error={amountError} /> diff --git a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx index ae3d9a4..cb6de40 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx @@ -6,7 +6,7 @@ import { MsgGetter } from ".."; import { useChains } from "../../../../context/ChainsContext"; import { ChainInfo } from "../../../../context/ChainsContext/types"; import { macroCoinToMicroCoin } from "../../../../lib/coinHelpers"; -import { checkAddress, exampleAddress } from "../../../../lib/displayHelpers"; +import { checkAddress, exampleAddress, trimStringsObj } from "../../../../lib/displayHelpers"; import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; import Input from "../../../inputs/Input"; import Select from "../../../inputs/Select"; @@ -54,14 +54,19 @@ const MsgInstantiateContractForm = ({ const [customDenomError, setCustomDenomError] = useState(""); const [amountError, setAmountError] = useState(""); + const trimmedInputs = trimStringsObj({ codeId, label, adminAddress, customDenom, amount }); + useEffect(() => { - setCodeIdError(""); - setLabelError(""); - setAdminAddressError(""); - setCustomDenomError(""); - setAmountError(""); + // eslint-disable-next-line no-shadow + const { codeId, label, adminAddress, customDenom, amount } = trimmedInputs; const isMsgValid = (): boolean => { + setCodeIdError(""); + setLabelError(""); + setAdminAddressError(""); + setCustomDenomError(""); + setAmountError(""); + if (jsonError.current) { return false; } @@ -136,18 +141,14 @@ const MsgInstantiateContractForm = ({ setMsgGetter({ isMsgValid, msg }); }, [ - adminAddress, - amount, chain.addressPrefix, chain.assets, chain.chainId, - codeId, - customDenom, fromAddress, - label, msgContent, selectedDenom.value, setMsgGetter, + trimmedInputs, ]); return ( @@ -161,7 +162,10 @@ const MsgInstantiateContractForm = ({ label="Code ID" name="code-id" value={codeId} - onChange={({ target }) => setCodeId(target.value)} + onChange={({ target }) => { + setCodeId(target.value); + setCodeIdError(""); + }} error={codeIdError} /> @@ -170,7 +174,10 @@ const MsgInstantiateContractForm = ({ label="Label" name="label" value={label} - onChange={({ target }) => setLabel(target.value)} + onChange={({ target }) => { + setLabel(target.value); + setLabelError(""); + }} error={labelError} /> @@ -179,7 +186,10 @@ const MsgInstantiateContractForm = ({ label="Admin Address" name="admin-address" value={adminAddress} - onChange={({ target }) => setAdminAddress(target.value)} + onChange={({ target }) => { + setAdminAddress(target.value); + setAdminAddressError(""); + }} error={adminAddressError} placeholder={`E.g. ${exampleAddress(0, chain.addressPrefix)}`} /> @@ -206,6 +216,7 @@ const MsgInstantiateContractForm = ({ if (option.value !== customDenomOption.value) { setCustomDenom(""); } + setCustomDenomError(""); }} /> @@ -215,7 +226,10 @@ const MsgInstantiateContractForm = ({ label="Custom denom" name="custom-denom" value={customDenom} - onChange={({ target }) => setCustomDenom(target.value)} + onChange={({ target }) => { + setCustomDenom(target.value); + setCustomDenomError(""); + }} placeholder={ selectedDenom.value === customDenomOption.value ? "Enter custom denom" @@ -232,7 +246,10 @@ const MsgInstantiateContractForm = ({ label="Amount" name="amount" value={amount} - onChange={({ target }) => setAmount(target.value)} + onChange={({ target }) => { + setAmount(target.value); + setAmountError(""); + }} error={amountError} /> diff --git a/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx index c1f4dae..cf88534 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx @@ -4,7 +4,7 @@ import dynamic from "next/dynamic"; import { useEffect, useRef, useState } from "react"; import { MsgGetter } from ".."; import { useChains } from "../../../../context/ChainsContext"; -import { checkAddress, exampleAddress } from "../../../../lib/displayHelpers"; +import { checkAddress, exampleAddress, trimStringsObj } from "../../../../lib/displayHelpers"; import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; import Input from "../../../inputs/Input"; import StackableContainer from "../../../layout/StackableContainer"; @@ -32,11 +32,16 @@ const MsgMigrateContractForm = ({ const [contractAddressError, setContractAddressError] = useState(""); const [codeIdError, setCodeIdError] = useState(""); + const trimmedInputs = trimStringsObj({ contractAddress, codeId }); + useEffect(() => { - setCodeIdError(""); - setContractAddressError(""); + // eslint-disable-next-line no-shadow + const { contractAddress, codeId } = trimmedInputs; const isMsgValid = (): boolean => { + setContractAddressError(""); + setCodeIdError(""); + if (jsonError.current) { return false; } @@ -74,15 +79,7 @@ const MsgMigrateContractForm = ({ const msg: MsgMigrateContractEncodeObject = { typeUrl: MsgTypeUrls.Migrate, value: msgValue }; setMsgGetter({ isMsgValid, msg }); - }, [ - chain.addressPrefix, - chain.chainId, - codeId, - contractAddress, - fromAddress, - msgContent, - setMsgGetter, - ]); + }, [chain.addressPrefix, chain.chainId, fromAddress, msgContent, setMsgGetter, trimmedInputs]); return ( @@ -95,7 +92,10 @@ const MsgMigrateContractForm = ({ label="Contract Address" name="contract-address" value={contractAddress} - onChange={({ target }) => setContractAddress(target.value)} + onChange={({ target }) => { + setContractAddress(target.value); + setContractAddressError(""); + }} error={contractAddressError} placeholder={`E.g. ${exampleAddress(0, chain.addressPrefix)}`} /> @@ -105,7 +105,10 @@ const MsgMigrateContractForm = ({ label="Code ID" name="code-id" value={codeId} - onChange={({ target }) => setCodeId(target.value)} + onChange={({ target }) => { + setCodeId(target.value); + setCodeIdError(""); + }} error={codeIdError} /> diff --git a/components/forms/CreateTxForm/MsgForm/MsgRedelegateForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgRedelegateForm.tsx index 25b9f20..9a90587 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgRedelegateForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgRedelegateForm.tsx @@ -1,9 +1,9 @@ -import { Decimal } from "@cosmjs/math"; import { EncodeObject } from "@cosmjs/proto-signing"; import { useEffect, useState } from "react"; import { MsgGetter } from ".."; import { useChains } from "../../../../context/ChainsContext"; -import { checkAddress, exampleAddress } from "../../../../lib/displayHelpers"; +import { macroCoinToMicroCoin } from "../../../../lib/coinHelpers"; +import { checkAddress, exampleAddress, trimStringsObj } from "../../../../lib/displayHelpers"; import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; import Input from "../../../inputs/Input"; import StackableContainer from "../../../layout/StackableContainer"; @@ -29,63 +29,67 @@ const MsgRedelegateForm = ({ const [validatorDstAddressError, setValidatorDstAddressError] = useState(""); const [amountError, setAmountError] = useState(""); + const trimmedInputs = trimStringsObj({ validatorSrcAddress, validatorDstAddress, amount }); + useEffect(() => { - try { + // eslint-disable-next-line no-shadow + const { validatorSrcAddress, validatorDstAddress, amount } = trimmedInputs; + + const isMsgValid = (): boolean => { setValidatorSrcAddressError(""); setValidatorDstAddressError(""); setAmountError(""); - const isMsgValid = (): boolean => { - const srcAddressErrorMsg = checkAddress(validatorSrcAddress, chain.addressPrefix); - if (srcAddressErrorMsg) { - setValidatorSrcAddressError( - `Invalid address for network ${chain.chainId}: ${srcAddressErrorMsg}`, - ); - return false; - } + const srcAddressErrorMsg = checkAddress(validatorSrcAddress, chain.addressPrefix); + if (srcAddressErrorMsg) { + setValidatorSrcAddressError( + `Invalid address for network ${chain.chainId}: ${srcAddressErrorMsg}`, + ); + return false; + } - const dstAddressErrorMsg = checkAddress(validatorDstAddress, chain.addressPrefix); - if (dstAddressErrorMsg) { - setValidatorDstAddressError( - `Invalid address for network ${chain.chainId}: ${dstAddressErrorMsg}`, - ); - return false; - } + const dstAddressErrorMsg = checkAddress(validatorDstAddress, chain.addressPrefix); + if (dstAddressErrorMsg) { + setValidatorDstAddressError( + `Invalid address for network ${chain.chainId}: ${dstAddressErrorMsg}`, + ); + return false; + } - if (!amount || Number(amount) <= 0) { - setAmountError("Amount must be greater than 0"); - return false; - } + if (!amount || Number(amount) <= 0) { + setAmountError("Amount must be greater than 0"); + return false; + } - return true; - }; + return true; + }; - const amountInAtomics = Decimal.fromUserInput( - amount || "0", - Number(chain.displayDenomExponent), - ).atomics; + const microCoin = (() => { + try { + return macroCoinToMicroCoin({ denom: chain.displayDenom, amount }, chain.assets); + } catch { + return { denom: chain.displayDenom, amount: "0" }; + } + })(); - const msgValue = MsgCodecs[MsgTypeUrls.BeginRedelegate].fromPartial({ - delegatorAddress, - validatorSrcAddress, - validatorDstAddress, - amount: { amount: amountInAtomics, denom: chain.denom }, - }); + const msgValue = MsgCodecs[MsgTypeUrls.BeginRedelegate].fromPartial({ + delegatorAddress, + validatorSrcAddress, + validatorDstAddress, + amount: microCoin, + }); - const msg: EncodeObject = { typeUrl: MsgTypeUrls.BeginRedelegate, value: msgValue }; + const msg: EncodeObject = { typeUrl: MsgTypeUrls.BeginRedelegate, value: msgValue }; - setMsgGetter({ isMsgValid, msg }); - } catch {} + setMsgGetter({ isMsgValid, msg }); }, [ - amount, chain.addressPrefix, + chain.assets, chain.chainId, - chain.denom, - chain.displayDenomExponent, + chain.displayDenom, delegatorAddress, setMsgGetter, - validatorDstAddress, - validatorSrcAddress, + trimmedInputs, ]); return ( @@ -99,7 +103,10 @@ const MsgRedelegateForm = ({ label="Source Validator Address" name="src-validator-address" value={validatorSrcAddress} - onChange={({ target }) => setValidatorSrcAddress(target.value)} + onChange={({ target }) => { + setValidatorSrcAddress(target.value); + setValidatorSrcAddressError(""); + }} error={validatorSrcAddressError} placeholder={`E.g. ${exampleAddress(0, chain.addressPrefix)}`} /> @@ -109,7 +116,10 @@ const MsgRedelegateForm = ({ label="Destination Validator Address" name="dst-validator-address" value={validatorDstAddress} - onChange={({ target }) => setValidatorDstAddress(target.value)} + onChange={({ target }) => { + setValidatorDstAddress(target.value); + setValidatorDstAddressError(""); + }} error={validatorDstAddressError} placeholder={`E.g. ${exampleAddress(0, chain.addressPrefix)}`} /> @@ -120,7 +130,10 @@ const MsgRedelegateForm = ({ label={`Amount (${chain.displayDenom})`} name="amount" value={amount} - onChange={({ target }) => setAmount(target.value)} + onChange={({ target }) => { + setAmount(target.value); + setAmountError(""); + }} error={amountError} /> diff --git a/components/forms/CreateTxForm/MsgForm/MsgSendForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgSendForm.tsx index 9a8728b..64f65fe 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgSendForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgSendForm.tsx @@ -3,7 +3,7 @@ import { useEffect, useState } from "react"; import { MsgGetter } from ".."; import { useChains } from "../../../../context/ChainsContext"; import { macroCoinToMicroCoin } from "../../../../lib/coinHelpers"; -import { checkAddress, exampleAddress } from "../../../../lib/displayHelpers"; +import { checkAddress, exampleAddress, trimStringsObj } from "../../../../lib/displayHelpers"; import { RegistryAsset } from "../../../../types/chainRegistry"; import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; import Input from "../../../inputs/Input"; @@ -40,12 +40,17 @@ const MsgSendForm = ({ fromAddress, setMsgGetter, deleteMsg }: MsgSendFormProps) const [customDenomError, setCustomDenomError] = useState(""); const [amountError, setAmountError] = useState(""); + const trimmedInputs = trimStringsObj({ toAddress, customDenom, amount }); + useEffect(() => { - setToAddressError(""); - setCustomDenomError(""); - setAmountError(""); + // eslint-disable-next-line no-shadow + const { toAddress, customDenom, amount } = trimmedInputs; const isMsgValid = (): boolean => { + setToAddressError(""); + setCustomDenomError(""); + setAmountError(""); + const addressErrorMsg = checkAddress(toAddress, chain.addressPrefix); if (addressErrorMsg) { setToAddressError(`Invalid address for network ${chain.chainId}: ${addressErrorMsg}`); @@ -91,15 +96,13 @@ const MsgSendForm = ({ fromAddress, setMsgGetter, deleteMsg }: MsgSendFormProps) setMsgGetter({ isMsgValid, msg }); }, [ - amount, chain.addressPrefix, chain.assets, chain.chainId, - customDenom, fromAddress, selectedDenom.value, setMsgGetter, - toAddress, + trimmedInputs, ]); return ( @@ -113,7 +116,10 @@ const MsgSendForm = ({ fromAddress, setMsgGetter, deleteMsg }: MsgSendFormProps) label="Recipient Address" name="recipient-address" value={toAddress} - onChange={({ target }) => setToAddress(target.value)} + onChange={({ target }) => { + setToAddress(target.value); + setToAddressError(""); + }} error={toAddressError} placeholder={`E.g. ${exampleAddress(0, chain.addressPrefix)}`} /> @@ -130,6 +136,7 @@ const MsgSendForm = ({ fromAddress, setMsgGetter, deleteMsg }: MsgSendFormProps) if (option.value !== customDenomOption.value) { setCustomDenom(""); } + setCustomDenomError(""); }} /> @@ -139,7 +146,10 @@ const MsgSendForm = ({ fromAddress, setMsgGetter, deleteMsg }: MsgSendFormProps) label="Custom denom" name="custom-denom" value={customDenom} - onChange={({ target }) => setCustomDenom(target.value)} + onChange={({ target }) => { + setCustomDenom(target.value); + setCustomDenomError(""); + }} placeholder={ selectedDenom.value === customDenomOption.value ? "Enter custom denom" @@ -156,7 +166,10 @@ const MsgSendForm = ({ fromAddress, setMsgGetter, deleteMsg }: MsgSendFormProps) label="Amount" name="amount" value={amount} - onChange={({ target }) => setAmount(target.value)} + onChange={({ target }) => { + setAmount(target.value); + setAmountError(""); + }} error={amountError} /> diff --git a/components/forms/CreateTxForm/MsgForm/MsgSetWithdrawAddressForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgSetWithdrawAddressForm.tsx index 13f2519..4081bff 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgSetWithdrawAddressForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgSetWithdrawAddressForm.tsx @@ -2,7 +2,7 @@ import { EncodeObject } from "@cosmjs/proto-signing"; import { useEffect, useState } from "react"; import { MsgGetter } from ".."; import { useChains } from "../../../../context/ChainsContext"; -import { checkAddress, exampleAddress } from "../../../../lib/displayHelpers"; +import { checkAddress, exampleAddress, trimStringsObj } from "../../../../lib/displayHelpers"; import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; import Input from "../../../inputs/Input"; import StackableContainer from "../../../layout/StackableContainer"; @@ -23,31 +23,32 @@ const MsgSetWithdrawAddressForm = ({ const [withdrawAddress, setWithdrawAddress] = useState(""); const [withdrawAddressError, setWithdrawAddressError] = useState(""); + const trimmedInputs = trimStringsObj({ withdrawAddress }); + useEffect(() => { - try { + // eslint-disable-next-line no-shadow + const { withdrawAddress } = trimmedInputs; + + const isMsgValid = (): boolean => { setWithdrawAddressError(""); - const isMsgValid = (): boolean => { - const addressErrorMsg = checkAddress(withdrawAddress, chain.addressPrefix); - if (addressErrorMsg) { - setWithdrawAddressError( - `Invalid address for network ${chain.chainId}: ${addressErrorMsg}`, - ); - return false; - } + const addressErrorMsg = checkAddress(withdrawAddress, chain.addressPrefix); + if (addressErrorMsg) { + setWithdrawAddressError(`Invalid address for network ${chain.chainId}: ${addressErrorMsg}`); + return false; + } - return true; - }; + return true; + }; - const msgValue = MsgCodecs[MsgTypeUrls.SetWithdrawAddress].fromPartial({ - delegatorAddress, - withdrawAddress, - }); - const msg: EncodeObject = { typeUrl: MsgTypeUrls.SetWithdrawAddress, value: msgValue }; + const msgValue = MsgCodecs[MsgTypeUrls.SetWithdrawAddress].fromPartial({ + delegatorAddress, + withdrawAddress, + }); + const msg: EncodeObject = { typeUrl: MsgTypeUrls.SetWithdrawAddress, value: msgValue }; - setMsgGetter({ isMsgValid, msg }); - } catch {} - }, [chain.addressPrefix, chain.chainId, delegatorAddress, setMsgGetter, withdrawAddress]); + setMsgGetter({ isMsgValid, msg }); + }, [chain.addressPrefix, chain.chainId, delegatorAddress, setMsgGetter, trimmedInputs]); return ( @@ -60,7 +61,10 @@ const MsgSetWithdrawAddressForm = ({ label="Withdraw Address" name="withdraw-address" value={withdrawAddress} - onChange={({ target }) => setWithdrawAddress(target.value)} + onChange={({ target }) => { + setWithdrawAddress(target.value); + setWithdrawAddressError(""); + }} error={withdrawAddressError} placeholder={`E.g. ${exampleAddress(0, chain.addressPrefix)}`} /> diff --git a/components/forms/CreateTxForm/MsgForm/MsgTransferForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgTransferForm.tsx index 293214b..6142803 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgTransferForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgTransferForm.tsx @@ -6,7 +6,7 @@ import { datetimeLocalFromTimestamp, timestampFromDatetimeLocal, } from "../../../../lib/dateHelpers"; -import { checkAddress, exampleAddress } from "../../../../lib/displayHelpers"; +import { checkAddress, exampleAddress, trimStringsObj } from "../../../../lib/displayHelpers"; import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; import Input from "../../../inputs/Input"; import StackableContainer from "../../../layout/StackableContainer"; @@ -32,39 +32,48 @@ interface MsgTransferFormProps { const MsgTransferForm = ({ fromAddress, setMsgGetter, deleteMsg }: MsgTransferFormProps) => { const { chain } = useChains(); - const [sourcePort, setSourcePort] = useState("transfer"); - const [sourceChannel, setSourceChannel] = useState(""); + const [toAddress, setToAddress] = useState(""); const [denom, setDenom] = useState(""); const [amount, setAmount] = useState("0"); - const [toAddress, setToAddress] = useState(""); + const [sourcePort, setSourcePort] = useState("transfer"); + const [sourceChannel, setSourceChannel] = useState(""); const [timeout, setTimeout] = useState( datetimeLocalFromTimestamp(Date.now() + humanTimestampOptions[0].value), ); const [memo, setMemo] = useState(""); - const [sourcePortError, setSourcePortError] = useState(""); - const [sourceChannelError, setSourceChannelError] = useState(""); + const [toAddressError, setToAddressError] = useState(""); const [denomError, setDenomError] = useState(""); const [amountError, setAmountError] = useState(""); - const [toAddressError, setToAddressError] = useState(""); + const [sourcePortError, setSourcePortError] = useState(""); + const [sourceChannelError, setSourceChannelError] = useState(""); const [timeoutError, setTimeoutError] = useState(""); + const trimmedInputs = trimStringsObj({ + toAddress, + denom, + amount, + sourcePort, + sourceChannel, + timeout, + memo, + }); + useEffect(() => { - setSourcePortError(""); - setSourceChannelError(""); - setDenomError(""); - setAmountError(""); - setToAddressError(""); - setTimeoutError(""); + // eslint-disable-next-line no-shadow + const { toAddress, denom, amount, sourcePort, sourceChannel, timeout, memo } = trimmedInputs; const isMsgValid = (): boolean => { - if (!sourcePort) { - setSourcePortError("Source port is required"); - return false; - } + setToAddressError(""); + setDenomError(""); + setAmountError(""); + setSourcePortError(""); + setSourceChannelError(""); + setTimeoutError(""); - if (!sourceChannel) { - setSourceChannelError("Source channel is required"); + const addressErrorMsg = checkAddress(toAddress, null); // Allow address from any chain + if (addressErrorMsg) { + setToAddressError(`Invalid address for network ${chain.chainId}: ${addressErrorMsg}`); return false; } @@ -78,9 +87,13 @@ const MsgTransferForm = ({ fromAddress, setMsgGetter, deleteMsg }: MsgTransferFo return false; } - const addressErrorMsg = checkAddress(toAddress, null); // Allow address from any chain - if (addressErrorMsg) { - setToAddressError(`Invalid address for network ${chain.chainId}: ${addressErrorMsg}`); + if (!sourcePort) { + setSourcePortError("Source port is required"); + return false; + } + + if (!sourceChannel) { + setSourceChannelError("Source channel is required"); return false; } @@ -106,18 +119,7 @@ const MsgTransferForm = ({ fromAddress, setMsgGetter, deleteMsg }: MsgTransferFo const msg: MsgTransferEncodeObject = { typeUrl: MsgTypeUrls.Transfer, value: msgValue }; setMsgGetter({ isMsgValid, msg }); - }, [ - amount, - chain.chainId, - denom, - fromAddress, - memo, - setMsgGetter, - sourceChannel, - sourcePort, - timeout, - toAddress, - ]); + }, [chain.chainId, fromAddress, setMsgGetter, trimmedInputs]); return ( @@ -130,7 +132,10 @@ const MsgTransferForm = ({ fromAddress, setMsgGetter, deleteMsg }: MsgTransferFo label="Recipient Address" name="recipient-address" value={toAddress} - onChange={({ target }) => setToAddress(target.value)} + onChange={({ target }) => { + setToAddress(target.value); + setToAddressError(""); + }} error={toAddressError} placeholder={`E.g. ${exampleAddress(0, chain.addressPrefix)}`} /> @@ -140,7 +145,10 @@ const MsgTransferForm = ({ fromAddress, setMsgGetter, deleteMsg }: MsgTransferFo label="Denom" name="denom" value={denom} - onChange={({ target }) => setDenom(target.value)} + onChange={({ target }) => { + setDenom(target.value); + setDenomError(""); + }} error={denomError} /> @@ -150,7 +158,10 @@ const MsgTransferForm = ({ fromAddress, setMsgGetter, deleteMsg }: MsgTransferFo label="Amount" name="amount" value={amount} - onChange={({ target }) => setAmount(target.value)} + onChange={({ target }) => { + setAmount(target.value); + setAmountError(""); + }} error={amountError} /> @@ -159,7 +170,10 @@ const MsgTransferForm = ({ fromAddress, setMsgGetter, deleteMsg }: MsgTransferFo label="Source Port" name="source-port" value={sourcePort} - onChange={({ target }) => setSourcePort(target.value)} + onChange={({ target }) => { + setSourcePort(target.value); + setSourcePortError(""); + }} error={sourcePortError} /> @@ -168,7 +182,10 @@ const MsgTransferForm = ({ fromAddress, setMsgGetter, deleteMsg }: MsgTransferFo label="Source Channel" name="source-channel" value={sourceChannel} - onChange={({ target }) => setSourceChannel(target.value)} + onChange={({ target }) => { + setSourceChannel(target.value); + setSourceChannelError(""); + }} error={sourceChannelError} /> @@ -179,7 +196,10 @@ const MsgTransferForm = ({ fromAddress, setMsgGetter, deleteMsg }: MsgTransferFo label="Timeout" name="timeout" value={timeout} - onChange={({ target }) => setTimeout(target.value)} + onChange={({ target }) => { + setTimeout(target.value); + setTimeoutError(""); + }} error={timeoutError} /> diff --git a/components/forms/CreateTxForm/MsgForm/MsgUndelegateForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgUndelegateForm.tsx index b1a16c5..d4b81e6 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgUndelegateForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgUndelegateForm.tsx @@ -1,9 +1,9 @@ -import { Decimal } from "@cosmjs/math"; import { MsgUndelegateEncodeObject } from "@cosmjs/stargate"; import { useEffect, useState } from "react"; import { MsgGetter } from ".."; import { useChains } from "../../../../context/ChainsContext"; -import { checkAddress, exampleAddress } from "../../../../lib/displayHelpers"; +import { macroCoinToMicroCoin } from "../../../../lib/coinHelpers"; +import { checkAddress, exampleAddress, trimStringsObj } from "../../../../lib/displayHelpers"; import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; import Input from "../../../inputs/Input"; import StackableContainer from "../../../layout/StackableContainer"; @@ -27,52 +27,57 @@ const MsgUndelegateForm = ({ const [validatorAddressError, setValidatorAddressError] = useState(""); const [amountError, setAmountError] = useState(""); + const trimmedInputs = trimStringsObj({ validatorAddress, amount }); + useEffect(() => { - try { + // eslint-disable-next-line no-shadow + const { validatorAddress, amount } = trimmedInputs; + + const isMsgValid = (): boolean => { setValidatorAddressError(""); setAmountError(""); - const isMsgValid = (): boolean => { - const addressErrorMsg = checkAddress(validatorAddress, chain.addressPrefix); - if (addressErrorMsg) { - setValidatorAddressError( - `Invalid address for network ${chain.chainId}: ${addressErrorMsg}`, - ); - return false; - } + const addressErrorMsg = checkAddress(validatorAddress, chain.addressPrefix); + if (addressErrorMsg) { + setValidatorAddressError( + `Invalid address for network ${chain.chainId}: ${addressErrorMsg}`, + ); + return false; + } - if (!amount || Number(amount) <= 0) { - setAmountError("Amount must be greater than 0"); - return false; - } + if (!amount || Number(amount) <= 0) { + setAmountError("Amount must be greater than 0"); + return false; + } - return true; - }; + return true; + }; - const amountInAtomics = Decimal.fromUserInput( - amount || "0", - Number(chain.displayDenomExponent), - ).atomics; + const microCoin = (() => { + try { + return macroCoinToMicroCoin({ denom: chain.displayDenom, amount }, chain.assets); + } catch { + return { denom: chain.displayDenom, amount: "0" }; + } + })(); - const msgValue = MsgCodecs[MsgTypeUrls.Undelegate].fromPartial({ - delegatorAddress, - validatorAddress, - amount: { amount: amountInAtomics, denom: chain.denom }, - }); + const msgValue = MsgCodecs[MsgTypeUrls.Undelegate].fromPartial({ + delegatorAddress, + validatorAddress, + amount: microCoin, + }); - const msg: MsgUndelegateEncodeObject = { typeUrl: MsgTypeUrls.Undelegate, value: msgValue }; + const msg: MsgUndelegateEncodeObject = { typeUrl: MsgTypeUrls.Undelegate, value: msgValue }; - setMsgGetter({ isMsgValid, msg }); - } catch {} + setMsgGetter({ isMsgValid, msg }); }, [ - amount, chain.addressPrefix, + chain.assets, chain.chainId, - chain.denom, - chain.displayDenomExponent, + chain.displayDenom, delegatorAddress, setMsgGetter, - validatorAddress, + trimmedInputs, ]); return ( @@ -86,7 +91,10 @@ const MsgUndelegateForm = ({ label="Validator Address" name="validator-address" value={validatorAddress} - onChange={({ target }) => setValidatorAddress(target.value)} + onChange={({ target }) => { + setValidatorAddress(target.value); + setValidatorAddressError(""); + }} error={validatorAddressError} placeholder={`E.g. ${exampleAddress(0, chain.addressPrefix)}`} /> @@ -97,7 +105,10 @@ const MsgUndelegateForm = ({ label={`Amount (${chain.displayDenom})`} name="amount" value={amount} - onChange={({ target }) => setAmount(target.value)} + onChange={({ target }) => { + setAmount(target.value); + setAmountError(""); + }} error={amountError} />