moves multisig queries to client

to be able to use context-based chain info
This commit is contained in:
samepant
2022-02-01 21:09:45 -05:00
parent 279279831d
commit aef9516047
4 changed files with 109 additions and 45 deletions
+4 -4
View File
@@ -38,7 +38,7 @@ const createMultisigFromCompressedSecp256k1Pubkeys = async (
/**
* This gets a multisigs account (pubkey, sequence, account number, etc) from
* a node and/or the faunadb 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
@@ -53,12 +53,12 @@ const getMultisigAccount = async (address, client) => {
if (!accountOnChain || !accountOnChain.pubkey) {
console.log("No pubkey on chain for: ", address);
const res = await getMultisig(address);
const res = await axios.get(`/api/multisig/${address}`);
if (!res.data.data.getMultisig) {
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.data.getMultisig.pubkeyJSON);
const pubkey = JSON.parse(res.data.pubkeyJSON);
if (!accountOnChain) {
accountOnChain = {};
@@ -0,0 +1,26 @@
import { getMultisig } from "../../../../lib/graphqlHelpers";
export default async function (req, res) {
switch (req.method) {
case "GET":
try {
const { multisigAddress } = req.query;
console.log("Function `getMultisig` invoked", multisigAddress);
const getRes = await getMultisig(multisigAddress);
if (!getRes.data.data.getMultisig) {
res.status(404).send("Multisig not found");
return;
}
console.log("success", getRes.data.data.getMultisig);
res.status(200).send(getRes.data.data.getMultisig);
return;
} catch (err) {
console.log(err);
res.status(400).send(err.message);
return;
}
}
// no route matched
res.status(405).end();
return;
}
+32 -25
View File
@@ -1,8 +1,9 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import { pubkeyToAddress } from "@cosmjs/amino";
import { StargateClient } from "@cosmjs/stargate";
import { useRouter } from "next/router";
import { useAppContext } from "../../../context/AppContext";
import Button from "../../../components/inputs/Button";
import { getMultisigAccount } from "../../../lib/multisigHelpers";
import HashView from "../../../components/dataViews/HashView";
@@ -12,23 +13,6 @@ import Page from "../../../components/layout/Page";
import StackableContainer from "../../../components/layout/StackableContainer";
import TransactionForm from "../../../components/forms/TransactionForm";
export async function getServerSideProps(context) {
try {
const client = await StargateClient.connect(process.env.NEXT_PUBLIC_NODE_ADDRESS);
const multisigAddress = context.params.address;
const holdings = await client.getBalance(multisigAddress, process.env.NEXT_PUBLIC_DENOM);
const accountOnChain = await getMultisigAccount(multisigAddress, client);
return {
props: { accountOnChain, holdings },
};
} catch (error) {
console.log(error);
return {
props: { error: error.message },
};
}
}
function participantPubkeysFromMultisig(multisigPubkey) {
return multisigPubkey.value.pubkeys;
}
@@ -40,28 +24,51 @@ function participantAddressesFromMultisig(multisigPubkey, addressPrefix) {
}
const multipage = (props) => {
const { state } = useAppContext();
const [showTxForm, setShowTxForm] = useState(false);
const [holdings, setHoldings] = useState("");
const [accountOnChain, setAccountOnChain] = useState(null);
const [accountError, setAccountError] = useState(null);
const router = useRouter();
const { address } = router.query;
useEffect(() => {
if (router.query.address) {
fetchMultisig(router.query.address);
}
}, [router.query.address]);
const fetchMultisig = async (address) => {
try {
const client = await StargateClient.connect(state.chain.nodeAddress);
const tempHoldings = await client.getBalance(address, state.chain.denom);
const tempAccountOnChain = await getMultisigAccount(address, client);
setHoldings(tempHoldings);
setAccountOnChain(tempAccountOnChain);
} catch (error) {
setAccountError(error.message);
console.log("Account error:", error);
}
};
return (
<Page>
<StackableContainer base>
<StackableContainer>
<label>Multisig Address</label>
<h1>
<HashView hash={address} />
<HashView hash={router.query.address} />
</h1>
</StackableContainer>
{props.accountOnChain?.pubkey && (
<MultisigMembers
members={participantAddressesFromMultisig(
props.accountOnChain?.pubkey,
process.env.NEXT_PUBLIC_ADDRESS_PREFIX,
accountOnChain?.pubkey,
state.chain.addressPrefix,
)}
threshold={props.accountOnChain?.pubkey.value.threshold}
/>
)}
{props.error && (
{accountError && (
<StackableContainer>
<div className="multisig-error">
<p>
@@ -78,7 +85,7 @@ const multipage = (props) => {
)}
{showTxForm ? (
<TransactionForm
address={address}
address={router.query.address}
accountOnChain={props.accountOnChain}
closeForm={() => {
setShowTxForm(false);
@@ -87,7 +94,7 @@ const multipage = (props) => {
) : (
<div className="interfaces">
<div className="col-1">
<MultisigHoldings holdings={props.holdings} />
<MultisigHoldings holdings={holdings} />
</div>
<div className="col-2">
<StackableContainer lessPadding>
@@ -2,9 +2,11 @@ import React from "react";
import axios from "axios";
import { StargateClient, makeMultisignedTx } from "@cosmjs/stargate";
import { TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx";
import { useState } from "react";
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import { fromBase64 } from "@cosmjs/encoding";
import { useAppContext } from "../../../../context/AppContext";
import Button from "../../../../components/inputs/Button";
import { findTransactionByID } from "../../../../lib/graphqlHelpers";
import { getMultisigAccount } from "../../../../lib/multisigHelpers";
@@ -16,17 +18,12 @@ import TransactionSigning from "../../../../components/forms/TransactionSigning"
import CompletedTransaction from "../../../../components/dataViews/CompletedTransaction";
export async function getServerSideProps(context) {
// get multisig account and transaction info
const nodeAddress = process.env.NEXT_PUBLIC_NODE_ADDRESS;
const client = await StargateClient.connect(nodeAddress);
const multisigAddress = context.params.address;
// get transaction info
const transactionID = context.params.transactionID;
let transactionJSON;
let txHash;
let accountOnChain;
let signatures;
try {
accountOnChain = await getMultisigAccount(multisigAddress, client);
console.log("Function `findTransactionByID` invoked", transactionID);
const getRes = await findTransactionByID(transactionID);
console.log("success", getRes.data);
@@ -38,13 +35,10 @@ export async function getServerSideProps(context) {
}
return {
props: {
multisigAddress,
transactionJSON,
txHash,
accountOnChain,
transactionID,
signatures,
nodeAddress,
},
};
}
@@ -54,18 +48,42 @@ const transactionPage = ({
transactionJSON,
transactionID,
signatures,
accountOnChain,
nodeAddress,
txHash,
}) => {
const { state } = useAppContext();
const [currentSignatures, setCurrentSignatures] = useState(signatures);
const [broadcastError, setBroadcastError] = useState("");
const [isBroadcasting, setIsBroadcasting] = useState(false);
const [transactionHash, setTransactionHash] = useState(txHash);
const [_holdings, setHoldings] = useState("");
const [accountOnChain, setAccountOnChain] = useState(null);
const [accountError, setAccountError] = useState(null);
const txInfo = (transactionJSON && JSON.parse(transactionJSON)) || null;
const router = useRouter();
const addSignature = (signature) => {
setCurrentSignatures((prevState) => [...prevState, signature]);
};
useEffect(() => {
if (router.query.address) {
fetchMultisig(router.query.address);
}
}, [router.query.address]);
const fetchMultisig = async (address) => {
try {
const client = await StargateClient.connect(state.chain.nodeAddress);
const tempHoldings = await client.getBalance(address, state.chain.denom);
const tempAccountOnChain = await getMultisigAccount(address, client);
setHoldings(tempHoldings);
setAccountOnChain(tempAccountOnChain);
} catch (error) {
setAccountError(error.message);
console.log("Account error:", error);
}
};
const broadcastTx = async () => {
try {
setIsBroadcasting(true);
@@ -79,7 +97,7 @@ const transactionPage = ({
bodyBytes,
new Map(currentSignatures.map((s) => [s.address, fromBase64(s.signature)])),
);
const broadcaster = await StargateClient.connect(nodeAddress);
const broadcaster = await StargateClient.connect(state.chain.nodeAddress);
const result = await broadcaster.broadcastTx(
Uint8Array.from(TxRaw.encode(signedTx).finish()),
);
@@ -100,13 +118,20 @@ const transactionPage = ({
<StackableContainer>
<h1>{transactionHash ? "Completed Transaction" : "In Progress Transaction"}</h1>
</StackableContainer>
{accountError && (
<StackableContainer>
<div className="multisig-error">
<p>Multisig address could not be found.</p>
</div>
</StackableContainer>
)}
{transactionHash && <CompletedTransaction transactionHash={transactionHash} />}
<TransactionInfo tx={txInfo} />
{!transactionHash && (
{!transactionHash && accountOnChain && (
<ThresholdInfo signatures={currentSignatures} account={accountOnChain} />
)}
{currentSignatures.length >= parseInt(accountOnChain.pubkey.value.threshold, 10) &&
{accountOnChain &&
currentSignatures.length >= parseInt(accountOnChain.pubkey.value.threshold, 10) &&
!transactionHash && (
<>
<Button
@@ -138,6 +163,12 @@ const transactionPage = ({
font-family: monospace;
max-width: 475px;
}
.multisig-error p {
max-width: 550px;
color: red;
font-size: 16px;
line-height: 1.4;
}
`}</style>
</Page>
);