seed generation fixes

This commit is contained in:
fosse 2023-08-04 10:54:20 -04:00
parent 6688682096
commit 32dd14a53e
4 changed files with 125 additions and 114 deletions

View file

@ -23,6 +23,10 @@ class NanoUtil {
NanoAccountType.NANO, privateKeyToPublic(seedToPrivate(seed, index)));
}
static String seedToMnemonic(String seed) {
return NanoMnemomics.seedToMnemonic(seed).join(" ");
}
// static String createPublicKey(String privateKey) {
// return NanoHelpers.byteToHex(Ed25519Blake2b.getPubkey(NanoHelpers.hexToBytes(privateKey))!);
// }
@ -207,5 +211,4 @@ class NanoUtil {
final Decimal rawDecimal = Decimal.parse(rawPerCur.toString());
return (asDecimal * rawDecimal).toString();
}
}

View file

@ -59,9 +59,10 @@ abstract class NanoWalletBase
final String _password;
final DerivationType _derivationType;
late final String _privateKey;
late final String _publicAddress;
late final String _seedKey;
String? _privateKey;
String? _publicAddress;
String? _seedKey;
String? _representativeAddress;
Timer? _receiveTimer;
@ -82,11 +83,10 @@ abstract class NanoWalletBase
// initialize the different forms of private / public key we'll need:
Future<void> init() async {
final String type = (_derivationType == DerivationType.nano) ? "standard" : "hd";
_seedKey = bip39.mnemonicToEntropy(_mnemonic).toUpperCase();
_privateKey = await NanoUtil.uniSeedToPrivate(_seedKey, 0, type);
_publicAddress = await NanoUtil.uniSeedToAddress(_seedKey, 0, type);
this.walletInfo.address = _publicAddress;
_privateKey = await NanoUtil.uniSeedToPrivate(_seedKey!, 0, type);
_publicAddress = await NanoUtil.uniSeedToAddress(_seedKey!, 0, type);
this.walletInfo.address = _publicAddress!;
await walletAddresses.init();
await transactionHistory.init();
@ -158,7 +158,7 @@ abstract class NanoWalletBase
final block = await _client.constructSendBlock(
amountRaw: amt.toString(),
destinationAddress: txOut.address,
privateKey: _privateKey,
privateKey: _privateKey!,
balanceAfterTx: runningBalance,
previousHash: previousHash,
);
@ -195,8 +195,8 @@ abstract class NanoWalletBase
Future<void> _receiveAll() async {
await _updateBalance();
int blocksReceived = await this._client.confirmAllReceivable(
destinationAddress: _publicAddress,
privateKey: _privateKey,
destinationAddress: _publicAddress!,
privateKey: _privateKey!,
);
if (blocksReceived > 0) {
@ -224,7 +224,7 @@ abstract class NanoWalletBase
@override
Future<Map<String, NanoTransactionInfo>> fetchTransactions() async {
String address = _publicAddress;
String address = _publicAddress!;
final transactions = await _client.fetchTransactions(address);
@ -249,7 +249,7 @@ abstract class NanoWalletBase
@override
NanoWalletKeys get keys {
return NanoWalletKeys(seedKey: _seedKey);
return NanoWalletKeys(seedKey: _seedKey!);
}
@override
@ -269,7 +269,7 @@ abstract class NanoWalletBase
@override
String get seed => _mnemonic;
String get representative => _representativeAddress ?? "";
@action
@ -303,7 +303,8 @@ abstract class NanoWalletBase
String toJSON() => json.encode({
'seedKey': _seedKey,
'mnemonic': _mnemonic,
// 'balance': balance[currency]!.toJSON(),
'currentBalance': balance[currency]?.currentBalance.toString() ?? "0",
'receivableBalance': balance[currency]?.receivableBalance.toString() ?? "0",
'derivationType': _derivationType.toString()
});
@ -314,11 +315,12 @@ abstract class NanoWalletBase
}) async {
final path = await pathForWallet(name: name, type: walletInfo.type);
final jsonSource = await read(path: path, password: password);
final data = json.decode(jsonSource) as Map;
final mnemonic = data['mnemonic'] as String;
final balance = NanoBalance.fromString(
formattedCurrentBalance: data['balance'] as String? ?? "0",
formattedReceivableBalance: "0");
formattedCurrentBalance: data['currentBalance'] as String? ?? "0",
formattedReceivableBalance: data['receivableBalance'] as String? ?? "0");
DerivationType derivationType = DerivationType.bip39;
if (data['derivationType'] == "DerivationType.nano") {
@ -336,16 +338,17 @@ abstract class NanoWalletBase
mnemonic: mnemonic,
initialBalance: balance,
);
// init() should always be run after this!
}
Future<void> _updateBalance() async {
balance[currency] = await _client.getBalance(_publicAddress);
balance[currency] = await _client.getBalance(_publicAddress!);
await save();
}
Future<void> _updateRep() async {
try {
final accountInfo = await _client.getAccountInfo(_publicAddress);
final accountInfo = await _client.getAccountInfo(_publicAddress!);
_representativeAddress = accountInfo["representative"] as String;
} catch (e) {
throw Exception("Failed to get representative address $e");
@ -355,9 +358,9 @@ abstract class NanoWalletBase
Future<void> changeRep(String address) async {
try {
final String hash = await _client.changeRep(
privateKey: _privateKey,
privateKey: _privateKey!,
repAddress: address,
ourAddress: _publicAddress,
ourAddress: _publicAddress!,
);
if (hash.isNotEmpty) {
_representativeAddress = address;

View file

@ -9,12 +9,13 @@ import 'package:cw_core/wallet_service.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:cw_nano/nano_balance.dart';
import 'package:cw_nano/nano_client.dart';
import 'package:cw_nano/nano_mnemonic.dart';
import 'package:cw_nano/nano_mnemonic.dart' as nm;
import 'package:cw_nano/nano_util.dart';
import 'package:cw_nano/nano_wallet.dart';
import 'package:cw_nano/nano_wallet_info.dart';
import 'package:hive/hive.dart';
import 'package:bip39/bip39.dart' as bip39;
import 'package:nanodart/nanodart.dart';
class NanoNewWalletCredentials extends WalletCredentials {
NanoNewWalletCredentials({required String name, String? password})
@ -65,10 +66,18 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
@override
Future<WalletBase> create(NanoNewWalletCredentials credentials) async {
final mnemonic = bip39.generateMnemonic();
// nano standard:
DerivationType derivationType = DerivationType.nano;
String seedKey = NanoSeeds.generateSeed();
String mnemonic = NanoUtil.seedToMnemonic(seedKey);
// bip39:
// derivationType derivationType = DerivationType.bip39;
// String mnemonic = bip39.generateMnemonic();
final nanoWalletInfo = NanoWalletInfo(
walletInfo: credentials.walletInfo!,
derivationType: DerivationType.nano,
derivationType: derivationType,
);
final wallet = NanoWallet(
@ -76,6 +85,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
mnemonic: mnemonic,
password: credentials.password!,
);
wallet.init();
return wallet;
}
@ -178,11 +188,11 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
@override
Future<NanoWallet> restoreFromSeed(NanoRestoreWalletFromSeedCredentials credentials) async {
if (!bip39.validateMnemonic(credentials.mnemonic)) {
throw NanoMnemonicIsIncorrectException();
throw nm.NanoMnemonicIsIncorrectException();
}
if (!NanoMnemomics.validateMnemonic(credentials.mnemonic.split(' '))) {
throw NanoMnemonicIsIncorrectException();
throw nm.NanoMnemonicIsIncorrectException();
}
DerivationType derivationType = credentials.derivationType ??

View file

@ -44,42 +44,48 @@ part 'exchange_view_model.g.dart';
class ExchangeViewModel = ExchangeViewModelBase with _$ExchangeViewModel;
abstract class ExchangeViewModelBase with Store {
ExchangeViewModelBase(this.wallet, this.trades, this._exchangeTemplateStore,
this.tradesStore, this._settingsStore, this.sharedPreferences)
: _cryptoNumberFormat = NumberFormat(),
isFixedRateMode = false,
isReceiveAmountEntered = false,
depositAmount = '',
receiveAmount = '',
receiveAddress = '',
depositAddress = '',
isDepositAddressEnabled = false,
isReceiveAddressEnabled = false,
isReceiveAmountEditable = false,
_useTorOnly = false,
receiveCurrencies = <CryptoCurrency>[],
depositCurrencies = <CryptoCurrency>[],
limits = Limits(min: 0, max: 0),
tradeState = ExchangeTradeStateInitial(),
limitsState = LimitsInitialState(),
receiveCurrency = wallet.currency,
depositCurrency = wallet.currency,
providerList = [],
selectedProviders = ObservableList<ExchangeProvider>() {
ExchangeViewModelBase(this.wallet, this.trades, this._exchangeTemplateStore, this.tradesStore,
this._settingsStore, this.sharedPreferences)
: _cryptoNumberFormat = NumberFormat(),
isFixedRateMode = false,
isReceiveAmountEntered = false,
depositAmount = '',
receiveAmount = '',
receiveAddress = '',
depositAddress = '',
isDepositAddressEnabled = false,
isReceiveAddressEnabled = false,
isReceiveAmountEditable = false,
_useTorOnly = false,
receiveCurrencies = <CryptoCurrency>[],
depositCurrencies = <CryptoCurrency>[],
limits = Limits(min: 0, max: 0),
tradeState = ExchangeTradeStateInitial(),
limitsState = LimitsInitialState(),
receiveCurrency = wallet.currency,
depositCurrency = wallet.currency,
providerList = [],
selectedProviders = ObservableList<ExchangeProvider>() {
_useTorOnly = _settingsStore.exchangeStatus == ExchangeApiMode.torOnly;
_setProviders();
const excludeDepositCurrencies = [CryptoCurrency.btt, CryptoCurrency.nano];
const excludeReceiveCurrencies = [CryptoCurrency.xlm, CryptoCurrency.xrp,
CryptoCurrency.bnb, CryptoCurrency.btt, CryptoCurrency.nano];
const excludeReceiveCurrencies = [
CryptoCurrency.xlm,
CryptoCurrency.xrp,
CryptoCurrency.bnb,
CryptoCurrency.btt,
CryptoCurrency.nano
];
_initialPairBasedOnWallet();
final Map<String, dynamic> exchangeProvidersSelection = json
.decode(sharedPreferences.getString(PreferencesKey.exchangeProvidersSelection) ?? "{}") as Map<String, dynamic>;
final Map<String, dynamic> exchangeProvidersSelection =
json.decode(sharedPreferences.getString(PreferencesKey.exchangeProvidersSelection) ?? "{}")
as Map<String, dynamic>;
/// if the provider is not in the user settings (user's first time or newly added provider)
/// then use its default value decided by us
selectedProviders = ObservableList.of(providersForCurrentPair().where(
(element) => exchangeProvidersSelection[element.title] == null
selectedProviders = ObservableList.of(providersForCurrentPair()
.where((element) => exchangeProvidersSelection[element.title] == null
? element.isEnabled
: (exchangeProvidersSelection[element.title] as bool))
.toList());
@ -94,33 +100,29 @@ abstract class ExchangeViewModelBase with Store {
depositAmount = '';
receiveAmount = '';
receiveAddress = '';
depositAddress = depositCurrency == wallet.currency
? wallet.walletAddresses.address : '';
depositAddress = depositCurrency == wallet.currency ? wallet.walletAddresses.address : '';
provider = providersForCurrentPair().first;
final initialProvider = provider;
provider!.checkIsAvailable().then((bool isAvailable) {
if (!isAvailable && provider == initialProvider) {
provider = providerList.firstWhere(
(provider) => provider is ChangeNowExchangeProvider,
provider = providerList.firstWhere((provider) => provider is ChangeNowExchangeProvider,
orElse: () => providerList.last);
_onPairChange();
}
});
receiveCurrencies = CryptoCurrency.all
.where((cryptoCurrency) => !excludeReceiveCurrencies.contains(cryptoCurrency))
.toList();
.where((cryptoCurrency) => !excludeReceiveCurrencies.contains(cryptoCurrency))
.toList();
depositCurrencies = CryptoCurrency.all
.where((cryptoCurrency) => !excludeDepositCurrencies.contains(cryptoCurrency))
.toList();
.where((cryptoCurrency) => !excludeDepositCurrencies.contains(cryptoCurrency))
.toList();
_defineIsReceiveAmountEditable();
loadLimits();
reaction(
(_) => isFixedRateMode,
(Object _) {
loadLimits();
_bestRate = 0;
_calculateBestRate();
});
reaction((_) => isFixedRateMode, (Object _) {
loadLimits();
_bestRate = 0;
_calculateBestRate();
});
}
bool _useTorOnly;
final WalletBase wallet;
@ -148,7 +150,7 @@ abstract class ExchangeViewModelBase with Store {
/// initialize with descending comparator
/// since we want largest rate first
final SplayTreeMap<double, ExchangeProvider> _sortedAvailableProviders =
SplayTreeMap<double, ExchangeProvider>((double a, double b) => b.compareTo(a));
SplayTreeMap<double, ExchangeProvider>((double a, double b) => b.compareTo(a));
final List<ExchangeProvider> _tradeAvailableProviders = [];
@ -204,9 +206,7 @@ abstract class ExchangeViewModelBase with Store {
SyncStatus get status => wallet.syncStatus;
@computed
ObservableList<ExchangeTemplate> get templates =>
_exchangeTemplateStore.templates;
ObservableList<ExchangeTemplate> get templates => _exchangeTemplateStore.templates;
@computed
TransactionPriority get transactionPriority {
@ -219,13 +219,13 @@ abstract class ExchangeViewModelBase with Store {
return priority;
}
bool get hasAllAmount =>
(wallet.type == WalletType.bitcoin || wallet.type == WalletType.litecoin) && depositCurrency == wallet.currency;
(wallet.type == WalletType.bitcoin || wallet.type == WalletType.litecoin) &&
depositCurrency == wallet.currency;
bool get isMoneroWallet => wallet.type == WalletType.monero;
bool get isMoneroWallet => wallet.type == WalletType.monero;
bool get isLowFee {
bool get isLowFee {
switch (wallet.type) {
case WalletType.monero:
case WalletType.haven:
@ -340,20 +340,19 @@ abstract class ExchangeViewModelBase with Store {
final amount = double.tryParse(isFixedRateMode ? receiveAmount : depositAmount) ?? 1;
final _providers = _tradeAvailableProviders
.where((element) => !isFixedRateMode || element.supportsFixedRate).toList();
.where((element) => !isFixedRateMode || element.supportsFixedRate)
.toList();
final result = await Future.wait<double>(
_providers.map((element) => element.fetchRate(
from: depositCurrency,
to: receiveCurrency,
amount: amount,
isFixedRateMode: isFixedRateMode,
isReceiveAmount: isFixedRateMode))
);
final result = await Future.wait<double>(_providers.map((element) => element.fetchRate(
from: depositCurrency,
to: receiveCurrency,
amount: amount,
isFixedRateMode: isFixedRateMode,
isReceiveAmount: isFixedRateMode)));
_sortedAvailableProviders.clear();
for (int i=0;i<result.length;i++) {
for (int i = 0; i < result.length; i++) {
if (result[i] != 0) {
/// add this provider as its valid for this trade
try {
@ -377,12 +376,8 @@ abstract class ExchangeViewModelBase with Store {
limitsState = LimitsIsLoading();
final from = isFixedRateMode
? receiveCurrency
: depositCurrency;
final to = isFixedRateMode
? depositCurrency
: receiveCurrency;
final from = isFixedRateMode ? receiveCurrency : depositCurrency;
final to = isFixedRateMode ? depositCurrency : receiveCurrency;
double? lowestMin = double.maxFinite;
double? highestMax = 0.0;
@ -395,10 +390,8 @@ abstract class ExchangeViewModelBase with Store {
}
try {
final tempLimits = await provider.fetchLimits(
from: from,
to: to,
isFixedRateMode: isFixedRateMode);
final tempLimits =
await provider.fetchLimits(from: from, to: to, isFixedRateMode: isFixedRateMode);
if (lowestMin != null && (tempLimits.min ?? -1) < lowestMin) {
lowestMin = tempLimits.min;
@ -445,7 +438,7 @@ abstract class ExchangeViewModelBase with Store {
settleMethod: receiveCurrency,
depositAmount: isFixedRateMode
? receiveAmount.replaceAll(',', '.')
: depositAmount.replaceAll(',', '.'),
: depositAmount.replaceAll(',', '.'),
settleAddress: receiveAddress,
refundAddress: depositAddress,
);
@ -519,12 +512,13 @@ abstract class ExchangeViewModelBase with Store {
} else {
try {
tradeState = TradeIsCreating();
final trade = await provider.createTrade(
request: request!, isFixedRateMode: isFixedRateMode);
final trade =
await provider.createTrade(request: request!, isFixedRateMode: isFixedRateMode);
trade.walletId = wallet.id;
tradesStore.setTrade(trade);
await trades.add(trade);
tradeState = TradeIsCreatedSuccessfully(trade: trade);
/// return after the first successful trade
return;
} catch (e) {
@ -554,10 +548,8 @@ abstract class ExchangeViewModelBase with Store {
isReceiveAmountEntered = false;
depositAmount = '';
receiveAmount = '';
depositAddress = depositCurrency == wallet.currency
? wallet.walletAddresses.address : '';
receiveAddress = receiveCurrency == wallet.currency
? wallet.walletAddresses.address : '';
depositAddress = depositCurrency == wallet.currency ? wallet.walletAddresses.address : '';
receiveAddress = receiveCurrency == wallet.currency ? wallet.walletAddresses.address : '';
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
isFixedRateMode = false;
@ -611,10 +603,8 @@ abstract class ExchangeViewModelBase with Store {
List<ExchangeProvider> _providersForPair(
{required CryptoCurrency from, required CryptoCurrency to}) {
final providers = providerList
.where((provider) => provider.pairList
.where((pair) =>
pair.from == from && pair.to == to)
.isNotEmpty)
.where((provider) =>
provider.pairList.where((pair) => pair.from == from && pair.to == to).isNotEmpty)
.toList();
return providers;
@ -651,6 +641,10 @@ abstract class ExchangeViewModelBase with Store {
depositCurrency = CryptoCurrency.eth;
receiveCurrency = CryptoCurrency.xmr;
break;
case WalletType.nano:
depositCurrency = CryptoCurrency.nano;
receiveCurrency = CryptoCurrency.xmr;
break;
default:
break;
}
@ -694,8 +688,9 @@ abstract class ExchangeViewModelBase with Store {
_bestRate = 0;
_calculateBestRate();
final Map<String, dynamic> exchangeProvidersSelection = json
.decode(sharedPreferences.getString(PreferencesKey.exchangeProvidersSelection) ?? "{}") as Map<String, dynamic>;
final Map<String, dynamic> exchangeProvidersSelection =
json.decode(sharedPreferences.getString(PreferencesKey.exchangeProvidersSelection) ?? "{}")
as Map<String, dynamic>;
for (var provider in providerList) {
exchangeProvidersSelection[provider.title] = selectedProviders.contains(provider);
@ -709,15 +704,15 @@ abstract class ExchangeViewModelBase with Store {
bool get isAvailableInSelected {
final providersForPair = providersForCurrentPair();
return selectedProviders.any((element) => element.isAvailable && providersForPair.contains(element));
return selectedProviders
.any((element) => element.isAvailable && providersForPair.contains(element));
}
void _setAvailableProviders() {
_tradeAvailableProviders.clear();
_tradeAvailableProviders.addAll(
selectedProviders
.where((provider) => providersForCurrentPair().contains(provider)));
selectedProviders.where((provider) => providersForCurrentPair().contains(provider)));
}
@action
@ -738,7 +733,7 @@ abstract class ExchangeViewModelBase with Store {
}
}
void _setProviders(){
void _setProviders() {
if (_settingsStore.exchangeStatus == ExchangeApiMode.torOnly) {
providerList = _allProviders.where((provider) => provider.supportsOnionAddress).toList();
} else {