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
This commit is contained in:
shreerang6921 2024-04-19 16:21:21 +05:30 committed by Nabarun Gogoi
parent 1172e67f5f
commit 8c0751f84b
8 changed files with 206 additions and 12 deletions

1
.husky/pre-commit Normal file
View File

@ -0,0 +1 @@
yarn lint

View File

@ -1,6 +1,6 @@
# laconic-wallet # laconic-wallet
### Install ## Install
- Install [Node](https://nodejs.org/en/download/package-manager/) - Install [Node](https://nodejs.org/en/download/package-manager/)
@ -134,3 +134,31 @@
5. Press `a` to run the application on android 5. Press `a` to run the application on android
You should see both the apps running on your emulator or physical device. 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
```

160
development.md Normal file
View File

@ -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"
}
}
```

View File

@ -5,10 +5,11 @@
"scripts": { "scripts": {
"android": "react-native run-android", "android": "react-native run-android",
"ios": "react-native run-ios", "ios": "react-native run-ios",
"lint": "eslint .", "lint": "eslint . --max-warnings=0",
"start": "react-native start", "start": "react-native start",
"test": "jest", "test": "jest",
"postinstall": "patch-package" "postinstall": "patch-package",
"prepare": "husky"
}, },
"dependencies": { "dependencies": {
"@cosmjs/amino": "^0.32.3", "@cosmjs/amino": "^0.32.3",
@ -66,6 +67,7 @@
"babel-jest": "^29.6.3", "babel-jest": "^29.6.3",
"babel-plugin-module-resolver": "^5.0.0", "babel-plugin-module-resolver": "^5.0.0",
"eslint": "^8.19.0", "eslint": "^8.19.0",
"husky": "^9.0.11",
"jest": "^29.6.3", "jest": "^29.6.3",
"metro-babel7-plugin-react-transform": "^0.54.1", "metro-babel7-plugin-react-transform": "^0.54.1",
"prettier": "2.8.8", "prettier": "2.8.8",

View File

@ -23,13 +23,7 @@ const SelectNetworkType = ({
return ( return (
<View style={styles.networkDropdown}> <View style={styles.networkDropdown}>
<Text <Text style={styles.selectNetworkText}>Select Network Type</Text>
style={{
fontWeight: 'bold',
marginVertical: 10,
}}>
Select Network Type
</Text>
<List.Accordion <List.Accordion
title={selectedNetwork} title={selectedNetwork}
expanded={expanded} expanded={expanded}

View File

@ -265,6 +265,10 @@ const styles = StyleSheet.create({
sessionsContainer: { paddingLeft: 12, borderBottomWidth: 0.5 }, sessionsContainer: { paddingLeft: 12, borderBottomWidth: 0.5 },
walletConnectUriText: { padding: 10 }, walletConnectUriText: { padding: 10 },
walletConnectLogo: { width: 24, height: 15, margin: 0 }, walletConnectLogo: { width: 24, height: 15, margin: 0 },
selectNetworkText: {
fontWeight: 'bold',
marginVertical: 10,
},
}); });
export default styles; export default styles;

View File

@ -10,7 +10,7 @@ export let web3wallet: IWeb3Wallet | undefined;
export let core: ICore; export let core: ICore;
export async function createWeb3Wallet() { export async function createWeb3Wallet() {
const core = new Core({ core = new Core({
projectId: Config.WALLET_CONNECT_PROJECT_ID, projectId: Config.WALLET_CONNECT_PROJECT_ID,
}); });

View File

@ -5494,6 +5494,11 @@ human-signals@^5.0.0:
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28"
integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==
husky@^9.0.11:
version "9.0.11"
resolved "https://registry.yarnpkg.com/husky/-/husky-9.0.11.tgz#fc91df4c756050de41b3e478b2158b87c1e79af9"
integrity sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==
idb-keyval@^6.2.1: idb-keyval@^6.2.1:
version "6.2.1" version "6.2.1"
resolved "https://registry.yarnpkg.com/idb-keyval/-/idb-keyval-6.2.1.tgz#94516d625346d16f56f3b33855da11bfded2db33" resolved "https://registry.yarnpkg.com/idb-keyval/-/idb-keyval-6.2.1.tgz#94516d625346d16f56f3b33855da11bfded2db33"