mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-06-28 12:29:51 +00:00
Minor nano fixes + abstract nano utils out into package (#1250)
* fixes * refactors * fixes * more fixes * fixes for monero.com * update confirmed balance to receivable balance * fix balance display bug * remove print statements * prevent unnecessary writes * review fixes * forgot to add pubspec changes * fix * fix sync status desyncing on rpc fail * fix * update translations + txDetails fixes * squash balance bug * add source address on tx info * fix
This commit is contained in:
parent
8d973cf919
commit
fe2e26f146
42 changed files with 306 additions and 518 deletions
|
@ -1,20 +1,19 @@
|
|||
import 'package:cw_core/balance.dart';
|
||||
import 'package:cw_nano/nano_util.dart';
|
||||
import 'package:nanoutil/nanoutil.dart';
|
||||
|
||||
class BananoBalance extends Balance {
|
||||
final BigInt currentBalance;
|
||||
final BigInt receivableBalance;
|
||||
|
||||
BananoBalance({required this.currentBalance, required this.receivableBalance}) : super(0, 0) {
|
||||
}
|
||||
BananoBalance({required this.currentBalance, required this.receivableBalance}) : super(0, 0);
|
||||
|
||||
@override
|
||||
String get formattedAvailableBalance {
|
||||
return NanoUtil.getRawAsUsableString(currentBalance.toString(), NanoUtil.rawPerBanano);
|
||||
return NanoAmounts.getRawAsUsableString(currentBalance.toString(), NanoAmounts.rawPerBanano);
|
||||
}
|
||||
|
||||
@override
|
||||
String get formattedAdditionalBalance {
|
||||
return NanoUtil.getRawAsUsableString(receivableBalance.toString(), NanoUtil.rawPerBanano);
|
||||
return NanoAmounts.getRawAsUsableString(receivableBalance.toString(), NanoAmounts.rawPerBanano);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,34 +1,35 @@
|
|||
import 'package:cw_core/balance.dart';
|
||||
import 'package:cw_nano/nano_util.dart';
|
||||
import 'package:nanoutil/nanoutil.dart';
|
||||
|
||||
BigInt stringAmountToBigInt(String amount) {
|
||||
return BigInt.parse(NanoUtil.getAmountAsRaw(amount, NanoUtil.rawPerNano));
|
||||
return BigInt.parse(NanoAmounts.getAmountAsRaw(amount, NanoAmounts.rawPerNano));
|
||||
}
|
||||
|
||||
class NanoBalance extends Balance {
|
||||
final BigInt currentBalance;
|
||||
final BigInt receivableBalance;
|
||||
late String formattedCurrentBalance;
|
||||
late String formattedReceivableBalance;
|
||||
|
||||
NanoBalance({required this.currentBalance, required this.receivableBalance}) : super(0, 0) {
|
||||
this.formattedCurrentBalance = "";
|
||||
this.formattedReceivableBalance = "";
|
||||
}
|
||||
NanoBalance({required this.currentBalance, required this.receivableBalance}) : super(0, 0);
|
||||
|
||||
NanoBalance.fromString(
|
||||
{required this.formattedCurrentBalance, required this.formattedReceivableBalance})
|
||||
NanoBalance.fromFormattedString(
|
||||
{required String formattedCurrentBalance, required String formattedReceivableBalance})
|
||||
: currentBalance = stringAmountToBigInt(formattedCurrentBalance),
|
||||
receivableBalance = stringAmountToBigInt(formattedReceivableBalance),
|
||||
super(0, 0);
|
||||
|
||||
NanoBalance.fromRawString(
|
||||
{required String currentBalance, required String receivableBalance})
|
||||
: currentBalance = BigInt.parse(currentBalance),
|
||||
receivableBalance = BigInt.parse(receivableBalance),
|
||||
super(0, 0);
|
||||
|
||||
@override
|
||||
String get formattedAvailableBalance {
|
||||
return NanoUtil.getRawAsUsableString(currentBalance.toString(), NanoUtil.rawPerNano);
|
||||
return NanoAmounts.getRawAsUsableString(currentBalance.toString(), NanoAmounts.rawPerNano);
|
||||
}
|
||||
|
||||
@override
|
||||
String get formattedAdditionalBalance {
|
||||
return NanoUtil.getRawAsUsableString(receivableBalance.toString(), NanoUtil.rawPerNano);
|
||||
return NanoAmounts.getRawAsUsableString(receivableBalance.toString(), NanoAmounts.rawPerNano);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,10 +4,10 @@ import 'dart:convert';
|
|||
import 'package:cw_core/nano_account_info_response.dart';
|
||||
import 'package:cw_nano/nano_balance.dart';
|
||||
import 'package:cw_nano/nano_transaction_model.dart';
|
||||
import 'package:cw_nano/nano_util.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:nanodart/nanodart.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:nanoutil/nanoutil.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class NanoClient {
|
||||
|
@ -61,6 +61,13 @@ class NanoClient {
|
|||
),
|
||||
);
|
||||
final data = await jsonDecode(response.body);
|
||||
if (response.statusCode != 200 ||
|
||||
data["error"] != null ||
|
||||
data["balance"] == null ||
|
||||
data["receivable"] == null) {
|
||||
throw Exception(
|
||||
"Error while trying to get balance! ${data["error"] != null ? data["error"] : ""}");
|
||||
}
|
||||
final String currentBalance = data["balance"] as String;
|
||||
final String receivableBalance = data["receivable"] as String;
|
||||
final BigInt cur = BigInt.parse(currentBalance);
|
||||
|
@ -203,7 +210,7 @@ class NanoClient {
|
|||
String? previousHash,
|
||||
}) async {
|
||||
// our address:
|
||||
final String publicAddress = NanoUtil.privateKeyToAddress(privateKey);
|
||||
final String publicAddress = NanoDerivations.privateKeyToAddress(privateKey);
|
||||
|
||||
// first get the current account balance:
|
||||
if (balanceAfterTx == null) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:cw_core/format_amount.dart';
|
||||
import 'package:cw_core/transaction_direction.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
import 'package:cw_nano/nano_util.dart';
|
||||
import 'package:nanoutil/nanoutil.dart';
|
||||
|
||||
class NanoTransactionInfo extends TransactionInfo {
|
||||
NanoTransactionInfo({
|
||||
|
@ -13,6 +13,8 @@ class NanoTransactionInfo extends TransactionInfo {
|
|||
required this.confirmed,
|
||||
required this.date,
|
||||
required this.confirmations,
|
||||
required this.to,
|
||||
required this.from,
|
||||
}) : this.amount = amountRaw.toInt();
|
||||
|
||||
final String id;
|
||||
|
@ -24,14 +26,17 @@ class NanoTransactionInfo extends TransactionInfo {
|
|||
final bool confirmed;
|
||||
final int confirmations;
|
||||
final String tokenSymbol;
|
||||
final String? to;
|
||||
final String? from;
|
||||
String? _fiatAmount;
|
||||
|
||||
bool get isPending => !this.confirmed;
|
||||
|
||||
@override
|
||||
String amountFormatted() {
|
||||
final String amt = NanoUtil.getRawAsUsableString(amountRaw.toString(), NanoUtil.rawPerNano);
|
||||
final String acc = NanoUtil.getRawAccuracy(amountRaw.toString(), NanoUtil.rawPerNano);
|
||||
final String amt =
|
||||
NanoAmounts.getRawAsUsableString(amountRaw.toString(), NanoAmounts.rawPerNano);
|
||||
final String acc = NanoAmounts.getRawAccuracy(amountRaw.toString(), NanoAmounts.rawPerNano);
|
||||
return "$acc$amt $tokenSymbol";
|
||||
}
|
||||
|
||||
|
@ -54,6 +59,8 @@ class NanoTransactionInfo extends TransactionInfo {
|
|||
confirmed: data['confirmed'] as bool,
|
||||
confirmations: data['confirmations'] as int,
|
||||
tokenSymbol: data['tokenSymbol'] as String,
|
||||
to: data['to'] as String,
|
||||
from: data['from'] as String,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -66,5 +73,7 @@ class NanoTransactionInfo extends TransactionInfo {
|
|||
'confirmed': confirmed,
|
||||
'confirmations': confirmations,
|
||||
'tokenSymbol': tokenSymbol,
|
||||
'to': to,
|
||||
'from': from,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,193 +0,0 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:convert/convert.dart';
|
||||
import "package:ed25519_hd_key/ed25519_hd_key.dart";
|
||||
import 'package:libcrypto/libcrypto.dart';
|
||||
import 'package:nanodart/nanodart.dart';
|
||||
import 'package:decimal/decimal.dart';
|
||||
|
||||
class NanoUtil {
|
||||
// standard:
|
||||
static String seedToPrivate(String seed, int index) {
|
||||
return NanoKeys.seedToPrivate(seed, index);
|
||||
}
|
||||
|
||||
static String seedToAddress(String seed, int index) {
|
||||
return NanoAccounts.createAccount(
|
||||
NanoAccountType.NANO, privateKeyToPublic(seedToPrivate(seed, index)));
|
||||
}
|
||||
|
||||
static String seedToMnemonic(String seed) {
|
||||
return NanoMnemomics.seedToMnemonic(seed).join(" ");
|
||||
}
|
||||
|
||||
static Future<String> mnemonicToSeed(String mnemonic) async {
|
||||
return NanoMnemomics.mnemonicListToSeed(mnemonic.split(' '));
|
||||
}
|
||||
|
||||
static String privateKeyToPublic(String privateKey) {
|
||||
// return NanoHelpers.byteToHex(Ed25519Blake2b.getPubkey(NanoHelpers.hexToBytes(privateKey))!);
|
||||
return NanoKeys.createPublicKey(privateKey);
|
||||
}
|
||||
|
||||
static String addressToPublicKey(String publicAddress) {
|
||||
return NanoAccounts.extractPublicKey(publicAddress);
|
||||
}
|
||||
|
||||
// universal:
|
||||
static String privateKeyToAddress(String privateKey) {
|
||||
return NanoAccounts.createAccount(NanoAccountType.NANO, privateKeyToPublic(privateKey));
|
||||
}
|
||||
|
||||
static String publicKeyToAddress(String publicKey) {
|
||||
return NanoAccounts.createAccount(NanoAccountType.NANO, publicKey);
|
||||
}
|
||||
|
||||
// standard + hd:
|
||||
static bool isValidSeed(String seed) {
|
||||
// Ensure seed is 64 or 128 characters long
|
||||
if (seed == null || (seed.length != 64 && seed.length != 128)) {
|
||||
return false;
|
||||
}
|
||||
// Ensure seed only contains hex characters, 0-9;A-F
|
||||
return NanoHelpers.isHexString(seed);
|
||||
}
|
||||
|
||||
// // hd:
|
||||
static Future<String> hdMnemonicListToSeed(List<String> words) async {
|
||||
// if (words.length != 24) {
|
||||
// throw Exception('Expected a 24-word list, got a ${words.length} list');
|
||||
// }
|
||||
final Uint8List salt = Uint8List.fromList(utf8.encode('mnemonic'));
|
||||
final Pbkdf2 hasher = Pbkdf2(iterations: 2048);
|
||||
final String seed = await hasher.sha512(words.join(' '), salt);
|
||||
return seed;
|
||||
}
|
||||
|
||||
static Future<String> hdSeedToPrivate(String seed, int index) async {
|
||||
List<int> seedBytes = hex.decode(seed);
|
||||
KeyData data = await ED25519_HD_KEY.derivePath("m/44'/165'/$index'", seedBytes);
|
||||
return hex.encode(data.key);
|
||||
}
|
||||
|
||||
static Future<String> hdSeedToAddress(String seed, int index) async {
|
||||
return NanoAccounts.createAccount(
|
||||
NanoAccountType.NANO, privateKeyToPublic(await hdSeedToPrivate(seed, index)));
|
||||
}
|
||||
|
||||
static Future<String> uniSeedToAddress(String seed, int index, String type) {
|
||||
if (type == "standard") {
|
||||
return Future<String>.value(seedToAddress(seed, index));
|
||||
} else if (type == "hd") {
|
||||
return hdSeedToAddress(seed, index);
|
||||
} else {
|
||||
throw Exception('Unknown seed type');
|
||||
}
|
||||
}
|
||||
|
||||
static Future<String> uniSeedToPrivate(String seed, int index, String type) {
|
||||
if (type == "standard") {
|
||||
return Future<String>.value(seedToPrivate(seed, index));
|
||||
} else if (type == "hd") {
|
||||
return hdSeedToPrivate(seed, index);
|
||||
} else {
|
||||
throw Exception('Unknown seed type');
|
||||
}
|
||||
}
|
||||
|
||||
static bool isValidBip39Seed(String seed) {
|
||||
// Ensure seed is 128 characters long
|
||||
if (seed.length != 128) {
|
||||
return false;
|
||||
}
|
||||
// Ensure seed only contains hex characters, 0-9;A-F
|
||||
return NanoHelpers.isHexString(seed);
|
||||
}
|
||||
|
||||
// number util:
|
||||
|
||||
static const int maxDecimalDigits = 6; // Max digits after decimal
|
||||
static BigInt rawPerNano = BigInt.parse("1000000000000000000000000000000");
|
||||
static BigInt rawPerNyano = BigInt.parse("1000000000000000000000000");
|
||||
static BigInt rawPerBanano = BigInt.parse("100000000000000000000000000000");
|
||||
static BigInt rawPerXMR = BigInt.parse("1000000000000");
|
||||
static BigInt convertXMRtoNano = BigInt.parse("1000000000000000000");
|
||||
// static BigInt convertXMRtoNano = BigInt.parse("1000000000000000000000000000");
|
||||
|
||||
/// Convert raw to ban and return as BigDecimal
|
||||
///
|
||||
/// @param raw 100000000000000000000000000000
|
||||
/// @return Decimal value 1.000000000000000000000000000000
|
||||
///
|
||||
static Decimal getRawAsDecimal(String? raw, BigInt? rawPerCur) {
|
||||
rawPerCur ??= rawPerNano;
|
||||
final Decimal amount = Decimal.parse(raw.toString());
|
||||
final Decimal result = (amount / Decimal.parse(rawPerCur.toString())).toDecimal();
|
||||
return result;
|
||||
}
|
||||
|
||||
static String truncateDecimal(Decimal input, {int digits = maxDecimalDigits}) {
|
||||
Decimal bigger = input.shift(digits);
|
||||
bigger = bigger.floor(); // chop off the decimal: 1.059 -> 1.05
|
||||
bigger = bigger.shift(-digits);
|
||||
return bigger.toString();
|
||||
}
|
||||
|
||||
/// Return raw as a NANO amount.
|
||||
///
|
||||
/// @param raw 100000000000000000000000000000
|
||||
/// @returns 1
|
||||
///
|
||||
static String getRawAsUsableString(String? raw, BigInt rawPerCur) {
|
||||
final String res =
|
||||
truncateDecimal(getRawAsDecimal(raw, rawPerCur), digits: maxDecimalDigits + 9);
|
||||
|
||||
if (raw == null || raw == "0" || raw == "00000000000000000000000000000000") {
|
||||
return "0";
|
||||
}
|
||||
|
||||
if (!res.contains(".")) {
|
||||
return res;
|
||||
}
|
||||
|
||||
final String numAmount = res.split(".")[0];
|
||||
String decAmount = res.split(".")[1];
|
||||
|
||||
// truncate:
|
||||
if (decAmount.length > maxDecimalDigits) {
|
||||
decAmount = decAmount.substring(0, maxDecimalDigits);
|
||||
// remove trailing zeros:
|
||||
decAmount = decAmount.replaceAllMapped(RegExp(r'0+$'), (Match match) => '');
|
||||
if (decAmount.isEmpty) {
|
||||
return numAmount;
|
||||
}
|
||||
}
|
||||
|
||||
return "$numAmount.$decAmount";
|
||||
}
|
||||
|
||||
static String getRawAccuracy(String? raw, BigInt rawPerCur) {
|
||||
final String rawString = getRawAsUsableString(raw, rawPerCur);
|
||||
final String rawDecimalString = getRawAsDecimal(raw, rawPerCur).toString();
|
||||
|
||||
if (raw == null || raw.isEmpty || raw == "0") {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (rawString != rawDecimalString) {
|
||||
return "~";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// Return readable string amount as raw string
|
||||
/// @param amount 1.01
|
||||
/// @returns 101000000000000000000000000000
|
||||
///
|
||||
static String getAmountAsRaw(String amount, BigInt rawPerCur) {
|
||||
final Decimal asDecimal = Decimal.parse(amount);
|
||||
final Decimal rawDecimal = Decimal.parse(rawPerCur.toString());
|
||||
return (asDecimal * rawDecimal).toString();
|
||||
}
|
||||
}
|
|
@ -18,7 +18,6 @@ import 'package:cw_nano/nano_client.dart';
|
|||
import 'package:cw_nano/nano_transaction_credentials.dart';
|
||||
import 'package:cw_nano/nano_transaction_history.dart';
|
||||
import 'package:cw_nano/nano_transaction_info.dart';
|
||||
import 'package:cw_nano/nano_util.dart';
|
||||
import 'package:cw_nano/nano_wallet_keys.dart';
|
||||
import 'package:cw_nano/pending_nano_transaction.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
@ -27,6 +26,7 @@ import 'package:cw_nano/nano_wallet_addresses.dart';
|
|||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:nanodart/nanodart.dart';
|
||||
import 'package:bip39/bip39.dart' as bip39;
|
||||
import 'package:nanoutil/nanoutil.dart';
|
||||
|
||||
part 'nano_wallet.g.dart';
|
||||
|
||||
|
@ -83,6 +83,8 @@ abstract class NanoWalletBase
|
|||
@observable
|
||||
late ObservableMap<CryptoCurrency, NanoBalance> balance;
|
||||
|
||||
static const int POLL_INTERVAL_SECONDS = 10;
|
||||
|
||||
// initialize the different forms of private / public key we'll need:
|
||||
Future<void> init() async {
|
||||
if (_derivationType == DerivationType.unknown) {
|
||||
|
@ -100,11 +102,21 @@ abstract class NanoWalletBase
|
|||
if (_derivationType == DerivationType.nano) {
|
||||
_hexSeed = bip39.mnemonicToEntropy(_mnemonic).toUpperCase();
|
||||
} else {
|
||||
_hexSeed = await NanoUtil.hdMnemonicListToSeed(_mnemonic.split(' '));
|
||||
_hexSeed = await NanoDerivations.hdMnemonicListToSeed(_mnemonic.split(' '));
|
||||
}
|
||||
}
|
||||
_privateKey = await NanoUtil.uniSeedToPrivate(_hexSeed!, 0, type);
|
||||
_publicAddress = await NanoUtil.uniSeedToAddress(_hexSeed!, 0, type);
|
||||
NanoDerivationType derivationType =
|
||||
type == "standard" ? NanoDerivationType.STANDARD : NanoDerivationType.HD;
|
||||
_privateKey = await NanoDerivations.universalSeedToPrivate(
|
||||
_hexSeed!,
|
||||
index: 0,
|
||||
type: derivationType,
|
||||
);
|
||||
_publicAddress = await NanoDerivations.universalSeedToAddress(
|
||||
_hexSeed!,
|
||||
index: 0,
|
||||
type: derivationType,
|
||||
);
|
||||
this.walletInfo.address = _publicAddress!;
|
||||
|
||||
await walletAddresses.init();
|
||||
|
@ -125,6 +137,7 @@ abstract class NanoWalletBase
|
|||
@override
|
||||
void close() {
|
||||
_client.stop();
|
||||
_receiveTimer?.cancel();
|
||||
}
|
||||
|
||||
@action
|
||||
|
@ -139,6 +152,7 @@ abstract class NanoWalletBase
|
|||
|
||||
try {
|
||||
await _updateBalance();
|
||||
await updateTransactions();
|
||||
await _updateRep();
|
||||
await _receiveAll();
|
||||
} catch (e) {
|
||||
|
@ -173,8 +187,8 @@ abstract class NanoWalletBase
|
|||
if (txOut.sendAll) {
|
||||
amt = balance[currency]?.currentBalance ?? BigInt.zero;
|
||||
} else {
|
||||
amt = BigInt.tryParse(NanoUtil.getAmountAsRaw(
|
||||
txOut.cryptoAmount?.replaceAll(',', '.') ?? "0", NanoUtil.rawPerNano)) ??
|
||||
amt = BigInt.tryParse(NanoAmounts.getAmountAsRaw(
|
||||
txOut.cryptoAmount?.replaceAll(',', '.') ?? "0", NanoAmounts.rawPerNano)) ??
|
||||
BigInt.zero;
|
||||
}
|
||||
|
||||
|
@ -186,9 +200,7 @@ abstract class NanoWalletBase
|
|||
|
||||
final block = await _client.constructSendBlock(
|
||||
amountRaw: amt.toString(),
|
||||
destinationAddress: txOut.isParsedAddress
|
||||
? txOut.extractedAddress!
|
||||
: txOut.address,
|
||||
destinationAddress: txOut.isParsedAddress ? txOut.extractedAddress! : txOut.address,
|
||||
privateKey: _privateKey!,
|
||||
balanceAfterTx: runningBalance,
|
||||
previousHash: previousHash,
|
||||
|
@ -236,10 +248,10 @@ abstract class NanoWalletBase
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> updateTransactions() async {
|
||||
Future<bool> updateTransactions() async {
|
||||
try {
|
||||
if (_isTransactionUpdating) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
_isTransactionUpdating = true;
|
||||
|
@ -247,8 +259,10 @@ abstract class NanoWalletBase
|
|||
transactionHistory.addMany(transactions);
|
||||
await transactionHistory.save();
|
||||
_isTransactionUpdating = false;
|
||||
return true;
|
||||
} catch (_) {
|
||||
_isTransactionUpdating = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,16 +275,17 @@ abstract class NanoWalletBase
|
|||
final Map<String, NanoTransactionInfo> result = {};
|
||||
|
||||
for (var transactionModel in transactions) {
|
||||
final bool isSend = transactionModel.type == "send";
|
||||
result[transactionModel.hash] = NanoTransactionInfo(
|
||||
id: transactionModel.hash,
|
||||
amountRaw: transactionModel.amount,
|
||||
height: transactionModel.height,
|
||||
direction: transactionModel.type == "send"
|
||||
? TransactionDirection.outgoing
|
||||
: TransactionDirection.incoming,
|
||||
direction: isSend ? TransactionDirection.outgoing : TransactionDirection.incoming,
|
||||
confirmed: transactionModel.confirmed,
|
||||
date: transactionModel.date ?? DateTime.now(),
|
||||
confirmations: transactionModel.confirmed ? 1 : 0,
|
||||
to: isSend ? transactionModel.account : address,
|
||||
from: isSend ? address : transactionModel.account,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -312,11 +327,10 @@ abstract class NanoWalletBase
|
|||
Future<void> startSync() async {
|
||||
try {
|
||||
syncStatus = AttemptingSyncStatus();
|
||||
await _updateBalance();
|
||||
await updateTransactions();
|
||||
|
||||
// setup a timer to receive transactions periodically:
|
||||
_receiveTimer?.cancel();
|
||||
_receiveTimer = Timer.periodic(const Duration(seconds: 15), (timer) async {
|
||||
_receiveTimer = Timer.periodic(const Duration(seconds: POLL_INTERVAL_SECONDS), (timer) async {
|
||||
// get our balance:
|
||||
await _updateBalance();
|
||||
// if we have anything to receive, process it:
|
||||
|
@ -325,6 +339,14 @@ abstract class NanoWalletBase
|
|||
}
|
||||
});
|
||||
|
||||
// also run once, immediately:
|
||||
await _updateBalance();
|
||||
bool updateSuccess = await updateTransactions();
|
||||
if (!updateSuccess) {
|
||||
syncStatus = FailedSyncStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
syncStatus = SyncedSyncStatus();
|
||||
} catch (e) {
|
||||
print(e);
|
||||
|
@ -353,9 +375,11 @@ abstract class NanoWalletBase
|
|||
|
||||
final data = json.decode(jsonSource) as Map;
|
||||
final mnemonic = data['mnemonic'] as String;
|
||||
final balance = NanoBalance.fromString(
|
||||
formattedCurrentBalance: data['currentBalance'] as String? ?? "0",
|
||||
formattedReceivableBalance: data['receivableBalance'] as String? ?? "0");
|
||||
|
||||
final balance = NanoBalance.fromRawString(
|
||||
currentBalance: data['currentBalance'] as String? ?? "0",
|
||||
receivableBalance: data['receivableBalance'] as String? ?? "0",
|
||||
);
|
||||
|
||||
DerivationType derivationType = DerivationType.nano;
|
||||
if (data['derivationType'] == "DerivationType.bip39") {
|
||||
|
@ -374,12 +398,26 @@ abstract class NanoWalletBase
|
|||
}
|
||||
|
||||
Future<void> _updateBalance() async {
|
||||
var oldBalance = balance[currency];
|
||||
try {
|
||||
balance[currency] = await _client.getBalance(_publicAddress!);
|
||||
} catch (e) {
|
||||
print("Failed to get balance $e");
|
||||
// if we don't have a balance, we should at least create one, since it's a late binding
|
||||
// otherwise, it's better to just leave it as whatever it was before:
|
||||
if (balance[currency] == null) {
|
||||
balance[currency] =
|
||||
NanoBalance(currentBalance: BigInt.zero, receivableBalance: BigInt.zero);
|
||||
}
|
||||
}
|
||||
// don't save unnecessarily:
|
||||
// trying to save too frequently can cause problems with the file system
|
||||
// since nano is updated frequently this can be a problem, so we only save if there is a change:
|
||||
if (oldBalance == null ||
|
||||
balance[currency]!.currentBalance != oldBalance.currentBalance ||
|
||||
balance[currency]!.receivableBalance != oldBalance.receivableBalance) {
|
||||
await save();
|
||||
}
|
||||
await save();
|
||||
}
|
||||
|
||||
Future<void> _updateRep() async {
|
||||
|
@ -394,11 +432,19 @@ abstract class NanoWalletBase
|
|||
}
|
||||
|
||||
Future<void> regenerateAddress() async {
|
||||
final String type = (_derivationType == DerivationType.nano) ? "standard" : "hd";
|
||||
_privateKey =
|
||||
await NanoUtil.uniSeedToPrivate(_hexSeed!, this.walletAddresses.account!.id, type);
|
||||
_publicAddress =
|
||||
await NanoUtil.uniSeedToAddress(_hexSeed!, this.walletAddresses.account!.id, type);
|
||||
final NanoDerivationType type = (_derivationType == DerivationType.nano)
|
||||
? NanoDerivationType.STANDARD
|
||||
: NanoDerivationType.HD;
|
||||
_privateKey = await NanoDerivations.universalSeedToPrivate(
|
||||
_hexSeed!,
|
||||
index: this.walletAddresses.account!.id,
|
||||
type: type,
|
||||
);
|
||||
_publicAddress = await NanoDerivations.universalSeedToAddress(
|
||||
_hexSeed!,
|
||||
index: this.walletAddresses.account!.id,
|
||||
type: type,
|
||||
);
|
||||
|
||||
this.walletInfo.address = _publicAddress!;
|
||||
this.walletAddresses.address = _publicAddress!;
|
||||
|
|
|
@ -6,12 +6,12 @@ import 'package:cw_core/wallet_info.dart';
|
|||
import 'package:cw_core/wallet_service.dart';
|
||||
import 'package:cw_core/wallet_type.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_creation_credentials.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:bip39/bip39.dart' as bip39;
|
||||
import 'package:nanodart/nanodart.dart';
|
||||
import 'package:nanoutil/nanoutil.dart';
|
||||
|
||||
class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
||||
NanoRestoreWalletFromSeedCredentials, NanoRestoreWalletFromKeysCredentials> {
|
||||
|
@ -30,7 +30,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
|||
// nano standard:
|
||||
DerivationType derivationType = DerivationType.nano;
|
||||
String seedKey = NanoSeeds.generateSeed();
|
||||
String mnemonic = NanoUtil.seedToMnemonic(seedKey);
|
||||
String mnemonic = NanoDerivations.standardSeedToMnemonic(seedKey);
|
||||
|
||||
credentials.walletInfo!.derivationType = derivationType;
|
||||
|
||||
|
@ -95,7 +95,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
|||
// we can't derive the mnemonic from the key in all cases, only if it's a "nano" seed
|
||||
if (credentials.seedKey.length == 64) {
|
||||
try {
|
||||
mnemonic = NanoUtil.seedToMnemonic(credentials.seedKey);
|
||||
mnemonic = NanoDerivations.standardSeedToMnemonic(credentials.seedKey);
|
||||
} catch (e) {
|
||||
throw Exception("Wasn't a valid nano style seed!");
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:cw_core/pending_transaction.dart';
|
||||
import 'package:cw_nano/nano_client.dart';
|
||||
import 'package:cw_nano/nano_util.dart';
|
||||
import 'package:nanoutil/nanoutil.dart';
|
||||
|
||||
class PendingNanoTransaction with PendingTransaction {
|
||||
PendingNanoTransaction({
|
||||
|
@ -18,13 +18,13 @@ class PendingNanoTransaction with PendingTransaction {
|
|||
|
||||
@override
|
||||
String get amountFormatted {
|
||||
final String amt = NanoUtil.getRawAsUsableString(amount.toString(), NanoUtil.rawPerNano);
|
||||
final String amt = NanoAmounts.getRawAsUsableString(amount.toString(), NanoAmounts.rawPerNano);
|
||||
return amt;
|
||||
}
|
||||
|
||||
String get accurateAmountFormatted {
|
||||
final String amt = NanoUtil.getRawAsUsableString(amount.toString(), NanoUtil.rawPerNano);
|
||||
final String acc = NanoUtil.getRawAccuracy(amount.toString(), NanoUtil.rawPerNano);
|
||||
final String amt = NanoAmounts.getRawAsUsableString(amount.toString(), NanoAmounts.rawPerNano);
|
||||
final String acc = NanoAmounts.getRawAccuracy(amount.toString(), NanoAmounts.rawPerNano);
|
||||
return "$acc$amt";
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,10 @@ dependencies:
|
|||
hex: ^0.2.0
|
||||
http: ^1.1.0
|
||||
shared_preferences: ^2.0.15
|
||||
nanoutil:
|
||||
git:
|
||||
url: https://github.com/perishllc/nanoutil.git
|
||||
ref: c37e72817cf0a28162f43124f79661d6c8e0098f
|
||||
cw_core:
|
||||
path: ../cw_core
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue