From 9d0a936668b0b2cc68bff3f17761729120ebfc30 Mon Sep 17 00:00:00 2001 From: Matthew A Elder Date: Thu, 24 Feb 2022 09:44:49 -0700 Subject: [PATCH 1/6] default yes --- components/forms/FlexibleTransactionForm.js | 2 +- components/messages/MsgVote.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/components/forms/FlexibleTransactionForm.js b/components/forms/FlexibleTransactionForm.js index 74068933..cb48c40e 100644 --- a/components/forms/FlexibleTransactionForm.js +++ b/components/forms/FlexibleTransactionForm.js @@ -104,7 +104,7 @@ function blankVoteJSON(voter, proposalId = -1) { value: { voter, proposalId, - option: 0, + option: 1, }, }, null, diff --git a/components/messages/MsgVote.js b/components/messages/MsgVote.js index 3b4a30e0..32fc46f2 100644 --- a/components/messages/MsgVote.js +++ b/components/messages/MsgVote.js @@ -7,7 +7,6 @@ import { checkAddress, exampleAddress } from "../../lib/displayHelpers"; // https://docs.cosmos.network/v0.44/core/proto-docs.html#cosmos.gov.v1beta1.VoteOption const voteOptions = [ - { label: "Unspecified", value: 0 }, { label: "Yes", value: 1 }, { label: "Abstain", value: 2 }, { label: "No", value: 3 }, From f7787c6abf0fe949b8220a2b404a0f0a98df5131 Mon Sep 17 00:00:00 2001 From: Matthew A Elder Date: Thu, 24 Feb 2022 10:33:40 -0700 Subject: [PATCH 2/6] wip --- components/forms/FlexibleTransactionForm.js | 2 +- components/forms/TransactionSigning.js | 21 ++++++++++----------- components/messages/MsgVote.js | 1 + pages/multi/[address]/index.js | 2 -- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/components/forms/FlexibleTransactionForm.js b/components/forms/FlexibleTransactionForm.js index cb48c40e..74068933 100644 --- a/components/forms/FlexibleTransactionForm.js +++ b/components/forms/FlexibleTransactionForm.js @@ -104,7 +104,7 @@ function blankVoteJSON(voter, proposalId = -1) { value: { voter, proposalId, - option: 1, + option: 0, }, }, null, diff --git a/components/forms/TransactionSigning.js b/components/forms/TransactionSigning.js index 5dc5ca07..dce3dade 100644 --- a/components/forms/TransactionSigning.js +++ b/components/forms/TransactionSigning.js @@ -16,20 +16,19 @@ const TransactionSigning = (props) => { useEffect(() => { connectWallet(); + window.addEventListener("keplr_keystorechange", connectWallet); }, []); const connectWallet = async () => { - try { - await window.keplr.enable(state.chain.chainId); - const tempWalletAccount = await window.keplr.getKey(state.chain.chainId); - const tempHasSigned = props.signatures.some( - (sig) => sig.address === tempWalletAccount.bech32Address, - ); - setWalletAccount(tempWalletAccount); - setHasSigned(tempHasSigned); - } catch (e) { - console.log("enable err: ", e); - } + await window.keplr.enable(state.chain.chainId); + const tempWalletAccount = await window.keplr.getKey(state.chain.chainId); + const tempHasSigned = props.signatures.some( + (sig) => sig.address === tempWalletAccount.bech32Address, + ); + setWalletAccount(tempWalletAccount); + setHasSigned(tempHasSigned); + console.log("wallet changed", tempWalletAccount); + window.keplr_wallet = tempWalletAccount; }; const signTransaction = async () => { diff --git a/components/messages/MsgVote.js b/components/messages/MsgVote.js index 32fc46f2..3b4a30e0 100644 --- a/components/messages/MsgVote.js +++ b/components/messages/MsgVote.js @@ -7,6 +7,7 @@ import { checkAddress, exampleAddress } from "../../lib/displayHelpers"; // https://docs.cosmos.network/v0.44/core/proto-docs.html#cosmos.gov.v1beta1.VoteOption const voteOptions = [ + { label: "Unspecified", value: 0 }, { label: "Yes", value: 1 }, { label: "Abstain", value: 2 }, { label: "No", value: 3 }, diff --git a/pages/multi/[address]/index.js b/pages/multi/[address]/index.js index a38de487..f2760c64 100644 --- a/pages/multi/[address]/index.js +++ b/pages/multi/[address]/index.js @@ -23,12 +23,10 @@ function participantAddressesFromMultisig(multisigPubkey, addressPrefix) { ); } -const msgKinds = ["/cosmos.bank.v1beta1.MsgSend", "/cosmos.staking.v1beta1.MsgDelegate"]; const multipage = (_props) => { const { state } = useAppContext(); const [showTxForm, setShowTxForm] = useState(false); - const [msgKind, setMsgKind] = useState("/cosmos.bank.v1beta1.MsgSend"); const [holdings, setHoldings] = useState(""); const [accountOnChain, setAccountOnChain] = useState(null); const [accountError, setAccountError] = useState(null); From c7db860588c26f600ffd8d009854f4e3288b99a3 Mon Sep 17 00:00:00 2001 From: Matthew A Elder Date: Thu, 24 Feb 2022 10:37:19 -0700 Subject: [PATCH 3/6] nomenclature change --- components/forms/TransactionSigning.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/forms/TransactionSigning.js b/components/forms/TransactionSigning.js index dce3dade..96369b85 100644 --- a/components/forms/TransactionSigning.js +++ b/components/forms/TransactionSigning.js @@ -27,7 +27,7 @@ const TransactionSigning = (props) => { ); setWalletAccount(tempWalletAccount); setHasSigned(tempHasSigned); - console.log("wallet changed", tempWalletAccount); + console.log("wallet connected:", tempWalletAccount); window.keplr_wallet = tempWalletAccount; }; From 16bc40bea173dbc5d0b1a62fa8e415c34541b3b4 Mon Sep 17 00:00:00 2001 From: Matthew A Elder Date: Thu, 24 Feb 2022 11:04:50 -0700 Subject: [PATCH 4/6] remove some defensive try catches --- components/forms/MultisigForm.js | 19 +++--- components/forms/TransactionSigning.js | 83 ++++++++++++-------------- 2 files changed, 45 insertions(+), 57 deletions(-) diff --git a/components/forms/MultisigForm.js b/components/forms/MultisigForm.js index c3b47d3d..e7b9281e 100644 --- a/components/forms/MultisigForm.js +++ b/components/forms/MultisigForm.js @@ -93,18 +93,13 @@ const MultiSigForm = (props) => { const handleCreate = async () => { setProcessing(true); const compressedPubkeys = pubkeys.map((item) => item.compressedPubkey); - let multisigAddress; - try { - multisigAddress = await createMultisigFromCompressedSecp256k1Pubkeys( - compressedPubkeys, - parseInt(threshold, 10), - state.chain.addressPrefix, - state.chain.chainId, - ); - props.router.push(`/multi/${multisigAddress}`); - } catch (error) { - console.log("Failed to creat multisig: ", error); - } + const multisigAddress = await createMultisigFromCompressedSecp256k1Pubkeys( + compressedPubkeys, + parseInt(threshold, 10), + state.chain.addressPrefix, + state.chain.chainId, + ); + props.router.push(`/multi/${multisigAddress}`); }; const togglePubkey = (index) => { diff --git a/components/forms/TransactionSigning.js b/components/forms/TransactionSigning.js index 96369b85..216cd33f 100644 --- a/components/forms/TransactionSigning.js +++ b/components/forms/TransactionSigning.js @@ -32,52 +32,45 @@ const TransactionSigning = (props) => { }; const signTransaction = async () => { - try { - window.keplr.defaultOptions = { - sign: { - preferNoSetMemo: true, - preferNoSetFee: true, - disableBalanceCheck: true, - }, - }; - const offlineSigner = window.getOfflineSignerOnlyAmino(state.chain.chainId); - const signingClient = await SigningStargateClient.offline(offlineSigner); - const signerData = { - accountNumber: props.tx.accountNumber, - sequence: props.tx.sequence, - chainId: state.chain.chainId, - }; - const { bodyBytes, signatures } = await signingClient.sign( - walletAccount.bech32Address, - props.tx.msgs, - props.tx.fee, - props.tx.memo, - signerData, - ); - // check existing signatures - const bases64EncodedSignature = toBase64(signatures[0]); - const bases64EncodedBodyBytes = toBase64(bodyBytes); - const prevSigMatch = props.signatures.findIndex( - (signature) => signature.signature === bases64EncodedSignature, - ); + window.keplr.defaultOptions = { + sign: { + preferNoSetMemo: true, + preferNoSetFee: true, + disableBalanceCheck: true, + }, + }; + const offlineSigner = window.getOfflineSignerOnlyAmino(state.chain.chainId); + const signingClient = await SigningStargateClient.offline(offlineSigner); + const signerData = { + accountNumber: props.tx.accountNumber, + sequence: props.tx.sequence, + chainId: state.chain.chainId, + }; + const { bodyBytes, signatures } = await signingClient.sign( + walletAccount.bech32Address, + props.tx.msgs, + props.tx.fee, + props.tx.memo, + signerData, + ); + // check existing signatures + const bases64EncodedSignature = toBase64(signatures[0]); + const bases64EncodedBodyBytes = toBase64(bodyBytes); + const prevSigMatch = props.signatures.findIndex( + (signature) => signature.signature === bases64EncodedSignature, + ); - if (prevSigMatch > -1) { - setSigError("This account has already signed."); - } else { - const signature = { - bodyBytes: bases64EncodedBodyBytes, - signature: bases64EncodedSignature, - address: walletAccount.bech32Address, - }; - const _res = await axios.post( - `/api/transaction/${props.transactionID}/signature`, - signature, - ); - props.addSignature(signature); - setHasSigned(true); - } - } catch (error) { - console.log("Error creating signature:", error); + if (prevSigMatch > -1) { + setSigError("This account has already signed."); + } else { + const signature = { + bodyBytes: bases64EncodedBodyBytes, + signature: bases64EncodedSignature, + address: walletAccount.bech32Address, + }; + const _res = await axios.post(`/api/transaction/${props.transactionID}/signature`, signature); + props.addSignature(signature); + setHasSigned(true); } }; From 2ed7fdae2b416c09383da21ae77075cc6a412d17 Mon Sep 17 00:00:00 2001 From: Matthew A Elder Date: Thu, 24 Feb 2022 11:41:41 -0700 Subject: [PATCH 5/6] streamline get multisig remove defensivity --- lib/multisigHelpers.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/lib/multisigHelpers.js b/lib/multisigHelpers.js index 3e5b861a..4e30aaa3 100644 --- a/lib/multisigHelpers.js +++ b/lib/multisigHelpers.js @@ -51,22 +51,15 @@ const getMultisigAccount = async (address, client) => { // is new, and has never submitted a transaction its pubkeys will not be // available from a node. If the multisig was created with this instance // of this tool its pubkey will be available in the fauna datastore - let accountOnChain = await client.getAccount(address); + const accountOnChain = await client.getAccount(address); const chainId = await client.getChainId(); if (!accountOnChain || !accountOnChain.pubkey) { - console.log("No pubkey on chain for: ", address); const res = await axios.get(`/api/chain/${chainId}/multisig/${address}`); if (res.status !== 200) { throw new Error("Multisig has no pubkey on node, and was not created using this tool."); } - const pubkey = JSON.parse(res.data.pubkeyJSON); - - if (!accountOnChain) { - accountOnChain = {}; - } - accountOnChain.pubkey = pubkey; } return accountOnChain; }; From d12f02692e50887ff4b6dfe212c059ce1ab7644d Mon Sep 17 00:00:00 2001 From: Matthew A Elder Date: Thu, 24 Feb 2022 11:54:02 -0700 Subject: [PATCH 6/6] fix bug in voting, add some validation --- components/messages/MsgVote.js | 18 +++++++++++++++++- lib/displayHelpers.js | 16 ++++++++++++++++ pages/multi/[address]/index.js | 1 - 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/components/messages/MsgVote.js b/components/messages/MsgVote.js index 3b4a30e0..63bf20a1 100644 --- a/components/messages/MsgVote.js +++ b/components/messages/MsgVote.js @@ -3,7 +3,7 @@ import React, { useState, useEffect } from "react"; import { useAppContext } from "../../context/AppContext"; import Input from "../../components/inputs/Input"; import Select from "../../components/inputs/Select"; -import { checkAddress, exampleAddress } from "../../lib/displayHelpers"; +import { checkAddress, checkProposalId } from "../../lib/displayHelpers"; // https://docs.cosmos.network/v0.44/core/proto-docs.html#cosmos.gov.v1beta1.VoteOption const voteOptions = [ @@ -19,6 +19,7 @@ const MsgVote = (props) => { const onCheck = props.onCheck || (() => {}); const { state } = useAppContext(); const [voterError, setVoterError] = useState(""); + const [proposalIdError, setProposalIdError] = useState(""); // const [amountError, setAmountError] = useState(""); @@ -41,6 +42,20 @@ const MsgVote = (props) => { } } + const toProposalIdError = checkProposalId(v.proposalId); + if (updateInternalErrors) { + if (toProposalIdError) { + const errorMsg = `Invalid proposal_id for network ${state.chain.chainId}: ${toProposalIdError}`; + setProposalIdError(errorMsg); + } else { + setProposalIdError(""); + } + } + + if (toVoterError || toProposalIdError) { + return false; + } + return true; } @@ -82,6 +97,7 @@ const MsgVote = (props) => { type="number" value={props.msg.value.proposalId} onChange={(e) => checkAndSetProposalId(e.target.value)} + error={proposalIdError} />
diff --git a/lib/displayHelpers.js b/lib/displayHelpers.js index 2af93024..74a6aa47 100644 --- a/lib/displayHelpers.js +++ b/lib/displayHelpers.js @@ -123,6 +123,21 @@ const checkAddress = (input, chainAddressPrefix) => { return null; }; +const checkProposalId = (input) => { + if (!input) return "Empty"; + const n = parseInt(input, 10); + + if (isNaN(n)) { + return "Expected an integer"; + } + + if (n < 0) { + return "Expected a non-negative number"; + } + + return null; +}; + /** * Returns a link to a transaction in an explorer if an explorer is configured * for transactions. Returns null otherwise. @@ -141,5 +156,6 @@ export { exampleAddress, examplePubkey, checkAddress, + checkProposalId, explorerLinkTx, }; diff --git a/pages/multi/[address]/index.js b/pages/multi/[address]/index.js index f2760c64..61a6f763 100644 --- a/pages/multi/[address]/index.js +++ b/pages/multi/[address]/index.js @@ -23,7 +23,6 @@ function participantAddressesFromMultisig(multisigPubkey, addressPrefix) { ); } - const multipage = (_props) => { const { state } = useAppContext(); const [showTxForm, setShowTxForm] = useState(false);