diff --git a/example/lib/main.dart b/example/lib/main.dart index c217f08..677b891 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -41,8 +41,7 @@ class MyHomePage extends StatefulWidget { _MyHomePageState createState() => _MyHomePageState(); } -const rpcUri = - 'https://rpc-mainnet.maticvigil.com/v1/140d92ff81094f0f3d7babde06603390d7e581be'; +const rpcUri = 'https://rpc-mainnet.maticvigil.com/v1/140d92ff81094f0f3d7babde06603390d7e581be'; enum MenuItems { PREVIOUS_SESSION, @@ -208,8 +207,7 @@ class _MyHomePageState extends State { ], ), body: InAppWebView( - initialUrlRequest: - URLRequest(url: Uri.parse('https://example.walletconnect.org')), + initialUrlRequest: URLRequest(url: Uri.parse('https://example.walletconnect.org')), initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( useShouldOverrideUrlLoading: true, @@ -222,8 +220,7 @@ class _MyHomePageState extends State { final url = navAction.request.url.toString(); debugPrint('URL $url'); if (url.contains('wc?uri=')) { - final wcUri = Uri.parse( - Uri.decodeFull(Uri.parse(url).queryParameters['uri']!)); + final wcUri = Uri.parse(Uri.decodeFull(Uri.parse(url).queryParameters['uri']!)); _qrScanHandler(wcUri.toString()); return NavigationActionPolicy.CANCEL; } else if (url.startsWith('wc:')) { @@ -245,9 +242,7 @@ class _MyHomePageState extends State { name: "Example Wallet", url: "https://example.wallet", description: "Example Wallet", - icons: [ - "https://gblobscdn.gitbook.com/spaces%2F-LJJeCjcLrr53DcT1Ml7%2Favatar.png" - ], + icons: ["https://gblobscdn.gitbook.com/spaces%2F-LJJeCjcLrr53DcT1Ml7%2Favatar.png"], ); _wcClient.connectNewSession(session: session, peerMeta: peerMeta); } @@ -256,9 +251,7 @@ class _MyHomePageState extends State { _connectToPreviousSession() { final _sessionSaved = _prefs.getString('session'); debugPrint('_sessionSaved $_sessionSaved'); - _sessionStore = _sessionSaved != null - ? WCSessionStore.fromJson(jsonDecode(_sessionSaved)) - : null; + _sessionStore = _sessionSaved != null ? WCSessionStore.fromJson(jsonDecode(_sessionSaved)) : null; if (_sessionStore != null) { debugPrint('_sessionStore $_sessionStore'); _wcClient.connectFromSessionStore(_sessionStore!); @@ -275,7 +268,7 @@ class _MyHomePageState extends State { }); } - _onSwitchNetwork(int id, int chainId) async { + _onSwitchNetwork(String id, int chainId) async { await _wcClient.updateSession(chainId: chainId); _wcClient.approveRequest(id: id, result: null); ScaffoldMessenger.of(context).showSnackBar(SnackBar( @@ -283,7 +276,7 @@ class _MyHomePageState extends State { )); } - _onSessionRequest(int id, WCPeerMeta peerMeta) { + _onSessionRequest(String id, WCPeerMeta peerMeta) { showDialog( context: context, builder: (_) => SessionRequestView( @@ -294,8 +287,7 @@ class _MyHomePageState extends State { chainId: chainId, ); _sessionStore = _wcClient.sessionStore; - await _prefs.setString( - 'session', jsonEncode(_wcClient.sessionStore.toJson())); + await _prefs.setString('session', jsonEncode(_wcClient.sessionStore.toJson())); Navigator.pop(context); }, onReject: () { @@ -383,7 +375,7 @@ class _MyHomePageState extends State { } _onSignTransaction( - int id, + String id, WCEthereumTransaction ethereumTransaction, ) { _onTransaction( @@ -411,7 +403,7 @@ class _MyHomePageState extends State { } _onSendTransaction( - int id, + String id, WCEthereumTransaction ethereumTransaction, ) { _onTransaction( @@ -440,7 +432,7 @@ class _MyHomePageState extends State { } _onTransaction({ - required int id, + required String id, required WCEthereumTransaction ethereumTransaction, required String title, required VoidCallback onConfirm, @@ -552,8 +544,7 @@ class _MyHomePageState extends State { ), ), Theme( - data: - Theme.of(context).copyWith(dividerColor: Colors.transparent), + data: Theme.of(context).copyWith(dividerColor: Colors.transparent), child: Padding( padding: const EdgeInsets.only(bottom: 8.0), child: ExpansionTile( @@ -606,7 +597,7 @@ class _MyHomePageState extends State { } _onSign( - int id, + String id, WCEthereumSignMessage ethereumSignMessage, ) { showDialog( @@ -645,8 +636,7 @@ class _MyHomePageState extends State { ), ), Theme( - data: - Theme.of(context).copyWith(dividerColor: Colors.transparent), + data: Theme.of(context).copyWith(dividerColor: Colors.transparent), child: Padding( padding: const EdgeInsets.only(bottom: 8.0), child: ExpansionTile( @@ -677,8 +667,7 @@ class _MyHomePageState extends State { ), onPressed: () async { String signedDataHex; - if (ethereumSignMessage.type == - WCSignType.TYPED_MESSAGE) { + if (ethereumSignMessage.type == WCSignType.TYPED_MESSAGE) { signedDataHex = EthSigUtil.signTypedData( privateKey: privateKey, jsonData: ethereumSignMessage.data!, @@ -686,10 +675,8 @@ class _MyHomePageState extends State { ); } else { final creds = EthPrivateKey.fromHex(privateKey); - final encodedMessage = - hexToBytes(ethereumSignMessage.data!); - final signedData = - await creds.signPersonalMessage(encodedMessage); + final encodedMessage = hexToBytes(ethereumSignMessage.data!); + final signedData = await creds.signPersonalMessage(encodedMessage); signedDataHex = bytesToHex(signedData, include0x: true); } debugPrint('SIGNED $signedDataHex'); @@ -728,17 +715,11 @@ class _MyHomePageState extends State { return Transaction( from: EthereumAddress.fromHex(ethereumTransaction.from), to: EthereumAddress.fromHex(ethereumTransaction.to!), - maxGas: ethereumTransaction.gasLimit != null - ? int.tryParse(ethereumTransaction.gasLimit!) - : null, - gasPrice: ethereumTransaction.gasPrice != null - ? EtherAmount.inWei(BigInt.parse(ethereumTransaction.gasPrice!)) - : null, + maxGas: ethereumTransaction.gasLimit != null ? int.tryParse(ethereumTransaction.gasLimit!) : null, + gasPrice: ethereumTransaction.gasPrice != null ? EtherAmount.inWei(BigInt.parse(ethereumTransaction.gasPrice!)) : null, value: EtherAmount.inWei(BigInt.parse(ethereumTransaction.value ?? '0')), data: hexToBytes(ethereumTransaction.data!), - nonce: ethereumTransaction.nonce != null - ? int.tryParse(ethereumTransaction.nonce!) - : null, + nonce: ethereumTransaction.nonce != null ? int.tryParse(ethereumTransaction.nonce!) : null, ); } } diff --git a/lib/models/exception/exceptions.dart b/lib/models/exception/exceptions.dart index a4076d5..0a45577 100644 --- a/lib/models/exception/exceptions.dart +++ b/lib/models/exception/exceptions.dart @@ -7,11 +7,10 @@ class HmacException implements Exception { } class InvalidJsonRpcParamsException implements Exception { - final int requestId; + final String requestId; final String message; - InvalidJsonRpcParamsException(this.requestId) - : this.message = 'Invalid JSON RPC Request.'; + InvalidJsonRpcParamsException(this.requestId) : this.message = 'Invalid JSON RPC Request.'; String toString() { return "InvalidJsonRpcParamsException: $message"; @@ -27,8 +26,7 @@ class InvalidSessionException implements Exception { } class HandshakeException implements Exception { - final String message = - "handshakeId must be greater than 0 on session approve/reject."; + final String message = "handshakeId must be greater than 0 on session approve/reject."; String toString() { return "HandshakeException: $message"; diff --git a/lib/models/jsonrpc/json_rpc_error_response.dart b/lib/models/jsonrpc/json_rpc_error_response.dart index 27a4982..50ba6de 100644 --- a/lib/models/jsonrpc/json_rpc_error_response.dart +++ b/lib/models/jsonrpc/json_rpc_error_response.dart @@ -6,7 +6,7 @@ part 'json_rpc_error_response.g.dart'; @JsonSerializable() class JsonRpcErrorResponse { - final int id; + final String id; final String jsonrpc = JSONRPC_VERSION; final JsonRpcError error; JsonRpcErrorResponse({ @@ -14,8 +14,7 @@ class JsonRpcErrorResponse { required this.error, }); - factory JsonRpcErrorResponse.fromJson(Map json) => - _$JsonRpcErrorResponseFromJson(json); + factory JsonRpcErrorResponse.fromJson(Map json) => _$JsonRpcErrorResponseFromJson(json); Map toJson() => _$JsonRpcErrorResponseToJson(this); @override diff --git a/lib/models/jsonrpc/json_rpc_error_response.g.dart b/lib/models/jsonrpc/json_rpc_error_response.g.dart index 1135a59..efc9c16 100644 --- a/lib/models/jsonrpc/json_rpc_error_response.g.dart +++ b/lib/models/jsonrpc/json_rpc_error_response.g.dart @@ -6,16 +6,12 @@ part of 'json_rpc_error_response.dart'; // JsonSerializableGenerator // ************************************************************************** -JsonRpcErrorResponse _$JsonRpcErrorResponseFromJson( - Map json) => - JsonRpcErrorResponse( - id: json['id'] as int, +JsonRpcErrorResponse _$JsonRpcErrorResponseFromJson(Map json) => JsonRpcErrorResponse( + id: json['id'].toString(), error: JsonRpcError.fromJson(json['error'] as Map), ); -Map _$JsonRpcErrorResponseToJson( - JsonRpcErrorResponse instance) => - { +Map _$JsonRpcErrorResponseToJson(JsonRpcErrorResponse instance) => { 'id': instance.id, 'error': instance.error, }; diff --git a/lib/models/jsonrpc/json_rpc_request.dart b/lib/models/jsonrpc/json_rpc_request.dart index 9a52700..c8ad8ab 100644 --- a/lib/models/jsonrpc/json_rpc_request.dart +++ b/lib/models/jsonrpc/json_rpc_request.dart @@ -6,7 +6,7 @@ part 'json_rpc_request.g.dart'; @JsonSerializable() class JsonRpcRequest { - final int id; + final String id; final String jsonrpc; @JsonKey(unknownEnumValue: JsonKey.nullForUndefinedEnumValue) final WCMethod? method; @@ -18,8 +18,7 @@ class JsonRpcRequest { required this.params, }); - factory JsonRpcRequest.fromJson(Map json) => - _$JsonRpcRequestFromJson(json); + factory JsonRpcRequest.fromJson(Map json) => _$JsonRpcRequestFromJson(json); Map toJson() => _$JsonRpcRequestToJson(this); @override diff --git a/lib/models/jsonrpc/json_rpc_request.g.dart b/lib/models/jsonrpc/json_rpc_request.g.dart index fc328fa..203b528 100644 --- a/lib/models/jsonrpc/json_rpc_request.g.dart +++ b/lib/models/jsonrpc/json_rpc_request.g.dart @@ -6,17 +6,14 @@ part of 'json_rpc_request.dart'; // JsonSerializableGenerator // ************************************************************************** -JsonRpcRequest _$JsonRpcRequestFromJson(Map json) => - JsonRpcRequest( - id: json['id'] as int, +JsonRpcRequest _$JsonRpcRequestFromJson(Map json) => JsonRpcRequest( + id: json['id'].toString(), jsonrpc: json['jsonrpc'] as String? ?? JSONRPC_VERSION, - method: $enumDecodeNullable(_$WCMethodEnumMap, json['method'], - unknownValue: JsonKey.nullForUndefinedEnumValue), + method: $enumDecodeNullable(_$WCMethodEnumMap, json['method'], unknownValue: JsonKey.nullForUndefinedEnumValue), params: json['params'] as List?, ); -Map _$JsonRpcRequestToJson(JsonRpcRequest instance) => - { +Map _$JsonRpcRequestToJson(JsonRpcRequest instance) => { 'id': instance.id, 'jsonrpc': instance.jsonrpc, 'method': _$WCMethodEnumMap[instance.method], diff --git a/lib/models/jsonrpc/json_rpc_response.dart b/lib/models/jsonrpc/json_rpc_response.dart index 994e905..88c123f 100644 --- a/lib/models/jsonrpc/json_rpc_response.dart +++ b/lib/models/jsonrpc/json_rpc_response.dart @@ -5,7 +5,7 @@ part 'json_rpc_response.g.dart'; @JsonSerializable(genericArgumentFactories: true) class JsonRpcResponse { - final int id; + final String id; final String jsonrpc; final T result; JsonRpcResponse({ @@ -14,11 +14,9 @@ class JsonRpcResponse { required this.result, }); - factory JsonRpcResponse.fromJson(Map json) => - _$JsonRpcResponseFromJson(json, (object) => object as T); + factory JsonRpcResponse.fromJson(Map json) => _$JsonRpcResponseFromJson(json, (object) => object as T); Map toJson() => _$JsonRpcResponseToJson(this, (t) => t); @override - String toString() => - 'JsonRpcResponse(id: $id, jsonrpc: $jsonrpc, result: $result)'; + String toString() => 'JsonRpcResponse(id: $id, jsonrpc: $jsonrpc, result: $result)'; } diff --git a/lib/models/jsonrpc/json_rpc_response.g.dart b/lib/models/jsonrpc/json_rpc_response.g.dart index d7978f8..b4fe20d 100644 --- a/lib/models/jsonrpc/json_rpc_response.g.dart +++ b/lib/models/jsonrpc/json_rpc_response.g.dart @@ -11,7 +11,7 @@ JsonRpcResponse _$JsonRpcResponseFromJson( T Function(Object? json) fromJsonT, ) => JsonRpcResponse( - id: json['id'] as int, + id: json['id'].toString(), jsonrpc: json['jsonrpc'] as String? ?? JSONRPC_VERSION, result: fromJsonT(json['result']), ); diff --git a/lib/wc_client.dart b/lib/wc_client.dart index b5515f1..1b7ad3b 100644 --- a/lib/wc_client.dart +++ b/lib/wc_client.dart @@ -24,14 +24,14 @@ import 'package:wallet_connect/wc_session_store.dart'; import 'package:web_socket_channel/io.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; -typedef SessionRequest = void Function(int id, WCPeerMeta peerMeta); +typedef SessionRequest = void Function(String id, WCPeerMeta peerMeta); typedef SocketError = void Function(dynamic message); typedef SocketClose = void Function(int? code, String? reason); -typedef EthSign = void Function(int id, WCEthereumSignMessage message); -typedef EthTransaction = void Function( - int id, WCEthereumTransaction transaction); -typedef CustomRequest = void Function(int id, String payload); -typedef WalletSwitchNetwork = void Function(int id, int chainId); +typedef EthSign = void Function(String id, WCEthereumSignMessage message); +typedef EthTransaction = void Function(String id, WCEthereumTransaction transaction); +typedef CustomRequest = void Function(String id, String payload); +typedef WalletSwitchNetwork = void Function(String id, int chainId); +typedef SessionUpdate = void Function(String id, bool approved, int? chainId, List? accounts); class WCClient { late WebSocketChannel _webSocket; @@ -42,7 +42,7 @@ class WCClient { WCSession? _session; WCPeerMeta? _peerMeta; WCPeerMeta? _remotePeerMeta; - int _handshakeId = -1; + String _handshakeId = "-1"; int? _chainId; String? _peerId; String? _remotePeerId; @@ -58,6 +58,8 @@ class WCClient { this.onWalletSwitchNetwork, this.onCustomRequest, this.onConnect, + //add sessionupdate + this.onSessionUpdate, }); final SessionRequest? onSessionRequest; @@ -67,6 +69,7 @@ class WCClient { final EthTransaction? onEthSignTransaction, onEthSendTransaction; final CustomRequest? onCustomRequest; final WalletSwitchNetwork? onWalletSwitchNetwork; + final SessionUpdate? onSessionUpdate; final Function()? onConnect; WCSession? get session => _session; @@ -121,7 +124,7 @@ class WCClient { ); approveSession({required List accounts, int? chainId}) { - if (_handshakeId <= 0) { + if (int.parse(_handshakeId) <= 0) { throw HandshakeException(); } @@ -153,7 +156,7 @@ class WCClient { accounts: accounts, ); final request = JsonRpcRequest( - id: DateTime.now().millisecondsSinceEpoch, + id: DateTime.now().millisecondsSinceEpoch.toString(), method: WCMethod.SESSION_UPDATE, params: [param.toJson()], ); @@ -161,7 +164,7 @@ class WCClient { } rejectSession({String message = "Session rejected"}) { - if (_handshakeId <= 0) { + if (int.parse(_handshakeId) <= 0) { throw HandshakeException(); } @@ -173,7 +176,7 @@ class WCClient { } approveRequest({ - required int id, + required String id, required T result, }) { final response = JsonRpcResponse( @@ -184,7 +187,7 @@ class WCClient { } rejectRequest({ - required int id, + required String id, String message = "Reject by the user", }) { final response = JsonRpcErrorResponse( @@ -215,8 +218,7 @@ class WCClient { _peerId = peerId; _remotePeerId = remotePeerId; _chainId = chainId; - final bridgeUri = - Uri.parse(session.bridge.replaceAll('https://', 'wss://')); + final bridgeUri = Uri.parse(session.bridge.replaceAll('https://', 'wss://')); final ws = await WebSocket.connect( bridgeUri.toString(), customClient: customClient, @@ -233,8 +235,8 @@ class WCClient { _subscribe(peerId); } - disconnect() { - _socketSink!.close(WebSocketStatus.normalClosure); + disconnect({String? reason}) { + _socketSink!.close(WebSocketStatus.normalClosure, reason); } _subscribe(String topic) { @@ -246,7 +248,7 @@ class WCClient { _socketSink!.add(jsonEncode(message)); } - _invalidParams(int id) { + _invalidParams(String id) { final response = JsonRpcErrorResponse( id: id, error: JsonRpcError.invalidParams("Invalid parameters"), @@ -292,8 +294,7 @@ class WCClient { } Future _decrypt(WCSocketMessage socketMessage) async { - final payload = - WCEncryptionPayload.fromJson(jsonDecode(socketMessage.payload)); + final payload = WCEncryptionPayload.fromJson(jsonDecode(socketMessage.payload)); final decrypted = await WCCipher.decrypt(payload, _session!.key); // print("DECRYPTED: $decrypted"); return decrypted; @@ -327,10 +328,11 @@ class WCClient { break; case WCMethod.SESSION_UPDATE: final param = WCSessionUpdate.fromJson(request.params!.first); - // print('SESSION_UPDATE $param'); + print('SESSION_UPDATE $param'); if (!param.approved) { - killSession(); + killSession(reason: "Session Update Closed"); } + onSessionUpdate?.call(request.id, param.approved, param.chainId, param.accounts); break; case WCMethod.ETH_SIGN: // print('ETH_SIGN $request'); @@ -396,13 +398,13 @@ class WCClient { } } - killSession() async { + killSession({String? reason}) async { await updateSession(approved: false); - disconnect(); + disconnect(reason: reason); } _resetState() { - _handshakeId = -1; + _handshakeId = "-1"; _isConnected = false; _session = null; _peerId = null;