diff --git a/.github/workflows/pr_test_build.yml b/.github/workflows/pr_test_build.yml index b5fe24f18..4df215e13 100644 --- a/.github/workflows/pr_test_build.yml +++ b/.github/workflows/pr_test_build.yml @@ -104,17 +104,7 @@ jobs: - name: Build generated code run: | cd /opt/android/cake_wallet - cd cw_core && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. - cd cw_evm && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. - cd cw_monero && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. - cd cw_bitcoin && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. - cd cw_haven && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. - cd cw_bitcoin_cash && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. - cd cw_nano && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. - cd cw_solana && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. - cd cw_ethereum && flutter pub get && cd .. - cd cw_polygon && flutter pub get && cd .. - flutter packages pub run build_runner build --delete-conflicting-outputs + ./model_generator.sh - name: Add secrets run: | @@ -159,12 +149,16 @@ jobs: echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart - name: Rename app - run: echo -e "id=com.cakewallet.test\nname=${{ env.BRANCH_NAME }}" > /opt/android/cake_wallet/android/app.properties + run: | + hash=`sha512sum <<<"${{ env.BRANCH_NAME }}"` + substring=${hash:0:15} + echo substring + echo -e "id=com.cakewallet.test_$(substring)\nname=${{ env.BRANCH_NAME }}" > /opt/android/cake_wallet/android/app.properties - name: Build run: | cd /opt/android/cake_wallet - flutter build apk --release + flutter build apk --release --split-per-abi # - name: Push to App Center # run: | @@ -181,21 +175,21 @@ jobs: - name: Rename apk file run: | - cd /opt/android/cake_wallet/build/app/outputs/apk/release + cd /opt/android/cake_wallet/build/app/outputs/flutter-apk mkdir test-apk - cp app-release.apk test-apk/${{env.BRANCH_NAME}}.apk + cp app-arm64-v8a-release.apk test-apk/${{env.BRANCH_NAME}}.apk - name: Upload Artifact uses: kittaakos/upload-artifact-as-is@v0 with: - path: /opt/android/cake_wallet/build/app/outputs/apk/release/test-apk/ + path: /opt/android/cake_wallet/build/app/outputs/flutter-apk/test-apk/ - name: Send Test APK continue-on-error: true uses: adrey/slack-file-upload-action@1.0.5 with: token: ${{ secrets.SLACK_APP_TOKEN }} - path: /opt/android/cake_wallet/build/app/outputs/apk/release/app-release.apk + path: /opt/android/cake_wallet/build/app/outputs/flutter-apk/test-apk/${{env.BRANCH_NAME}}.apk channel: ${{ secrets.SLACK_APK_CHANNEL }} title: "${{ env.BRANCH_NAME }}.apk" filename: ${{ env.BRANCH_NAME }}.apk diff --git a/assets/text/Monerocom_Release_Notes.txt b/assets/text/Monerocom_Release_Notes.txt index 7cf786332..732e58a18 100644 --- a/assets/text/Monerocom_Release_Notes.txt +++ b/assets/text/Monerocom_Release_Notes.txt @@ -1,3 +1,2 @@ -Improve wallet recovery and error tolerance -Enhance Background sync for Monero wallets -Bug fixes \ No newline at end of file +New themes +Bug fixes and enhancements \ No newline at end of file diff --git a/assets/text/Release_Notes.txt b/assets/text/Release_Notes.txt index ac032e354..1c2ec154c 100644 --- a/assets/text/Release_Notes.txt +++ b/assets/text/Release_Notes.txt @@ -1,3 +1,6 @@ +Add Solana wallet Support ALL Bitcoin address types (Legacy, Segwit (both variants), Taproot) Enhance Sending/Receiving flow for Bitcoin -Improve fee calculations in Bitcoin \ No newline at end of file +Improve fee calculations in Bitcoin +New themes +Bug fixes and enhancements \ No newline at end of file diff --git a/cw_bitcoin/lib/bitcoin_receive_page_option.dart b/cw_bitcoin/lib/bitcoin_receive_page_option.dart index cd471ef28..aa3d4a4cd 100644 --- a/cw_bitcoin/lib/bitcoin_receive_page_option.dart +++ b/cw_bitcoin/lib/bitcoin_receive_page_option.dart @@ -2,7 +2,7 @@ import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:cw_core/receive_page_option.dart'; class BitcoinReceivePageOption implements ReceivePageOption { - static const p2wpkh = BitcoinReceivePageOption._('Segwit (P2WPKH)'); + static const p2wpkh = BitcoinReceivePageOption._('Segwit (P2WPKH) (Default)'); static const p2sh = BitcoinReceivePageOption._('Segwit-Compatible (P2SH)'); static const p2tr = BitcoinReceivePageOption._('Taproot (P2TR)'); static const p2wsh = BitcoinReceivePageOption._('Segwit (P2WSH)'); @@ -21,10 +21,10 @@ class BitcoinReceivePageOption implements ReceivePageOption { static const all = [ BitcoinReceivePageOption.silent_payments, BitcoinReceivePageOption.p2wpkh, - BitcoinReceivePageOption.p2sh, BitcoinReceivePageOption.p2tr, BitcoinReceivePageOption.p2wsh, - BitcoinReceivePageOption.p2pkh, + BitcoinReceivePageOption.p2sh, + BitcoinReceivePageOption.p2pkh ]; BitcoinAddressType toType() { diff --git a/cw_core/lib/crypto_currency.dart b/cw_core/lib/crypto_currency.dart index 67581ecb8..ce509015c 100644 --- a/cw_core/lib/crypto_currency.dart +++ b/cw_core/lib/crypto_currency.dart @@ -102,6 +102,7 @@ class CryptoCurrency extends EnumerableItem with Serializable implemen CryptoCurrency.usdcEPoly, CryptoCurrency.kaspa, CryptoCurrency.digibyte, + CryptoCurrency.usdtSol, ]; static const havenCurrencies = [ @@ -246,7 +247,16 @@ class CryptoCurrency extends EnumerableItem with Serializable implemen return CryptoCurrency._rawCurrencyMap[raw]!; } - static CryptoCurrency fromString(String name) { + // TODO: refactor this + static CryptoCurrency fromString(String name, {CryptoCurrency? walletCurrency}) { + try { + return CryptoCurrency.all.firstWhere((element) => + element.title.toLowerCase() == name && + (element.tag == null || + element.tag == walletCurrency?.title || + element.tag == walletCurrency?.tag)); + } catch (_) {} + if (CryptoCurrency._nameCurrencyMap[name.toLowerCase()] == null) { final s = 'Unexpected token: $name for CryptoCurrency fromString'; throw ArgumentError.value(name, 'name', s); diff --git a/cw_evm/lib/evm_chain_wallet.dart b/cw_evm/lib/evm_chain_wallet.dart index ea19a8557..0fb282960 100644 --- a/cw_evm/lib/evm_chain_wallet.dart +++ b/cw_evm/lib/evm_chain_wallet.dart @@ -146,7 +146,7 @@ abstract class EVMChainWalletBase privateKey: _hexPrivateKey, password: _password, ); - walletAddresses.address = _evmChainPrivateKey.address.toString(); + walletAddresses.address = _evmChainPrivateKey.address.hexEip55; await save(); } diff --git a/cw_solana/lib/solana_client.dart b/cw_solana/lib/solana_client.dart index ececc56ba..ea4a9161a 100644 --- a/cw_solana/lib/solana_client.dart +++ b/cw_solana/lib/solana_client.dart @@ -263,7 +263,7 @@ class SolanaWalletClient { required Ed25519HDKeyPair ownerKeypair, List references = const [], }) async { - const commitment = Commitment.finalized; + const commitment = Commitment.confirmed; final latestBlockhash = await _client!.rpcClient.getLatestBlockhash(commitment: commitment).value; @@ -394,9 +394,7 @@ class SolanaWalletClient { funder: ownerKeypair, ); } catch (e) { - throw Exception( - 'Error while creating an associated token account for the recipient: ${e.toString()}', - ); + throw Exception('Insufficient lamports balance to complete this transaction'); } // Input by the user @@ -468,7 +466,10 @@ class SolanaWalletClient { required SignedTx signedTransaction, required Commitment commitment, }) async { - final signature = await _client!.rpcClient.sendTransaction(signedTransaction.encode()); + final signature = await _client!.rpcClient.sendTransaction( + signedTransaction.encode(), + preflightCommitment: commitment, + ); _client!.waitForSignatureStatus(signature, status: commitment); diff --git a/ios/Podfile b/ios/Podfile index 027d48ceb..00b5fd2df 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '11.0' +platform :ios, '12.0' source 'https://github.com/CocoaPods/Specs.git' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. @@ -44,7 +44,7 @@ post_install do |installer| flutter_additional_ios_build_settings(target) target.build_configurations.each do |config| - config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0' + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0' config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ '$(inherited)', diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 2545e90ce..4f3aea7ec 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -7,7 +7,7 @@ PODS: - connectivity_plus (0.0.1): - Flutter - ReachabilitySwift - - CryptoSwift (1.7.1) + - CryptoSwift (1.8.1) - cw_haven (0.0.1): - cw_haven/Boost (= 0.0.1) - cw_haven/Haven (= 0.0.1) @@ -132,9 +132,9 @@ PODS: - permission_handler_apple (9.1.1): - Flutter - ReachabilitySwift (5.0.0) - - SDWebImage (5.16.0): - - SDWebImage/Core (= 5.16.0) - - SDWebImage/Core (5.16.0) + - SDWebImage (5.18.11): + - SDWebImage/Core (= 5.18.11) + - SDWebImage/Core (5.18.11) - sensitive_clipboard (0.0.1): - Flutter - share_plus (0.0.1): @@ -142,9 +142,9 @@ PODS: - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS - - SwiftProtobuf (1.22.0) + - SwiftProtobuf (1.25.2) - SwiftyGif (5.4.4) - - Toast (4.0.0) + - Toast (4.1.0) - uni_links (0.0.1): - Flutter - UnstoppableDomainsResolution (4.0.0): @@ -262,8 +262,8 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: barcode_scan2: 0af2bb63c81b4565aab6cd78278e4c0fa136dbb0 BigInt: f668a80089607f521586bbe29513d708491ef2f7 - connectivity_plus: 413a8857dd5d9f1c399a39130850d02fe0feaf7e - CryptoSwift: d3d18dc357932f7e6d580689e065cf1f176007c1 + connectivity_plus: bf0076dd84a130856aa636df1c71ccaff908fa1d + CryptoSwift: b9c701d6f5011df23794dbf7f2e480a77835d83d cw_haven: b3e54e1fbe7b8e6fda57a93206bc38f8e89b898a cw_monero: 4cf3b96f2da8e95e2ef7d6703dd4d2c509127b7d cw_shared_external: 2972d872b8917603478117c9957dfca611845a92 @@ -287,19 +287,19 @@ SPEC CHECKSUMS: path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 - SDWebImage: 2aea163b50bfcb569a2726b6a754c54a4506fcf6 + SDWebImage: a3ba0b8faac7228c3c8eadd1a55c9c9fe5e16457 sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986 share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 - SwiftProtobuf: 40bd808372cb8706108f22d28f8ab4a6b9bc6989 + SwiftProtobuf: 407a385e97fd206c4fbe880cc84123989167e0d1 SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f - Toast: 91b396c56ee72a5790816f40d3a94dd357abc196 + Toast: ec33c32b8688982cecc6348adeae667c1b9938da uni_links: d97da20c7701486ba192624d99bffaaffcfc298a UnstoppableDomainsResolution: c3c67f4d0a5e2437cb00d4bd50c2e00d6e743841 url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812 wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47 workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6 -PODFILE CHECKSUM: 09df1114e7c360f55770d35a79356bf5446e0100 +PODFILE CHECKSUM: fcb1b8418441a35b438585c9dd8374e722e6c6ca COCOAPODS: 1.12.1 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 1da5bc4bc..7a8b99b49 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -377,7 +377,7 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -523,7 +523,7 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -561,7 +561,7 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -607,9 +607,4 @@ /* End XCConfigurationList section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; - SystemCapabilities = { - com.apple.BackgroundModes = { - enabled = 1; - }; - }; } diff --git a/lib/bitcoin/cw_bitcoin.dart b/lib/bitcoin/cw_bitcoin.dart index 1ce79352c..3e86ad381 100644 --- a/lib/bitcoin/cw_bitcoin.dart +++ b/lib/bitcoin/cw_bitcoin.dart @@ -181,7 +181,7 @@ class CWBitcoin extends Bitcoin { } @override - BitcoinReceivePageOption getSelectedAddressType(Object wallet) { + ReceivePageOption getSelectedAddressType(Object wallet) { final bitcoinWallet = wallet as ElectrumWallet; return BitcoinReceivePageOption.fromType(bitcoinWallet.walletAddresses.addressPageType); } @@ -195,6 +195,22 @@ class CWBitcoin extends Bitcoin { @override List getBitcoinReceivePageOptions() => BitcoinReceivePageOption.all; + @override + BitcoinAddressType getBitcoinAddressType(ReceivePageOption option) { + switch (option) { + case BitcoinReceivePageOption.p2pkh: + return P2pkhAddressType.p2pkh; + case BitcoinReceivePageOption.p2sh: + return P2shAddressType.p2wpkhInP2sh; + case BitcoinReceivePageOption.p2tr: + return SegwitAddresType.p2tr; + case BitcoinReceivePageOption.p2wsh: + return SegwitAddresType.p2wsh; + case BitcoinReceivePageOption.p2wpkh: + default: + return SegwitAddresType.p2wpkh; + } + List getSilentAddresses(Object wallet) { final bitcoinWallet = wallet as ElectrumWallet; return bitcoinWallet.walletAddresses.silentAddresses; diff --git a/lib/core/address_validator.dart b/lib/core/address_validator.dart index d3253aa0f..78c818127 100644 --- a/lib/core/address_validator.dart +++ b/lib/core/address_validator.dart @@ -296,6 +296,16 @@ class AddressValidator extends TextValidator { case CryptoCurrency.sol: return '([^0-9a-zA-Z]|^)[1-9A-HJ-NP-Za-km-z]{43,44}([^0-9a-zA-Z]|\$)'; default: + if (type.tag == CryptoCurrency.eth.title) { + return '0x[0-9a-zA-Z]{42}'; + } + if (type.tag == CryptoCurrency.maticpoly.tag) { + return '0x[0-9a-zA-Z]{42}'; + } + if (type.tag == CryptoCurrency.sol.title) { + return '([^0-9a-zA-Z]|^)[1-9A-HJ-NP-Za-km-z]{43,44}([^0-9a-zA-Z]|\$)'; + } + return null; } } diff --git a/lib/entities/parse_address_from_domain.dart b/lib/entities/parse_address_from_domain.dart index 3ebc08c55..bab0ef51d 100644 --- a/lib/entities/parse_address_from_domain.dart +++ b/lib/entities/parse_address_from_domain.dart @@ -51,7 +51,8 @@ class AddressResolver { } final match = RegExp(addressPattern).firstMatch(raw); - return match?.group(0)?.replaceAllMapped(RegExp('[^0-9a-zA-Z]|bitcoincash:|nano_'), (Match match) { + return match?.group(0)?.replaceAllMapped(RegExp('[^0-9a-zA-Z]|bitcoincash:|nano_'), + (Match match) { String group = match.group(0)!; if (group.startsWith('bitcoincash:') || group.startsWith('nano_')) { return group; @@ -68,7 +69,7 @@ class AddressResolver { return emailRegex.hasMatch(address); } - + // TODO: refactor this to take Crypto currency instead of ticker, or at least pass in the tag as well Future resolve(BuildContext context, String text, String ticker) async { try { if (text.startsWith('@') && !text.substring(1).contains('@')) { @@ -76,7 +77,8 @@ class AddressResolver { final formattedName = text.substring(1); final twitterUser = await TwitterApi.lookupUserByName(userName: formattedName); final addressFromBio = extractAddressByType( - raw: twitterUser.description, type: CryptoCurrency.fromString(ticker)); + raw: twitterUser.description, + type: CryptoCurrency.fromString(ticker, walletCurrency: wallet.currency)); if (addressFromBio != null) { return ParsedAddress.fetchTwitterAddress( address: addressFromBio, @@ -87,8 +89,9 @@ class AddressResolver { final pinnedTweet = twitterUser.pinnedTweet?.text; if (pinnedTweet != null) { - final addressFromPinnedTweet = - extractAddressByType(raw: pinnedTweet, type: CryptoCurrency.fromString(ticker)); + final addressFromPinnedTweet = extractAddressByType( + raw: pinnedTweet, + type: CryptoCurrency.fromString(ticker, walletCurrency: wallet.currency)); if (addressFromPinnedTweet != null) { return ParsedAddress.fetchTwitterAddress( address: addressFromPinnedTweet, @@ -108,11 +111,11 @@ class AddressResolver { final userName = subText.substring(0, hostNameIndex); final mastodonUser = - await MastodonAPI.lookupUserByUserName(userName: userName, apiHost: hostName); + await MastodonAPI.lookupUserByUserName(userName: userName, apiHost: hostName); if (mastodonUser != null) { - String? addressFromBio = - extractAddressByType(raw: mastodonUser.note, type: CryptoCurrency.fromString(ticker)); + String? addressFromBio = extractAddressByType( + raw: mastodonUser.note, type: CryptoCurrency.fromString(ticker)); if (addressFromBio != null) { return ParsedAddress.fetchMastodonAddress( @@ -122,7 +125,7 @@ class AddressResolver { profileName: mastodonUser.username); } else { final pinnedPosts = - await MastodonAPI.getPinnedPosts(userId: mastodonUser.id, apiHost: hostName); + await MastodonAPI.getPinnedPosts(userId: mastodonUser.id, apiHost: hostName); if (pinnedPosts.isNotEmpty) { final userPinnedPostsText = pinnedPosts.map((item) => item.content).join('\n'); @@ -150,7 +153,7 @@ class AddressResolver { } } if (text.hasOnlyEmojis) { - if(settingsStore.lookupsYatService) { + if (settingsStore.lookupsYatService) { if (walletType != WalletType.haven) { final addresses = await yatService.fetchYatAddress(text, ticker); return ParsedAddress.fetchEmojiAddress(addresses: addresses, name: text); @@ -166,7 +169,7 @@ class AddressResolver { } if (unstoppableDomains.any((domain) => name.trim() == domain)) { - if(settingsStore.lookupsUnstoppableDomains) { + if (settingsStore.lookupsUnstoppableDomains) { final address = await fetchUnstoppableDomainAddress(text, ticker); return ParsedAddress.fetchUnstoppableDomainAddress(address: address, name: text); } @@ -182,7 +185,7 @@ class AddressResolver { } if (formattedName.contains(".")) { - if(settingsStore.lookupsOpenAlias) { + if (settingsStore.lookupsOpenAlias) { final txtRecord = await OpenaliasRecord.lookupOpenAliasRecord(formattedName); if (txtRecord != null) { final record = await OpenaliasRecord.fetchAddressAndName( @@ -201,7 +204,11 @@ class AddressResolver { String? addressFromBio = extractAddressByType( raw: nostrUserData.about, type: CryptoCurrency.fromString(ticker)); if (addressFromBio != null) { - return ParsedAddress.nostrAddress(address: addressFromBio, name: text); + return ParsedAddress.nostrAddress( + address: addressFromBio, + name: text, + profileImageUrl: nostrUserData.picture, + profileName: nostrUserData.name); } } } diff --git a/lib/entities/parsed_address.dart b/lib/entities/parsed_address.dart index d87deb9e8..fc8ab2440 100644 --- a/lib/entities/parsed_address.dart +++ b/lib/entities/parsed_address.dart @@ -119,11 +119,17 @@ class ParsedAddress { ); } - factory ParsedAddress.nostrAddress({required String address, required String name}) { + factory ParsedAddress.nostrAddress( + {required String address, + required String name, + required String profileImageUrl, + required String profileName}) { return ParsedAddress( addresses: [address], name: name, parseFrom: ParseFrom.nostr, + profileImageUrl: profileImageUrl, + profileName: profileName, ); } diff --git a/lib/src/screens/dashboard/pages/address_page.dart b/lib/src/screens/dashboard/pages/address_page.dart index ce1ab31f1..044866f5c 100644 --- a/lib/src/screens/dashboard/pages/address_page.dart +++ b/lib/src/screens/dashboard/pages/address_page.dart @@ -1,3 +1,4 @@ +import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart'; import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; import 'package:cake_wallet/di.dart'; @@ -6,7 +7,6 @@ import 'package:cake_wallet/src/screens/monero_accounts/monero_account_list_page import 'package:cake_wallet/anonpay/anonpay_donation_link_info.dart'; import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cw_core/receive_page_option.dart'; -import 'package:cw_bitcoin/bitcoin_receive_page_option.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option_picker.dart'; import 'package:cake_wallet/src/widgets/gradient_background.dart'; import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; @@ -28,7 +28,6 @@ import 'package:keyboard_actions/keyboard_actions.dart'; import 'package:mobx/mobx.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:cake_wallet/themes/extensions/balance_page_theme.dart'; -import 'package:bitcoin_base/bitcoin_base.dart'; class AddressPage extends BasePage { AddressPage({ @@ -235,22 +234,10 @@ class AddressPage extends BasePage { ); } break; - case BitcoinReceivePageOption.p2pkh: - addressListViewModel.setAddressType(P2pkhAddressType.p2pkh); - break; - case BitcoinReceivePageOption.p2sh: - addressListViewModel.setAddressType(P2shAddressType.p2wpkhInP2sh); - break; - case BitcoinReceivePageOption.p2wpkh: - addressListViewModel.setAddressType(SegwitAddresType.p2wpkh); - break; - case BitcoinReceivePageOption.p2tr: - addressListViewModel.setAddressType(SegwitAddresType.p2tr); - break; - case BitcoinReceivePageOption.p2wsh: - addressListViewModel.setAddressType(SegwitAddresType.p2wsh); - break; default: + if (addressListViewModel.type == WalletType.bitcoin) { + addressListViewModel.setAddressType(bitcoin!.getBitcoinAddressType(option)); + } } }); diff --git a/lib/src/screens/send/widgets/extract_address_from_parsed.dart b/lib/src/screens/send/widgets/extract_address_from_parsed.dart index 42e646d58..eb997c11b 100644 --- a/lib/src/screens/send/widgets/extract_address_from_parsed.dart +++ b/lib/src/screens/send/widgets/extract_address_from_parsed.dart @@ -53,6 +53,8 @@ Future extractAddressFromParsed( title = S.of(context).address_detected; content = S.of(context).extracted_address_content('${parsedAddress.name} (Nostr NIP-05)'); address = parsedAddress.addresses.first; + profileImageUrl = parsedAddress.profileImageUrl; + profileName = parsedAddress.profileName; break; case ParseFrom.yatRecord: if (parsedAddress.name.isEmpty) { diff --git a/lib/src/widgets/base_alert_dialog.dart b/lib/src/widgets/base_alert_dialog.dart index e9ef522df..b251e4b45 100644 --- a/lib/src/widgets/base_alert_dialog.dart +++ b/lib/src/widgets/base_alert_dialog.dart @@ -1,4 +1,3 @@ -import 'package:cake_wallet/src/screens/receive/widgets/header_tile.dart'; import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; import 'dart:ui'; import 'package:cake_wallet/src/widgets/section_divider.dart'; diff --git a/lib/store/settings_store.dart b/lib/store/settings_store.dart index fe6c98826..6c91d73f3 100644 --- a/lib/store/settings_store.dart +++ b/lib/store/settings_store.dart @@ -790,9 +790,16 @@ abstract class SettingsStoreBase with Store { final exchangeStatus = ExchangeApiMode.deserialize( raw: sharedPreferences.getInt(PreferencesKey.exchangeStatusKey) ?? ExchangeApiMode.enabled.raw); + final bool isNewInstall = sharedPreferences.getBool(PreferencesKey.isNewInstall) ?? true; + final int defaultTheme; + if (isNewInstall) { + defaultTheme = isMoneroOnly ? ThemeList.moneroDarkTheme.raw : ThemeList.brightTheme.raw; + } else { + defaultTheme = ThemeType.bright.index; + } final savedTheme = initialTheme ?? ThemeList.deserialize( - raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ?? (isMoneroOnly ? ThemeList.moneroDarkTheme.raw : ThemeList.cakeDarkTheme.raw)); + raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ?? defaultTheme); final actionListDisplayMode = ObservableList(); actionListDisplayMode.addAll(deserializeActionlistDisplayModes( sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ?? defaultActionsMode)); @@ -1151,7 +1158,8 @@ abstract class SettingsStoreBase with Store { raw: sharedPreferences.getInt(PreferencesKey.exchangeStatusKey) ?? ExchangeApiMode.enabled.raw); currentTheme = ThemeList.deserialize( - raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ?? (isMoneroOnly ? ThemeList.moneroDarkTheme.raw : ThemeList.cakeDarkTheme.raw)); + raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ?? + (isMoneroOnly ? ThemeList.moneroDarkTheme.raw : ThemeList.brightTheme.raw)); actionlistDisplayMode = ObservableList(); actionlistDisplayMode.addAll(deserializeActionlistDisplayModes( sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ?? defaultActionsMode)); diff --git a/lib/twitter/twitter_api.dart b/lib/twitter/twitter_api.dart index bf6298dae..5acb00e2a 100644 --- a/lib/twitter/twitter_api.dart +++ b/lib/twitter/twitter_api.dart @@ -32,7 +32,10 @@ class TwitterApi { } final Map responseJSON = jsonDecode(response.body) as Map; - if (responseJSON['errors'] != null) { + if (responseJSON['errors'] != null && + !responseJSON['errors'][0]['detail'] + .toString() + .contains("Could not find tweet with pinned_tweet_id")) { throw Exception(responseJSON['errors'][0]['detail']); } @@ -40,20 +43,24 @@ class TwitterApi { } static Tweet? _getPinnedTweet(Map responseJSON) { - final tweetId = responseJSON['data']['pinned_tweet_id'] as String?; - if (tweetId == null || responseJSON['includes'] == null) return null; + try { + final tweetId = responseJSON['data']['pinned_tweet_id'] as String?; + if (tweetId == null || responseJSON['includes'] == null) return null; - final tweetIncludes = List.from(responseJSON['includes']['tweets'] as List); - final pinnedTweetData = tweetIncludes.firstWhere( - (tweet) => tweet['id'] == tweetId, - orElse: () => null, - ) as Map?; + final tweetIncludes = List.from(responseJSON['includes']['tweets'] as List); + final pinnedTweetData = tweetIncludes.firstWhere( + (tweet) => tweet['id'] == tweetId, + orElse: () => null, + ) as Map?; - if (pinnedTweetData == null) return null; + if (pinnedTweetData == null) return null; - final pinnedTweetText = - (pinnedTweetData['note_tweet']?['text'] ?? pinnedTweetData['text']) as String; + final pinnedTweetText = + (pinnedTweetData['note_tweet']?['text'] ?? pinnedTweetData['text']) as String; - return Tweet(id: tweetId, text: pinnedTweetText); + return Tweet(id: tweetId, text: pinnedTweetText); + } catch (e) { + return null; + } } } diff --git a/lib/view_model/exchange/exchange_trade_view_model.dart b/lib/view_model/exchange/exchange_trade_view_model.dart index 93877a525..0d40ae240 100644 --- a/lib/view_model/exchange/exchange_trade_view_model.dart +++ b/lib/view_model/exchange/exchange_trade_view_model.dart @@ -162,9 +162,14 @@ abstract class ExchangeTradeViewModelBase with Store { wallet.currency == CryptoCurrency.maticpoly && tradesStore.trade!.from.tag == CryptoCurrency.maticpoly.tag; + bool _isSplToken() => + wallet.currency == CryptoCurrency.sol && + tradesStore.trade!.from.tag == CryptoCurrency.sol.title; + return tradesStore.trade!.from == wallet.currency || tradesStore.trade!.provider == ExchangeProviderDescription.xmrto || _isEthToken() || - _isPolygonToken(); + _isPolygonToken() || + _isSplToken(); } } diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 05996a674..75a78404f 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,7 +5,7 @@ import FlutterMacOS import Foundation -import connectivity_plus_macos +import connectivity_plus import cw_monero import device_info_plus import devicelocale diff --git a/macos/Podfile.lock b/macos/Podfile.lock index fcbe1d733..106a8a652 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -1,5 +1,5 @@ PODS: - - connectivity_plus_macos (0.0.1): + - connectivity_plus (0.0.1): - FlutterMacOS - ReachabilitySwift - cw_monero (0.0.1): @@ -51,7 +51,7 @@ PODS: - FlutterMacOS DEPENDENCIES: - - connectivity_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus_macos/macos`) + - connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos`) - cw_monero (from `Flutter/ephemeral/.symlinks/plugins/cw_monero/macos`) - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) - devicelocale (from `Flutter/ephemeral/.symlinks/plugins/devicelocale/macos`) @@ -73,8 +73,8 @@ SPEC REPOS: - ReachabilitySwift EXTERNAL SOURCES: - connectivity_plus_macos: - :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus_macos/macos + connectivity_plus: + :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos cw_monero: :path: Flutter/ephemeral/.symlinks/plugins/cw_monero/macos device_info_plus: @@ -105,8 +105,8 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos SPEC CHECKSUMS: - connectivity_plus_macos: f6e86fd000e971d361e54b5afcadc8c8fa773308 - cw_monero: f8b7f104508efba2591548e76b5c058d05cba3f0 + connectivity_plus: 18d3c32514c886e046de60e9c13895109866c747 + cw_monero: ec03de55a19c4a2b174ea687e0f4202edc716fa4 device_info_plus: 5401765fde0b8d062a2f8eb65510fb17e77cf07f devicelocale: 9f0f36ac651cabae2c33f32dcff4f32b61c38225 flutter_inappwebview_macos: 9600c9df9fdb346aaa8933812009f8d94304203d @@ -123,6 +123,6 @@ SPEC CHECKSUMS: url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95 wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269 -PODFILE CHECKSUM: 5107934592df7813b33d744aebc8ddc6b5a5445f +PODFILE CHECKSUM: 65ec1541137fb5b35d00490dec1bb48d4d9586bb COCOAPODS: 1.12.1 diff --git a/pubspec_base.yaml b/pubspec_base.yaml index 758287601..d4bf981cd 100644 --- a/pubspec_base.yaml +++ b/pubspec_base.yaml @@ -55,7 +55,7 @@ dependencies: basic_utils: ^5.6.1 get_it: ^7.2.0 # connectivity: ^3.0.3 - connectivity_plus: ^2.3.5 + connectivity_plus: ^5.0.2 keyboard_actions: ^4.0.1 another_flushbar: ^1.12.29 archive: ^3.3.0 @@ -107,6 +107,10 @@ dependencies: polyseed: ^0.0.2 nostr_tools: ^1.0.9 solana: ^0.30.1 + bitcoin_base: + git: + url: https://github.com/cake-tech/bitcoin_base.git + ref: cake-update-v1 dev_dependencies: flutter_test: diff --git a/scripts/android/app_env.sh b/scripts/android/app_env.sh index 9251ec31a..fa3701fa7 100644 --- a/scripts/android/app_env.sh +++ b/scripts/android/app_env.sh @@ -15,15 +15,15 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN) APP_ANDROID_TYPE=$1 MONERO_COM_NAME="Monero.com" -MONERO_COM_VERSION="1.10.3" -MONERO_COM_BUILD_NUMBER=75 +MONERO_COM_VERSION="1.11.0" +MONERO_COM_BUILD_NUMBER=77 MONERO_COM_BUNDLE_ID="com.monero.app" MONERO_COM_PACKAGE="com.monero.app" MONERO_COM_SCHEME="monero.com" CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_VERSION="4.14.0" -CAKEWALLET_BUILD_NUMBER=193 +CAKEWALLET_BUILD_NUMBER=196 CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet" CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet" CAKEWALLET_SCHEME="cakewallet" diff --git a/scripts/ios/app_env.sh b/scripts/ios/app_env.sh index 47d80013c..31f0b9548 100644 --- a/scripts/ios/app_env.sh +++ b/scripts/ios/app_env.sh @@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN) APP_IOS_TYPE=$1 MONERO_COM_NAME="Monero.com" -MONERO_COM_VERSION="1.10.3" -MONERO_COM_BUILD_NUMBER=73 +MONERO_COM_VERSION="1.11.0" +MONERO_COM_BUILD_NUMBER=75 MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_VERSION="4.14.0" -CAKEWALLET_BUILD_NUMBER=213 +CAKEWALLET_BUILD_NUMBER=215 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" HAVEN_NAME="Haven" diff --git a/scripts/macos/app_env.sh b/scripts/macos/app_env.sh index 49edd9acb..4dec47f40 100755 --- a/scripts/macos/app_env.sh +++ b/scripts/macos/app_env.sh @@ -16,13 +16,13 @@ if [ -n "$1" ]; then fi MONERO_COM_NAME="Monero.com" -MONERO_COM_VERSION="1.0.3" -MONERO_COM_BUILD_NUMBER=5 +MONERO_COM_VERSION="1.1.0" +MONERO_COM_BUILD_NUMBER=7 MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="1.6.3" -CAKEWALLET_BUILD_NUMBER=53 +CAKEWALLET_VERSION="1.7.0" +CAKEWALLET_BUILD_NUMBER=55 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then diff --git a/tool/configure.dart b/tool/configure.dart index 2dd772bbe..10b573655 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -61,6 +61,7 @@ Future main(List args) async { Future generateBitcoin(bool hasImplementation) async { final outputFile = File(bitcoinOutputPath); const bitcoinCommonHeaders = """ +import 'package:cw_core/receive_page_option.dart'; import 'package:cw_core/unspent_transaction_output.dart'; import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; @@ -70,7 +71,8 @@ import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/wallet_service.dart'; import 'package:cake_wallet/view_model/send/output.dart'; import 'package:cw_core/wallet_type.dart'; -import 'package:hive/hive.dart';"""; +import 'package:hive/hive.dart'; +import 'package:bitcoin_base/bitcoin_base.dart';"""; const bitcoinCWHeaders = """ import 'package:cw_bitcoin/bitcoin_receive_page_option.dart'; import 'package:cw_bitcoin/electrum_wallet.dart'; @@ -83,7 +85,6 @@ import 'package:cw_bitcoin/bitcoin_amount_format.dart'; import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart'; import 'package:cw_bitcoin/litecoin_wallet_service.dart'; -import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:mobx/mobx.dart'; """; const bitcoinCwPart = "part 'cw_bitcoin.dart';"; @@ -145,6 +146,7 @@ abstract class Bitcoin { Future setAddressType(Object wallet, dynamic option); BitcoinReceivePageOption getSelectedAddressType(Object wallet); + BitcoinAddressType getBitcoinAddressType(ReceivePageOption option); bool hasSelectedSilentPayments(Object wallet); List getBitcoinReceivePageOptions(); } @@ -908,6 +910,7 @@ import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_service.dart'; import 'package:hive/hive.dart'; +import 'package:solana/solana.dart'; """; const solanaCWHeaders = """ @@ -918,7 +921,6 @@ import 'package:cw_solana/solana_wallet_service.dart'; import 'package:cw_solana/solana_transaction_info.dart'; import 'package:cw_solana/solana_transaction_credentials.dart'; import 'package:cw_solana/solana_wallet_creation_credentials.dart'; -import 'package:solana/solana.dart'; """; const solanaCwPart = "part 'cw_solana.dart';"; const solanaContent = """ @@ -946,10 +948,10 @@ abstract class Solana { List outputs, { required CryptoCurrency currency, }); - List getSPLTokenCurrencies(WalletBase wallet); + List getSPLTokenCurrencies(WalletBase wallet); Future addSPLToken(WalletBase wallet, CryptoCurrency token); Future deleteSPLToken(WalletBase wallet, CryptoCurrency token); - Future getSPLToken(WalletBase wallet, String contractAddress); + Future getSPLToken(WalletBase wallet, String contractAddress); CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction); double getTransactionAmountRaw(TransactionInfo transactionInfo);