Adding Ledger Support to Sign TX
This commit is contained in:
@@ -40,6 +40,7 @@ const TransactionForm = (props) => {
|
||||
value: msgSend,
|
||||
};
|
||||
const fee = calculateFee(Number(txGas), gasPrice);
|
||||
console.log(props.accountOnChain.accountNumber);
|
||||
return {
|
||||
accountNumber: props.accountOnChain.accountNumber,
|
||||
sequence: props.accountOnChain.sequence,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import React, { useState } from "react";
|
||||
import axios from "axios";
|
||||
import { toBase64 } from "@cosmjs/encoding";
|
||||
import { SigningStargateClient } from "@cosmjs/stargate";
|
||||
@@ -8,17 +8,19 @@ import Button from "../inputs/Button";
|
||||
import HashView from "../dataViews/HashView";
|
||||
import StackableContainer from "../layout/StackableContainer";
|
||||
|
||||
import TransportWebUSB from "@ledgerhq/hw-transport-webusb";
|
||||
import { LedgerSigner } from "@cosmjs/ledger-amino";
|
||||
import { makeCosmoshubPath } from "@cosmjs/amino";
|
||||
|
||||
const TransactionSigning = (props) => {
|
||||
const { state } = useAppContext();
|
||||
const [walletAccount, setWalletAccount] = useState(null);
|
||||
const [sigError, setSigError] = useState(null);
|
||||
const [hasSigned, setHasSigned] = useState(false);
|
||||
const [walletType, setWalletType] = useState("");
|
||||
const [ledgerSigner, setLedgerSigner] = useState({});
|
||||
|
||||
useEffect(() => {
|
||||
connectWallet();
|
||||
}, []);
|
||||
|
||||
const connectWallet = async () => {
|
||||
const connectKeplr = async () => {
|
||||
try {
|
||||
await window.keplr.enable(state.chain.chainId);
|
||||
const tempWalletAccount = await window.keplr.getKey(state.chain.chainId);
|
||||
@@ -27,58 +29,73 @@ const TransactionSigning = (props) => {
|
||||
);
|
||||
setWalletAccount(tempWalletAccount);
|
||||
setHasSigned(tempHasSigned);
|
||||
setWalletType("keplr");
|
||||
} catch (e) {
|
||||
console.log("enable err: ", e);
|
||||
}
|
||||
};
|
||||
|
||||
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,
|
||||
);
|
||||
const connectLedger = async () => {
|
||||
// Prepare ledger
|
||||
const ledgerTransport = await TransportWebUSB.create(120_000, 120_000);
|
||||
|
||||
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);
|
||||
// Setup signer
|
||||
const offlineSigner = new LedgerSigner(ledgerTransport, {
|
||||
hdPaths: [makeCosmoshubPath(0)],
|
||||
prefix: state.chain.addressPrefix,
|
||||
});
|
||||
|
||||
const accounts = await offlineSigner.getAccounts();
|
||||
const tempWalletAccount = accounts[0].address;
|
||||
|
||||
const tempHasSigned = props.signatures.some(
|
||||
(sig) => sig.address === tempWalletAccount.bech32Address,
|
||||
);
|
||||
setWalletAccount(tempWalletAccount);
|
||||
setHasSigned(tempHasSigned);
|
||||
setLedgerSigner(offlineSigner);
|
||||
setWalletType("ledger");
|
||||
};
|
||||
|
||||
const signTransaction = async () => {
|
||||
const offlineSigner =
|
||||
walletType === "keplr" ? window.getOfflineSignerOnlyAmino(state.chain.chainId) : ledgerSigner;
|
||||
|
||||
const address = walletType === "keplr" ? walletAccount.bech32Address : ledgerSigner.accounts[0]?.address;
|
||||
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(
|
||||
address,
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -99,7 +116,10 @@ const TransactionSigning = (props) => {
|
||||
{walletAccount ? (
|
||||
<Button label="Sign transaction" onClick={signTransaction} />
|
||||
) : (
|
||||
<Button label="Connect Wallet" onClick={connectWallet} />
|
||||
<>
|
||||
<Button label="Connect Keplr" onClick={connectKeplr} />
|
||||
<Button label="Connect Ledger" onClick={connectLedger} />
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -68,6 +68,7 @@ const getMultisigAccount = async (address, client) => {
|
||||
}
|
||||
accountOnChain.pubkey = pubkey;
|
||||
}
|
||||
|
||||
return accountOnChain;
|
||||
};
|
||||
|
||||
|
||||
Generated
+5498
-18
File diff suppressed because it is too large
Load Diff
@@ -11,10 +11,12 @@
|
||||
"@cosmjs/amino": "^0.27.0",
|
||||
"@cosmjs/crypto": "^0.27.0",
|
||||
"@cosmjs/encoding": "^0.27.0",
|
||||
"@cosmjs/ledger-amino": "^0.28.0",
|
||||
"@cosmjs/math": "^0.27.0",
|
||||
"@cosmjs/proto-signing": "^0.27.0",
|
||||
"@cosmjs/stargate": "^0.27.0",
|
||||
"@keplr-wallet/types": "^0.9.0-alpha.4",
|
||||
"@ledgerhq/hw-transport-webusb": "^6.24.1",
|
||||
"axios": "^0.21.1",
|
||||
"copy-to-clipboard": "^3.3.1",
|
||||
"cosmjs-types": "^0.4.1",
|
||||
|
||||
Reference in New Issue
Block a user