From 72191621858e7eb9554fc03ffd7429bed4480d37 Mon Sep 17 00:00:00 2001 From: shreerang6921 <68148922+shreerang6921@users.noreply.github.com> Date: Tue, 12 Mar 2024 16:47:05 +0530 Subject: [PATCH] Sign message using signDirect method with cosmos accounts (#51) * Sign message using signDirect method with cosmos accounts * Add explaination for signDirect method * Use existing utility function to convert hex string to uint8array * Handle review changes --- App.tsx | 1 - package.json | 6 +- utils/sign-message.ts | 36 ++++++++-- utils/utils.ts | 14 ++++ utils/wallet-connect/WalletConnectRequests.ts | 36 +++++++--- yarn.lock | 71 ++++++++++++------- 6 files changed, 119 insertions(+), 45 deletions(-) diff --git a/App.tsx b/App.tsx index 5697b09..ac2e27e 100644 --- a/App.tsx +++ b/App.tsx @@ -69,7 +69,6 @@ const App = (): React.JSX.Element => { }); break; - // TODO: Debug signDirect case 'cosmos_signDirect': navigation.navigate('SignRequest', { network: 'cosmos', diff --git a/package.json b/package.json index 05620d5..09bc1f6 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,9 @@ "postinstall": "patch-package" }, "dependencies": { - "@cosmjs/amino": "^0.32.2", - "@cosmjs/crypto": "^0.32.2", + "@cosmjs/amino": "^0.32.3", + "@cosmjs/crypto": "^0.32.3", + "@cosmjs/proto-signing": "^0.32.3", "@ethersproject/shims": "^5.7.0", "@json-rpc-tools/utils": "^1.7.6", "@react-native-async-storage/async-storage": "^1.22.3", @@ -21,6 +22,7 @@ "@react-navigation/native-stack": "^6.9.18", "@walletconnect/react-native-compat": "^2.11.2", "@walletconnect/web3wallet": "^1.10.2", + "cosmjs-types": "^0.9.0", "ethers": "5.7.2", "fast-text-encoding": "^1.0.6", "metro-react-native-babel-preset": "^0.77.0", diff --git a/utils/sign-message.ts b/utils/sign-message.ts index 4d07e6b..4256d8a 100644 --- a/utils/sign-message.ts +++ b/utils/sign-message.ts @@ -5,9 +5,15 @@ import 'react-native-get-random-values'; import '@ethersproject/shims'; import { Wallet } from 'ethers'; +import { SignDoc } from 'cosmjs-types/cosmos/tx/v1beta1/tx'; import { SignMessageParams } from '../types'; -import { getCosmosAccounts, getMnemonic, getPathKey } from './utils'; +import { + getCosmosAccounts, + getDirectWallet, + getMnemonic, + getPathKey, +} from './utils'; const signMessage = async ({ message, @@ -38,7 +44,7 @@ const signEthMessage = async ( return signature; } catch (error) { console.error('Error signing Ethereum message:', error); - return undefined; + throw error; } }; @@ -76,8 +82,30 @@ const signCosmosMessage = async ( return cosmosSignature.signature.signature; } catch (error) { console.error('Error signing Cosmos message:', error); - return undefined; + throw error; } }; -export { signMessage, signEthMessage, signCosmosMessage }; +const signDirectMessage = async ( + network: string, + accountId: number, + signDoc: SignDoc, +): Promise => { + try { + const path = (await getPathKey(network, accountId)).path; + const mnemonic = await getMnemonic(); + const { directWallet, data } = await getDirectWallet(mnemonic, path); + + const directSignature = await directWallet.signDirect( + data.address, + signDoc, + ); + + return directSignature.signature.signature; + } catch (error) { + console.error('Error signing Cosmos message:', error); + throw error; + } +}; + +export { signMessage, signEthMessage, signCosmosMessage, signDirectMessage }; diff --git a/utils/utils.ts b/utils/utils.ts index ceec650..b878eaa 100644 --- a/utils/utils.ts +++ b/utils/utils.ts @@ -12,6 +12,7 @@ import { } from 'react-native-keychain'; import { AccountData, Secp256k1HdWallet } from '@cosmjs/amino'; +import { DirectSecp256k1HdWallet } from '@cosmjs/proto-signing'; import { stringToPath } from '@cosmjs/crypto'; const getMnemonic = async (): Promise => { @@ -58,6 +59,19 @@ const getCosmosAccounts = async ( return { cosmosWallet, data }; }; +export const getDirectWallet = async ( + mnemonic: string, + path: string, +): Promise<{ directWallet: DirectSecp256k1HdWallet; data: AccountData }> => { + const directWallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { + hdPaths: [stringToPath(`m/44'/118'/${path}`)], + }); + const accountsData = await directWallet.getAccounts(); + const data = accountsData[0]; + + return { directWallet, data }; +}; + const accountInfoFromHDPath = async ( hdPath: string, ): Promise< diff --git a/utils/wallet-connect/WalletConnectRequests.ts b/utils/wallet-connect/WalletConnectRequests.ts index 3efbb69..57fe268 100644 --- a/utils/wallet-connect/WalletConnectRequests.ts +++ b/utils/wallet-connect/WalletConnectRequests.ts @@ -5,7 +5,7 @@ import { SignClientTypes } from '@walletconnect/types'; import { getSdkError } from '@walletconnect/utils'; import { EIP155_SIGNING_METHODS } from './EIP155Lib'; -import { signEthMessage } from '../sign-message'; +import { signDirectMessage, signEthMessage } from '../sign-message'; import { Account } from '../../types'; import { getCosmosAccounts, getMnemonic, getPathKey } from '../utils'; @@ -25,31 +25,45 @@ export async function approveWalletConnectRequest( switch (request.method) { case EIP155_SIGNING_METHODS.PERSONAL_SIGN: - const signedEthMessage = await signEthMessage(message, account.counterId); - return formatJsonRpcResult(id, signedEthMessage); - // TODO: Debug signDirect + const ethSignature = await signEthMessage(message, account.counterId); + return formatJsonRpcResult(id, ethSignature); + case 'cosmos_signDirect': - const signedCosmosMessage = await cosmosAccount.cosmosWallet.signAmino( - address, - request.params.signDoc, + // Reference: https://github.com/confio/cosmjs-types/blob/66e52711914fccd2a9d1a03e392d3628fdf499e2/src/cosmos/tx/v1beta1/tx.ts#L51 + // According above doc, in the signDoc interface 'bodyBytes' and 'authInfoBytes' have Uint8Array type + const bodyBytesArray = Uint8Array.from( + Buffer.from(request.params.signDoc.bodyBytes, 'hex'), + ); + const authInfoBytesArray = Uint8Array.from( + Buffer.from(request.params.signDoc.authInfoBytes, 'hex'), + ); + + const cosmosDirectSignature = await signDirectMessage( + network, + account.counterId, + { + ...request.params.signDoc, + bodyBytes: bodyBytesArray, + authInfoBytes: authInfoBytesArray, + }, ); return formatJsonRpcResult(id, { - signature: signedCosmosMessage.signature.signature, + signature: cosmosDirectSignature, }); case 'cosmos_signAmino': - const signedAminoMessage = await cosmosAccount.cosmosWallet.signAmino( + const cosmosAminoSignature = await cosmosAccount.cosmosWallet.signAmino( address, request.params.signDoc, ); - if (!signedAminoMessage) { + if (!cosmosAminoSignature) { throw new Error('Error signing message'); } return formatJsonRpcResult(id, { - signature: signedAminoMessage.signature.signature, + signature: cosmosAminoSignature.signature.signature, }); default: throw new Error(getSdkError('INVALID_METHOD').message); diff --git a/yarn.lock b/yarn.lock index e0a57c5..8cc90cf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1167,49 +1167,61 @@ deepmerge "^3.2.0" hoist-non-react-statics "^3.3.0" -"@cosmjs/amino@^0.32.2": - version "0.32.2" - resolved "https://registry.yarnpkg.com/@cosmjs/amino/-/amino-0.32.2.tgz#ba3cf255e4e6b1ba67461f1ef7b0b8ad3f895da7" - integrity sha512-lcK5RCVm4OfdAooxKcF2+NwaDVVpghOq6o/A40c2mHXDUzUoRZ33VAHjVJ9Me6vOFxshrw/XEFn1f4KObntjYA== +"@cosmjs/amino@^0.32.3": + version "0.32.3" + resolved "https://registry.yarnpkg.com/@cosmjs/amino/-/amino-0.32.3.tgz#b81d4a2b8d61568431a1afcd871e1344a19d97ff" + integrity sha512-G4zXl+dJbqrz1sSJ56H/25l5NJEk/pAPIr8piAHgbXYw88OdAOlpA26PQvk2IbSN/rRgVbvlLTNgX2tzz1dyUA== dependencies: - "@cosmjs/crypto" "^0.32.2" - "@cosmjs/encoding" "^0.32.2" - "@cosmjs/math" "^0.32.2" - "@cosmjs/utils" "^0.32.2" + "@cosmjs/crypto" "^0.32.3" + "@cosmjs/encoding" "^0.32.3" + "@cosmjs/math" "^0.32.3" + "@cosmjs/utils" "^0.32.3" -"@cosmjs/crypto@^0.32.2": - version "0.32.2" - resolved "https://registry.yarnpkg.com/@cosmjs/crypto/-/crypto-0.32.2.tgz#8ed255d3d1c1c4d916a1586f8cbc33eaab82f511" - integrity sha512-RuxrYKzhrPF9g6NmU7VEq++Hn1vZJjqqJpZ9Tmw9lOYOV8BUsv+j/0BE86kmWi7xVJ7EwxiuxYsKuM8IR18CIA== +"@cosmjs/crypto@^0.32.3": + version "0.32.3" + resolved "https://registry.yarnpkg.com/@cosmjs/crypto/-/crypto-0.32.3.tgz#787f8e659709678722068ee1ddf379f65051a25e" + integrity sha512-niQOWJHUtlJm2GG4F00yGT7sGPKxfUwz+2qQ30uO/E3p58gOusTcH2qjiJNVxb8vScYJhFYFqpm/OA/mVqoUGQ== dependencies: - "@cosmjs/encoding" "^0.32.2" - "@cosmjs/math" "^0.32.2" - "@cosmjs/utils" "^0.32.2" + "@cosmjs/encoding" "^0.32.3" + "@cosmjs/math" "^0.32.3" + "@cosmjs/utils" "^0.32.3" "@noble/hashes" "^1" bn.js "^5.2.0" elliptic "^6.5.4" libsodium-wrappers-sumo "^0.7.11" -"@cosmjs/encoding@^0.32.2": - version "0.32.2" - resolved "https://registry.yarnpkg.com/@cosmjs/encoding/-/encoding-0.32.2.tgz#8c5c64481a85cd570740c34dccce69d024a29805" - integrity sha512-WX7m1wLpA9V/zH0zRcz4EmgZdAv1F44g4dbXOgNj1eXZw1PIGR12p58OEkLN51Ha3S4DKRtCv5CkhK1KHEvQtg== +"@cosmjs/encoding@^0.32.3": + version "0.32.3" + resolved "https://registry.yarnpkg.com/@cosmjs/encoding/-/encoding-0.32.3.tgz#e245ff511fe4a0df7ba427b5187aab69e3468e5b" + integrity sha512-p4KF7hhv8jBQX3MkB3Defuhz/W0l3PwWVYU2vkVuBJ13bJcXyhU9nJjiMkaIv+XP+W2QgRceqNNgFUC5chNR7w== dependencies: base64-js "^1.3.0" bech32 "^1.1.4" readonly-date "^1.0.0" -"@cosmjs/math@^0.32.2": - version "0.32.2" - resolved "https://registry.yarnpkg.com/@cosmjs/math/-/math-0.32.2.tgz#4522312769197e132679e4960862bcec0eed4cb8" - integrity sha512-b8+ruAAY8aKtVKWSft2IvtCVCUH1LigIlf9ALIiY8n9jtM4kMASiaRbQ/27etnSAInV88IaezKK9rQZrtxTjcw== +"@cosmjs/math@^0.32.3": + version "0.32.3" + resolved "https://registry.yarnpkg.com/@cosmjs/math/-/math-0.32.3.tgz#16e4256f4da507b9352327da12ae64056a2ba6c9" + integrity sha512-amumUtZs8hCCnV+lSBaJIiZkGabQm22QGg/IotYrhcmoOEOjt82n7hMNlNXRs7V6WLMidGrGYcswB5zcmp0Meg== dependencies: bn.js "^5.2.0" -"@cosmjs/utils@^0.32.2": - version "0.32.2" - resolved "https://registry.yarnpkg.com/@cosmjs/utils/-/utils-0.32.2.tgz#324304aa85bfa6f10561cc17781d824d02130897" - integrity sha512-Gg5t+eR7vPJMAmhkFt6CZrzPd0EKpAslWwk5rFVYZpJsM8JG5KT9XQ99hgNM3Ov6ScNoIWbXkpX27F6A9cXR4Q== +"@cosmjs/proto-signing@^0.32.3": + version "0.32.3" + resolved "https://registry.yarnpkg.com/@cosmjs/proto-signing/-/proto-signing-0.32.3.tgz#91ae149b747d18666a6ccc924165b306431f7c0d" + integrity sha512-kSZ0ZUY0DwcRT0NcIn2HkadH4NKlwjfZgbLj1ABwh/4l0RgeT84QCscZCu63tJYq3K6auwqTiZSZERwlO4/nbg== + dependencies: + "@cosmjs/amino" "^0.32.3" + "@cosmjs/crypto" "^0.32.3" + "@cosmjs/encoding" "^0.32.3" + "@cosmjs/math" "^0.32.3" + "@cosmjs/utils" "^0.32.3" + cosmjs-types "^0.9.0" + +"@cosmjs/utils@^0.32.3": + version "0.32.3" + resolved "https://registry.yarnpkg.com/@cosmjs/utils/-/utils-0.32.3.tgz#5dcaee6dd7cc846cdc073e9a7a7f63242f5f7e31" + integrity sha512-WCZK4yksj2hBDz4w7xFZQTRZQ/RJhBX26uFHmmQFIcNUUVAihrLO+RerqJgk0dZqC42wstM9pEUQGtPmLcIYvg== "@craftzdog/react-native-buffer@^6.0.5": version "6.0.5" @@ -3944,6 +3956,11 @@ cosmiconfig@^5.0.5, cosmiconfig@^5.1.0: js-yaml "^3.13.1" parse-json "^4.0.0" +cosmjs-types@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/cosmjs-types/-/cosmjs-types-0.9.0.tgz#c3bc482d28c7dfa25d1445093fdb2d9da1f6cfcc" + integrity sha512-MN/yUe6mkJwHnCFfsNPeCfXVhyxHYW6c/xDUzrSbBycYzw++XvWDMJArXp2pLdgD6FQ8DW79vkPjeNKVrXaHeQ== + create-ecdh@^4.0.0: version "4.0.4" resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e"