mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 11:39:22 +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,4 +1,24 @@
|
|||
cd scripts/android
|
||||
IOS="ios"
|
||||
ANDROID="android"
|
||||
|
||||
PLATFORMS=($IOS $ANDROID)
|
||||
PLATFORM=$1
|
||||
|
||||
if ! [[ " ${PLATFORMS[*]} " =~ " ${PLATFORM} " ]]; then
|
||||
echo "specify platform: ./configure_cake_wallet.sh ios|android"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$PLATFORM" == "$IOS" ]; then
|
||||
echo "Configuring for iOS"
|
||||
cd scripts/ios
|
||||
fi
|
||||
|
||||
if [ "$PLATFORM" == "$ANDROID" ]; then
|
||||
echo "Configuring for Android"
|
||||
cd scripts/android
|
||||
fi
|
||||
|
||||
source ./app_env.sh cakewallet
|
||||
./app_config.sh
|
||||
cd ../.. && flutter pub get
|
|
@ -15,6 +15,7 @@ abstract class TransactionInfo extends Object with Keyable {
|
|||
String? feeFormatted();
|
||||
void changeFiatAmount(String amount);
|
||||
String? to;
|
||||
String? from;
|
||||
|
||||
@override
|
||||
dynamic get keyIndex => id;
|
||||
|
|
|
@ -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,13 +398,27 @@ 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();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _updateRep() async {
|
||||
try {
|
||||
|
@ -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
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@ class CWNano extends Nano {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<void> updateTransactions(Object wallet) async {
|
||||
Future<bool> updateTransactions(Object wallet) async {
|
||||
return (wallet as NanoWallet).updateTransactions();
|
||||
}
|
||||
|
||||
|
@ -189,116 +189,10 @@ class CWNano extends Nano {
|
|||
}
|
||||
|
||||
class CWNanoUtil extends NanoUtil {
|
||||
// standard:
|
||||
@override
|
||||
String seedToPrivate(String seed, int index) {
|
||||
return ND.NanoKeys.seedToPrivate(seed, index);
|
||||
}
|
||||
|
||||
@override
|
||||
String seedToAddress(String seed, int index) {
|
||||
return ND.NanoAccounts.createAccount(
|
||||
ND.NanoAccountType.NANO, privateKeyToPublic(seedToPrivate(seed, index)));
|
||||
}
|
||||
|
||||
@override
|
||||
String seedToMnemonic(String seed) {
|
||||
return NanoMnemomics.seedToMnemonic(seed).join(" ");
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> mnemonicToSeed(String mnemonic) async {
|
||||
return NanoMnemomics.mnemonicListToSeed(mnemonic.split(' '));
|
||||
}
|
||||
|
||||
@override
|
||||
String privateKeyToPublic(String privateKey) {
|
||||
// return NanoHelpers.byteToHex(Ed25519Blake2b.getPubkey(NanoHelpers.hexToBytes(privateKey))!);
|
||||
return ND.NanoKeys.createPublicKey(privateKey);
|
||||
}
|
||||
|
||||
@override
|
||||
String addressToPublicKey(String publicAddress) {
|
||||
return ND.NanoAccounts.extractPublicKey(publicAddress);
|
||||
}
|
||||
|
||||
// universal:
|
||||
@override
|
||||
String privateKeyToAddress(String privateKey) {
|
||||
return ND.NanoAccounts.createAccount(ND.NanoAccountType.NANO, privateKeyToPublic(privateKey));
|
||||
}
|
||||
|
||||
@override
|
||||
String publicKeyToAddress(String publicKey) {
|
||||
return ND.NanoAccounts.createAccount(ND.NanoAccountType.NANO, publicKey);
|
||||
}
|
||||
|
||||
// standard + hd:
|
||||
@override
|
||||
bool isValidSeed(String seed) {
|
||||
// Ensure seed is 64 or 128 characters long
|
||||
if (seed.length != 64 && seed.length != 128) {
|
||||
return false;
|
||||
}
|
||||
// Ensure seed only contains hex characters, 0-9;A-F
|
||||
return ND.NanoHelpers.isHexString(seed);
|
||||
}
|
||||
|
||||
// hd:
|
||||
@override
|
||||
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;
|
||||
}
|
||||
|
||||
@override
|
||||
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);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> hdSeedToAddress(String seed, int index) async {
|
||||
return ND.NanoAccounts.createAccount(
|
||||
ND.NanoAccountType.NANO, privateKeyToPublic(await hdSeedToPrivate(seed, index)));
|
||||
}
|
||||
|
||||
@override
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
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 ND.NanoHelpers.isHexString(seed);
|
||||
return NanoDerivations.isValidBip39Seed(seed);
|
||||
}
|
||||
|
||||
// number util:
|
||||
|
@ -309,92 +203,20 @@ class CWNanoUtil extends NanoUtil {
|
|||
BigInt rawPerBanano = BigInt.parse("100000000000000000000000000000");
|
||||
BigInt rawPerXMR = BigInt.parse("1000000000000");
|
||||
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
|
||||
///
|
||||
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;
|
||||
}
|
||||
|
||||
@override
|
||||
String getRawAsDecimalString(String? raw, BigInt? rawPerCur) {
|
||||
final Decimal result = _getRawAsDecimal(raw, rawPerCur);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
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
|
||||
///
|
||||
@override
|
||||
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";
|
||||
return NanoAmounts.getRawAsUsableString(raw, rawPerCur);
|
||||
}
|
||||
|
||||
@override
|
||||
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 "";
|
||||
return NanoAmounts.getRawAccuracy(raw, rawPerCur);
|
||||
}
|
||||
|
||||
if (rawString != rawDecimalString) {
|
||||
return "~";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// Return readable string amount as raw string
|
||||
/// @param amount 1.01
|
||||
/// @returns 101000000000000000000000000000
|
||||
///
|
||||
@override
|
||||
String getAmountAsRaw(String amount, BigInt rawPerCur) {
|
||||
final Decimal asDecimal = Decimal.parse(amount);
|
||||
final Decimal rawDecimal = Decimal.parse(rawPerCur.toString());
|
||||
return (asDecimal * rawDecimal).toString();
|
||||
return NanoAmounts.getAmountAsRaw(amount, rawPerCur);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -411,29 +233,29 @@ class CWNanoUtil extends NanoUtil {
|
|||
if (seedKey != null) {
|
||||
if (seedKey.length == 64) {
|
||||
try {
|
||||
mnemonic = nanoUtil!.seedToMnemonic(seedKey);
|
||||
mnemonic = NanoDerivations.standardSeedToMnemonic(seedKey);
|
||||
} catch (e) {
|
||||
print("not a valid 'nano' seed key");
|
||||
}
|
||||
}
|
||||
if (derivationType == DerivationType.bip39) {
|
||||
publicAddress = await hdSeedToAddress(seedKey, 0);
|
||||
publicAddress = await NanoDerivations.hdSeedToAddress(seedKey, index: 0);
|
||||
} else if (derivationType == DerivationType.nano) {
|
||||
publicAddress = await seedToAddress(seedKey, 0);
|
||||
publicAddress = await NanoDerivations.standardSeedToAddress(seedKey, index: 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (derivationType == DerivationType.bip39) {
|
||||
if (mnemonic != null) {
|
||||
seedKey = await hdMnemonicListToSeed(mnemonic.split(' '));
|
||||
publicAddress = await hdSeedToAddress(seedKey, 0);
|
||||
seedKey = await NanoDerivations.hdMnemonicListToSeed(mnemonic.split(' '));
|
||||
publicAddress = await NanoDerivations.hdSeedToAddress(seedKey, index: 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (derivationType == DerivationType.nano) {
|
||||
if (mnemonic != null) {
|
||||
seedKey = await mnemonicToSeed(mnemonic);
|
||||
publicAddress = await seedToAddress(seedKey, 0);
|
||||
seedKey = await NanoDerivations.standardMnemonicToSeed(mnemonic);
|
||||
publicAddress = await NanoDerivations.standardSeedToAddress(seedKey, index: 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -461,7 +283,7 @@ class CWNanoUtil extends NanoUtil {
|
|||
return [DerivationType.bip39];
|
||||
} else if (seedKey?.length == 64) {
|
||||
try {
|
||||
mnemonic = nanoUtil!.seedToMnemonic(seedKey!);
|
||||
mnemonic = NanoDerivations.standardSeedToMnemonic(seedKey!);
|
||||
} catch (e) {
|
||||
print("not a valid 'nano' seed key");
|
||||
}
|
||||
|
@ -475,19 +297,19 @@ class CWNanoUtil extends NanoUtil {
|
|||
nanoClient.connect(node);
|
||||
|
||||
if (mnemonic != null) {
|
||||
seedKey = await hdMnemonicListToSeed(mnemonic.split(' '));
|
||||
publicAddressBip39 = await hdSeedToAddress(seedKey, 0);
|
||||
seedKey = await NanoDerivations.hdMnemonicListToSeed(mnemonic.split(' '));
|
||||
publicAddressBip39 = await NanoDerivations.hdSeedToAddress(seedKey, index: 0);
|
||||
|
||||
seedKey = await mnemonicToSeed(mnemonic);
|
||||
publicAddressStandard = await seedToAddress(seedKey, 0);
|
||||
seedKey = await NanoDerivations.standardMnemonicToSeed(mnemonic);
|
||||
publicAddressStandard = await NanoDerivations.standardSeedToAddress(seedKey, index: 0);
|
||||
} else if (seedKey != null) {
|
||||
try {
|
||||
publicAddressBip39 = await hdSeedToAddress(seedKey, 0);
|
||||
publicAddressBip39 = await NanoDerivations.hdSeedToAddress(seedKey, index: 0);
|
||||
} catch (e) {
|
||||
return [DerivationType.nano];
|
||||
}
|
||||
try {
|
||||
publicAddressStandard = await seedToAddress(seedKey, 0);
|
||||
publicAddressStandard = await NanoDerivations.standardSeedToAddress(seedKey, index: 0);
|
||||
} catch (e) {
|
||||
return [DerivationType.bip39];
|
||||
}
|
||||
|
|
|
@ -125,6 +125,8 @@ abstract class BalanceViewModelBase with Store {
|
|||
case WalletType.haven:
|
||||
case WalletType.ethereum:
|
||||
case WalletType.polygon:
|
||||
case WalletType.nano:
|
||||
case WalletType.banano:
|
||||
return S.current.xmr_available_balance;
|
||||
default:
|
||||
return S.current.confirmed;
|
||||
|
@ -139,6 +141,9 @@ abstract class BalanceViewModelBase with Store {
|
|||
case WalletType.ethereum:
|
||||
case WalletType.polygon:
|
||||
return S.current.xmr_full_balance;
|
||||
case WalletType.nano:
|
||||
case WalletType.banano:
|
||||
return S.current.receivable_balance;
|
||||
default:
|
||||
return S.current.unconfirmed;
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ class TransactionListItem extends ActionListItem with Keyable {
|
|||
break;
|
||||
case WalletType.nano:
|
||||
amount = calculateFiatAmountRaw(
|
||||
cryptoAmount: double.parse(nanoUtil!.getRawAsDecimalString(
|
||||
cryptoAmount: double.parse(nanoUtil!.getRawAsUsableString(
|
||||
nano!.getTransactionAmountRaw(transaction).toString(), nanoUtil!.rawPerNano)),
|
||||
price: price);
|
||||
break;
|
||||
|
|
|
@ -247,11 +247,15 @@ abstract class TransactionDetailsViewModelBase with Store {
|
|||
void _addNanoListItems(TransactionInfo tx, DateFormat dateFormat) {
|
||||
final _items = [
|
||||
StandartListItem(title: S.current.transaction_details_transaction_id, value: tx.id),
|
||||
if (showRecipientAddress && tx.to != null)
|
||||
StandartListItem(title: S.current.transaction_details_recipient_address, value: tx.to!),
|
||||
if (showRecipientAddress && tx.from != null)
|
||||
StandartListItem(title: S.current.transaction_details_source_address, value: tx.from!),
|
||||
StandartListItem(title: S.current.transaction_details_amount, value: tx.amountFormatted()),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_date, value: dateFormat.format(tx.date)),
|
||||
StandartListItem(title: S.current.confirmations, value: (tx.confirmations > 0).toString()),
|
||||
StandartListItem(title: S.current.confirmed_tx, value: (tx.confirmations > 0).toString()),
|
||||
StandartListItem(title: S.current.transaction_details_height, value: '${tx.height}'),
|
||||
StandartListItem(title: S.current.transaction_details_amount, value: tx.amountFormatted()),
|
||||
];
|
||||
|
||||
items.addAll(_items);
|
||||
|
|
|
@ -759,5 +759,8 @@
|
|||
"default_sell_provider": " ﻲﺿﺍﺮﺘﻓﻻﺍ ﻊﻴﺒﻟﺍ ﺩﻭﺰﻣ",
|
||||
"select_sell_provider_notice": ".ﻖﻴﺒﻄﺘﻟﺍ ﺕﺍﺩﺍﺪﻋﺇ ﻲﻓ ﻚﺑ ﺹﺎﺨﻟﺍ ﻲﺿﺍﺮﺘﻓﻻﺍ ﻊﻴﺒﻟﺍ ﺩﻭﺰﻣ ﻦﻴﻴﻌﺗ ﻖﻳﺮﻃ ﻦﻋ ﺔﺷﺎﺸﻟﺍ ﻩﺬﻫ ﻲﻄﺨﺗ",
|
||||
"custom_drag": "مخصص (عقد وسحب)",
|
||||
"switchToEVMCompatibleWallet": " (Ethereum، Polygon) ﻯﺮﺧﺃ ﺓﺮﻣ ﺔﻟﻭﺎﺤﻤﻟﺍﻭ EVM ﻊﻣ ﺔﻘﻓﺍﻮﺘﻣ ﺔﻈﻔﺤﻣ ﻰﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻰﺟﺮﻳ"
|
||||
"switchToEVMCompatibleWallet": " (Ethereum، Polygon) ﻯﺮﺧﺃ ﺓﺮﻣ ﺔﻟﻭﺎﺤﻤﻟﺍﻭ EVM ﻊﻣ ﺔﻘﻓﺍﻮﺘﻣ ﺔﻈﻔﺤﻣ ﻰﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻰﺟﺮﻳ",
|
||||
"receivable_balance": "التوازن القادم",
|
||||
"confirmed_tx": "مؤكد",
|
||||
"transaction_details_source_address": "عنوان المصدر"
|
||||
}
|
|
@ -755,5 +755,8 @@
|
|||
"default_sell_provider": "Доставчик за продажба по подразбиране",
|
||||
"select_sell_provider_notice": "Изберете доставчик на продажба по-горе. Можете да пропуснете този екран, като зададете своя доставчик на продажба по подразбиране в настройките на приложението.",
|
||||
"custom_drag": "Персонализиране (задръжте и плъзнете)",
|
||||
"switchToEVMCompatibleWallet": "Моля, превключете към портфейл, съвместим с EVM, и опитайте отново (Ethereum, Polygon)"
|
||||
"switchToEVMCompatibleWallet": "Моля, превключете към портфейл, съвместим с EVM, и опитайте отново (Ethereum, Polygon)",
|
||||
"receivable_balance": "Баланс за вземания",
|
||||
"confirmed_tx": "Потвърдено",
|
||||
"transaction_details_source_address": "Адрес на източника"
|
||||
}
|
|
@ -755,5 +755,8 @@
|
|||
"default_sell_provider": "Výchozí poskytovatel prodeje",
|
||||
"select_sell_provider_notice": "Výše vyberte poskytovatele prodeje. Tuto obrazovku můžete přeskočit nastavením výchozího poskytovatele prodeje v nastavení aplikace.",
|
||||
"custom_drag": "Custom (Hold and Drag)",
|
||||
"switchToEVMCompatibleWallet": "Přepněte na peněženku kompatibilní s EVM a zkuste to znovu (Ethereum, Polygon)"
|
||||
"switchToEVMCompatibleWallet": "Přepněte na peněženku kompatibilní s EVM a zkuste to znovu (Ethereum, Polygon)",
|
||||
"receivable_balance": "Zůstatek pohledávek",
|
||||
"confirmed_tx": "Potvrzeno",
|
||||
"transaction_details_source_address": "Zdrojová adresa"
|
||||
}
|
|
@ -763,5 +763,8 @@
|
|||
"default_sell_provider": "Standard-Verkaufsanbieter",
|
||||
"select_sell_provider_notice": "Wählen Sie oben einen Verkaufsanbieter aus. Sie können diesen Bildschirm überspringen, indem Sie in den App-Einstellungen Ihren Standard-Verkaufsanbieter festlegen.",
|
||||
"custom_drag": "Custom (Hold and Drag)",
|
||||
"switchToEVMCompatibleWallet": "Bitte wechseln Sie zu einem EVM-kompatiblen Wallet und versuchen Sie es erneut (Ethereum, Polygon)"
|
||||
"switchToEVMCompatibleWallet": "Bitte wechseln Sie zu einem EVM-kompatiblen Wallet und versuchen Sie es erneut (Ethereum, Polygon)",
|
||||
"receivable_balance": "Forderungsbilanz",
|
||||
"confirmed_tx": "Bestätigt",
|
||||
"transaction_details_source_address": "Quelladresse"
|
||||
}
|
|
@ -764,5 +764,8 @@
|
|||
"default_sell_provider": "Default Sell Provider",
|
||||
"select_sell_provider_notice": "Select a sell provider above. You can skip this screen by setting your default sell provider in app settings.",
|
||||
"custom_drag": "Custom (Hold and Drag)",
|
||||
"switchToEVMCompatibleWallet": "Please switch to an EVM compatible wallet and try again (Ethereum, Polygon)"
|
||||
"switchToEVMCompatibleWallet": "Please switch to an EVM compatible wallet and try again (Ethereum, Polygon)",
|
||||
"receivable_balance": "Receivable Balance",
|
||||
"confirmed_tx": "Confirmed",
|
||||
"transaction_details_source_address": "Source address"
|
||||
}
|
|
@ -763,5 +763,8 @@
|
|||
"default_sell_provider": "Proveedor de venta predeterminado",
|
||||
"select_sell_provider_notice": "Seleccione un proveedor de venta arriba. Puede omitir esta pantalla configurando su proveedor de venta predeterminado en la configuración de la aplicación.",
|
||||
"custom_drag": "Custom (mantenía y arrastre)",
|
||||
"switchToEVMCompatibleWallet": "Cambie a una billetera compatible con EVM e inténtelo nuevamente (Ethereum, Polygon)"
|
||||
"switchToEVMCompatibleWallet": "Cambie a una billetera compatible con EVM e inténtelo nuevamente (Ethereum, Polygon)",
|
||||
"receivable_balance": "Saldo de cuentas por cobrar",
|
||||
"confirmed_tx": "Confirmado",
|
||||
"transaction_details_source_address": "Dirección de la fuente"
|
||||
}
|
|
@ -763,5 +763,8 @@
|
|||
"default_sell_provider": "Fournisseur de vente par défaut",
|
||||
"select_sell_provider_notice": "Sélectionnez un fournisseur de vente ci-dessus. Vous pouvez ignorer cet écran en définissant votre fournisseur de vente par défaut dans les paramètres de l'application.",
|
||||
"custom_drag": "Custom (maintenir et traîner)",
|
||||
"switchToEVMCompatibleWallet": "Veuillez passer à un portefeuille compatible EVM et réessayer (Ethereum, Polygon)"
|
||||
"switchToEVMCompatibleWallet": "Veuillez passer à un portefeuille compatible EVM et réessayer (Ethereum, Polygon)",
|
||||
"receivable_balance": "Solde de créances",
|
||||
"confirmed_tx": "Confirmé",
|
||||
"transaction_details_source_address": "Adresse source"
|
||||
}
|
|
@ -745,5 +745,8 @@
|
|||
"default_sell_provider": "Tsohuwar Mai Bayar Siyarwa",
|
||||
"select_sell_provider_notice": "Zaɓi mai bada siyarwa a sama. Kuna iya tsallake wannan allon ta saita mai bada siyar da ku a cikin saitunan app.",
|
||||
"custom_drag": "Al'ada (riƙe da ja)",
|
||||
"switchToEVMCompatibleWallet": "Da fatan za a canza zuwa walat ɗin EVM mai jituwa kuma a sake gwadawa (Ethereum, Polygon)"
|
||||
"switchToEVMCompatibleWallet": "Da fatan za a canza zuwa walat ɗin EVM mai jituwa kuma a sake gwadawa (Ethereum, Polygon)",
|
||||
"receivable_balance": "Daidaituwa da daidaituwa",
|
||||
"confirmed_tx": "Tabbatar",
|
||||
"transaction_details_source_address": "Adireshin Incord"
|
||||
}
|
|
@ -763,5 +763,8 @@
|
|||
"default_sell_provider": "डिफ़ॉल्ट विक्रय प्रदाता",
|
||||
"select_sell_provider_notice": "ऊपर एक विक्रय प्रदाता का चयन करें। आप ऐप सेटिंग में अपना डिफ़ॉल्ट विक्रय प्रदाता सेट करके इस स्क्रीन को छोड़ सकते हैं।",
|
||||
"custom_drag": "कस्टम (पकड़ और खींचें)",
|
||||
"switchToEVMCompatibleWallet": "कृपया ईवीएम संगत वॉलेट पर स्विच करें और पुनः प्रयास करें (एथेरियम, पॉलीगॉन)"
|
||||
"switchToEVMCompatibleWallet": "कृपया ईवीएम संगत वॉलेट पर स्विच करें और पुनः प्रयास करें (एथेरियम, पॉलीगॉन)",
|
||||
"receivable_balance": "प्राप्य शेष",
|
||||
"confirmed_tx": "की पुष्टि",
|
||||
"transaction_details_source_address": "स्रोत पता"
|
||||
}
|
|
@ -761,5 +761,8 @@
|
|||
"default_sell_provider": "Zadani dobavljač prodaje",
|
||||
"select_sell_provider_notice": "Gore odaberite pružatelja usluga prodaje. Ovaj zaslon možete preskočiti postavljanjem zadanog pružatelja usluga prodaje u postavkama aplikacije.",
|
||||
"custom_drag": "Prilagođeni (držite i povucite)",
|
||||
"switchToEVMCompatibleWallet": "Prijeđite na novčanik kompatibilan s EVM-om i pokušajte ponovno (Ethereum, Polygon)"
|
||||
"switchToEVMCompatibleWallet": "Prijeđite na novčanik kompatibilan s EVM-om i pokušajte ponovno (Ethereum, Polygon)",
|
||||
"receivable_balance": "Stanje potraživanja",
|
||||
"confirmed_tx": "Potvrđen",
|
||||
"transaction_details_source_address": "Adresa izvora"
|
||||
}
|
|
@ -751,5 +751,8 @@
|
|||
"default_sell_provider": "Penyedia Penjualan Default",
|
||||
"select_sell_provider_notice": "Pilih penyedia jual di atas. Anda dapat melewati layar ini dengan mengatur penyedia penjualan default Anda di pengaturan aplikasi.",
|
||||
"custom_drag": "Khusus (tahan dan seret)",
|
||||
"switchToEVMCompatibleWallet": "Silakan beralih ke dompet yang kompatibel dengan EVM dan coba lagi (Ethereum, Polygon)"
|
||||
"switchToEVMCompatibleWallet": "Silakan beralih ke dompet yang kompatibel dengan EVM dan coba lagi (Ethereum, Polygon)",
|
||||
"receivable_balance": "Saldo piutang",
|
||||
"confirmed_tx": "Dikonfirmasi",
|
||||
"transaction_details_source_address": "Alamat sumber"
|
||||
}
|
|
@ -763,5 +763,8 @@
|
|||
"default_sell_provider": "Fornitore di vendita predefinito",
|
||||
"select_sell_provider_notice": "Seleziona un fornitore di vendita sopra. Puoi saltare questa schermata impostando il tuo fornitore di vendita predefinito nelle impostazioni dell'app.",
|
||||
"custom_drag": "Custom (Hold and Drag)",
|
||||
"switchToEVMCompatibleWallet": "Passa a un portafoglio compatibile con EVM e riprova (Ethereum, Polygon)"
|
||||
"switchToEVMCompatibleWallet": "Passa a un portafoglio compatibile con EVM e riprova (Ethereum, Polygon)",
|
||||
"receivable_balance": "Bilanciamento creditizio",
|
||||
"confirmed_tx": "Confermato",
|
||||
"transaction_details_source_address": "Indirizzo di partenza"
|
||||
}
|
|
@ -763,5 +763,8 @@
|
|||
"default_sell_provider": "デフォルトの販売プロバイダー",
|
||||
"select_sell_provider_notice": "上記の販売プロバイダーを選択してください。アプリ設定でデフォルトの販売プロバイダーを設定することで、この画面をスキップできます。",
|
||||
"custom_drag": "カスタム(ホールドとドラッグ)",
|
||||
"switchToEVMCompatibleWallet": "EVM 互換のウォレットに切り替えて再試行してください (イーサリアム、ポリゴン)"
|
||||
"switchToEVMCompatibleWallet": "EVM 互換のウォレットに切り替えて再試行してください (イーサリアム、ポリゴン)",
|
||||
"receivable_balance": "売掛金残高",
|
||||
"confirmed_tx": "確認済み",
|
||||
"transaction_details_source_address": "ソースアドレス"
|
||||
}
|
|
@ -761,5 +761,8 @@
|
|||
"default_sell_provider": "기본 판매 공급자",
|
||||
"select_sell_provider_notice": "위에서 판매 공급자를 선택하세요. 앱 설정에서 기본 판매 공급자를 설정하면 이 화면을 건너뛸 수 있습니다.",
|
||||
"custom_drag": "사용자 정의 (홀드 앤 드래그)",
|
||||
"switchToEVMCompatibleWallet": "EVM 호환 지갑으로 전환 후 다시 시도해 주세요. (이더리움, 폴리곤)"
|
||||
"switchToEVMCompatibleWallet": "EVM 호환 지갑으로 전환 후 다시 시도해 주세요. (이더리움, 폴리곤)",
|
||||
"receivable_balance": "채권 잔액",
|
||||
"confirmed_tx": "확인",
|
||||
"transaction_details_source_address": "소스 주소"
|
||||
}
|
|
@ -761,5 +761,8 @@
|
|||
"default_sell_provider": "ပုံသေရောင်းချပေးသူ",
|
||||
"select_sell_provider_notice": "အထက်ဖော်ပြပါ အရောင်းဝန်ဆောင်မှုပေးသူကို ရွေးပါ။ အက်ပ်ဆက်တင်များတွင် သင်၏မူလရောင်းချပေးသူကို သတ်မှတ်ခြင်းဖြင့် ဤစခရင်ကို ကျော်နိုင်သည်။",
|
||||
"custom_drag": "စိတ်ကြိုက် (Drag)",
|
||||
"switchToEVMCompatibleWallet": "ကျေးဇူးပြု၍ EVM တွဲဖက်သုံးနိုင်သော ပိုက်ဆံအိတ်သို့ ပြောင်းပြီး ထပ်စမ်းကြည့်ပါ (Ethereum၊ Polygon)"
|
||||
"switchToEVMCompatibleWallet": "ကျေးဇူးပြု၍ EVM တွဲဖက်သုံးနိုင်သော ပိုက်ဆံအိတ်သို့ ပြောင်းပြီး ထပ်စမ်းကြည့်ပါ (Ethereum၊ Polygon)",
|
||||
"receivable_balance": "လက်ကျန်ငွေ",
|
||||
"confirmed_tx": "အတည်ပြုသည်",
|
||||
"transaction_details_source_address": "အရင်းအမြစ်လိပ်စာ"
|
||||
}
|
|
@ -763,5 +763,8 @@
|
|||
"default_sell_provider": "Standaard verkoopaanbieder",
|
||||
"select_sell_provider_notice": "Selecteer hierboven een verkoopaanbieder. U kunt dit scherm overslaan door uw standaardverkoopprovider in te stellen in de app-instellingen.",
|
||||
"custom_drag": "Custom (vasthouden en slepen)",
|
||||
"switchToEVMCompatibleWallet": "Schakel over naar een EVM-compatibele portemonnee en probeer het opnieuw (Ethereum, Polygon)"
|
||||
"switchToEVMCompatibleWallet": "Schakel over naar een EVM-compatibele portemonnee en probeer het opnieuw (Ethereum, Polygon)",
|
||||
"receivable_balance": "Het saldo",
|
||||
"confirmed_tx": "Bevestigd",
|
||||
"transaction_details_source_address": "Bron adres"
|
||||
}
|
|
@ -763,5 +763,8 @@
|
|||
"default_sell_provider": "Domyślny dostawca sprzedaży",
|
||||
"select_sell_provider_notice": "Wybierz dostawcę sprzedaży powyżej. Możesz pominąć ten ekran, ustawiając domyślnego dostawcę sprzedaży w ustawieniach aplikacji.",
|
||||
"custom_drag": "Niestandardowe (trzymaj i przeciągnij)",
|
||||
"switchToEVMCompatibleWallet": "Przejdź na portfel zgodny z EVM i spróbuj ponownie (Ethereum, Polygon)"
|
||||
"switchToEVMCompatibleWallet": "Przejdź na portfel zgodny z EVM i spróbuj ponownie (Ethereum, Polygon)",
|
||||
"receivable_balance": "Saldo należności",
|
||||
"confirmed_tx": "Potwierdzony",
|
||||
"transaction_details_source_address": "Adres źródłowy"
|
||||
}
|
|
@ -762,5 +762,8 @@
|
|||
"default_sell_provider": "Provedor de venda padrão",
|
||||
"select_sell_provider_notice": "Selecione um fornecedor de venda acima. Você pode pular esta tela definindo seu provedor de venda padrão nas configurações do aplicativo.",
|
||||
"custom_drag": "Personalizado (segure e arraste)",
|
||||
"switchToEVMCompatibleWallet": "Mude para uma carteira compatível com EVM e tente novamente (Ethereum, Polygon)"
|
||||
"switchToEVMCompatibleWallet": "Mude para uma carteira compatível com EVM e tente novamente (Ethereum, Polygon)",
|
||||
"receivable_balance": "Saldo a receber",
|
||||
"confirmed_tx": "Confirmado",
|
||||
"transaction_details_source_address": "Endereço de Origem"
|
||||
}
|
|
@ -763,5 +763,8 @@
|
|||
"default_sell_provider": "Поставщик продаж по умолчанию",
|
||||
"select_sell_provider_notice": "Выберите поставщика услуг продажи выше. Вы можете пропустить этот экран, установив поставщика услуг продаж по умолчанию в настройках приложения.",
|
||||
"custom_drag": "Пользователь (удерживайте и перетаскивайте)",
|
||||
"switchToEVMCompatibleWallet": "Пожалуйста, переключитесь на кошелек, совместимый с EVM, и повторите попытку (Ethereum, Polygon)."
|
||||
"switchToEVMCompatibleWallet": "Пожалуйста, переключитесь на кошелек, совместимый с EVM, и повторите попытку (Ethereum, Polygon).",
|
||||
"receivable_balance": "Баланс дебиторской задолженности",
|
||||
"confirmed_tx": "Подтвержденный",
|
||||
"transaction_details_source_address": "Адрес источника"
|
||||
}
|
|
@ -761,5 +761,8 @@
|
|||
"default_sell_provider": "ผู้ให้บริการการขายเริ่มต้น",
|
||||
"select_sell_provider_notice": "เลือกผู้ให้บริการการขายด้านบน คุณสามารถข้ามหน้าจอนี้ได้โดยการตั้งค่าผู้ให้บริการการขายเริ่มต้นในการตั้งค่าแอป",
|
||||
"custom_drag": "กำหนดเอง (ค้างและลาก)",
|
||||
"switchToEVMCompatibleWallet": "โปรดเปลี่ยนไปใช้กระเป๋าเงินที่รองรับ EVM แล้วลองอีกครั้ง (Ethereum, Polygon)"
|
||||
"switchToEVMCompatibleWallet": "โปรดเปลี่ยนไปใช้กระเป๋าเงินที่รองรับ EVM แล้วลองอีกครั้ง (Ethereum, Polygon)",
|
||||
"receivable_balance": "ยอดลูกหนี้",
|
||||
"confirmed_tx": "ซึ่งยืนยันแล้ว",
|
||||
"transaction_details_source_address": "ที่อยู่แหล่งกำเนิด"
|
||||
}
|
|
@ -757,5 +757,8 @@
|
|||
"default_sell_provider": "Default na Sell Provider",
|
||||
"select_sell_provider_notice": "Pumili ng provider ng nagbebenta sa itaas. Maaari mong laktawan ang screen na ito sa pamamagitan ng pagtatakda ng iyong default na sell provider sa mga setting ng app.",
|
||||
"custom_drag": "Pasadyang (hawakan at i -drag)",
|
||||
"switchToEVMCompatibleWallet": "Mangyaring lumipat sa isang EVM compatible na wallet at subukang muli (Ethereum, Polygon)"
|
||||
"switchToEVMCompatibleWallet": "Mangyaring lumipat sa isang EVM compatible na wallet at subukang muli (Ethereum, Polygon)",
|
||||
"receivable_balance": "Natatanggap na balanse",
|
||||
"confirmed_tx": "Nakumpirma",
|
||||
"transaction_details_source_address": "SOURCE ADDRESS"
|
||||
}
|
|
@ -761,5 +761,8 @@
|
|||
"default_sell_provider": "Varsayılan Satış Sağlayıcısı",
|
||||
"select_sell_provider_notice": "Yukarıdan bir satış sağlayıcısı seçin. Uygulama ayarlarında varsayılan satış sağlayıcınızı ayarlayarak bu ekranı atlayabilirsiniz.",
|
||||
"custom_drag": "Özel (Bekle ve Sürükle)",
|
||||
"switchToEVMCompatibleWallet": "Lütfen EVM uyumlu bir cüzdana geçin ve tekrar deneyin (Ethereum, Polygon)"
|
||||
"switchToEVMCompatibleWallet": "Lütfen EVM uyumlu bir cüzdana geçin ve tekrar deneyin (Ethereum, Polygon)",
|
||||
"receivable_balance": "Alacak bakiyesi",
|
||||
"confirmed_tx": "Onaylanmış",
|
||||
"transaction_details_source_address": "Kaynak adresi"
|
||||
}
|
|
@ -763,5 +763,8 @@
|
|||
"default_sell_provider": "Постачальник продажу за замовчуванням",
|
||||
"select_sell_provider_notice": "Виберіть вище постачальника послуг продажу. Ви можете пропустити цей екран, встановивши постачальника послуг продажу за умовчанням у налаштуваннях програми.",
|
||||
"custom_drag": "На замовлення (утримуйте та перетягується)",
|
||||
"switchToEVMCompatibleWallet": "Перейдіть на гаманець, сумісний з EVM, і повторіть спробу (Ethereum, Polygon)"
|
||||
"switchToEVMCompatibleWallet": "Перейдіть на гаманець, сумісний з EVM, і повторіть спробу (Ethereum, Polygon)",
|
||||
"receivable_balance": "Баланс дебіторської заборгованості",
|
||||
"confirmed_tx": "Підтверджений",
|
||||
"transaction_details_source_address": "Адреса джерела"
|
||||
}
|
|
@ -755,5 +755,8 @@
|
|||
"default_sell_provider": " ﮦﺪﻨﻨﮐ ﻢﮨﺍﺮﻓ ﻞﯿﺳ ﭧﻟﺎﻔﯾﮈ",
|
||||
"select_sell_provider_notice": "۔ﮟﯿﮨ ﮯﺘﮑﺳ ﮌﻮﮭﭼ ﻮﮐ ﻦﯾﺮﮑﺳﺍ ﺱﺍ ﺮﮐ ﮮﺩ ﺐﯿﺗﺮﺗ ﻮﮐ ﮦﺪﻨﻨﮐ ﻢﮨﺍﺮﻓ ﻞﯿﺳ ﭧﻟﺎﻔﯾﮈ ﮯﻨﭘﺍ ﮟﯿﻣ ﺕﺎﺒ",
|
||||
"custom_drag": "کسٹم (ہولڈ اینڈ ڈریگ)",
|
||||
"switchToEVMCompatibleWallet": "(Ethereum, Polygon) ﮟﯾﺮﮐ ﺶﺷﻮﮐ ﮦﺭﺎﺑﻭﺩ ﺭﻭﺍ ﮟﯾﺮﮐ ﭻﺋﻮﺳ ﺮﭘ ﭧﯿﻟﺍﻭ ﮯﻟﺍﻭ ﮯﻨﮭﮐﺭ ﺖﻘﺑﺎﻄﻣ "
|
||||
"switchToEVMCompatibleWallet": "(Ethereum, Polygon) ﮟﯾﺮﮐ ﺶﺷﻮﮐ ﮦﺭﺎﺑﻭﺩ ﺭﻭﺍ ﮟﯾﺮﮐ ﭻﺋﻮﺳ ﺮﭘ ﭧﯿﻟﺍﻭ ﮯﻟﺍﻭ ﮯﻨﮭﮐﺭ ﺖﻘﺑﺎﻄﻣ ",
|
||||
"receivable_balance": "قابل وصول توازن",
|
||||
"confirmed_tx": "تصدیق",
|
||||
"transaction_details_source_address": "ماخذ ایڈریس"
|
||||
}
|
|
@ -757,5 +757,8 @@
|
|||
"default_sell_provider": "Aiyipada Olupese Tita",
|
||||
"select_sell_provider_notice": "Yan olupese ti o ta loke. O le foju iboju yii nipa tito olupese iṣẹ tita aiyipada rẹ ni awọn eto app.",
|
||||
"custom_drag": "Aṣa (mu ati fa)",
|
||||
"switchToEVMCompatibleWallet": "Jọwọ yipada si apamọwọ ibaramu EVM ki o tun gbiyanju lẹẹkansi (Ethereum, Polygon)"
|
||||
"switchToEVMCompatibleWallet": "Jọwọ yipada si apamọwọ ibaramu EVM ki o tun gbiyanju lẹẹkansi (Ethereum, Polygon)",
|
||||
"receivable_balance": "Iwontunws.funfun ti o gba",
|
||||
"confirmed_tx": "Jẹrisi",
|
||||
"transaction_details_source_address": "Adirẹsi orisun"
|
||||
}
|
|
@ -762,5 +762,8 @@
|
|||
"default_sell_provider": "默认销售提供商",
|
||||
"select_sell_provider_notice": "选择上面的销售提供商。您可以通过在应用程序设置中设置默认销售提供商来跳过此屏幕。",
|
||||
"custom_drag": "定制(保持和拖动)",
|
||||
"switchToEVMCompatibleWallet": "请切换到 EVM 兼容钱包并重试(以太坊、Polygon)"
|
||||
"switchToEVMCompatibleWallet": "请切换到 EVM 兼容钱包并重试(以太坊、Polygon)",
|
||||
"receivable_balance": "应收余额",
|
||||
"confirmed_tx": "确认的",
|
||||
"transaction_details_source_address": "源地址"
|
||||
}
|
|
@ -759,7 +759,7 @@ import 'package:convert/convert.dart';
|
|||
import "package:ed25519_hd_key/ed25519_hd_key.dart";
|
||||
import 'package:libcrypto/libcrypto.dart';
|
||||
import 'package:nanodart/nanodart.dart' as ND;
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:nanoutil/nanoutil.dart';
|
||||
""";
|
||||
const nanoCwPart = "part 'cw_nano.dart';";
|
||||
const nanoContent = """
|
||||
|
@ -795,7 +795,7 @@ abstract class Nano {
|
|||
Map<String, String> getKeys(Object wallet);
|
||||
Object createNanoTransactionCredentials(List<Output> outputs);
|
||||
Future<void> changeRep(Object wallet, String address);
|
||||
Future<void> updateTransactions(Object wallet);
|
||||
Future<bool> updateTransactions(Object wallet);
|
||||
BigInt getTransactionAmountRaw(TransactionInfo transactionInfo);
|
||||
String getRepresentative(Object wallet);
|
||||
}
|
||||
|
@ -810,20 +810,6 @@ abstract class NanoAccountList {
|
|||
}
|
||||
|
||||
abstract class NanoUtil {
|
||||
String seedToPrivate(String seed, int index);
|
||||
String seedToAddress(String seed, int index);
|
||||
String seedToMnemonic(String seed);
|
||||
Future<String> mnemonicToSeed(String mnemonic);
|
||||
String privateKeyToPublic(String privateKey);
|
||||
String addressToPublicKey(String publicAddress);
|
||||
String privateKeyToAddress(String privateKey);
|
||||
String publicKeyToAddress(String publicKey);
|
||||
bool isValidSeed(String seed);
|
||||
Future<String> hdMnemonicListToSeed(List<String> words);
|
||||
Future<String> hdSeedToPrivate(String seed, int index);
|
||||
Future<String> hdSeedToAddress(String seed, int index);
|
||||
Future<String> uniSeedToAddress(String seed, int index, String type);
|
||||
Future<String> uniSeedToPrivate(String seed, int index, String type);
|
||||
bool isValidBip39Seed(String seed);
|
||||
static const int maxDecimalDigits = 6; // Max digits after decimal
|
||||
BigInt rawPerNano = BigInt.parse("1000000000000000000000000000000");
|
||||
|
@ -831,7 +817,6 @@ abstract class NanoUtil {
|
|||
BigInt rawPerBanano = BigInt.parse("100000000000000000000000000000");
|
||||
BigInt rawPerXMR = BigInt.parse("1000000000000");
|
||||
BigInt convertXMRtoNano = BigInt.parse("1000000000000000000");
|
||||
String getRawAsDecimalString(String? raw, BigInt? rawPerCur);
|
||||
String getRawAsUsableString(String? raw, BigInt rawPerCur);
|
||||
String getRawAccuracy(String? raw, BigInt rawPerCur);
|
||||
String getAmountAsRaw(String amount, BigInt rawPerCur);
|
||||
|
|
Loading…
Reference in a new issue