Skip to content

Commit

Permalink
fix(multisig): refacto, force amino signing, disable keplr balance ch…
Browse files Browse the repository at this point in the history
…eck and prevent modification by signer (#1203)

* fix(multisig): refacto and force amino signing

Signed-off-by: Norman Meier <[email protected]>

* chore: change cosmos endpoints

Signed-off-by: Norman Meier <[email protected]>

* fix: multisig signer params

Signed-off-by: Norman Meier <[email protected]>

* fix: error out on multisig tx change

Signed-off-by: Norman Meier <[email protected]>

* chore: remove debug

Signed-off-by: Norman Meier <[email protected]>

---------

Signed-off-by: Norman Meier <[email protected]>
  • Loading branch information
n0izn0iz authored Apr 15, 2024
1 parent e266d82 commit 6b2c92b
Show file tree
Hide file tree
Showing 13 changed files with 426 additions and 117 deletions.
4 changes: 2 additions & 2 deletions networks.json
Original file line number Diff line number Diff line change
Expand Up @@ -2584,8 +2584,8 @@
"testnet": false,
"backendEndpoint": "https://dapp-backend.mainnet.teritori.com",
"addressPrefix": "cosmos",
"restEndpoint": "https://api-cosmoshub-ia.cosmosia.notional.ventures",
"rpcEndpoint": "https://rpc-cosmoshub-ia.cosmosia.notional.ventures",
"restEndpoint": "https://rest-cosmoshub.ecostake.com",
"rpcEndpoint": "https://rpc-cosmoshub.ecostake.com",
"stakeCurrency": "uatom",
"gasPriceStep": {
"low": 0.01,
Expand Down
42 changes: 8 additions & 34 deletions packages/components/multisig/LoginButton.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import { Keplr } from "@keplr-wallet/types";
import { Buffer } from "buffer";
import { FC } from "react";

import {
GetTokenRequest,
TokenRequestInfo,
} from "../../api/multisig/v1/multisig";
import { useFeedbacks } from "../../context/FeedbacksProvider";
import { useMultisigAuthToken } from "../../hooks/multisig/useMultisigAuthToken";
import { useMultisigClient } from "../../hooks/multisig/useMultisigClient";
Expand All @@ -15,6 +10,8 @@ import { useAppDispatch } from "../../store/store";
import { keplrSignArbitrary } from "../../utils/keplr";
import { PrimaryButton } from "../buttons/PrimaryButton";

import { multisigLogin } from "@/utils/multisig";

export const LoginButton: FC<{ userId: string | undefined }> = ({ userId }) => {
const [network, userAddress] = parseUserId(userId);
const storeAuthToken = useMultisigAuthToken(userId);
Expand Down Expand Up @@ -56,35 +53,12 @@ export const LoginButton: FC<{ userId: string | undefined }> = ({ userId }) => {
throw new Error("Unsupported key algorithm");
}

const challengeResponse = await client.GetChallenge({});

if (!challengeResponse.challenge) {
throw new Error("No challenge returned from server");
}

const info = TokenRequestInfo.toJSON({
kind: "Login to Teritori Multisig Service",
challenge: challengeResponse.challenge,
userBech32Prefix: network.addressPrefix,
userPubkeyJson: JSON.stringify({
type: "tendermint/PubKeySecp256k1",
value: Buffer.from(pubKey).toString("base64"),
}),
});
const infoJSON = JSON.stringify(info);

const stdsig = await keplrSignArbitrary(userId, infoJSON);

const req: GetTokenRequest = {
infoJson: infoJSON,
userSignature: stdsig.signature,
};

const { authToken } = await client.GetToken(req);

if (!authToken) {
throw new Error("No auth token returned from server");
}
const authToken = await multisigLogin(
network,
client,
pubKey,
(infoJSON) => keplrSignArbitrary(userId, infoJSON),
);

dispatch(setMultisigToken({ userAddress, token: authToken }));
})}
Expand Down
2 changes: 1 addition & 1 deletion packages/components/tx/getTxInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { SocialMessageContent } from "../socialFeed/SocialCard/SocialMessageCont
import { SpacerColumn } from "../spacer";
import { Username } from "../user/Username";

import { cosmosTypesRegistry } from "@/networks/signer";
import { cosmosTypesRegistry } from "@/networks/cosmos-types";

// once we gather enough different messages here, we should try to establish meaningful abstractions and split this func

Expand Down
50 changes: 32 additions & 18 deletions packages/hooks/multisig/useApproveTransaction.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { toBase64 } from "@cosmjs/encoding";
import { StdSignDoc } from "@cosmjs/amino";
import { Window as KeplrWindow } from "@keplr-wallet/types";
import { useQueryClient } from "@tanstack/react-query";
import { isEqual } from "lodash";
import { useCallback } from "react";

import { useMultisigAuthToken } from "./useMultisigAuthToken";
Expand All @@ -14,7 +15,8 @@ import useSelectedWallet from "../useSelectedWallet";
import { Signature } from "@/api/multisig/v1/multisig";
import { useFeedbacks } from "@/context/FeedbacksProvider";
import { getUserId } from "@/networks";
import { getKeplrOnlyAminoStargateClient } from "@/networks/signer";
import { cosmosAminoTypes, cosmosTypesRegistry } from "@/networks/cosmos-types";
import { getKeplrOnlyAminoSigner } from "@/networks/signer";

