Merge pull request #70 from cosmos/pubkey-with-null-account

Let getMultisigAccount always return a pubkey
This commit is contained in:
Simon Warta
2022-06-28 09:55:02 +02:00
committed by GitHub
6 changed files with 49 additions and 45 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ import StackableContainer from "../layout/StackableContainer";
interface Props {
/** Addresses of the multisig members */
members: string[];
threshold: number;
threshold: string;
}
const MultisigMembers = (props: Props) => (
+5 -4
View File
@@ -1,14 +1,15 @@
import React from "react";
import { MultisigThresholdPubkey } from "@cosmjs/amino";
import { DbSignature } from "../../types";
import StackableContainer from "../layout/StackableContainer";
import { AccountWithPubkey } from "../../lib/multisigHelpers";
interface Props {
signatures: DbSignature[];
account: AccountWithPubkey;
pubkey: MultisigThresholdPubkey;
}
const ThresholdInfo = ({ signatures, account }: Props) => (
const ThresholdInfo = ({ signatures, pubkey }: Props) => (
<StackableContainer lessPadding lessMargin>
<h2>Signatures</h2>
<StackableContainer lessPadding lessMargin lessRadius>
@@ -21,7 +22,7 @@ const ThresholdInfo = ({ signatures, account }: Props) => (
<div className="threshold">
<div className="current">{signatures.length}</div>
<div className="label divider">of</div>
<div className="required">{account.pubkey.value.threshold}</div>
<div className="required">{pubkey.value.threshold}</div>
<div className="label">signatures complete</div>
</div>
</StackableContainer>
+2 -3
View File
@@ -1,5 +1,5 @@
import axios from "axios";
import { calculateFee } from "@cosmjs/stargate";
import { Account, calculateFee } from "@cosmjs/stargate";
import { Decimal } from "@cosmjs/math";
import { assert } from "@cosmjs/utils";
import React, { useState } from "react";
@@ -10,11 +10,10 @@ import Button from "../inputs/Button";
import Input from "../inputs/Input";
import StackableContainer from "../layout/StackableContainer";
import { checkAddress, exampleAddress } from "../../lib/displayHelpers";
import { AccountWithPubkey } from "../../lib/multisigHelpers";
interface Props {
address: string | null;
accountOnChain: AccountWithPubkey | null;
accountOnChain: Account | null;
router: NextRouter;
closeForm: () => void;
}
+19 -16
View File
@@ -1,7 +1,13 @@
import axios from "axios";
import { createMultisigThresholdPubkey, Pubkey, pubkeyToAddress } from "@cosmjs/amino";
import {
createMultisigThresholdPubkey,
isMultisigThresholdPubkey,
MultisigThresholdPubkey,
pubkeyToAddress,
} from "@cosmjs/amino";
import { Account } from "@cosmjs/stargate";
import { StargateClient } from "@cosmjs/stargate";
import { assert } from "@cosmjs/utils";
/**
* Turns array of compressed Secp256k1 pubkeys
@@ -40,31 +46,31 @@ const createMultisigFromCompressedSecp256k1Pubkeys = async (
return res.data.address;
};
/** Like Account but with non-optional pubkey */
export type AccountWithPubkey = Account & { readonly pubkey: Pubkey };
/**
* This gets a multisigs account (pubkey, sequence, account number, etc) from
* a node and/or the api if the multisig was made on this app
* a node and/or the api if the multisig was made on this app.
*
* @param {string} address The multisig address
* @param client A connected stargate cosmoshub client
* @return {object} The multisig account.
* The public key should always be available, either on chain or in the app's database.
* The account is only available when the there was any on-chain activity such as
* receipt of tokens.
*/
const getMultisigAccount = async (
address: string,
client: StargateClient,
): Promise<AccountWithPubkey | null> => {
): Promise<[MultisigThresholdPubkey, Account | null]> => {
// we need the multisig pubkeys to create transactions, if the multisig
// 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
const accountOnChain = await client.getAccount(address);
const chainId = await client.getChainId();
if (!accountOnChain) return null;
let pubkey: Pubkey;
if (accountOnChain.pubkey) {
let pubkey: MultisigThresholdPubkey;
if (accountOnChain?.pubkey) {
assert(
isMultisigThresholdPubkey(accountOnChain.pubkey),
"Pubkey on chain is not of type MultisigThreshold",
);
pubkey = accountOnChain.pubkey;
} else {
console.log("No pubkey on chain for: ", address);
@@ -76,10 +82,7 @@ const getMultisigAccount = async (
pubkey = JSON.parse(res.data.pubkeyJSON);
}
return {
...accountOnChain,
pubkey: pubkey,
};
return [pubkey, accountOnChain];
};
export { createMultisigFromCompressedSecp256k1Pubkeys, getMultisigAccount };
+11 -12
View File
@@ -1,13 +1,13 @@
import React, { useState, useEffect } from "react";
import { pubkeyToAddress, Pubkey } from "@cosmjs/amino";
import { StargateClient } from "@cosmjs/stargate";
import { pubkeyToAddress, Pubkey, MultisigThresholdPubkey } from "@cosmjs/amino";
import { Account, StargateClient } from "@cosmjs/stargate";
import { assert } from "@cosmjs/utils";
import { Coin } from "cosmjs-types/cosmos/base/v1beta1/coin";
import { useRouter } from "next/router";
import { useAppContext } from "../../../context/AppContext";
import Button from "../../../components/inputs/Button";
import { AccountWithPubkey, getMultisigAccount } from "../../../lib/multisigHelpers";
import { getMultisigAccount } from "../../../lib/multisigHelpers";
import HashView from "../../../components/dataViews/HashView";
import MultisigHoldings from "../../../components/dataViews/MultisigHoldings";
import MultisigMembers from "../../../components/dataViews/MultisigMembers";
@@ -30,7 +30,8 @@ const multipage = () => {
const [showTxForm, setShowTxForm] = useState(false);
const [holdings, setHoldings] = useState<Coin | null>(null);
const [multisigAddress, setMultisigAddress] = useState("");
const [accountOnChain, setAccountOnChain] = useState<AccountWithPubkey | null>(null);
const [accountOnChain, setAccountOnChain] = useState<Account | null>(null);
const [pubkey, setPubkey] = useState<MultisigThresholdPubkey>();
const [accountError, setAccountError] = useState(null);
const router = useRouter();
@@ -49,9 +50,10 @@ const multipage = () => {
const client = await StargateClient.connect(state.chain.nodeAddress);
assert(state.chain.denom, "denom missing");
const tempHoldings = await client.getBalance(address, state.chain.denom);
const tempAccountOnChain = await getMultisigAccount(address, client);
setHoldings(tempHoldings);
setAccountOnChain(tempAccountOnChain);
const result = await getMultisigAccount(address, client);
setPubkey(result[0]);
setAccountOnChain(result[1]);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
setAccountError(error.message);
@@ -74,13 +76,10 @@ const multipage = () => {
)}
</h1>
</StackableContainer>
{accountOnChain && (
{pubkey && (
<MultisigMembers
members={participantAddressesFromMultisig(
accountOnChain.pubkey,
state.chain.addressPrefix,
)}
threshold={accountOnChain.pubkey.value.threshold}
members={participantAddressesFromMultisig(pubkey, state.chain.addressPrefix)}
threshold={pubkey.value.threshold}
/>
)}
{accountError && (
@@ -1,7 +1,7 @@
import axios from "axios";
import React from "react";
import { GetServerSideProps } from "next";
import { StargateClient, makeMultisignedTx } from "@cosmjs/stargate";
import { StargateClient, makeMultisignedTx, Account } from "@cosmjs/stargate";
import { TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx";
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
@@ -12,7 +12,7 @@ import { DbSignature, DbTransaction } from "../../../../types";
import { useAppContext } from "../../../../context/AppContext";
import Button from "../../../../components/inputs/Button";
import { findTransactionByID } from "../../../../lib/graphqlHelpers";
import { AccountWithPubkey, getMultisigAccount } from "../../../../lib/multisigHelpers";
import { getMultisigAccount } from "../../../../lib/multisigHelpers";
import Page from "../../../../components/layout/Page";
import StackableContainer from "../../../../components/layout/StackableContainer";
import ThresholdInfo from "../../../../components/dataViews/ThresholdInfo";
@@ -75,7 +75,8 @@ const transactionPage = ({
const [broadcastError, setBroadcastError] = useState("");
const [isBroadcasting, setIsBroadcasting] = useState(false);
const [transactionHash, setTransactionHash] = useState(txHash);
const [accountOnChain, setAccountOnChain] = useState<AccountWithPubkey | null>(null);
const [accountOnChain, setAccountOnChain] = useState<Account | null>(null);
const [pubkey, setPubkey] = useState<MultisigThresholdPubkey>();
const [accountError, setAccountError] = useState(null);
const txInfo: DbTransaction = (transactionJSON && JSON.parse(transactionJSON)) || null;
const router = useRouter();
@@ -95,8 +96,9 @@ const transactionPage = ({
try {
assert(state.chain.nodeAddress, "Node address missing");
const client = await StargateClient.connect(state.chain.nodeAddress);
const tempAccountOnChain = await getMultisigAccount(address, client);
setAccountOnChain(tempAccountOnChain);
const result = await getMultisigAccount(address, client);
setPubkey(result[0]);
setAccountOnChain(result[1]);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
setAccountError(error.toString());
@@ -150,11 +152,11 @@ const transactionPage = ({
)}
{transactionHash && <CompletedTransaction transactionHash={transactionHash} />}
<TransactionInfo tx={txInfo} />
{!transactionHash && accountOnChain && (
<ThresholdInfo signatures={currentSignatures} account={accountOnChain} />
{!transactionHash && pubkey && (
<ThresholdInfo signatures={currentSignatures} pubkey={pubkey} />
)}
{accountOnChain &&
currentSignatures.length >= parseInt(accountOnChain.pubkey.value.threshold, 10) &&
{pubkey &&
currentSignatures.length >= parseInt(pubkey.value.threshold, 10) &&
!transactionHash && (
<>
<Button