diff --git a/components/dataViews/TransactionInfo/TxMsgUpdateAdminContractDetails.tsx b/components/dataViews/TransactionInfo/TxMsgUpdateAdminContractDetails.tsx new file mode 100644 index 0000000..04e9e3f --- /dev/null +++ b/components/dataViews/TransactionInfo/TxMsgUpdateAdminContractDetails.tsx @@ -0,0 +1,59 @@ +import { MsgUpdateAdmin } from "cosmjs-types/cosmwasm/wasm/v1/tx"; +import HashView from "../HashView"; + +interface TxMsgUpdateAdminDetailsProps { + readonly msgValue: MsgUpdateAdmin; +} + +const TxMsgUpdateAdminDetails = ({ msgValue }: TxMsgUpdateAdminDetailsProps) => { + return ( + <> +
  • +

    MsgUpdateAdmin

    +
  • +
  • + +
    + +
    +
  • +
  • + +
    {msgValue.newAdmin.toString()}
    +
  • + + + ); +}; + +export default TxMsgUpdateAdminDetails; diff --git a/components/dataViews/TransactionInfo/index.tsx b/components/dataViews/TransactionInfo/index.tsx index e0a959b..c8f6c42 100644 --- a/components/dataViews/TransactionInfo/index.tsx +++ b/components/dataViews/TransactionInfo/index.tsx @@ -16,6 +16,7 @@ import TxMsgSendDetails from "./TxMsgSendDetails"; import TxMsgSetWithdrawAddressDetails from "./TxMsgSetWithdrawAddressDetails"; import TxMsgTransferDetails from "./TxMsgTransferDetails"; import TxMsgUndelegateDetails from "./TxMsgUndelegateDetails"; +import TxMsgUpdateAdminContractDetails from "./TxMsgUpdateAdminContractDetails"; const TxMsgDetails = ({ typeUrl, value: msgValue }: EncodeObject) => { switch (typeUrl) { @@ -43,6 +44,8 @@ const TxMsgDetails = ({ typeUrl, value: msgValue }: EncodeObject) => { return ; case MsgTypeUrls.Migrate: return ; + case MsgTypeUrls.UpdateAdmin: + return ; default: return null; } diff --git a/components/forms/CreateTxForm/MsgForm/MsgUpdateAdminContractForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgUpdateAdminContractForm.tsx new file mode 100644 index 0000000..3aa6e75 --- /dev/null +++ b/components/forms/CreateTxForm/MsgForm/MsgUpdateAdminContractForm.tsx @@ -0,0 +1,128 @@ +import { MsgUpdateAdminEncodeObject } from "@cosmjs/cosmwasm-stargate"; +import { useEffect, useRef, useState } from "react"; +import { MsgGetter } from ".."; +import { useChains } from "../../../../context/ChainsContext"; +import { checkAddress, exampleAddress, trimStringsObj } from "../../../../lib/displayHelpers"; +import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; +import Input from "../../../inputs/Input"; +import StackableContainer from "../../../layout/StackableContainer"; + +interface MsgUpdateAdminContractFormProps { + readonly fromAddress: string; + readonly setMsgGetter: (msgGetter: MsgGetter) => void; + readonly deleteMsg: () => void; +} + +const MsgUpdateAdminContractForm = ({ + fromAddress, + setMsgGetter, + deleteMsg, + }: MsgUpdateAdminContractFormProps) => { + const { chain } = useChains(); + + const [contractAddress, setContractAddress] = useState(""); + const [newAdmin, setNewAdmin] = useState(""); + + const [contractAddressError, setContractAddressError] = useState(""); + const [codeIdError, setNewAdminError] = useState(""); + + const trimmedInputs = trimStringsObj({ contractAddress, newAdmin }); + + useEffect(() => { + // eslint-disable-next-line no-shadow + const { contractAddress, newAdmin } = trimmedInputs; + + const isMsgValid = (): boolean => { + setContractAddressError(""); + setNewAdminError(""); + + const addressErrorMsg = checkAddress(contractAddress, chain.addressPrefix); + if (addressErrorMsg) { + setContractAddressError(`Invalid address for network ${chain.chainId}: ${addressErrorMsg}`); + return false; + } + + const newAdminErrorMsg = checkAddress(newAdmin, chain.addressPrefix); + if (newAdminErrorMsg) { + setNewAdminError("New admin should be a valid bech32 address."); + return false; + } + + return true; + }; + + const msgValue = MsgCodecs[MsgTypeUrls.UpdateAdmin].fromPartial({ + sender: fromAddress, + contract: contractAddress, + newAdmin: newAdmin, + }); + + const msg: MsgUpdateAdminEncodeObject = { typeUrl: MsgTypeUrls.UpdateAdmin, value: msgValue }; + + setMsgGetter({ isMsgValid, msg }); + }, [chain.addressPrefix, chain.chainId, fromAddress, setMsgGetter, trimmedInputs]); + + return ( + + +

    MsgUpdateAdminContract

    +
    + { + setContractAddress(target.value); + setContractAddressError(""); + }} + error={contractAddressError} + placeholder={`E.g. ${exampleAddress(0, chain.addressPrefix)}`} + /> +
    +
    + { + setNewAdmin(target.value); + setNewAdminError(""); + }} + error={codeIdError} + /> +
    + +
    + ); +}; + +export default MsgUpdateAdminContractForm; diff --git a/components/forms/CreateTxForm/MsgForm/index.tsx b/components/forms/CreateTxForm/MsgForm/index.tsx index 21f048f..13718b5 100644 --- a/components/forms/CreateTxForm/MsgForm/index.tsx +++ b/components/forms/CreateTxForm/MsgForm/index.tsx @@ -12,6 +12,7 @@ import MsgSendForm from "./MsgSendForm"; import MsgSetWithdrawAddressForm from "./MsgSetWithdrawAddressForm"; import MsgTransferForm from "./MsgTransferForm"; import MsgUndelegateForm from "./MsgUndelegateForm"; +import MsgUpdateAdminContractForm from "@/components/forms/CreateTxForm/MsgForm/MsgUpdateAdminContractForm"; interface MsgFormProps { readonly msgType: MsgTypeUrl; @@ -46,6 +47,8 @@ const MsgForm = ({ msgType, senderAddress, ...restProps }: MsgFormProps) => { return ; case MsgTypeUrls.Migrate: return ; + case MsgTypeUrls.UpdateAdmin: + return ; default: return null; } diff --git a/components/forms/CreateTxForm/index.tsx b/components/forms/CreateTxForm/index.tsx index f5aca87..c575686 100644 --- a/components/forms/CreateTxForm/index.tsx +++ b/components/forms/CreateTxForm/index.tsx @@ -254,6 +254,9 @@ const CreateTxForm = ({ router, senderAddress, accountOnChain }: CreateTxFormPro
  • +
  • +
  • diff --git a/lib/txMsgHelpers.ts b/lib/txMsgHelpers.ts index 5f365b3..e4022e6 100644 --- a/lib/txMsgHelpers.ts +++ b/lib/txMsgHelpers.ts @@ -30,6 +30,8 @@ const gasOfMsg = (msgType: MsgTypeUrl): number => { return 150_000; case MsgTypeUrls.Migrate: return 150_000; + case MsgTypeUrls.UpdateAdmin: + return 150_000; default: throw new Error("Unknown msg type"); } @@ -37,8 +39,7 @@ const gasOfMsg = (msgType: MsgTypeUrl): number => { export const gasOfTx = (msgTypes: readonly MsgTypeUrl[]): number => { const txFlatGas = 100_000; - const totalTxGas = msgTypes.reduce((acc, msgType) => acc + gasOfMsg(msgType), txFlatGas); - return totalTxGas; + return msgTypes.reduce((acc, msgType) => acc + gasOfMsg(msgType), txFlatGas); }; export const isKnownMsgTypeUrl = (typeUrl: string): typeUrl is MsgTypeUrl => diff --git a/types/txMsg.ts b/types/txMsg.ts index 6a1ccb2..129d3ab 100644 --- a/types/txMsg.ts +++ b/types/txMsg.ts @@ -14,6 +14,7 @@ import { MsgInstantiateContract, MsgInstantiateContract2, MsgMigrateContract, + MsgUpdateAdmin } from "cosmjs-types/cosmwasm/wasm/v1/tx"; import { MsgTransfer } from "cosmjs-types/ibc/applications/transfer/v1/tx"; @@ -30,6 +31,7 @@ export const MsgTypeUrls = { Instantiate: "/cosmwasm.wasm.v1.MsgInstantiateContract", Instantiate2: "/cosmwasm.wasm.v1.MsgInstantiateContract2", Migrate: "/cosmwasm.wasm.v1.MsgMigrateContract", + UpdateAdmin: "/cosmwasm.wasm.v1.MsgUpdateAdmin", } as const; export type MsgTypeUrl = (typeof MsgTypeUrls)[keyof typeof MsgTypeUrls]; @@ -47,4 +49,5 @@ export const MsgCodecs = { [MsgTypeUrls.Instantiate]: MsgInstantiateContract, [MsgTypeUrls.Instantiate2]: MsgInstantiateContract2, [MsgTypeUrls.Migrate]: MsgMigrateContract, + [MsgTypeUrls.UpdateAdmin]: MsgUpdateAdmin, };