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

Add WalletConnect V2 implementation via Web3Modal Flutter SDK #113

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ android {
applicationId "com.example.example"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion 21
minSdkVersion 23
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
Expand Down
16 changes: 16 additions & 0 deletions example/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<queries>
<package android:name="org.toshi"/> <!--Support for Coinbase wallet-->
<package android:name="io.metamask"/>
<package android:name="com.wallet.crypto.trustapp"/>
<package android:name="io.gnosis.safe"/>
<package android:name="me.rainbow"/>
<package android:name="im.token.app"/>
<package android:name="io.zerion.android"/>
<package android:name="com.spot.spot"/>
<package android:name="fi.steakwallet.app"/>
<package android:name="vip.mytokenpocket"/>
<package android:name="com.frontierwallet"/>
<package android:name="com.bitkeep.wallet"/>
<package android:name="im.argent.contractwalletclient"/>
<package android:name="com.walletconnect.sample.wallet"/>
</queries>
<application
android:label="example"
android:name="${applicationName}"
Expand Down
47 changes: 47 additions & 0 deletions example/ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,52 @@
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>metamask</string>
<string>trust</string>
<string>safe</string>
<string>rainbow</string>
<string>uniswap</string>
<string>zerion</string>
<string>imtokenv2</string>
<string>spot</string>
<string>omni</string>
<string>dfw</string>
<string>tpoutside</string>
<string>robinhood-wallet</string>
<string>frontier</string>
<string>blockchain-wallet</string>
<string>safepalwallet</string>
<string>bitkeep</string>
<string>oneinch</string>
<string>exodus</string>
<string>bnc</string>
<string>ledgerlive</string>
<string>mewwallet</string>
<string>awallet</string>
<string>keyring</string>
<string>lobstr</string>
<string>ontoprovider</string>
<string>mathwallet</string>
<string>unstoppabledomains</string>
<string>obvious</string>
<string>fireblocks-wc</string>
<string>ambire</string>
<string>internetmoney</string>
<string>walletnow</string>
<string>bitcoincom</string>
<string>coin98</string>
<string>arculuswc</string>
<string>cryptobrowser</string>
<string>chainapp</string>
<string>huddln</string>
<string>verso</string>
<string>haha</string>
<string>modularwallet</string>
<string>coinomi</string>
<string>cbwallet</string>
</array>
<key>LSRequiresIPhoneOS</key>
</dict>
</plist>
76 changes: 76 additions & 0 deletions example/lib/Web3ModalService.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import 'package:flutter/cupertino.dart';
import 'package:web3modal_flutter/web3modal_flutter.dart';
import 'package:xmtp/xmtp.dart' as xmtp;

const PROJECT_ID = 'af3346694438a7a937ee3aee9968e8fa';// change this to your project id, for more info visit https://cloud.walletconnect.com/

final Web3ModalService w3mService = Web3ModalService._();

class Web3ModalService extends ChangeNotifier {
W3MService w3mService;
void Function(SessionConnect?)? onSessionConnectCallback;

Web3ModalService._()
: w3mService = W3MService(
projectId: PROJECT_ID,
metadata: const PairingMetadata(
name: 'XMTP.org',
description: 'XMTP Flutter Example',
url: 'https://www.xmtp.org/',
icons: ['https://avatars.githubusercontent.com/u/82580170?s=48&v=4'],
redirect: Redirect(
native: 'xmtp-example-wc://request',
universal: 'https://www.walletconnect.com',
),
),
);

void init({required void Function(SessionConnect?) callback}) async {
onSessionConnectCallback = callback;
await w3mService.init();
w3mService.onSessionConnectEvent.subscribe(_onSessionConnect);
w3mService.onSessionUpdateEvent.subscribe((args) { notifyListeners(); });
w3mService.onSessionExpireEvent.subscribe((args) { notifyListeners(); });
w3mService.onSessionDeleteEvent.subscribe((args) { notifyListeners(); });


}

xmtp.Signer asSigner() {
var address = w3mService.session?.address;
debugPrint('address: $address');
w3mService.launchConnectedWallet();
return xmtp.Signer.create(
address!,
(text) => w3mService.web3App!.request(
topic: w3mService.session!.topic!,
chainId: 'eip155:1',
request: SessionRequestParams(
method: 'personal_sign', params: [text, address]),
).then((answer) =>
hexToBytes(answer)
)
);
}

sendSignReq(text, address) {
w3mService.web3App!.request(
topic: w3mService.session!.topic!,
chainId: 'eip155:1',
request: SessionRequestParams(
method: 'personal_sign', params: [text, address]),
).then((answer) =>
hexToBytes(answer)
);

}

void _onSessionConnect(SessionConnect? args) {
debugPrint('[$runtimeType] _onSessionConnect $args');
if (onSessionConnectCallback != null) {
onSessionConnectCallback!(args);
}
}


}
140 changes: 23 additions & 117 deletions example/lib/pages/login_page.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import "dart:math";

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:web3dart/web3dart.dart';
import 'package:go_router/go_router.dart';
import 'package:web3modal_flutter/web3modal_flutter.dart';
import 'package:xmtp/xmtp.dart' as xmtp;
import 'package:qr_flutter/qr_flutter.dart';
import 'package:url_launcher/url_launcher.dart';
import "dart:math";

import '../Web3ModalService.dart';
import '../session/foreground_session.dart';
import '../wallet.dart';

/// A page prompting the user to login.
///
Expand All @@ -27,7 +25,24 @@ class LoginPage extends HookWidget {

@override
Widget build(BuildContext context) {
useListenable(wallet);
handleSessionConnect(BuildContext context,SessionConnect? args) async {
try {
var signer = w3mService.asSigner();
await session.authorize(signer);
context.goNamed('home');
}
catch(e){
print('Errorf: $e');
}
}
useEffect(() {
w3mService.init(callback: (args) => handleSessionConnect(context, args));
return () {
};
}, []);
useListenable(w3mService);

var service = w3mService.w3mService;
return Scaffold(
body: Container(
padding: const EdgeInsets.all(16),
Expand All @@ -36,28 +51,7 @@ class LoginPage extends HookWidget {
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
child: const Text('Connect Wallet'),
onPressed: () async {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) => const _BottomQrModal(),
);
try {
if (!wallet.wc.connected) {
await wallet.connect();
}
if (wallet.wc.session.accounts.isEmpty) {
throw Exception('No accounts connected');
}
await session.authorize(wallet.asSigner());
// ignore: use_build_context_synchronously
context.goNamed('home');
} catch (err) {
Navigator.pop(context);
}
},
),
W3MConnectWalletButton(service: service),
ElevatedButton(
child: const Text('Create Random Wallet'),
onPressed: () async {
Expand Down Expand Up @@ -92,92 +86,4 @@ class LoginPage extends HookWidget {
}
}

/// A sheet that slides up with buttons for the current [WalletConnect] session.
///
/// It shows buttons for Rainbow and Metamask wallets alongside a QR code.
class _BottomQrModal extends HookWidget {
const _BottomQrModal({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
useListenable(wallet);
return Container(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text('Tap your wallet app to connect'),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_WalletIconButton(
name: "Metamask",
logoId: "5195e9db-94d8-4579-6f11-ef553be95100",
makeUri: (uri) => "metamask://wc?uri=$uri",
),
_WalletIconButton(
name: "Rainbow",
logoId: "7a33d7f1-3d12-4b5c-f3ee-5cd83cb1b500",
makeUri: (uri) => "rainbow://wc?uri=$uri",
),
],
),
const SizedBox(height: 16),
const Text('Or scan to connect your wallet'),
IconButton(
tooltip: "QR Code",
padding: const EdgeInsets.all(0),
icon: QrImage(
data: wallet.displayUri,
version: QrVersions.auto,
// foregroundColor: Colors.deepPurple.shade900,
size: 200.0,
),
iconSize: 200,
onPressed: () =>
Clipboard.setData(ClipboardData(text: wallet.displayUri)),
),
const Text('Tap to copy to clipboard.'),
const SizedBox(height: 32),
],
),
);
}
}

// Create your WalletConnect project at https://cloud.walletconnect.com/
const String _wcProjectId = "af3346694438a7a937ee3aee9968e8fa";

String _wcLogo(logoId, {size = "md"}) =>
"https://explorer-api.walletconnect.com/v3/logo/$size/$logoId"
"?projectId=$_wcProjectId";

/// A button displaying a WalletConnect wallet that can be tapped to connect.
///
/// Find the wallets at https://explorer.walletconnect.com/?type=wallet
/// See also https://docs.walletconnect.com/2.0/cloud/explorer#logos
class _WalletIconButton extends HookWidget {
final String name;
final String logoId;
final String Function(String uri) makeUri;

const _WalletIconButton({
Key? key,
required this.name,
required this.logoId,
required this.makeUri,
}) : super(key: key);

@override
Widget build(BuildContext context) {
return IconButton(
tooltip: name,
iconSize: 100,
onPressed: () => launchUrl(
Uri.parse(makeUri(wallet.displayUri)),
mode: LaunchMode.externalNonBrowserApplication,
),
icon: Image.network(_wcLogo(logoId)),
);
}
}
Loading
Loading