Merge pull request #1 from samepant/save-sig
Save transaction hash on successful broadcast
This commit is contained in:
commit
35f62daf80
13
components/dataViews/CompletedTransaction.js
Normal file
13
components/dataViews/CompletedTransaction.js
Normal file
@ -0,0 +1,13 @@
|
||||
import StackableContainer from "../layout/StackableContainer";
|
||||
import Button from "../inputs/Button";
|
||||
|
||||
export default ({ transactionHash }) => (
|
||||
<StackableContainer lessPadding lessMargin>
|
||||
This transaction has been broadcast.
|
||||
<Button
|
||||
href={`https://www.mintscan.io/cosmos/txs/${transactionHash}`}
|
||||
label=" View on Mintscan"
|
||||
></Button>
|
||||
<style jsx>{``}</style>
|
||||
</StackableContainer>
|
||||
);
|
||||
41
components/dataViews/ThresholdInfo.js
Normal file
41
components/dataViews/ThresholdInfo.js
Normal file
@ -0,0 +1,41 @@
|
||||
import StackableContainer from "../layout/StackableContainer";
|
||||
|
||||
export default ({ signatures, account }) => (
|
||||
<StackableContainer lessPadding lessMargin>
|
||||
<h2>Signatures</h2>
|
||||
<StackableContainer lessPadding lessMargin lessRadius>
|
||||
<p>
|
||||
Once the number of required signatures have been created, this
|
||||
transaction will be ready to broadcast.
|
||||
</p>
|
||||
</StackableContainer>
|
||||
<StackableContainer lessPadding lessMargin lessRadius>
|
||||
<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="label">signatures complete</div>
|
||||
</div>
|
||||
</StackableContainer>
|
||||
<style jsx>{`
|
||||
.threshold {
|
||||
display: flex;
|
||||
font-size: 30px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.threshold div {
|
||||
padding: 0 5px;
|
||||
}
|
||||
.label {
|
||||
font-size: 16px;
|
||||
}
|
||||
p {
|
||||
margin-top: 1em;
|
||||
}
|
||||
p:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
`}</style>
|
||||
</StackableContainer>
|
||||
);
|
||||
@ -23,11 +23,6 @@ export default (props) => (
|
||||
</div>
|
||||
</li>
|
||||
)}
|
||||
|
||||
<li>
|
||||
<label>Status:</label>
|
||||
<div>{props.tx.status || "signing in progress"}</div>
|
||||
</li>
|
||||
{props.tx.fee && (
|
||||
<li>
|
||||
<label>Gas:</label>
|
||||
|
||||
@ -31,7 +31,7 @@ class TransactionForm extends React.Component {
|
||||
const msgSend = {
|
||||
fromAddress: this.props.address,
|
||||
toAddress: toAddress,
|
||||
amount: coins(amount * 1000000, "uatom"),
|
||||
amount: coins(amount * 1000000, "stake"),
|
||||
};
|
||||
const msg = {
|
||||
typeUrl: "/cosmos.bank.v1beta1.MsgSend",
|
||||
@ -39,19 +39,18 @@ class TransactionForm extends React.Component {
|
||||
};
|
||||
const gasLimit = gas;
|
||||
const fee = {
|
||||
amount: coins(2000, "uatom"),
|
||||
amount: coins(2000, "stake"),
|
||||
gas: gasLimit.toString(),
|
||||
};
|
||||
|
||||
return {
|
||||
accountNumber: this.props.accountOnChain.accountNumber,
|
||||
sequence: this.props.accountOnChain.sequence,
|
||||
chainId: "cosmoshub-4",
|
||||
chainId: "purp-chain",
|
||||
msgs: [msg],
|
||||
fee: fee,
|
||||
memo: this.state.memo,
|
||||
};
|
||||
return baseTX;
|
||||
};
|
||||
|
||||
handleCreate = async () => {
|
||||
@ -62,7 +61,7 @@ class TransactionForm extends React.Component {
|
||||
this.state.amount,
|
||||
this.state.gas
|
||||
);
|
||||
|
||||
console.log(tx);
|
||||
const dataJSON = JSON.stringify(tx);
|
||||
const res = await axios.post("/api/transaction", { dataJSON });
|
||||
const { transactionID } = res.data;
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import axios from "axios";
|
||||
import { encode, decode } from "uint8-to-base64";
|
||||
import React from "react";
|
||||
import { SigningStargateClient } from "@cosmjs/stargate";
|
||||
import { registry } from "@cosmjs/proto-signing";
|
||||
|
||||
import Button from "../inputs/Button";
|
||||
import StackableContainer from "../layout/StackableContainer";
|
||||
@ -13,6 +15,7 @@ export default class TransactionSigning extends React.Component {
|
||||
transaction: this.props.transaction,
|
||||
walletAccount: null,
|
||||
walletError: null,
|
||||
sigError: null,
|
||||
};
|
||||
}
|
||||
|
||||
@ -41,9 +44,14 @@ export default class TransactionSigning extends React.Component {
|
||||
|
||||
connectWallet = async () => {
|
||||
try {
|
||||
await window.keplr.enable("cosmoshub");
|
||||
const walletAccount = await window.keplr.getKey("cosmoshub");
|
||||
console.log(walletAccount);
|
||||
window.keplr.defaultOptions = {
|
||||
sign: {
|
||||
preferNoSetMemo: true,
|
||||
preferNoSetFee: true,
|
||||
},
|
||||
};
|
||||
await window.keplr.enable("purp-chain");
|
||||
const walletAccount = await window.keplr.getKey("purp-chain");
|
||||
this.setState({ walletAccount });
|
||||
} catch (e) {
|
||||
console.log("enable err: ", e);
|
||||
@ -52,14 +60,13 @@ export default class TransactionSigning extends React.Component {
|
||||
|
||||
signTransaction = async () => {
|
||||
try {
|
||||
const offlineSigner = window.getOfflineSigner("cosmoshub");
|
||||
const offlineSigner = window.getOfflineSignerOnlyAmino("purp-chain");
|
||||
const accounts = await offlineSigner.getAccounts();
|
||||
console.log(accounts);
|
||||
const signingClient = await SigningStargateClient.offline(offlineSigner);
|
||||
const signerData = {
|
||||
accountNumber: this.props.tx.accountNumber,
|
||||
sequence: this.props.tx.sequence,
|
||||
chainId: "cosmoshub",
|
||||
chainId: "purp-chain",
|
||||
};
|
||||
const { bodyBytes, signatures } = await signingClient.sign(
|
||||
this.state.walletAccount.bech32Address,
|
||||
@ -68,30 +75,63 @@ export default class TransactionSigning extends React.Component {
|
||||
this.props.tx.memo,
|
||||
signerData
|
||||
);
|
||||
// save body bytes to the tx
|
||||
// save/create the signature in the db
|
||||
console.log(bodyBytes, signatures);
|
||||
// check existing signatures
|
||||
const bases64EncodedSignature = encode(signatures[0]);
|
||||
const bases64EncodedBodyBytes = encode(bodyBytes);
|
||||
const prevSigMatch = this.props.signatures.findIndex(
|
||||
(signature) => signature.signature === bases64EncodedSignature
|
||||
);
|
||||
|
||||
if (prevSigMatch > -1) {
|
||||
this.setState({ sigError: "This account has already signed." });
|
||||
} else {
|
||||
const signature = {
|
||||
bodyBytes: bases64EncodedBodyBytes,
|
||||
signature: bases64EncodedSignature,
|
||||
address: this.state.walletAccount.bech32Address,
|
||||
};
|
||||
const res = await axios.post(
|
||||
`/api/transaction/${this.props.transactionID}/signature`,
|
||||
signature
|
||||
);
|
||||
this.props.addSignature(res.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
console.log("Error creating signature:", error);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<StackableContainer lessPadding>
|
||||
<StackableContainer lessPadding lessMargin>
|
||||
<h2>Sign this transaction</h2>
|
||||
{this.state.walletAccount ? (
|
||||
<Button label="Sign transaction" onClick={this.signTransaction} />
|
||||
) : (
|
||||
<Button label="Connect Wallet" onClick={this.connectWallet} />
|
||||
)}
|
||||
|
||||
<h2>Current Signatures</h2>
|
||||
{!this.state.signatures && (
|
||||
<StackableContainer lessPadding lessMargin lessRadius>
|
||||
<p>No signatures yet</p>
|
||||
{this.state.sigError && (
|
||||
<StackableContainer lessPadding lessRadius lessMargin>
|
||||
<div className="signature-error">
|
||||
<p>This account has already signed this transaction.</p>
|
||||
</div>
|
||||
</StackableContainer>
|
||||
)}
|
||||
<h2>Current Signers</h2>
|
||||
<StackableContainer lessPadding lessMargin lessRadius>
|
||||
{this.props.signatures.map((signature, i) => (
|
||||
<StackableContainer
|
||||
lessPadding
|
||||
lessRadius
|
||||
lessMargin
|
||||
key={`${signature.address}_${i}`}
|
||||
>
|
||||
<p>{signature.address}</p>
|
||||
</StackableContainer>
|
||||
))}
|
||||
|
||||
{this.props.signatures.length === 0 && <p>No signatures yet</p>}
|
||||
</StackableContainer>
|
||||
<style jsx>{`
|
||||
p {
|
||||
text-align: center;
|
||||
@ -103,6 +143,20 @@ export default class TransactionSigning extends React.Component {
|
||||
h2:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.signature-error p {
|
||||
max-width: 550px;
|
||||
color: red;
|
||||
font-size: 16px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.signature-error p:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
`}</style>
|
||||
</StackableContainer>
|
||||
);
|
||||
|
||||
@ -1,14 +1,25 @@
|
||||
const Button = (props) => (
|
||||
<>
|
||||
<button
|
||||
className={props.primary ? "primary" : ""}
|
||||
onClick={props.onClick}
|
||||
disable={props.disable && props.disable.toString()}
|
||||
>
|
||||
{props.label}
|
||||
</button>
|
||||
{props.href ? (
|
||||
<a
|
||||
className={props.primary ? "primary button" : "button"}
|
||||
href={props.href}
|
||||
disabled={props.disabled && props.disabled.toString()}
|
||||
>
|
||||
{props.label}
|
||||
</a>
|
||||
) : (
|
||||
<button
|
||||
className={props.primary ? "primary button" : "button"}
|
||||
onClick={props.onClick}
|
||||
disabled={props.disabled && props.disabled.toString()}
|
||||
>
|
||||
{props.label}
|
||||
</button>
|
||||
)}
|
||||
<style jsx>{`
|
||||
button {
|
||||
.button {
|
||||
display: block;
|
||||
border-radius: 10px;
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
border: none;
|
||||
@ -17,6 +28,8 @@ const Button = (props) => (
|
||||
color: white;
|
||||
font-style: italic;
|
||||
margin-top: 20px;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
}
|
||||
.primary {
|
||||
border: 2px solid white;
|
||||
@ -25,6 +38,10 @@ const Button = (props) => (
|
||||
button:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
button:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: initial;
|
||||
}
|
||||
`}</style>
|
||||
</>
|
||||
);
|
||||
|
||||
@ -13,18 +13,16 @@ type SourceAddress {
|
||||
type Transaction {
|
||||
signatures: [Signature] @relation
|
||||
dataJSON: String
|
||||
bodyBytes: String
|
||||
txHash: String
|
||||
}
|
||||
|
||||
type Signature {
|
||||
transaction: Transaction! @relation
|
||||
dataJSON: String!
|
||||
bodyBytes: String!
|
||||
signature: String!
|
||||
address: String!
|
||||
}
|
||||
|
||||
type Query {
|
||||
getMultisig(address: String!): Multisig
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
setTransactionBody(address: String!): Multisig
|
||||
}
|
||||
|
||||
@ -90,10 +90,45 @@ const findTransactionByID = async (id) => {
|
||||
query: `
|
||||
query {
|
||||
findTransactionByID(id: "${id}") {
|
||||
_id
|
||||
dataJSON
|
||||
txHash
|
||||
signatures {
|
||||
data {
|
||||
dataJSON
|
||||
address
|
||||
signature
|
||||
bodyBytes
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates txHash of transaction on FaunaDB
|
||||
*
|
||||
* @param {string} id Faunadb resource id
|
||||
* @param {string} txHash tx hash returned from broadcasting a tx
|
||||
* @return Returns async function that makes a request to the faunadb graphql endpoint
|
||||
*/
|
||||
const updateTxHash = async (id, txHash) => {
|
||||
return graphqlReq({
|
||||
method: "POST",
|
||||
data: {
|
||||
query: `
|
||||
mutation {
|
||||
updateTransaction(id: ${id}, data: {txHash: "${txHash}"}) {
|
||||
_id
|
||||
dataJSON
|
||||
txHash
|
||||
signatures {
|
||||
data {
|
||||
address
|
||||
signature
|
||||
bodyBytes
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -106,7 +141,8 @@ const findTransactionByID = async (id) => {
|
||||
/**
|
||||
* Creates signature record in faunadb
|
||||
*
|
||||
* @param {object} transaction The base transaction
|
||||
* @param {object} signature an object with bodyBytes (string) and signature set (Uint8 Array)
|
||||
* @param {string} transactionId id of the transaction to relate the signature with
|
||||
* @return Returns async function that makes a request to the faunadb graphql endpoint
|
||||
*/
|
||||
const createSignature = async (signature, transactionId) => {
|
||||
@ -117,9 +153,14 @@ const createSignature = async (signature, transactionId) => {
|
||||
mutation {
|
||||
createSignature(data: {
|
||||
transaction: {connect: ${transactionId}},
|
||||
dataJSON:
|
||||
bodyBytes: "${signature.bodyBytes}",
|
||||
signature: "${signature.signature}",
|
||||
address: "${signature.address}"
|
||||
}) {
|
||||
_id
|
||||
address
|
||||
signature
|
||||
address
|
||||
}
|
||||
}
|
||||
`,
|
||||
@ -127,4 +168,11 @@ const createSignature = async (signature, transactionId) => {
|
||||
});
|
||||
};
|
||||
|
||||
export { createMultisig, getMultisig, createTransaction, findTransactionByID };
|
||||
export {
|
||||
createMultisig,
|
||||
getMultisig,
|
||||
createTransaction,
|
||||
findTransactionByID,
|
||||
updateTxHash,
|
||||
createSignature,
|
||||
};
|
||||
|
||||
@ -54,7 +54,7 @@ const getMultisigAccount = async (address, client) => {
|
||||
// of this tool its pubkey will be available in the fauna datastore
|
||||
let accountOnChain = await client.getAccount(address);
|
||||
|
||||
if (!accountOnChain.pubkey) {
|
||||
if (!accountOnChain || !accountOnChain.pubkey) {
|
||||
console.log("No pubkey on chain for: ", address);
|
||||
const res = await getMultisig(address);
|
||||
|
||||
@ -64,6 +64,10 @@ const getMultisigAccount = async (address, client) => {
|
||||
);
|
||||
}
|
||||
const pubkey = JSON.parse(res.data.data.getMultisig.pubkeyJSON);
|
||||
|
||||
if (!accountOnChain) {
|
||||
accountOnChain = {};
|
||||
}
|
||||
accountOnChain.pubkey = pubkey;
|
||||
}
|
||||
return accountOnChain;
|
||||
|
||||
4017
package-lock.json
generated
4017
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -6,10 +6,11 @@
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cosmjs/amino": "^0.25.0-alpha.1",
|
||||
"@cosmjs/launchpad": "^0.25.0-alpha.1",
|
||||
"@cosmjs/proto-signing": "^0.25.0-alpha.1",
|
||||
"@cosmjs/stargate": "^0.25.0-alpha.1",
|
||||
"@cosmjs/amino": "^0.25.0-alpha.1",
|
||||
"@keplr-wallet/types": "^0.9.0-alpha.4",
|
||||
"axios": "^0.21.1",
|
||||
"chalk": "^4.1.0",
|
||||
"encoding": "^0.1.13",
|
||||
@ -17,6 +18,7 @@
|
||||
"next": "^10.0.7",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"uint8-to-base64": "^0.2.0",
|
||||
"uuid": "^8.3.0"
|
||||
}
|
||||
}
|
||||
|
||||
25
pages/api/transaction/[transactionID]/index.js
Normal file
25
pages/api/transaction/[transactionID]/index.js
Normal file
@ -0,0 +1,25 @@
|
||||
import { updateTxHash } from "../../../../lib/graphqlHelpers";
|
||||
|
||||
export default async function (req, res) {
|
||||
return new Promise(async (resolve) => {
|
||||
switch (req.method) {
|
||||
case "POST":
|
||||
try {
|
||||
const { transactionID } = req.query;
|
||||
const { txHash } = req.body;
|
||||
console.log("Function `updateTransaction` invoked", txHash);
|
||||
const saveRes = await updateTxHash(transactionID, txHash);
|
||||
console.log("success", saveRes.data);
|
||||
res.status(200).send(saveRes.data.data.updateTransaction);
|
||||
return resolve();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
res.status(400).send(err.message);
|
||||
return resolve();
|
||||
}
|
||||
}
|
||||
// no route matched
|
||||
res.status(405).end();
|
||||
return resolve();
|
||||
});
|
||||
}
|
||||
@ -1,17 +1,16 @@
|
||||
import { createTransaction } from "../../../../lib/graphqlHelpers";
|
||||
import { createSignature } from "../../../../lib/graphqlHelpers";
|
||||
|
||||
export default async function (req, res) {
|
||||
return new Promise(async (resolve) => {
|
||||
switch (req.method) {
|
||||
case "POST":
|
||||
try {
|
||||
const { transactionID } = req.query;
|
||||
const data = req.body;
|
||||
console.log("Function `createTransaction` invoked", data);
|
||||
const saveRes = await createTransaction(data.dataJSON);
|
||||
console.log("Function `createSignature` invoked", data);
|
||||
const saveRes = await createSignature(data, transactionID);
|
||||
console.log("success", saveRes.data);
|
||||
res
|
||||
.status(200)
|
||||
.send({ transactionID: saveRes.data.data.createTransaction._id });
|
||||
res.status(200).send(saveRes.data.data.createSignature);
|
||||
return resolve();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
|
||||
@ -14,9 +14,9 @@ import TransactionList from "../../../components/dataViews/TransactionList";
|
||||
export async function getServerSideProps(context) {
|
||||
let holdings;
|
||||
try {
|
||||
const client = await StargateClient.connect("143.198.6.14:26657");
|
||||
const client = await StargateClient.connect(process.env.NODE_ADDRESS);
|
||||
const multisigAddress = context.params.address;
|
||||
holdings = await client.getBalance(multisigAddress, "uatom");
|
||||
holdings = await client.getBalance(multisigAddress, "stake");
|
||||
const accountOnChain = await getMultisigAccount(multisigAddress, client);
|
||||
|
||||
return {
|
||||
|
||||
@ -1,48 +1,140 @@
|
||||
import { StargateClient } from "@cosmjs/stargate";
|
||||
import axios from "axios";
|
||||
import { StargateClient, makeMultisignedTx } from "@cosmjs/stargate";
|
||||
import { TxRaw } from "@cosmjs/stargate/build/codec/cosmos/tx/v1beta1/tx";
|
||||
import { useState } from "react";
|
||||
import { encode, decode } from "uint8-to-base64";
|
||||
import { createMultisigThresholdPubkey, pubkeyToAddress } from "@cosmjs/amino";
|
||||
import { registry } from "@cosmjs/proto-signing";
|
||||
|
||||
import Button from "../../../../components/inputs/Button";
|
||||
import { findTransactionByID } from "../../../../lib/graphqlHelpers";
|
||||
import { getMultisigAccount } from "../../../../lib/multisigHelpers";
|
||||
import Page from "../../../../components/layout/Page";
|
||||
import StackableContainer from "../../../../components/layout/StackableContainer";
|
||||
import ThresholdInfo from "../../../../components/dataViews/ThresholdInfo";
|
||||
import TransactionInfo from "../../../../components/dataViews/TransactionInfo";
|
||||
import TransactionSigning from "../../../../components/forms/TransactionSigning";
|
||||
import CompletedTransaction from "../../../../components/dataViews/CompletedTransaction";
|
||||
|
||||
export async function getServerSideProps(context) {
|
||||
// get multisig account and transaction info
|
||||
const client = await StargateClient.connect("143.198.6.14:26657");
|
||||
const nodeAddress = process.env.NODE_ADDRESS;
|
||||
const client = await StargateClient.connect(nodeAddress);
|
||||
const multisigAddress = context.params.address;
|
||||
const holdings = await client.getBalance(multisigAddress, "uatom");
|
||||
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);
|
||||
txHash = getRes.data.data.findTransactionByID.txHash;
|
||||
transactionJSON = getRes.data.data.findTransactionByID.dataJSON;
|
||||
signatures = getRes.data.data.findTransactionByID.signatures.data || [];
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
return {
|
||||
props: { transactionJSON, accountOnChain, holdings },
|
||||
props: {
|
||||
transactionJSON,
|
||||
txHash,
|
||||
accountOnChain,
|
||||
holdings,
|
||||
transactionID,
|
||||
signatures,
|
||||
nodeAddress,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const transactionPage = ({ transactionJSON }) => {
|
||||
const transactionPage = ({
|
||||
transactionJSON,
|
||||
transactionID,
|
||||
signatures,
|
||||
accountOnChain,
|
||||
nodeAddress,
|
||||
txHash,
|
||||
}) => {
|
||||
const [currentSignatures, setCurrentSignatures] = useState(signatures);
|
||||
const [isBroadcasting, setIsBroadcasting] = useState(false);
|
||||
const [transactionHash, setTransactionHash] = useState(txHash);
|
||||
const txInfo = (transactionJSON && JSON.parse(transactionJSON)) || null;
|
||||
console.log(txInfo);
|
||||
const addSignature = (signature) => {
|
||||
setCurrentSignatures(currentSignatures.push(signature));
|
||||
};
|
||||
const broadcastTx = async () => {
|
||||
setIsBroadcasting(true);
|
||||
const signatures = new Map();
|
||||
currentSignatures.forEach((signature) => {
|
||||
signatures.set(signature.address, decode(signature.signature));
|
||||
});
|
||||
|
||||
const bodyBytes = decode(currentSignatures[0].bodyBytes);
|
||||
const signedTx = makeMultisignedTx(
|
||||
accountOnChain.pubkey,
|
||||
txInfo.sequence,
|
||||
txInfo.fee,
|
||||
bodyBytes,
|
||||
signatures
|
||||
);
|
||||
const broadcaster = await StargateClient.connect(nodeAddress);
|
||||
const result = await broadcaster.broadcastTx(
|
||||
Uint8Array.from(TxRaw.encode(signedTx).finish())
|
||||
);
|
||||
console.log(result);
|
||||
const res = await axios.post(`/api/transaction/${transactionID}`, {
|
||||
txHash: result.transactionHash,
|
||||
});
|
||||
setTransactionHash(result.transactionHash);
|
||||
};
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<StackableContainer base>
|
||||
<StackableContainer>
|
||||
<h1>In Progress Transaction</h1>
|
||||
<h1>
|
||||
{transactionHash
|
||||
? "Completed Transaction"
|
||||
: "In Progress Transaction"}
|
||||
</h1>
|
||||
</StackableContainer>
|
||||
|
||||
{transactionHash && (
|
||||
<CompletedTransaction transactionHash={transactionHash} />
|
||||
)}
|
||||
<TransactionInfo tx={txInfo} />
|
||||
<TransactionSigning tx={txInfo} />
|
||||
{!transactionHash && (
|
||||
<ThresholdInfo signatures={signatures} account={accountOnChain} />
|
||||
)}
|
||||
{signatures.length >= parseInt(accountOnChain.pubkey.value.threshold) &&
|
||||
!transactionHash && (
|
||||
<Button
|
||||
label={
|
||||
isBroadcasting ? "Broadcasting..." : "Broadcast Transaction"
|
||||
}
|
||||
onClick={broadcastTx}
|
||||
primary
|
||||
disabled={isBroadcasting}
|
||||
/>
|
||||
)}
|
||||
{!transactionHash && (
|
||||
<TransactionSigning
|
||||
tx={txInfo}
|
||||
transactionID={transactionID}
|
||||
signatures={signatures}
|
||||
addSignature={addSignature}
|
||||
/>
|
||||
)}
|
||||
</StackableContainer>
|
||||
|
||||
<style jsx>{``}</style>
|
||||
<style jsx>{`
|
||||
.broadcast {
|
||||
}
|
||||
`}</style>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user