mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-03 09:19:22 +00:00
nano sending + minor sats constants refactor
This commit is contained in:
parent
8f89f19b91
commit
7a95c20645
10 changed files with 274 additions and 151 deletions
|
@ -50,7 +50,7 @@ class MainDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
// contact entries
|
// contact entries
|
||||||
List<ContactEntry> getContactEntries(){
|
List<ContactEntry> getContactEntries() {
|
||||||
return isar.contactEntrys.where().findAllSync();
|
return isar.contactEntrys.where().findAllSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,11 +66,7 @@ class MainDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> isContactEntryExists({required String id}) async {
|
Future<bool> isContactEntryExists({required String id}) async {
|
||||||
return isar.contactEntrys
|
return isar.contactEntrys.where().customIdEqualTo(id).count().then((value) => value > 0);
|
||||||
.where()
|
|
||||||
.customIdEqualTo(id)
|
|
||||||
.count()
|
|
||||||
.then((value) => value > 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ContactEntry? getContactEntry({required String id}) {
|
ContactEntry? getContactEntry({required String id}) {
|
||||||
|
@ -90,14 +86,10 @@ class MainDB {
|
||||||
|
|
||||||
// tx block explorers
|
// tx block explorers
|
||||||
TransactionBlockExplorer? getTransactionBlockExplorer({required Coin coin}) {
|
TransactionBlockExplorer? getTransactionBlockExplorer({required Coin coin}) {
|
||||||
return isar.transactionBlockExplorers
|
return isar.transactionBlockExplorers.where().tickerEqualTo(coin.ticker).findFirstSync();
|
||||||
.where()
|
|
||||||
.tickerEqualTo(coin.ticker)
|
|
||||||
.findFirstSync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<int> putTransactionBlockExplorer(
|
Future<int> putTransactionBlockExplorer(TransactionBlockExplorer explorer) async {
|
||||||
TransactionBlockExplorer explorer) async {
|
|
||||||
try {
|
try {
|
||||||
return await isar.writeTxn(() async {
|
return await isar.writeTxn(() async {
|
||||||
return await isar.transactionBlockExplorers.put(explorer);
|
return await isar.transactionBlockExplorers.put(explorer);
|
||||||
|
@ -108,8 +100,7 @@ class MainDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
// addresses
|
// addresses
|
||||||
QueryBuilder<Address, Address, QAfterWhereClause> getAddresses(
|
QueryBuilder<Address, Address, QAfterWhereClause> getAddresses(String walletId) =>
|
||||||
String walletId) =>
|
|
||||||
isar.addresses.where().walletIdEqualTo(walletId);
|
isar.addresses.where().walletIdEqualTo(walletId);
|
||||||
|
|
||||||
Future<int> putAddress(Address address) async {
|
Future<int> putAddress(Address address) async {
|
||||||
|
@ -137,8 +128,7 @@ class MainDB {
|
||||||
List<int> ids = [];
|
List<int> ids = [];
|
||||||
await isar.writeTxn(() async {
|
await isar.writeTxn(() async {
|
||||||
for (final address in addresses) {
|
for (final address in addresses) {
|
||||||
final storedAddress = await isar.addresses
|
final storedAddress = await isar.addresses.getByValueWalletId(address.value, address.walletId);
|
||||||
.getByValueWalletId(address.value, address.walletId);
|
|
||||||
|
|
||||||
int id;
|
int id;
|
||||||
if (storedAddress == null) {
|
if (storedAddress == null) {
|
||||||
|
@ -178,14 +168,12 @@ class MainDB {
|
||||||
return id;
|
return id;
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw MainDBException(
|
throw MainDBException("failed updateAddress: from=$oldAddress to=$newAddress", e);
|
||||||
"failed updateAddress: from=$oldAddress to=$newAddress", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// transactions
|
// transactions
|
||||||
QueryBuilder<Transaction, Transaction, QAfterWhereClause> getTransactions(
|
QueryBuilder<Transaction, Transaction, QAfterWhereClause> getTransactions(String walletId) =>
|
||||||
String walletId) =>
|
|
||||||
isar.transactions.where().walletIdEqualTo(walletId);
|
isar.transactions.where().walletIdEqualTo(walletId);
|
||||||
|
|
||||||
Future<int> putTransaction(Transaction transaction) async {
|
Future<int> putTransaction(Transaction transaction) async {
|
||||||
|
@ -220,8 +208,7 @@ class MainDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
// utxos
|
// utxos
|
||||||
QueryBuilder<UTXO, UTXO, QAfterWhereClause> getUTXOs(String walletId) =>
|
QueryBuilder<UTXO, UTXO, QAfterWhereClause> getUTXOs(String walletId) => isar.utxos.where().walletIdEqualTo(walletId);
|
||||||
isar.utxos.where().walletIdEqualTo(walletId);
|
|
||||||
|
|
||||||
Future<void> putUTXO(UTXO utxo) => isar.writeTxn(() async {
|
Future<void> putUTXO(UTXO utxo) => isar.writeTxn(() async {
|
||||||
await isar.utxos.put(utxo);
|
await isar.utxos.put(utxo);
|
||||||
|
@ -236,10 +223,8 @@ class MainDB {
|
||||||
final set = utxos.toSet();
|
final set = utxos.toSet();
|
||||||
for (final utxo in utxos) {
|
for (final utxo in utxos) {
|
||||||
// check if utxo exists in db and update accordingly
|
// check if utxo exists in db and update accordingly
|
||||||
final storedUtxo = await isar.utxos
|
final storedUtxo =
|
||||||
.where()
|
await isar.utxos.where().txidWalletIdVoutEqualTo(utxo.txid, utxo.walletId, utxo.vout).findFirst();
|
||||||
.txidWalletIdVoutEqualTo(utxo.txid, utxo.walletId, utxo.vout)
|
|
||||||
.findFirst();
|
|
||||||
|
|
||||||
if (storedUtxo != null) {
|
if (storedUtxo != null) {
|
||||||
// update
|
// update
|
||||||
|
@ -269,22 +254,18 @@ class MainDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
// transaction notes
|
// transaction notes
|
||||||
QueryBuilder<TransactionNote, TransactionNote, QAfterWhereClause>
|
QueryBuilder<TransactionNote, TransactionNote, QAfterWhereClause> getTransactionNotes(String walletId) =>
|
||||||
getTransactionNotes(String walletId) =>
|
isar.transactionNotes.where().walletIdEqualTo(walletId);
|
||||||
isar.transactionNotes.where().walletIdEqualTo(walletId);
|
|
||||||
|
|
||||||
Future<void> putTransactionNote(TransactionNote transactionNote) =>
|
Future<void> putTransactionNote(TransactionNote transactionNote) => isar.writeTxn(() async {
|
||||||
isar.writeTxn(() async {
|
|
||||||
await isar.transactionNotes.put(transactionNote);
|
await isar.transactionNotes.put(transactionNote);
|
||||||
});
|
});
|
||||||
|
|
||||||
Future<void> putTransactionNotes(List<TransactionNote> transactionNotes) =>
|
Future<void> putTransactionNotes(List<TransactionNote> transactionNotes) => isar.writeTxn(() async {
|
||||||
isar.writeTxn(() async {
|
|
||||||
await isar.transactionNotes.putAll(transactionNotes);
|
await isar.transactionNotes.putAll(transactionNotes);
|
||||||
});
|
});
|
||||||
|
|
||||||
Future<TransactionNote?> getTransactionNote(
|
Future<TransactionNote?> getTransactionNote(String walletId, String txid) async {
|
||||||
String walletId, String txid) async {
|
|
||||||
return isar.transactionNotes.getByTxidWalletId(
|
return isar.transactionNotes.getByTxidWalletId(
|
||||||
txid,
|
txid,
|
||||||
walletId,
|
walletId,
|
||||||
|
@ -295,17 +276,14 @@ class MainDB {
|
||||||
required Id id,
|
required Id id,
|
||||||
bool fireImmediately = false,
|
bool fireImmediately = false,
|
||||||
}) {
|
}) {
|
||||||
return isar.transactionNotes
|
return isar.transactionNotes.watchObject(id, fireImmediately: fireImmediately);
|
||||||
.watchObject(id, fireImmediately: fireImmediately);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// address labels
|
// address labels
|
||||||
QueryBuilder<AddressLabel, AddressLabel, QAfterWhereClause> getAddressLabels(
|
QueryBuilder<AddressLabel, AddressLabel, QAfterWhereClause> getAddressLabels(String walletId) =>
|
||||||
String walletId) =>
|
|
||||||
isar.addressLabels.where().walletIdEqualTo(walletId);
|
isar.addressLabels.where().walletIdEqualTo(walletId);
|
||||||
|
|
||||||
Future<int> putAddressLabel(AddressLabel addressLabel) =>
|
Future<int> putAddressLabel(AddressLabel addressLabel) => isar.writeTxn(() async {
|
||||||
isar.writeTxn(() async {
|
|
||||||
return await isar.addressLabels.put(addressLabel);
|
return await isar.addressLabels.put(addressLabel);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -313,13 +291,11 @@ class MainDB {
|
||||||
return isar.addressLabels.putSync(addressLabel);
|
return isar.addressLabels.putSync(addressLabel);
|
||||||
});
|
});
|
||||||
|
|
||||||
Future<void> putAddressLabels(List<AddressLabel> addressLabels) =>
|
Future<void> putAddressLabels(List<AddressLabel> addressLabels) => isar.writeTxn(() async {
|
||||||
isar.writeTxn(() async {
|
|
||||||
await isar.addressLabels.putAll(addressLabels);
|
await isar.addressLabels.putAll(addressLabels);
|
||||||
});
|
});
|
||||||
|
|
||||||
Future<AddressLabel?> getAddressLabel(
|
Future<AddressLabel?> getAddressLabel(String walletId, String addressString) async {
|
||||||
String walletId, String addressString) async {
|
|
||||||
return isar.addressLabels.getByAddressStringWalletId(
|
return isar.addressLabels.getByAddressStringWalletId(
|
||||||
addressString,
|
addressString,
|
||||||
walletId,
|
walletId,
|
||||||
|
@ -361,31 +337,19 @@ class MainDB {
|
||||||
|
|
||||||
// transactions
|
// transactions
|
||||||
for (int i = 0; i < transactionCount; i += paginateLimit) {
|
for (int i = 0; i < transactionCount; i += paginateLimit) {
|
||||||
final txnIds = await getTransactions(walletId)
|
final txnIds = await getTransactions(walletId).offset(i).limit(paginateLimit).idProperty().findAll();
|
||||||
.offset(i)
|
|
||||||
.limit(paginateLimit)
|
|
||||||
.idProperty()
|
|
||||||
.findAll();
|
|
||||||
await isar.transactions.deleteAll(txnIds);
|
await isar.transactions.deleteAll(txnIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
// addresses
|
// addresses
|
||||||
for (int i = 0; i < addressCount; i += paginateLimit) {
|
for (int i = 0; i < addressCount; i += paginateLimit) {
|
||||||
final addressIds = await getAddresses(walletId)
|
final addressIds = await getAddresses(walletId).offset(i).limit(paginateLimit).idProperty().findAll();
|
||||||
.offset(i)
|
|
||||||
.limit(paginateLimit)
|
|
||||||
.idProperty()
|
|
||||||
.findAll();
|
|
||||||
await isar.addresses.deleteAll(addressIds);
|
await isar.addresses.deleteAll(addressIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
// utxos
|
// utxos
|
||||||
for (int i = 0; i < utxoCount; i += paginateLimit) {
|
for (int i = 0; i < utxoCount; i += paginateLimit) {
|
||||||
final utxoIds = await getUTXOs(walletId)
|
final utxoIds = await getUTXOs(walletId).offset(i).limit(paginateLimit).idProperty().findAll();
|
||||||
.offset(i)
|
|
||||||
.limit(paginateLimit)
|
|
||||||
.idProperty()
|
|
||||||
.findAll();
|
|
||||||
await isar.utxos.deleteAll(utxoIds);
|
await isar.utxos.deleteAll(utxoIds);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -396,11 +360,7 @@ class MainDB {
|
||||||
await isar.writeTxn(() async {
|
await isar.writeTxn(() async {
|
||||||
const paginateLimit = 50;
|
const paginateLimit = 50;
|
||||||
for (int i = 0; i < addressLabelCount; i += paginateLimit) {
|
for (int i = 0; i < addressLabelCount; i += paginateLimit) {
|
||||||
final labelIds = await getAddressLabels(walletId)
|
final labelIds = await getAddressLabels(walletId).offset(i).limit(paginateLimit).idProperty().findAll();
|
||||||
.offset(i)
|
|
||||||
.limit(paginateLimit)
|
|
||||||
.idProperty()
|
|
||||||
.findAll();
|
|
||||||
await isar.addressLabels.deleteAll(labelIds);
|
await isar.addressLabels.deleteAll(labelIds);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -411,11 +371,7 @@ class MainDB {
|
||||||
await isar.writeTxn(() async {
|
await isar.writeTxn(() async {
|
||||||
const paginateLimit = 50;
|
const paginateLimit = 50;
|
||||||
for (int i = 0; i < noteCount; i += paginateLimit) {
|
for (int i = 0; i < noteCount; i += paginateLimit) {
|
||||||
final labelIds = await getTransactionNotes(walletId)
|
final labelIds = await getTransactionNotes(walletId).offset(i).limit(paginateLimit).idProperty().findAll();
|
||||||
.offset(i)
|
|
||||||
.limit(paginateLimit)
|
|
||||||
.idProperty()
|
|
||||||
.findAll();
|
|
||||||
await isar.transactionNotes.deleteAll(labelIds);
|
await isar.transactionNotes.deleteAll(labelIds);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -465,8 +421,7 @@ class MainDB {
|
||||||
|
|
||||||
// eth contracts
|
// eth contracts
|
||||||
|
|
||||||
QueryBuilder<EthContract, EthContract, QWhere> getEthContracts() =>
|
QueryBuilder<EthContract, EthContract, QWhere> getEthContracts() => isar.ethContracts.where();
|
||||||
isar.ethContracts.where();
|
|
||||||
|
|
||||||
Future<EthContract?> getEthContract(String contractAddress) =>
|
Future<EthContract?> getEthContract(String contractAddress) =>
|
||||||
isar.ethContracts.where().addressEqualTo(contractAddress).findFirst();
|
isar.ethContracts.where().addressEqualTo(contractAddress).findFirst();
|
||||||
|
@ -478,8 +433,7 @@ class MainDB {
|
||||||
return await isar.ethContracts.put(contract);
|
return await isar.ethContracts.put(contract);
|
||||||
});
|
});
|
||||||
|
|
||||||
Future<void> putEthContracts(List<EthContract> contracts) =>
|
Future<void> putEthContracts(List<EthContract> contracts) => isar.writeTxn(() async {
|
||||||
isar.writeTxn(() async {
|
|
||||||
await isar.ethContracts.putAll(contracts);
|
await isar.ethContracts.putAll(contracts);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,7 +223,7 @@ class Transaction {
|
||||||
txType: json['txType'] as String,
|
txType: json['txType'] as String,
|
||||||
amount: (Decimal.parse(json["amount"].toString()) *
|
amount: (Decimal.parse(json["amount"].toString()) *
|
||||||
Decimal.fromInt(Constants.satsPerCoin(Coin
|
Decimal.fromInt(Constants.satsPerCoin(Coin
|
||||||
.firo))) // dirty hack but we need 8 decimal places here to keep consistent data structure
|
.firo).toInt())) // dirty hack but we need 8 decimal places here to keep consistent data structure
|
||||||
.toBigInt()
|
.toBigInt()
|
||||||
.toInt(),
|
.toInt(),
|
||||||
aliens: [],
|
aliens: [],
|
||||||
|
@ -231,7 +231,7 @@ class Transaction {
|
||||||
worthAtBlockTimestamp: json['worthAtBlockTimestamp'] as String? ?? "0",
|
worthAtBlockTimestamp: json['worthAtBlockTimestamp'] as String? ?? "0",
|
||||||
fees: (Decimal.parse(json["fees"].toString()) *
|
fees: (Decimal.parse(json["fees"].toString()) *
|
||||||
Decimal.fromInt(Constants.satsPerCoin(Coin
|
Decimal.fromInt(Constants.satsPerCoin(Coin
|
||||||
.firo))) // dirty hack but we need 8 decimal places here to keep consistent data structure
|
.firo).toInt())) // dirty hack but we need 8 decimal places here to keep consistent data structure
|
||||||
.toBigInt()
|
.toBigInt()
|
||||||
.toInt(),
|
.toInt(),
|
||||||
inputSize: json['inputSize'] as int? ?? 0,
|
inputSize: json['inputSize'] as int? ?? 0,
|
||||||
|
@ -397,7 +397,7 @@ class Output {
|
||||||
value: (Decimal.parse(
|
value: (Decimal.parse(
|
||||||
(json["value"] ?? 0).toString()) *
|
(json["value"] ?? 0).toString()) *
|
||||||
Decimal.fromInt(Constants.satsPerCoin(Coin
|
Decimal.fromInt(Constants.satsPerCoin(Coin
|
||||||
.firo))) // dirty hack but we need 8 decimal places here to keep consistent data structure
|
.firo).toInt())) // dirty hack but we need 8 decimal places here to keep consistent data structure
|
||||||
.toBigInt()
|
.toBigInt()
|
||||||
.toInt(),
|
.toInt(),
|
||||||
);
|
);
|
||||||
|
@ -410,7 +410,7 @@ class Output {
|
||||||
scriptpubkeyAddress: "",
|
scriptpubkeyAddress: "",
|
||||||
value: (Decimal.parse(0.toString()) *
|
value: (Decimal.parse(0.toString()) *
|
||||||
Decimal.fromInt(Constants.satsPerCoin(Coin
|
Decimal.fromInt(Constants.satsPerCoin(Coin
|
||||||
.firo))) // dirty hack but we need 8 decimal places here to keep consistent data structure
|
.firo).toInt())) // dirty hack but we need 8 decimal places here to keep consistent data structure
|
||||||
.toBigInt()
|
.toBigInt()
|
||||||
.toInt());
|
.toInt());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1412,7 +1412,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
if (coin != Coin.epicCash)
|
if (!([Coin.nano, Coin.epicCash].contains(coin)))
|
||||||
Text(
|
Text(
|
||||||
"Transaction fee (${coin == Coin.ethereum ? "max" : "estimated"})",
|
"Transaction fee (${coin == Coin.ethereum ? "max" : "estimated"})",
|
||||||
style: STextStyles.desktopTextExtraSmall(context).copyWith(
|
style: STextStyles.desktopTextExtraSmall(context).copyWith(
|
||||||
|
@ -1422,11 +1422,11 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
||||||
),
|
),
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
),
|
),
|
||||||
if (coin != Coin.epicCash)
|
if (!([Coin.nano, Coin.epicCash].contains(coin)))
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 10,
|
height: 10,
|
||||||
),
|
),
|
||||||
if (coin != Coin.epicCash)
|
if (!([Coin.nano, Coin.epicCash].contains(coin)))
|
||||||
DesktopFeeDropDown(
|
DesktopFeeDropDown(
|
||||||
walletId: walletId,
|
walletId: walletId,
|
||||||
),
|
),
|
||||||
|
|
|
@ -278,7 +278,7 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
Future<int> get maxFee async {
|
Future<int> get maxFee async {
|
||||||
final fee = (await fees).fast as String;
|
final fee = (await fees).fast as String;
|
||||||
final satsFee =
|
final satsFee =
|
||||||
Decimal.parse(fee) * Decimal.fromInt(Constants.satsPerCoin(coin));
|
Decimal.parse(fee) * Decimal.fromInt(Constants.satsPerCoin(coin).toInt());
|
||||||
return satsFee.floor().toBigInt().toInt();
|
return satsFee.floor().toBigInt().toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2338,7 +2338,7 @@ class FiroWallet extends CoinServiceAPI
|
||||||
Future<int> _fetchMaxFee() async {
|
Future<int> _fetchMaxFee() async {
|
||||||
final balance = availablePrivateBalance();
|
final balance = availablePrivateBalance();
|
||||||
int spendAmount =
|
int spendAmount =
|
||||||
(balance.decimal * Decimal.fromInt(Constants.satsPerCoin(coin)))
|
(balance.decimal * Decimal.fromInt(Constants.satsPerCoin(coin).toInt()))
|
||||||
.toBigInt()
|
.toBigInt()
|
||||||
.toInt();
|
.toInt();
|
||||||
int fee = await estimateJoinSplitFee(spendAmount);
|
int fee = await estimateJoinSplitFee(spendAmount);
|
||||||
|
@ -3549,7 +3549,7 @@ class FiroWallet extends CoinServiceAPI
|
||||||
if (nFees != null) {
|
if (nFees != null) {
|
||||||
nFeesUsed = true;
|
nFeesUsed = true;
|
||||||
fees = (Decimal.parse(nFees.toString()) *
|
fees = (Decimal.parse(nFees.toString()) *
|
||||||
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
Decimal.fromInt(Constants.satsPerCoin(coin).toInt()))
|
||||||
.toBigInt()
|
.toBigInt()
|
||||||
.toInt();
|
.toInt();
|
||||||
}
|
}
|
||||||
|
@ -3573,14 +3573,14 @@ class FiroWallet extends CoinServiceAPI
|
||||||
|
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
outAmount += (Decimal.parse(value.toString()) *
|
outAmount += (Decimal.parse(value.toString()) *
|
||||||
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
Decimal.fromInt(Constants.satsPerCoin(coin).toInt()))
|
||||||
.toBigInt()
|
.toBigInt()
|
||||||
.toInt();
|
.toInt();
|
||||||
|
|
||||||
if (address != null) {
|
if (address != null) {
|
||||||
if (changeAddresses.contains(address)) {
|
if (changeAddresses.contains(address)) {
|
||||||
inputAmtSentFromWallet -= (Decimal.parse(value.toString()) *
|
inputAmtSentFromWallet -= (Decimal.parse(value.toString()) *
|
||||||
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
Decimal.fromInt(Constants.satsPerCoin(coin).toInt()))
|
||||||
.toBigInt()
|
.toBigInt()
|
||||||
.toInt();
|
.toInt();
|
||||||
} else {
|
} else {
|
||||||
|
@ -3597,7 +3597,7 @@ class FiroWallet extends CoinServiceAPI
|
||||||
final nFees = input["nFees"];
|
final nFees = input["nFees"];
|
||||||
if (nFees != null) {
|
if (nFees != null) {
|
||||||
fees += (Decimal.parse(nFees.toString()) *
|
fees += (Decimal.parse(nFees.toString()) *
|
||||||
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
Decimal.fromInt(Constants.satsPerCoin(coin).toInt()))
|
||||||
.toBigInt()
|
.toBigInt()
|
||||||
.toInt();
|
.toInt();
|
||||||
}
|
}
|
||||||
|
@ -3612,7 +3612,7 @@ class FiroWallet extends CoinServiceAPI
|
||||||
|
|
||||||
if (allAddresses.where((e) => e.value == address).isNotEmpty) {
|
if (allAddresses.where((e) => e.value == address).isNotEmpty) {
|
||||||
outputAmtAddressedToWallet += (Decimal.parse(value.toString()) *
|
outputAmtAddressedToWallet += (Decimal.parse(value.toString()) *
|
||||||
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
Decimal.fromInt(Constants.satsPerCoin(coin).toInt()))
|
||||||
.toBigInt()
|
.toBigInt()
|
||||||
.toInt();
|
.toInt();
|
||||||
outAddress = address;
|
outAddress = address;
|
||||||
|
@ -4833,7 +4833,7 @@ class FiroWallet extends CoinServiceAPI
|
||||||
) async {
|
) async {
|
||||||
var lelantusEntry = await _getLelantusEntry();
|
var lelantusEntry = await _getLelantusEntry();
|
||||||
final balance = availablePrivateBalance().decimal;
|
final balance = availablePrivateBalance().decimal;
|
||||||
int spendAmount = (balance * Decimal.fromInt(Constants.satsPerCoin(coin)))
|
int spendAmount = (balance * Decimal.fromInt(Constants.satsPerCoin(coin).toInt()))
|
||||||
.toBigInt()
|
.toBigInt()
|
||||||
.toInt();
|
.toInt();
|
||||||
if (spendAmount == 0 || lelantusEntry.isEmpty) {
|
if (spendAmount == 0 || lelantusEntry.isEmpty) {
|
||||||
|
|
|
@ -223,7 +223,7 @@ class LitecoinWallet extends CoinServiceAPI
|
||||||
Future<int> get maxFee async {
|
Future<int> get maxFee async {
|
||||||
final fee = (await fees).fast as String;
|
final fee = (await fees).fast as String;
|
||||||
final satsFee =
|
final satsFee =
|
||||||
Decimal.parse(fee) * Decimal.fromInt(Constants.satsPerCoin(coin));
|
Decimal.parse(fee) * Decimal.fromInt(Constants.satsPerCoin(coin).toInt());
|
||||||
return satsFee.floor().toBigInt().toInt();
|
return satsFee.floor().toBigInt().toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -215,7 +215,7 @@ class NamecoinWallet extends CoinServiceAPI
|
||||||
Future<int> get maxFee async {
|
Future<int> get maxFee async {
|
||||||
final fee = (await fees).fast as String;
|
final fee = (await fees).fast as String;
|
||||||
final satsFee =
|
final satsFee =
|
||||||
Decimal.parse(fee) * Decimal.fromInt(Constants.satsPerCoin(coin));
|
Decimal.parse(fee) * Decimal.fromInt(Constants.satsPerCoin(coin).toInt());
|
||||||
return satsFee.floor().toBigInt().toInt();
|
return satsFee.floor().toBigInt().toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@ import 'package:stackwallet/services/mixins/wallet_cache.dart';
|
||||||
import 'package:stackwallet/services/mixins/wallet_db.dart';
|
import 'package:stackwallet/services/mixins/wallet_db.dart';
|
||||||
import 'package:stackwallet/utilities/amount/amount.dart';
|
import 'package:stackwallet/utilities/amount/amount.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
|
import 'package:stackwallet/utilities/enums/log_level_enum.dart';
|
||||||
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
|
|
||||||
import '../../../db/isar/main_db.dart';
|
import '../../../db/isar/main_db.dart';
|
||||||
import '../../../models/isar/models/blockchain_data/address.dart';
|
import '../../../models/isar/models/blockchain_data/address.dart';
|
||||||
|
@ -52,12 +54,11 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB, CoinControlI
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<String?> get mnemonicPassphrase => _secureStore.read(
|
Future<String?> get mnemonicPassphrase => _secureStore.read(
|
||||||
key: '${_walletId}_mnemonicPassphrase',
|
key: '${_walletId}_mnemonicPassphrase',
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<String?> get mnemonicString =>
|
Future<String?> get mnemonicString => _secureStore.read(key: '${_walletId}_mnemonic');
|
||||||
_secureStore.read(key: '${_walletId}_mnemonic');
|
|
||||||
|
|
||||||
Future<String> getSeedFromMnemonic() async {
|
Future<String> getSeedFromMnemonic() async {
|
||||||
var mnemonic = await mnemonicString;
|
var mnemonic = await mnemonicString;
|
||||||
|
@ -73,7 +74,8 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB, CoinControlI
|
||||||
Future<String> getAddressFromMnemonic() async {
|
Future<String> getAddressFromMnemonic() async {
|
||||||
var mnemonic = await mnemonicString;
|
var mnemonic = await mnemonicString;
|
||||||
var seed = NanoMnemomics.mnemonicListToSeed(mnemonic!.split(' '));
|
var seed = NanoMnemomics.mnemonicListToSeed(mnemonic!.split(' '));
|
||||||
var address = NanoAccounts.createAccount(NanoAccountType.NANO, NanoKeys.createPublicKey(NanoKeys.seedToPrivate(seed, 0)));
|
var address =
|
||||||
|
NanoAccounts.createAccount(NanoAccountType.NANO, NanoKeys.createPublicKey(NanoKeys.seedToPrivate(seed, 0)));
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,10 +130,143 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB, CoinControlI
|
||||||
Balance get balance => _balance ??= getCachedBalance();
|
Balance get balance => _balance ??= getCachedBalance();
|
||||||
Balance? _balance;
|
Balance? _balance;
|
||||||
|
|
||||||
|
Future<String?> requestWork(String url, String hash) async {
|
||||||
|
return http
|
||||||
|
.post(
|
||||||
|
Uri.parse(url),
|
||||||
|
headers: {'Content-type': 'application/json'},
|
||||||
|
body: json.encode(
|
||||||
|
{
|
||||||
|
"action": "work_generate",
|
||||||
|
"hash": hash,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.then((http.Response response) {
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final Map<String, dynamic> decoded = json.decode(response.body) as Map<String, dynamic>;
|
||||||
|
if (decoded.containsKey("error")) {
|
||||||
|
throw Exception("Received error ${decoded["error"]}");
|
||||||
|
}
|
||||||
|
return decoded["work"] as String?;
|
||||||
|
} else {
|
||||||
|
throw Exception("Received error ${response.statusCode}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<String> confirmSend({required Map<String, dynamic> txData}) {
|
Future<String> confirmSend({required Map<String, dynamic> txData}) async {
|
||||||
// TODO: implement confirmSend
|
|
||||||
throw UnimplementedError();
|
try {
|
||||||
|
// first get the account balance:
|
||||||
|
final balanceBody = jsonEncode({
|
||||||
|
"action": "account_balance",
|
||||||
|
"account": await getAddressFromMnemonic(),
|
||||||
|
});
|
||||||
|
final headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
};
|
||||||
|
final balanceResponse = await http.post(
|
||||||
|
Uri.parse(getCurrentNode().host),
|
||||||
|
headers: headers,
|
||||||
|
body: balanceBody,
|
||||||
|
);
|
||||||
|
|
||||||
|
final balanceData = jsonDecode(balanceResponse.body);
|
||||||
|
final BigInt currentBalance = BigInt.parse(balanceData["balance"].toString());
|
||||||
|
final BigInt txAmount = txData["recipientAmt"].raw as BigInt;
|
||||||
|
final BigInt balanceAfterTx = currentBalance - txAmount;
|
||||||
|
|
||||||
|
// get the account info (we need the frontier and representative):
|
||||||
|
final infoBody = jsonEncode({
|
||||||
|
"action": "account_info",
|
||||||
|
"representative": "true",
|
||||||
|
"account": await getAddressFromMnemonic(),
|
||||||
|
});
|
||||||
|
final infoResponse = await http.post(
|
||||||
|
Uri.parse(getCurrentNode().host),
|
||||||
|
headers: headers,
|
||||||
|
body: infoBody,
|
||||||
|
);
|
||||||
|
|
||||||
|
final String frontier = jsonDecode(infoResponse.body)["frontier"].toString();
|
||||||
|
final String representative = jsonDecode(infoResponse.body)["representative"].toString();
|
||||||
|
// our address:
|
||||||
|
final String publicAddress = await getAddressFromMnemonic();
|
||||||
|
// link = destination address:
|
||||||
|
final String link = NanoAccounts.extractPublicKey(txData["address"].toString());
|
||||||
|
final String linkAsAccount = txData["address"].toString();
|
||||||
|
|
||||||
|
// construct the send block:
|
||||||
|
final Map<String, String> sendBlock = {
|
||||||
|
"type": "state",
|
||||||
|
"account": publicAddress,
|
||||||
|
"previous": frontier,
|
||||||
|
"representative": representative,
|
||||||
|
"balance": balanceAfterTx.toString(),
|
||||||
|
"link": link,
|
||||||
|
};
|
||||||
|
|
||||||
|
// sign the send block:
|
||||||
|
final String hash = NanoBlocks.computeStateHash(
|
||||||
|
NanoAccountType.NANO,
|
||||||
|
sendBlock["account"]!,
|
||||||
|
sendBlock["previous"]!,
|
||||||
|
sendBlock["representative"]!,
|
||||||
|
BigInt.parse(sendBlock["balance"]!),
|
||||||
|
sendBlock["link"]!,
|
||||||
|
);
|
||||||
|
final String privateKey = await getPrivateKeyFromMnemonic();
|
||||||
|
final String signature = NanoSignatures.signBlock(hash, privateKey);
|
||||||
|
|
||||||
|
// get PoW for the send block:
|
||||||
|
final String? work = await requestWork("https://rpc.nano.to", frontier);
|
||||||
|
if (work == null) {
|
||||||
|
throw Exception("Failed to get PoW for send block");
|
||||||
|
}
|
||||||
|
|
||||||
|
// process the send block:
|
||||||
|
final Map<String, String> finalSendBlock = {
|
||||||
|
"type": "state",
|
||||||
|
"account": publicAddress,
|
||||||
|
"previous": frontier,
|
||||||
|
"representative": representative,
|
||||||
|
"balance": balanceAfterTx.toString(),
|
||||||
|
"link": link,
|
||||||
|
"link_as_account": linkAsAccount,
|
||||||
|
"signature": signature,
|
||||||
|
"work": work,
|
||||||
|
};
|
||||||
|
|
||||||
|
final processBody = jsonEncode({
|
||||||
|
"action": "process",
|
||||||
|
"json_block": "true",
|
||||||
|
"subtype": "send",
|
||||||
|
"block": finalSendBlock,
|
||||||
|
});
|
||||||
|
final processResponse = await http.post(
|
||||||
|
Uri.parse(getCurrentNode().host),
|
||||||
|
headers: headers,
|
||||||
|
body: processBody,
|
||||||
|
);
|
||||||
|
|
||||||
|
final Map<String, dynamic> decoded = json.decode(processResponse.body) as Map<String, dynamic>;
|
||||||
|
if (decoded.containsKey("error")) {
|
||||||
|
throw Exception("Received error ${decoded["error"]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
print(jsonDecode(processBody));
|
||||||
|
print(jsonDecode(processResponse.body));
|
||||||
|
|
||||||
|
throw Exception("Received error ${decoded["error"]}");
|
||||||
|
|
||||||
|
// return the hash of the transaction:
|
||||||
|
return decoded["hash"].toString();
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log("Error sending transaction $e - $s", level: LogLevel.Error);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -139,8 +274,8 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB, CoinControlI
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Amount> estimateFeeFor(Amount amount, int feeRate) {
|
Future<Amount> estimateFeeFor(Amount amount, int feeRate) {
|
||||||
// TODO: implement estimateFeeFor
|
// fees are always 0 :)
|
||||||
throw UnimplementedError();
|
return Future.value(Amount(rawValue: BigInt.from(0), fractionDigits: 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -163,10 +298,15 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB, CoinControlI
|
||||||
final response = await http.post(Uri.parse(getCurrentNode().host), headers: headers, body: body);
|
final response = await http.post(Uri.parse(getCurrentNode().host), headers: headers, body: body);
|
||||||
final data = jsonDecode(response.body);
|
final data = jsonDecode(response.body);
|
||||||
_balance = Balance(
|
_balance = Balance(
|
||||||
total: Amount(rawValue: (BigInt.parse(data["balance"].toString()) + BigInt.parse(data["receivable"].toString())) ~/ BigInt.from(10).pow(23), fractionDigits: 7),
|
total: Amount(
|
||||||
spendable: Amount(rawValue: BigInt.parse(data["balance"].toString()) ~/ BigInt.from(10).pow(23), fractionDigits: 7),
|
rawValue: (BigInt.parse(data["balance"].toString()) /*+ BigInt.parse(data["receivable"].toString())*/) ~/
|
||||||
|
BigInt.from(10).pow(23),
|
||||||
|
fractionDigits: 7),
|
||||||
|
spendable:
|
||||||
|
Amount(rawValue: BigInt.parse(data["balance"].toString()) ~/ BigInt.from(10).pow(23), fractionDigits: 7),
|
||||||
blockedTotal: Amount(rawValue: BigInt.parse("0"), fractionDigits: 30),
|
blockedTotal: Amount(rawValue: BigInt.parse("0"), fractionDigits: 30),
|
||||||
pendingSpendable: Amount(rawValue: BigInt.parse(data["receivable"].toString()) ~/ BigInt.from(10).pow(23), fractionDigits: 7),
|
pendingSpendable:
|
||||||
|
Amount(rawValue: BigInt.parse(data["receivable"].toString()) ~/ BigInt.from(10).pow(23), fractionDigits: 7),
|
||||||
);
|
);
|
||||||
await updateCachedBalance(_balance!);
|
await updateCachedBalance(_balance!);
|
||||||
}
|
}
|
||||||
|
@ -177,7 +317,13 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB, CoinControlI
|
||||||
|
|
||||||
Future<void> updateTransactions() async {
|
Future<void> updateTransactions() async {
|
||||||
await confirmAllReceivable();
|
await confirmAllReceivable();
|
||||||
final response = await http.post(Uri.parse(getCurrentNode().host), headers: {"Content-Type": "application/json"}, body: jsonEncode({"action": "account_history", "account": await getAddressFromMnemonic(), "count": "-1"}));
|
final response = await http.post(Uri.parse(getCurrentNode().host),
|
||||||
|
headers: {"Content-Type": "application/json"},
|
||||||
|
body: jsonEncode({
|
||||||
|
"action": "account_history",
|
||||||
|
"account": await getAddressFromMnemonic(),
|
||||||
|
"count": "-1",
|
||||||
|
}));
|
||||||
final data = await jsonDecode(response.body);
|
final data = await jsonDecode(response.body);
|
||||||
final transactions = data["history"] as List<dynamic>;
|
final transactions = data["history"] as List<dynamic>;
|
||||||
if (transactions.isEmpty) {
|
if (transactions.isEmpty) {
|
||||||
|
@ -205,7 +351,7 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB, CoinControlI
|
||||||
subType: TransactionSubType.none,
|
subType: TransactionSubType.none,
|
||||||
amount: intAmount,
|
amount: intAmount,
|
||||||
amountString: strAmount,
|
amountString: strAmount,
|
||||||
fee: 0, // TODO: Use real fee?
|
fee: 0,
|
||||||
height: int.parse(tx["height"].toString()),
|
height: int.parse(tx["height"].toString()),
|
||||||
isCancelled: false,
|
isCancelled: false,
|
||||||
isLelantus: false,
|
isLelantus: false,
|
||||||
|
@ -213,8 +359,7 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB, CoinControlI
|
||||||
otherData: "",
|
otherData: "",
|
||||||
inputs: [],
|
inputs: [],
|
||||||
outputs: [],
|
outputs: [],
|
||||||
nonce: 0
|
nonce: 0);
|
||||||
);
|
|
||||||
transactionList.add(transaction);
|
transactionList.add(transaction);
|
||||||
}
|
}
|
||||||
await db.putTransactions(transactionList);
|
await db.putTransactions(transactionList);
|
||||||
|
@ -247,8 +392,7 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB, CoinControlI
|
||||||
@override
|
@override
|
||||||
Future<void> initializeNew() async {
|
Future<void> initializeNew() async {
|
||||||
if ((await mnemonicString) != null || (await mnemonicPassphrase) != null) {
|
if ((await mnemonicString) != null || (await mnemonicPassphrase) != null) {
|
||||||
throw Exception(
|
throw Exception("Attempted to overwrite mnemonic on generate new wallet!");
|
||||||
"Attempted to overwrite mnemonic on generate new wallet!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await _prefs.init();
|
await _prefs.init();
|
||||||
|
@ -256,8 +400,8 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB, CoinControlI
|
||||||
String seed = NanoSeeds.generateSeed();
|
String seed = NanoSeeds.generateSeed();
|
||||||
final mnemonic = NanoMnemomics.seedToMnemonic(seed);
|
final mnemonic = NanoMnemomics.seedToMnemonic(seed);
|
||||||
await _secureStore.write(
|
await _secureStore.write(
|
||||||
key: '${_walletId}_mnemonic',
|
key: '${_walletId}_mnemonic',
|
||||||
value: mnemonic.join(' '),
|
value: mnemonic.join(' '),
|
||||||
);
|
);
|
||||||
await _secureStore.write(
|
await _secureStore.write(
|
||||||
key: '${_walletId}_mnemonicPassphrase',
|
key: '${_walletId}_mnemonicPassphrase',
|
||||||
|
@ -279,10 +423,7 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB, CoinControlI
|
||||||
|
|
||||||
await db.putAddress(address);
|
await db.putAddress(address);
|
||||||
|
|
||||||
await Future.wait([
|
await Future.wait([updateCachedId(walletId), updateCachedIsFavorite(false)]);
|
||||||
updateCachedId(walletId),
|
|
||||||
updateCachedIsFavorite(false)
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -296,8 +437,7 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB, CoinControlI
|
||||||
bool refreshMutex = false;
|
bool refreshMutex = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
// TODO: implement maxFee
|
Future<int> get maxFee => Future.value(0);
|
||||||
Future<int> get maxFee => throw UnimplementedError();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<String>> get mnemonic => _getMnemonicList();
|
Future<List<String>> get mnemonic => _getMnemonicList();
|
||||||
|
@ -312,26 +452,54 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB, CoinControlI
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Map<String, dynamic>> prepareSend({required String address, required Amount amount, Map<String, dynamic>? args}) {
|
Future<Map<String, dynamic>> prepareSend({
|
||||||
// TODO: implement prepareSend
|
required String address,
|
||||||
throw UnimplementedError();
|
required Amount amount,
|
||||||
|
Map<String, dynamic>? args,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
int satAmount = amount.raw.toInt();
|
||||||
|
int realfee = 0;
|
||||||
|
|
||||||
|
if (balance.spendable == amount) {
|
||||||
|
satAmount = balance.spendable.raw.toInt() - realfee;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> txData = {
|
||||||
|
"fee": realfee,
|
||||||
|
"addresss": address,
|
||||||
|
"recipientAmt": Amount(
|
||||||
|
rawValue: BigInt.from(satAmount),
|
||||||
|
fractionDigits: coin.decimals,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
Logging.instance.log("prepare send: $txData", level: LogLevel.Info);
|
||||||
|
return txData;
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log("Error getting fees $e - $s", level: LogLevel.Error);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> recoverFromMnemonic({required String mnemonic, String? mnemonicPassphrase, required int maxUnusedAddressGap, required int maxNumberOfIndexesToCheck, required int height}) async {
|
Future<void> recoverFromMnemonic(
|
||||||
|
{required String mnemonic,
|
||||||
|
String? mnemonicPassphrase,
|
||||||
|
required int maxUnusedAddressGap,
|
||||||
|
required int maxNumberOfIndexesToCheck,
|
||||||
|
required int height}) async {
|
||||||
try {
|
try {
|
||||||
if ((await mnemonicString) != null ||
|
if ((await mnemonicString) != null || (await this.mnemonicPassphrase) != null) {
|
||||||
(await this.mnemonicPassphrase) != null) {
|
|
||||||
throw Exception("Attempted to overwrite mnemonic on restore!");
|
throw Exception("Attempted to overwrite mnemonic on restore!");
|
||||||
}
|
}
|
||||||
|
|
||||||
await _secureStore.write(
|
await _secureStore.write(key: '${_walletId}_mnemonic', value: mnemonic.trim());
|
||||||
key: '${_walletId}_mnemonic', value: mnemonic.trim());
|
|
||||||
await _secureStore.write(
|
await _secureStore.write(
|
||||||
key: '${_walletId}_mnemonicPassphrase',
|
key: '${_walletId}_mnemonicPassphrase',
|
||||||
value: mnemonicPassphrase ?? "",
|
value: mnemonicPassphrase ?? "",
|
||||||
);
|
);
|
||||||
|
|
||||||
String seed = NanoMnemomics.mnemonicListToSeed(mnemonic.split(" "));
|
String seed = NanoMnemomics.mnemonicListToSeed(mnemonic.split(" "));
|
||||||
String privateKey = NanoKeys.seedToPrivate(seed, 0);
|
String privateKey = NanoKeys.seedToPrivate(seed, 0);
|
||||||
String publicKey = NanoKeys.createPublicKey(privateKey);
|
String publicKey = NanoKeys.createPublicKey(privateKey);
|
||||||
|
@ -349,10 +517,7 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB, CoinControlI
|
||||||
|
|
||||||
await db.putAddress(address);
|
await db.putAddress(address);
|
||||||
|
|
||||||
await Future.wait([
|
await Future.wait([updateCachedId(walletId), updateCachedIsFavorite(false)]);
|
||||||
updateCachedId(walletId),
|
|
||||||
updateCachedIsFavorite(false)
|
|
||||||
]);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
|
@ -370,11 +535,10 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB, CoinControlI
|
||||||
|
|
||||||
NodeModel getCurrentNode() {
|
NodeModel getCurrentNode() {
|
||||||
return _xnoNode ??
|
return _xnoNode ??
|
||||||
NodeService(secureStorageInterface: _secureStore)
|
NodeService(secureStorageInterface: _secureStore).getPrimaryNodeFor(coin: coin) ??
|
||||||
.getPrimaryNodeFor(coin: coin) ??
|
|
||||||
DefaultNodes.getNodeFor(coin);
|
DefaultNodes.getNodeFor(coin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> testNetworkConnection() {
|
Future<bool> testNetworkConnection() {
|
||||||
http.get(Uri.parse("${getCurrentNode().host}?action=version")).then((response) {
|
http.get(Uri.parse("${getCurrentNode().host}?action=version")).then((response) {
|
||||||
|
@ -390,8 +554,7 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB, CoinControlI
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> updateNode(bool shouldRefresh) async {
|
Future<void> updateNode(bool shouldRefresh) async {
|
||||||
_xnoNode = NodeService(secureStorageInterface: _secureStore)
|
_xnoNode = NodeService(secureStorageInterface: _secureStore).getPrimaryNodeFor(coin: coin) ??
|
||||||
.getPrimaryNodeFor(coin: coin) ??
|
|
||||||
DefaultNodes.getNodeFor(coin);
|
DefaultNodes.getNodeFor(coin);
|
||||||
|
|
||||||
if (shouldRefresh) {
|
if (shouldRefresh) {
|
||||||
|
@ -413,4 +576,4 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB, CoinControlI
|
||||||
bool validateAddress(String address) {
|
bool validateAddress(String address) {
|
||||||
return NanoAccounts.isValid(NanoAccountType.NANO, address);
|
return NanoAccounts.isValid(NanoAccountType.NANO, address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,7 +210,7 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
Future<int> get maxFee async {
|
Future<int> get maxFee async {
|
||||||
final fee = (await fees).fast as String;
|
final fee = (await fees).fast as String;
|
||||||
final satsFee =
|
final satsFee =
|
||||||
Decimal.parse(fee) * Decimal.fromInt(Constants.satsPerCoin(coin));
|
Decimal.parse(fee) * Decimal.fromInt(Constants.satsPerCoin(coin).toInt());
|
||||||
return satsFee.floor().toBigInt().toInt();
|
return satsFee.floor().toBigInt().toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2191,7 +2191,7 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
if (prevOut == out["n"]) {
|
if (prevOut == out["n"]) {
|
||||||
inputAmtSentFromWallet +=
|
inputAmtSentFromWallet +=
|
||||||
(Decimal.parse(out["value"]!.toString()) *
|
(Decimal.parse(out["value"]!.toString()) *
|
||||||
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
Decimal.fromInt(Constants.satsPerCoin(coin).toInt()))
|
||||||
.toBigInt()
|
.toBigInt()
|
||||||
.toInt();
|
.toInt();
|
||||||
}
|
}
|
||||||
|
@ -2210,7 +2210,7 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
output["scriptPubKey"]!["addresses"][0] as String;
|
output["scriptPubKey"]!["addresses"][0] as String;
|
||||||
final value = output["value"]!;
|
final value = output["value"]!;
|
||||||
final _value = (Decimal.parse(value.toString()) *
|
final _value = (Decimal.parse(value.toString()) *
|
||||||
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
Decimal.fromInt(Constants.satsPerCoin(coin).toInt()))
|
||||||
.toBigInt()
|
.toBigInt()
|
||||||
.toInt();
|
.toInt();
|
||||||
totalOutput += _value;
|
totalOutput += _value;
|
||||||
|
@ -2245,7 +2245,7 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
final ctFee = output["ct_fee"]!;
|
final ctFee = output["ct_fee"]!;
|
||||||
final feeValue = (Decimal.parse(ctFee.toString()) *
|
final feeValue = (Decimal.parse(ctFee.toString()) *
|
||||||
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
Decimal.fromInt(Constants.satsPerCoin(coin).toInt()))
|
||||||
.toBigInt()
|
.toBigInt()
|
||||||
.toInt();
|
.toInt();
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
|
@ -2280,7 +2280,7 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
output["scriptPubKey"]?["addresses"]?[0] as String?;
|
output["scriptPubKey"]?["addresses"]?[0] as String?;
|
||||||
if (address != null) {
|
if (address != null) {
|
||||||
final value = (Decimal.parse((output["value"] ?? 0).toString()) *
|
final value = (Decimal.parse((output["value"] ?? 0).toString()) *
|
||||||
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
Decimal.fromInt(Constants.satsPerCoin(coin).toInt()))
|
||||||
.toBigInt()
|
.toBigInt()
|
||||||
.toInt();
|
.toInt();
|
||||||
totalOut += value;
|
totalOut += value;
|
||||||
|
@ -2306,7 +2306,7 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
for (final out in tx["vout"] as List) {
|
for (final out in tx["vout"] as List) {
|
||||||
if (prevOut == out["n"]) {
|
if (prevOut == out["n"]) {
|
||||||
totalIn += (Decimal.parse((out["value"] ?? 0).toString()) *
|
totalIn += (Decimal.parse((out["value"] ?? 0).toString()) *
|
||||||
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
Decimal.fromInt(Constants.satsPerCoin(coin).toInt()))
|
||||||
.toBigInt()
|
.toBigInt()
|
||||||
.toInt();
|
.toInt();
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,11 +25,13 @@ abstract class Constants {
|
||||||
// static bool enableBuy = enableExchange;
|
// static bool enableBuy = enableExchange;
|
||||||
// // true; // true for development,
|
// // true; // true for development,
|
||||||
|
|
||||||
static const int _satsPerCoinEthereum = 1000000000000000000;
|
static final BigInt _satsPerCoinEthereum = BigInt.from(1000000000000000000);
|
||||||
static const int _satsPerCoinMonero = 1000000000000;
|
static final BigInt _satsPerCoinMonero = BigInt.from(1000000000000);
|
||||||
static const int _satsPerCoinWownero = 100000000000;
|
static final BigInt _satsPerCoinWownero = BigInt.from(100000000000);
|
||||||
static const int _satsPerCoin = 100000000;
|
static final BigInt _satsPerCoinNano = BigInt.parse("1000000000000000000000000000000");
|
||||||
|
static final BigInt _satsPerCoin = BigInt.from(100000000);
|
||||||
static const int _decimalPlaces = 8;
|
static const int _decimalPlaces = 8;
|
||||||
|
static const int _decimalPlacesNano = 6;
|
||||||
static const int _decimalPlacesWownero = 11;
|
static const int _decimalPlacesWownero = 11;
|
||||||
static const int _decimalPlacesMonero = 12;
|
static const int _decimalPlacesMonero = 12;
|
||||||
static const int _decimalPlacesEthereum = 18;
|
static const int _decimalPlacesEthereum = 18;
|
||||||
|
@ -46,7 +48,7 @@ abstract class Constants {
|
||||||
|
|
||||||
static const int rescanV1 = 1;
|
static const int rescanV1 = 1;
|
||||||
|
|
||||||
static int satsPerCoin(Coin coin) {
|
static BigInt satsPerCoin(Coin coin) {
|
||||||
switch (coin) {
|
switch (coin) {
|
||||||
case Coin.bitcoin:
|
case Coin.bitcoin:
|
||||||
case Coin.litecoin:
|
case Coin.litecoin:
|
||||||
|
@ -61,9 +63,11 @@ abstract class Constants {
|
||||||
case Coin.epicCash:
|
case Coin.epicCash:
|
||||||
case Coin.namecoin:
|
case Coin.namecoin:
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
case Coin.nano: // TODO: Check this: https://nano.org/en/faq#what-are-the-units-of-nano
|
|
||||||
return _satsPerCoin;
|
return _satsPerCoin;
|
||||||
|
|
||||||
|
case Coin.nano:
|
||||||
|
return _satsPerCoinNano;
|
||||||
|
|
||||||
case Coin.wownero:
|
case Coin.wownero:
|
||||||
return _satsPerCoinWownero;
|
return _satsPerCoinWownero;
|
||||||
|
|
||||||
|
@ -90,9 +94,11 @@ abstract class Constants {
|
||||||
case Coin.epicCash:
|
case Coin.epicCash:
|
||||||
case Coin.namecoin:
|
case Coin.namecoin:
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
case Coin.nano:
|
|
||||||
return _decimalPlaces;
|
return _decimalPlaces;
|
||||||
|
|
||||||
|
case Coin.nano:
|
||||||
|
return _decimalPlacesNano;
|
||||||
|
|
||||||
case Coin.wownero:
|
case Coin.wownero:
|
||||||
return _decimalPlacesWownero;
|
return _decimalPlacesWownero;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue