From 8c0751f84bb2f21316db40fbda50ce5b17b40db2 Mon Sep 17 00:00:00 2001 From: shreerang6921 <68148922+shreerang6921@users.noreply.github.com> Date: Fri, 19 Apr 2024 16:21:21 +0530 Subject: [PATCH] Add details to setup wallet connect in readme (#58) * Add details to setup wallet connect in readme * Add hyperlinks for wallet connect terms * Handle review changes * Add keystore data structure and troubleshooting steps in readme * Update readme * Add pre-commit lint hook * Resolve linter warnings * Handle review changes * Fix heading level in readme --- .husky/pre-commit | 1 + README.md | 32 +++- development.md | 160 ++++++++++++++++++ package.json | 6 +- src/components/SelectNetworkType.tsx | 8 +- src/styles/stylesheet.js | 4 + .../wallet-connect/WalletConnectUtils.tsx | 2 +- yarn.lock | 5 + 8 files changed, 206 insertions(+), 12 deletions(-) create mode 100644 .husky/pre-commit create mode 100644 development.md diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..39abe4d --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +yarn lint diff --git a/README.md b/README.md index 5027bd4..37c8aca 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # laconic-wallet -### Install +## Install - Install [Node](https://nodejs.org/en/download/package-manager/) @@ -87,7 +87,7 @@ ``` cp .env.example .env ``` - + - In [.env](./.env) file add WalletConnect project id. You can generate your own ProjectId at https://cloud.walletconnect.com ``` @@ -134,3 +134,31 @@ 5. Press `a` to run the application on android You should see both the apps running on your emulator or physical device. + +## Flow for the app + +- User scans QR Code on dApp from wallet to connect + +- After clicking on pair button, dApp emits an event 'session_proposal' + +- Wallet listens to this event and opens a modal to either accept or reject the proposal + + - Modal shows information about methods, chains and events the dApp is requesting for + + - This information is taken from [namespaces](https://docs.walletconnect.com/advanced/glossary#namespaces) object received from dApp + +- On accepting, wallet sends the [namespaces](https://docs.walletconnect.com/advanced/glossary#namespaces) object with information about the accounts that are present in the wallet in response + +- Once [session](https://docs.walletconnect.com/advanced/glossary#session) is established, it is shown in the active sessions page + +- In this way, wallet can connect to multiple dApps + +## Troubleshooting + +- To clean the buid + + ``` + cd adroid + + ./gradlew clean + ``` diff --git a/development.md b/development.md new file mode 100644 index 0000000..a4eb585 --- /dev/null +++ b/development.md @@ -0,0 +1,160 @@ +# Development + +## WalletConnect details + +- Docs - https://docs.walletconnect.com/api/sign/overview + +- Doc for terminologies - https://docs.walletconnect.com/advanced/glossary + +- Function for creating web3 wallet + + ```js + export let web3wallet: IWeb3Wallet; + export let core: ICore; + + export async function createWeb3Wallet() { + const core = new Core({ + projectId: Config.WALLET_CONNECT_PROJECT_ID, + }); + + web3wallet = await Web3Wallet.init({ + core, + metadata: { + name: 'Laconic Wallet', + description: 'Laconic Wallet', + url: 'https://wallet.laconic.com/', + icons: ['https://avatars.githubusercontent.com/u/92608123'], + }, + }); + } + ``` + +- Hook used for intializing web3 wallet + + ```js + export default function useInitialization() { + const [initialized, setInitialized] = useState(false); + + const onInitialize = useCallback(async () => { + try { + await createWeb3Wallet(); + setInitialized(true); + } catch (err: unknown) { + console.log('Error for initializing', err); + } + }, []); + + useEffect(() => { + if (!initialized) { + onInitialize(); + } + }, [initialized, onInitialize]); + + return initialized; + } + ``` + +- Once user clicks on pair, this function is triggered + + ```js + export async function web3WalletPair(params: { uri: string }) { + return await web3wallet.core.pairing.pair({ uri: params.uri }); + } + ``` + +- In a useEffect, we keep on listening to events that are emitted by dapp and do actions based on it + + ```js + useEffect(() => { + web3wallet?.on('session_proposal', onSessionProposal); + web3wallet?.on('session_request', onSessionRequest); + web3wallet?.on('session_delete', onSessionDelete); + return () => { + web3wallet?.off('session_proposal', onSessionProposal); + web3wallet?.off('session_request', onSessionRequest); + web3wallet?.off('session_delete', onSessionDelete); + } + }) + ``` +- Signing messages + + - Cosmos methods info + + - The signDoc format for signAmino and signDirect is different + + - Reference - https://docs.leapwallet.io/cosmos/for-dapps-connect-to-leap/api-reference + + - For signDirect, the message is protobuf encoded , hence to sign it , we have to first convert it to uint8Array + + ```js + const bodyBytesArray = Uint8Array.from( + Buffer.from(request.params.signDoc.bodyBytes, 'hex'), + ); + const authInfoBytesArray = Uint8Array.from( + Buffer.from(request.params.signDoc.authInfoBytes, 'hex'), + ); + ``` + + - This will give us correct signature + +## Data structure of keystore + + ```json + { + // Accounts data -> hdpath, privateKey, publicKey, address + "accounts/eip155:1/0":{ + "username": "", + "password": "m/44'/60'/0'/0/0,0x0654623fe7a0e3d74f518e22818c1cfd58517e80a232df5d6d20a3afd99fd3bb,0x02cced178c903835bb29e337fa227ba0204a3285eb35797b766ed975b478b4beb6,0xe5fA0Dd92659e287e5e3Fa582Ee20fcf74fb1116" + }, + "accounts/cosmos:cosmoshub-4/0":{ + "username": "", + "password": "m/44'/118'/0'/0/0,0xbb9ccc3029178a61ba847c22108318ba119220451c99e6358efd7b85d7d49ed5,0x03a8002f56f99126f930ca3ac1963731e3f08df30822031db7c1dd50851bdfcc3c,cosmos1s5a5ls3d6xmks5fc8tst9x7tx2jv8mfjmn0aq8" + }, + + // Networks Data + "networks":{ + "username":"", + "password":[ + { + "networkId":"1", + "namespace": "eip155", + "chainId": "1", + "networkName": "Ethereum", + "rpcUrl": "https://cloudflare-eth.com/", + "currencySymbol": "ETH", + "coinType": "60" + }, + { + "networkId":"2", + "namespace": "cosmos", + "chainId": "theta-testnet-001", + "networkName": "Cosmos Hub Testnet", + "rpcUrl": "https://rpc-t.cosmos.nodestake.top", + "nativeDenom": "ATOM", + "addressPrefix": "cosmos", + "coinType": "118" + } + ] + }, + + // Stores count of total accounts for specific chain + "addAccountCounter/eip155:1":{ + "username": "", + "password": "3" + }, + "addAccountCounter/cosmos:cosmoshub-4":{ + "username": "", + "password": "3" + }, + + // Stores ids of accounts for specific chain + "accountIndices/eip155:1":{ + "username": "", + "password": "0,1,2" + }, + "accountIndices/cosmos:cosmoshub-4":{ + "username": "", + "password": "0,1,2" + } + } + ``` diff --git a/package.json b/package.json index b952e15..61705ec 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,11 @@ "scripts": { "android": "react-native run-android", "ios": "react-native run-ios", - "lint": "eslint .", + "lint": "eslint . --max-warnings=0", "start": "react-native start", "test": "jest", - "postinstall": "patch-package" + "postinstall": "patch-package", + "prepare": "husky" }, "dependencies": { "@cosmjs/amino": "^0.32.3", @@ -66,6 +67,7 @@ "babel-jest": "^29.6.3", "babel-plugin-module-resolver": "^5.0.0", "eslint": "^8.19.0", + "husky": "^9.0.11", "jest": "^29.6.3", "metro-babel7-plugin-react-transform": "^0.54.1", "prettier": "2.8.8", diff --git a/src/components/SelectNetworkType.tsx b/src/components/SelectNetworkType.tsx index e26558f..dc76fef 100644 --- a/src/components/SelectNetworkType.tsx +++ b/src/components/SelectNetworkType.tsx @@ -23,13 +23,7 @@ const SelectNetworkType = ({ return ( - - Select Network Type - + Select Network Type