New versions (#1312)

* New versions Fix issues with Monero.com * Add sending for Solana tokens exchanges * Add default keyword for P2WPKH [skip ci] * chore: Switch solana commitment to confirmed to reduced blockhash expiration (#1313) * Modify test workflow to send arm64-v8a build only * Fix workflow build path * Remove unnecessary reverse of txId * Show case sensitive evm wallet address * Revert default Cake Theme add custom package id for test builds * Fix workflow script * Fix workflow * hash branch name * hash branch name * Update versions * Add user image to Nostr Add fetching address from text for tokens * Fix test app package id * fix: Solana message improvement (#1316) --------- Co-authored-by: Adegoke David <64401859+Blazebrain@users.noreply.github.com>

Omar Hatem committed Mar 4, 2024 at 19:32 UTC c7deeaea9b65330c5fe9894da3ee4f4ab9cd9d11
28 files changed +186 -138
.github/workflows/pr_test_build.yml
+11 -17
@@ -104,17 +104,7 @@ jobs:
104 - name: Build generated code
105 run: |
106 cd /opt/android/cake_wallet
107 - cd cw_core && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
108 - cd cw_evm && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
109 - cd cw_monero && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
110 - cd cw_bitcoin && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
111 - cd cw_haven && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
112 - cd cw_bitcoin_cash && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
113 - cd cw_nano && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
114 - cd cw_solana && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
115 - cd cw_ethereum && flutter pub get && cd ..
116 - cd cw_polygon && flutter pub get && cd ..
117 - flutter packages pub run build_runner build --delete-conflicting-outputs
107 + ./model_generator.sh
108
109 - name: Add secrets
110 run: |
@@ -159,12 +149,16 @@ jobs:
149 echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
150
151 - name: Rename app
162 - run: echo -e "id=com.cakewallet.test\nname=${{ env.BRANCH_NAME }}" > /opt/android/cake_wallet/android/app.properties
152 + run: |
153 + hash=`sha512sum <<<"${{ env.BRANCH_NAME }}"`
154 + substring=${hash:0:15}
155 + echo substring
156 + echo -e "id=com.cakewallet.test_$(substring)\nname=${{ env.BRANCH_NAME }}" > /opt/android/cake_wallet/android/app.properties
157
158 - name: Build
159 run: |
160 cd /opt/android/cake_wallet
167 - flutter build apk --release
161 + flutter build apk --release --split-per-abi
162
163 # - name: Push to App Center
164 # run: |
@@ -181,21 +175,21 @@ jobs:
175
176 - name: Rename apk file
177 run: |
184 - cd /opt/android/cake_wallet/build/app/outputs/apk/release
178 + cd /opt/android/cake_wallet/build/app/outputs/flutter-apk
179 mkdir test-apk
186 - cp app-release.apk test-apk/${{env.BRANCH_NAME}}.apk
180 + cp app-arm64-v8a-release.apk test-apk/${{env.BRANCH_NAME}}.apk
181
182 - name: Upload Artifact
183 uses: kittaakos/upload-artifact-as-is@v0
184 with:
191 - path: /opt/android/cake_wallet/build/app/outputs/apk/release/test-apk/
185 + path: /opt/android/cake_wallet/build/app/outputs/flutter-apk/test-apk/
186
187 - name: Send Test APK
188 continue-on-error: true
189 uses: adrey/slack-file-upload-action@1.0.5
190 with:
191 token: ${{ secrets.SLACK_APP_TOKEN }}
198 - path: /opt/android/cake_wallet/build/app/outputs/apk/release/app-release.apk
192 + path: /opt/android/cake_wallet/build/app/outputs/flutter-apk/test-apk/${{env.BRANCH_NAME}}.apk
193 channel: ${{ secrets.SLACK_APK_CHANNEL }}
194 title: "${{ env.BRANCH_NAME }}.apk"
195 filename: ${{ env.BRANCH_NAME }}.apk
assets/text/Monerocom_Release_Notes.txt
+2 -3
@@ -1,3 +1,2 @@
1 -Improve wallet recovery and error tolerance
2 -Enhance Background sync for Monero wallets
3 -Bug fixes
\ No newline at end of file
1 +New themes
2 +Bug fixes and enhancements
\ No newline at end of file
assets/text/Release_Notes.txt
+4 -1
@@ -1,3 +1,6 @@
1 +Add Solana wallet
2 Support ALL Bitcoin address types (Legacy, Segwit (both variants), Taproot)
3 Enhance Sending/Receiving flow for Bitcoin
3 -Improve fee calculations in Bitcoin
\ No newline at end of file
4 +Improve fee calculations in Bitcoin
5 +New themes
6 +Bug fixes and enhancements
\ No newline at end of file
cw_bitcoin/lib/bitcoin_receive_page_option.dart
+2 -2
@@ -2,7 +2,7 @@ import 'package:bitcoin_base/bitcoin_base.dart';
2 import 'package:cw_core/receive_page_option.dart';
3
4 class BitcoinReceivePageOption implements ReceivePageOption {
5 - static const p2wpkh = BitcoinReceivePageOption._('Segwit (P2WPKH)');
5 + static const p2wpkh = BitcoinReceivePageOption._('Segwit (P2WPKH) (Default)');
6 static const p2sh = BitcoinReceivePageOption._('Segwit-Compatible (P2SH)');
7 static const p2tr = BitcoinReceivePageOption._('Taproot (P2TR)');
8 static const p2wsh = BitcoinReceivePageOption._('Segwit (P2WSH)');
@@ -18,9 +18,9 @@ class BitcoinReceivePageOption implements ReceivePageOption {
18
19 static const all = [
20 BitcoinReceivePageOption.p2wpkh,
21 - BitcoinReceivePageOption.p2sh,
21 BitcoinReceivePageOption.p2tr,
22 BitcoinReceivePageOption.p2wsh,
23 + BitcoinReceivePageOption.p2sh,
24 BitcoinReceivePageOption.p2pkh
25 ];
26
cw_bitcoin/lib/electrum_wallet.dart
+3 -11
@@ -35,7 +35,6 @@ import 'package:cw_core/utils/file.dart';
35 import 'package:cw_core/wallet_base.dart';
36 import 'package:cw_core/wallet_info.dart';
37 import 'package:flutter/foundation.dart';
38 -import 'package:hex/hex.dart';
38 import 'package:hive/hive.dart';
39 import 'package:mobx/mobx.dart';
40 import 'package:rxdart/subjects.dart';
@@ -623,16 +622,9 @@ abstract class ElectrumWalletBase
622 final ins = <bitcoin_base.BtcTransaction>[];
623
624 for (final vin in original.inputs) {
626 - try {
627 - final id = HEX.encode(HEX.decode(vin.txId).reversed.toList());
628 - final txHex = await electrumClient.getTransactionHex(hash: id);
629 - final tx = bitcoin_base.BtcTransaction.fromRaw(txHex);
630 - ins.add(tx);
631 - } catch (_) {
632 - ins.add(bitcoin_base.BtcTransaction.fromRaw(
633 - await electrumClient.getTransactionHex(hash: vin.txId),
634 - ));
635 - }
625 + final txHex = await electrumClient.getTransactionHex(hash: vin.txId);
626 + final tx = bitcoin_base.BtcTransaction.fromRaw(txHex);
627 + ins.add(tx);
628 }
629
630 return ElectrumTransactionBundle(original,
cw_core/lib/crypto_currency.dart
+11 -1
@@ -102,6 +102,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
102 CryptoCurrency.usdcEPoly,
103 CryptoCurrency.kaspa,
104 CryptoCurrency.digibyte,
105 + CryptoCurrency.usdtSol,
106 ];
107
108 static const havenCurrencies = [
@@ -246,7 +247,16 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
247 return CryptoCurrency._rawCurrencyMap[raw]!;
248 }
249
249 - static CryptoCurrency fromString(String name) {
250 + // TODO: refactor this
251 + static CryptoCurrency fromString(String name, {CryptoCurrency? walletCurrency}) {
252 + try {
253 + return CryptoCurrency.all.firstWhere((element) =>
254 + element.title.toLowerCase() == name &&
255 + (element.tag == null ||
256 + element.tag == walletCurrency?.title ||
257 + element.tag == walletCurrency?.tag));
258 + } catch (_) {}
259 +
260 if (CryptoCurrency._nameCurrencyMap[name.toLowerCase()] == null) {
261 final s = 'Unexpected token: $name for CryptoCurrency fromString';
262 throw ArgumentError.value(name, 'name', s);
cw_evm/lib/evm_chain_wallet.dart
+1 -1
@@ -146,7 +146,7 @@ abstract class EVMChainWalletBase
146 privateKey: _hexPrivateKey,
147 password: _password,
148 );
149 - walletAddresses.address = _evmChainPrivateKey.address.toString();
149 + walletAddresses.address = _evmChainPrivateKey.address.hexEip55;
150 await save();
151 }
152
cw_solana/lib/solana_client.dart
+6 -5
@@ -263,7 +263,7 @@ class SolanaWalletClient {
263 required Ed25519HDKeyPair ownerKeypair,
264 List<String> references = const [],
265 }) async {
266 - const commitment = Commitment.finalized;
266 + const commitment = Commitment.confirmed;
267
268 final latestBlockhash =
269 await _client!.rpcClient.getLatestBlockhash(commitment: commitment).value;
@@ -394,9 +394,7 @@ class SolanaWalletClient {
394 funder: ownerKeypair,
395 );
396 } catch (e) {
397 - throw Exception(
398 - 'Error while creating an associated token account for the recipient: ${e.toString()}',
399 - );
397 + throw Exception('Insufficient lamports balance to complete this transaction');
398 }
399
400 // Input by the user
@@ -468,7 +466,10 @@ class SolanaWalletClient {
466 required SignedTx signedTransaction,
467 required Commitment commitment,
468 }) async {
471 - final signature = await _client!.rpcClient.sendTransaction(signedTransaction.encode());
469 + final signature = await _client!.rpcClient.sendTransaction(
470 + signedTransaction.encode(),
471 + preflightCommitment: commitment,
472 + );
473
474 _client!.waitForSignatureStatus(signature, status: commitment);
475
ios/Podfile
+2 -2
@@ -1,5 +1,5 @@
1 # Uncomment this line to define a global platform for your project
2 -platform :ios, '11.0'
2 +platform :ios, '12.0'
3 source 'https://github.com/CocoaPods/Specs.git'
4
5 # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
@@ -44,7 +44,7 @@ post_install do |installer|
44 flutter_additional_ios_build_settings(target)
45
46 target.build_configurations.each do |config|
47 - config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0'
47 + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0'
48 config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
49 '$(inherited)',
50
ios/Podfile.lock
+12 -12
@@ -7,7 +7,7 @@ PODS:
7 - connectivity_plus (0.0.1):
8 - Flutter
9 - ReachabilitySwift
10 - - CryptoSwift (1.7.1)
10 + - CryptoSwift (1.8.1)
11 - cw_haven (0.0.1):
12 - cw_haven/Boost (= 0.0.1)
13 - cw_haven/Haven (= 0.0.1)
@@ -132,9 +132,9 @@ PODS:
132 - permission_handler_apple (9.1.1):
133 - Flutter
134 - ReachabilitySwift (5.0.0)
135 - - SDWebImage (5.16.0):
136 - - SDWebImage/Core (= 5.16.0)
137 - - SDWebImage/Core (5.16.0)
135 + - SDWebImage (5.18.11):
136 + - SDWebImage/Core (= 5.18.11)
137 + - SDWebImage/Core (5.18.11)
138 - sensitive_clipboard (0.0.1):
139 - Flutter
140 - share_plus (0.0.1):
@@ -142,9 +142,9 @@ PODS:
142 - shared_preferences_foundation (0.0.1):
143 - Flutter
144 - FlutterMacOS
145 - - SwiftProtobuf (1.22.0)
145 + - SwiftProtobuf (1.25.2)
146 - SwiftyGif (5.4.4)
147 - - Toast (4.0.0)
147 + - Toast (4.1.0)
148 - uni_links (0.0.1):
149 - Flutter
150 - UnstoppableDomainsResolution (4.0.0):
@@ -262,8 +262,8 @@ EXTERNAL SOURCES:
262 SPEC CHECKSUMS:
263 barcode_scan2: 0af2bb63c81b4565aab6cd78278e4c0fa136dbb0
264 BigInt: f668a80089607f521586bbe29513d708491ef2f7
265 - connectivity_plus: 413a8857dd5d9f1c399a39130850d02fe0feaf7e
266 - CryptoSwift: d3d18dc357932f7e6d580689e065cf1f176007c1
265 + connectivity_plus: bf0076dd84a130856aa636df1c71ccaff908fa1d
266 + CryptoSwift: b9c701d6f5011df23794dbf7f2e480a77835d83d
267 cw_haven: b3e54e1fbe7b8e6fda57a93206bc38f8e89b898a
268 cw_monero: 4cf3b96f2da8e95e2ef7d6703dd4d2c509127b7d
269 cw_shared_external: 2972d872b8917603478117c9957dfca611845a92
@@ -287,19 +287,19 @@ SPEC CHECKSUMS:
287 path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
288 permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
289 ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
290 - SDWebImage: 2aea163b50bfcb569a2726b6a754c54a4506fcf6
290 + SDWebImage: a3ba0b8faac7228c3c8eadd1a55c9c9fe5e16457
291 sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986
292 share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
293 shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
294 - SwiftProtobuf: 40bd808372cb8706108f22d28f8ab4a6b9bc6989
294 + SwiftProtobuf: 407a385e97fd206c4fbe880cc84123989167e0d1
295 SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
296 - Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
296 + Toast: ec33c32b8688982cecc6348adeae667c1b9938da
297 uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
298 UnstoppableDomainsResolution: c3c67f4d0a5e2437cb00d4bd50c2e00d6e743841
299 url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812
300 wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47
301 workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6
302
303 -PODFILE CHECKSUM: 09df1114e7c360f55770d35a79356bf5446e0100
303 +PODFILE CHECKSUM: fcb1b8418441a35b438585c9dd8374e722e6c6ca
304
305 COCOAPODS: 1.12.1
ios/Runner.xcodeproj/project.pbxproj
+3 -8
@@ -377,7 +377,7 @@
377 "$(PROJECT_DIR)/Flutter",
378 );
379 INFOPLIST_FILE = Runner/Info.plist;
380 - IPHONEOS_DEPLOYMENT_TARGET = 11.0;
380 + IPHONEOS_DEPLOYMENT_TARGET = 12.0;
381 LD_RUNPATH_SEARCH_PATHS = (
382 "$(inherited)",
383 "@executable_path/Frameworks",
@@ -523,7 +523,7 @@
523 "$(PROJECT_DIR)/Flutter",
524 );
525 INFOPLIST_FILE = Runner/Info.plist;
526 - IPHONEOS_DEPLOYMENT_TARGET = 11.0;
526 + IPHONEOS_DEPLOYMENT_TARGET = 12.0;
527 LD_RUNPATH_SEARCH_PATHS = (
528 "$(inherited)",
529 "@executable_path/Frameworks",
@@ -561,7 +561,7 @@
561 "$(PROJECT_DIR)/Flutter",
562 );
563 INFOPLIST_FILE = Runner/Info.plist;
564 - IPHONEOS_DEPLOYMENT_TARGET = 11.0;
564 + IPHONEOS_DEPLOYMENT_TARGET = 12.0;
565 LD_RUNPATH_SEARCH_PATHS = (
566 "$(inherited)",
567 "@executable_path/Frameworks",
@@ -607,9 +607,4 @@
607 /* End XCConfigurationList section */
608 };
609 rootObject = 97C146E61CF9000F007C117D /* Project object */;
610 - SystemCapabilities = {
611 - com.apple.BackgroundModes = {
612 - enabled = 1;
613 - };
614 - };
610 }
lib/bitcoin/cw_bitcoin.dart
+19 -2
@@ -181,11 +181,28 @@ class CWBitcoin extends Bitcoin {
181 }
182
183 @override
184 - BitcoinReceivePageOption getSelectedAddressType(Object wallet) {
184 + ReceivePageOption getSelectedAddressType(Object wallet) {
185 final bitcoinWallet = wallet as ElectrumWallet;
186 return BitcoinReceivePageOption.fromType(bitcoinWallet.walletAddresses.addressPageType);
187 }
188
189 @override
190 - List<BitcoinReceivePageOption> getBitcoinReceivePageOptions() => BitcoinReceivePageOption.all;
190 + List<ReceivePageOption> getBitcoinReceivePageOptions() => BitcoinReceivePageOption.all;
191 +
192 + @override
193 + BitcoinAddressType getBitcoinAddressType(ReceivePageOption option) {
194 + switch (option) {
195 + case BitcoinReceivePageOption.p2pkh:
196 + return P2pkhAddressType.p2pkh;
197 + case BitcoinReceivePageOption.p2sh:
198 + return P2shAddressType.p2wpkhInP2sh;
199 + case BitcoinReceivePageOption.p2tr:
200 + return SegwitAddresType.p2tr;
201 + case BitcoinReceivePageOption.p2wsh:
202 + return SegwitAddresType.p2wsh;
203 + case BitcoinReceivePageOption.p2wpkh:
204 + default:
205 + return SegwitAddresType.p2wpkh;
206 + }
207 + }
208 }
lib/core/address_validator.dart
+10
@@ -295,6 +295,16 @@ class AddressValidator extends TextValidator {
295 case CryptoCurrency.sol:
296 return '([^0-9a-zA-Z]|^)[1-9A-HJ-NP-Za-km-z]{43,44}([^0-9a-zA-Z]|\$)';
297 default:
298 + if (type.tag == CryptoCurrency.eth.title) {
299 + return '0x[0-9a-zA-Z]{42}';
300 + }
301 + if (type.tag == CryptoCurrency.maticpoly.tag) {
302 + return '0x[0-9a-zA-Z]{42}';
303 + }
304 + if (type.tag == CryptoCurrency.sol.title) {
305 + return '([^0-9a-zA-Z]|^)[1-9A-HJ-NP-Za-km-z]{43,44}([^0-9a-zA-Z]|\$)';
306 + }
307 +
308 return null;
309 }
310 }
lib/entities/parse_address_from_domain.dart
+20 -13
@@ -51,7 +51,8 @@ class AddressResolver {
51 }
52
53 final match = RegExp(addressPattern).firstMatch(raw);
54 - return match?.group(0)?.replaceAllMapped(RegExp('[^0-9a-zA-Z]|bitcoincash:|nano_'), (Match match) {
54 + return match?.group(0)?.replaceAllMapped(RegExp('[^0-9a-zA-Z]|bitcoincash:|nano_'),
55 + (Match match) {
56 String group = match.group(0)!;
57 if (group.startsWith('bitcoincash:') || group.startsWith('nano_')) {
58 return group;
@@ -68,7 +69,7 @@ class AddressResolver {
69 return emailRegex.hasMatch(address);
70 }
71
71 -
72 + // TODO: refactor this to take Crypto currency instead of ticker, or at least pass in the tag as well
73 Future<ParsedAddress> resolve(BuildContext context, String text, String ticker) async {
74 try {
75 if (text.startsWith('@') && !text.substring(1).contains('@')) {
@@ -76,7 +77,8 @@ class AddressResolver {
77 final formattedName = text.substring(1);
78 final twitterUser = await TwitterApi.lookupUserByName(userName: formattedName);
79 final addressFromBio = extractAddressByType(
79 - raw: twitterUser.description, type: CryptoCurrency.fromString(ticker));
80 + raw: twitterUser.description,
81 + type: CryptoCurrency.fromString(ticker, walletCurrency: wallet.currency));
82 if (addressFromBio != null) {
83 return ParsedAddress.fetchTwitterAddress(
84 address: addressFromBio,
@@ -87,8 +89,9 @@ class AddressResolver {
89
90 final pinnedTweet = twitterUser.pinnedTweet?.text;
91 if (pinnedTweet != null) {
90 - final addressFromPinnedTweet =
91 - extractAddressByType(raw: pinnedTweet, type: CryptoCurrency.fromString(ticker));
92 + final addressFromPinnedTweet = extractAddressByType(
93 + raw: pinnedTweet,
94 + type: CryptoCurrency.fromString(ticker, walletCurrency: wallet.currency));
95 if (addressFromPinnedTweet != null) {
96 return ParsedAddress.fetchTwitterAddress(
97 address: addressFromPinnedTweet,
@@ -108,11 +111,11 @@ class AddressResolver {
111 final userName = subText.substring(0, hostNameIndex);
112
113 final mastodonUser =
111 - await MastodonAPI.lookupUserByUserName(userName: userName, apiHost: hostName);
114 + await MastodonAPI.lookupUserByUserName(userName: userName, apiHost: hostName);
115
116 if (mastodonUser != null) {
114 - String? addressFromBio =
115 - extractAddressByType(raw: mastodonUser.note, type: CryptoCurrency.fromString(ticker));
117 + String? addressFromBio = extractAddressByType(
118 + raw: mastodonUser.note, type: CryptoCurrency.fromString(ticker));
119
120 if (addressFromBio != null) {
121 return ParsedAddress.fetchMastodonAddress(
@@ -122,7 +125,7 @@ class AddressResolver {
125 profileName: mastodonUser.username);
126 } else {
127 final pinnedPosts =
125 - await MastodonAPI.getPinnedPosts(userId: mastodonUser.id, apiHost: hostName);
128 + await MastodonAPI.getPinnedPosts(userId: mastodonUser.id, apiHost: hostName);
129
130 if (pinnedPosts.isNotEmpty) {
131 final userPinnedPostsText = pinnedPosts.map((item) => item.content).join('\n');
@@ -150,7 +153,7 @@ class AddressResolver {
153 }
154 }
155 if (text.hasOnlyEmojis) {
153 - if(settingsStore.lookupsYatService) {
156 + if (settingsStore.lookupsYatService) {
157 if (walletType != WalletType.haven) {
158 final addresses = await yatService.fetchYatAddress(text, ticker);
159 return ParsedAddress.fetchEmojiAddress(addresses: addresses, name: text);
@@ -166,7 +169,7 @@ class AddressResolver {
169 }
170
171 if (unstoppableDomains.any((domain) => name.trim() == domain)) {
169 - if(settingsStore.lookupsUnstoppableDomains) {
172 + if (settingsStore.lookupsUnstoppableDomains) {
173 final address = await fetchUnstoppableDomainAddress(text, ticker);
174 return ParsedAddress.fetchUnstoppableDomainAddress(address: address, name: text);
175 }
@@ -182,7 +185,7 @@ class AddressResolver {
185 }
186
187 if (formattedName.contains(".")) {
185 - if(settingsStore.lookupsOpenAlias) {
188 + if (settingsStore.lookupsOpenAlias) {
189 final txtRecord = await OpenaliasRecord.lookupOpenAliasRecord(formattedName);
190 if (txtRecord != null) {
191 final record = await OpenaliasRecord.fetchAddressAndName(
@@ -201,7 +204,11 @@ class AddressResolver {
204 String? addressFromBio = extractAddressByType(
205 raw: nostrUserData.about, type: CryptoCurrency.fromString(ticker));
206 if (addressFromBio != null) {
204 - return ParsedAddress.nostrAddress(address: addressFromBio, name: text);
207 + return ParsedAddress.nostrAddress(
208 + address: addressFromBio,
209 + name: text,
210 + profileImageUrl: nostrUserData.picture,
211 + profileName: nostrUserData.name);
212 }
213 }
214 }
lib/entities/parsed_address.dart
+7 -1
@@ -119,11 +119,17 @@ class ParsedAddress {
119 );
120 }
121
122 - factory ParsedAddress.nostrAddress({required String address, required String name}) {
122 + factory ParsedAddress.nostrAddress(
123 + {required String address,
124 + required String name,
125 + required String profileImageUrl,
126 + required String profileName}) {
127 return ParsedAddress(
128 addresses: [address],
129 name: name,
130 parseFrom: ParseFrom.nostr,
131 + profileImageUrl: profileImageUrl,
132 + profileName: profileName,
133 );
134 }
135
lib/src/screens/dashboard/pages/address_page.dart
+4 -17
@@ -1,3 +1,4 @@
1 +import 'package:cake_wallet/bitcoin/bitcoin.dart';
2 import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart';
3 import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
4 import 'package:cake_wallet/di.dart';
@@ -6,7 +7,6 @@ import 'package:cake_wallet/src/screens/monero_accounts/monero_account_list_page
7 import 'package:cake_wallet/anonpay/anonpay_donation_link_info.dart';
8 import 'package:cake_wallet/entities/preferences_key.dart';
9 import 'package:cw_core/receive_page_option.dart';
9 -import 'package:cw_bitcoin/bitcoin_receive_page_option.dart';
10 import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option_picker.dart';
11 import 'package:cake_wallet/src/widgets/gradient_background.dart';
12 import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
@@ -28,7 +28,6 @@ import 'package:keyboard_actions/keyboard_actions.dart';
28 import 'package:mobx/mobx.dart';
29 import 'package:shared_preferences/shared_preferences.dart';
30 import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
31 -import 'package:bitcoin_base/bitcoin_base.dart';
31
32 class AddressPage extends BasePage {
33 AddressPage({
@@ -230,22 +229,10 @@ class AddressPage extends BasePage {
229 );
230 }
231 break;
233 - case BitcoinReceivePageOption.p2pkh:
234 - addressListViewModel.setAddressType(P2pkhAddressType.p2pkh);
235 - break;
236 - case BitcoinReceivePageOption.p2sh:
237 - addressListViewModel.setAddressType(P2shAddressType.p2wpkhInP2sh);
238 - break;
239 - case BitcoinReceivePageOption.p2wpkh:
240 - addressListViewModel.setAddressType(SegwitAddresType.p2wpkh);
241 - break;
242 - case BitcoinReceivePageOption.p2tr:
243 - addressListViewModel.setAddressType(SegwitAddresType.p2tr);
244 - break;
245 - case BitcoinReceivePageOption.p2wsh:
246 - addressListViewModel.setAddressType(SegwitAddresType.p2wsh);
247 - break;
232 default:
233 + if (addressListViewModel.type == WalletType.bitcoin) {
234 + addressListViewModel.setAddressType(bitcoin!.getBitcoinAddressType(option));
235 + }
236 }
237 });
238
lib/src/screens/send/widgets/extract_address_from_parsed.dart
+2
@@ -53,6 +53,8 @@ Future<String> extractAddressFromParsed(
53 title = S.of(context).address_detected;
54 content = S.of(context).extracted_address_content('${parsedAddress.name} (Nostr NIP-05)');
55 address = parsedAddress.addresses.first;
56 + profileImageUrl = parsedAddress.profileImageUrl;
57 + profileName = parsedAddress.profileName;
58 break;
59 case ParseFrom.yatRecord:
60 if (parsedAddress.name.isEmpty) {
lib/src/widgets/base_alert_dialog.dart
-1
@@ -1,4 +1,3 @@
1 -import 'package:cake_wallet/src/screens/receive/widgets/header_tile.dart';
1 import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
2 import 'dart:ui';
3 import 'package:cake_wallet/src/widgets/section_divider.dart';
lib/store/settings_store.dart
+10 -2
@@ -790,9 +790,16 @@ abstract class SettingsStoreBase with Store {
790 final exchangeStatus = ExchangeApiMode.deserialize(
791 raw: sharedPreferences.getInt(PreferencesKey.exchangeStatusKey) ??
792 ExchangeApiMode.enabled.raw);
793 + final bool isNewInstall = sharedPreferences.getBool(PreferencesKey.isNewInstall) ?? true;
794 + final int defaultTheme;
795 + if (isNewInstall) {
796 + defaultTheme = isMoneroOnly ? ThemeList.moneroDarkTheme.raw : ThemeList.brightTheme.raw;
797 + } else {
798 + defaultTheme = ThemeType.bright.index;
799 + }
800 final savedTheme = initialTheme ??
801 ThemeList.deserialize(
795 - raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ?? (isMoneroOnly ? ThemeList.moneroDarkTheme.raw : ThemeList.cakeDarkTheme.raw));
802 + raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ?? defaultTheme);
803 final actionListDisplayMode = ObservableList<ActionListDisplayMode>();
804 actionListDisplayMode.addAll(deserializeActionlistDisplayModes(
805 sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ?? defaultActionsMode));
@@ -1151,7 +1158,8 @@ abstract class SettingsStoreBase with Store {
1158 raw: sharedPreferences.getInt(PreferencesKey.exchangeStatusKey) ??
1159 ExchangeApiMode.enabled.raw);
1160 currentTheme = ThemeList.deserialize(
1154 - raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ?? (isMoneroOnly ? ThemeList.moneroDarkTheme.raw : ThemeList.cakeDarkTheme.raw));
1161 + raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ??
1162 + (isMoneroOnly ? ThemeList.moneroDarkTheme.raw : ThemeList.brightTheme.raw));
1163 actionlistDisplayMode = ObservableList<ActionListDisplayMode>();
1164 actionlistDisplayMode.addAll(deserializeActionlistDisplayModes(
1165 sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ?? defaultActionsMode));
lib/twitter/twitter_api.dart
+19 -12
@@ -32,7 +32,10 @@ class TwitterApi {
32 }
33
34 final Map<String, dynamic> responseJSON = jsonDecode(response.body) as Map<String, dynamic>;
35 - if (responseJSON['errors'] != null) {
35 + if (responseJSON['errors'] != null &&
36 + !responseJSON['errors'][0]['detail']
37 + .toString()
38 + .contains("Could not find tweet with pinned_tweet_id")) {
39 throw Exception(responseJSON['errors'][0]['detail']);
40 }
41
@@ -40,20 +43,24 @@ class TwitterApi {
43 }
44
45 static Tweet? _getPinnedTweet(Map<String, dynamic> responseJSON) {
43 - final tweetId = responseJSON['data']['pinned_tweet_id'] as String?;
44 - if (tweetId == null || responseJSON['includes'] == null) return null;
46 + try {
47 + final tweetId = responseJSON['data']['pinned_tweet_id'] as String?;
48 + if (tweetId == null || responseJSON['includes'] == null) return null;
49
46 - final tweetIncludes = List.from(responseJSON['includes']['tweets'] as List);
47 - final pinnedTweetData = tweetIncludes.firstWhere(
48 - (tweet) => tweet['id'] == tweetId,
49 - orElse: () => null,
50 - ) as Map<String, dynamic>?;
50 + final tweetIncludes = List.from(responseJSON['includes']['tweets'] as List);
51 + final pinnedTweetData = tweetIncludes.firstWhere(
52 + (tweet) => tweet['id'] == tweetId,
53 + orElse: () => null,
54 + ) as Map<String, dynamic>?;
55
52 - if (pinnedTweetData == null) return null;
56 + if (pinnedTweetData == null) return null;
57
54 - final pinnedTweetText =
55 - (pinnedTweetData['note_tweet']?['text'] ?? pinnedTweetData['text']) as String;
58 + final pinnedTweetText =
59 + (pinnedTweetData['note_tweet']?['text'] ?? pinnedTweetData['text']) as String;
60
57 - return Tweet(id: tweetId, text: pinnedTweetText);
61 + return Tweet(id: tweetId, text: pinnedTweetText);
62 + } catch (e) {
63 + return null;
64 + }
65 }
66 }
lib/view_model/exchange/exchange_trade_view_model.dart
+6 -1
@@ -162,9 +162,14 @@ abstract class ExchangeTradeViewModelBase with Store {
162 wallet.currency == CryptoCurrency.maticpoly &&
163 tradesStore.trade!.from.tag == CryptoCurrency.maticpoly.tag;
164
165 + bool _isSplToken() =>
166 + wallet.currency == CryptoCurrency.sol &&
167 + tradesStore.trade!.from.tag == CryptoCurrency.sol.title;
168 +
169 return tradesStore.trade!.from == wallet.currency ||
170 tradesStore.trade!.provider == ExchangeProviderDescription.xmrto ||
171 _isEthToken() ||
168 - _isPolygonToken();
172 + _isPolygonToken() ||
173 + _isSplToken();
174 }
175 }
macos/Flutter/GeneratedPluginRegistrant.swift
+1 -1
@@ -5,7 +5,7 @@
5 import FlutterMacOS
6 import Foundation
7
8 -import connectivity_plus_macos
8 +import connectivity_plus
9 import cw_monero
10 import device_info_plus
11 import devicelocale
macos/Podfile.lock
+7 -7
@@ -1,5 +1,5 @@
1 PODS:
2 - - connectivity_plus_macos (0.0.1):
2 + - connectivity_plus (0.0.1):
3 - FlutterMacOS
4 - ReachabilitySwift
5 - cw_monero (0.0.1):
@@ -51,7 +51,7 @@ PODS:
51 - FlutterMacOS
52
53 DEPENDENCIES:
54 - - connectivity_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus_macos/macos`)
54 + - connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos`)
55 - cw_monero (from `Flutter/ephemeral/.symlinks/plugins/cw_monero/macos`)
56 - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`)
57 - devicelocale (from `Flutter/ephemeral/.symlinks/plugins/devicelocale/macos`)
@@ -73,8 +73,8 @@ SPEC REPOS:
73 - ReachabilitySwift
74
75 EXTERNAL SOURCES:
76 - connectivity_plus_macos:
77 - :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus_macos/macos
76 + connectivity_plus:
77 + :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos
78 cw_monero:
79 :path: Flutter/ephemeral/.symlinks/plugins/cw_monero/macos
80 device_info_plus:
@@ -105,8 +105,8 @@ EXTERNAL SOURCES:
105 :path: Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos
106
107 SPEC CHECKSUMS:
108 - connectivity_plus_macos: f6e86fd000e971d361e54b5afcadc8c8fa773308
109 - cw_monero: f8b7f104508efba2591548e76b5c058d05cba3f0
108 + connectivity_plus: 18d3c32514c886e046de60e9c13895109866c747
109 + cw_monero: ec03de55a19c4a2b174ea687e0f4202edc716fa4
110 device_info_plus: 5401765fde0b8d062a2f8eb65510fb17e77cf07f
111 devicelocale: 9f0f36ac651cabae2c33f32dcff4f32b61c38225
112 flutter_inappwebview_macos: 9600c9df9fdb346aaa8933812009f8d94304203d
@@ -123,6 +123,6 @@ SPEC CHECKSUMS:
123 url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95
124 wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269
125
126 -PODFILE CHECKSUM: 5107934592df7813b33d744aebc8ddc6b5a5445f
126 +PODFILE CHECKSUM: 65ec1541137fb5b35d00490dec1bb48d4d9586bb
127
128 COCOAPODS: 1.12.1
pubspec_base.yaml
+5 -1
@@ -55,7 +55,7 @@ dependencies:
55 basic_utils: ^5.6.1
56 get_it: ^7.2.0
57 # connectivity: ^3.0.3
58 - connectivity_plus: ^2.3.5
58 + connectivity_plus: ^5.0.2
59 keyboard_actions: ^4.0.1
60 another_flushbar: ^1.12.29
61 archive: ^3.3.0
@@ -107,6 +107,10 @@ dependencies:
107 polyseed: ^0.0.2
108 nostr_tools: ^1.0.9
109 solana: ^0.30.1
110 + bitcoin_base:
111 + git:
112 + url: https://github.com/cake-tech/bitcoin_base.git
113 + ref: cake-update-v1
114
115 dev_dependencies:
116 flutter_test:
scripts/android/app_env.sh
+3 -3
@@ -15,15 +15,15 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
15 APP_ANDROID_TYPE=$1
16
17 MONERO_COM_NAME="Monero.com"
18 -MONERO_COM_VERSION="1.10.3"
19 -MONERO_COM_BUILD_NUMBER=75
18 +MONERO_COM_VERSION="1.11.0"
19 +MONERO_COM_BUILD_NUMBER=77
20 MONERO_COM_BUNDLE_ID="com.monero.app"
21 MONERO_COM_PACKAGE="com.monero.app"
22 MONERO_COM_SCHEME="monero.com"
23
24 CAKEWALLET_NAME="Cake Wallet"
25 CAKEWALLET_VERSION="4.14.0"
26 -CAKEWALLET_BUILD_NUMBER=193
26 +CAKEWALLET_BUILD_NUMBER=196
27 CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
28 CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"
29 CAKEWALLET_SCHEME="cakewallet"
scripts/ios/app_env.sh
+3 -3
@@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
13 APP_IOS_TYPE=$1
14
15 MONERO_COM_NAME="Monero.com"
16 -MONERO_COM_VERSION="1.10.3"
17 -MONERO_COM_BUILD_NUMBER=73
16 +MONERO_COM_VERSION="1.11.0"
17 +MONERO_COM_BUILD_NUMBER=75
18 MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
19
20 CAKEWALLET_NAME="Cake Wallet"
21 CAKEWALLET_VERSION="4.14.0"
22 -CAKEWALLET_BUILD_NUMBER=213
22 +CAKEWALLET_BUILD_NUMBER=215
23 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
24
25 HAVEN_NAME="Haven"
scripts/macos/app_env.sh
+4 -4
@@ -16,13 +16,13 @@ if [ -n "$1" ]; then
16 fi
17
18 MONERO_COM_NAME="Monero.com"
19 -MONERO_COM_VERSION="1.0.3"
20 -MONERO_COM_BUILD_NUMBER=5
19 +MONERO_COM_VERSION="1.1.0"
20 +MONERO_COM_BUILD_NUMBER=7
21 MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
22
23 CAKEWALLET_NAME="Cake Wallet"
24 -CAKEWALLET_VERSION="1.6.3"
25 -CAKEWALLET_BUILD_NUMBER=53
24 +CAKEWALLET_VERSION="1.7.0"
25 +CAKEWALLET_BUILD_NUMBER=55
26 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
27
28 if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then
tool/configure.dart
+9 -7
@@ -61,6 +61,7 @@ Future<void> main(List<String> args) async {
61 Future<void> generateBitcoin(bool hasImplementation) async {
62 final outputFile = File(bitcoinOutputPath);
63 const bitcoinCommonHeaders = """
64 +import 'package:cw_core/receive_page_option.dart';
65 import 'package:cw_core/unspent_transaction_output.dart';
66 import 'package:cw_core/wallet_credentials.dart';
67 import 'package:cw_core/wallet_info.dart';
@@ -70,7 +71,8 @@ import 'package:cw_core/unspent_coins_info.dart';
71 import 'package:cw_core/wallet_service.dart';
72 import 'package:cake_wallet/view_model/send/output.dart';
73 import 'package:cw_core/wallet_type.dart';
73 -import 'package:hive/hive.dart';""";
74 +import 'package:hive/hive.dart';
75 +import 'package:bitcoin_base/bitcoin_base.dart';""";
76 const bitcoinCWHeaders = """
77 import 'package:cw_bitcoin/bitcoin_receive_page_option.dart';
78 import 'package:cw_bitcoin/electrum_wallet.dart';
@@ -83,7 +85,6 @@ import 'package:cw_bitcoin/bitcoin_amount_format.dart';
85 import 'package:cw_bitcoin/bitcoin_address_record.dart';
86 import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart';
87 import 'package:cw_bitcoin/litecoin_wallet_service.dart';
86 -import 'package:bitcoin_base/bitcoin_base.dart';
88 import 'package:mobx/mobx.dart';
89 """;
90 const bitcoinCwPart = "part 'cw_bitcoin.dart';";
@@ -143,8 +144,9 @@ abstract class Bitcoin {
144 TransactionPriority getLitecoinTransactionPrioritySlow();
145
146 Future<void> setAddressType(Object wallet, dynamic option);
146 - BitcoinReceivePageOption getSelectedAddressType(Object wallet);
147 - List<BitcoinReceivePageOption> getBitcoinReceivePageOptions();
147 + ReceivePageOption getSelectedAddressType(Object wallet);
148 + List<ReceivePageOption> getBitcoinReceivePageOptions();
149 + BitcoinAddressType getBitcoinAddressType(ReceivePageOption option);
150 }
151 """;
152
@@ -906,6 +908,7 @@ import 'package:cw_core/wallet_credentials.dart';
908 import 'package:cw_core/wallet_info.dart';
909 import 'package:cw_core/wallet_service.dart';
910 import 'package:hive/hive.dart';
911 +import 'package:solana/solana.dart';
912
913 """;
914 const solanaCWHeaders = """
@@ -916,7 +919,6 @@ import 'package:cw_solana/solana_wallet_service.dart';
919 import 'package:cw_solana/solana_transaction_info.dart';
920 import 'package:cw_solana/solana_transaction_credentials.dart';
921 import 'package:cw_solana/solana_wallet_creation_credentials.dart';
919 -import 'package:solana/solana.dart';
922 """;
923 const solanaCwPart = "part 'cw_solana.dart';";
924 const solanaContent = """
@@ -944,10 +946,10 @@ abstract class Solana {
946 List<OutputInfo> outputs, {
947 required CryptoCurrency currency,
948 });
947 - List<SPLToken> getSPLTokenCurrencies(WalletBase wallet);
949 + List<CryptoCurrency> getSPLTokenCurrencies(WalletBase wallet);
950 Future<void> addSPLToken(WalletBase wallet, CryptoCurrency token);
951 Future<void> deleteSPLToken(WalletBase wallet, CryptoCurrency token);
950 - Future<SPLToken?> getSPLToken(WalletBase wallet, String contractAddress);
952 + Future<CryptoCurrency?> getSPLToken(WalletBase wallet, String contractAddress);
953
954 CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction);
955 double getTransactionAmountRaw(TransactionInfo transactionInfo);