Yat, electrum addresses fixes

This commit is contained in:
M 2021-12-08 11:09:38 +00:00
parent cf20123ede
commit 42104fd825
14 changed files with 333 additions and 136 deletions

4
.gitignore vendored
View file

@ -109,3 +109,7 @@ ios/Flutter/.last_build_id
ios/build
*.sublime-workspace
*.sublime-project
shared_external/**
cw_shared_external/**
cw_haven/**

View file

@ -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);
}

View file

@ -17,13 +17,15 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses
WalletInfo walletInfo,
{@required List<BitcoinAddressRecord> 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;

View file

@ -14,19 +14,23 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
ElectrumWalletAddressesBase(WalletInfo walletInfo,
{@required List<BitcoinAddressRecord> initialAddresses,
int accountIndex = 0,
@required bitcoin.HDWallet hd})
this.mainHd,
this.sideHd})
: super(walletInfo) {
this.hd = hd;
this.accountIndex = accountIndex;
addresses = ObservableList<BitcoinAddressRecord>.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<BitcoinAddressRecord> addresses;
@ -53,19 +57,36 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
}
Future<void> generateAddresses() async {
if (addresses.length < 33) {
final addressesCount = 33 - addresses.length;
final regularAddresses = <BitcoinAddressRecord>[];
final hiddenAddresses = <BitcoinAddressRecord>[];
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<BitcoinAddressRecord> 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);
}

View file

@ -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<LitecoinWallet> open({

View file

@ -18,18 +18,18 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses
WalletInfo walletInfo,
{@required List<BitcoinAddressRecord> 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);
}
}
}

View file

@ -194,8 +194,9 @@ Future setup(
getIt.registerSingleton<ExchangeTemplateStore>(
ExchangeTemplateStore(templateSource: _exchangeTemplates));
getIt.registerSingleton<YatStore>(YatStore(
appStore: getIt.get<AppStore>()
));
appStore: getIt.get<AppStore>(),
secureStorage: getIt.get<FlutterSecureStorage>())
..init());
final secretStore =
await SecretStoreBase.load(getIt.get<FlutterSecureStorage>());

View file

@ -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<String>.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<String> get yatLastUsedAddressStream => _yatLastUsedAddressController.stream;
StreamController<String> _yatLastUsedAddressController;
}

View file

@ -110,8 +110,6 @@ Future<void> main() async {
final unspentCoinsInfoSource =
await Hive.openBox<UnspentCoinsInfo>(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,

View file

@ -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<YatStore>();
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>, TransactionInfo>

View file

@ -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<void>(
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<void> _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<void>(
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());
});
}
}
}

View file

@ -32,7 +32,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
@override
void initState() {
_isInactiveController = StreamController<bool>();
_isInactiveController = StreamController<bool>.broadcast();
_isInactive = false;
_postFrameCallback = false;
WidgetsBinding.instance.addObserver(this);

View file

@ -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 = <String, List<String>>{"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<List<String>> 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<String, dynamic>;
final result = responseJSON['result'] as List<dynamic>;
if (result?.isEmpty ?? true) {
return [];
}
final List<String> addresses = [];
final addresses = <String>[];
final currency = ticker.toUpperCase();
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final result = responseJSON['result'] as Map<dynamic, dynamic>;
result.forEach((dynamic key, dynamic value) {
final tag = key as String ?? '';
final record = value as Map<String, dynamic>;
for (var elem in result) {
final tag = elem['tag'] as String;
if (tag?.isEmpty ?? true) {
continue;
}
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<String> 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: <String, String>{
'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<String, dynamic>;
return responseJSON['access_token'] as String;
}catch(_) {
return '';
}
}
Future<String> fetchYatApiKey(String accessKey) async {
try {
final url = YatLink.apiUrl + '/api_keys';
final bodyJson = json.encode({'name': 'CW'});
final response = await post(
url,
headers: <String, String>{
'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<String, dynamic>;
return responseJSON['api_key'] as String;
}catch(_) {
return '';
}
}
Future<void> 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: <String, String>{
'x-api-key': apiKey,
'Content-Type': 'application/json',
'Accept': '*/*'
},
body: bodyJson);
if (response.statusCode != 200) {
throw YatException(text: response.body.toString());
}
}
Future<String> 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<String, dynamic>;
final data = responseJSON['data'] as Map<String, dynamic>;
@ -88,23 +163,39 @@ Future<String> 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<String>();
reaction((_) => emoji, (String _) => _onEmojiChange());
reaction((_) => refreshToken, (String _) => _onRefreshTokenChange());
emojiIncommingSC = StreamController<String>.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<String> emojiIncommingSC;
Stream<String> get emojiIncommingStream => emojiIncommingSC.stream;
@ -113,6 +204,16 @@ abstract class YatStoreBase with Store {
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>
_wallet;
Future<void> 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<Balance, TransactionHistoryBase<TransactionInfo>,
@ -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 {
}
}
@action
Future<void> _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());
}
}
String defineQueryParameters() {
String parameters = '';
switch (_wallet.type) {
case WalletType.monero:
final wallet = _wallet as MoneroWallet;
final subaddressList = MoneroSubaddressList();
var isFirstAddress = true;
final result = <String, String>{};
final tags = YatLink.tags[_wallet.currency.toString().toUpperCase()];
String tag = tags.first;
wallet.walletAddresses.accountList.accounts.forEach((account) {
subaddressList.update(accountIndex: account.id);
subaddressList.subaddresses.forEach((subaddress) {
if (!isFirstAddress) {
parameters += '%7C';
} else {
isFirstAddress = !isFirstAddress;
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);
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 = '';
}
return parameters;
return base64.encode(addressJsonBytes);
}
}

View file

@ -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>, 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<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>
@ -169,6 +194,9 @@ abstract class WalletAddressListViewModelBase with Store {
ReactionDisposer _onWalletChangeReaction;
StreamSubscription<String> _onLastUsedYatAddressSubscription;
StreamSubscription<String> _onEmojiIdChangeSubscription;
@action
void setAddress(WalletAddressListItem address) =>
_wallet.walletAddresses.address = address.address;