From ef2bea511d8883d20b19b89debc3a6c5a36fdad0 Mon Sep 17 00:00:00 2001 From: Alfreedom <00tango.bromine@icloud.com> Date: Tue, 20 Feb 2024 12:47:48 +0100 Subject: [PATCH 1/7] fix _onSessionRequest logic in sign_engine so wallet can use either methods handlers or onSessionRequest event --- .../lib/dependencies/chains/evm_service.dart | 74 +++++++++------- .../lib/dependencies/web3wallet_service.dart | 3 + .../lib/utils/namespace_model_builder.dart | 31 ++++--- .../wallet/lib/utils/string_constants.dart | 1 + lib/apis/core/relay_client/relay_client.dart | 2 +- lib/apis/sign_api/sign_engine.dart | 88 ++++++++----------- 6 files changed, 99 insertions(+), 100 deletions(-) diff --git a/example/wallet/lib/dependencies/chains/evm_service.dart b/example/wallet/lib/dependencies/chains/evm_service.dart index a97f83b9..1124fa39 100644 --- a/example/wallet/lib/dependencies/chains/evm_service.dart +++ b/example/wallet/lib/dependencies/chains/evm_service.dart @@ -27,50 +27,60 @@ class EVMService { final ChainMetadata chainSupported; late final Web3Client ethClient; + Map get sessionRequestHandlers => { + 'personal_sign': personalSign, + }; + + Map get methodRequestHandlers => { + 'eth_sign': ethSign, + 'eth_signTransaction': ethSignTransaction, + 'eth_sendTransaction': ethSendTransaction, + 'eth_signTypedData': ethSignTypedData, + 'eth_signTypedData_v4': ethSignTypedDataV4, + 'wallet_switchEthereumChain': switchChain, + 'wallet_addEthereumChain': addChain, + }; + EVMService({required this.chainSupported}) { final supportedId = chainSupported.chainId; final chainMetadata = ChainData.allChains.firstWhere( (c) => c.chainId == supportedId, ); - debugPrint('supportedId $supportedId - ${chainMetadata.rpc.first}'); ethClient = Web3Client(chainMetadata.rpc.first, http.Client()); const supportedEvents = EventsConstants.requiredEvents; - for (final String event in supportedEvents) { - debugPrint('Supported event ${chainSupported.chainId} $event'); + for (final event in supportedEvents) { _web3Wallet.registerEventEmitter( chainId: chainSupported.chainId, event: event, ); } - // Supported methods - Map methodsHandlers = { - 'personal_sign': personalSign, - 'eth_sign': ethSign, - 'eth_signTransaction': ethSignTransaction, - 'eth_sendTransaction': ethSendTransaction, - 'eth_signTypedData': ethSignTypedData, - 'eth_signTypedData_v4': ethSignTypedDataV4, - 'wallet_switchEthereumChain': switchChain, - 'wallet_addEthereumChain': addChain, - // add whatever method/handler you want to support - }; - - for (var handler in methodsHandlers.entries) { + for (var handler in methodRequestHandlers.entries) { _web3Wallet.registerRequestHandler( chainId: chainSupported.chainId, method: handler.key, handler: handler.value, ); } + + _web3Wallet.onSessionRequest.subscribe(_onSessionRequest); + } + + void _onSessionRequest(SessionRequestEvent? args) async { + if (args != null && args.chainId == chainSupported.chainId) { + debugPrint('[$runtimeType] onSessionRequest $args'); + final handler = sessionRequestHandlers[args.method]; + if (handler != null) { + await handler(args.topic, args.params); + } + } } + // personal_sign is handled using onSessionRequest event for demo purposes Future personalSign(String topic, dynamic parameters) async { debugPrint('[$runtimeType] personalSign request: $parameters'); - // message, address - - final pRequest = _web3Wallet.pendingRequests.getAll().first; + final pRequest = _web3Wallet.pendingRequests.getAll().last; final data = EthUtils.getDataFromParamsList(parameters); final message = EthUtils.getUtf8Message(data.toString()); var response = JsonRpcResponse( @@ -115,9 +125,7 @@ class EVMService { Future ethSign(String topic, dynamic parameters) async { debugPrint('[$runtimeType] ethSign request: $parameters'); - // address, message - - final pRequest = _web3Wallet.pendingRequests.getAll().first; + final pRequest = _web3Wallet.pendingRequests.getAll().last; final data = EthUtils.getDataFromParamsList(parameters); final message = EthUtils.getUtf8Message(data.toString()); var response = JsonRpcResponse( @@ -162,13 +170,13 @@ class EVMService { Future ethSignTypedData(String topic, dynamic parameters) async { debugPrint('[$runtimeType] ethSignTypedData request: $parameters'); - - final pRequest = _web3Wallet.pendingRequests.getAll().first; + final pRequest = _web3Wallet.pendingRequests.getAll().last; final data = EthUtils.getDataFromParamsList(parameters); var response = JsonRpcResponse( id: pRequest.id, jsonrpc: '2.0', ); + if (await requestApproval(data)) { try { final keys = GetIt.I().getKeysForChain( @@ -203,13 +211,13 @@ class EVMService { Future ethSignTypedDataV4(String topic, dynamic parameters) async { debugPrint('[$runtimeType] ethSignTypedDataV4 request: $parameters'); - - final pRequest = _web3Wallet.pendingRequests.getAll().first; + final pRequest = _web3Wallet.pendingRequests.getAll().last; final data = EthUtils.getDataFromParamsList(parameters); var response = JsonRpcResponse( id: pRequest.id, jsonrpc: '2.0', ); + if (await requestApproval(data)) { try { final keys = GetIt.I().getKeysForChain( @@ -244,14 +252,14 @@ class EVMService { Future ethSignTransaction(String topic, dynamic parameters) async { debugPrint('[$runtimeType] ethSignTransaction request: $parameters'); - final pRequest = _web3Wallet.pendingRequests.getAll().first; + final pRequest = _web3Wallet.pendingRequests.getAll().last; + final data = EthUtils.getTransactionFromParams(parameters); + if (data == null) return; var response = JsonRpcResponse( id: pRequest.id, jsonrpc: '2.0', ); - final data = EthUtils.getTransactionFromParams(parameters); - if (data == null) return; final result = await approveTransaction(data); if (result is Transaction) { try { @@ -297,14 +305,14 @@ class EVMService { Future ethSendTransaction(String topic, dynamic parameters) async { debugPrint('[$runtimeType] ethSendTransaction request: $parameters'); - final pRequest = _web3Wallet.pendingRequests.getAll().first; + final pRequest = _web3Wallet.pendingRequests.getAll().last; + final data = EthUtils.getTransactionFromParams(parameters); + if (data == null) return; var response = JsonRpcResponse( id: pRequest.id, jsonrpc: '2.0', ); - final data = EthUtils.getTransactionFromParams(parameters); - if (data == null) return; final result = await approveTransaction(data); if (result is Transaction) { try { diff --git a/example/wallet/lib/dependencies/web3wallet_service.dart b/example/wallet/lib/dependencies/web3wallet_service.dart index 2a7c897a..322ae2f6 100644 --- a/example/wallet/lib/dependencies/web3wallet_service.dart +++ b/example/wallet/lib/dependencies/web3wallet_service.dart @@ -167,6 +167,9 @@ class Web3WalletService extends IWeb3WalletService { void _onSessionProposal(SessionProposalEvent? args) async { if (args != null) { + final accounts = args.params.generatedNamespaces?['eip155']?.accounts; + final allChains = NamespaceUtils.getChainsFromAccounts(accounts ?? []); + debugPrint('[$runtimeType] _onSessionProposal chains: $allChains'); final approved = await _bottomSheetHandler.queueBottomSheet( widget: WCRequestWidget( child: WCConnectionRequestWidget( diff --git a/example/wallet/lib/utils/namespace_model_builder.dart b/example/wallet/lib/utils/namespace_model_builder.dart index 798015e9..8bc4e1c0 100644 --- a/example/wallet/lib/utils/namespace_model_builder.dart +++ b/example/wallet/lib/utils/namespace_model_builder.dart @@ -11,25 +11,28 @@ class ConnectionWidgetBuilder { ) { final List views = []; for (final key in generatedNamespaces.keys) { - Namespace ns = generatedNamespaces[key]!; + final namespaces = generatedNamespaces[key]!; + final chains = NamespaceUtils.getChainsFromAccounts(namespaces.accounts); final List models = []; // If the chains property is present, add the chain data to the models models.add( WCConnectionModel( title: StringConstants.chains, - elements: ns.accounts.map((acc) { - return NamespaceUtils.getChainFromAccount(acc); - }).toList(), + elements: chains, + ), + ); + models.add( + WCConnectionModel( + title: StringConstants.methods, + elements: namespaces.methods, + ), + ); + models.add( + WCConnectionModel( + title: StringConstants.events, + elements: namespaces.events, ), ); - models.add(WCConnectionModel( - title: StringConstants.methods, - elements: ns.methods, - )); - models.add(WCConnectionModel( - title: StringConstants.events, - elements: ns.events, - )); views.add( WCConnectionWidget( @@ -48,12 +51,12 @@ class ConnectionWidgetBuilder { ) { final List views = []; for (final key in namespaces.keys) { - final Namespace ns = namespaces[key]!; + final ns = namespaces[key]!; final List models = []; // If the chains property is present, add the chain data to the models models.add( WCConnectionModel( - title: StringConstants.chains, + title: StringConstants.accounts, elements: ns.accounts, ), ); diff --git a/example/wallet/lib/utils/string_constants.dart b/example/wallet/lib/utils/string_constants.dart index 9c8d2725..9b9198ee 100644 --- a/example/wallet/lib/utils/string_constants.dart +++ b/example/wallet/lib/utils/string_constants.dart @@ -28,6 +28,7 @@ class StringConstants { // Session Proposal static const String chains = 'Chains'; + static const String accounts = 'Accounts'; static const String methods = 'Methods'; static const String events = 'Events'; diff --git a/lib/apis/core/relay_client/relay_client.dart b/lib/apis/core/relay_client/relay_client.dart index f806f908..8e482da8 100644 --- a/lib/apis/core/relay_client/relay_client.dart +++ b/lib/apis/core/relay_client/relay_client.dart @@ -236,7 +236,7 @@ class RelayClient implements IRelayClient { Future _createJsonRPCProvider() async { _connecting = true; _active = true; - var auth = await core.crypto.signJWT(core.relayUrl); + final auth = await core.crypto.signJWT(core.relayUrl); core.logger.t('Signed JWT: $auth'); try { final url = WalletConnectUtils.formatRelayRpcUrl( diff --git a/lib/apis/sign_api/sign_engine.dart b/lib/apis/sign_api/sign_engine.dart index 417e2784..5d78bf29 100644 --- a/lib/apis/sign_api/sign_engine.dart +++ b/lib/apis/sign_api/sign_engine.dart @@ -1273,64 +1273,48 @@ class SignEngine implements ISignEngine { sessionRequest, ); - final String methodKey = _getRegisterKey( + final methodKey = _getRegisterKey( request.chainId, request.request.method, ); - // print('method key: $methodKey'); - if (_methodHandlers.containsKey(methodKey)) { - final handler = _methodHandlers[methodKey]; - if (handler != null) { - try { - final result = await handler( - topic, - request.request.params, - ); - await core.pairing.sendResult( - payload.id, - topic, - MethodConstants.WC_SESSION_REQUEST, - result, - ); - } on WalletConnectError catch (e) { - await core.pairing.sendError( - payload.id, - topic, - payload.method, - JsonRpcError.fromJson( - e.toJson(), - ), - ); - } on WalletConnectErrorSilent catch (_) { - // Do nothing on silent error - } catch (err) { - await core.pairing.sendError( - payload.id, - topic, - payload.method, - JsonRpcError.invalidParams( - err.toString(), - ), - ); - } - await _deletePendingRequest(payload.id); + // else, we send an onSessionRequest event + onSessionRequest.broadcast( + SessionRequestEvent.fromSessionRequest( + sessionRequest, + ), + ); + + final methodHandler = _methodHandlers[methodKey]; + if (methodHandler != null) { + // If a method handler has been set using registerRequestHandler we use it to process the request + try { + final result = await methodHandler(topic, request.request.params); + await core.pairing.sendResult( + payload.id, + topic, + MethodConstants.WC_SESSION_REQUEST, + result, + ); + } on WalletConnectError catch (e) { + await core.pairing.sendError( + payload.id, + topic, + payload.method, + JsonRpcError.fromJson(e.toJson()), + ); + } on WalletConnectErrorSilent catch (_) { + // Do nothing on silent error + } catch (err) { + await core.pairing.sendError( + payload.id, + topic, + payload.method, + JsonRpcError.invalidParams(err.toString()), + ); } - onSessionRequest.broadcast( - SessionRequestEvent.fromSessionRequest( - sessionRequest, - ), - ); - } else { - await core.pairing.sendError( - payload.id, - topic, - payload.method, - JsonRpcError.methodNotFound( - 'No handler found for chainId:method -> $methodKey', - ), - ); + await _deletePendingRequest(payload.id); } } on WalletConnectError catch (err) { await core.pairing.sendError( From 34e7d99b7047981141de472d5891883a10cecc1a Mon Sep 17 00:00:00 2001 From: Alfreedom <00tango.bromine@icloud.com> Date: Tue, 20 Feb 2024 12:58:54 +0100 Subject: [PATCH 2/7] minor change --- lib/apis/sign_api/sign_engine.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/apis/sign_api/sign_engine.dart b/lib/apis/sign_api/sign_engine.dart index 5d78bf29..56f80f50 100644 --- a/lib/apis/sign_api/sign_engine.dart +++ b/lib/apis/sign_api/sign_engine.dart @@ -1278,7 +1278,8 @@ class SignEngine implements ISignEngine { request.request.method, ); - // else, we send an onSessionRequest event + // We send onSessionRequest event on every session request, + // the developer can decide wether to use it or just register method handlers onSessionRequest.broadcast( SessionRequestEvent.fromSessionRequest( sessionRequest, @@ -1286,8 +1287,8 @@ class SignEngine implements ISignEngine { ); final methodHandler = _methodHandlers[methodKey]; + // If a method handler has been set using registerRequestHandler we use it to process the request if (methodHandler != null) { - // If a method handler has been set using registerRequestHandler we use it to process the request try { final result = await methodHandler(topic, request.request.params); await core.pairing.sendResult( From 696e8a8c7d56695a11f79c7f732e0eeb7be9a514 Mon Sep 17 00:00:00 2001 From: Alfreedom <00tango.bromine@icloud.com> Date: Tue, 20 Feb 2024 14:01:22 +0100 Subject: [PATCH 3/7] minor change --- lib/apis/sign_api/sign_engine.dart | 89 +++++++++++++++++------------- 1 file changed, 52 insertions(+), 37 deletions(-) diff --git a/lib/apis/sign_api/sign_engine.dart b/lib/apis/sign_api/sign_engine.dart index 56f80f50..417e2784 100644 --- a/lib/apis/sign_api/sign_engine.dart +++ b/lib/apis/sign_api/sign_engine.dart @@ -1273,49 +1273,64 @@ class SignEngine implements ISignEngine { sessionRequest, ); - final methodKey = _getRegisterKey( + final String methodKey = _getRegisterKey( request.chainId, request.request.method, ); + // print('method key: $methodKey'); + if (_methodHandlers.containsKey(methodKey)) { + final handler = _methodHandlers[methodKey]; + if (handler != null) { + try { + final result = await handler( + topic, + request.request.params, + ); + await core.pairing.sendResult( + payload.id, + topic, + MethodConstants.WC_SESSION_REQUEST, + result, + ); + } on WalletConnectError catch (e) { + await core.pairing.sendError( + payload.id, + topic, + payload.method, + JsonRpcError.fromJson( + e.toJson(), + ), + ); + } on WalletConnectErrorSilent catch (_) { + // Do nothing on silent error + } catch (err) { + await core.pairing.sendError( + payload.id, + topic, + payload.method, + JsonRpcError.invalidParams( + err.toString(), + ), + ); + } - // We send onSessionRequest event on every session request, - // the developer can decide wether to use it or just register method handlers - onSessionRequest.broadcast( - SessionRequestEvent.fromSessionRequest( - sessionRequest, - ), - ); - - final methodHandler = _methodHandlers[methodKey]; - // If a method handler has been set using registerRequestHandler we use it to process the request - if (methodHandler != null) { - try { - final result = await methodHandler(topic, request.request.params); - await core.pairing.sendResult( - payload.id, - topic, - MethodConstants.WC_SESSION_REQUEST, - result, - ); - } on WalletConnectError catch (e) { - await core.pairing.sendError( - payload.id, - topic, - payload.method, - JsonRpcError.fromJson(e.toJson()), - ); - } on WalletConnectErrorSilent catch (_) { - // Do nothing on silent error - } catch (err) { - await core.pairing.sendError( - payload.id, - topic, - payload.method, - JsonRpcError.invalidParams(err.toString()), - ); + await _deletePendingRequest(payload.id); } - await _deletePendingRequest(payload.id); + onSessionRequest.broadcast( + SessionRequestEvent.fromSessionRequest( + sessionRequest, + ), + ); + } else { + await core.pairing.sendError( + payload.id, + topic, + payload.method, + JsonRpcError.methodNotFound( + 'No handler found for chainId:method -> $methodKey', + ), + ); } } on WalletConnectError catch (err) { await core.pairing.sendError( From 08a32618f76b4dd5ed4c0772ce6bf48b752db64f Mon Sep 17 00:00:00 2001 From: Alfreedom <00tango.bromine@icloud.com> Date: Wed, 21 Feb 2024 10:10:37 +0100 Subject: [PATCH 4/7] Change on bundleId so it doesn't fail due to origin --- test/auth_api/auth_client_test.dart | 2 +- test/core_api/core_test.dart | 2 +- test/core_api/pairing_store_test.dart | 2 +- test/core_api/pairing_test.dart | 2 +- test/core_api/relay_auth_test.dart | 2 +- test/core_api/relay_client_test.dart | 2 +- test/sign_api/sign_client_test.dart | 2 +- test/sign_api/sign_engine_test.dart | 2 +- test/sign_api/web3wallet_sign_test.dart | 2 +- test/web3wallet/web3wallet_test.dart | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/test/auth_api/auth_client_test.dart b/test/auth_api/auth_client_test.dart index c3752eaf..2333782d 100644 --- a/test/auth_api/auth_client_test.dart +++ b/test/auth_api/auth_client_test.dart @@ -20,7 +20,7 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); PackageInfo.setMockInitialValues( appName: 'walletconnect_flutter_v2', - packageName: 'sdk.test', + packageName: 'com.walletconnect.flutterdapp', version: '1.0', buildNumber: '2', buildSignature: 'buildSignature', diff --git a/test/core_api/core_test.dart b/test/core_api/core_test.dart index 00f72721..5f155f82 100644 --- a/test/core_api/core_test.dart +++ b/test/core_api/core_test.dart @@ -11,7 +11,7 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); PackageInfo.setMockInitialValues( appName: 'walletconnect_flutter_v2', - packageName: 'sdk.test', + packageName: 'com.walletconnect.flutterdapp', version: '1.0', buildNumber: '2', buildSignature: 'buildSignature', diff --git a/test/core_api/pairing_store_test.dart b/test/core_api/pairing_store_test.dart index c0e615f7..62f6d670 100644 --- a/test/core_api/pairing_store_test.dart +++ b/test/core_api/pairing_store_test.dart @@ -20,7 +20,7 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); PackageInfo.setMockInitialValues( appName: 'walletconnect_flutter_v2', - packageName: 'sdk.test', + packageName: 'com.walletconnect.flutterdapp', version: '1.0', buildNumber: '2', buildSignature: 'buildSignature', diff --git a/test/core_api/pairing_test.dart b/test/core_api/pairing_test.dart index 41322129..d67990ca 100644 --- a/test/core_api/pairing_test.dart +++ b/test/core_api/pairing_test.dart @@ -20,7 +20,7 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); PackageInfo.setMockInitialValues( appName: 'walletconnect_flutter_v2', - packageName: 'sdk.test', + packageName: 'com.walletconnect.flutterdapp', version: '1.0', buildNumber: '2', buildSignature: 'buildSignature', diff --git a/test/core_api/relay_auth_test.dart b/test/core_api/relay_auth_test.dart index 3812e30c..ed0fe89b 100644 --- a/test/core_api/relay_auth_test.dart +++ b/test/core_api/relay_auth_test.dart @@ -11,7 +11,7 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); PackageInfo.setMockInitialValues( appName: 'walletconnect_flutter_v2', - packageName: 'sdk.test', + packageName: 'com.walletconnect.flutterdapp', version: '1.0', buildNumber: '2', buildSignature: 'buildSignature', diff --git a/test/core_api/relay_client_test.dart b/test/core_api/relay_client_test.dart index 666a9386..d8cc8446 100644 --- a/test/core_api/relay_client_test.dart +++ b/test/core_api/relay_client_test.dart @@ -15,7 +15,7 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); PackageInfo.setMockInitialValues( appName: 'walletconnect_flutter_v2', - packageName: 'sdk.test', + packageName: 'com.walletconnect.flutterdapp', version: '1.0', buildNumber: '2', buildSignature: 'buildSignature', diff --git a/test/sign_api/sign_client_test.dart b/test/sign_api/sign_client_test.dart index d22eadd8..ced4babc 100644 --- a/test/sign_api/sign_client_test.dart +++ b/test/sign_api/sign_client_test.dart @@ -13,7 +13,7 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); PackageInfo.setMockInitialValues( appName: 'walletconnect_flutter_v2', - packageName: 'sdk.test', + packageName: 'com.walletconnect.flutterdapp', version: '1.0', buildNumber: '2', buildSignature: 'buildSignature', diff --git a/test/sign_api/sign_engine_test.dart b/test/sign_api/sign_engine_test.dart index aee94147..99e3c707 100644 --- a/test/sign_api/sign_engine_test.dart +++ b/test/sign_api/sign_engine_test.dart @@ -12,7 +12,7 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); PackageInfo.setMockInitialValues( appName: 'walletconnect_flutter_v2', - packageName: 'sdk.test', + packageName: 'com.walletconnect.flutterdapp', version: '1.0', buildNumber: '2', buildSignature: 'buildSignature', diff --git a/test/sign_api/web3wallet_sign_test.dart b/test/sign_api/web3wallet_sign_test.dart index 8d1b70fc..04f689b3 100644 --- a/test/sign_api/web3wallet_sign_test.dart +++ b/test/sign_api/web3wallet_sign_test.dart @@ -10,7 +10,7 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); PackageInfo.setMockInitialValues( appName: 'walletconnect_flutter_v2', - packageName: 'sdk.test', + packageName: 'com.walletconnect.flutterdapp', version: '1.0', buildNumber: '2', buildSignature: 'buildSignature', diff --git a/test/web3wallet/web3wallet_test.dart b/test/web3wallet/web3wallet_test.dart index 960be7eb..7893abfc 100644 --- a/test/web3wallet/web3wallet_test.dart +++ b/test/web3wallet/web3wallet_test.dart @@ -12,7 +12,7 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); PackageInfo.setMockInitialValues( appName: 'walletconnect_flutter_v2', - packageName: 'sdk.test', + packageName: 'com.walletconnect.flutterdapp', version: '1.0', buildNumber: '2', buildSignature: 'buildSignature', From 2f17835f193eab2cf322f7723a2023145b54eaeb Mon Sep 17 00:00:00 2001 From: Alfreedom <00tango.bromine@icloud.com> Date: Thu, 22 Feb 2024 10:58:59 +0100 Subject: [PATCH 5/7] Change on Sign Engine on how methods handlers vs session requests events are handled --- example/dapp/lib/utils/crypto/eip155.dart | 12 +- example/dapp/lib/widgets/session_widget.dart | 32 +++-- .../lib/dependencies/chains/evm_service.dart | 11 +- .../lib/dependencies/web3wallet_service.dart | 38 ++++-- lib/apis/core/verify/verify.dart | 6 + lib/apis/sign_api/sign_engine.dart | 88 +++++-------- .../tests/sign_request_and_handler.dart | 120 ++++++++++-------- 7 files changed, 165 insertions(+), 142 deletions(-) diff --git a/example/dapp/lib/utils/crypto/eip155.dart b/example/dapp/lib/utils/crypto/eip155.dart index 8fbf05d8..2205db83 100644 --- a/example/dapp/lib/utils/crypto/eip155.dart +++ b/example/dapp/lib/utils/crypto/eip155.dart @@ -66,7 +66,7 @@ class EIP155 { topic: topic, chainId: chainData.chainId, address: address, - data: testSignData, + message: testSignData, ); case EIP155Methods.ethSign: return ethSign( @@ -74,7 +74,7 @@ class EIP155 { topic: topic, chainId: chainData.chainId, address: address, - data: testSignData, + message: testSignData, ); case EIP155Methods.ethSignTypedData: return ethSignTypedData( @@ -159,14 +159,14 @@ class EIP155 { required String topic, required String chainId, required String address, - required String data, + required String message, }) async { return await web3App.request( topic: topic, chainId: chainId, request: SessionRequestParams( method: methods[EIP155Methods.personalSign]!, - params: [data, address], + params: [message, address], ), ); } @@ -176,14 +176,14 @@ class EIP155 { required String topic, required String chainId, required String address, - required String data, + required String message, }) async { return await web3App.request( topic: topic, chainId: chainId, request: SessionRequestParams( method: methods[EIP155Methods.ethSign]!, - params: [address, data], + params: [address, message], ), ); } diff --git a/example/dapp/lib/widgets/session_widget.dart b/example/dapp/lib/widgets/session_widget.dart index 56d99bb4..b98c32ee 100644 --- a/example/dapp/lib/widgets/session_widget.dart +++ b/example/dapp/lib/widgets/session_widget.dart @@ -167,6 +167,8 @@ class SessionWidgetState extends State { final List buttons = []; // Add Methods for (final String method in getChainMethods(chainMetadata.type)) { + final namespaces = widget.session.namespaces[chainMetadata.type.name]; + final supported = namespaces?.methods.contains(method) ?? false; buttons.add( Container( width: double.infinity, @@ -175,20 +177,24 @@ class SessionWidgetState extends State { vertical: StyleConstants.linear8, ), child: ElevatedButton( - onPressed: () async { - final future = EIP155.callMethod( - web3App: widget.web3App, - topic: widget.session.topic, - method: method.toEip155Method()!, - chainData: chainMetadata, - address: address.toLowerCase(), - ); - MethodDialog.show(context, method, future); - _launchWallet(); - }, + onPressed: supported + ? () async { + final future = EIP155.callMethod( + web3App: widget.web3App, + topic: widget.session.topic, + method: method.toEip155Method()!, + chainData: chainMetadata, + address: address.toLowerCase(), + ); + MethodDialog.show(context, method, future); + _launchWallet(); + } + : null, style: ButtonStyle( - backgroundColor: MaterialStateProperty.all( - chainMetadata.color, + backgroundColor: MaterialStateProperty.resolveWith( + (states) => states.contains(MaterialState.disabled) + ? Colors.grey + : chainMetadata.color, ), shape: MaterialStateProperty.all( RoundedRectangleBorder( diff --git a/example/wallet/lib/dependencies/chains/evm_service.dart b/example/wallet/lib/dependencies/chains/evm_service.dart index 1124fa39..b62b9631 100644 --- a/example/wallet/lib/dependencies/chains/evm_service.dart +++ b/example/wallet/lib/dependencies/chains/evm_service.dart @@ -48,8 +48,7 @@ class EVMService { ); ethClient = Web3Client(chainMetadata.rpc.first, http.Client()); - const supportedEvents = EventsConstants.requiredEvents; - for (final event in supportedEvents) { + for (final event in EventsConstants.requiredEvents) { _web3Wallet.registerEventEmitter( chainId: chainSupported.chainId, event: event, @@ -68,8 +67,8 @@ class EVMService { } void _onSessionRequest(SessionRequestEvent? args) async { - if (args != null && args.chainId == chainSupported.chainId) { - debugPrint('[$runtimeType] onSessionRequest $args'); + if (args?.chainId == chainSupported.chainId) { + debugPrint('[$runtimeType] onSessionRequest ${args!}'); final handler = sessionRequestHandlers[args.method]; if (handler != null) { await handler(args.topic, args.params); @@ -250,7 +249,7 @@ class EVMService { ); } - Future ethSignTransaction(String topic, dynamic parameters) async { + Future ethSignTransaction(String topic, dynamic parameters) async { debugPrint('[$runtimeType] ethSignTransaction request: $parameters'); final pRequest = _web3Wallet.pendingRequests.getAll().last; final data = EthUtils.getTransactionFromParams(parameters); @@ -303,7 +302,7 @@ class EVMService { ); } - Future ethSendTransaction(String topic, dynamic parameters) async { + Future ethSendTransaction(String topic, dynamic parameters) async { debugPrint('[$runtimeType] ethSendTransaction request: $parameters'); final pRequest = _web3Wallet.pendingRequests.getAll().last; final data = EthUtils.getTransactionFromParams(parameters); diff --git a/example/wallet/lib/dependencies/web3wallet_service.dart b/example/wallet/lib/dependencies/web3wallet_service.dart index 322ae2f6..f14fa2e5 100644 --- a/example/wallet/lib/dependencies/web3wallet_service.dart +++ b/example/wallet/lib/dependencies/web3wallet_service.dart @@ -10,6 +10,7 @@ import 'package:walletconnect_flutter_v2_wallet/dependencies/deep_link_handler.d import 'package:walletconnect_flutter_v2_wallet/dependencies/i_web3wallet_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/models/chain_metadata.dart'; import 'package:walletconnect_flutter_v2_wallet/utils/constants.dart'; import 'package:walletconnect_flutter_v2_wallet/utils/dart_defines.dart'; import 'package:walletconnect_flutter_v2_wallet/widgets/wc_connection_request/wc_auth_request_model.dart'; @@ -165,17 +166,38 @@ class Web3WalletService extends IWeb3WalletService { } } + Map _generateNamespaces( + Map? approvedNamespaces, + ChainType chainType, + ) { + // + final constructedNS = Map.from(approvedNamespaces ?? {}); + constructedNS[chainType.name] = constructedNS[chainType.name]!.copyWith( + methods: [ + 'personal_sign', + ...constructedNS[chainType.name]!.methods, + ], + ); + return constructedNS; + } + void _onSessionProposal(SessionProposalEvent? args) async { if (args != null) { - final accounts = args.params.generatedNamespaces?['eip155']?.accounts; - final allChains = NamespaceUtils.getChainsFromAccounts(accounts ?? []); - debugPrint('[$runtimeType] _onSessionProposal chains: $allChains'); + // generatedNamespaces is constructed based on registered methods handlers + // so if you want to handle requests using onSessionRequest event then you would need to manually add that method in the approved namespaces + final approvedNS = _generateNamespaces( + args.params.generatedNamespaces!, + ChainType.eip155, + ); + final proposalData = args.params.copyWith( + generatedNamespaces: approvedNS, + ); final approved = await _bottomSheetHandler.queueBottomSheet( widget: WCRequestWidget( child: WCConnectionRequestWidget( wallet: _web3Wallet!, sessionProposal: WCSessionRequestModel( - request: args.params, + request: proposalData, verifyContext: args.verifyContext, ), ), @@ -185,7 +207,7 @@ class Web3WalletService extends IWeb3WalletService { if (approved == true) { _web3Wallet!.approveSession( id: args.id, - namespaces: args.params.generatedNamespaces!, + namespaces: approvedNS, ); final scheme = args.params.proposer.metadata.redirect?.native ?? ''; DeepLinkHandler.goTo(scheme, delay: 300); @@ -220,11 +242,9 @@ class Web3WalletService extends IWeb3WalletService { Future _onAuthRequest(AuthRequest? args) async { if (args != null) { - List chainKeys = GetIt.I().getKeysForChain( - 'eip155:1', - ); + final chainKeys = GetIt.I().getKeysForChain('eip155:1'); // Create the message to be signed - final String iss = 'did:pkh:eip155:1:${chainKeys.first.address}'; + final iss = 'did:pkh:eip155:1:${chainKeys.first.address}'; final bool? auth = await _bottomSheetHandler.queueBottomSheet( widget: WCRequestWidget( diff --git a/lib/apis/core/verify/verify.dart b/lib/apis/core/verify/verify.dart index 269ce8b4..0538c4de 100644 --- a/lib/apis/core/verify/verify.dart +++ b/lib/apis/core/verify/verify.dart @@ -62,6 +62,12 @@ class Verify implements IVerify { final error = 'Attestation response error: ${response.statusCode}'; throw Exception(error); } + if (response.body.isEmpty) { + throw AttestationNotFound( + code: 404, + message: 'Attestion for this dapp could not be found', + ); + } return AttestationResponse.fromJson(jsonDecode(response.body)); } diff --git a/lib/apis/sign_api/sign_engine.dart b/lib/apis/sign_api/sign_engine.dart index 417e2784..49085640 100644 --- a/lib/apis/sign_api/sign_engine.dart +++ b/lib/apis/sign_api/sign_engine.dart @@ -267,9 +267,9 @@ class SignEngine implements ISignEngine { peerPubKey, ); // print('approve session topic: $sessionTopic'); - final relay = Relay( - relayProtocol ?? 'irn', - ); + final protocol = + relayProtocol ?? WalletConnectConstants.RELAYER_DEFAULT_PROTOCOL; + final relay = Relay(protocol); // Respond to the proposal await core.pairing.sendResult( @@ -277,9 +277,7 @@ class SignEngine implements ISignEngine { proposal.pairingTopic, MethodConstants.WC_SESSION_PROPOSE, WcSessionProposeResponse( - relay: Relay( - relayProtocol ?? WalletConnectConstants.RELAYER_DEFAULT_PROTOCOL, - ), + relay: relay, responderPublicKey: selfPubKey, ), ); @@ -1273,64 +1271,46 @@ class SignEngine implements ISignEngine { sessionRequest, ); - final String methodKey = _getRegisterKey( + final methodKey = _getRegisterKey( request.chainId, request.request.method, ); - // print('method key: $methodKey'); - if (_methodHandlers.containsKey(methodKey)) { - final handler = _methodHandlers[methodKey]; - if (handler != null) { - try { - final result = await handler( - topic, - request.request.params, - ); - await core.pairing.sendResult( - payload.id, - topic, - MethodConstants.WC_SESSION_REQUEST, - result, - ); - } on WalletConnectError catch (e) { - await core.pairing.sendError( - payload.id, - topic, - payload.method, - JsonRpcError.fromJson( - e.toJson(), - ), - ); - } on WalletConnectErrorSilent catch (_) { - // Do nothing on silent error - } catch (err) { - await core.pairing.sendError( - payload.id, - topic, - payload.method, - JsonRpcError.invalidParams( - err.toString(), - ), - ); - } - + final handler = _methodHandlers[methodKey]; + // If a method handler has been set using registerRequestHandler we use it to process the request + if (handler != null) { + try { + await handler(topic, request.request.params); + } on WalletConnectError catch (e) { + await core.pairing.sendError( + payload.id, + topic, + payload.method, + JsonRpcError.fromJson( + e.toJson(), + ), + ); + await _deletePendingRequest(payload.id); + } on WalletConnectErrorSilent catch (_) { + // Do nothing on silent error + await _deletePendingRequest(payload.id); + } catch (err) { + await core.pairing.sendError( + payload.id, + topic, + payload.method, + JsonRpcError.invalidParams( + err.toString(), + ), + ); await _deletePendingRequest(payload.id); } - + } else { + // Otherwise we send onSessionRequest event onSessionRequest.broadcast( SessionRequestEvent.fromSessionRequest( sessionRequest, ), ); - } else { - await core.pairing.sendError( - payload.id, - topic, - payload.method, - JsonRpcError.methodNotFound( - 'No handler found for chainId:method -> $methodKey', - ), - ); } } on WalletConnectError catch (err) { await core.pairing.sendError( diff --git a/test/sign_api/tests/sign_request_and_handler.dart b/test/sign_api/tests/sign_request_and_handler.dart index 47ddf5ed..bac8720d 100644 --- a/test/sign_api/tests/sign_request_and_handler.dart +++ b/test/sign_api/tests/sign_request_and_handler.dart @@ -83,8 +83,14 @@ void signRequestAndHandler({ // expect(request, TEST_MESSAGE_1); // print(clientB.getPendingSessionRequests()); expect(clientB.getPendingSessionRequests().length, 1); - - return request; + final pRequest = clientB.pendingRequests.getAll().last; + return await clientB.respondSessionRequest( + topic: sessionTopic, + response: JsonRpcResponse( + id: pRequest.id, + result: request, + ), + ); }; clientB.registerRequestHandler( chainId: TEST_ETHEREUM_CHAIN, @@ -150,15 +156,22 @@ void signRequestAndHandler({ String topic, dynamic request, ) async { - if (request is String) { - if (request == TEST_MESSAGE_2) { - throw Errors.getSdkError(Errors.USER_REJECTED_SIGN); - } else { - throw WalletConnectErrorSilent(); - } - } else { - return request['try']!; + expect(topic, sessionTopic); + expect(clientB.getPendingSessionRequests().length, 1); + if (request == 'silent') { + throw WalletConnectErrorSilent(); } + final pRequest = clientB.pendingRequests.getAll().last; + late dynamic error = (request is String) + ? Errors.getSdkError(Errors.USER_REJECTED_SIGN) + : JsonRpcError.invalidParams('swag'); + return await clientB.respondSessionRequest( + topic: sessionTopic, + response: JsonRpcResponse( + id: pRequest.id, + error: JsonRpcError(code: error.code, message: error.message), + ), + ); }; clientB.registerRequestHandler( chainId: TEST_ETHEREUM_CHAIN, @@ -168,14 +181,14 @@ void signRequestAndHandler({ try { // print('silent error'); - clientA.request( - topic: connectionInfo.session.topic, - chainId: TEST_ETHEREUM_CHAIN, - request: const SessionRequestParams( - method: TEST_METHOD_1, - params: 'silent', - ), - ); + // clientA.request( + // topic: connectionInfo.session.topic, + // chainId: TEST_ETHEREUM_CHAIN, + // request: const SessionRequestParams( + // method: TEST_METHOD_1, + // params: 'silent', + // ), + // ); // print('user rejected sign'); await clientA.request( @@ -200,8 +213,20 @@ void signRequestAndHandler({ ); } + Completer pendingRequestCompleter = Completer(); + clientB.pendingRequests.onSync.subscribe((_) { + if (clientB.getPendingSessionRequests().isEmpty) { + pendingRequestCompleter.complete(); + } + }); + if (!pendingRequestCompleter.isCompleted) { + clientA.core.logger.i('waiting pendingRequestCompleter'); + await pendingRequestCompleter.future; + } + clientB.pendingRequests.onSync.unsubscribeAll(); + try { - final _ = await clientA.request( + await clientA.request( topic: connectionInfo.session.topic, chainId: TEST_ETHEREUM_CHAIN, request: const SessionRequestParams( @@ -218,31 +243,18 @@ void signRequestAndHandler({ ); } - Completer pendingRequestCompleter = Completer(); - Completer sessionRequestCompleter = Completer(); + pendingRequestCompleter = Completer(); clientB.pendingRequests.onSync.subscribe((_) { if (clientB.getPendingSessionRequests().isEmpty) { pendingRequestCompleter.complete(); } }); - clientB.onSessionRequest.subscribe((args) { - sessionRequestCompleter.complete(); - sessionRequestCompleter = Completer(); - }); - if (!pendingRequestCompleter.isCompleted) { clientA.core.logger.i('waiting pendingRequestCompleter'); await pendingRequestCompleter.future; } - if (!sessionRequestCompleter.isCompleted) { - clientA.core.logger.i('waiting sessionRequestComplete'); - await sessionRequestCompleter.future; - } clientB.pendingRequests.onSync.unsubscribeAll(); - clientB.onSessionRequest.unsubscribeAll(); - expect(clientB.getPendingSessionRequests().length, 0); - /// Event driven, null handler /// clientB.registerRequestHandler( chainId: TEST_ETHEREUM_CHAIN, method: TEST_METHOD_1, @@ -252,31 +264,31 @@ void signRequestAndHandler({ method: TEST_METHOD_2, ); clientB.onSessionRequest.subscribe(( - SessionRequestEvent? request, + SessionRequestEvent? event, ) async { - expect(request != null, true); - expect(request!.topic, sessionTopic); - expect(request.params, TEST_MESSAGE_1); + expect(event != null, true); + expect(event!.topic, sessionTopic); + expect(event.params, TEST_MESSAGE_1); - if (request.method == TEST_METHOD_1) { - expect(clientB.pendingRequests.has(request.id.toString()), true); + if (event.method == TEST_METHOD_1) { + expect(clientB.pendingRequests.has(event.id.toString()), true); expect(clientB.getPendingSessionRequests().length, 1); await clientB.respondSessionRequest( - topic: request.topic, + topic: event.topic, response: JsonRpcResponse>( - id: request.id, + id: event.id, result: TEST_MESSAGE_1, ), ); - expect(clientB.pendingRequests.has(request.id.toString()), false); - } else if (request.method == TEST_METHOD_2) { + expect(clientB.pendingRequests.has(event.id.toString()), false); + } else if (event.method == TEST_METHOD_2) { await clientB.respondSessionRequest( - topic: request.topic, + topic: event.topic, response: JsonRpcResponse( - id: request.id, - error: JsonRpcError.invalidParams(request.params.toString()), + id: event.id, + error: JsonRpcError.invalidParams(event.params.toString()), ), ); } @@ -316,23 +328,23 @@ void signRequestAndHandler({ // Try an error clientB.onSessionRequest.unsubscribeAll(); clientB.onSessionRequest.subscribe(( - SessionRequestEvent? session, + SessionRequestEvent? event, ) async { - expect(session != null, true); - expect(session!.topic, sessionTopic); - expect(session.params, TEST_MESSAGE_1); + expect(event != null, true); + expect(event!.topic, sessionTopic); + expect(event.params, TEST_MESSAGE_1); - expect(clientB.pendingRequests.has(session.id.toString()), true); + expect(clientB.pendingRequests.has(event.id.toString()), true); await clientB.respondSessionRequest( - topic: session.topic, + topic: event.topic, response: JsonRpcResponse( - id: session.id, + id: event.id, error: JsonRpcError.invalidParams('invalid'), ), ); - expect(clientB.pendingRequests.has(session.id.toString()), false); + expect(clientB.pendingRequests.has(event.id.toString()), false); }); try { From de43eb76210ff873f1666894e8c15ef8ddc564b0 Mon Sep 17 00:00:00 2001 From: Alfreedom <00tango.bromine@icloud.com> Date: Thu, 22 Feb 2024 13:03:22 +0100 Subject: [PATCH 6/7] minor changes in error handling --- test/sign_api/tests/sign_request_and_handler.dart | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/test/sign_api/tests/sign_request_and_handler.dart b/test/sign_api/tests/sign_request_and_handler.dart index bac8720d..fdb64969 100644 --- a/test/sign_api/tests/sign_request_and_handler.dart +++ b/test/sign_api/tests/sign_request_and_handler.dart @@ -180,16 +180,6 @@ void signRequestAndHandler({ ); try { - // print('silent error'); - // clientA.request( - // topic: connectionInfo.session.topic, - // chainId: TEST_ETHEREUM_CHAIN, - // request: const SessionRequestParams( - // method: TEST_METHOD_1, - // params: 'silent', - // ), - // ); - // print('user rejected sign'); await clientA.request( topic: connectionInfo.session.topic, From ed45b49935bd5704d3ff2c9f6ba69e3cbd2dd498 Mon Sep 17 00:00:00 2001 From: Alfreedom <00tango.bromine@icloud.com> Date: Thu, 22 Feb 2024 13:11:14 +0100 Subject: [PATCH 7/7] changed version and entry changelog --- CHANGELOG.md | 4 ++++ lib/src/version.dart | 2 +- pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cce13f2..c293ad07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.2.1 + +- [Wallet] Fixed and issue where Sign Engine was not properly deciding between using a registered request handler or emitting an onSessionRequest event. + ## 2.2.0 - Added Smart Contract interactions to SignEngine diff --git a/lib/src/version.dart b/lib/src/version.dart index 3f25c8a6..5022a538 100644 --- a/lib/src/version.dart +++ b/lib/src/version.dart @@ -1,2 +1,2 @@ // Generated code. Do not modify. -const packageVersion = '2.2.0'; +const packageVersion = '2.2.1'; diff --git a/pubspec.yaml b/pubspec.yaml index f19fafc4..8e4ec9f8 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.2.0 +version: 2.2.1 repository: https://github.com/WalletConnect/WalletConnectFlutterV2 environment: