diff --git a/.gitignore b/.gitignore index 2e5ffb5cb..6aee5aef7 100644 --- a/.gitignore +++ b/.gitignore @@ -109,3 +109,7 @@ ios/Flutter/.last_build_id ios/build *.sublime-workspace *.sublime-project + +shared_external/** +cw_shared_external/** +cw_haven/** diff --git a/lib/bitcoin/bitcoin_wallet.dart b/lib/bitcoin/bitcoin_wallet.dart index 79444844d..2c70bd4f8 100644 --- a/lib/bitcoin/bitcoin_wallet.dart +++ b/lib/bitcoin/bitcoin_wallet.dart @@ -1,3 +1,4 @@ +import 'package:cake_wallet/bitcoin/bitcoin_mnemonic.dart'; import 'package:cake_wallet/bitcoin/unspent_coins_info.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; @@ -35,7 +36,10 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { walletInfo, initialAddresses: initialAddresses, accountIndex: accountIndex, - hd: hd, + mainHd: hd, + sideHd: bitcoin.HDWallet.fromSeed( + mnemonicToSeedBytes(mnemonic), network: networkType) + .derivePath("m/0'/1"), networkType: networkType); } diff --git a/lib/bitcoin/bitcoin_wallet_addresses.dart b/lib/bitcoin/bitcoin_wallet_addresses.dart index ecded3cb8..17c07efc0 100644 --- a/lib/bitcoin/bitcoin_wallet_addresses.dart +++ b/lib/bitcoin/bitcoin_wallet_addresses.dart @@ -17,13 +17,15 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses WalletInfo walletInfo, {@required List initialAddresses, int accountIndex = 0, - @required bitcoin.HDWallet hd, + @required bitcoin.HDWallet mainHd, + @required bitcoin.HDWallet sideHd, @required this.networkType}) : super( walletInfo, initialAddresses: initialAddresses, accountIndex: accountIndex, - hd: hd); + mainHd: mainHd, + sideHd: sideHd); bitcoin.NetworkType networkType; diff --git a/lib/bitcoin/electrum_wallet_addresses.dart b/lib/bitcoin/electrum_wallet_addresses.dart index 843ac4065..bf4bc064b 100644 --- a/lib/bitcoin/electrum_wallet_addresses.dart +++ b/lib/bitcoin/electrum_wallet_addresses.dart @@ -14,19 +14,23 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { ElectrumWalletAddressesBase(WalletInfo walletInfo, {@required List initialAddresses, int accountIndex = 0, - @required bitcoin.HDWallet hd}) + this.mainHd, + this.sideHd}) : super(walletInfo) { - this.hd = hd; this.accountIndex = accountIndex; addresses = ObservableList.of( (initialAddresses ?? []).toSet()); } + static const regularAddressesCount = 22; + static const hiddenAddressesCount = 17; + @override @observable String address; - bitcoin.HDWallet hd; + bitcoin.HDWallet mainHd; + bitcoin.HDWallet sideHd; ObservableList addresses; @@ -53,19 +57,36 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { } Future generateAddresses() async { - if (addresses.length < 33) { - final addressesCount = 33 - addresses.length; + final regularAddresses = []; + final hiddenAddresses = []; + + addresses.forEach((addr) { + if (addr.isHidden) { + hiddenAddresses.add(addr); + return; + } + + regularAddresses.add(addr); + }); + + if (regularAddresses.length < regularAddressesCount) { + final addressesCount = regularAddressesCount - regularAddresses.length; await generateNewAddresses(addressesCount, - startIndex: addresses.length, hd: hd); + startIndex: regularAddresses.length, hd: mainHd, isHidden: false); + } + + if (hiddenAddresses.length < hiddenAddressesCount) { + final addressesCount = hiddenAddressesCount - hiddenAddresses.length; + await generateNewAddresses(addressesCount, + startIndex: hiddenAddresses.length, hd: sideHd, isHidden: true); } } Future generateNewAddress( {bool isHidden = false, bitcoin.HDWallet hd}) async { accountIndex += 1; - final _hd = hd ?? this.hd; final address = BitcoinAddressRecord( - getAddress(index: accountIndex, hd: _hd), + getAddress(index: accountIndex, hd: hd), index: accountIndex, isHidden: isHidden); addresses.add(address); @@ -79,6 +100,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { for (var i = startIndex; i < count + startIndex; i++) { final address = BitcoinAddressRecord(getAddress(index: i, hd: hd), index: i, isHidden: isHidden); + print(address.address); list.add(address); } diff --git a/lib/bitcoin/litecoin_wallet.dart b/lib/bitcoin/litecoin_wallet.dart index ac7e24349..cdae9a73b 100644 --- a/lib/bitcoin/litecoin_wallet.dart +++ b/lib/bitcoin/litecoin_wallet.dart @@ -1,3 +1,4 @@ +import 'package:cake_wallet/bitcoin/bitcoin_mnemonic.dart'; import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart'; import 'package:cake_wallet/bitcoin/unspent_coins_info.dart'; import 'package:cake_wallet/bitcoin/litecoin_wallet_addresses.dart'; @@ -11,6 +12,7 @@ import 'package:cake_wallet/bitcoin/electrum_wallet.dart'; import 'package:cake_wallet/bitcoin/bitcoin_address_record.dart'; import 'package:cake_wallet/bitcoin/electrum_balance.dart'; import 'package:cake_wallet/bitcoin/litecoin_network.dart'; +import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin; part 'litecoin_wallet.g.dart'; @@ -37,9 +39,11 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { walletInfo, initialAddresses: initialAddresses, accountIndex: accountIndex, - hd: hd, - networkType: networkType, - mnemonic: mnemonic); + mainHd: hd, + sideHd: bitcoin.HDWallet + .fromSeed(mnemonicToSeedBytes(mnemonic), network: networkType) + .derivePath("m/0'/1"), + networkType: networkType,); } static Future open({ diff --git a/lib/bitcoin/litecoin_wallet_addresses.dart b/lib/bitcoin/litecoin_wallet_addresses.dart index 19ade7566..5dd6fba95 100644 --- a/lib/bitcoin/litecoin_wallet_addresses.dart +++ b/lib/bitcoin/litecoin_wallet_addresses.dart @@ -18,18 +18,18 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses WalletInfo walletInfo, {@required List initialAddresses, int accountIndex = 0, - @required bitcoin.HDWallet hd, - @required this.networkType, - @required this.mnemonic}) + @required bitcoin.HDWallet mainHd, + @required bitcoin.HDWallet sideHd, + @required this.networkType}) : super( walletInfo, initialAddresses: initialAddresses, accountIndex: accountIndex, - hd: hd); + mainHd: mainHd, + sideHd: sideHd); bitcoin.NetworkType networkType; - final String mnemonic; @override String getAddress({@required int index, @required bitcoin.HDWallet hd}) => @@ -40,15 +40,9 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses if (addresses.length < 33) { final addressesCount = 22 - addresses.length; await generateNewAddresses(addressesCount, - hd: hd, startIndex: addresses.length); - - final changeRoot = bitcoin.HDWallet.fromSeed( - mnemonicToSeedBytes(mnemonic), - network: networkType) - .derivePath("m/0'/1"); - + hd: mainHd, startIndex: addresses.length); await generateNewAddresses(11, - startIndex: 0, hd: changeRoot, isHidden: true); + startIndex: 0, hd: sideHd, isHidden: true); } } } \ No newline at end of file diff --git a/lib/di.dart b/lib/di.dart index 31baa3f6b..eb6a9e9b2 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -194,8 +194,9 @@ Future setup( getIt.registerSingleton( ExchangeTemplateStore(templateSource: _exchangeTemplates)); getIt.registerSingleton(YatStore( - appStore: getIt.get() - )); + appStore: getIt.get(), + secureStorage: getIt.get()) + ..init()); final secretStore = await SecretStoreBase.load(getIt.get()); diff --git a/lib/entities/wallet_info.dart b/lib/entities/wallet_info.dart index 85a9af470..19dab6032 100644 --- a/lib/entities/wallet_info.dart +++ b/lib/entities/wallet_info.dart @@ -1,6 +1,7 @@ import 'package:flutter/foundation.dart'; import 'package:hive/hive.dart'; import 'package:cake_wallet/entities/wallet_type.dart'; +import 'dart:async'; part 'wallet_info.g.dart'; @@ -8,7 +9,8 @@ part 'wallet_info.g.dart'; class WalletInfo extends HiveObject { WalletInfo(this.id, this.name, this.type, this.isRecovery, this.restoreHeight, this.timestamp, this.dirPath, this.path, this.address, this.yatEid, - this.yatRefreshToken); + this.yatLastUsedAddressRaw) + : _yatLastUsedAddressController = StreamController.broadcast(); factory WalletInfo.external( {@required String id, @@ -21,10 +23,10 @@ class WalletInfo extends HiveObject { @required String path, @required String address, String yatEid ='', - String yatRefreshToken = ''}) { + String yatLastUsedAddressRaw = ''}) { return WalletInfo(id, name, type, isRecovery, restoreHeight, date.millisecondsSinceEpoch ?? 0, dirPath, path, address, - yatEid, yatRefreshToken); + yatEid, yatLastUsedAddressRaw); } static const typeId = 4; @@ -64,11 +66,20 @@ class WalletInfo extends HiveObject { String yatEid; @HiveField(12) - String yatRefreshToken; + String yatLastUsedAddressRaw; + + String get yatLastUsedAddress => yatLastUsedAddressRaw; + + set yatLastUsedAddress(String address) { + yatLastUsedAddressRaw = address; + _yatLastUsedAddressController.add(address); + } String get yatEmojiId => yatEid ?? ''; - String get yatToken => yatRefreshToken ?? ''; - DateTime get date => DateTime.fromMillisecondsSinceEpoch(timestamp); + + Stream get yatLastUsedAddressStream => _yatLastUsedAddressController.stream; + + StreamController _yatLastUsedAddressController; } diff --git a/lib/main.dart b/lib/main.dart index 129f45602..692532a4f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -110,8 +110,6 @@ Future main() async { final unspentCoinsInfoSource = await Hive.openBox(UnspentCoinsInfo.boxName); - await visualisationForEmojiId('%E2%98%A0%EF%B8%8F%F0%9F%90%99%E2%98%A0%EF%B8%8F'); - await initialSetup( sharedPreferences: await SharedPreferences.getInstance(), nodes: nodes, diff --git a/lib/reactions/on_current_wallet_change.dart b/lib/reactions/on_current_wallet_change.dart index 5c702b0af..3e3ce4694 100644 --- a/lib/reactions/on_current_wallet_change.dart +++ b/lib/reactions/on_current_wallet_change.dart @@ -13,14 +13,38 @@ import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/core/fiat_conversion_service.dart'; import 'package:cake_wallet/core/wallet_base.dart'; import 'package:cake_wallet/entities/wallet_type.dart'; +import 'package:cake_wallet/store/yat/yat_store.dart'; ReactionDisposer _onCurrentWalletChangeReaction; ReactionDisposer _onCurrentWalletChangeFiatRateUpdateReaction; +ReactionDisposer _onCurrentWalletAddressChangeReaction; void startCurrentWalletChangeReaction(AppStore appStore, SettingsStore settingsStore, FiatConversionStore fiatConversionStore) { _onCurrentWalletChangeReaction?.reaction?.dispose(); _onCurrentWalletChangeFiatRateUpdateReaction?.reaction?.dispose(); + _onCurrentWalletAddressChangeReaction?.reaction?.dispose(); + + _onCurrentWalletAddressChangeReaction = reaction((_) => appStore.wallet.walletAddresses.address, + (String address) async { + if (address == appStore.wallet.walletInfo.yatLastUsedAddress) { + return; + } + + try { + final yatStore = getIt.get(); + await updateEmojiIdAddress( + appStore.wallet.walletInfo.yatEmojiId, + appStore.wallet.walletAddresses.address, + yatStore.apiKey, + appStore.wallet.type + ); + appStore.wallet.walletInfo.yatLastUsedAddress = address; + await appStore.wallet.walletInfo.save(); + } catch (e) { + print(e.toString()); + } + }); _onCurrentWalletChangeReaction = reaction((_) => appStore.wallet, (WalletBase< Balance, TransactionHistoryBase, TransactionInfo> diff --git a/lib/src/screens/dashboard/dashboard_page.dart b/lib/src/screens/dashboard/dashboard_page.dart index 9b55ac306..eec1b5bb8 100644 --- a/lib/src/screens/dashboard/dashboard_page.dart +++ b/lib/src/screens/dashboard/dashboard_page.dart @@ -98,6 +98,10 @@ class DashboardPage extends BasePage { height: 22.24, width: 24, color: Theme.of(context).accentTextTheme.display3.backgroundColor); + final sellImage = Image.asset('assets/images/restore_wallet_image.png', + height: 22.24, + width: 24, + color: Theme.of(context).accentTextTheme.display3.backgroundColor); _setEffects(context); return SafeArea( @@ -144,6 +148,12 @@ class DashboardPage extends BasePage { onClick: () async => await _onClickBuyButton(context), ), + ActionButton( + image: sellImage, + title: 'Sell', + onClick: () async => + await _onClickSellButton(context), + ), ], ), ) @@ -227,7 +237,13 @@ class DashboardPage extends BasePage { final walletType = walletViewModel.type; switch (walletType) { - case WalletType.monero: + case WalletType.bitcoin: + Navigator.of(context).pushNamed(Routes.preOrder); + break; + case WalletType.litecoin: + Navigator.of(context).pushNamed(Routes.preOrder); + break; + default: await showPopUp( context: context, builder: (BuildContext context) { @@ -237,10 +253,29 @@ class DashboardPage extends BasePage { buttonText: S.of(context).ok, buttonAction: () => Navigator.of(context).pop()); }); - break; - default: + } + } + + Future _onClickSellButton(BuildContext context) async { + final walletType = walletViewModel.type; + + switch (walletType) { + case WalletType.bitcoin: Navigator.of(context).pushNamed(Routes.preOrder); break; + case WalletType.litecoin: + Navigator.of(context).pushNamed(Routes.preOrder); + break; + default: + await showPopUp( + context: context, + builder: (BuildContext context) { + return AlertWithOneAction( + alertTitle: S.of(context).buy, + alertContent: S.of(context).buy_alert_content, + buttonText: S.of(context).ok, + buttonAction: () => Navigator.of(context).pop()); + }); } } } diff --git a/lib/src/screens/root/root.dart b/lib/src/screens/root/root.dart index 9944344b8..9d15a41ac 100644 --- a/lib/src/screens/root/root.dart +++ b/lib/src/screens/root/root.dart @@ -32,7 +32,7 @@ class RootState extends State with WidgetsBindingObserver { @override void initState() { - _isInactiveController = StreamController(); + _isInactiveController = StreamController.broadcast(); _isInactive = false; _postFrameCallback = false; WidgetsBinding.instance.addObserver(this); diff --git a/lib/store/yat/yat_store.dart b/lib/store/yat/yat_store.dart index aacc48bae..cace91a88 100644 --- a/lib/store/yat/yat_store.dart +++ b/lib/store/yat/yat_store.dart @@ -13,6 +13,7 @@ import 'dart:convert'; import 'package:cake_wallet/store/yat/yat_exception.dart'; import 'package:http/http.dart'; import 'dart:async'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; part 'yat_store.g.dart'; @@ -23,61 +24,135 @@ class YatLink { static const signInSuffix = '/partner/$partnerId/link-email'; static const createSuffix = '/create'; static const managePath = '/partner/$partnerId/manage'; - static const queryParameter = '?addresses='; + static const queryParameter = '?address_json='; + static const apiDevUrl = 'https://a.yat.fyi'; + static const apiReleaseUrl = 'https://a.y.at'; static const requestDevUrl = 'https://a.yat.fyi/emoji_id/'; static const requestReleaseUrl = 'https://a.y.at/emoji_id/'; - static const startFlowUrl = 'https://www.y03btrk.com/4RQSJ/55M6S/'; - static const isDevMode = false; + static const startFlowUrl = 'https://www.y03btrk.com/4RQSJ/6JHXF/'; + static const isDevMode = true; static const tags = >{"XMR" : ['0x1001', '0x1002'], "BTC" : ['0x1003'], "LTC" : ['0x3fff']}; + static String get apiUrl => YatLink.isDevMode + ? YatLink.apiDevUrl + : YatLink.apiReleaseUrl; + + static String get emojiIdUrl => apiUrl + '/emoji_id/'; + static String get baseUrl => YatLink.isDevMode ? YatLink.baseDevUrl : YatLink.baseReleaseUrl; } Future> fetchYatAddress(String emojiId, String ticker) async { - final requestURL = YatLink.isDevMode - ? YatLink.requestDevUrl - : YatLink.requestReleaseUrl; - final url = requestURL + emojiId; + final url = YatLink.emojiIdUrl + emojiId + '/payment'; final response = await get(url); - + if (response.statusCode != 200) { throw YatException(text: response.body.toString()); } - - final responseJSON = json.decode(response.body) as Map; - final result = responseJSON['result'] as List; - - if (result?.isEmpty ?? true) { - return []; - } - - final List addresses = []; + + final addresses = []; final currency = ticker.toUpperCase(); - - for (var elem in result) { - final tag = elem['tag'] as String; - if (tag?.isEmpty ?? true) { - continue; - } + final responseJSON = json.decode(response.body) as Map; + final result = responseJSON['result'] as Map; + result.forEach((dynamic key, dynamic value) { + final tag = key as String ?? ''; + final record = value as Map; + if (YatLink.tags[currency]?.contains(tag) ?? false) { - final yatAddress = elem['data'] as String; - if (yatAddress?.isNotEmpty ?? false) { - addresses.add(yatAddress); + final address = record['address'] as String; + if (address?.isNotEmpty ?? false) { + addresses.add(address); } } - } + }); return addresses; } +Future fetchYatAccessToken(String refreshToken) async { + try { + final url = YatLink.apiUrl + '/auth/token/refresh'; + final bodyJson = json.encode({'refresh_token': refreshToken}); + final response = await post( + url, + headers: { + 'Content-Type': 'application/json', + 'Accept': '*/*' + }, + body: bodyJson); + + if (response.statusCode != 200) { + throw YatException(text: response.body.toString()); + } + + final responseJSON = json.decode(response.body) as Map; + return responseJSON['access_token'] as String; + }catch(_) { + return ''; + } +} + +Future fetchYatApiKey(String accessKey) async { + try { + final url = YatLink.apiUrl + '/api_keys'; + final bodyJson = json.encode({'name': 'CW'}); + final response = await post( + url, + headers: { + 'Authorization': 'Bearer $accessKey', + 'Content-Type': 'application/json', + 'Accept': '*/*' + }, + body: bodyJson); + + if (response.statusCode != 200) { + throw YatException(text: response.body.toString()); + } + + final responseJSON = json.decode(response.body) as Map; + return responseJSON['api_key'] as String; + }catch(_) { + return ''; + } +} + +Future updateEmojiIdAddress(String emojiId, String address, String apiKey, WalletType type) async { + final url = YatLink.emojiIdUrl + emojiId; + final cur = walletTypeToCryptoCurrency(type); + final curFormatted = cur.toString().toUpperCase(); + var tag = ''; + + if (type == WalletType.monero && !address.startsWith('4')) { + tag = YatLink.tags[curFormatted].last; + } else { + tag = YatLink.tags[curFormatted].first; + } + + final bodyJson = json.encode({ + 'insert': [{ + 'data': address, + 'tag': tag + }] + }); + final response = await patch( + url, + headers: { + 'x-api-key': apiKey, + 'Content-Type': 'application/json', + 'Accept': '*/*' + }, + body: bodyJson); + + if (response.statusCode != 200) { + throw YatException(text: response.body.toString()); + } +} + Future visualisationForEmojiId(String emojiId) async { - final requestURL = YatLink.isDevMode - ? YatLink.requestDevUrl - : YatLink.requestReleaseUrl; - final url = requestURL + emojiId + '/json/VisualizerFileLocations'; + final url = YatLink.emojiIdUrl + emojiId + '/json/VisualizerFileLocations'; final response = await get(url); final responseJSON = json.decode(response.body) as Map; final data = responseJSON['data'] as Map; @@ -88,23 +163,39 @@ Future visualisationForEmojiId(String emojiId) async { class YatStore = YatStoreBase with _$YatStore; abstract class YatStoreBase with Store { - YatStoreBase({@required this.appStore}) { + YatStoreBase({@required this.appStore, @required this.secureStorage}) { _wallet ??= appStore.wallet; emoji = _wallet?.walletInfo?.yatEmojiId ?? ''; - refreshToken = _wallet?.walletInfo?.yatToken ?? ''; reaction((_) => appStore.wallet, _onWalletChange); - reaction((_) => emoji, (String emoji) => _onEmojiChange()); - emojiIncommingSC = StreamController(); + reaction((_) => emoji, (String _) => _onEmojiChange()); + reaction((_) => refreshToken, (String _) => _onRefreshTokenChange()); + emojiIncommingSC = StreamController.broadcast(); } + static const yatRefreshTokenKeyBase = 'yat_refresh_token'; + static const yatAccessTokenKeyBase = 'yat_access_token'; + static const yatApiKeyBase = 'yat_api_key'; + + static String yatRefreshTokenKey(String name) => '${yatRefreshTokenKeyBase}_$name'; + static String yatAccessTokenKey(String name) => '${yatAccessTokenKeyBase}_$name'; + static String yatApiKey(String name) => '${yatApiKeyBase}_$name'; + AppStore appStore; + FlutterSecureStorage secureStorage; + @observable String emoji; @observable String refreshToken; + @observable + String accessToken; + + @observable + String apiKey; + StreamController emojiIncommingSC; Stream get emojiIncommingStream => emojiIncommingSC.stream; @@ -113,6 +204,16 @@ abstract class YatStoreBase with Store { WalletBase, TransactionInfo> _wallet; + Future init() async { + if (_wallet == null) { + return; + } + + refreshToken = await secureStorage.read(key: yatRefreshTokenKey(_wallet.walletInfo.name)); + accessToken = await secureStorage.read(key: yatAccessTokenKey(_wallet.walletInfo.name)); + apiKey = await secureStorage.read(key: yatApiKey(_wallet.walletInfo.name)); + } + @action void _onWalletChange( WalletBase, @@ -120,7 +221,7 @@ abstract class YatStoreBase with Store { wallet) { this._wallet = wallet; emoji = wallet?.walletInfo?.yatEmojiId ?? ''; - refreshToken = wallet?.walletInfo?.yatToken ?? ''; + init(); } @action @@ -133,7 +234,6 @@ abstract class YatStoreBase with Store { } walletInfo.yatEid = emoji; - walletInfo.yatRefreshToken = refreshToken; if (walletInfo.isInBox) { walletInfo.save(); @@ -143,62 +243,32 @@ abstract class YatStoreBase with Store { } } - String defineQueryParameters() { - String parameters = ''; - switch (_wallet.type) { - case WalletType.monero: - final wallet = _wallet as MoneroWallet; - final subaddressList = MoneroSubaddressList(); - var isFirstAddress = true; - - wallet.walletAddresses.accountList.accounts.forEach((account) { - subaddressList.update(accountIndex: account.id); - subaddressList.subaddresses.forEach((subaddress) { - if (!isFirstAddress) { - parameters += '%7C'; - } else { - isFirstAddress = !isFirstAddress; - } - - parameters += subaddress.address.startsWith('4') - ? YatLink.tags["XMR"].first + '%3D' - : YatLink.tags["XMR"].last + '%3D'; - - parameters += subaddress.address; - }); - }); - break; - case WalletType.bitcoin: - final wallet = _wallet as ElectrumWallet; - var isFirstAddress = true; - - wallet.walletAddresses.addresses.forEach((record) { - if (!isFirstAddress) { - parameters += '%7C'; - } else { - isFirstAddress = !isFirstAddress; - } - - parameters += YatLink.tags["BTC"].first + '%3D' + record.address; - }); - break; - case WalletType.litecoin: - final wallet = _wallet as ElectrumWallet; - var isFirstAddress = true; - - wallet.walletAddresses.addresses.forEach((record) { - if (!isFirstAddress) { - parameters += '%7C'; - } else { - isFirstAddress = !isFirstAddress; - } - - parameters += YatLink.tags["LTC"].first + '%3D' + record.address; - }); - break; - default: - parameters = ''; + @action + Future _onRefreshTokenChange() async { + try { + await secureStorage.write(key: yatRefreshTokenKey(_wallet.walletInfo.name), value: refreshToken); + accessToken = await fetchYatAccessToken(refreshToken); + await secureStorage.write(key: yatAccessTokenKey(_wallet.walletInfo.name), value: accessToken); + apiKey = await fetchYatApiKey(accessToken); + await secureStorage.write(key: yatApiKey(_wallet.walletInfo.name), value: accessToken); + } catch (e) { + print(e.toString()); } - return parameters; + } + + String defineQueryParameters() { + final result = {}; + final tags = YatLink.tags[_wallet.currency.toString().toUpperCase()]; + String tag = tags.first; + + if (_wallet.type == WalletType.monero + && _wallet.walletAddresses.address.startsWith('4')) { + tag = tags.last; + } + result[tag] = '${_wallet.walletAddresses.address}|${_wallet.name}'; + final addressJson = json.encode([result]); + final addressJsonBytes = utf8.encode(addressJson); + + return base64.encode(addressJsonBytes); } } \ No newline at end of file diff --git a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart index 879aae5c4..cff230637 100644 --- a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart +++ b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart @@ -14,6 +14,7 @@ import 'package:cake_wallet/core/transaction_history.dart'; import 'package:cake_wallet/entities/balance.dart'; import 'package:cake_wallet/entities/transaction_info.dart'; import 'package:cake_wallet/store/app_store.dart'; +import 'dart:async'; part 'wallet_address_list_view_model.g.dart'; @@ -66,7 +67,31 @@ abstract class WalletAddressListViewModelBase with Store { }) { _appStore = appStore; _wallet = _appStore.wallet; + emoji = ''; hasAccounts = _wallet?.type == WalletType.monero; + reaction((_) => _wallet.walletAddresses.address, (String address) { + if (address == _wallet.walletInfo.yatLastUsedAddress) { + emoji = yatStore.emoji; + } else { + emoji = ''; + } + }); + + reaction((_) => yatStore.emoji, (String emojiId) => this.emoji = emojiId); + + _onLastUsedYatAddressSubscription = + _wallet.walletInfo.yatLastUsedAddressStream.listen((String yatAddress) { + if (yatAddress == _wallet.walletAddresses.address) { + emoji = yatStore.emoji; + } else { + emoji = ''; + } + }); + + if (_wallet.walletAddresses.address == _wallet.walletInfo.yatLastUsedAddress) { + emoji = yatStore.emoji; + } + _onWalletChangeReaction = reaction((_) => _appStore.wallet, (WalletBase< Balance, TransactionHistoryBase, TransactionInfo> wallet) { @@ -154,8 +179,8 @@ abstract class WalletAddressListViewModelBase with Store { @computed bool get hasAddressList => _wallet.type == WalletType.monero; - @computed - String get emoji => yatStore.emoji; + @observable + String emoji; @observable WalletBase, TransactionInfo> @@ -169,6 +194,9 @@ abstract class WalletAddressListViewModelBase with Store { ReactionDisposer _onWalletChangeReaction; + StreamSubscription _onLastUsedYatAddressSubscription; + StreamSubscription _onEmojiIdChangeSubscription; + @action void setAddress(WalletAddressListItem address) => _wallet.walletAddresses.address = address.address;