import { StargateClient } from "@cosmjs/stargate"; import { assert } from "@cosmjs/utils"; import { NextRouter, withRouter } from "next/router"; import { useState } from "react"; import { useAppContext } from "../../context/AppContext"; import { exampleAddress, examplePubkey } from "../../lib/displayHelpers"; import { createMultisigFromCompressedSecp256k1Pubkeys } from "../../lib/multisigHelpers"; import Button from "../inputs/Button"; import Input from "../inputs/Input"; import ThresholdInput from "../inputs/ThresholdInput"; import StackableContainer from "../layout/StackableContainer"; const emptyPubKeyGroup = () => { return { address: "", compressedPubkey: "", keyError: "", isPubkey: false }; }; interface Props { router: NextRouter; } const MultiSigForm = (props: Props) => { const { state } = useAppContext(); const [pubkeys, setPubkeys] = useState([emptyPubKeyGroup(), emptyPubKeyGroup()]); const [threshold, setThreshold] = useState(2); const [processing, setProcessing] = useState(false); const handleChangeThreshold = (e: React.ChangeEvent) => { let newThreshold = parseInt(e.target.value, 10); if (newThreshold > pubkeys.length || newThreshold <= 0) { newThreshold = threshold; } setThreshold(newThreshold); }; const handleKeyGroupChange = (index: number, e: React.ChangeEvent) => { const tempPubkeys = [...pubkeys]; if (e.target.name === "compressedPubkey") { tempPubkeys[index].compressedPubkey = e.target.value; } else if (e.target.name === "address") { tempPubkeys[index].address = e.target.value; } setPubkeys(tempPubkeys); }; const handleAddKey = () => { const tempPubkeys = [...pubkeys]; setPubkeys(tempPubkeys.concat(emptyPubKeyGroup())); }; const handleRemove = (index: number) => { const tempPubkeys = [...pubkeys]; const oldLength = tempPubkeys.length; tempPubkeys.splice(index, 1); const newThreshold = threshold > tempPubkeys.length ? tempPubkeys.length : oldLength; setPubkeys(tempPubkeys); setThreshold(newThreshold); }; const getPubkeyFromNode = async (address: string) => { assert(state.chain.nodeAddress, "nodeAddress missing"); const client = await StargateClient.connect(state.chain.nodeAddress); const accountOnChain = await client.getAccount(address); console.log(accountOnChain); if (!accountOnChain || !accountOnChain.pubkey) { throw new Error( "Account has no pubkey on chain, this address will need to send a transaction to appear on chain.", ); } return accountOnChain.pubkey.value; }; const handleKeyBlur = async (index: number, e: React.ChangeEvent) => { try { const tempPubkeys = [...pubkeys]; let pubkey; // use pubkey console.log(tempPubkeys[index]); if (tempPubkeys[index].isPubkey) { pubkey = e.target.value; if (pubkey.length !== 44) { throw new Error("Invalid Secp256k1 pubkey"); } } else { // use address to fetch pubkey const address = e.target.value; if (address.length > 0) { pubkey = await getPubkeyFromNode(address); } } tempPubkeys[index].compressedPubkey = pubkey; tempPubkeys[index].keyError = ""; setPubkeys(tempPubkeys); // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error: any) { console.log(error); const tempPubkeys = [...pubkeys]; tempPubkeys[index].keyError = error.message; setPubkeys(tempPubkeys); } }; const handleCreate = async () => { setProcessing(true); const compressedPubkeys = pubkeys.map((item) => item.compressedPubkey); let multisigAddress; try { assert(state.chain.addressPrefix, "addressPrefix missing"); assert(state.chain.chainId, "chainId missing"); multisigAddress = await createMultisigFromCompressedSecp256k1Pubkeys( compressedPubkeys, threshold, state.chain.addressPrefix, state.chain.chainId, ); props.router.push(`/multi/${multisigAddress}`); } catch (error) { console.log("Failed to creat multisig: ", error); } }; const togglePubkey = (index: number) => { const tempPubkeys = [...pubkeys]; tempPubkeys[index].isPubkey = !tempPubkeys[index].isPubkey; setPubkeys(tempPubkeys); }; return ( <>

Add the addresses that will make up this multisig.

{pubkeys.map((pubkeyGroup, index) => { assert(state.chain.addressPrefix, "addressPrefix missing"); return (
{pubkeys.length > 2 && ( )}
) => { handleKeyGroupChange(index, e); }} value={ pubkeyGroup.isPubkey ? pubkeyGroup.compressedPubkey : pubkeyGroup.address } label={pubkeyGroup.isPubkey ? "Public Key (Secp256k1)" : "Address"} name={pubkeyGroup.isPubkey ? "compressedPubkey" : "address"} width="100%" placeholder={`E.g. ${ pubkeyGroup.isPubkey ? examplePubkey(index) : exampleAddress(index, state.chain.addressPrefix) }`} error={pubkeyGroup.keyError} onBlur={(e: React.ChangeEvent) => { handleKeyBlur(index, e); }} />
); })}