From ffbbe0663c8ea5b11eb772e65d28de08d29710a8 Mon Sep 17 00:00:00 2001 From: Alfreedom <00tango.bromine@icloud.com> Date: Wed, 10 Jul 2024 15:45:21 +0200 Subject: [PATCH] Bug fixes and enhancements --- CHANGELOG.md | 2 +- example/android/gradle.properties | 2 +- example/ios/Runner.xcodeproj/project.pbxproj | 12 +- example/ios/Runner/Info.plist | 2 +- example/pubspec.lock | 6 +- lib/pages/approve_magic_request_page.dart | 8 +- lib/pages/approve_siwe.dart | 3 +- .../blockchain_service.dart | 156 ++++++++++++------ .../blockchain_service_singleton.dart | 2 +- .../i_blockchain_service.dart | 15 +- .../coinbase_service/coinbase_service.dart | 16 +- .../explorer_service/explorer_service.dart | 18 +- .../ledger_service/i_ledger_service.dart | 7 - .../ledger_service/ledger_service.dart | 32 ---- .../ledger_service_singleton.dart | 10 -- lib/services/w3m_service/w3m_service.dart | 47 +++--- lib/version.dart | 2 +- lib/widgets/w3m_account_button.dart | 2 +- pubspec.lock | 4 +- pubspec.yaml | 4 +- test/mock_classes.dart | 2 - test/mock_classes.mocks.dart | 141 +++++----------- test/w3m_service/w3m_service_unit_test.dart | 40 +++-- 23 files changed, 250 insertions(+), 283 deletions(-) delete mode 100644 lib/services/ledger_service/i_ledger_service.dart delete mode 100644 lib/services/ledger_service/ledger_service.dart delete mode 100644 lib/services/ledger_service/ledger_service_singleton.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 74403e95..62ae1e1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 3.3.0-beta05 +## 3.3.0-beta06 - One-Click Auth + SIWE implementation - Coinbase Wallet dependency update diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 7c06f16b..3f04ec0e 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -2,4 +2,4 @@ org.gradle.jvmargs=-Xmx1536M android.useAndroidX=true android.enableJetifier=true versionName=3.3.0 -versionCode=66 +versionCode=67 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 34f67823..58328b9b 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -470,7 +470,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22; ENABLE_BITCODE = NO; @@ -496,7 +496,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.web3modal.flutterExample.RunnerTests; @@ -514,7 +514,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.web3modal.flutterExample.RunnerTests; @@ -530,7 +530,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.web3modal.flutterExample.RunnerTests; @@ -655,7 +655,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22; ENABLE_BITCODE = NO; @@ -686,7 +686,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22; ENABLE_BITCODE = NO; diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index 9565095f..1a2a788d 100644 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -36,7 +36,7 @@ CFBundleVersion - 66 + 67 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/example/pubspec.lock b/example/pubspec.lock index d387e96f..b76fd0b0 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -213,10 +213,10 @@ packages: dependency: transitive description: name: coinbase_wallet_sdk - sha256: e18bd5351939aacda75c0b525aa9167b945f1206040ec254f971afe96dfd98b0 + sha256: "4a309b22d1d8647ab4381ac075921dba211ac642f58b2ca06c0c1fb8f58973da" url: "https://pub.dev" source: hosted - version: "1.0.8" + version: "1.0.9" collection: dependency: transitive description: @@ -1131,7 +1131,7 @@ packages: path: ".." relative: true source: path - version: "3.3.0-beta05" + version: "3.3.0-beta06" web_socket_channel: dependency: transitive description: diff --git a/lib/pages/approve_magic_request_page.dart b/lib/pages/approve_magic_request_page.dart index 547cb227..e5224587 100644 --- a/lib/pages/approve_magic_request_page.dart +++ b/lib/pages/approve_magic_request_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:web3modal_flutter/constants/key_constants.dart'; import 'package:web3modal_flutter/services/magic_service/magic_service_singleton.dart'; +import 'package:web3modal_flutter/widgets/miscellaneous/responsive_container.dart'; import 'package:web3modal_flutter/widgets/navigation/navbar.dart'; class ApproveTransactionPage extends StatefulWidget { @@ -22,7 +23,12 @@ class _ApproveTransactionPageState extends State { noClose: true, safeAreaLeft: true, safeAreaRight: true, - body: magicService.instance.webview, + body: ConstrainedBox( + constraints: BoxConstraints( + maxHeight: ResponsiveData.maxHeightOf(context), + ), + child: magicService.instance.webview, + ), ); } } diff --git a/lib/pages/approve_siwe.dart b/lib/pages/approve_siwe.dart index 79fed3da..15379866 100644 --- a/lib/pages/approve_siwe.dart +++ b/lib/pages/approve_siwe.dart @@ -110,11 +110,12 @@ class _ApproveSIWEPageState extends State { debugPrint('[$runtimeType] _handleError $error'); String chainId = _service!.selectedChain?.chainId ?? '1'; analyticsService.instance.sendEvent(SiweAuthError(network: chainId)); - setState(() => _waitingSign = false); toastUtils.instance.show(ToastMessage( type: ToastType.error, text: error ?? 'Something went wrong.', )); + if (!mounted) return; + setState(() => _waitingSign = false); } void _cancelSIWE() async { diff --git a/lib/services/blockchain_service/blockchain_service.dart b/lib/services/blockchain_service/blockchain_service.dart index 97db7e62..b46321f0 100644 --- a/lib/services/blockchain_service/blockchain_service.dart +++ b/lib/services/blockchain_service/blockchain_service.dart @@ -6,72 +6,136 @@ import 'package:web3modal_flutter/constants/string_constants.dart'; import 'package:web3modal_flutter/constants/url_constants.dart'; import 'package:web3modal_flutter/services/blockchain_service/models/blockchain_identity.dart'; import 'package:web3modal_flutter/services/blockchain_service/i_blockchain_service.dart'; +import 'package:web3modal_flutter/services/logger_service/logger_service_singleton.dart'; + +class BlockChainService implements IBlockChainService { + late final ICore _core; + late final String _baseUrl; + late final String _clientId; + + BlockChainService({required ICore core}) : _core = core; -class BlockChainService extends IBlockChainService { - // @override - final String projectId; + Future init() async { + _baseUrl = '${UrlConstants.blockChainService}/v1'; + _clientId = await _core.crypto.getClientId(); + } - final IWeb3App _web3app; + Map get _requiredParams => { + 'projectId': _core.projectId, + 'clientId': _clientId, + }; - BlockChainService({ - required this.projectId, - required IWeb3App web3app, - }) : _web3app = web3app; + Map get _requiredHeaders => { + 'x-sdk-type': StringConstants.X_SDK_TYPE, + 'x-sdk-version': 'flutter-${StringConstants.X_SDK_VERSION}', + }; @override - Future getIdentity(String address, int chainId) async { - final scope = '${StringConstants.namespace}:$chainId'; - final clientId = await _web3app.core.crypto.getClientId(); - final uri = Uri.parse( - '${UrlConstants.blockChainService}/v1/identity/$address', + Future getIdentity(String address) async { + try { + final uri = Uri.parse('$_baseUrl/identity/$address'); + final queryParams = {..._requiredParams}; + final response = await http.get( + uri.replace(queryParameters: queryParams), + headers: _requiredHeaders, + ); + if (response.statusCode == 200) { + return BlockchainIdentity.fromJson(jsonDecode(response.body)); + } else { + throw Exception('Failed to load avatar'); + } + } catch (e) { + loggerService.instance.e('[$runtimeType] getIdentity: $e'); + rethrow; + } + } + + @override + Future getRpcRequest({ + required String method, + required List params, + required String chain, + }) async { + final bool isChainId = NamespaceUtils.isValidChainId(chain); + if (!isChainId) { + throw Errors.getSdkError( + Errors.UNSUPPORTED_CHAINS, + context: '[$runtimeType] chain should be CAIP-2 valid', + ); + } + final uri = Uri.parse(_baseUrl); + final queryParams = {..._requiredParams, 'chainId': chain}; + final response = await http.post( + uri.replace(queryParameters: queryParams), + headers: { + ..._requiredHeaders, + 'Content-Type': 'application/json', + }, + body: jsonEncode({ + 'jsonrpc': '2.0', + 'method': method, + 'params': params, + 'chainId': chain.split(':').last, + }), ); - final queryParams = { - 'chainId': scope, - 'projectId': projectId, - 'clientId': clientId, - }; - final response = await http.get(uri.replace(queryParameters: queryParams)); - if (response.statusCode == 200) { - return BlockchainIdentity.fromJson(jsonDecode(response.body)); + if (response.statusCode == 200 && response.body.isNotEmpty) { + try { + final result = _parseRpcResultAs(response.body); + final amount = EtherAmount.fromBigInt(EtherUnit.wei, hexToInt(result)); + return amount.getValueInUnit(EtherUnit.ether); + } catch (e) { + rethrow; + } } else { - throw Exception('Failed to load avatar'); + throw Exception('Failed to get request $method'); + } + } + + T _parseRpcResultAs(String body) { + final result = Map.from({ + ...jsonDecode(body), + 'id': -1, + }); + final jsonResponse = JsonRpcResponse.fromJson(result); + if (jsonResponse.result != null) { + return jsonResponse.result; } + throw jsonResponse.error!; } // TODO to be implemented // @override - // Future getBalance(String chainId, String address) async { - // // final client = Web3Client(rpcUrl, Client()); - // // final amount = await client.getBalance(EthereumAddress.fromHex(address)); - // // return amount.getValueInUnit(EtherUnit.ether); - // final scope = '${StringConstants.namespace}:$chainId'; - // final clientId = await _web3app.core.crypto.getClientId(); - // final uri = Uri.parse('${UrlConstants.blockChainService}/v1'); + // Future getBalance( + // String address, + // String currency, { + // String? chain, + // String? forceUpdate, + // }) async { + // final uri = Uri.parse('$_baseUrl/account/$address/balance'); // final queryParams = { - // 'chainId': scope, - // 'projectId': projectId, - // 'clientId': clientId, + // ..._requiredParams, + // 'currency': currency, + // if (chain != null) 'chainId': chain, + // if (forceUpdate != null) 'forceUpdate': forceUpdate, // }; - // // "chainId=eip155%3A1&projectId=cad4956f31a5e40a00b62865b030c6f8&clientId=did%3Akey%3Az6MkgNA9sezpYrpiJGSkkQwUQSqoEWSDsDFZifbu6tYbu…" - // final response = await http.post( + // final response = await http.get( // uri.replace(queryParameters: queryParams), // headers: { - // ...coreUtils.instance.getAPIHeaders(projectId), - // 'Content-Type': 'application/json', + // ..._requiredHeaders, + // // 'chain': chainId, + // // 'forceUpdate': string + // // 'Content-Type': 'application/json', // }, - // body: jsonEncode({ - // 'jsonrpc': '2.0', - // 'method': 'eth_getBalance', - // 'params': [address, 'latest'], - // 'chainId': 1 - // }), + // // body: jsonEncode({ + // // 'jsonrpc': '2.0', + // // 'method': 'eth_getBalance', + // // 'params': [address, 'latest'], + // // 'chainId': 1 + // // }), // ); - // print(response.body); + // _core.logger.i('[$runtimeType] getBalance $address: ${response.body}'); // if (response.statusCode == 200) { - // final result = JsonRpcResponse.fromJson(jsonDecode(response.body)); - // final bytes = hex.decode(result.result.toString().replaceFirst('0x', '')); - // // "{"jsonrpc":"2.0","id":"","result":"0x0"}" // } else { // throw Exception('Failed to load balance'); // } diff --git a/lib/services/blockchain_service/blockchain_service_singleton.dart b/lib/services/blockchain_service/blockchain_service_singleton.dart index f2165b01..9fadc72d 100644 --- a/lib/services/blockchain_service/blockchain_service_singleton.dart +++ b/lib/services/blockchain_service/blockchain_service_singleton.dart @@ -1,7 +1,7 @@ import 'package:web3modal_flutter/services/blockchain_service/i_blockchain_service.dart'; class BlockChainServiceSingleton { - IBlockChainService? instance; + late IBlockChainService instance; } final blockchainService = BlockChainServiceSingleton(); diff --git a/lib/services/blockchain_service/i_blockchain_service.dart b/lib/services/blockchain_service/i_blockchain_service.dart index 5b23527b..aa9c79c8 100644 --- a/lib/services/blockchain_service/i_blockchain_service.dart +++ b/lib/services/blockchain_service/i_blockchain_service.dart @@ -1,15 +1,14 @@ import 'package:web3modal_flutter/services/blockchain_service/models/blockchain_identity.dart'; abstract class IBlockChainService { - /// The project ID used when querying the API. - String get projectId; + Future init(); /// Gets the name and avatar of a provided address on the given chain - Future getIdentity(String address, int chainId); + Future getIdentity(String address); - // Future getBalance(String chainId, String address); - - // Future fetchEnsName(String rpcUrl, String address); - - // Future fetchEnsAvatar(String rpcUrl, String address); + Future getRpcRequest({ + required String method, + required List params, + required String chain, + }); } diff --git a/lib/services/coinbase_service/coinbase_service.dart b/lib/services/coinbase_service/coinbase_service.dart index bd06665b..1322d4b2 100644 --- a/lib/services/coinbase_service/coinbase_service.dart +++ b/lib/services/coinbase_service/coinbase_service.dart @@ -79,12 +79,14 @@ class CoinbaseService implements ICoinbaseService { Event get onCoinbaseResponse => Event(); - final IWeb3App _web3app; + late final PairingMetadata _metadata; late bool _enabled; late W3MWalletInfo _walletData; - CoinbaseService({required IWeb3App web3app, bool enabled = false}) - : _web3app = web3app, + CoinbaseService({ + required PairingMetadata metadata, + bool enabled = false, + }) : _metadata = metadata, _enabled = enabled; @override @@ -97,8 +99,8 @@ class CoinbaseService implements ICoinbaseService { final imageId = defaultWalletData.listing.imageId; _iconImage = explorerService.instance.getWalletImageUrl(imageId); - final universal = _web3app.metadata.redirect?.universal ?? ''; - final nativeLink = _web3app.metadata.redirect?.native ?? ''; + final universal = _metadata.redirect?.universal ?? ''; + final nativeLink = _metadata.redirect?.native ?? ''; final walletLink = _walletData.listing.mobileLink ?? ''; if ((universal.isNotEmpty && nativeLink.isNotEmpty) || walletLink.isNotEmpty) { @@ -162,7 +164,7 @@ class CoinbaseService implements ICoinbaseService { publicKey: await peerPublicKey, ), self: ConnectionMetadata( - metadata: _web3app.metadata, + metadata: _metadata, publicKey: await ownPublicKey, ), ); @@ -209,7 +211,7 @@ class CoinbaseService implements ICoinbaseService { publicKey: await peerPublicKey, ), self: ConnectionMetadata( - metadata: _web3app.metadata, + metadata: _metadata, publicKey: await ownPublicKey, ), ); diff --git a/lib/services/explorer_service/explorer_service.dart b/lib/services/explorer_service/explorer_service.dart index 68d0b098..ed41d3ea 100644 --- a/lib/services/explorer_service/explorer_service.dart +++ b/lib/services/explorer_service/explorer_service.dart @@ -31,9 +31,10 @@ class ExplorerService implements IExplorerService { final String _referer; late RequestParams _requestParams; + late final ICore _core; @override - final String projectId; + String get projectId => _core.projectId; @override ValueNotifier initialized = ValueNotifier(false); @@ -91,12 +92,13 @@ class ExplorerService implements IExplorerService { bool get canPaginate => _canPaginate; ExplorerService({ - required this.projectId, + required ICore core, required String referer, this.featuredWalletIds, this.includedWalletIds, this.excludedWalletIds, - }) : _referer = referer, + }) : _core = core, + _referer = referer, _client = http.Client(); @override @@ -197,7 +199,10 @@ class ExplorerService implements IExplorerService { } Future> _fetchNativeAppData() async { - final headers = coreUtils.instance.getAPIHeaders(projectId, _referer); + final headers = coreUtils.instance.getAPIHeaders( + _core.projectId, + _referer, + ); final uri = Platform.isIOS ? Uri.parse('${UrlConstants.apiService}/getIosData') : Uri.parse('${UrlConstants.apiService}/getAndroidData'); @@ -278,7 +283,10 @@ class ExplorerService implements IExplorerService { bool updateCount = true, }) async { final queryParams = params?.toJson() ?? {}; - final headers = coreUtils.instance.getAPIHeaders(projectId, _referer); + final headers = coreUtils.instance.getAPIHeaders( + _core.projectId, + _referer, + ); final uri = Uri.parse('${UrlConstants.apiService}/getWallets').replace( queryParameters: queryParams, ); diff --git a/lib/services/ledger_service/i_ledger_service.dart b/lib/services/ledger_service/i_ledger_service.dart deleted file mode 100644 index 5082fc7d..00000000 --- a/lib/services/ledger_service/i_ledger_service.dart +++ /dev/null @@ -1,7 +0,0 @@ -abstract class ILedgerService { - Future getBalance(String rpcUrl, String address); - - Future fetchEnsName(String rpcUrl, String address); - - Future fetchEnsAvatar(String rpcUrl, String address); -} diff --git a/lib/services/ledger_service/ledger_service.dart b/lib/services/ledger_service/ledger_service.dart deleted file mode 100644 index 5bd48547..00000000 --- a/lib/services/ledger_service/ledger_service.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:http/http.dart'; -import 'package:web3modal_flutter/services/ledger_service/i_ledger_service.dart'; -import 'package:web3modal_flutter/services/logger_service/logger_service_singleton.dart'; -import 'package:web3modal_flutter/web3modal_flutter.dart'; - -class LedgerService extends ILedgerService { - @override - Future getBalance(String rpcUrl, String address) async { - try { - final client = Web3Client(rpcUrl, Client()); - final amount = await client.getBalance(EthereumAddress.fromHex(address)); - return amount.getValueInUnit(EtherUnit.ether); - } catch (e, s) { - loggerService.instance.e( - '[$runtimeType] getBalance error', - error: e, - stackTrace: s, - ); - return null; - } - } - - @override - Future fetchEnsName(String rpcUrl, String address) async { - return ''; - } - - @override - Future fetchEnsAvatar(String rpcUrl, String address) async { - return ''; - } -} diff --git a/lib/services/ledger_service/ledger_service_singleton.dart b/lib/services/ledger_service/ledger_service_singleton.dart deleted file mode 100644 index c987f262..00000000 --- a/lib/services/ledger_service/ledger_service_singleton.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:web3modal_flutter/services/ledger_service/i_ledger_service.dart'; -import 'package:web3modal_flutter/services/ledger_service/ledger_service.dart'; - -class LedgerServiceSingleton { - ILedgerService instance; - - LedgerServiceSingleton() : instance = LedgerService(); -} - -final ledgerService = LedgerServiceSingleton(); diff --git a/lib/services/w3m_service/w3m_service.dart b/lib/services/w3m_service/w3m_service.dart index eb030f7f..ed0c456c 100644 --- a/lib/services/w3m_service/w3m_service.dart +++ b/lib/services/w3m_service/w3m_service.dart @@ -26,7 +26,6 @@ import 'package:web3modal_flutter/services/coinbase_service/models/coinbase_even import 'package:web3modal_flutter/services/explorer_service/explorer_service.dart'; import 'package:web3modal_flutter/services/explorer_service/explorer_service_singleton.dart'; import 'package:web3modal_flutter/services/explorer_service/models/redirect.dart'; -import 'package:web3modal_flutter/services/ledger_service/ledger_service_singleton.dart'; import 'package:web3modal_flutter/services/logger_service/i_logger_service.dart'; import 'package:web3modal_flutter/services/magic_service/magic_service.dart'; import 'package:web3modal_flutter/services/magic_service/magic_service_singleton.dart'; @@ -178,7 +177,7 @@ class W3MService with ChangeNotifier implements IW3MService { }); explorerService.instance = ExplorerService( - projectId: _projectId, + core: _web3App.core, referer: _web3App.metadata.name.replaceAll(' ', ''), featuredWalletIds: featuredWalletIds, includedWalletIds: includedWalletIds, @@ -186,24 +185,22 @@ class W3MService with ChangeNotifier implements IW3MService { ); blockchainService.instance = BlockChainService( - web3app: _web3App, - projectId: _projectId, - ); - - siweService.instance = SiweService( - web3app: _web3App, - siweConfig: siweConfig, + core: _web3App.core, ); - magicService.instance = MagicService( web3app: _web3App, enabled: enableEmail, ); coinbaseService.instance = CoinbaseService( - web3app: _web3App, + metadata: _web3App.metadata, enabled: _initializeCoinbaseSDK, ); + + siweService.instance = SiweService( + web3app: _web3App, + siweConfig: siweConfig, + ); } ////////* PUBLIC METHODS *///////// @@ -230,11 +227,12 @@ class W3MService with ChangeNotifier implements IW3MService { _registerListeners(); + await _web3App.init(); await storageService.instance.init(); await networkService.instance.init(); await explorerService.instance.init(); await coinbaseService.instance.init(); - await _web3App.init(); + await blockchainService.instance.init(); _currentSession = await _getStoredSession(); final isMagic = _currentSession?.sessionService.isMagic == true; @@ -551,8 +549,8 @@ class W3MService with ChangeNotifier implements IW3MService { final isBottomSheet = platformUtils.instance.isBottomSheet(); final theme = Web3ModalTheme.maybeOf(_context!); - final themeData = theme?.themeData ?? const Web3ModalThemeData(); await magicService.instance.syncTheme(theme); + final themeData = theme?.themeData ?? const Web3ModalThemeData(); Widget? showWidget = startWidget; if (_isConnected && showWidget == null) { @@ -895,6 +893,7 @@ class W3MService with ChangeNotifier implements IW3MService { } } if (_currentSession?.sessionService.isMagic == true) { + await Future.delayed(Duration(milliseconds: 300)); final disconnected = await magicService.instance.disconnect(); if (!disconnected) { _status = W3MServiceStatus.initialized; @@ -1224,18 +1223,18 @@ class W3MService with ChangeNotifier implements IW3MService { } // Get the chain balance. - _chainBalance = await ledgerService.instance.getBalance( - _currentSelectedChain!.rpcUrl, - _currentSession!.address!, + _chainBalance = await blockchainService.instance.getRpcRequest( + method: 'eth_getBalance', + params: [_currentSession!.address!, 'latest'], + chain: _currentSelectedChain!.namespace, ); - balanceNotifier.value = - '$chainBalance ${_currentSelectedChain?.tokenName ?? ''}'; + final tokenName = _currentSelectedChain?.tokenName ?? ''; + balanceNotifier.value = '$_chainBalance $tokenName'; // Get the avatar, each chainId is just a number in string form. try { - final blockchainId = await blockchainService.instance!.getIdentity( + final blockchainId = await blockchainService.instance.getIdentity( _currentSession!.address!, - int.parse(_currentSelectedChain!.chainId), ); _avatarUrl = blockchainId.avatar; _logger.i('[$runtimeType] loadAccountData'); @@ -1489,6 +1488,8 @@ extension _W3MMagicExtension on W3MService { onModalUpdate.broadcast(ModalConnect(_currentSession!)); } else { _disconnectOnClose = true; + final theme = Web3ModalTheme.maybeOf(_context!); + await magicService.instance.syncTheme(theme); widgetStack.instance.push(ApproveSIWEPage( onSiweFinish: _oneSIWEFinish, )); @@ -1545,7 +1546,11 @@ extension _W3MMagicExtension on W3MService { void _onMagicRequest(MagicRequestEvent? args) { _logger.d('[$runtimeType] _onMagicRequest ${args?.toString()}'); if (args?.result != null) { - closeModal(); + if (args!.result is JsonRpcError && widgetStack.instance.canPop()) { + widgetStack.instance.pop(); + } else { + closeModal(); + } } } diff --git a/lib/version.dart b/lib/version.dart index 3212ce43..04717b4a 100644 --- a/lib/version.dart +++ b/lib/version.dart @@ -1,2 +1,2 @@ // Generated code. Do not modify. -const packageVersion = '3.3.0-beta05'; +const packageVersion = '3.3.0-beta06'; diff --git a/lib/widgets/w3m_account_button.dart b/lib/widgets/w3m_account_button.dart index 7006b74c..7957ed31 100644 --- a/lib/widgets/w3m_account_button.dart +++ b/lib/widgets/w3m_account_button.dart @@ -83,7 +83,7 @@ class _W3MAccountButtonState extends State { void _approveSign(MagicRequestEvent? args) async { if (args?.request != null) { if (widget.service.isOpen) { - widgetStack.instance.popAllAndPush(ApproveTransactionPage()); + widgetStack.instance.push(ApproveTransactionPage()); } else { if (widget.service.modalContext != null) { widget.service.openModalView(ApproveTransactionPage()); diff --git a/pubspec.lock b/pubspec.lock index 28040cbc..8a447eef 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -205,10 +205,10 @@ packages: dependency: "direct main" description: name: coinbase_wallet_sdk - sha256: e18bd5351939aacda75c0b525aa9167b945f1206040ec254f971afe96dfd98b0 + sha256: "4a309b22d1d8647ab4381ac075921dba211ac642f58b2ca06c0c1fb8f58973da" url: "https://pub.dev" source: hosted - version: "1.0.8" + version: "1.0.9" collection: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 70d859b3..20e1454f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: web3modal_flutter description: "WalletConnect Web3Modal: Simple, intuitive wallet login. With this drop-in UI SDK, enable any wallet's users to seamlessly log in to your app and enjoy a unified experience" -version: 3.3.0-beta05 +version: 3.3.0-beta06 repository: https://github.com/WalletConnect/Web3ModalFlutter environment: @@ -9,7 +9,7 @@ environment: dependencies: appcheck: ^1.0.6 cached_network_image: ^3.3.1 - coinbase_wallet_sdk: ^1.0.8 + coinbase_wallet_sdk: ^1.0.9 collection: ^1.17.2 convert: ^3.1.1 cupertino_icons: ^1.0.2 diff --git a/test/mock_classes.dart b/test/mock_classes.dart index 3086bdc7..9c532f0c 100644 --- a/test/mock_classes.dart +++ b/test/mock_classes.dart @@ -4,7 +4,6 @@ import 'package:mockito/annotations.dart'; import 'package:http/http.dart' as http; import 'package:web3modal_flutter/services/blockchain_service/blockchain_service.dart'; import 'package:web3modal_flutter/services/explorer_service/explorer_service.dart'; -import 'package:web3modal_flutter/services/ledger_service/ledger_service.dart'; import 'package:web3modal_flutter/services/network_service/network_service.dart'; import 'package:web3modal_flutter/services/storage_service/storage_service.dart'; import 'package:web3modal_flutter/utils/platform/platform_utils.dart'; @@ -27,7 +26,6 @@ import 'mock_classes.mocks.dart'; http.Client, NetworkService, BlockChainService, - LedgerService, StorageService, WidgetStack, ]) diff --git a/test/mock_classes.mocks.dart b/test/mock_classes.mocks.dart index 317be5b8..20569bfd 100644 --- a/test/mock_classes.mocks.dart +++ b/test/mock_classes.mocks.dart @@ -28,7 +28,7 @@ import 'package:walletconnect_flutter_v2/apis/core/store/i_store.dart' as _i6; import 'package:walletconnect_flutter_v2/apis/sign_api/i_sessions.dart' as _i5; import 'package:web3modal_flutter/models/grid_item.dart' as _i29; import 'package:web3modal_flutter/services/analytics_service/models/analytics_event.dart' - as _i34; + as _i33; import 'package:web3modal_flutter/services/blockchain_service/blockchain_service.dart' as _i30; import 'package:web3modal_flutter/services/blockchain_service/models/blockchain_identity.dart' @@ -37,12 +37,10 @@ import 'package:web3modal_flutter/services/explorer_service/explorer_service.dar as _i12; import 'package:web3modal_flutter/services/explorer_service/models/redirect.dart' as _i19; -import 'package:web3modal_flutter/services/ledger_service/ledger_service.dart' - as _i31; import 'package:web3modal_flutter/services/network_service/network_service.dart' as _i28; import 'package:web3modal_flutter/services/storage_service/storage_service.dart' - as _i32; + as _i31; import 'package:web3modal_flutter/services/w3m_service/i_w3m_service.dart' as _i15; import 'package:web3modal_flutter/utils/platform/i_platform_utils.dart' as _i20; @@ -52,7 +50,7 @@ import 'package:web3modal_flutter/utils/toast/toast_utils.dart' as _i22; import 'package:web3modal_flutter/utils/url/url_utils.dart' as _i17; import 'package:web3modal_flutter/web3modal_flutter.dart' as _i3; import 'package:web3modal_flutter/widgets/widget_stack/widget_stack.dart' - as _i33; + as _i32; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -290,14 +288,6 @@ class MockExplorerService extends _i1.Mock implements _i12.ExplorerService { _i1.throwOnMissingStub(this); } - @override - String get projectId => (super.noSuchMethod( - Invocation.getter(#projectId), - returnValue: _i13.dummyValue( - this, - Invocation.getter(#projectId), - ), - ) as String); @override _i2.ValueNotifier get initialized => (super.noSuchMethod( Invocation.getter(#initialized), @@ -390,6 +380,14 @@ class MockExplorerService extends _i1.Mock implements _i12.ExplorerService { returnValueForMissingStub: null, ); @override + String get projectId => (super.noSuchMethod( + Invocation.getter(#projectId), + returnValue: _i13.dummyValue( + this, + Invocation.getter(#projectId), + ), + ) as String); + @override String get searchValue => (super.noSuchMethod( Invocation.getter(#searchValue), returnValue: _i13.dummyValue( @@ -2358,117 +2356,54 @@ class MockBlockChainService extends _i1.Mock implements _i30.BlockChainService { } @override - String get projectId => (super.noSuchMethod( - Invocation.getter(#projectId), - returnValue: _i13.dummyValue( - this, - Invocation.getter(#projectId), + _i14.Future init() => (super.noSuchMethod( + Invocation.method( + #init, + [], ), - ) as String); + returnValue: _i14.Future.value(), + returnValueForMissingStub: _i14.Future.value(), + ) as _i14.Future); @override - _i14.Future<_i10.BlockchainIdentity> getIdentity( - String? address, - int? chainId, - ) => + _i14.Future<_i10.BlockchainIdentity> getIdentity(String? address) => (super.noSuchMethod( Invocation.method( #getIdentity, - [ - address, - chainId, - ], + [address], ), returnValue: _i14.Future<_i10.BlockchainIdentity>.value( _FakeBlockchainIdentity_18( this, Invocation.method( #getIdentity, - [ - address, - chainId, - ], + [address], ), )), ) as _i14.Future<_i10.BlockchainIdentity>); -} - -/// A class which mocks [LedgerService]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockLedgerService extends _i1.Mock implements _i31.LedgerService { - MockLedgerService() { - _i1.throwOnMissingStub(this); - } - - @override - _i14.Future getBalance( - String? rpcUrl, - String? address, - ) => - (super.noSuchMethod( - Invocation.method( - #getBalance, - [ - rpcUrl, - address, - ], - ), - returnValue: _i14.Future.value(), - ) as _i14.Future); @override - _i14.Future fetchEnsName( - String? rpcUrl, - String? address, - ) => - (super.noSuchMethod( - Invocation.method( - #fetchEnsName, - [ - rpcUrl, - address, - ], - ), - returnValue: _i14.Future.value(_i13.dummyValue( - this, - Invocation.method( - #fetchEnsName, - [ - rpcUrl, - address, - ], - ), - )), - ) as _i14.Future); - @override - _i14.Future fetchEnsAvatar( - String? rpcUrl, - String? address, - ) => + _i14.Future getRpcRequest({ + required String? method, + required List? params, + required String? chain, + }) => (super.noSuchMethod( Invocation.method( - #fetchEnsAvatar, - [ - rpcUrl, - address, - ], + #getRpcRequest, + [], + { + #method: method, + #params: params, + #chain: chain, + }, ), - returnValue: _i14.Future.value(_i13.dummyValue( - this, - Invocation.method( - #fetchEnsAvatar, - [ - rpcUrl, - address, - ], - ), - )), - ) as _i14.Future); + returnValue: _i14.Future.value(), + ) as _i14.Future); } /// A class which mocks [StorageService]. /// /// See the documentation for Mockito's code generation for more information. -class MockStorageService extends _i1.Mock implements _i32.StorageService { +class MockStorageService extends _i1.Mock implements _i31.StorageService { MockStorageService() { _i1.throwOnMissingStub(this); } @@ -2529,7 +2464,7 @@ class MockStorageService extends _i1.Mock implements _i32.StorageService { /// A class which mocks [WidgetStack]. /// /// See the documentation for Mockito's code generation for more information. -class MockWidgetStack extends _i1.Mock implements _i33.WidgetStack { +class MockWidgetStack extends _i1.Mock implements _i32.WidgetStack { MockWidgetStack() { _i1.throwOnMissingStub(this); } @@ -2565,7 +2500,7 @@ class MockWidgetStack extends _i1.Mock implements _i33.WidgetStack { void push( _i11.Widget? widget, { bool? renderScreen = false, - _i34.AnalyticsEvent? event, + _i33.AnalyticsEvent? event, }) => super.noSuchMethod( Invocation.method( diff --git a/test/w3m_service/w3m_service_unit_test.dart b/test/w3m_service/w3m_service_unit_test.dart index c3fec83d..76b5965c 100644 --- a/test/w3m_service/w3m_service_unit_test.dart +++ b/test/w3m_service/w3m_service_unit_test.dart @@ -25,7 +25,6 @@ void main() { late MockNetworkService mockNetworkService; late MockStorageService mockStorageService; late MockBlockChainService mockBlockChainService; - late MockLedgerService mockEVMService; late MockUrlUtils mockUrlUtils; late Event onSessionDelete = Event(); @@ -81,7 +80,6 @@ void main() { mockStorageService = MockStorageService(); mockBlockChainService = MockBlockChainService(); es = MockExplorerService(); - mockEVMService = MockLedgerService(); mockUrlUtils = MockUrlUtils(); networkService.instance = mockNetworkService; storageService.instance = mockStorageService; @@ -102,10 +100,10 @@ void main() { .thenAnswer((_) => Future.value(true)); when(es.getAssetImageUrl('imageId')).thenReturn('abc'); when(es.getWalletRedirect(anyNamed('name'))).thenReturn(null); - when(mockEVMService.getBalance(any, any)).thenAnswer( - (_) => Future.value(1.0), - ); - when(mockBlockChainService.getIdentity(any, any)).thenAnswer( + // when(mockEVMService.getBalance(any, any)).thenAnswer( + // (_) => Future.value(1.0), + // ); + when(mockBlockChainService.getIdentity(any)).thenAnswer( (realInvocation) => Future.value( const BlockchainIdentity( avatar: null, @@ -126,16 +124,16 @@ void main() { // ); }); - group('Constructor', () { - test('initializes blockchainApiUtils with projectId', () { - W3MService( - projectId: 'projectId', - metadata: metadata, - ); + // group('Constructor', () { + // test('initializes blockchainApiUtils with projectId', () { + // W3MService( + // projectId: 'projectId', + // metadata: metadata, + // ); - expect(blockchainService.instance!.projectId, 'projectId'); - }); - }); + // expect(blockchainService.instance!.projectId, 'projectId'); + // }); + // }); group('init', () { test( @@ -192,8 +190,8 @@ void main() { mockStorageService.setString(StringConstants.selectedChainId, '1'), ).called(1); verify(es.getAssetImageUrl('imageId')).called(1); - verify(mockEVMService.getBalance(any, any)).called(1); - verify(mockBlockChainService.getIdentity(any, any)).called(1); + // verify(mockEVMService.getBalance(any, any)).called(1); + verify(mockBlockChainService.getIdentity(any)).called(1); expect(service.selectedChain, W3MChainPresets.chains['1']); expect(counter, 4); @@ -229,8 +227,8 @@ void main() { mockStorageService.setString(StringConstants.selectedChainId, '1'), ).called(1); verify(es.getAssetImageUrl('imageId')).called(1); - verify(mockEVMService.getBalance(any, any)).called(1); - verify(mockBlockChainService.getIdentity(any, any)).called(1); + // verify(mockEVMService.getBalance(any, any)).called(1); + verify(mockBlockChainService.getIdentity(any)).called(1); expect(service.selectedChain, W3MChainPresets.chains['1']); // Chain swap to polygon @@ -242,8 +240,8 @@ void main() { mockStorageService.setString(StringConstants.selectedChainId, '137'), ).called(1); verify(es.getAssetImageUrl('imageId')).called(1); - verify(mockEVMService.getBalance(any, any)).called(1); - verify(mockBlockChainService.getIdentity(any, any)).called(1); + // verify(mockEVMService.getBalance(any, any)).called(1); + verify(mockBlockChainService.getIdentity(any)).called(1); expect(service.selectedChain, W3MChainPresets.chains['137']); // Setting selected chain to null will disconnect