export const useApproveTransaction = () => {
const { setToastError } = useFeedbacks();
Expand Down Expand Up @@ -61,30 +63,42 @@ export const useApproveTransaction = () => {
return;
}

const client = await getKeplrOnlyAminoStargateClient(selectedNetworkId);

const signer = await getKeplrOnlyAminoSigner(selectedNetworkId, {
disableBalanceCheck: true,
preferNoSetFee: true,
preferNoSetMemo: true,
});
const signerAddress = walletAccount.address;
const signerData = {
accountNumber: tx.accountNumber,
sequence: tx.sequence,
chainId: tx.chainId,

const sd: StdSignDoc = {
chain_id: tx.chainId,
account_number: tx.accountNumber.toString(),
sequence: tx.sequence.toString(),
fee: tx.fee,
msgs: tx.msgs.map((m) => {
return cosmosAminoTypes.toAmino(m);
}),
memo: "",
};

const { bodyBytes, signatures } = await client.sign(
signerAddress,
tx.msgs,
tx.fee,
tx.memo,
signerData,
);
const {
signed,
signature: { signature },
} = await signer.signAmino(signerAddress, sd);

const bases64EncodedSignature = toBase64(signatures[0]);
if (!isEqual(sd, signed)) {
throw new Error(
"Tx modified by signer, you can't change the fee or memo in a multisig transaction!",
);
}

await multisigClient.SignTransaction({
authToken,
signature: bases64EncodedSignature,
signature,
transactionId,
bodyBytes,
bodyBytes: cosmosTypesRegistry.encodeTxBody({
messages: tx.msgs,
}),
});

await queryClient.invalidateQueries(
Expand Down
2 changes: 1 addition & 1 deletion packages/hooks/multisig/useMultisigTransactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useMultisigClient } from "./useMultisigClient";

import { ExecutionState, Transaction } from "@/api/multisig/v1/multisig";
import { getCosmosNetwork, parseUserId } from "@/networks";
import { cosmosTypesRegistry } from "@/networks/signer";
import { cosmosTypesRegistry } from "@/networks/cosmos-types";

const batchSize = 16;

Expand Down
6 changes: 2 additions & 4 deletions packages/hooks/useRunOrProposeTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,8 @@ import {
parseUserId,
UserKind,
} from "@/networks";
import {
cosmosTypesRegistry,
getKeplrSigningStargateClient,
} from "@/networks/signer";
import { cosmosTypesRegistry } from "@/networks/cosmos-types";
import { getKeplrSigningStargateClient } from "@/networks/signer";
import { AppNavigationProp, useAppNavigation } from "@/utils/navigation";

export const useRunOrProposeTransaction = (
Expand Down
4 changes: 2 additions & 2 deletions packages/networks/cosmos-hub/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ export const cosmosNetwork: NetworkInfo = {
testnet: false,
backendEndpoint: "https://dapp-backend.mainnet.teritori.com",
addressPrefix: "cosmos",
restEndpoint: "https://api-cosmoshub-ia.cosmosia.notional.ventures",
rpcEndpoint: "https://rpc-cosmoshub-ia.cosmosia.notional.ventures",
restEndpoint: "https://rest-cosmoshub.ecostake.com",
rpcEndpoint: "https://rpc-cosmoshub.ecostake.com",
stakeCurrency: "uatom",
gasPriceStep: {
low: 0.01,
Expand Down
27 changes: 27 additions & 0 deletions packages/networks/cosmos-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {
createWasmAminoConverters,
wasmTypes,
} from "@cosmjs/cosmwasm-stargate/build/modules";
import { Registry } from "@cosmjs/proto-signing";
import {
AminoTypes,
createDefaultAminoConverters,
defaultRegistryTypes,
} from "@cosmjs/stargate";

import {
teritoriAminoConverters,
teritoriProtoRegistry,
} from "@/api/teritori-chain";

export const cosmosTypesRegistry = new Registry([
...defaultRegistryTypes,
...wasmTypes,
...teritoriProtoRegistry,
]);

export const cosmosAminoTypes = new AminoTypes({
...createDefaultAminoConverters(),
...createWasmAminoConverters(),
...teritoriAminoConverters,
});
60 changes: 11 additions & 49 deletions packages/networks/signer.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,10 @@
import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate";
import {
createWasmAminoConverters,
wasmTypes,
} from "@cosmjs/cosmwasm-stargate/build/modules";
import { Registry } from "@cosmjs/proto-signing";
import {
AminoTypes,
createDefaultAminoConverters,
defaultRegistryTypes,
SigningStargateClient,
} from "@cosmjs/stargate";
import { SigningStargateClient } from "@cosmjs/stargate";
import { KeplrSignOptions } from "@keplr-wallet/types";
import { Platform } from "react-native";

import {
teritoriAminoConverters,
teritoriProtoRegistry,
} from "@/api/teritori-chain";
import { cosmosTypesRegistry, cosmosAminoTypes } from "./cosmos-types";

import {
cosmosNetworkGasPrice,
keplrChainInfoFromNetworkInfo,
Expand All @@ -24,16 +13,6 @@ import {
import { convertKeplrSigner, getKeplr } from "@/utils/keplr";
import { getNativeWallet } from "@/utils/wallet/getNativeWallet";

export const cosmosTypesRegistry = new Registry([
...defaultRegistryTypes,
...wasmTypes,
...teritoriProtoRegistry,
]);
const cosmosAminoTypes = new AminoTypes({
...createDefaultAminoConverters(),
...createWasmAminoConverters(),
...teritoriAminoConverters,
});
export const getKeplrSigner = async (networkId: string) => {
const network = mustGetCosmosNetwork(networkId);

Expand All @@ -47,7 +26,11 @@ export const getKeplrSigner = async (networkId: string) => {

return convertKeplrSigner(keplrSigner);
};
const getKeplrOnlyAminoSigner = async (networkId: string) => {

export const getKeplrOnlyAminoSigner = async (
networkId: string,
signOptions?: KeplrSignOptions,
) => {
const network = mustGetCosmosNetwork(networkId);

const keplr = getKeplr();
Expand All @@ -56,8 +39,9 @@ const getKeplrOnlyAminoSigner = async (networkId: string) => {

await keplr.enable(network.chainId);

return keplr.getOfflineSignerOnlyAmino(network.chainId);
return keplr.getOfflineSignerOnlyAmino(network.chainId, signOptions);
};

export const getKeplrSigningStargateClient = async (
networkId: string,
gasPriceKind: "low" | "average" | "high" = "average",
Expand All @@ -81,29 +65,7 @@ export const getKeplrSigningStargateClient = async (
},
);
};
export const getKeplrOnlyAminoStargateClient = async (
networkId: string,
gasPriceKind: "low" | "average" | "high" = "average",
) => {
const network = mustGetCosmosNetwork(networkId);

const gasPrice = cosmosNetworkGasPrice(network, gasPriceKind);
if (!gasPrice) {
throw new Error("gas price not found");
}

const signer = await getKeplrOnlyAminoSigner(networkId);

return await SigningStargateClient.connectWithSigner(
network.rpcEndpoint,
signer,
{
gasPrice,
registry: cosmosTypesRegistry,
aminoTypes: cosmosAminoTypes,
},
);
};
export const getKeplrSigningCosmWasmClient = async (
networkId: string,
gasPriceKind: "low" | "average" | "high" = "average",
Expand Down
4 changes: 2 additions & 2 deletions packages/networks/teritori-testnet/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { teritoriTestnetCurrencies } from "./currencies";
import { CosmWasmPremiumFeed, NetworkFeature } from "../features";
import { NetworkInfo, NetworkKind } from "../types";
import { CosmosNetworkInfo, NetworkKind } from "../types";

const nameServiceContractAddress =
"tori14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s3hewys";
Expand All @@ -16,7 +16,7 @@ const riotContractAddressGen0 =
"tori1hzz0s0ucrhdp6tue2lxk3c03nj6f60qy463we7lgx0wudd72ctmstg4wkc";
const riotContractAddressGen1 = "";

export const teritoriTestnetNetwork: NetworkInfo = {
export const teritoriTestnetNetwork: CosmosNetworkInfo = {
id: "teritori-testnet",
kind: NetworkKind.Cosmos,
chainId: "teritori-test-6",
Expand Down
29 changes: 25 additions & 4 deletions packages/scripts/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,38 @@ import util from "util";
import { z } from "zod";

import {
GrpcWebImpl,
GrpcWebImpl as MarketplaceGrpcWebImpl,
MarketplaceServiceClientImpl,
} from "../api/marketplace/v1/marketplace";
import { getNetwork } from "../networks";
} from "@/api/marketplace/v1/marketplace";
import {
GrpcWebImpl as MultisigGrpcWebImpl,
MultisigServiceClientImpl,
} from "@/api/multisig/v1/multisig";
import { getNetwork } from "@/networks";

export const mustGetNodeMultisigClient = (networkId: string | undefined) => {
const network = getNetwork(networkId);
let endpoint = process.env.MULTISIG_BACKEND_URL;
if (!endpoint) {
if (network?.testnet) {
endpoint = "https://multisig.testnet.teritori.com";
} else {
endpoint = "https://multisig.mainnet.teritori.com";
}
}
const rpc = new MultisigGrpcWebImpl(endpoint, {
transport: NodeHttpTransport(),
debug: false,
});
return new MultisigServiceClientImpl(rpc);
};

export const mustGetNodeMarketplaceClient = (networkId: string) => {
const network = getNetwork(networkId);
if (!network) {
throw new Error("network not found");
}
const rpc = new GrpcWebImpl(network.backendEndpoint, {
const rpc = new MarketplaceGrpcWebImpl(network.backendEndpoint, {
transport: NodeHttpTransport(),
debug: false,
// metadata: new grpc.Metadata({ SomeHeader: "bar" }),
Expand Down
Loading

0 comments on commit 6b2c92b

Please sign in to comment.