diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5915794f..0f683cde 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 2.1.11
+
+- Fixed an issue with `generatedNamespaces` during session proposal
+- Small enhancements in example wallet/dapp.
+- Minor changes and bug fixe
+
## 2.1.10
- License change
diff --git a/README.md b/README.md
index cea39b26..665e5535 100644
--- a/README.md
+++ b/README.md
@@ -29,15 +29,17 @@ ConnectResponse resp = await wcClient.connect(
requiredNamespaces: {
'eip155': RequiredNamespace(
chains: ['eip155:1'], // Ethereum chain
- methods: ['eth_signTransaction'], // Requestable Methods
- events: ['eth_sendTransaction'], // Requestable Events
+ methods: ['personal_sign'], // Requestable Methods, see MethodsConstants for reference
+ events: ['chainChanged'], // Requestable Events, see EventsConstants for reference
),
- 'kadena': RequiredNamespace(
- chains: ['kadena:mainnet01'], // Kadena chain
- methods: ['kadena_quicksign_v1'], // Requestable Methods
- events: ['kadena_transaction_updated'], // Requestable Events
+ },
+ optionalNamespaces: {
+ 'eip155': RequiredNamespace(
+ chains: ['eip155:1', 'eip155:5'], // Any other optional Ethereum chain
+ methods: ['eth_signTransaction'], // Optional requestable Methods, see MethodsConstants for reference
+ events: ['accountsChanged'], // Optional requestable events, see EventsConstants for reference
),
- }
+ },
);
Uri? uri = resp.uri;
@@ -50,7 +52,7 @@ final dynamic signResponse = await wcClient.request(
chainId: 'eip155:1',
request: SessionRequestParams(
method: 'eth_signTransaction',
- params: 'json serializable parameters',
+ params: '{json serializable parameters}',
),
);
// Unpack, or use the signResponse.
@@ -85,13 +87,13 @@ else {
// You can also respond to events from the wallet, like session events
+wcClient.registerEventHandler(
+ chainId: 'eip155:1',
+ event: 'accountsChanged',
+);
wcClient.onSessionEvent.subscribe((SessionEvent? session) {
// Do something with the event
});
-wcClient.registerEventHandler(
- chainId: 'kadena',
- event: 'kadena_transaction_updated',
-);
```
### Wallet Flow
@@ -112,7 +114,15 @@ late int id;
wcClient.onSessionProposal.subscribe((SessionProposal? args) async {
// Handle UI updates using the args.params
// Keep track of the args.id for the approval response
- id = args!.id;
+ if (args != null) {
+ id = args!.id;
+ // To check VerifyAPI validation in regards of the dApp is trying to connnect you can check verifyContext
+ // More info about VerifyAPI https://docs.walletconnect.com/web3wallet/verify
+ final isScamApp = args.verifyContext?.validation.scam;
+ final isInvalidApp = args.verifyContext?.validation.invalid;
+ final isValidApp = args.verifyContext?.validation.valid;
+ final unknown = args.verifyContext?.validation.unknown;
+ }
});
// Also setup the methods and chains that your wallet supports
@@ -212,16 +222,13 @@ final walletNamespaces = {
'eip155': Namespace(
accounts: ['eip155:1:abc'],
methods: ['eth_signTransaction'],
- ),
- 'kadena': Namespace(
- accounts: ['kadena:mainnet01:abc'],
- methods: ['kadena_sign_v1', 'kadena_quicksign_v1'],
- events: ['kadena_transaction_updated'],
+ events: ['accountsChanged'],
),
}
await wcClient.approveSession(
id: id,
namespaces: walletNamespaces // This will have the accounts requested in params
+ // If you registered correctly events emitters, methods handlers and accounts for your supported chains you can just us `args.params.generatedNamespaces!` value from SessionProposalEvent
);
// Or to reject...
// Error codes and reasons can be found here: https://docs.walletconnect.com/2.0/specs/clients/sign/error-codes
@@ -246,7 +253,7 @@ await wcClient.respondAuthRequest(
// Error codes and reasons can be found here: https://docs.walletconnect.com/2.0/specs/clients/sign/error-codes
await wcClient.respondAuthRequest(
id: args.id,
- iss: 'did:pkh:eip155:1:0x06C6A22feB5f8CcEDA0db0D593e6F26A3611d5fa',
+ iss: 'did:pkh:eip155:1:ETH_ADDRESS',
error: Errors.getSdkError(Errors.USER_REJECTED_AUTH),
);
diff --git a/example/dapp/android/app/src/main/AndroidManifest.xml b/example/dapp/android/app/src/main/AndroidManifest.xml
index 577d92aa..27e113ac 100644
--- a/example/dapp/android/app/src/main/AndroidManifest.xml
+++ b/example/dapp/android/app/src/main/AndroidManifest.xml
@@ -23,6 +23,12 @@
+
+
+
+
+
+
diff --git a/example/dapp/ios/Runner/Info.plist b/example/dapp/ios/Runner/Info.plist
index 5109ec5f..909bdb52 100644
--- a/example/dapp/ios/Runner/Info.plist
+++ b/example/dapp/ios/Runner/Info.plist
@@ -49,5 +49,22 @@
LSApplicationCategoryType
+ CFBundleURLTypes
+
+
+ CFBundleTypeRole
+ Editor
+ CFBundleURLName
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleURLSchemes
+
+ myflutterdapp
+
+
+
+ LSApplicationQueriesSchemes
+
+ myflutterwallet
+
diff --git a/example/dapp/lib/main.dart b/example/dapp/lib/main.dart
index d238b565..4dd6f766 100644
--- a/example/dapp/lib/main.dart
+++ b/example/dapp/lib/main.dart
@@ -69,6 +69,10 @@ class _MyHomePageState extends State {
description: 'Flutter WalletConnect Dapp Example',
url: 'https://walletconnect.com/',
icons: ['https://walletconnect.com/walletconnect-logo.png'],
+ redirect: Redirect(
+ native: 'myflutterdapp://',
+ universal: 'https://walletconnect.com',
+ ),
),
);
@@ -83,6 +87,8 @@ class _MyHomePageState extends State {
// Register event handlers
_web3App!.onSessionPing.subscribe(_onSessionPing);
_web3App!.onSessionEvent.subscribe(_onSessionEvent);
+ _web3App!.core.relayClient.onRelayClientConnect.subscribe(_setState);
+ _web3App!.core.relayClient.onRelayClientDisconnect.subscribe(_setState);
setState(() {
_pageDatas = [
@@ -115,8 +121,12 @@ class _MyHomePageState extends State {
// }
}
+ void _setState(dynamic args) => setState(() {});
+
@override
void dispose() {
+ _web3App!.core.relayClient.onRelayClientConnect.unsubscribe(_setState);
+ _web3App!.core.relayClient.onRelayClientDisconnect.unsubscribe(_setState);
_web3App!.onSessionPing.unsubscribe(_onSessionPing);
_web3App!.onSessionEvent.unsubscribe(_onSessionEvent);
super.dispose();
@@ -146,20 +156,18 @@ class _MyHomePageState extends State {
right: StyleConstants.magic20,
child: Row(
children: [
- // Disconnect buttons for testing
- _buildIconButton(
- Icons.discord,
- () {
- _web3App!.core.relayClient.disconnect();
- },
- ),
- const SizedBox(
- width: StyleConstants.magic20,
- ),
- _buildIconButton(
- Icons.connect_without_contact,
- () {
- _web3App!.core.relayClient.connect();
+ Text(_web3App!.core.relayClient.isConnected
+ ? 'Relay Connected'
+ : 'Relay Disconnected'),
+ Switch(
+ value: _web3App!.core.relayClient.isConnected,
+ onChanged: (value) {
+ if (!value) {
+ _web3App!.core.relayClient.disconnect();
+ } else {
+ _web3App!.core.relayClient.connect();
+ }
+ setState(() {});
},
),
],
@@ -252,23 +260,4 @@ class _MyHomePageState extends State {
},
);
}
-
- Widget _buildIconButton(IconData icon, void Function()? onPressed) {
- return Container(
- decoration: BoxDecoration(
- color: StyleConstants.primaryColor,
- borderRadius: BorderRadius.circular(
- StyleConstants.linear48,
- ),
- ),
- child: IconButton(
- icon: Icon(
- icon,
- color: StyleConstants.titleTextColor,
- ),
- iconSize: StyleConstants.linear24,
- onPressed: onPressed,
- ),
- );
- }
}
diff --git a/example/dapp/lib/pages/connect_page.dart b/example/dapp/lib/pages/connect_page.dart
index e3f98110..e4bebdf7 100644
--- a/example/dapp/lib/pages/connect_page.dart
+++ b/example/dapp/lib/pages/connect_page.dart
@@ -8,7 +8,6 @@ import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
import 'package:walletconnect_flutter_v2_dapp/models/chain_metadata.dart';
import 'package:walletconnect_flutter_v2_dapp/utils/constants.dart';
import 'package:walletconnect_flutter_v2_dapp/utils/crypto/chain_data.dart';
-import 'package:walletconnect_flutter_v2_dapp/utils/crypto/helpers.dart';
import 'package:walletconnect_flutter_v2_dapp/utils/string_constants.dart';
import 'package:walletconnect_flutter_v2_dapp/widgets/chain_button.dart';
@@ -27,27 +26,19 @@ class ConnectPage extends StatefulWidget {
class ConnectPageState extends State {
bool _testnetOnly = false;
final List _selectedChains = [];
-
bool _shouldDismissQrCode = true;
- void setTestnet(bool value) {
- if (value != _testnetOnly) {
- _selectedChains.clear();
- }
- _testnetOnly = value;
- }
-
@override
Widget build(BuildContext context) {
// Build the list of chain buttons, clear if the textnet changed
final List chains =
_testnetOnly ? ChainData.testChains : ChainData.mainChains;
- List chainButtons = [];
+ List children = [];
for (final ChainMetadata chain in chains) {
// Build the button
- chainButtons.add(
+ children.add(
ChainButton(
chain: chain,
onPressed: () {
@@ -64,44 +55,46 @@ class ConnectPageState extends State {
);
}
+ children.add(const SizedBox.square(dimension: 12.0));
+
// Add a connect button
- chainButtons.add(
- Container(
- width: double.infinity,
- height: StyleConstants.linear48,
- margin: const EdgeInsets.symmetric(
- vertical: StyleConstants.linear8,
- ),
- child: ElevatedButton(
- onPressed: () => _onConnect(
- _selectedChains,
- showToast: (m) async {
- await showPlatformToast(child: Text(m), context: context);
+ children.add(
+ ElevatedButton(
+ onPressed: _selectedChains.isEmpty
+ ? null
+ : () => _onConnect(showToast: (m) async {
+ await showPlatformToast(child: Text(m), context: context);
+ }),
+ style: ButtonStyle(
+ backgroundColor: MaterialStateProperty.resolveWith(
+ (states) {
+ if (states.contains(MaterialState.disabled)) {
+ return StyleConstants.grayColor;
+ }
+ return StyleConstants.primaryColor;
},
),
- style: ButtonStyle(
- backgroundColor: MaterialStateProperty.all(
- StyleConstants.primaryColor,
- ),
- shape: MaterialStateProperty.all(
- RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(
- StyleConstants.linear8,
- ),
+ minimumSize: MaterialStateProperty.all(const Size(
+ 1000.0,
+ StyleConstants.linear48,
+ )),
+ shape: MaterialStateProperty.all(
+ RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(
+ StyleConstants.linear8,
),
),
),
- child: const Text(
- StringConstants.connect,
- style: StyleConstants.buttonText,
- ),
+ ),
+ child: const Text(
+ StringConstants.connect,
+ style: StyleConstants.buttonText,
),
),
);
return Center(
child: Container(
- // color: StyleConstants.primaryColor,
padding: const EdgeInsets.all(
StyleConstants.linear8,
),
@@ -110,16 +103,13 @@ class ConnectPageState extends State {
),
child: ListView(
children: [
- const SizedBox(
- height: StyleConstants.linear48,
- ),
const Text(
StringConstants.appTitle,
style: StyleConstants.titleText,
textAlign: TextAlign.center,
),
const SizedBox(
- height: StyleConstants.linear48,
+ height: StyleConstants.linear16,
),
const Text(
StringConstants.selectChains,
@@ -127,7 +117,7 @@ class ConnectPageState extends State {
textAlign: TextAlign.center,
),
const SizedBox(
- height: StyleConstants.linear24,
+ height: StyleConstants.linear16,
),
SizedBox(
height: StyleConstants.linear48,
@@ -142,6 +132,7 @@ class ConnectPageState extends State {
value: _testnetOnly,
onChanged: (value) {
setState(() {
+ _selectedChains.clear();
_testnetOnly = value;
});
},
@@ -152,7 +143,7 @@ class ConnectPageState extends State {
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
- children: chainButtons,
+ children: children,
),
],
),
@@ -160,43 +151,32 @@ class ConnectPageState extends State {
);
}
- Future _onConnect(
- List chains, {
- Function(String message)? showToast,
- }) async {
- // Use the chain metadata to build the required namespaces:
- // Get the methods, get the events
- final Map requiredNamespaces = {};
- for (final chain in chains) {
- // If the chain is already in the required namespaces, add it to the chains list
- final String chainName = chain.chainId.split(':')[0];
- if (requiredNamespaces.containsKey(chainName)) {
- requiredNamespaces[chainName]!.chains!.add(chain.chainId);
- continue;
- }
- final RequiredNamespace rNamespace = RequiredNamespace(
- chains: [chain.chainId],
- methods: getChainMethods(chain.type),
- events: getChainEvents(chain.type),
- );
- requiredNamespaces[chainName] = rNamespace;
- }
- debugPrint('Required namespaces: $requiredNamespaces');
-
- // Send off a connect
+ Future _onConnect({Function(String message)? showToast}) async {
debugPrint('Creating connection and session');
+ // It is currently safer to send chains approvals on optionalNamespaces
+ // but depending on Wallet implementation you may need to send some (for innstance eip155:1) as required
final ConnectResponse res = await widget.web3App.connect(
- optionalNamespaces: requiredNamespaces,
+ requiredNamespaces: {
+ 'eip155': const RequiredNamespace(
+ chains: [],
+ methods: MethodsConstants.requiredMethods,
+ events: EventsConstants.requiredEvents,
+ ),
+ },
+ optionalNamespaces: {
+ 'eip155': RequiredNamespace(
+ chains: _selectedChains.map((c) => c.chainId).toList(),
+ methods: MethodsConstants.optionalMethods,
+ events: EventsConstants.optionalEvents,
+ ),
+ },
);
- // debugPrint('Connection created, connection response: ${res.uri}');
- // print(res.uri!.toString());
_showQrCode(res);
try {
debugPrint('Awaiting session proposal settlement');
final _ = await res.session.future;
- // print(sessionData);
showToast?.call(StringConstants.connectionEstablished);
@@ -205,7 +185,7 @@ class ConnectPageState extends State {
final AuthRequestResponse authRes = await widget.web3App.requestAuth(
pairingTopic: res.pairingTopic,
params: AuthRequestParams(
- chainId: chains[0].chainId,
+ chainId: _selectedChains[0].chainId,
domain: Constants.domain,
aud: Constants.aud,
// statement: 'Welcome to example flutter app',
diff --git a/example/dapp/lib/utils/constants.dart b/example/dapp/lib/utils/constants.dart
index 954fb4d2..14612b24 100644
--- a/example/dapp/lib/utils/constants.dart
+++ b/example/dapp/lib/utils/constants.dart
@@ -27,7 +27,7 @@ class StyleConstants {
static const double magic10 = 10;
static const double magic14 = 14;
static const double magic20 = 20;
- static const double magic40 = 40;
+ static const double magic40 = 28;
static const double magic64 = 64;
// Width
diff --git a/example/dapp/lib/utils/crypto/chain_data.dart b/example/dapp/lib/utils/crypto/chain_data.dart
index 5b775089..301af08d 100644
--- a/example/dapp/lib/utils/crypto/chain_data.dart
+++ b/example/dapp/lib/utils/crypto/chain_data.dart
@@ -19,27 +19,22 @@ class ChainData {
color: Colors.purple.shade300,
rpc: ['https://polygon-rpc.com/'],
),
- // const ChainMetadata(
- // type: ChainType.solana,
- // chainId: 'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ',
- // name: 'Solana',
- // logo: 'TODO',
- // color: Colors.black,
- // rpc: [
- // "https://api.mainnet-beta.solana.com",
- // "https://solana-api.projectserum.com",
- // ],
- // ),
- // ChainMetadata(
- // type: ChainType.kadena,
- // chainId: 'kadena:mainnet01',
- // name: 'Kadena',
- // logo: 'TODO',
- // color: Colors.purple.shade600,
- // rpc: [
- // "https://api.testnet.chainweb.com",
- // ],
- // ),
+ const ChainMetadata(
+ type: ChainType.eip155,
+ chainId: 'eip155:42161',
+ name: 'Arbitrum',
+ logo: '/chain-logos/eip155-42161.png',
+ color: Colors.black,
+ rpc: ['https://arbitrum.blockpi.network/v1/rpc/public'],
+ ),
+ const ChainMetadata(
+ type: ChainType.eip155,
+ chainId: 'eip155:43114',
+ name: 'Avalanche',
+ logo: '/chain-logos/eip155-43114.png',
+ color: Colors.red,
+ rpc: ['https://api.avax.network/ext/bc/C/rpc'],
+ ),
];
static final List testChains = [
@@ -61,15 +56,6 @@ class ChainData {
isTestnet: true,
rpc: ['https://matic-mumbai.chainstacklabs.com'],
),
- // const ChainMetadata(
- // type: ChainType.eip155,
- // chainId: 'solana:8E9rvCKLFQia2Y35HXjjpWzj8weVo44K',
- // name: 'Solana Devnet',
- // logo: 'TODO',
- // color: Colors.black,
- // isTestnet: true,
- // rpc: ["https://api.devnet.solana.com"],
- // ),
ChainMetadata(
type: ChainType.kadena,
chainId: 'kadena:testnet04',
diff --git a/example/dapp/lib/utils/string_constants.dart b/example/dapp/lib/utils/string_constants.dart
index 4cec305a..0d0396f1 100644
--- a/example/dapp/lib/utils/string_constants.dart
+++ b/example/dapp/lib/utils/string_constants.dart
@@ -6,7 +6,7 @@ class StringConstants {
static const String delete = 'Delete';
// Main Page
- static const String appTitle = 'Wallet Connect v2 Flutter dApp Demo';
+ static const String appTitle = 'WalletConnect v2\nFlutter dApp Demo';
static const String connectPageTitle = 'Connect';
static const String pairingsPageTitle = 'Pairings';
static const String sessionsPageTitle = 'Sessions';
diff --git a/example/wallet/android/app/src/main/AndroidManifest.xml b/example/wallet/android/app/src/main/AndroidManifest.xml
index 636a1ade..63e1f074 100644
--- a/example/wallet/android/app/src/main/AndroidManifest.xml
+++ b/example/wallet/android/app/src/main/AndroidManifest.xml
@@ -23,6 +23,12 @@
+
+
+
+
+
+
diff --git a/example/wallet/ios/Podfile.lock b/example/wallet/ios/Podfile.lock
index db6c3de3..2a1d5c69 100644
--- a/example/wallet/ios/Podfile.lock
+++ b/example/wallet/ios/Podfile.lock
@@ -48,7 +48,7 @@ PODS:
- GTMSessionFetcher/Core (< 3.0, >= 1.1)
- MLImage (= 1.0.0-beta4)
- MLKitCommon (~> 9.0)
- - mobile_scanner (3.2.0):
+ - mobile_scanner (3.5.2):
- Flutter
- GoogleMLKit/BarcodeScanning (~> 4.0.0)
- nanopb (2.30909.0):
@@ -106,7 +106,7 @@ SPEC CHECKSUMS:
MLKitBarcodeScanning: 04e264482c5f3810cb89ebc134ef6b61e67db505
MLKitCommon: c1b791c3e667091918d91bda4bba69a91011e390
MLKitVision: 8baa5f46ee3352614169b85250574fde38c36f49
- mobile_scanner: 47056db0c04027ea5f41a716385542da28574662
+ mobile_scanner: 5090a13b7a35fc1c25b0d97e18e84f271a6eb605
nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431
package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef
diff --git a/example/wallet/ios/Runner/Info.plist b/example/wallet/ios/Runner/Info.plist
index 89968174..fe18a95e 100644
--- a/example/wallet/ios/Runner/Info.plist
+++ b/example/wallet/ios/Runner/Info.plist
@@ -49,5 +49,18 @@
UIViewControllerBasedStatusBarAppearance
+ CFBundleURLTypes
+
+
+ CFBundleTypeRole
+ Editor
+ CFBundleURLName
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleURLSchemes
+
+ myflutterwallet
+
+
+
diff --git a/example/wallet/lib/dependencies/chains/evm_service.dart b/example/wallet/lib/dependencies/chains/evm_service.dart
index 233ff47a..d42c4ad2 100644
--- a/example/wallet/lib/dependencies/chains/evm_service.dart
+++ b/example/wallet/lib/dependencies/chains/evm_service.dart
@@ -7,8 +7,6 @@ import 'dart:typed_data';
import 'package:convert/convert.dart';
import 'package:eth_sig_util/eth_sig_util.dart';
import 'package:get_it/get_it.dart';
-import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
-import 'package:walletconnect_flutter_v2_wallet/dependencies/chains/i_chain.dart';
import 'package:walletconnect_flutter_v2_wallet/dependencies/bottom_sheet/i_bottom_sheet_service.dart';
import 'package:walletconnect_flutter_v2_wallet/dependencies/i_web3wallet_service.dart';
import 'package:walletconnect_flutter_v2_wallet/dependencies/key_service/chain_key.dart';
@@ -20,107 +18,87 @@ import 'package:walletconnect_flutter_v2_wallet/widgets/wc_connection_widget/wc_
import 'package:walletconnect_flutter_v2_wallet/widgets/wc_request_widget.dart/wc_request_widget.dart';
import 'package:web3dart/web3dart.dart';
-enum EVMChainId {
+enum EVMChainsSupported {
ethereum,
polygon,
+ arbitrum,
goerli,
bsc,
- mumbai,
-}
+ mumbai;
-extension KadenaChainIdX on EVMChainId {
String chain() {
- String name = '';
+ String id = '';
switch (this) {
- case EVMChainId.ethereum:
- name = '1';
+ case EVMChainsSupported.ethereum:
+ id = '1';
+ break;
+ case EVMChainsSupported.polygon:
+ id = '137';
break;
- case EVMChainId.polygon:
- name = '137';
+ case EVMChainsSupported.arbitrum:
+ id = '42161';
break;
- case EVMChainId.goerli:
- name = '5';
+ case EVMChainsSupported.goerli:
+ id = '5';
break;
- case EVMChainId.bsc:
- name = '56';
+ case EVMChainsSupported.bsc:
+ id = '56';
break;
- case EVMChainId.mumbai:
- name = '80001';
+ case EVMChainsSupported.mumbai:
+ id = '80001';
break;
}
- return '${EVMService.namespace}:$name';
+ return 'eip155:$id';
}
}
-class EVMService extends IChain {
- static const namespace = 'eip155';
- static const pSign = 'personal_sign';
- static const eSign = 'eth_sign';
- static const eSignTransaction = 'eth_signTransaction';
- static const eSignTypedData = 'eth_signTypedData';
- static const eSendTransaction = 'eth_sendTransaction';
-
+class EVMService {
final IBottomSheetService _bottomSheetService =
GetIt.I();
final IWeb3WalletService _web3WalletService = GetIt.I();
- final EVMChainId reference;
+ final EVMChainsSupported chainSupported;
final Web3Client ethClient;
- EVMService({
- required this.reference,
- Web3Client? ethClient,
- }) : ethClient = ethClient ??
+ EVMService({required this.chainSupported, Web3Client? ethClient})
+ : ethClient = ethClient ??
Web3Client(
'https://mainnet.infura.io/v3/51716d2096df4e73bec298680a51f0c5',
http.Client()) {
- final Web3Wallet wallet = _web3WalletService.getWeb3Wallet();
- for (final String event in getEvents()) {
- wallet.registerEventEmitter(chainId: getChainId(), event: event);
+ final wallet = _web3WalletService.getWeb3Wallet();
+ // Supported events
+ final supportedEvents = [
+ 'chainChanged',
+ 'accountsChanged'
+ ]; // add whatever event you want to support
+ for (final String event in supportedEvents) {
+ print('Supported event ${chainSupported.chain()} $event');
+ wallet.registerEventEmitter(
+ chainId: chainSupported.chain(),
+ event: event,
+ );
+ }
+ // Supported methods
+ Map methodsHandlers = {
+ 'personal_sign': personalSign,
+ 'eth_sign': ethSign,
+ 'eth_signTransaction': ethSignTransaction,
+ 'eth_signTypedData': ethSignTypedData,
+ 'eth_sendTransaction': ethSignTransaction,
+ // add whatever method/handler you want to support
+ // 'eth_signTypedData_v4': ethSignTypedDataV4,
+ };
+
+ for (var handler in methodsHandlers.entries) {
+ wallet.registerRequestHandler(
+ chainId: chainSupported.chain(),
+ method: handler.key,
+ handler: handler.value,
+ );
}
- wallet.registerRequestHandler(
- chainId: getChainId(),
- method: pSign,
- handler: personalSign,
- );
- wallet.registerRequestHandler(
- chainId: getChainId(),
- method: eSign,
- handler: ethSign,
- );
- wallet.registerRequestHandler(
- chainId: getChainId(),
- method: eSignTransaction,
- handler: ethSignTransaction,
- );
- wallet.registerRequestHandler(
- chainId: getChainId(),
- method: eSendTransaction,
- handler: ethSignTransaction,
- );
- wallet.registerRequestHandler(
- chainId: getChainId(),
- method: eSignTypedData,
- handler: ethSignTypedData,
- );
- }
-
- @override
- String getNamespace() {
- return namespace;
- }
-
- @override
- String getChainId() {
- return reference.chain();
- }
-
- @override
- List getEvents() {
- return ['chainChanged', 'accountsChanged'];
}
Future requestAuthorization(String text) async {
@@ -128,11 +106,7 @@ class EVMService extends IChain {
widget: WCRequestWidget(
child: WCConnectionWidget(
title: 'Sign Transaction',
- info: [
- WCConnectionModel(
- text: text,
- ),
- ],
+ info: [WCConnectionModel(text: text)],
),
),
);
@@ -157,7 +131,7 @@ class EVMService extends IChain {
try {
// Load the private key
final List keys = GetIt.I().getKeysForChain(
- getChainId(),
+ chainSupported.chain(),
);
final Credentials credentials = EthPrivateKey.fromHex(keys[0].privateKey);
@@ -176,7 +150,7 @@ class EVMService extends IChain {
}
}
- Future ethSign(String topic, dynamic parameters) async {
+ Future ethSign(String topic, dynamic parameters) async {
print('received eth sign request: $parameters');
final String message = EthUtils.getUtf8Message(parameters[1]);
@@ -189,7 +163,7 @@ class EVMService extends IChain {
try {
// Load the private key
final List keys = GetIt.I().getKeysForChain(
- getChainId(),
+ chainSupported.chain(),
);
// print('private key');
// print(keys[0].privateKey);
@@ -220,7 +194,7 @@ class EVMService extends IChain {
}
}
- Future ethSignTransaction(String topic, dynamic parameters) async {
+ Future ethSignTransaction(String topic, dynamic parameters) async {
print('received eth sign transaction request: $parameters');
final String? authAcquired = await requestAuthorization(
jsonEncode(
@@ -233,7 +207,7 @@ class EVMService extends IChain {
// Load the private key
final List keys = GetIt.I().getKeysForChain(
- getChainId(),
+ chainSupported.chain(),
);
final Credentials credentials = EthPrivateKey.fromHex(
'0x${keys[0].privateKey}',
@@ -294,7 +268,7 @@ class EVMService extends IChain {
}
}
- Future ethSignTypedData(String topic, dynamic parameters) async {
+ Future ethSignTypedData(String topic, dynamic parameters) async {
print('received eth sign typed data request: $parameters');
final String data = parameters[1];
final String? authAcquired = await requestAuthorization(data);
@@ -303,7 +277,7 @@ class EVMService extends IChain {
}
final List keys = GetIt.I().getKeysForChain(
- getChainId(),
+ chainSupported.chain(),
);
// EthPrivateKey credentials = EthPrivateKey.fromHex(keys[0].privateKey);
diff --git a/example/wallet/lib/dependencies/chains/i_chain.dart b/example/wallet/lib/dependencies/chains/i_chain.dart
deleted file mode 100644
index f3a3e36b..00000000
--- a/example/wallet/lib/dependencies/chains/i_chain.dart
+++ /dev/null
@@ -1,5 +0,0 @@
-abstract class IChain {
- String getNamespace();
- String getChainId();
- List getEvents();
-}
diff --git a/example/wallet/lib/dependencies/key_service/key_service.dart b/example/wallet/lib/dependencies/key_service/key_service.dart
index dce0c503..0bea000b 100644
--- a/example/wallet/lib/dependencies/key_service/key_service.dart
+++ b/example/wallet/lib/dependencies/key_service/key_service.dart
@@ -1,3 +1,4 @@
+import 'package:walletconnect_flutter_v2_wallet/dependencies/chains/evm_service.dart';
import 'package:walletconnect_flutter_v2_wallet/dependencies/key_service/chain_key.dart';
import 'package:walletconnect_flutter_v2_wallet/dependencies/key_service/i_key_service.dart';
import 'package:walletconnect_flutter_v2_wallet/utils/dart_defines.dart';
@@ -14,13 +15,7 @@ class KeyService extends IKeyService {
publicKey: DartDefines.kadenaPublicKey,
),
ChainKey(
- chains: [
- 'eip155:1',
- 'eip155:5',
- 'eip155:56',
- 'eip155:137',
- 'eip155:80001',
- ],
+ chains: EVMChainsSupported.values.map((e) => e.chain()).toList(),
privateKey:
'300851edb635b2dbb2d4e70615444925afeb60bf95c19365aff88740e09d7345',
publicKey:
diff --git a/example/wallet/lib/dependencies/web3wallet_service.dart b/example/wallet/lib/dependencies/web3wallet_service.dart
index 8a570ae3..3cca879c 100644
--- a/example/wallet/lib/dependencies/web3wallet_service.dart
+++ b/example/wallet/lib/dependencies/web3wallet_service.dart
@@ -49,6 +49,10 @@ class Web3WalletService extends IWeb3WalletService {
icons: [
'https://github.com/WalletConnect/Web3ModalFlutter/blob/master/assets/png/logo_wc.png'
],
+ redirect: Redirect(
+ native: 'myflutterwallet://',
+ universal: 'https://walletconnect.com',
+ ),
),
);
diff --git a/example/wallet/lib/main.dart b/example/wallet/lib/main.dart
index 1e50c7f1..27f79c2d 100644
--- a/example/wallet/lib/main.dart
+++ b/example/wallet/lib/main.dart
@@ -2,9 +2,8 @@ import 'package:get_it/get_it.dart';
import 'package:get_it_mixin/get_it_mixin.dart';
import 'package:walletconnect_flutter_v2_wallet/dependencies/bottom_sheet/bottom_sheet_listener.dart';
import 'package:walletconnect_flutter_v2_wallet/dependencies/bottom_sheet/bottom_sheet_service.dart';
-import 'package:walletconnect_flutter_v2_wallet/dependencies/chains/evm_service.dart';
-import 'package:walletconnect_flutter_v2_wallet/dependencies/chains/i_chain.dart';
import 'package:walletconnect_flutter_v2_wallet/dependencies/bottom_sheet/i_bottom_sheet_service.dart';
+import 'package:walletconnect_flutter_v2_wallet/dependencies/chains/evm_service.dart';
import 'package:walletconnect_flutter_v2_wallet/dependencies/i_web3wallet_service.dart';
import 'package:walletconnect_flutter_v2_wallet/dependencies/key_service/i_key_service.dart';
import 'package:walletconnect_flutter_v2_wallet/dependencies/key_service/key_service.dart';
@@ -137,10 +136,10 @@ class _MyHomePageState extends State with GetItStateMixin {
// );
// }
- for (final cId in EVMChainId.values) {
- GetIt.I.registerSingleton(
- EVMService(reference: cId),
- instanceName: cId.chain(),
+ for (final supportedChain in EVMChainsSupported.values) {
+ GetIt.I.registerSingleton(
+ EVMService(chainSupported: supportedChain),
+ instanceName: supportedChain.chain(),
);
}
diff --git a/example/wallet/lib/utils/namespace_model_builder.dart b/example/wallet/lib/utils/namespace_model_builder.dart
index 28177e8e..890b3860 100644
--- a/example/wallet/lib/utils/namespace_model_builder.dart
+++ b/example/wallet/lib/utils/namespace_model_builder.dart
@@ -7,21 +7,21 @@ import 'package:walletconnect_flutter_v2_wallet/widgets/wc_connection_widget/wc_
class ConnectionWidgetBuilder {
static List buildFromRequiredNamespaces(
- Map requiredNamespaces,
+ Map generatedNamespaces,
) {
final List views = [];
- for (final key in requiredNamespaces.keys) {
- RequiredNamespace ns = requiredNamespaces[key]!;
+ for (final key in generatedNamespaces.keys) {
+ Namespace ns = generatedNamespaces[key]!;
final List models = [];
// If the chains property is present, add the chain data to the models
- if (ns.chains != null) {
- models.add(
- WCConnectionModel(
- title: StringConstants.chains,
- elements: ns.chains!,
- ),
- );
- }
+ models.add(
+ WCConnectionModel(
+ title: StringConstants.chains,
+ elements: ns.accounts.map((acc) {
+ return NamespaceUtils.getChainFromAccount(acc);
+ }).toList(),
+ ),
+ );
models.add(WCConnectionModel(
title: StringConstants.methods,
elements: ns.methods,
diff --git a/example/wallet/lib/widgets/wc_connection_request/wc_connection_request_widget.dart b/example/wallet/lib/widgets/wc_connection_request/wc_connection_request_widget.dart
index 690cee63..97957cf1 100644
--- a/example/wallet/lib/widgets/wc_connection_request/wc_connection_request_widget.dart
+++ b/example/wallet/lib/widgets/wc_connection_request/wc_connection_request_widget.dart
@@ -55,8 +55,8 @@ class WCConnectionRequestWidget extends StatelessWidget {
),
const SizedBox(height: StyleConstants.linear8),
authRequest != null
- ? _buildAuthRequest()
- : _buildSessionProposal(context),
+ ? _buildAuthRequestView()
+ : _buildSessionProposalView(context),
],
),
);
@@ -70,7 +70,7 @@ class WCConnectionRequestWidget extends StatelessWidget {
);
}
- Widget _buildAuthRequest() {
+ Widget _buildAuthRequestView() {
final model = WCConnectionModel(
text: wallet.formatAuthMessage(
iss: 'did:pkh:eip155:1:${authRequest!.iss}',
@@ -86,26 +86,16 @@ class WCConnectionRequestWidget extends StatelessWidget {
);
}
- Widget _buildSessionProposal(BuildContext context) {
+ Widget _buildSessionProposalView(BuildContext context) {
// Create the connection models using the required and optional namespaces provided by the proposal data
// The key is the title and the list of values is the data
- final List views =
- ConnectionWidgetBuilder.buildFromRequiredNamespaces(
- sessionProposal!.request.requiredNamespaces,
+ final views = ConnectionWidgetBuilder.buildFromRequiredNamespaces(
+ sessionProposal!.request.generatedNamespaces!,
);
return Column(
children: views,
);
- // return Expanded(
- // child: ListView.separated(
- // itemBuilder: (context, index) => views[index],
- // separatorBuilder: (context, index) => const SizedBox(
- // height: StyleConstants.linear8,
- // ),
- // itemCount: views.length,
- // ),
- // );
}
}
diff --git a/lib/apis/utils/constants.dart b/lib/apis/utils/constants.dart
index 739f3bd2..4ddb5b53 100644
--- a/lib/apis/utils/constants.dart
+++ b/lib/apis/utils/constants.dart
@@ -1,5 +1,5 @@
class WalletConnectConstants {
- static const SDK_VERSION = '2.1.10';
+ static const SDK_VERSION = '2.1.11';
static const CORE_PROTOCOL = 'wc';
static const CORE_VERSION = 2;
@@ -64,3 +64,47 @@ class StoreVersions {
static const CONTEXT_COMPLETE_REQUESTS = 'completeRequests';
static const VERSION_COMPLETE_REQUESTS = '2.1';
}
+
+class MethodsConstants {
+ static const walletSwitchEthChain = 'wallet_switchEthereumChain';
+ static const walletAddEthChain = 'wallet_addEthereumChain';
+ static const requiredMethods = [
+ 'eth_sendTransaction',
+ 'personal_sign',
+ ];
+ static const optionalMethods = [
+ 'eth_accounts',
+ 'eth_requestAccounts',
+ 'eth_sendRawTransaction',
+ 'eth_sign',
+ 'eth_signTransaction',
+ 'eth_signTypedData',
+ 'eth_signTypedData_v3',
+ 'eth_signTypedData_v4',
+ 'eth_sendTransaction',
+ 'personal_sign',
+ walletSwitchEthChain,
+ walletAddEthChain,
+ 'wallet_getPermissions',
+ 'wallet_requestPermissions',
+ 'wallet_registerOnboarding',
+ 'wallet_watchAsset',
+ 'wallet_scanQRCode',
+ ];
+ static const allMethods = [...requiredMethods, ...optionalMethods];
+}
+
+class EventsConstants {
+ static const chainChanged = 'chainChanged';
+ static const accountsChanged = 'accountsChanged';
+ static const requiredEvents = [
+ chainChanged,
+ accountsChanged,
+ ];
+ static const optionalEvents = [
+ 'message',
+ 'disconnect',
+ 'connect',
+ ];
+ static const allEvents = [...requiredEvents, ...optionalEvents];
+}
diff --git a/lib/apis/utils/namespace_utils.dart b/lib/apis/utils/namespace_utils.dart
index aee2d1da..9460c67e 100644
--- a/lib/apis/utils/namespace_utils.dart
+++ b/lib/apis/utils/namespace_utils.dart
@@ -312,9 +312,8 @@ class NamespaceUtils {
final List events = [];
final List methods = [];
final namespace = requiredNamespaces[namespaceOrChainId]!;
- if (NamespaceUtils.isValidChainId(namespaceOrChainId) ||
- namespace.chains == null ||
- namespace.chains!.isEmpty) {
+ final chains = namespace.chains ?? [];
+ if (NamespaceUtils.isValidChainId(namespaceOrChainId) || chains.isEmpty) {
// Add the chain specific availableAccounts
accounts.addAll(
_getMatching(
@@ -340,10 +339,6 @@ class NamespaceUtils {
),
);
} else {
- final List chains = namespace.chains!;
- // Add the namespace specific functions
- final List> chainMethodSets = [];
- final List> chainEventSets = [];
// Loop through all of the chains
for (final String chainId in chains) {
// Add the chain specific availableAccounts
@@ -354,7 +349,7 @@ class NamespaceUtils {
).map((e) => '$chainId:$e'),
);
// Add the chain specific events
- chainEventSets.add(
+ events.addAll(
_getMatching(
namespaceOrChainId: chainId,
available: availableEvents,
@@ -362,7 +357,7 @@ class NamespaceUtils {
),
);
// Add the chain specific methods
- chainMethodSets.add(
+ methods.addAll(
_getMatching(
namespaceOrChainId: chainId,
available: availableMethods,
@@ -370,18 +365,13 @@ class NamespaceUtils {
),
);
}
-
- methods.addAll(chainMethodSets.reduce((v, e) => v.intersection(e)));
- events.addAll(chainEventSets.reduce((v, e) => v.intersection(e)));
}
- // print(availableAccounts);
- // print(accounts);
// Add the namespace to the list
namespaces[namespaceOrChainId] = Namespace(
- accounts: accounts,
- events: events,
- methods: methods,
+ accounts: accounts.toSet().toList(),
+ events: events.toSet().toList(),
+ methods: methods.toSet().toList(),
);
}
diff --git a/lib/src/version.dart b/lib/src/version.dart
index 71ae6bf6..f1c02a75 100644
--- a/lib/src/version.dart
+++ b/lib/src/version.dart
@@ -1,2 +1,2 @@
// Generated code. Do not modify.
-const packageVersion = '2.1.10';
+const packageVersion = '2.1.11';
diff --git a/pubspec.yaml b/pubspec.yaml
index 184f8f84..c0889c94 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
name: walletconnect_flutter_v2
description: This repository contains oficial implementation of WalletConnect v2 protocols for Flutter applications. The communications protocol for web3.
-version: 2.1.10
+version: 2.1.11
repository: https://github.com/WalletConnect/WalletConnectFlutterV2
environment:
diff --git a/test/shared/namespace_utils_test.dart b/test/shared/namespace_utils_test.dart
index 0fa7141e..ba767e89 100644
--- a/test/shared/namespace_utils_test.dart
+++ b/test/shared/namespace_utils_test.dart
@@ -312,6 +312,39 @@ void main() {
);
});
+ test('constructs namespaces with required and optional namespaces', () {
+ Map namespaces = NamespaceUtils.constructNamespaces(
+ availableAccounts: availableAccounts3,
+ availableMethods: availableMethods3,
+ availableEvents: availableEvents3,
+ requiredNamespaces: requiredNamespacesInAvailable3,
+ optionalNamespaces: optionalNamespacesInAvailable3,
+ );
+
+ expect(namespaces.length, 1);
+ expect(
+ namespaces['eip155']!.accounts,
+ availableAccounts3.toList(),
+ );
+ expect(
+ namespaces['eip155']!.methods,
+ availableMethods3.map((m) => m.split(':').last).toList(),
+ );
+ expect(
+ namespaces['eip155']!.events,
+ availableEvents3.map((m) => m.split(':').last).toList(),
+ );
+
+ expect(
+ SignApiValidatorUtils.isConformingNamespaces(
+ requiredNamespaces: requiredNamespacesInAvailable3,
+ namespaces: namespaces,
+ context: '',
+ ),
+ true,
+ );
+ });
+
test('constructNamespaces trims off unrequested', () {
final reqNamespace = {
'eip155': const RequiredNamespace(
@@ -449,7 +482,7 @@ void main() {
Errors.getSdkError(
Errors.UNSUPPORTED_METHODS,
context:
- " namespaces methods don't satisfy requiredNamespaces methods for namespace2. Requested: [method3, method4], Supported: [method3]",
+ " namespaces methods don't satisfy requiredNamespaces methods for namespace1:chain1. Requested: [method1, method2, method3], Supported: [method1, method2]",
).message,
Errors.getSdkError(
Errors.UNSUPPORTED_EVENTS,
@@ -459,13 +492,12 @@ void main() {
Errors.getSdkError(
Errors.UNSUPPORTED_EVENTS,
context:
- " namespaces events don't satisfy requiredNamespaces events for namespace2. Requested: [event3, event4], Supported: [event3]",
+ " namespaces events don't satisfy requiredNamespaces events for namespace1:chain1. Requested: [event1, event2, event3], Supported: [event1, event2]",
).message,
];
for (int i = 0; i < nonconforming.length; i++) {
- Map namespaces =
- NamespaceUtils.constructNamespaces(
+ final namespaces = NamespaceUtils.constructNamespaces(
availableAccounts: availableAccounts,
availableMethods: availableMethods,
availableEvents: availableEvents,
diff --git a/test/shared/shared_test_values.dart b/test/shared/shared_test_values.dart
index 616594bd..67bcfcc1 100644
--- a/test/shared/shared_test_values.dart
+++ b/test/shared/shared_test_values.dart
@@ -135,7 +135,7 @@ final Map requiredNamespacesNonconformingMethods1 = {
final Map requiredNamespacesNonconformingMethods2 = {
'namespace1:chain1': const RequiredNamespace(
- methods: ['method1', 'method2'],
+ methods: ['method1', 'method2', 'method3'],
events: ['event1', 'event2'],
),
'namespace2': const RequiredNamespace(
@@ -160,7 +160,7 @@ final Map requiredNamespacesNonconformingEvents1 = {
final Map requiredNamespacesNonconformingEvents2 = {
'namespace1:chain1': const RequiredNamespace(
methods: ['method1', 'method2'],
- events: ['event1', 'event2'],
+ events: ['event1', 'event2', 'event3'],
),
'namespace2': const RequiredNamespace(
chains: ['namespace2:chain1', 'namespace2:chain2'],
@@ -175,3 +175,61 @@ Map optionalNamespaces = {
events: ['event5', 'event2'],
),
};
+
+const sepolia = 'eip155:11155111';
+
+final Set availableAccounts3 = {
+ '$sepolia:0x99999999999999999999999999',
+};
+
+final Set availableMethods3 = {
+ '$sepolia:eth_sendTransaction',
+ '$sepolia:personal_sign',
+ '$sepolia:eth_signTypedData',
+ '$sepolia:eth_signTypedData_v4',
+ '$sepolia:eth_sign',
+};
+
+final Set availableEvents3 = {
+ '$sepolia:chainChanged',
+ '$sepolia:accountsChanged',
+};
+
+final Map requiredNamespacesInAvailable3 = {
+ 'eip155': const RequiredNamespace(
+ chains: [sepolia],
+ methods: ['eth_sendTransaction', 'personal_sign'],
+ events: ['chainChanged', 'accountsChanged'],
+ ),
+};
+
+final Map optionalNamespacesInAvailable3 = {
+ 'eip155': const RequiredNamespace(chains: [
+ 'eip155:1',
+ 'eip155:5',
+ sepolia,
+ 'eip155:137',
+ 'eip155:80001',
+ 'eip155:42220',
+ 'eip155:44787',
+ 'eip155:56',
+ 'eip155:43114',
+ 'eip155:42161',
+ 'eip155:421613',
+ 'eip155:10',
+ 'eip155:420',
+ 'eip155:8453'
+ ], methods: [
+ 'eth_sendTransaction',
+ 'personal_sign',
+ 'eth_signTypedData',
+ 'eth_signTypedData_v4',
+ 'eth_sign'
+ ], events: [
+ 'chainChanged',
+ 'accountsChanged',
+ 'message',
+ 'disconnect',
+ 'connect'
+ ]),
+};