mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 11:39:22 +00:00
Yat, electrum addresses fixes
This commit is contained in:
parent
cf20123ede
commit
42104fd825
14 changed files with 333 additions and 136 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -109,3 +109,7 @@ ios/Flutter/.last_build_id
|
|||
ios/build
|
||||
*.sublime-workspace
|
||||
*.sublime-project
|
||||
|
||||
shared_external/**
|
||||
cw_shared_external/**
|
||||
cw_haven/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>());
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue