Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CON-547 Create PoC react-native example using HWC #1

Merged
merged 1 commit into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
EXPO_PUBLIC_WC_PROJECT_ID=76fe8acdb87cc235b2790897a47e960c
EXPO_PUBLIC_WC_NAME="Test hedera-connect"
EXPO_PUBLIC_WC_DESCRIPTION="Test hedera-connect"
EXPO_PUBLIC_WC_URL=https://hwc-docs.hgraph.app
EXPO_PUBLIC_WC_ICON=https://hwc-docs.hgraph.app/img/logo.svg
EXPO_PUBLIC_ACCOUNT_ID=
EXPO_PUBLIC_PRIVATE_KEY=
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ web-build/
# The following patterns were generated by expo-cli

expo-env.d.ts
android
.env
# @end expo-cli
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ This is an [Expo](https://expo.dev) project created with [`create-expo-app`](htt
1. Install dependencies

```bash
npm install
npm install --legacy-peer-deps
```

2. Seup env vars

```bash
cp .env.example .env
```

2. Start the app
Expand Down
9 changes: 3 additions & 6 deletions app.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@
"slug": "react-native-template",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/images/icon.png",
"scheme": "myapp",
"userInterfaceStyle": "automatic",
"splash": {
"image": "./assets/images/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
Expand All @@ -17,14 +15,13 @@
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/images/adaptive-icon.png",
"backgroundColor": "#ffffff"
}
},
"package": "com.hgraph.reactnativetemplate"
},
"web": {
"bundler": "metro",
"output": "static",
"favicon": "./assets/images/favicon.png"
"output": "static"
},
"plugins": [
"expo-router"
Expand Down
2 changes: 1 addition & 1 deletion app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Stack } from "expo-router";
export default function RootLayout() {
return (
<Stack>
<Stack.Screen name="index" options={{ title: '@hgraph.io/sdk example' }} />
<Stack.Screen name="index" options={{ title: 'HWC Wallet Example' }} />
</Stack>
);
}
185 changes: 149 additions & 36 deletions app/index.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,145 @@
import { Button, Text, View } from "react-native";
import {useState, useRef} from 'react'
import Client from '@hgraph.io/sdk'

const LatestTransactionSubscription = `
subscription LatestTransaction {
transaction(limit: 1, order_by: {consensus_timestamp: desc}) {
consensus_timestamp
}
}`
import "../src/polyfills.js";
import { Button, Text, View, Alert, TextInput } from "react-native";
import type { Web3WalletTypes } from "@walletconnect/web3wallet";
import { getSdkError } from "@walletconnect/utils";
import { Wallet, HederaChainId } from "@hashgraph/hedera-wallet-connect";
import React, { useState, useEffect } from "react";

const client = new Client()

export default function Index() {
const [logState, setLog] = useState("");
const [wallet, setWallet] = useState<Wallet>();
const [pairUrl, onChangeUrl] = React.useState("");

const [state, setState] = useState()
const [subscribed, setSubscribed] = useState(false)
const unsubscribe = useRef(() => {})

const toggle = () => {
if (subscribed) {
unsubscribe.current()
setSubscribed(false)
} else {
unsubscribe.current = client.subscribe(LatestTransactionSubscription, {
// handle the data
next: (data: any) => {
console.log(data)
setState(data)
},
error: (e) => {
console.error(e)
},
complete: () => {
unsubscribe.current = () => {}
console.log('Optionally do some cleanup')
const confirm = (message: string) =>
new Promise((resolve) =>
Alert.alert("Confirm", message, [
{
text: "Reject",
onPress: () => resolve(false),
style: "cancel",
},
}).unsubscribe;
setSubscribed(true)
{ text: "OK", onPress: () => resolve(true) },
]),
);

function log(message: string) {
console.log(message);
setLog((currentLog) => currentLog + "\n" + message);
}

async function init() {
const projectId = process.env.EXPO_PUBLIC_WC_PROJECT_ID!;
const metadata: Web3WalletTypes.Metadata = {
name: process.env.EXPO_PUBLIC_WC_NAME!,
description: process.env.EXPO_PUBLIC_WC_DESCRIPTION!,
url: process.env.EXPO_PUBLIC_WC_URL!,
icons: [process.env.EXPO_PUBLIC_WC_ICON!],
};

const wallet = await Wallet.create(projectId, metadata);
setWallet(wallet);
/*
* Add listeners
*/

// called after pairing to set parameters of session, i.e. accounts, chains, methods, events
wallet.on(
"session_proposal",
async (proposal: Web3WalletTypes.SessionProposal) => {
const accountId = process.env.EXPO_PUBLIC_ACCOUNT_ID!;
const chainId = HederaChainId.Testnet;
const accounts: string[] = [`${chainId}:${accountId}`];

if (
await confirm(
`Do you want to connect to this session?: ${JSON.stringify(
proposal,
)}`,
)
)
wallet!.buildAndApproveSession(accounts, proposal);
else
await wallet!.rejectSession({
id: proposal.id,
reason: getSdkError("USER_REJECTED_METHODS"),
});
},
);

// requests to call a JSON-RPC method
wallet.on(
"session_request",
async (event: Web3WalletTypes.SessionRequest) => {
try {
const { chainId, accountId } = wallet!.parseSessionRequest(event);

if (
!(await confirm(
`Do you want to proceed with this request?: ${JSON.stringify(
event,
)}`,
))
)
throw getSdkError("USER_REJECTED_METHODS");

const hederaWallet = wallet!.getHederaWallet(
chainId,
accountId || process.env.EXPO_PUBLIC_ACCOUNT_ID!,
process.env.EXPO_PUBLIC_PRIVATE_KEY!,
);

return await wallet!.executeSessionRequest(event, hederaWallet);
} catch (e) {
const error = e as { message: string; code: number };
log("Error: " + error.message);
wallet!.rejectSessionRequest(event, error);
}
},
);

wallet.on("session_delete", () => {
// Session was deleted
log("Wallet: Session deleted by dapp!");
});

wallet.core.pairing.events.on("pairing_delete", (pairing: string) => {
// Session was deleted
log(pairing);
log(`Wallet: Pairing deleted by dapp!`);
});

log("Wallet: WalletConnect initialized!");
}

async function pair(uri: string) {
wallet!.core.pairing.pair({ uri });

}

async function disconnect() {
//https://docs.walletconnect.com/web3wallet/wallet-usage#session-disconnect
for (const session of Object.values(wallet!.getActiveSessions())) {
log(`Disconnecting from session: ${session}`);
await wallet!.disconnectSession({
// @ts-ignore
topic: session.topic,
reason: getSdkError("USER_DISCONNECTED"),
});
}
for (const pairing of wallet!.core.pairing.getPairings()) {
log(`Disconnecting from pairing: ${pairing}`);
await wallet!.disconnectSession({
topic: pairing.topic,
reason: getSdkError("USER_DISCONNECTED"),
});
}
}

useEffect(() => {
init();
}, []);

return (
<View
style={{
Expand All @@ -49,8 +149,21 @@ export default function Index() {
alignItems: "center",
}}
>
<Button onPress={toggle} title={subscribed ? 'Stop' : 'Start'} />
<Text>{JSON.stringify(state)}</Text>
<TextInput
style={{
height: 40,
width: '50%',
margin: 12,
borderWidth: 1,
padding: 10,
}}
onChangeText={onChangeUrl}
value={pairUrl}
placeholder="Pair URI"
/>
<Button disabled={!pairUrl} title="Pair" onPress={() => pair(pairUrl)} />
<Button title="Disconnect" onPress={disconnect} />
<Text>{logState}</Text>
</View>
);
}
Loading