Adding Ledger Support to Sign TX

This commit is contained in:
Milan Steiner
2022-03-24 11:29:24 +01:00
parent 19c01d31f8
commit 9394d10e02
5 changed files with 5575 additions and 71 deletions
+1
View File
@@ -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,
+73 -53
View File
@@ -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} />
</>
)}
</>
)}
+1
View File
@@ -68,6 +68,7 @@ const getMultisigAccount = async (address, client) => {
}
accountOnChain.pubkey = pubkey;
}
return accountOnChain;
};
+5498 -18
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -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",