Merge pull request #220 from cosmos/hkeep/keplr-utils
Extract keplr to helpers
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { getKeplrKey, useKeplrReconnect } from "@/lib/keplr";
|
||||
import { cn, toastError } from "@/lib/utils";
|
||||
import { LoadingStates, WalletInfo, WalletType } from "@/types/signing";
|
||||
import { makeCosmoshubPath } from "@cosmjs/amino";
|
||||
@@ -6,7 +7,7 @@ import { LedgerSigner } from "@cosmjs/ledger-amino";
|
||||
import TransportWebUSB from "@ledgerhq/hw-transport-webusb";
|
||||
import { Loader2, Unplug } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import { Dispatch, SetStateAction, useCallback, useLayoutEffect, useState } from "react";
|
||||
import { Dispatch, SetStateAction, useCallback, useState } from "react";
|
||||
import { useChains } from "../../../context/ChainsContext";
|
||||
import { getConnectError } from "../../../lib/errorHelpers";
|
||||
import { Button } from "../../ui/button";
|
||||
@@ -30,16 +31,8 @@ export default function ButtonConnectWallet({
|
||||
try {
|
||||
setLoading((oldLoading) => ({ ...oldLoading, keplr: true }));
|
||||
|
||||
await window.keplr.enable(chain.chainId);
|
||||
window.keplr.defaultOptions = {
|
||||
sign: { preferNoSetFee: true, preferNoSetMemo: true, disableBalanceCheck: true },
|
||||
};
|
||||
|
||||
const { bech32Address: address, pubKey: pubKeyArray } = await window.keplr.getKey(
|
||||
chain.chainId,
|
||||
);
|
||||
const { bech32Address: address, pubKey: pubKeyArray } = await getKeplrKey(chain.chainId);
|
||||
const pubKey = toBase64(pubKeyArray);
|
||||
|
||||
setWalletInfo({ type: "Keplr", address, pubKey });
|
||||
} catch (e) {
|
||||
const connectError = getConnectError(e);
|
||||
@@ -53,19 +46,7 @@ export default function ButtonConnectWallet({
|
||||
}
|
||||
}, [chain.chainId, setWalletInfo]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!walletInfo?.address) {
|
||||
return;
|
||||
}
|
||||
|
||||
const accountChangeKey = "keplr_keystorechange";
|
||||
|
||||
if (walletInfo.type === "Keplr") {
|
||||
window.addEventListener(accountChangeKey, connectKeplr);
|
||||
} else {
|
||||
window.removeEventListener(accountChangeKey, connectKeplr);
|
||||
}
|
||||
}, [connectKeplr, walletInfo]);
|
||||
useKeplrReconnect(!!walletInfo?.address, connectKeplr);
|
||||
|
||||
const connectLedger = async () => {
|
||||
try {
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import { useChains } from "@/context/ChainsContext";
|
||||
import { ellideMiddle } from "@/lib/displayHelpers";
|
||||
import { getConnectError } from "@/lib/errorHelpers";
|
||||
import { getKeplrKey, getKeplrVerifySignature, useKeplrReconnect } from "@/lib/keplr";
|
||||
import { requestJson } from "@/lib/request";
|
||||
import { msgTypeCountsFromJson } from "@/lib/txMsgHelpers";
|
||||
import { cn, toastError } from "@/lib/utils";
|
||||
import { DbNonce, DbTransaction } from "@/types";
|
||||
import { DbNonce, DbTransaction } from "@/types/db";
|
||||
import { WalletInfo } from "@/types/signing";
|
||||
import { toBase64 } from "@cosmjs/encoding";
|
||||
import { StargateClient } from "@cosmjs/stargate";
|
||||
import { Loader2, MoveRightIcon } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useCallback, useLayoutEffect, useState } from "react";
|
||||
import { useCallback, useState } from "react";
|
||||
import { Badge } from "../ui/badge";
|
||||
import { Button } from "../ui/button";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card";
|
||||
@@ -19,8 +20,6 @@ import { Label } from "../ui/label";
|
||||
import { Switch } from "../ui/switch";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
|
||||
|
||||
// Show pending default. Toggle con show already broadcasted too
|
||||
|
||||
interface ListMultisigTxsProps {
|
||||
readonly multisigAddress: string;
|
||||
readonly multisigThreshold: number;
|
||||
@@ -52,36 +51,10 @@ export default function ListMultisigTxs({
|
||||
`/api/chain/${chain.chainId}/nonce/${accountOnChain.address}`,
|
||||
);
|
||||
|
||||
const { signature } = await window.keplr.signAmino(chain.chainId, accountOnChain.address, {
|
||||
chain_id: "",
|
||||
account_number: "0",
|
||||
sequence: "0",
|
||||
fee: { gas: "0", amount: [] },
|
||||
msgs: [
|
||||
{
|
||||
type: "sign/MsgSignData",
|
||||
value: {
|
||||
signer: accountOnChain.address,
|
||||
data: toBase64(
|
||||
new Uint8Array(
|
||||
Buffer.from(
|
||||
JSON.stringify({
|
||||
title: `Keplr Login to ${chain.chainDisplayName}`,
|
||||
description: "Sign this no fee transaction to login with your Keplr wallet",
|
||||
nonce,
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
},
|
||||
],
|
||||
memo: "",
|
||||
});
|
||||
|
||||
const signature = await getKeplrVerifySignature(accountOnChain.address, chain, nonce);
|
||||
return signature;
|
||||
},
|
||||
[chain.chainDisplayName, chain.chainId, chain.nodeAddress],
|
||||
[chain],
|
||||
);
|
||||
|
||||
const fetchTransactions = useCallback(
|
||||
@@ -112,17 +85,8 @@ export default function ListMultisigTxs({
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
await window.keplr.enable(chain.chainId);
|
||||
window.keplr.defaultOptions = {
|
||||
sign: { preferNoSetFee: true, preferNoSetMemo: true, disableBalanceCheck: true },
|
||||
};
|
||||
|
||||
const { bech32Address: address, pubKey: pubKeyArray } = await window.keplr.getKey(
|
||||
chain.chainId,
|
||||
);
|
||||
|
||||
const { bech32Address: address, pubKey: pubKeyArray } = await getKeplrKey(chain.chainId);
|
||||
const pubKey = toBase64(pubKeyArray);
|
||||
|
||||
setWalletInfo({ address, pubKey });
|
||||
|
||||
await fetchTransactions(address);
|
||||
@@ -138,18 +102,7 @@ export default function ListMultisigTxs({
|
||||
}
|
||||
}, [chain.chainId, fetchTransactions]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!walletInfo?.address) {
|
||||
return;
|
||||
}
|
||||
|
||||
const accountChangeKey = "keplr_keystorechange";
|
||||
window.addEventListener(accountChangeKey, connectWallet);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener(accountChangeKey, connectWallet);
|
||||
};
|
||||
}, [connectWallet, walletInfo?.address]);
|
||||
useKeplrReconnect(!!walletInfo?.address, connectWallet);
|
||||
|
||||
return (
|
||||
<Card>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { useChains } from "@/context/ChainsContext";
|
||||
import { getConnectError } from "@/lib/errorHelpers";
|
||||
import { MultisigFromQuery } from "@/lib/graphqlHelpers";
|
||||
import { getKeplrKey, getKeplrVerifySignature, useKeplrReconnect } from "@/lib/keplr";
|
||||
import { requestJson } from "@/lib/request";
|
||||
import { toastError } from "@/lib/utils";
|
||||
import { DbNonce } from "@/types";
|
||||
import { DbNonce } from "@/types/db";
|
||||
import { WalletInfo } from "@/types/signing";
|
||||
import { MultisigThresholdPubkey } from "@cosmjs/amino";
|
||||
import { toBase64 } from "@cosmjs/encoding";
|
||||
@@ -11,7 +12,7 @@ import { StargateClient } from "@cosmjs/stargate";
|
||||
import { Loader2, MoveRightIcon } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useCallback, useLayoutEffect, useState } from "react";
|
||||
import { useCallback, useState } from "react";
|
||||
import { Badge } from "../ui/badge";
|
||||
import { Button } from "../ui/button";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card";
|
||||
@@ -44,36 +45,10 @@ export default function ListUserMultisigs() {
|
||||
`/api/chain/${chain.chainId}/nonce/${accountOnChain.address}`,
|
||||
);
|
||||
|
||||
const { signature } = await window.keplr.signAmino(chain.chainId, accountOnChain.address, {
|
||||
chain_id: "",
|
||||
account_number: "0",
|
||||
sequence: "0",
|
||||
fee: { gas: "0", amount: [] },
|
||||
msgs: [
|
||||
{
|
||||
type: "sign/MsgSignData",
|
||||
value: {
|
||||
signer: accountOnChain.address,
|
||||
data: toBase64(
|
||||
new Uint8Array(
|
||||
Buffer.from(
|
||||
JSON.stringify({
|
||||
title: `Keplr Login to ${chain.chainDisplayName}`,
|
||||
description: "Sign this no fee transaction to login with your Keplr wallet",
|
||||
nonce,
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
},
|
||||
],
|
||||
memo: "",
|
||||
});
|
||||
|
||||
const signature = await getKeplrVerifySignature(accountOnChain.address, chain, nonce);
|
||||
return signature;
|
||||
},
|
||||
[chain.chainDisplayName, chain.chainId, chain.nodeAddress],
|
||||
[chain],
|
||||
);
|
||||
|
||||
const fetchMultisigs = useCallback(
|
||||
@@ -104,17 +79,8 @@ export default function ListUserMultisigs() {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
await window.keplr.enable(chain.chainId);
|
||||
window.keplr.defaultOptions = {
|
||||
sign: { preferNoSetFee: true, preferNoSetMemo: true, disableBalanceCheck: true },
|
||||
};
|
||||
|
||||
const { bech32Address: address, pubKey: pubKeyArray } = await window.keplr.getKey(
|
||||
chain.chainId,
|
||||
);
|
||||
|
||||
const { bech32Address: address, pubKey: pubKeyArray } = await getKeplrKey(chain.chainId);
|
||||
const pubKey = toBase64(pubKeyArray);
|
||||
|
||||
setWalletInfo({ address, pubKey });
|
||||
|
||||
await fetchMultisigs(address);
|
||||
@@ -130,18 +96,7 @@ export default function ListUserMultisigs() {
|
||||
}
|
||||
}, [chain.chainId, fetchMultisigs]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!walletInfo?.address) {
|
||||
return;
|
||||
}
|
||||
|
||||
const accountChangeKey = "keplr_keystorechange";
|
||||
window.addEventListener(accountChangeKey, connectWallet);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener(accountChangeKey, connectWallet);
|
||||
};
|
||||
}, [connectWallet, walletInfo?.address]);
|
||||
useKeplrReconnect(!!walletInfo?.address, connectWallet);
|
||||
|
||||
return (
|
||||
<Card>
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { isChainInfoFilled } from "@/context/ChainsContext/helpers";
|
||||
import { checkAddress } from "@/lib/displayHelpers";
|
||||
import { getKeplrKey } from "@/lib/keplr";
|
||||
import {
|
||||
HostedMultisig,
|
||||
createMultisigFromCompressedSecp256k1Pubkeys,
|
||||
@@ -44,12 +45,7 @@ export default function MultisigView() {
|
||||
"Pubkey on chain is not of type MultisigThreshold",
|
||||
);
|
||||
|
||||
await window.keplr.enable(chain.chainId);
|
||||
window.keplr.defaultOptions = {
|
||||
sign: { preferNoSetFee: true, preferNoSetMemo: true, disableBalanceCheck: true },
|
||||
};
|
||||
|
||||
const { bech32Address: address } = await window.keplr.getKey(chain.chainId);
|
||||
const { bech32Address: address } = await getKeplrKey(chain.chainId);
|
||||
|
||||
await createMultisigFromCompressedSecp256k1Pubkeys(
|
||||
newHostedMultisig.accountOnChain.pubkey.value.pubkeys.map((p) => p.value),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { DbSignature } from "@/types/db";
|
||||
import { MultisigThresholdPubkey } from "@cosmjs/amino";
|
||||
import { useEffect, useState } from "react";
|
||||
import { DbSignature } from "../../types";
|
||||
import StackableContainer from "../layout/StackableContainer";
|
||||
import CopyAndPaste from "./CopyAndPaste";
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { DbTransactionJsonObj } from "@/types/db";
|
||||
import { MsgTypeUrls } from "@/types/txMsg";
|
||||
import { EncodeObject } from "@cosmjs/proto-signing";
|
||||
import { useChains } from "../../../context/ChainsContext";
|
||||
import { printableCoins } from "../../../lib/displayHelpers";
|
||||
import { DbTransactionJsonObj } from "../../../types";
|
||||
import { MsgTypeUrls } from "../../../types/txMsg";
|
||||
import StackableContainer from "../../layout/StackableContainer";
|
||||
import TxMsgBeginRedelegateDetails from "./TxMsgBeginRedelegateDetails";
|
||||
import TxMsgCreateVestingAccountDetails from "./TxMsgCreateVestingAccountDetails";
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { getKeplrKey } from "@/lib/keplr";
|
||||
import { toastError } from "@/lib/utils";
|
||||
import { StargateClient } from "@cosmjs/stargate";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
@@ -91,12 +92,7 @@ export default function CreateMultisigForm() {
|
||||
);
|
||||
|
||||
try {
|
||||
await window.keplr.enable(chain.chainId);
|
||||
window.keplr.defaultOptions = {
|
||||
sign: { preferNoSetFee: true, preferNoSetMemo: true, disableBalanceCheck: true },
|
||||
};
|
||||
|
||||
const { bech32Address: address } = await window.keplr.getKey(chain.chainId);
|
||||
const { bech32Address: address } = await getKeplrKey(chain.chainId);
|
||||
|
||||
const multisigAddress = await createMultisigFromCompressedSecp256k1Pubkeys(
|
||||
pubkeys,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { loadValidators } from "@/context/ChainsContext/helpers";
|
||||
import { toastError, toastSuccess } from "@/lib/utils";
|
||||
import { DbTransactionJsonObj } from "@/types/db";
|
||||
import { MsgTypeUrl, MsgTypeUrls } from "@/types/txMsg";
|
||||
import { EncodeObject } from "@cosmjs/proto-signing";
|
||||
import { Account, calculateFee } from "@cosmjs/stargate";
|
||||
import { assert, sleep } from "@cosmjs/utils";
|
||||
@@ -9,8 +11,6 @@ import { toast } from "sonner";
|
||||
import { useChains } from "../../../context/ChainsContext";
|
||||
import { requestJson } from "../../../lib/request";
|
||||
import { exportMsgToJson, gasOfTx } from "../../../lib/txMsgHelpers";
|
||||
import { DbTransactionJsonObj } from "../../../types";
|
||||
import { MsgTypeUrl, MsgTypeUrls } from "../../../types/txMsg";
|
||||
import Button from "../../inputs/Button";
|
||||
import Input from "../../inputs/Input";
|
||||
import StackableContainer from "../../layout/StackableContainer";
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { getKeplrAminoSigner, getKeplrKey, useKeplrReconnect } from "@/lib/keplr";
|
||||
import { toastError, toastSuccess } from "@/lib/utils";
|
||||
import { DbSignature, DbTransactionJsonObj } from "@/types/db";
|
||||
import { LoadingStates, SigningStatus } from "@/types/signing";
|
||||
import { MultisigThresholdPubkey, makeCosmoshubPath } from "@cosmjs/amino";
|
||||
import { createWasmAminoConverters, wasmTypes } from "@cosmjs/cosmwasm-stargate";
|
||||
@@ -12,13 +14,13 @@ import {
|
||||
defaultRegistryTypes,
|
||||
} from "@cosmjs/stargate";
|
||||
import { assert } from "@cosmjs/utils";
|
||||
import { Key } from "@keplr-wallet/types";
|
||||
import TransportWebUSB from "@ledgerhq/hw-transport-webusb";
|
||||
import { useCallback, useLayoutEffect, useState } from "react";
|
||||
import { useCallback, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { useChains } from "../../context/ChainsContext";
|
||||
import { getConnectError } from "../../lib/errorHelpers";
|
||||
import { requestJson } from "../../lib/request";
|
||||
import { DbSignature, DbTransactionJsonObj, WalletAccount } from "../../types";
|
||||
import HashView from "../dataViews/HashView";
|
||||
import Button from "../inputs/Button";
|
||||
import StackableContainer from "../layout/StackableContainer";
|
||||
@@ -35,7 +37,7 @@ const TransactionSigning = (props: TransactionSigningProps) => {
|
||||
const memberPubkeys = props.pubkey.value.pubkeys.map(({ value }) => value);
|
||||
|
||||
const { chain } = useChains();
|
||||
const [walletAccount, setWalletAccount] = useState<WalletAccount>();
|
||||
const [walletAccount, setWalletAccount] = useState<Partial<Key>>();
|
||||
const [signing, setSigning] = useState<SigningStatus>("not_signed");
|
||||
const [walletType, setWalletType] = useState<"Keplr" | "Ledger">();
|
||||
const [ledgerSigner, setLedgerSigner] = useState<OfflineSigner | null>(null);
|
||||
@@ -45,17 +47,13 @@ const TransactionSigning = (props: TransactionSigningProps) => {
|
||||
try {
|
||||
setLoading((oldLoading) => ({ ...oldLoading, keplr: true }));
|
||||
|
||||
await window.keplr.enable(chain.chainId);
|
||||
window.keplr.defaultOptions = {
|
||||
sign: { preferNoSetFee: true, preferNoSetMemo: true, disableBalanceCheck: true },
|
||||
};
|
||||
const tempWalletAccount = await window.keplr.getKey(chain.chainId);
|
||||
setWalletAccount(tempWalletAccount);
|
||||
const newWalletAccount = await getKeplrKey(chain.chainId);
|
||||
setWalletAccount(newWalletAccount);
|
||||
|
||||
const pubkey = toBase64(tempWalletAccount.pubKey);
|
||||
const pubkey = toBase64(newWalletAccount.pubKey);
|
||||
const isMember = memberPubkeys.includes(pubkey);
|
||||
const hasSigned = isMember
|
||||
? props.signatures.some((sig) => sig.address === tempWalletAccount.bech32Address)
|
||||
? props.signatures.some((sig) => sig.address === newWalletAccount.bech32Address)
|
||||
: false;
|
||||
if (!isMember) {
|
||||
setSigning("not_a_member");
|
||||
@@ -80,15 +78,7 @@ const TransactionSigning = (props: TransactionSigningProps) => {
|
||||
}
|
||||
}, [chain.chainId, memberPubkeys, props.signatures]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const accountChangeKey = "keplr_keystorechange";
|
||||
|
||||
if (walletType === "Keplr") {
|
||||
window.addEventListener(accountChangeKey, connectKeplr);
|
||||
} else {
|
||||
window.removeEventListener(accountChangeKey, connectKeplr);
|
||||
}
|
||||
}, [connectKeplr, walletType]);
|
||||
useKeplrReconnect(!!walletAccount?.address, connectKeplr);
|
||||
|
||||
const connectLedger = async () => {
|
||||
try {
|
||||
@@ -103,7 +93,7 @@ const TransactionSigning = (props: TransactionSigningProps) => {
|
||||
prefix: chain.addressPrefix,
|
||||
});
|
||||
const accounts = await offlineSigner.getAccounts();
|
||||
const tempWalletAccount: WalletAccount = {
|
||||
const tempWalletAccount = {
|
||||
bech32Address: accounts[0].address,
|
||||
pubKey: accounts[0].pubkey,
|
||||
algo: accounts[0].algo,
|
||||
@@ -146,9 +136,7 @@ const TransactionSigning = (props: TransactionSigningProps) => {
|
||||
setLoading((newLoading) => ({ ...newLoading, signing: true }));
|
||||
|
||||
const offlineSigner =
|
||||
walletType === "Keplr"
|
||||
? window.keplr.getOfflineSignerOnlyAmino(chain.chainId)
|
||||
: ledgerSigner;
|
||||
walletType === "Keplr" ? await getKeplrAminoSigner(chain.chainId) : ledgerSigner;
|
||||
|
||||
if (!offlineSigner) {
|
||||
throw new Error("Offline signer not found");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DbMultisig, DbNonce, DbSignature, DbTransaction, DbTransactionJsonObj } from "../types";
|
||||
import { DbMultisig, DbNonce, DbSignature, DbTransaction, DbTransactionJsonObj } from "../types/db";
|
||||
import { requestGraphQlJson } from "./request";
|
||||
|
||||
/**
|
||||
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
import { ChainInfo } from "@/context/ChainsContext/types";
|
||||
import { StdSignature, decodeSignature, pubkeyToAddress } from "@cosmjs/amino";
|
||||
import { toBase64 } from "@cosmjs/encoding";
|
||||
import { verifyADR36Amino } from "@keplr-wallet/cosmos";
|
||||
import { StdSignDoc } from "@keplr-wallet/types";
|
||||
import { useLayoutEffect } from "react";
|
||||
|
||||
const getKeplr = async (chainId: string) => {
|
||||
const keplr = window.keplr;
|
||||
if (!keplr) {
|
||||
throw new Error("Keplr not found");
|
||||
}
|
||||
|
||||
await keplr.enable(chainId);
|
||||
|
||||
keplr.defaultOptions = {
|
||||
sign: { preferNoSetFee: true, preferNoSetMemo: true, disableBalanceCheck: true },
|
||||
};
|
||||
|
||||
return keplr;
|
||||
};
|
||||
|
||||
export const getKeplrKey = async (chainId: string) => {
|
||||
const keplr = await getKeplr(chainId);
|
||||
const keplrKey = await keplr.getKey(chainId);
|
||||
|
||||
return keplrKey;
|
||||
};
|
||||
|
||||
export const getKeplrAminoSigner = async (chainId: string) => {
|
||||
const keplr = await getKeplr(chainId);
|
||||
const aminoSigner = keplr.getOfflineSignerOnlyAmino(chainId);
|
||||
|
||||
return aminoSigner;
|
||||
};
|
||||
|
||||
export const getKeplrVerifySignature = async (signer: string, chain: ChainInfo, nonce: number) => {
|
||||
const keplr = await getKeplr(chain.chainId);
|
||||
|
||||
const { signature } = await keplr.signAmino(
|
||||
chain.chainId,
|
||||
signer,
|
||||
getKeplrVerifyMsg(signer, chain.chainDisplayName, nonce),
|
||||
);
|
||||
|
||||
return signature;
|
||||
};
|
||||
|
||||
const getKeplrVerifyMsg = (
|
||||
signer: string,
|
||||
chainDisplayName: string,
|
||||
nonce: number,
|
||||
): StdSignDoc => ({
|
||||
chain_id: "",
|
||||
account_number: "0",
|
||||
sequence: "0",
|
||||
fee: { gas: "0", amount: [] },
|
||||
memo: "",
|
||||
msgs: [
|
||||
{
|
||||
type: "sign/MsgSignData",
|
||||
value: {
|
||||
signer,
|
||||
data: toBase64(new Uint8Array(Buffer.from(getKeplrVerifyData(chainDisplayName, nonce)))),
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const getKeplrVerifyData = (chainDisplayName: string, nonce: number) =>
|
||||
JSON.stringify({
|
||||
title: `Keplr Login to ${chainDisplayName}`,
|
||||
description: "Sign this no fee transaction to login with your Keplr wallet",
|
||||
nonce,
|
||||
});
|
||||
|
||||
export const verifyKeplrSignature = (signature: StdSignature, chain: ChainInfo, nonce: number) => {
|
||||
const signer = pubkeyToAddress(signature.pub_key, chain.addressPrefix);
|
||||
const data = getKeplrVerifyData(chain.chainDisplayName, nonce);
|
||||
const { pubkey: decodedPubKey, signature: decodedSignature } = decodeSignature(signature);
|
||||
|
||||
const verified = verifyADR36Amino(
|
||||
chain.addressPrefix,
|
||||
signer,
|
||||
data,
|
||||
decodedPubKey,
|
||||
decodedSignature,
|
||||
);
|
||||
|
||||
return verified;
|
||||
};
|
||||
|
||||
const accountChangeKey = "keplr_keystorechange";
|
||||
export const useKeplrReconnect = (condition: boolean, connectWallet: () => Promise<void>) => {
|
||||
useLayoutEffect(() => {
|
||||
if (!condition) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.addEventListener(accountChangeKey, connectWallet);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener(accountChangeKey, connectWallet);
|
||||
};
|
||||
}, [condition, connectWallet]);
|
||||
};
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { DbTransactionJsonObj } from "@/types/db";
|
||||
import { MsgCodecs, MsgTypeUrl, MsgTypeUrls } from "@/types/txMsg";
|
||||
import { EncodeObject } from "@cosmjs/proto-signing";
|
||||
import { DbTransactionJsonObj } from "../types";
|
||||
import { MsgCodecs, MsgTypeUrl, MsgTypeUrls } from "../types/txMsg";
|
||||
|
||||
const gasOfMsg = (msgType: MsgTypeUrl): number => {
|
||||
switch (msgType) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { isChainInfoFilled } from "@/context/ChainsContext/helpers";
|
||||
import { toastError, toastSuccess } from "@/lib/utils";
|
||||
import { DbSignature } from "@/types/db";
|
||||
import { MultisigThresholdPubkey } from "@cosmjs/amino";
|
||||
import { fromBase64 } from "@cosmjs/encoding";
|
||||
import { Account, StargateClient, makeMultisignedTxBytes } from "@cosmjs/stargate";
|
||||
@@ -17,10 +18,9 @@ import Page from "../../../../components/layout/Page";
|
||||
import StackableContainer from "../../../../components/layout/StackableContainer";
|
||||
import { useChains } from "../../../../context/ChainsContext";
|
||||
import { findTransactionByID } from "../../../../lib/graphqlHelpers";
|
||||
import { isAccount, getHostedMultisig } from "../../../../lib/multisigHelpers";
|
||||
import { getHostedMultisig, isAccount } from "../../../../lib/multisigHelpers";
|
||||
import { requestJson } from "../../../../lib/request";
|
||||
import { dbTxFromJson } from "../../../../lib/txMsgHelpers";
|
||||
import { DbSignature } from "../../../../types";
|
||||
|
||||
interface Props {
|
||||
props: {
|
||||
|
||||
@@ -5,10 +5,10 @@ import {
|
||||
getNonce,
|
||||
updateNonce,
|
||||
} from "@/lib/graphqlHelpers";
|
||||
import { verifyKeplrSignature } from "@/lib/keplr";
|
||||
import { decodeSignature, pubkeyToAddress } from "@cosmjs/amino";
|
||||
import { toBase64 } from "@cosmjs/encoding";
|
||||
import { StargateClient } from "@cosmjs/stargate";
|
||||
import { verifyADR36Amino } from "@keplr-wallet/cosmos";
|
||||
import { StdSignature } from "@keplr-wallet/types";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
@@ -38,27 +38,17 @@ export default async function multisigsApi(req: NextApiRequest, res: NextApiResp
|
||||
throw new Error(`Nonce not found on ${chainId} for ${address}`);
|
||||
}
|
||||
|
||||
const { pubkey: decodedPubKey, signature: decodedSignature } = decodeSignature(signature);
|
||||
const data = JSON.stringify({
|
||||
title: `Keplr Login to ${chain.chainDisplayName}`,
|
||||
description: "Sign this no fee transaction to login with your Keplr wallet",
|
||||
nonce: dbNonce.nonce,
|
||||
});
|
||||
|
||||
await updateNonce(chainId, address, dbNonce.nonce + 1);
|
||||
|
||||
const verified = verifyADR36Amino(
|
||||
chain.addressPrefix,
|
||||
address,
|
||||
data,
|
||||
decodedPubKey,
|
||||
decodedSignature,
|
||||
);
|
||||
const verified = verifyKeplrSignature(signature, chain, dbNonce.nonce);
|
||||
|
||||
if (verified) {
|
||||
console.log("Function `getMultisigs` invoked", chainId, address);
|
||||
|
||||
const created = await getCreatedMultisigs(chainId, address);
|
||||
|
||||
const { pubkey: decodedPubKey } = decodeSignature(signature);
|
||||
const belonged = await getBelongedMultisigs(chainId, toBase64(decodedPubKey));
|
||||
|
||||
console.log("success", { created, belonged });
|
||||
res.status(200).send({ created, belonged });
|
||||
return;
|
||||
|
||||
@@ -6,10 +6,10 @@ import {
|
||||
getTransactions,
|
||||
updateNonce,
|
||||
} from "@/lib/graphqlHelpers";
|
||||
import { verifyKeplrSignature } from "@/lib/keplr";
|
||||
import { decodeSignature, pubkeyToAddress } from "@cosmjs/amino";
|
||||
import { toBase64 } from "@cosmjs/encoding";
|
||||
import { StargateClient } from "@cosmjs/stargate";
|
||||
import { verifyADR36Amino } from "@keplr-wallet/cosmos";
|
||||
import { StdSignature } from "@keplr-wallet/types";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
@@ -28,7 +28,7 @@ export default async function transactionsApi(req: NextApiRequest, res: NextApiR
|
||||
throw new Error("Multisig not found");
|
||||
}
|
||||
|
||||
const { pubkey: decodedPubKey, signature: decodedSignature } = decodeSignature(signature);
|
||||
const { pubkey: decodedPubKey } = decodeSignature(signature);
|
||||
|
||||
if (!multisig.pubkeyJSON.includes(toBase64(decodedPubKey))) {
|
||||
throw new Error("You don't belong to the multisig");
|
||||
@@ -49,21 +49,8 @@ export default async function transactionsApi(req: NextApiRequest, res: NextApiR
|
||||
throw new Error(`Nonce not found on ${chain.chainId} for ${address}`);
|
||||
}
|
||||
|
||||
const data = JSON.stringify({
|
||||
title: `Keplr Login to ${chain.chainDisplayName}`,
|
||||
description: "Sign this no fee transaction to login with your Keplr wallet",
|
||||
nonce: dbNonce.nonce,
|
||||
});
|
||||
|
||||
await updateNonce(chain.chainId, address, dbNonce.nonce + 1);
|
||||
|
||||
const verified = verifyADR36Amino(
|
||||
chain.addressPrefix,
|
||||
address,
|
||||
data,
|
||||
decodedPubKey,
|
||||
decodedSignature,
|
||||
);
|
||||
const verified = verifyKeplrSignature(signature, chain, dbNonce.nonce);
|
||||
|
||||
if (verified) {
|
||||
const multisigId = await getMultisigId(multisigAddress, chain.chainId);
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
import { StdFee } from "@cosmjs/amino";
|
||||
import { EncodeObject } from "@cosmjs/proto-signing";
|
||||
import { Keplr } from "@keplr-wallet/types";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
keplr: Keplr;
|
||||
}
|
||||
}
|
||||
|
||||
export interface DbSignature {
|
||||
bodyBytes: string;
|
||||
@@ -42,12 +35,3 @@ export type DbNonce = {
|
||||
readonly address: string;
|
||||
readonly nonce: number;
|
||||
};
|
||||
|
||||
export interface WalletAccount {
|
||||
address?: Uint8Array;
|
||||
pubKey: Uint8Array;
|
||||
algo: string;
|
||||
bech32Address: string;
|
||||
isNanoLedger?: boolean;
|
||||
name?: string;
|
||||
}
|
||||
Reference in New Issue
Block a user