mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-06-28 20:39:51 +00:00
CW-415 add coin control for xmr (#985)
* Added CoinsInfo to monero_api_cpp * Add struct on dart * Add struct on dart * Set coins value * CW-415 Use add-coin-to-monero branch * CW-415 Add get Coin and build Monero Deps using Docker * CW-415 Fix Typo * CW-415 add debug log info * CW-415 Add preferred key Images for coin control to Monero * CW-415 Fix generation * CW-415 Skip GA Cache Externals * CW-415 Skip GA Cache Externals * CW-415 Coin Control: remove Block Explorer for Monero, Add Tx hash, save note on field exit * CW-415 Coin Control: Throw Exception when all outputs are deselected * CW-415 Coin Control: Show Frozen Balance on Dashboard * CW-415 Coin Control: Show Frozen Balance on Dashboard * CW-415 Ignore cached Monero deps in Workflow * CW-415 Fix displaying frozen Balance * Use own Translator with http 1.1.0 * CW-415 Resolve requested Changes * CW-415 Resolve requested Changes * CW-415 Resolve requested Changes * CW-415 Apply requested Changes * CW-415 Apply requested Changes * CW-415 Ensure opening of UnspentCoinsInfo Box, even for Monero.com --------- Co-authored-by: Konstantin Ullrich <konstantinullrich12@gmail.com>
This commit is contained in:
parent
3577730de8
commit
f6670c0236
56 changed files with 1584 additions and 545 deletions
2
.github/workflows/pr_test_build.yml
vendored
2
.github/workflows/pr_test_build.yml
vendored
|
@ -55,7 +55,7 @@ jobs:
|
||||||
/opt/android/cake_wallet/cw_monero/android/.cxx
|
/opt/android/cake_wallet/cw_monero/android/.cxx
|
||||||
/opt/android/cake_wallet/cw_monero/ios/External
|
/opt/android/cake_wallet/cw_monero/ios/External
|
||||||
/opt/android/cake_wallet/cw_shared_external/ios/External
|
/opt/android/cake_wallet/cw_shared_external/ios/External
|
||||||
key: ${{ hashFiles('**/build_monero.sh', '**/build_haven.sh') }}
|
key: ${{ hashFiles('**/build_monero.sh', '**/build_haven.sh', '**/monero_api.cpp') }}
|
||||||
|
|
||||||
- if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }}
|
- if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }}
|
||||||
name: Generate Externals
|
name: Generate Externals
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
class BitcoinTransactionNoInputsException implements Exception {
|
class BitcoinTransactionNoInputsException implements Exception {
|
||||||
@override
|
@override
|
||||||
String toString() => 'Not enough inputs available';
|
String toString() => 'Not enough inputs available. Please select more under Coin Control';
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,24 +2,31 @@ import 'package:cw_core/balance.dart';
|
||||||
import 'package:cw_core/monero_amount_format.dart';
|
import 'package:cw_core/monero_amount_format.dart';
|
||||||
|
|
||||||
class MoneroBalance extends Balance {
|
class MoneroBalance extends Balance {
|
||||||
MoneroBalance({required this.fullBalance, required this.unlockedBalance})
|
MoneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0})
|
||||||
: formattedFullBalance = moneroAmountToString(amount: fullBalance),
|
: formattedFullBalance = moneroAmountToString(amount: fullBalance),
|
||||||
formattedUnlockedBalance =
|
formattedUnlockedBalance = moneroAmountToString(amount: unlockedBalance),
|
||||||
moneroAmountToString(amount: unlockedBalance),
|
frozenFormatted = moneroAmountToString(amount: frozenBalance),
|
||||||
super(unlockedBalance, fullBalance);
|
super(unlockedBalance, fullBalance);
|
||||||
|
|
||||||
MoneroBalance.fromString(
|
MoneroBalance.fromString(
|
||||||
{required this.formattedFullBalance,
|
{required this.formattedFullBalance,
|
||||||
required this.formattedUnlockedBalance})
|
required this.formattedUnlockedBalance,
|
||||||
|
this.frozenFormatted = '0.0'})
|
||||||
: fullBalance = moneroParseAmount(amount: formattedFullBalance),
|
: fullBalance = moneroParseAmount(amount: formattedFullBalance),
|
||||||
unlockedBalance = moneroParseAmount(amount: formattedUnlockedBalance),
|
unlockedBalance = moneroParseAmount(amount: formattedUnlockedBalance),
|
||||||
|
frozenBalance = moneroParseAmount(amount: frozenFormatted),
|
||||||
super(moneroParseAmount(amount: formattedUnlockedBalance),
|
super(moneroParseAmount(amount: formattedUnlockedBalance),
|
||||||
moneroParseAmount(amount: formattedFullBalance));
|
moneroParseAmount(amount: formattedFullBalance));
|
||||||
|
|
||||||
final int fullBalance;
|
final int fullBalance;
|
||||||
final int unlockedBalance;
|
final int unlockedBalance;
|
||||||
|
final int frozenBalance;
|
||||||
final String formattedFullBalance;
|
final String formattedFullBalance;
|
||||||
final String formattedUnlockedBalance;
|
final String formattedUnlockedBalance;
|
||||||
|
final String frozenFormatted;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get formattedFrozenBalance => frozenFormatted == '0.0' ? '' : frozenFormatted;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get formattedAvailableBalance => formattedUnlockedBalance;
|
String get formattedAvailableBalance => formattedUnlockedBalance;
|
||||||
|
|
|
@ -13,7 +13,9 @@ class UnspentCoinsInfo extends HiveObject {
|
||||||
required this.noteRaw,
|
required this.noteRaw,
|
||||||
required this.address,
|
required this.address,
|
||||||
required this.vout,
|
required this.vout,
|
||||||
required this.value});
|
required this.value,
|
||||||
|
this.keyImage = null
|
||||||
|
});
|
||||||
|
|
||||||
static const typeId = UNSPENT_COINS_INFO_TYPE_ID;
|
static const typeId = UNSPENT_COINS_INFO_TYPE_ID;
|
||||||
static const boxName = 'Unspent';
|
static const boxName = 'Unspent';
|
||||||
|
@ -43,6 +45,9 @@ class UnspentCoinsInfo extends HiveObject {
|
||||||
@HiveField(7, defaultValue: 0)
|
@HiveField(7, defaultValue: 0)
|
||||||
int vout;
|
int vout;
|
||||||
|
|
||||||
|
@HiveField(8, defaultValue: null)
|
||||||
|
String? keyImage;
|
||||||
|
|
||||||
String get note => noteRaw ?? '';
|
String get note => noteRaw ?? '';
|
||||||
|
|
||||||
set note(String value) => noteRaw = value;
|
set note(String value) => noteRaw = value;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <list>
|
||||||
#include "thread"
|
#include "thread"
|
||||||
#include "CwWalletListener.h"
|
#include "CwWalletListener.h"
|
||||||
#if __APPLE__
|
#if __APPLE__
|
||||||
|
@ -182,6 +183,62 @@ extern "C"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CoinsInfoRow
|
||||||
|
{
|
||||||
|
uint64_t blockHeight;
|
||||||
|
char *hash;
|
||||||
|
uint64_t internalOutputIndex;
|
||||||
|
uint64_t globalOutputIndex;
|
||||||
|
bool spent;
|
||||||
|
bool frozen;
|
||||||
|
uint64_t spentHeight;
|
||||||
|
uint64_t amount;
|
||||||
|
bool rct;
|
||||||
|
bool keyImageKnown;
|
||||||
|
uint64_t pkIndex;
|
||||||
|
uint32_t subaddrIndex;
|
||||||
|
uint32_t subaddrAccount;
|
||||||
|
char *address;
|
||||||
|
char *addressLabel;
|
||||||
|
char *keyImage;
|
||||||
|
uint64_t unlockTime;
|
||||||
|
bool unlocked;
|
||||||
|
char *pubKey;
|
||||||
|
bool coinbase;
|
||||||
|
char *description;
|
||||||
|
|
||||||
|
CoinsInfoRow(Monero::CoinsInfo *coinsInfo)
|
||||||
|
{
|
||||||
|
blockHeight = coinsInfo->blockHeight();
|
||||||
|
std::string *hash_str = new std::string(coinsInfo->hash());
|
||||||
|
hash = strdup(hash_str->c_str());
|
||||||
|
internalOutputIndex = coinsInfo->internalOutputIndex();
|
||||||
|
globalOutputIndex = coinsInfo->globalOutputIndex();
|
||||||
|
spent = coinsInfo->spent();
|
||||||
|
frozen = coinsInfo->frozen();
|
||||||
|
spentHeight = coinsInfo->spentHeight();
|
||||||
|
amount = coinsInfo->amount();
|
||||||
|
rct = coinsInfo->rct();
|
||||||
|
keyImageKnown = coinsInfo->keyImageKnown();
|
||||||
|
pkIndex = coinsInfo->pkIndex();
|
||||||
|
subaddrIndex = coinsInfo->subaddrIndex();
|
||||||
|
subaddrAccount = coinsInfo->subaddrAccount();
|
||||||
|
address = strdup(coinsInfo->address().c_str()) ;
|
||||||
|
addressLabel = strdup(coinsInfo->addressLabel().c_str());
|
||||||
|
keyImage = strdup(coinsInfo->keyImage().c_str());
|
||||||
|
unlockTime = coinsInfo->unlockTime();
|
||||||
|
unlocked = coinsInfo->unlocked();
|
||||||
|
pubKey = strdup(coinsInfo->pubKey().c_str());
|
||||||
|
coinbase = coinsInfo->coinbase();
|
||||||
|
description = strdup(coinsInfo->description().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void setUnlocked(bool unlocked);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Monero::Coins *m_coins;
|
||||||
|
|
||||||
Monero::Wallet *m_wallet;
|
Monero::Wallet *m_wallet;
|
||||||
Monero::TransactionHistory *m_transaction_history;
|
Monero::TransactionHistory *m_transaction_history;
|
||||||
MoneroWalletListener *m_listener;
|
MoneroWalletListener *m_listener;
|
||||||
|
@ -189,6 +246,7 @@ extern "C"
|
||||||
Monero::SubaddressAccount *m_account;
|
Monero::SubaddressAccount *m_account;
|
||||||
uint64_t m_last_known_wallet_height;
|
uint64_t m_last_known_wallet_height;
|
||||||
uint64_t m_cached_syncing_blockchain_height = 0;
|
uint64_t m_cached_syncing_blockchain_height = 0;
|
||||||
|
std::list<Monero::CoinsInfo*> m_coins_info;
|
||||||
std::mutex store_lock;
|
std::mutex store_lock;
|
||||||
bool is_storing = false;
|
bool is_storing = false;
|
||||||
|
|
||||||
|
@ -224,6 +282,17 @@ extern "C"
|
||||||
{
|
{
|
||||||
m_subaddress = nullptr;
|
m_subaddress = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_coins_info = std::list<Monero::CoinsInfo*>();
|
||||||
|
|
||||||
|
if (wallet != nullptr)
|
||||||
|
{
|
||||||
|
m_coins = wallet->coins();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_coins = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Monero::Wallet *get_current_wallet()
|
Monero::Wallet *get_current_wallet()
|
||||||
|
@ -487,9 +556,18 @@ extern "C"
|
||||||
}
|
}
|
||||||
|
|
||||||
bool transaction_create(char *address, char *payment_id, char *amount,
|
bool transaction_create(char *address, char *payment_id, char *amount,
|
||||||
uint8_t priority_raw, uint32_t subaddr_account, Utf8Box &error, PendingTransactionRaw &pendingTransaction)
|
uint8_t priority_raw, uint32_t subaddr_account,
|
||||||
|
char **preferred_inputs, uint32_t preferred_inputs_size,
|
||||||
|
Utf8Box &error, PendingTransactionRaw &pendingTransaction)
|
||||||
{
|
{
|
||||||
nice(19);
|
nice(19);
|
||||||
|
|
||||||
|
std::set<std::string> _preferred_inputs;
|
||||||
|
|
||||||
|
for (int i = 0; i < preferred_inputs_size; i++) {
|
||||||
|
_preferred_inputs.insert(std::string(*preferred_inputs));
|
||||||
|
preferred_inputs++;
|
||||||
|
}
|
||||||
|
|
||||||
auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
|
auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
|
||||||
std::string _payment_id;
|
std::string _payment_id;
|
||||||
|
@ -503,11 +581,11 @@ extern "C"
|
||||||
if (amount != nullptr)
|
if (amount != nullptr)
|
||||||
{
|
{
|
||||||
uint64_t _amount = Monero::Wallet::amountFromString(std::string(amount));
|
uint64_t _amount = Monero::Wallet::amountFromString(std::string(amount));
|
||||||
transaction = m_wallet->createTransaction(std::string(address), _payment_id, _amount, m_wallet->defaultMixin(), priority, subaddr_account);
|
transaction = m_wallet->createTransaction(std::string(address), _payment_id, _amount, m_wallet->defaultMixin(), priority, subaddr_account, {}, _preferred_inputs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
transaction = m_wallet->createTransaction(std::string(address), _payment_id, Monero::optional<uint64_t>(), m_wallet->defaultMixin(), priority, subaddr_account);
|
transaction = m_wallet->createTransaction(std::string(address), _payment_id, Monero::optional<uint64_t>(), m_wallet->defaultMixin(), priority, subaddr_account, {}, _preferred_inputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
int status = transaction->status();
|
int status = transaction->status();
|
||||||
|
@ -527,7 +605,9 @@ extern "C"
|
||||||
}
|
}
|
||||||
|
|
||||||
bool transaction_create_mult_dest(char **addresses, char *payment_id, char **amounts, uint32_t size,
|
bool transaction_create_mult_dest(char **addresses, char *payment_id, char **amounts, uint32_t size,
|
||||||
uint8_t priority_raw, uint32_t subaddr_account, Utf8Box &error, PendingTransactionRaw &pendingTransaction)
|
uint8_t priority_raw, uint32_t subaddr_account,
|
||||||
|
char **preferred_inputs, uint32_t preferred_inputs_size,
|
||||||
|
Utf8Box &error, PendingTransactionRaw &pendingTransaction)
|
||||||
{
|
{
|
||||||
nice(19);
|
nice(19);
|
||||||
|
|
||||||
|
@ -541,6 +621,13 @@ extern "C"
|
||||||
amounts++;
|
amounts++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::set<std::string> _preferred_inputs;
|
||||||
|
|
||||||
|
for (int i = 0; i < preferred_inputs_size; i++) {
|
||||||
|
_preferred_inputs.insert(std::string(*preferred_inputs));
|
||||||
|
preferred_inputs++;
|
||||||
|
}
|
||||||
|
|
||||||
auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
|
auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
|
||||||
std::string _payment_id;
|
std::string _payment_id;
|
||||||
Monero::PendingTransaction *transaction;
|
Monero::PendingTransaction *transaction;
|
||||||
|
@ -800,6 +887,91 @@ extern "C"
|
||||||
return m_wallet->trustedDaemon();
|
return m_wallet->trustedDaemon();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CoinsInfoRow* coin(int index)
|
||||||
|
{
|
||||||
|
if (index >= 0 && index < m_coins_info.size()) {
|
||||||
|
std::list<Monero::CoinsInfo*>::iterator it = m_coins_info.begin();
|
||||||
|
std::advance(it, index);
|
||||||
|
Monero::CoinsInfo* element = *it;
|
||||||
|
std::cout << "Element at index " << index << ": " << element << std::endl;
|
||||||
|
return new CoinsInfoRow(element);
|
||||||
|
} else {
|
||||||
|
std::cout << "Invalid index." << std::endl;
|
||||||
|
return nullptr; // Return a default value (nullptr) for invalid index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh_coins(uint32_t accountIndex)
|
||||||
|
{
|
||||||
|
m_coins_info.clear();
|
||||||
|
|
||||||
|
m_coins->refresh();
|
||||||
|
for (const auto i : m_coins->getAll()) {
|
||||||
|
if (i->subaddrAccount() == accountIndex && !(i->spent())) {
|
||||||
|
m_coins_info.push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t coins_count()
|
||||||
|
{
|
||||||
|
return m_coins_info.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
CoinsInfoRow** coins_from_account(uint32_t accountIndex)
|
||||||
|
{
|
||||||
|
std::vector<CoinsInfoRow*> matchingCoins;
|
||||||
|
|
||||||
|
for (int i = 0; i < coins_count(); i++) {
|
||||||
|
CoinsInfoRow* coinInfo = coin(i);
|
||||||
|
if (coinInfo->subaddrAccount == accountIndex) {
|
||||||
|
matchingCoins.push_back(coinInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CoinsInfoRow** result = new CoinsInfoRow*[matchingCoins.size()];
|
||||||
|
std::copy(matchingCoins.begin(), matchingCoins.end(), result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
CoinsInfoRow** coins_from_txid(const char* txid, size_t* count)
|
||||||
|
{
|
||||||
|
std::vector<CoinsInfoRow*> matchingCoins;
|
||||||
|
|
||||||
|
for (int i = 0; i < coins_count(); i++) {
|
||||||
|
CoinsInfoRow* coinInfo = coin(i);
|
||||||
|
if (std::string(coinInfo->hash) == txid) {
|
||||||
|
matchingCoins.push_back(coinInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*count = matchingCoins.size();
|
||||||
|
CoinsInfoRow** result = new CoinsInfoRow*[*count];
|
||||||
|
std::copy(matchingCoins.begin(), matchingCoins.end(), result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
CoinsInfoRow** coins_from_key_image(const char** keyimages, size_t keyimageCount, size_t* count)
|
||||||
|
{
|
||||||
|
std::vector<CoinsInfoRow*> matchingCoins;
|
||||||
|
|
||||||
|
for (int i = 0; i < coins_count(); i++) {
|
||||||
|
CoinsInfoRow* coinsInfoRow = coin(i);
|
||||||
|
for (size_t j = 0; j < keyimageCount; j++) {
|
||||||
|
if (coinsInfoRow->keyImageKnown && std::string(coinsInfoRow->keyImage) == keyimages[j]) {
|
||||||
|
matchingCoins.push_back(coinsInfoRow);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*count = matchingCoins.size();
|
||||||
|
CoinsInfoRow** result = new CoinsInfoRow*[*count];
|
||||||
|
std::copy(matchingCoins.begin(), matchingCoins.end(), result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
23
cw_monero/lib/api/coins_info.dart
Normal file
23
cw_monero/lib/api/coins_info.dart
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:cw_monero/api/signatures.dart';
|
||||||
|
import 'package:cw_monero/api/structs/coins_info_row.dart';
|
||||||
|
import 'package:cw_monero/api/types.dart';
|
||||||
|
import 'package:cw_monero/api/monero_api.dart';
|
||||||
|
|
||||||
|
final refreshCoinsNative = moneroApi
|
||||||
|
.lookup<NativeFunction<refresh_coins>>('refresh_coins')
|
||||||
|
.asFunction<RefreshCoins>();
|
||||||
|
|
||||||
|
final coinsCountNative = moneroApi
|
||||||
|
.lookup<NativeFunction<coins_count>>('coins_count')
|
||||||
|
.asFunction<CoinsCount>();
|
||||||
|
|
||||||
|
final coinNative = moneroApi
|
||||||
|
.lookup<NativeFunction<coin>>('coin')
|
||||||
|
.asFunction<GetCoin>();
|
||||||
|
|
||||||
|
void refreshCoins(int accountIndex) => refreshCoinsNative(accountIndex);
|
||||||
|
|
||||||
|
int countOfCoins() => coinsCountNative();
|
||||||
|
|
||||||
|
CoinsInfoRow getCoin(int index) => coinNative(index).ref;
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:ffi';
|
import 'dart:ffi';
|
||||||
|
import 'package:cw_monero/api/structs/coins_info_row.dart';
|
||||||
import 'package:cw_monero/api/structs/pending_transaction.dart';
|
import 'package:cw_monero/api/structs/pending_transaction.dart';
|
||||||
import 'package:cw_monero/api/structs/ut8_box.dart';
|
import 'package:cw_monero/api/structs/ut8_box.dart';
|
||||||
import 'package:ffi/ffi.dart';
|
import 'package:ffi/ffi.dart';
|
||||||
|
@ -9,8 +10,8 @@ typedef create_wallet = Int8 Function(
|
||||||
typedef restore_wallet_from_seed = Int8 Function(
|
typedef restore_wallet_from_seed = Int8 Function(
|
||||||
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
|
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
|
||||||
|
|
||||||
typedef restore_wallet_from_keys = Int8 Function(Pointer<Utf8>, Pointer<Utf8>,
|
typedef restore_wallet_from_keys = Int8 Function(Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>,
|
||||||
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
|
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
|
||||||
|
|
||||||
typedef is_wallet_exist = Int8 Function(Pointer<Utf8>);
|
typedef is_wallet_exist = Int8 Function(Pointer<Utf8>);
|
||||||
|
|
||||||
|
@ -63,8 +64,7 @@ typedef subaddrress_refresh = Void Function(Int32);
|
||||||
|
|
||||||
typedef subaddress_get_all = Pointer<Int64> Function();
|
typedef subaddress_get_all = Pointer<Int64> Function();
|
||||||
|
|
||||||
typedef subaddress_add_new = Void Function(
|
typedef subaddress_add_new = Void Function(Int32 accountIndex, Pointer<Utf8> label);
|
||||||
Int32 accountIndex, Pointer<Utf8> label);
|
|
||||||
|
|
||||||
typedef subaddress_set_label = Void Function(
|
typedef subaddress_set_label = Void Function(
|
||||||
Int32 accountIndex, Int32 addressIndex, Pointer<Utf8> label);
|
Int32 accountIndex, Int32 addressIndex, Pointer<Utf8> label);
|
||||||
|
@ -77,8 +77,7 @@ typedef account_get_all = Pointer<Int64> Function();
|
||||||
|
|
||||||
typedef account_add_new = Void Function(Pointer<Utf8> label);
|
typedef account_add_new = Void Function(Pointer<Utf8> label);
|
||||||
|
|
||||||
typedef account_set_label = Void Function(
|
typedef account_set_label = Void Function(Int32 accountIndex, Pointer<Utf8> label);
|
||||||
Int32 accountIndex, Pointer<Utf8> label);
|
|
||||||
|
|
||||||
typedef transactions_refresh = Void Function();
|
typedef transactions_refresh = Void Function();
|
||||||
|
|
||||||
|
@ -94,6 +93,8 @@ typedef transaction_create = Int8 Function(
|
||||||
Pointer<Utf8> amount,
|
Pointer<Utf8> amount,
|
||||||
Int8 priorityRaw,
|
Int8 priorityRaw,
|
||||||
Int32 subaddrAccount,
|
Int32 subaddrAccount,
|
||||||
|
Pointer<Pointer<Utf8>> preferredInputs,
|
||||||
|
Int32 preferredInputsSize,
|
||||||
Pointer<Utf8Box> error,
|
Pointer<Utf8Box> error,
|
||||||
Pointer<PendingTransactionRaw> pendingTransaction);
|
Pointer<PendingTransactionRaw> pendingTransaction);
|
||||||
|
|
||||||
|
@ -104,6 +105,8 @@ typedef transaction_create_mult_dest = Int8 Function(
|
||||||
Int32 size,
|
Int32 size,
|
||||||
Int8 priorityRaw,
|
Int8 priorityRaw,
|
||||||
Int32 subaddrAccount,
|
Int32 subaddrAccount,
|
||||||
|
Pointer<Pointer<Utf8>> preferredInputs,
|
||||||
|
Int32 preferredInputsSize,
|
||||||
Pointer<Utf8Box> error,
|
Pointer<Utf8Box> error,
|
||||||
Pointer<PendingTransactionRaw> pendingTransaction);
|
Pointer<PendingTransactionRaw> pendingTransaction);
|
||||||
|
|
||||||
|
@ -123,10 +126,16 @@ typedef on_startup = Void Function();
|
||||||
|
|
||||||
typedef rescan_blockchain = Void Function();
|
typedef rescan_blockchain = Void Function();
|
||||||
|
|
||||||
typedef get_subaddress_label = Pointer<Utf8> Function(
|
typedef get_subaddress_label = Pointer<Utf8> Function(Int32 accountIndex, Int32 addressIndex);
|
||||||
Int32 accountIndex,
|
|
||||||
Int32 addressIndex);
|
|
||||||
|
|
||||||
typedef set_trusted_daemon = Void Function(Int8 trusted);
|
typedef set_trusted_daemon = Void Function(Int8 trusted);
|
||||||
|
|
||||||
typedef trusted_daemon = Int8 Function();
|
typedef trusted_daemon = Int8 Function();
|
||||||
|
|
||||||
|
typedef refresh_coins = Void Function(Int32 accountIndex);
|
||||||
|
|
||||||
|
typedef coins_count = Int64 Function();
|
||||||
|
|
||||||
|
// typedef coins_from_txid = Pointer<CoinsInfoRow> Function(Pointer<Utf8> txid);
|
||||||
|
|
||||||
|
typedef coin = Pointer<CoinsInfoRow> Function(Int32 index);
|
||||||
|
|
73
cw_monero/lib/api/structs/coins_info_row.dart
Normal file
73
cw_monero/lib/api/structs/coins_info_row.dart
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
|
||||||
|
class CoinsInfoRow extends Struct {
|
||||||
|
@Int64()
|
||||||
|
external int blockHeight;
|
||||||
|
|
||||||
|
external Pointer<Utf8> hash;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int internalOutputIndex;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int globalOutputIndex;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int spent;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int frozen;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int spentHeight;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int amount;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int rct;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int keyImageKnown;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int pkIndex;
|
||||||
|
|
||||||
|
@Uint32()
|
||||||
|
external int subaddrIndex;
|
||||||
|
|
||||||
|
@Uint32()
|
||||||
|
external int subaddrAccount;
|
||||||
|
|
||||||
|
external Pointer<Utf8> address;
|
||||||
|
|
||||||
|
external Pointer<Utf8> addressLabel;
|
||||||
|
|
||||||
|
external Pointer<Utf8> keyImage;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int unlockTime;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int unlocked;
|
||||||
|
|
||||||
|
external Pointer<Utf8> pubKey;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int coinbase;
|
||||||
|
|
||||||
|
external Pointer<Utf8> description;
|
||||||
|
|
||||||
|
String getHash() => hash.toDartString();
|
||||||
|
|
||||||
|
String getAddress() => address.toDartString();
|
||||||
|
|
||||||
|
String getAddressLabel() => addressLabel.toDartString();
|
||||||
|
|
||||||
|
String getKeyImage() => keyImage.toDartString();
|
||||||
|
|
||||||
|
String getPubKey() => pubKey.toDartString();
|
||||||
|
|
||||||
|
String getDescription() => description.toDartString();
|
||||||
|
}
|
|
@ -35,9 +35,8 @@ final transactionCommitNative = moneroApi
|
||||||
.lookup<NativeFunction<transaction_commit>>('transaction_commit')
|
.lookup<NativeFunction<transaction_commit>>('transaction_commit')
|
||||||
.asFunction<TransactionCommit>();
|
.asFunction<TransactionCommit>();
|
||||||
|
|
||||||
final getTxKeyNative = moneroApi
|
final getTxKeyNative =
|
||||||
.lookup<NativeFunction<get_tx_key>>('get_tx_key')
|
moneroApi.lookup<NativeFunction<get_tx_key>>('get_tx_key').asFunction<GetTxKey>();
|
||||||
.asFunction<GetTxKey>();
|
|
||||||
|
|
||||||
String getTxKey(String txId) {
|
String getTxKey(String txId) {
|
||||||
final txIdPointer = txId.toNativeUtf8();
|
final txIdPointer = txId.toNativeUtf8();
|
||||||
|
@ -71,10 +70,21 @@ PendingTransactionDescription createTransactionSync(
|
||||||
required String paymentId,
|
required String paymentId,
|
||||||
required int priorityRaw,
|
required int priorityRaw,
|
||||||
String? amount,
|
String? amount,
|
||||||
int accountIndex = 0}) {
|
int accountIndex = 0,
|
||||||
|
List<String> preferredInputs = const []}) {
|
||||||
final addressPointer = address.toNativeUtf8();
|
final addressPointer = address.toNativeUtf8();
|
||||||
final paymentIdPointer = paymentId.toNativeUtf8();
|
final paymentIdPointer = paymentId.toNativeUtf8();
|
||||||
final amountPointer = amount != null ? amount.toNativeUtf8() : nullptr;
|
final amountPointer = amount != null ? amount.toNativeUtf8() : nullptr;
|
||||||
|
|
||||||
|
final int preferredInputsSize = preferredInputs.length;
|
||||||
|
final List<Pointer<Utf8>> preferredInputsPointers =
|
||||||
|
preferredInputs.map((output) => output.toNativeUtf8()).toList();
|
||||||
|
final Pointer<Pointer<Utf8>> preferredInputsPointerPointer = calloc(preferredInputsSize);
|
||||||
|
|
||||||
|
for (int i = 0; i < preferredInputsSize; i++) {
|
||||||
|
preferredInputsPointerPointer[i] = preferredInputsPointers[i];
|
||||||
|
}
|
||||||
|
|
||||||
final errorMessagePointer = calloc<Utf8Box>();
|
final errorMessagePointer = calloc<Utf8Box>();
|
||||||
final pendingTransactionRawPointer = calloc<PendingTransactionRaw>();
|
final pendingTransactionRawPointer = calloc<PendingTransactionRaw>();
|
||||||
final created = transactionCreateNative(
|
final created = transactionCreateNative(
|
||||||
|
@ -83,10 +93,16 @@ PendingTransactionDescription createTransactionSync(
|
||||||
amountPointer,
|
amountPointer,
|
||||||
priorityRaw,
|
priorityRaw,
|
||||||
accountIndex,
|
accountIndex,
|
||||||
|
preferredInputsPointerPointer,
|
||||||
|
preferredInputsSize,
|
||||||
errorMessagePointer,
|
errorMessagePointer,
|
||||||
pendingTransactionRawPointer) !=
|
pendingTransactionRawPointer) !=
|
||||||
0;
|
0;
|
||||||
|
|
||||||
|
calloc.free(preferredInputsPointerPointer);
|
||||||
|
|
||||||
|
preferredInputsPointers.forEach((element) => calloc.free(element));
|
||||||
|
|
||||||
calloc.free(addressPointer);
|
calloc.free(addressPointer);
|
||||||
calloc.free(paymentIdPointer);
|
calloc.free(paymentIdPointer);
|
||||||
|
|
||||||
|
@ -111,15 +127,16 @@ PendingTransactionDescription createTransactionSync(
|
||||||
|
|
||||||
PendingTransactionDescription createTransactionMultDestSync(
|
PendingTransactionDescription createTransactionMultDestSync(
|
||||||
{required List<MoneroOutput> outputs,
|
{required List<MoneroOutput> outputs,
|
||||||
required String paymentId,
|
required String paymentId,
|
||||||
required int priorityRaw,
|
required int priorityRaw,
|
||||||
int accountIndex = 0}) {
|
int accountIndex = 0,
|
||||||
|
List<String> preferredInputs = const []}) {
|
||||||
final int size = outputs.length;
|
final int size = outputs.length;
|
||||||
final List<Pointer<Utf8>> addressesPointers = outputs.map((output) =>
|
final List<Pointer<Utf8>> addressesPointers =
|
||||||
output.address.toNativeUtf8()).toList();
|
outputs.map((output) => output.address.toNativeUtf8()).toList();
|
||||||
final Pointer<Pointer<Utf8>> addressesPointerPointer = calloc(size);
|
final Pointer<Pointer<Utf8>> addressesPointerPointer = calloc(size);
|
||||||
final List<Pointer<Utf8>> amountsPointers = outputs.map((output) =>
|
final List<Pointer<Utf8>> amountsPointers =
|
||||||
output.amount.toNativeUtf8()).toList();
|
outputs.map((output) => output.amount.toNativeUtf8()).toList();
|
||||||
final Pointer<Pointer<Utf8>> amountsPointerPointer = calloc(size);
|
final Pointer<Pointer<Utf8>> amountsPointerPointer = calloc(size);
|
||||||
|
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
|
@ -127,25 +144,38 @@ PendingTransactionDescription createTransactionMultDestSync(
|
||||||
amountsPointerPointer[i] = amountsPointers[i];
|
amountsPointerPointer[i] = amountsPointers[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final int preferredInputsSize = preferredInputs.length;
|
||||||
|
final List<Pointer<Utf8>> preferredInputsPointers =
|
||||||
|
preferredInputs.map((output) => output.toNativeUtf8()).toList();
|
||||||
|
final Pointer<Pointer<Utf8>> preferredInputsPointerPointer = calloc(preferredInputsSize);
|
||||||
|
|
||||||
|
for (int i = 0; i < preferredInputsSize; i++) {
|
||||||
|
preferredInputsPointerPointer[i] = preferredInputsPointers[i];
|
||||||
|
}
|
||||||
|
|
||||||
final paymentIdPointer = paymentId.toNativeUtf8();
|
final paymentIdPointer = paymentId.toNativeUtf8();
|
||||||
final errorMessagePointer = calloc<Utf8Box>();
|
final errorMessagePointer = calloc<Utf8Box>();
|
||||||
final pendingTransactionRawPointer = calloc<PendingTransactionRaw>();
|
final pendingTransactionRawPointer = calloc<PendingTransactionRaw>();
|
||||||
final created = transactionCreateMultDestNative(
|
final created = transactionCreateMultDestNative(
|
||||||
addressesPointerPointer,
|
addressesPointerPointer,
|
||||||
paymentIdPointer,
|
paymentIdPointer,
|
||||||
amountsPointerPointer,
|
amountsPointerPointer,
|
||||||
size,
|
size,
|
||||||
priorityRaw,
|
priorityRaw,
|
||||||
accountIndex,
|
accountIndex,
|
||||||
errorMessagePointer,
|
preferredInputsPointerPointer,
|
||||||
pendingTransactionRawPointer) !=
|
preferredInputsSize,
|
||||||
|
errorMessagePointer,
|
||||||
|
pendingTransactionRawPointer) !=
|
||||||
0;
|
0;
|
||||||
|
|
||||||
calloc.free(addressesPointerPointer);
|
calloc.free(addressesPointerPointer);
|
||||||
calloc.free(amountsPointerPointer);
|
calloc.free(amountsPointerPointer);
|
||||||
|
calloc.free(preferredInputsPointerPointer);
|
||||||
|
|
||||||
addressesPointers.forEach((element) => calloc.free(element));
|
addressesPointers.forEach((element) => calloc.free(element));
|
||||||
amountsPointers.forEach((element) => calloc.free(element));
|
amountsPointers.forEach((element) => calloc.free(element));
|
||||||
|
preferredInputsPointers.forEach((element) => calloc.free(element));
|
||||||
|
|
||||||
calloc.free(paymentIdPointer);
|
calloc.free(paymentIdPointer);
|
||||||
|
|
||||||
|
@ -164,13 +194,12 @@ PendingTransactionDescription createTransactionMultDestSync(
|
||||||
pointerAddress: pendingTransactionRawPointer.address);
|
pointerAddress: pendingTransactionRawPointer.address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void commitTransactionFromPointerAddress({required int address}) => commitTransaction(
|
void commitTransactionFromPointerAddress({required int address}) =>
|
||||||
transactionPointer: Pointer<PendingTransactionRaw>.fromAddress(address));
|
commitTransaction(transactionPointer: Pointer<PendingTransactionRaw>.fromAddress(address));
|
||||||
|
|
||||||
void commitTransaction({required Pointer<PendingTransactionRaw> transactionPointer}) {
|
void commitTransaction({required Pointer<PendingTransactionRaw> transactionPointer}) {
|
||||||
final errorMessagePointer = calloc<Utf8Box>();
|
final errorMessagePointer = calloc<Utf8Box>();
|
||||||
final isCommited =
|
final isCommited = transactionCommitNative(transactionPointer, errorMessagePointer) != 0;
|
||||||
transactionCommitNative(transactionPointer, errorMessagePointer) != 0;
|
|
||||||
|
|
||||||
if (!isCommited) {
|
if (!isCommited) {
|
||||||
final message = errorMessagePointer.ref.getValue();
|
final message = errorMessagePointer.ref.getValue();
|
||||||
|
@ -185,13 +214,15 @@ PendingTransactionDescription _createTransactionSync(Map args) {
|
||||||
final amount = args['amount'] as String?;
|
final amount = args['amount'] as String?;
|
||||||
final priorityRaw = args['priorityRaw'] as int;
|
final priorityRaw = args['priorityRaw'] as int;
|
||||||
final accountIndex = args['accountIndex'] as int;
|
final accountIndex = args['accountIndex'] as int;
|
||||||
|
final preferredInputs = args['preferredInputs'] as List<String>;
|
||||||
|
|
||||||
return createTransactionSync(
|
return createTransactionSync(
|
||||||
address: address,
|
address: address,
|
||||||
paymentId: paymentId,
|
paymentId: paymentId,
|
||||||
amount: amount,
|
amount: amount,
|
||||||
priorityRaw: priorityRaw,
|
priorityRaw: priorityRaw,
|
||||||
accountIndex: accountIndex);
|
accountIndex: accountIndex,
|
||||||
|
preferredInputs: preferredInputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
PendingTransactionDescription _createTransactionMultDestSync(Map args) {
|
PendingTransactionDescription _createTransactionMultDestSync(Map args) {
|
||||||
|
@ -199,12 +230,14 @@ PendingTransactionDescription _createTransactionMultDestSync(Map args) {
|
||||||
final paymentId = args['paymentId'] as String;
|
final paymentId = args['paymentId'] as String;
|
||||||
final priorityRaw = args['priorityRaw'] as int;
|
final priorityRaw = args['priorityRaw'] as int;
|
||||||
final accountIndex = args['accountIndex'] as int;
|
final accountIndex = args['accountIndex'] as int;
|
||||||
|
final preferredInputs = args['preferredInputs'] as List<String>;
|
||||||
|
|
||||||
return createTransactionMultDestSync(
|
return createTransactionMultDestSync(
|
||||||
outputs: outputs,
|
outputs: outputs,
|
||||||
paymentId: paymentId,
|
paymentId: paymentId,
|
||||||
priorityRaw: priorityRaw,
|
priorityRaw: priorityRaw,
|
||||||
accountIndex: accountIndex);
|
accountIndex: accountIndex,
|
||||||
|
preferredInputs: preferredInputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<PendingTransactionDescription> createTransaction(
|
Future<PendingTransactionDescription> createTransaction(
|
||||||
|
@ -212,23 +245,27 @@ Future<PendingTransactionDescription> createTransaction(
|
||||||
required int priorityRaw,
|
required int priorityRaw,
|
||||||
String? amount,
|
String? amount,
|
||||||
String paymentId = '',
|
String paymentId = '',
|
||||||
int accountIndex = 0}) =>
|
int accountIndex = 0,
|
||||||
|
List<String> preferredInputs = const []}) =>
|
||||||
compute(_createTransactionSync, {
|
compute(_createTransactionSync, {
|
||||||
'address': address,
|
'address': address,
|
||||||
'paymentId': paymentId,
|
'paymentId': paymentId,
|
||||||
'amount': amount,
|
'amount': amount,
|
||||||
'priorityRaw': priorityRaw,
|
'priorityRaw': priorityRaw,
|
||||||
'accountIndex': accountIndex
|
'accountIndex': accountIndex,
|
||||||
|
'preferredInputs': preferredInputs
|
||||||
});
|
});
|
||||||
|
|
||||||
Future<PendingTransactionDescription> createTransactionMultDest(
|
Future<PendingTransactionDescription> createTransactionMultDest(
|
||||||
{required List<MoneroOutput> outputs,
|
{required List<MoneroOutput> outputs,
|
||||||
required int priorityRaw,
|
required int priorityRaw,
|
||||||
String paymentId = '',
|
String paymentId = '',
|
||||||
int accountIndex = 0}) =>
|
int accountIndex = 0,
|
||||||
|
List<String> preferredInputs = const []}) =>
|
||||||
compute(_createTransactionMultDestSync, {
|
compute(_createTransactionMultDestSync, {
|
||||||
'outputs': outputs,
|
'outputs': outputs,
|
||||||
'paymentId': paymentId,
|
'paymentId': paymentId,
|
||||||
'priorityRaw': priorityRaw,
|
'priorityRaw': priorityRaw,
|
||||||
'accountIndex': accountIndex
|
'accountIndex': accountIndex,
|
||||||
|
'preferredInputs': preferredInputs
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:ffi';
|
import 'dart:ffi';
|
||||||
|
import 'package:cw_monero/api/structs/coins_info_row.dart';
|
||||||
import 'package:cw_monero/api/structs/pending_transaction.dart';
|
import 'package:cw_monero/api/structs/pending_transaction.dart';
|
||||||
import 'package:cw_monero/api/structs/ut8_box.dart';
|
import 'package:cw_monero/api/structs/ut8_box.dart';
|
||||||
import 'package:ffi/ffi.dart';
|
import 'package:ffi/ffi.dart';
|
||||||
|
@ -92,6 +93,8 @@ typedef TransactionCreate = int Function(
|
||||||
Pointer<Utf8> amount,
|
Pointer<Utf8> amount,
|
||||||
int priorityRaw,
|
int priorityRaw,
|
||||||
int subaddrAccount,
|
int subaddrAccount,
|
||||||
|
Pointer<Pointer<Utf8>> preferredInputs,
|
||||||
|
int preferredInputsSize,
|
||||||
Pointer<Utf8Box> error,
|
Pointer<Utf8Box> error,
|
||||||
Pointer<PendingTransactionRaw> pendingTransaction);
|
Pointer<PendingTransactionRaw> pendingTransaction);
|
||||||
|
|
||||||
|
@ -102,6 +105,8 @@ typedef TransactionCreateMultDest = int Function(
|
||||||
int size,
|
int size,
|
||||||
int priorityRaw,
|
int priorityRaw,
|
||||||
int subaddrAccount,
|
int subaddrAccount,
|
||||||
|
Pointer<Pointer<Utf8>> preferredInputs,
|
||||||
|
int preferredInputsSize,
|
||||||
Pointer<Utf8Box> error,
|
Pointer<Utf8Box> error,
|
||||||
Pointer<PendingTransactionRaw> pendingTransaction);
|
Pointer<PendingTransactionRaw> pendingTransaction);
|
||||||
|
|
||||||
|
@ -127,4 +132,10 @@ typedef GetSubaddressLabel = Pointer<Utf8> Function(
|
||||||
|
|
||||||
typedef SetTrustedDaemon = void Function(int);
|
typedef SetTrustedDaemon = void Function(int);
|
||||||
|
|
||||||
typedef TrustedDaemon = int Function();
|
typedef TrustedDaemon = int Function();
|
||||||
|
|
||||||
|
typedef RefreshCoins = void Function(int);
|
||||||
|
|
||||||
|
typedef CoinsCount = int Function();
|
||||||
|
|
||||||
|
typedef GetCoin = Pointer<CoinsInfoRow> Function(int);
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
class MoneroTransactionNoInputsException implements Exception {
|
||||||
|
@override
|
||||||
|
String toString() => 'Not enough inputs available. Please select more under Coin Control';
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:cw_monero/api/structs/subaddress_row.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:cw_monero/api/coins_info.dart';
|
||||||
import 'package:cw_monero/api/subaddress_list.dart' as subaddress_list;
|
import 'package:cw_monero/api/subaddress_list.dart' as subaddress_list;
|
||||||
import 'package:cw_core/subaddress.dart';
|
import 'package:cw_core/subaddress.dart';
|
||||||
|
|
||||||
|
@ -22,6 +22,8 @@ abstract class MoneroSubaddressListBase with Store {
|
||||||
bool _isUpdating;
|
bool _isUpdating;
|
||||||
|
|
||||||
void update({required int accountIndex}) {
|
void update({required int accountIndex}) {
|
||||||
|
refreshCoins(accountIndex);
|
||||||
|
|
||||||
if (_isUpdating) {
|
if (_isUpdating) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
28
cw_monero/lib/monero_unspent.dart
Normal file
28
cw_monero/lib/monero_unspent.dart
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import 'package:cw_monero/api/structs/coins_info_row.dart';
|
||||||
|
|
||||||
|
class MoneroUnspent {
|
||||||
|
MoneroUnspent(this.address, this.hash, this.keyImage, this.value, this.isFrozen, this.isUnlocked)
|
||||||
|
: isSending = true,
|
||||||
|
note = '';
|
||||||
|
|
||||||
|
MoneroUnspent.fromCoinsInfoRow(CoinsInfoRow coinsInfoRow)
|
||||||
|
: address = coinsInfoRow.getAddress(),
|
||||||
|
hash = coinsInfoRow.getHash(),
|
||||||
|
keyImage = coinsInfoRow.getKeyImage(),
|
||||||
|
value = coinsInfoRow.amount,
|
||||||
|
isFrozen = coinsInfoRow.frozen == 1,
|
||||||
|
isUnlocked = coinsInfoRow.unlocked == 1,
|
||||||
|
isSending = true,
|
||||||
|
note = '';
|
||||||
|
|
||||||
|
final String address;
|
||||||
|
final String hash;
|
||||||
|
final String keyImage;
|
||||||
|
final int value;
|
||||||
|
|
||||||
|
final bool isUnlocked;
|
||||||
|
|
||||||
|
bool isFrozen;
|
||||||
|
bool isSending;
|
||||||
|
String note;
|
||||||
|
}
|
|
@ -1,33 +1,35 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
|
||||||
import 'package:cw_core/transaction_priority.dart';
|
|
||||||
import 'package:cw_core/monero_amount_format.dart';
|
|
||||||
import 'package:cw_monero/monero_transaction_creation_exception.dart';
|
|
||||||
import 'package:cw_monero/monero_transaction_info.dart';
|
|
||||||
import 'package:cw_monero/monero_wallet_addresses.dart';
|
|
||||||
import 'package:cw_core/monero_wallet_utils.dart';
|
|
||||||
import 'package:cw_monero/api/structs/pending_transaction.dart';
|
|
||||||
import 'package:mobx/mobx.dart';
|
|
||||||
import 'package:cw_monero/api/transaction_history.dart'
|
|
||||||
as monero_transaction_history;
|
|
||||||
import 'package:cw_monero/api/wallet.dart';
|
|
||||||
import 'package:cw_monero/api/wallet.dart' as monero_wallet;
|
|
||||||
import 'package:cw_monero/api/transaction_history.dart' as transaction_history;
|
|
||||||
import 'package:cw_monero/api/monero_output.dart';
|
|
||||||
import 'package:cw_monero/monero_transaction_creation_credentials.dart';
|
|
||||||
import 'package:cw_monero/pending_monero_transaction.dart';
|
|
||||||
import 'package:cw_core/monero_wallet_keys.dart';
|
|
||||||
import 'package:cw_core/monero_balance.dart';
|
|
||||||
import 'package:cw_monero/monero_transaction_history.dart';
|
|
||||||
import 'package:cw_core/account.dart';
|
import 'package:cw_core/account.dart';
|
||||||
import 'package:cw_core/pending_transaction.dart';
|
|
||||||
import 'package:cw_core/wallet_base.dart';
|
|
||||||
import 'package:cw_core/sync_status.dart';
|
|
||||||
import 'package:cw_core/wallet_info.dart';
|
|
||||||
import 'package:cw_core/node.dart';
|
|
||||||
import 'package:cw_core/monero_transaction_priority.dart';
|
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:cw_core/monero_amount_format.dart';
|
||||||
|
import 'package:cw_core/monero_balance.dart';
|
||||||
|
import 'package:cw_core/monero_transaction_priority.dart';
|
||||||
|
import 'package:cw_core/monero_wallet_keys.dart';
|
||||||
|
import 'package:cw_core/monero_wallet_utils.dart';
|
||||||
|
import 'package:cw_core/node.dart';
|
||||||
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
|
import 'package:cw_core/pending_transaction.dart';
|
||||||
|
import 'package:cw_core/sync_status.dart';
|
||||||
|
import 'package:cw_core/transaction_priority.dart';
|
||||||
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
import 'package:cw_monero/api/coins_info.dart';
|
||||||
|
import 'package:cw_monero/api/monero_output.dart';
|
||||||
|
import 'package:cw_monero/api/structs/pending_transaction.dart';
|
||||||
|
import 'package:cw_monero/api/transaction_history.dart' as transaction_history;
|
||||||
|
import 'package:cw_monero/api/wallet.dart' as monero_wallet;
|
||||||
|
import 'package:cw_monero/exceptions/monero_transaction_creation_exception.dart';
|
||||||
|
import 'package:cw_monero/exceptions/monero_transaction_no_inputs_exception.dart';
|
||||||
|
import 'package:cw_monero/pending_monero_transaction.dart';
|
||||||
|
import 'package:cw_monero/monero_transaction_creation_credentials.dart';
|
||||||
|
import 'package:cw_monero/monero_transaction_history.dart';
|
||||||
|
import 'package:cw_monero/monero_transaction_info.dart';
|
||||||
|
import 'package:cw_monero/monero_unspent.dart';
|
||||||
|
import 'package:cw_monero/monero_wallet_addresses.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
|
||||||
part 'monero_wallet.g.dart';
|
part 'monero_wallet.g.dart';
|
||||||
|
|
||||||
|
@ -37,37 +39,39 @@ class MoneroWallet = MoneroWalletBase with _$MoneroWallet;
|
||||||
|
|
||||||
abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
MoneroTransactionHistory, MoneroTransactionInfo> with Store {
|
MoneroTransactionHistory, MoneroTransactionInfo> with Store {
|
||||||
MoneroWalletBase({required WalletInfo walletInfo})
|
MoneroWalletBase({required WalletInfo walletInfo,
|
||||||
|
required Box<UnspentCoinsInfo> unspentCoinsInfo})
|
||||||
: balance = ObservableMap<CryptoCurrency, MoneroBalance>.of({
|
: balance = ObservableMap<CryptoCurrency, MoneroBalance>.of({
|
||||||
CryptoCurrency.xmr: MoneroBalance(
|
CryptoCurrency.xmr: MoneroBalance(
|
||||||
fullBalance: monero_wallet.getFullBalance(accountIndex: 0),
|
fullBalance: monero_wallet.getFullBalance(accountIndex: 0),
|
||||||
unlockedBalance: monero_wallet.getFullBalance(accountIndex: 0))
|
unlockedBalance: monero_wallet.getFullBalance(accountIndex: 0))
|
||||||
}),
|
}),
|
||||||
_isTransactionUpdating = false,
|
_isTransactionUpdating = false,
|
||||||
_hasSyncAfterStartup = false,
|
_hasSyncAfterStartup = false,
|
||||||
walletAddresses = MoneroWalletAddresses(walletInfo),
|
walletAddresses = MoneroWalletAddresses(walletInfo),
|
||||||
syncStatus = NotConnectedSyncStatus(),
|
syncStatus = NotConnectedSyncStatus(),
|
||||||
|
unspentCoins = [],
|
||||||
|
this.unspentCoinsInfo = unspentCoinsInfo,
|
||||||
super(walletInfo) {
|
super(walletInfo) {
|
||||||
transactionHistory = MoneroTransactionHistory();
|
transactionHistory = MoneroTransactionHistory();
|
||||||
_onAccountChangeReaction = reaction((_) => walletAddresses.account,
|
_onAccountChangeReaction = reaction((_) => walletAddresses.account, (Account? account) {
|
||||||
(Account? account) {
|
|
||||||
if (account == null) {
|
if (account == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
balance = ObservableMap<CryptoCurrency, MoneroBalance>.of(
|
balance = ObservableMap<CryptoCurrency, MoneroBalance>.of(<CryptoCurrency, MoneroBalance>{
|
||||||
<CryptoCurrency, MoneroBalance>{
|
currency: MoneroBalance(
|
||||||
currency: MoneroBalance(
|
|
||||||
fullBalance: monero_wallet.getFullBalance(accountIndex: account.id),
|
fullBalance: monero_wallet.getFullBalance(accountIndex: account.id),
|
||||||
unlockedBalance:
|
unlockedBalance: monero_wallet.getUnlockedBalance(accountIndex: account.id))
|
||||||
monero_wallet.getUnlockedBalance(accountIndex: account.id))
|
});
|
||||||
});
|
|
||||||
walletAddresses.updateSubaddressList(accountIndex: account.id);
|
walletAddresses.updateSubaddressList(accountIndex: account.id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static const int _autoSaveInterval = 30;
|
static const int _autoSaveInterval = 30;
|
||||||
|
|
||||||
|
Box<UnspentCoinsInfo> unspentCoinsInfo;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MoneroWalletAddresses walletAddresses;
|
MoneroWalletAddresses walletAddresses;
|
||||||
|
|
||||||
|
@ -89,11 +93,12 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
publicSpendKey: monero_wallet.getPublicSpendKey(),
|
publicSpendKey: monero_wallet.getPublicSpendKey(),
|
||||||
publicViewKey: monero_wallet.getPublicViewKey());
|
publicViewKey: monero_wallet.getPublicViewKey());
|
||||||
|
|
||||||
SyncListener? _listener;
|
monero_wallet.SyncListener? _listener;
|
||||||
ReactionDisposer? _onAccountChangeReaction;
|
ReactionDisposer? _onAccountChangeReaction;
|
||||||
bool _isTransactionUpdating;
|
bool _isTransactionUpdating;
|
||||||
bool _hasSyncAfterStartup;
|
bool _hasSyncAfterStartup;
|
||||||
Timer? _autoSaveTimer;
|
Timer? _autoSaveTimer;
|
||||||
|
List<MoneroUnspent> unspentCoins;
|
||||||
|
|
||||||
Future<void> init() async {
|
Future<void> init() async {
|
||||||
await walletAddresses.init();
|
await walletAddresses.init();
|
||||||
|
@ -170,10 +175,12 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
@override
|
@override
|
||||||
Future<PendingTransaction> createTransaction(Object credentials) async {
|
Future<PendingTransaction> createTransaction(Object credentials) async {
|
||||||
final _credentials = credentials as MoneroTransactionCreationCredentials;
|
final _credentials = credentials as MoneroTransactionCreationCredentials;
|
||||||
|
final inputs = <String>[];
|
||||||
final outputs = _credentials.outputs;
|
final outputs = _credentials.outputs;
|
||||||
final hasMultiDestination = outputs.length > 1;
|
final hasMultiDestination = outputs.length > 1;
|
||||||
final unlockedBalance =
|
final unlockedBalance =
|
||||||
monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id);
|
monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id);
|
||||||
|
var allInputsAmount = 0;
|
||||||
|
|
||||||
PendingTransactionDescription pendingTransactionDescription;
|
PendingTransactionDescription pendingTransactionDescription;
|
||||||
|
|
||||||
|
@ -181,6 +188,21 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
throw MoneroTransactionCreationException('The wallet is not synced.');
|
throw MoneroTransactionCreationException('The wallet is not synced.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (unspentCoins.isEmpty) {
|
||||||
|
await updateUnspent();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final utx in unspentCoins) {
|
||||||
|
if (utx.isSending) {
|
||||||
|
allInputsAmount += utx.value;
|
||||||
|
inputs.add(utx.keyImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputs.isEmpty) {
|
||||||
|
throw MoneroTransactionNoInputsException();
|
||||||
|
}
|
||||||
|
|
||||||
if (hasMultiDestination) {
|
if (hasMultiDestination) {
|
||||||
if (outputs.any((item) => item.sendAll
|
if (outputs.any((item) => item.sendAll
|
||||||
|| (item.formattedCryptoAmount ?? 0) <= 0)) {
|
|| (item.formattedCryptoAmount ?? 0) <= 0)) {
|
||||||
|
@ -208,7 +230,8 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
await transaction_history.createTransactionMultDest(
|
await transaction_history.createTransactionMultDest(
|
||||||
outputs: moneroOutputs,
|
outputs: moneroOutputs,
|
||||||
priorityRaw: _credentials.priority.serialize(),
|
priorityRaw: _credentials.priority.serialize(),
|
||||||
accountIndex: walletAddresses.account!.id);
|
accountIndex: walletAddresses.account!.id,
|
||||||
|
preferredInputs: inputs);
|
||||||
} else {
|
} else {
|
||||||
final output = outputs.first;
|
final output = outputs.first;
|
||||||
final address = output.isParsedAddress
|
final address = output.isParsedAddress
|
||||||
|
@ -229,12 +252,12 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
'You do not have enough unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.');
|
'You do not have enough unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.');
|
||||||
}
|
}
|
||||||
|
|
||||||
pendingTransactionDescription =
|
pendingTransactionDescription = await transaction_history.createTransaction(
|
||||||
await transaction_history.createTransaction(
|
|
||||||
address: address!,
|
address: address!,
|
||||||
amount: amount,
|
amount: amount,
|
||||||
priorityRaw: _credentials.priority.serialize(),
|
priorityRaw: _credentials.priority.serialize(),
|
||||||
accountIndex: walletAddresses.account!.id);
|
accountIndex: walletAddresses.account!.id,
|
||||||
|
preferredInputs: inputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
return PendingMoneroTransaction(pendingTransactionDescription);
|
return PendingMoneroTransaction(pendingTransactionDescription);
|
||||||
|
@ -354,6 +377,85 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
await walletInfo.save();
|
await walletInfo.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> updateUnspent() async {
|
||||||
|
refreshCoins(walletAddresses.account!.id);
|
||||||
|
|
||||||
|
unspentCoins.clear();
|
||||||
|
|
||||||
|
final coinCount = countOfCoins();
|
||||||
|
for (var i = 0; i < coinCount; i++) {
|
||||||
|
final coin = getCoin(i);
|
||||||
|
if (coin.spent == 0) {
|
||||||
|
unspentCoins.add(MoneroUnspent.fromCoinsInfoRow(coin));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unspentCoinsInfo.isEmpty) {
|
||||||
|
unspentCoins.forEach((coin) => _addCoinInfo(coin));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unspentCoins.isNotEmpty) {
|
||||||
|
unspentCoins.forEach((coin) {
|
||||||
|
final coinInfoList = unspentCoinsInfo.values.where((element) =>
|
||||||
|
element.walletId.contains(id) && element.hash.contains(coin.hash));
|
||||||
|
|
||||||
|
if (coinInfoList.isNotEmpty) {
|
||||||
|
final coinInfo = coinInfoList.first;
|
||||||
|
|
||||||
|
coin.isFrozen = coinInfo.isFrozen;
|
||||||
|
coin.isSending = coinInfo.isSending;
|
||||||
|
coin.note = coinInfo.note;
|
||||||
|
} else {
|
||||||
|
_addCoinInfo(coin);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await _refreshUnspentCoinsInfo();
|
||||||
|
_askForUpdateBalance();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _addCoinInfo(MoneroUnspent coin) async {
|
||||||
|
final newInfo = UnspentCoinsInfo(
|
||||||
|
walletId: id,
|
||||||
|
hash: coin.hash,
|
||||||
|
isFrozen: coin.isFrozen,
|
||||||
|
isSending: coin.isSending,
|
||||||
|
noteRaw: coin.note,
|
||||||
|
address: coin.address,
|
||||||
|
value: coin.value,
|
||||||
|
vout: 0,
|
||||||
|
keyImage: coin.keyImage
|
||||||
|
);
|
||||||
|
|
||||||
|
await unspentCoinsInfo.add(newInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _refreshUnspentCoinsInfo() async {
|
||||||
|
try {
|
||||||
|
final List<dynamic> keys = <dynamic>[];
|
||||||
|
final currentWalletUnspentCoins = unspentCoinsInfo.values
|
||||||
|
.where((element) => element.walletId.contains(id));
|
||||||
|
|
||||||
|
if (currentWalletUnspentCoins.isNotEmpty) {
|
||||||
|
currentWalletUnspentCoins.forEach((element) {
|
||||||
|
final existUnspentCoins = unspentCoins.where((coin) => element.hash.contains(coin.hash));
|
||||||
|
|
||||||
|
if (existUnspentCoins.isEmpty) {
|
||||||
|
keys.add(element.key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keys.isNotEmpty) {
|
||||||
|
await unspentCoinsInfo.deleteAll(keys);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String getTransactionAddress(int accountIndex, int addressIndex) =>
|
String getTransactionAddress(int accountIndex, int addressIndex) =>
|
||||||
monero_wallet.getAddress(
|
monero_wallet.getAddress(
|
||||||
accountIndex: accountIndex,
|
accountIndex: accountIndex,
|
||||||
|
@ -361,7 +463,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Map<String, MoneroTransactionInfo>> fetchTransactions() async {
|
Future<Map<String, MoneroTransactionInfo>> fetchTransactions() async {
|
||||||
monero_transaction_history.refreshTransactions();
|
transaction_history.refreshTransactions();
|
||||||
return _getAllTransactions(null).fold<Map<String, MoneroTransactionInfo>>(
|
return _getAllTransactions(null).fold<Map<String, MoneroTransactionInfo>>(
|
||||||
<String, MoneroTransactionInfo>{},
|
<String, MoneroTransactionInfo>{},
|
||||||
(Map<String, MoneroTransactionInfo> acc, MoneroTransactionInfo tx) {
|
(Map<String, MoneroTransactionInfo> acc, MoneroTransactionInfo tx) {
|
||||||
|
@ -392,7 +494,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
}
|
}
|
||||||
|
|
||||||
List<MoneroTransactionInfo> _getAllTransactions(dynamic _) =>
|
List<MoneroTransactionInfo> _getAllTransactions(dynamic _) =>
|
||||||
monero_transaction_history
|
transaction_history
|
||||||
.getAllTransations()
|
.getAllTransations()
|
||||||
.map((row) => MoneroTransactionInfo.fromRow(row))
|
.map((row) => MoneroTransactionInfo.fromRow(row))
|
||||||
.toList();
|
.toList();
|
||||||
|
@ -407,7 +509,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final currentHeight = getCurrentHeight();
|
final currentHeight = monero_wallet.getCurrentHeight();
|
||||||
|
|
||||||
if (currentHeight <= 1) {
|
if (currentHeight <= 1) {
|
||||||
final height = _getHeightByDate(walletInfo.date);
|
final height = _getHeightByDate(walletInfo.date);
|
||||||
|
@ -439,11 +541,13 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
void _askForUpdateBalance() {
|
void _askForUpdateBalance() {
|
||||||
final unlockedBalance = _getUnlockedBalance();
|
final unlockedBalance = _getUnlockedBalance();
|
||||||
final fullBalance = _getFullBalance();
|
final fullBalance = _getFullBalance();
|
||||||
|
final frozenBalance = _getFrozenBalance();
|
||||||
|
|
||||||
if (balance[currency]!.fullBalance != fullBalance ||
|
if (balance[currency]!.fullBalance != fullBalance ||
|
||||||
balance[currency]!.unlockedBalance != unlockedBalance) {
|
balance[currency]!.unlockedBalance != unlockedBalance ||
|
||||||
|
balance[currency]!.frozenBalance != frozenBalance) {
|
||||||
balance[currency] = MoneroBalance(
|
balance[currency] = MoneroBalance(
|
||||||
fullBalance: fullBalance, unlockedBalance: unlockedBalance);
|
fullBalance: fullBalance, unlockedBalance: unlockedBalance, frozenBalance: frozenBalance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,6 +560,17 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
int _getUnlockedBalance() =>
|
int _getUnlockedBalance() =>
|
||||||
monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id);
|
monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id);
|
||||||
|
|
||||||
|
int _getFrozenBalance() {
|
||||||
|
var frozenBalance = 0;
|
||||||
|
|
||||||
|
for (var coin in unspentCoinsInfo.values) {
|
||||||
|
if (coin.isFrozen)
|
||||||
|
frozenBalance += coin.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return frozenBalance;
|
||||||
|
}
|
||||||
|
|
||||||
void _onNewBlock(int height, int blocksLeft, double ptc) async {
|
void _onNewBlock(int height, int blocksLeft, double ptc) async {
|
||||||
try {
|
try {
|
||||||
if (walletInfo.isRecovery) {
|
if (walletInfo.isRecovery) {
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
|
||||||
import 'package:cw_core/monero_wallet_utils.dart';
|
import 'package:cw_core/monero_wallet_utils.dart';
|
||||||
import 'package:hive/hive.dart';
|
|
||||||
import 'package:cw_monero/api/wallet_manager.dart' as monero_wallet_manager;
|
|
||||||
import 'package:cw_monero/api/wallet.dart' as monero_wallet;
|
|
||||||
import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart';
|
|
||||||
import 'package:cw_monero/monero_wallet.dart';
|
|
||||||
import 'package:cw_core/wallet_credentials.dart';
|
|
||||||
import 'package:cw_core/wallet_service.dart';
|
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
import 'package:cw_core/wallet_credentials.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
import 'package:cw_core/wallet_service.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart';
|
||||||
|
import 'package:cw_monero/api/wallet_manager.dart' as monero_wallet_manager;
|
||||||
|
import 'package:cw_monero/monero_wallet.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
|
||||||
class MoneroNewWalletCredentials extends WalletCredentials {
|
class MoneroNewWalletCredentials extends WalletCredentials {
|
||||||
MoneroNewWalletCredentials({required String name, required this.language, String? password})
|
MoneroNewWalletCredentials({required String name, required this.language, String? password})
|
||||||
|
@ -53,9 +53,10 @@ class MoneroWalletService extends WalletService<
|
||||||
MoneroNewWalletCredentials,
|
MoneroNewWalletCredentials,
|
||||||
MoneroRestoreWalletFromSeedCredentials,
|
MoneroRestoreWalletFromSeedCredentials,
|
||||||
MoneroRestoreWalletFromKeysCredentials> {
|
MoneroRestoreWalletFromKeysCredentials> {
|
||||||
MoneroWalletService(this.walletInfoSource);
|
MoneroWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
|
||||||
|
|
||||||
final Box<WalletInfo> walletInfoSource;
|
final Box<WalletInfo> walletInfoSource;
|
||||||
|
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
|
||||||
|
|
||||||
static bool walletFilesExist(String path) =>
|
static bool walletFilesExist(String path) =>
|
||||||
!File(path).existsSync() && !File('$path.keys').existsSync();
|
!File(path).existsSync() && !File('$path.keys').existsSync();
|
||||||
|
@ -71,7 +72,8 @@ class MoneroWalletService extends WalletService<
|
||||||
path: path,
|
path: path,
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
language: credentials.language);
|
language: credentials.language);
|
||||||
final wallet = MoneroWallet(walletInfo: credentials.walletInfo!);
|
final wallet = MoneroWallet(
|
||||||
|
walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
|
||||||
return wallet;
|
return wallet;
|
||||||
|
@ -107,7 +109,7 @@ class MoneroWalletService extends WalletService<
|
||||||
.openWalletAsync({'path': path, 'password': password});
|
.openWalletAsync({'path': path, 'password': password});
|
||||||
final walletInfo = walletInfoSource.values.firstWhere(
|
final walletInfo = walletInfoSource.values.firstWhere(
|
||||||
(info) => info.id == WalletBase.idFor(name, getType()));
|
(info) => info.id == WalletBase.idFor(name, getType()));
|
||||||
final wallet = MoneroWallet(walletInfo: walletInfo);
|
final wallet = MoneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
|
||||||
final isValid = wallet.walletAddresses.validate();
|
final isValid = wallet.walletAddresses.validate();
|
||||||
|
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
|
@ -157,7 +159,8 @@ class MoneroWalletService extends WalletService<
|
||||||
String currentName, String password, String newName) async {
|
String currentName, String password, String newName) async {
|
||||||
final currentWalletInfo = walletInfoSource.values.firstWhere(
|
final currentWalletInfo = walletInfoSource.values.firstWhere(
|
||||||
(info) => info.id == WalletBase.idFor(currentName, getType()));
|
(info) => info.id == WalletBase.idFor(currentName, getType()));
|
||||||
final currentWallet = MoneroWallet(walletInfo: currentWalletInfo);
|
final currentWallet =
|
||||||
|
MoneroWallet(walletInfo: currentWalletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
|
||||||
|
|
||||||
await currentWallet.renameWalletFiles(newName);
|
await currentWallet.renameWalletFiles(newName);
|
||||||
|
|
||||||
|
@ -181,7 +184,8 @@ class MoneroWalletService extends WalletService<
|
||||||
address: credentials.address,
|
address: credentials.address,
|
||||||
viewKey: credentials.viewKey,
|
viewKey: credentials.viewKey,
|
||||||
spendKey: credentials.spendKey);
|
spendKey: credentials.spendKey);
|
||||||
final wallet = MoneroWallet(walletInfo: credentials.walletInfo!);
|
final wallet = MoneroWallet(
|
||||||
|
walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
|
||||||
return wallet;
|
return wallet;
|
||||||
|
@ -202,7 +206,8 @@ class MoneroWalletService extends WalletService<
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
seed: credentials.mnemonic,
|
seed: credentials.mnemonic,
|
||||||
restoreHeight: credentials.height!);
|
restoreHeight: credentials.height!);
|
||||||
final wallet = MoneroWallet(walletInfo: credentials.walletInfo!);
|
final wallet = MoneroWallet(
|
||||||
|
walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
|
||||||
return wallet;
|
return wallet;
|
||||||
|
|
|
@ -128,7 +128,8 @@ class CWBitcoin extends Bitcoin {
|
||||||
bitcoinUnspent.address.address,
|
bitcoinUnspent.address.address,
|
||||||
bitcoinUnspent.hash,
|
bitcoinUnspent.hash,
|
||||||
bitcoinUnspent.value,
|
bitcoinUnspent.value,
|
||||||
bitcoinUnspent.vout))
|
bitcoinUnspent.vout,
|
||||||
|
null))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,4 +161,4 @@ class CWBitcoin extends Bitcoin {
|
||||||
@override
|
@override
|
||||||
TransactionPriority getLitecoinTransactionPrioritySlow()
|
TransactionPriority getLitecoinTransactionPrioritySlow()
|
||||||
=> LitecoinTransactionPriority.slow;
|
=> LitecoinTransactionPriority.slow;
|
||||||
}
|
}
|
||||||
|
|
12
lib/di.dart
12
lib/di.dart
|
@ -216,10 +216,10 @@ late Box<Template> _templates;
|
||||||
late Box<ExchangeTemplate> _exchangeTemplates;
|
late Box<ExchangeTemplate> _exchangeTemplates;
|
||||||
late Box<TransactionDescription> _transactionDescriptionBox;
|
late Box<TransactionDescription> _transactionDescriptionBox;
|
||||||
late Box<Order> _ordersSource;
|
late Box<Order> _ordersSource;
|
||||||
late Box<UnspentCoinsInfo>? _unspentCoinsInfoSource;
|
late Box<UnspentCoinsInfo> _unspentCoinsInfoSource;
|
||||||
late Box<AnonpayInvoiceInfo> _anonpayInvoiceInfoSource;
|
late Box<AnonpayInvoiceInfo> _anonpayInvoiceInfoSource;
|
||||||
|
|
||||||
Future setup({
|
Future<void> setup({
|
||||||
required Box<WalletInfo> walletInfoSource,
|
required Box<WalletInfo> walletInfoSource,
|
||||||
required Box<Node> nodeSource,
|
required Box<Node> nodeSource,
|
||||||
required Box<Contact> contactSource,
|
required Box<Contact> contactSource,
|
||||||
|
@ -228,7 +228,7 @@ Future setup({
|
||||||
required Box<ExchangeTemplate> exchangeTemplates,
|
required Box<ExchangeTemplate> exchangeTemplates,
|
||||||
required Box<TransactionDescription> transactionDescriptionBox,
|
required Box<TransactionDescription> transactionDescriptionBox,
|
||||||
required Box<Order> ordersSource,
|
required Box<Order> ordersSource,
|
||||||
Box<UnspentCoinsInfo>? unspentCoinsInfoSource,
|
required Box<UnspentCoinsInfo> unspentCoinsInfoSource,
|
||||||
required Box<AnonpayInvoiceInfo> anonpayInvoiceInfoSource,
|
required Box<AnonpayInvoiceInfo> anonpayInvoiceInfoSource,
|
||||||
}) async {
|
}) async {
|
||||||
_walletInfoSource = walletInfoSource;
|
_walletInfoSource = walletInfoSource;
|
||||||
|
@ -731,11 +731,11 @@ Future setup({
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
return haven!.createHavenWalletService(_walletInfoSource);
|
return haven!.createHavenWalletService(_walletInfoSource);
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
return monero!.createMoneroWalletService(_walletInfoSource);
|
return monero!.createMoneroWalletService(_walletInfoSource, _unspentCoinsInfoSource);
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
return bitcoin!.createBitcoinWalletService(_walletInfoSource, _unspentCoinsInfoSource!);
|
return bitcoin!.createBitcoinWalletService(_walletInfoSource, _unspentCoinsInfoSource);
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
return bitcoin!.createLitecoinWalletService(_walletInfoSource, _unspentCoinsInfoSource!);
|
return bitcoin!.createLitecoinWalletService(_walletInfoSource, _unspentCoinsInfoSource);
|
||||||
case WalletType.ethereum:
|
case WalletType.ethereum:
|
||||||
return ethereum!.createEthereumWalletService(_walletInfoSource);
|
return ethereum!.createEthereumWalletService(_walletInfoSource);
|
||||||
default:
|
default:
|
||||||
|
|
18
lib/entities/unspent_transaction_output.dart
Normal file
18
lib/entities/unspent_transaction_output.dart
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
class Unspent {
|
||||||
|
Unspent(this.address, this.hash, this.value, this.vout, this.keyImage)
|
||||||
|
: isSending = true,
|
||||||
|
isFrozen = false,
|
||||||
|
note = '';
|
||||||
|
|
||||||
|
final String address;
|
||||||
|
final String hash;
|
||||||
|
final int value;
|
||||||
|
final int vout;
|
||||||
|
final String? keyImage;
|
||||||
|
|
||||||
|
bool isSending;
|
||||||
|
bool isFrozen;
|
||||||
|
String note;
|
||||||
|
|
||||||
|
bool get isP2wpkh => address.startsWith('bc') || address.startsWith('ltc');
|
||||||
|
}
|
|
@ -133,11 +133,7 @@ Future<void> initializeAppConfigs() async {
|
||||||
final templates = await CakeHive.openBox<Template>(Template.boxName);
|
final templates = await CakeHive.openBox<Template>(Template.boxName);
|
||||||
final exchangeTemplates = await CakeHive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName);
|
final exchangeTemplates = await CakeHive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName);
|
||||||
final anonpayInvoiceInfo = await CakeHive.openBox<AnonpayInvoiceInfo>(AnonpayInvoiceInfo.boxName);
|
final anonpayInvoiceInfo = await CakeHive.openBox<AnonpayInvoiceInfo>(AnonpayInvoiceInfo.boxName);
|
||||||
Box<UnspentCoinsInfo>? unspentCoinsInfoSource;
|
final unspentCoinsInfoSource = await CakeHive.openBox<UnspentCoinsInfo>(UnspentCoinsInfo.boxName);
|
||||||
|
|
||||||
if (!isMoneroOnly) {
|
|
||||||
unspentCoinsInfoSource = await CakeHive.openBox<UnspentCoinsInfo>(UnspentCoinsInfo.boxName);
|
|
||||||
}
|
|
||||||
|
|
||||||
await initialSetup(
|
await initialSetup(
|
||||||
sharedPreferences: await SharedPreferences.getInstance(),
|
sharedPreferences: await SharedPreferences.getInstance(),
|
||||||
|
@ -169,7 +165,7 @@ Future<void> initialSetup(
|
||||||
required Box<TransactionDescription> transactionDescriptions,
|
required Box<TransactionDescription> transactionDescriptions,
|
||||||
required FlutterSecureStorage secureStorage,
|
required FlutterSecureStorage secureStorage,
|
||||||
required Box<AnonpayInvoiceInfo> anonpayInvoiceInfo,
|
required Box<AnonpayInvoiceInfo> anonpayInvoiceInfo,
|
||||||
Box<UnspentCoinsInfo>? unspentCoinsInfoSource,
|
required Box<UnspentCoinsInfo> unspentCoinsInfoSource,
|
||||||
int initialMigrationVersion = 15}) async {
|
int initialMigrationVersion = 15}) async {
|
||||||
LanguageService.loadLocaleList();
|
LanguageService.loadLocaleList();
|
||||||
await defaultSettingsMigration(
|
await defaultSettingsMigration(
|
||||||
|
|
|
@ -1,361 +1,363 @@
|
||||||
part of 'monero.dart';
|
part of 'monero.dart';
|
||||||
|
|
||||||
class CWMoneroAccountList extends MoneroAccountList {
|
class CWMoneroAccountList extends MoneroAccountList {
|
||||||
CWMoneroAccountList(this._wallet);
|
CWMoneroAccountList(this._wallet);
|
||||||
final Object _wallet;
|
|
||||||
|
|
||||||
@override
|
final Object _wallet;
|
||||||
@computed
|
|
||||||
|
@override
|
||||||
|
@computed
|
||||||
ObservableList<Account> get accounts {
|
ObservableList<Account> get accounts {
|
||||||
final moneroWallet = _wallet as MoneroWallet;
|
final moneroWallet = _wallet as MoneroWallet;
|
||||||
final accounts = moneroWallet.walletAddresses.accountList
|
final accounts = moneroWallet.walletAddresses.accountList.accounts
|
||||||
.accounts
|
.map((acc) => Account(id: acc.id, label: acc.label, balance: acc.balance))
|
||||||
.map((acc) => Account(id: acc.id, label: acc.label, balance: acc.balance))
|
.toList();
|
||||||
.toList();
|
return ObservableList<Account>.of(accounts);
|
||||||
return ObservableList<Account>.of(accounts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void update(Object wallet) {
|
void update(Object wallet) {
|
||||||
final moneroWallet = wallet as MoneroWallet;
|
final moneroWallet = wallet as MoneroWallet;
|
||||||
moneroWallet.walletAddresses.accountList.update();
|
moneroWallet.walletAddresses.accountList.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void refresh(Object wallet) {
|
void refresh(Object wallet) {
|
||||||
final moneroWallet = wallet as MoneroWallet;
|
final moneroWallet = wallet as MoneroWallet;
|
||||||
moneroWallet.walletAddresses.accountList.refresh();
|
moneroWallet.walletAddresses.accountList.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Account> getAll(Object wallet) {
|
List<Account> getAll(Object wallet) {
|
||||||
final moneroWallet = wallet as MoneroWallet;
|
final moneroWallet = wallet as MoneroWallet;
|
||||||
return moneroWallet.walletAddresses.accountList
|
return moneroWallet.walletAddresses.accountList
|
||||||
.getAll()
|
.getAll()
|
||||||
.map((acc) => Account(id: acc.id, label: acc.label, balance: acc.balance))
|
.map((acc) => Account(id: acc.id, label: acc.label, balance: acc.balance))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> addAccount(Object wallet, {required String label}) async {
|
Future<void> addAccount(Object wallet, {required String label}) async {
|
||||||
final moneroWallet = wallet as MoneroWallet;
|
final moneroWallet = wallet as MoneroWallet;
|
||||||
await moneroWallet.walletAddresses.accountList.addAccount(label: label);
|
await moneroWallet.walletAddresses.accountList.addAccount(label: label);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> setLabelAccount(Object wallet, {required int accountIndex, required String label}) async {
|
Future<void> setLabelAccount(Object wallet,
|
||||||
final moneroWallet = wallet as MoneroWallet;
|
{required int accountIndex, required String label}) async {
|
||||||
await moneroWallet.walletAddresses.accountList
|
final moneroWallet = wallet as MoneroWallet;
|
||||||
.setLabelAccount(
|
await moneroWallet.walletAddresses.accountList
|
||||||
accountIndex: accountIndex,
|
.setLabelAccount(accountIndex: accountIndex, label: label);
|
||||||
label: label);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CWMoneroSubaddressList extends MoneroSubaddressList {
|
class CWMoneroSubaddressList extends MoneroSubaddressList {
|
||||||
CWMoneroSubaddressList(this._wallet);
|
CWMoneroSubaddressList(this._wallet);
|
||||||
final Object _wallet;
|
|
||||||
|
|
||||||
@override
|
final Object _wallet;
|
||||||
@computed
|
|
||||||
|
@override
|
||||||
|
@computed
|
||||||
ObservableList<Subaddress> get subaddresses {
|
ObservableList<Subaddress> get subaddresses {
|
||||||
final moneroWallet = _wallet as MoneroWallet;
|
final moneroWallet = _wallet as MoneroWallet;
|
||||||
final subAddresses = moneroWallet.walletAddresses.subaddressList
|
final subAddresses = moneroWallet.walletAddresses.subaddressList.subaddresses
|
||||||
.subaddresses
|
.map((sub) => Subaddress(id: sub.id, address: sub.address, label: sub.label))
|
||||||
.map((sub) => Subaddress(
|
.toList();
|
||||||
id: sub.id,
|
return ObservableList<Subaddress>.of(subAddresses);
|
||||||
address: sub.address,
|
|
||||||
label: sub.label))
|
|
||||||
.toList();
|
|
||||||
return ObservableList<Subaddress>.of(subAddresses);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void update(Object wallet, {required int accountIndex}) {
|
void update(Object wallet, {required int accountIndex}) {
|
||||||
final moneroWallet = wallet as MoneroWallet;
|
final moneroWallet = wallet as MoneroWallet;
|
||||||
moneroWallet.walletAddresses.subaddressList.update(accountIndex: accountIndex);
|
moneroWallet.walletAddresses.subaddressList.update(accountIndex: accountIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void refresh(Object wallet, {required int accountIndex}) {
|
void refresh(Object wallet, {required int accountIndex}) {
|
||||||
final moneroWallet = wallet as MoneroWallet;
|
final moneroWallet = wallet as MoneroWallet;
|
||||||
moneroWallet.walletAddresses.subaddressList.refresh(accountIndex: accountIndex);
|
moneroWallet.walletAddresses.subaddressList.refresh(accountIndex: accountIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Subaddress> getAll(Object wallet) {
|
List<Subaddress> getAll(Object wallet) {
|
||||||
final moneroWallet = wallet as MoneroWallet;
|
final moneroWallet = wallet as MoneroWallet;
|
||||||
return moneroWallet.walletAddresses
|
return moneroWallet.walletAddresses.subaddressList
|
||||||
.subaddressList
|
.getAll()
|
||||||
.getAll()
|
.map((sub) => Subaddress(id: sub.id, label: sub.label, address: sub.address))
|
||||||
.map((sub) => Subaddress(id: sub.id, label: sub.label, address: sub.address))
|
.toList();
|
||||||
.toList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> addSubaddress(Object wallet, {required int accountIndex, required String label}) async {
|
Future<void> addSubaddress(Object wallet,
|
||||||
final moneroWallet = wallet as MoneroWallet;
|
{required int accountIndex, required String label}) async {
|
||||||
await moneroWallet.walletAddresses.subaddressList
|
final moneroWallet = wallet as MoneroWallet;
|
||||||
.addSubaddress(
|
await moneroWallet.walletAddresses.subaddressList
|
||||||
accountIndex: accountIndex,
|
.addSubaddress(accountIndex: accountIndex, label: label);
|
||||||
label: label);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> setLabelSubaddress(Object wallet,
|
Future<void> setLabelSubaddress(Object wallet,
|
||||||
{required int accountIndex, required int addressIndex, required String label}) async {
|
{required int accountIndex, required int addressIndex, required String label}) async {
|
||||||
final moneroWallet = wallet as MoneroWallet;
|
final moneroWallet = wallet as MoneroWallet;
|
||||||
await moneroWallet.walletAddresses.subaddressList
|
await moneroWallet.walletAddresses.subaddressList
|
||||||
.setLabelSubaddress(
|
.setLabelSubaddress(accountIndex: accountIndex, addressIndex: addressIndex, label: label);
|
||||||
accountIndex: accountIndex,
|
|
||||||
addressIndex: addressIndex,
|
|
||||||
label: label);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CWMoneroWalletDetails extends MoneroWalletDetails {
|
class CWMoneroWalletDetails extends MoneroWalletDetails {
|
||||||
CWMoneroWalletDetails(this._wallet);
|
CWMoneroWalletDetails(this._wallet);
|
||||||
final Object _wallet;
|
|
||||||
|
|
||||||
@computed
|
final Object _wallet;
|
||||||
|
|
||||||
|
@computed
|
||||||
@override
|
@override
|
||||||
Account get account {
|
Account get account {
|
||||||
final moneroWallet = _wallet as MoneroWallet;
|
final moneroWallet = _wallet as MoneroWallet;
|
||||||
final acc = moneroWallet.walletAddresses.account;
|
final acc = moneroWallet.walletAddresses.account;
|
||||||
return Account(id: acc!.id, label: acc.label, balance: acc.balance);
|
return Account(id: acc!.id, label: acc.label, balance: acc.balance);
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
@override
|
@override
|
||||||
MoneroBalance get balance {
|
MoneroBalance get balance {
|
||||||
final moneroWallet = _wallet as MoneroWallet;
|
final moneroWallet = _wallet as MoneroWallet;
|
||||||
final balance = moneroWallet.balance;
|
final balance = moneroWallet.balance;
|
||||||
throw Exception('Unimplemented');
|
throw Exception('Unimplemented');
|
||||||
// return MoneroBalance();
|
// return MoneroBalance();
|
||||||
//return MoneroBalance(
|
//return MoneroBalance(
|
||||||
// fullBalance: balance.fullBalance,
|
// fullBalance: balance.fullBalance,
|
||||||
// unlockedBalance: balance.unlockedBalance);
|
// unlockedBalance: balance.unlockedBalance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CWMonero extends Monero {
|
class CWMonero extends Monero {
|
||||||
@override
|
@override
|
||||||
MoneroAccountList getAccountList(Object wallet) {
|
MoneroAccountList getAccountList(Object wallet) {
|
||||||
return CWMoneroAccountList(wallet);
|
return CWMoneroAccountList(wallet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
MoneroSubaddressList getSubaddressList(Object wallet) {
|
|
||||||
return CWMoneroSubaddressList(wallet);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
TransactionHistoryBase getTransactionHistory(Object wallet) {
|
|
||||||
final moneroWallet = wallet as MoneroWallet;
|
|
||||||
return moneroWallet.transactionHistory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
MoneroWalletDetails getMoneroWalletDetails(Object wallet) {
|
|
||||||
return CWMoneroWalletDetails(wallet);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int getHeigthByDate({required DateTime date}) {
|
|
||||||
return getMoneroHeigthByDate(date: date);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
TransactionPriority getDefaultTransactionPriority() {
|
|
||||||
return MoneroTransactionPriority.automatic;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
TransactionPriority getMoneroTransactionPrioritySlow()
|
MoneroSubaddressList getSubaddressList(Object wallet) {
|
||||||
=> MoneroTransactionPriority.slow;
|
return CWMoneroSubaddressList(wallet);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
TransactionPriority getMoneroTransactionPriorityAutomatic()
|
TransactionHistoryBase getTransactionHistory(Object wallet) {
|
||||||
=> MoneroTransactionPriority.automatic;
|
final moneroWallet = wallet as MoneroWallet;
|
||||||
|
return moneroWallet.transactionHistory;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
TransactionPriority deserializeMoneroTransactionPriority({required int raw}) {
|
MoneroWalletDetails getMoneroWalletDetails(Object wallet) {
|
||||||
return MoneroTransactionPriority.deserialize(raw: raw);
|
return CWMoneroWalletDetails(wallet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<TransactionPriority> getTransactionPriorities() {
|
int getHeigthByDate({required DateTime date}) {
|
||||||
return MoneroTransactionPriority.all;
|
return getMoneroHeigthByDate(date: date);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> getMoneroWordList(String language) {
|
TransactionPriority getDefaultTransactionPriority() {
|
||||||
switch (language.toLowerCase()) {
|
return MoneroTransactionPriority.automatic;
|
||||||
case 'english':
|
}
|
||||||
return EnglishMnemonics.words;
|
|
||||||
case 'chinese (simplified)':
|
|
||||||
return ChineseSimplifiedMnemonics.words;
|
|
||||||
case 'dutch':
|
|
||||||
return DutchMnemonics.words;
|
|
||||||
case 'german':
|
|
||||||
return GermanMnemonics.words;
|
|
||||||
case 'japanese':
|
|
||||||
return JapaneseMnemonics.words;
|
|
||||||
case 'portuguese':
|
|
||||||
return PortugueseMnemonics.words;
|
|
||||||
case 'russian':
|
|
||||||
return RussianMnemonics.words;
|
|
||||||
case 'spanish':
|
|
||||||
return SpanishMnemonics.words;
|
|
||||||
case 'french':
|
|
||||||
return FrenchMnemonics.words;
|
|
||||||
case 'italian':
|
|
||||||
return ItalianMnemonics.words;
|
|
||||||
default:
|
|
||||||
return EnglishMnemonics.words;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletCredentials createMoneroRestoreWalletFromKeysCredentials({
|
TransactionPriority getMoneroTransactionPrioritySlow() => MoneroTransactionPriority.slow;
|
||||||
required String name,
|
|
||||||
required String spendKey,
|
|
||||||
required String viewKey,
|
|
||||||
required String address,
|
|
||||||
required String password,
|
|
||||||
required String language,
|
|
||||||
required int height}) {
|
|
||||||
return MoneroRestoreWalletFromKeysCredentials(
|
|
||||||
name: name,
|
|
||||||
spendKey: spendKey,
|
|
||||||
viewKey: viewKey,
|
|
||||||
address: address,
|
|
||||||
password: password,
|
|
||||||
language: language,
|
|
||||||
height: height);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
WalletCredentials createMoneroRestoreWalletFromSeedCredentials({
|
|
||||||
required String name,
|
|
||||||
required String password,
|
|
||||||
required int height,
|
|
||||||
required String mnemonic}) {
|
|
||||||
return MoneroRestoreWalletFromSeedCredentials(
|
|
||||||
name: name,
|
|
||||||
password: password,
|
|
||||||
height: height,
|
|
||||||
mnemonic: mnemonic);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletCredentials createMoneroNewWalletCredentials({
|
TransactionPriority getMoneroTransactionPriorityAutomatic() =>
|
||||||
|
MoneroTransactionPriority.automatic;
|
||||||
|
|
||||||
|
@override
|
||||||
|
TransactionPriority deserializeMoneroTransactionPriority({required int raw}) {
|
||||||
|
return MoneroTransactionPriority.deserialize(raw: raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<TransactionPriority> getTransactionPriorities() {
|
||||||
|
return MoneroTransactionPriority.all;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<String> getMoneroWordList(String language) {
|
||||||
|
switch (language.toLowerCase()) {
|
||||||
|
case 'english':
|
||||||
|
return EnglishMnemonics.words;
|
||||||
|
case 'chinese (simplified)':
|
||||||
|
return ChineseSimplifiedMnemonics.words;
|
||||||
|
case 'dutch':
|
||||||
|
return DutchMnemonics.words;
|
||||||
|
case 'german':
|
||||||
|
return GermanMnemonics.words;
|
||||||
|
case 'japanese':
|
||||||
|
return JapaneseMnemonics.words;
|
||||||
|
case 'portuguese':
|
||||||
|
return PortugueseMnemonics.words;
|
||||||
|
case 'russian':
|
||||||
|
return RussianMnemonics.words;
|
||||||
|
case 'spanish':
|
||||||
|
return SpanishMnemonics.words;
|
||||||
|
case 'french':
|
||||||
|
return FrenchMnemonics.words;
|
||||||
|
case 'italian':
|
||||||
|
return ItalianMnemonics.words;
|
||||||
|
default:
|
||||||
|
return EnglishMnemonics.words;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
WalletCredentials createMoneroRestoreWalletFromKeysCredentials(
|
||||||
|
{required String name,
|
||||||
|
required String spendKey,
|
||||||
|
required String viewKey,
|
||||||
|
required String address,
|
||||||
|
required String password,
|
||||||
|
required String language,
|
||||||
|
required int height}) {
|
||||||
|
return MoneroRestoreWalletFromKeysCredentials(
|
||||||
|
name: name,
|
||||||
|
spendKey: spendKey,
|
||||||
|
viewKey: viewKey,
|
||||||
|
address: address,
|
||||||
|
password: password,
|
||||||
|
language: language,
|
||||||
|
height: height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
WalletCredentials createMoneroRestoreWalletFromSeedCredentials(
|
||||||
|
{required String name,
|
||||||
|
required String password,
|
||||||
|
required int height,
|
||||||
|
required String mnemonic}) {
|
||||||
|
return MoneroRestoreWalletFromSeedCredentials(
|
||||||
|
name: name, password: password, height: height, mnemonic: mnemonic);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
WalletCredentials createMoneroNewWalletCredentials({
|
||||||
required String name,
|
required String name,
|
||||||
required String language,
|
required String language,
|
||||||
String? password,}) {
|
String? password,
|
||||||
return MoneroNewWalletCredentials(
|
}) {
|
||||||
name: name,
|
return MoneroNewWalletCredentials(name: name, password: password, language: language);
|
||||||
password: password,
|
}
|
||||||
language: language);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, String> getKeys(Object wallet) {
|
Map<String, String> getKeys(Object wallet) {
|
||||||
final moneroWallet = wallet as MoneroWallet;
|
final moneroWallet = wallet as MoneroWallet;
|
||||||
final keys = moneroWallet.keys;
|
final keys = moneroWallet.keys;
|
||||||
return <String, String>{
|
return <String, String>{
|
||||||
'privateSpendKey': keys.privateSpendKey,
|
'privateSpendKey': keys.privateSpendKey,
|
||||||
'privateViewKey': keys.privateViewKey,
|
'privateViewKey': keys.privateViewKey,
|
||||||
'publicSpendKey': keys.publicSpendKey,
|
'publicSpendKey': keys.publicSpendKey,
|
||||||
'publicViewKey': keys.publicViewKey};
|
'publicViewKey': keys.publicViewKey
|
||||||
}
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Object createMoneroTransactionCreationCredentials({
|
Object createMoneroTransactionCreationCredentials(
|
||||||
required List<Output> outputs,
|
{required List<Output> outputs, required TransactionPriority priority}) {
|
||||||
required TransactionPriority priority}) {
|
return MoneroTransactionCreationCredentials(
|
||||||
return MoneroTransactionCreationCredentials(
|
outputs: outputs
|
||||||
outputs: outputs.map((out) => OutputInfo(
|
.map((out) => OutputInfo(
|
||||||
fiatAmount: out.fiatAmount,
|
fiatAmount: out.fiatAmount,
|
||||||
cryptoAmount: out.cryptoAmount,
|
cryptoAmount: out.cryptoAmount,
|
||||||
address: out.address,
|
address: out.address,
|
||||||
note: out.note,
|
note: out.note,
|
||||||
sendAll: out.sendAll,
|
sendAll: out.sendAll,
|
||||||
extractedAddress: out.extractedAddress,
|
extractedAddress: out.extractedAddress,
|
||||||
isParsedAddress: out.isParsedAddress,
|
isParsedAddress: out.isParsedAddress,
|
||||||
formattedCryptoAmount: out.formattedCryptoAmount))
|
formattedCryptoAmount: out.formattedCryptoAmount))
|
||||||
.toList(),
|
.toList(),
|
||||||
priority: priority as MoneroTransactionPriority);
|
priority: priority as MoneroTransactionPriority);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Object createMoneroTransactionCreationCredentialsRaw({
|
Object createMoneroTransactionCreationCredentialsRaw(
|
||||||
required List<OutputInfo> outputs,
|
{required List<OutputInfo> outputs, required TransactionPriority priority}) {
|
||||||
required TransactionPriority priority}) {
|
return MoneroTransactionCreationCredentials(
|
||||||
return MoneroTransactionCreationCredentials(
|
outputs: outputs, priority: priority as MoneroTransactionPriority);
|
||||||
outputs: outputs,
|
}
|
||||||
priority: priority as MoneroTransactionPriority);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String formatterMoneroAmountToString({required int amount}) {
|
String formatterMoneroAmountToString({required int amount}) {
|
||||||
return moneroAmountToString(amount: amount);
|
return moneroAmountToString(amount: amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
double formatterMoneroAmountToDouble({required int amount}) {
|
double formatterMoneroAmountToDouble({required int amount}) {
|
||||||
return moneroAmountToDouble(amount: amount);
|
return moneroAmountToDouble(amount: amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int formatterMoneroParseAmount({required String amount}) {
|
int formatterMoneroParseAmount({required String amount}) {
|
||||||
return moneroParseAmount(amount: amount);
|
return moneroParseAmount(amount: amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Account getCurrentAccount(Object wallet) {
|
Account getCurrentAccount(Object wallet) {
|
||||||
final moneroWallet = wallet as MoneroWallet;
|
final moneroWallet = wallet as MoneroWallet;
|
||||||
final acc = moneroWallet.walletAddresses.account;
|
final acc = moneroWallet.walletAddresses.account;
|
||||||
return Account(id: acc!.id, label: acc.label, balance: acc.balance);
|
return Account(id: acc!.id, label: acc.label, balance: acc.balance);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void setCurrentAccount(Object wallet, int id, String label, String? balance) {
|
void setCurrentAccount(Object wallet, int id, String label, String? balance) {
|
||||||
final moneroWallet = wallet as MoneroWallet;
|
final moneroWallet = wallet as MoneroWallet;
|
||||||
moneroWallet.walletAddresses.account = monero_account.Account(id: id, label: label, balance: balance);
|
moneroWallet.walletAddresses.account =
|
||||||
}
|
monero_account.Account(id: id, label: label, balance: balance);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onStartup() {
|
void onStartup() {
|
||||||
monero_wallet_api.onStartup();
|
monero_wallet_api.onStartup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int getTransactionInfoAccountId(TransactionInfo tx) {
|
int getTransactionInfoAccountId(TransactionInfo tx) {
|
||||||
final moneroTransactionInfo = tx as MoneroTransactionInfo;
|
final moneroTransactionInfo = tx as MoneroTransactionInfo;
|
||||||
return moneroTransactionInfo.accountIndex;
|
return moneroTransactionInfo.accountIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletService createMoneroWalletService(Box<WalletInfo> walletInfoSource) {
|
WalletService createMoneroWalletService(
|
||||||
return MoneroWalletService(walletInfoSource);
|
Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
|
||||||
}
|
return MoneroWalletService(walletInfoSource, unspentCoinSource);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String getTransactionAddress(Object wallet, int accountIndex, int addressIndex) {
|
String getTransactionAddress(Object wallet, int accountIndex, int addressIndex) {
|
||||||
final moneroWallet = wallet as MoneroWallet;
|
final moneroWallet = wallet as MoneroWallet;
|
||||||
return moneroWallet.getTransactionAddress(accountIndex, addressIndex);
|
return moneroWallet.getTransactionAddress(accountIndex, addressIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String getSubaddressLabel(Object wallet, int accountIndex, int addressIndex) {
|
String getSubaddressLabel(Object wallet, int accountIndex, int addressIndex) {
|
||||||
final moneroWallet = wallet as MoneroWallet;
|
final moneroWallet = wallet as MoneroWallet;
|
||||||
return moneroWallet.getSubaddressLabel(accountIndex, addressIndex);
|
return moneroWallet.getSubaddressLabel(accountIndex, addressIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, String> pendingTransactionInfo(Object transaction) {
|
Map<String, String> pendingTransactionInfo(Object transaction) {
|
||||||
final ptx = transaction as PendingMoneroTransaction;
|
final ptx = transaction as PendingMoneroTransaction;
|
||||||
return {'id': ptx.id, 'hex': ptx.hex, 'key': ptx.txKey};
|
return {'id': ptx.id, 'hex': ptx.hex, 'key': ptx.txKey};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Unspent> getUnspents(Object wallet) {
|
||||||
|
final moneroWallet = wallet as MoneroWallet;
|
||||||
|
return moneroWallet.unspentCoins
|
||||||
|
.map((MoneroUnspent moneroUnspent) => Unspent(moneroUnspent.address, moneroUnspent.hash,
|
||||||
|
moneroUnspent.value, 0, moneroUnspent.keyImage))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void updateUnspents(Object wallet) async {
|
||||||
|
final moneroWallet = wallet as MoneroWallet;
|
||||||
|
await moneroWallet.updateUnspent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ class SendPage extends BasePage {
|
||||||
AppBarStyle get appBarStyle => AppBarStyle.transparent;
|
AppBarStyle get appBarStyle => AppBarStyle.transparent;
|
||||||
|
|
||||||
double _sendCardHeight(BuildContext context) {
|
double _sendCardHeight(BuildContext context) {
|
||||||
final double initialHeight = sendViewModel.isElectrumWallet ? 490 : 465;
|
final double initialHeight = sendViewModel.hasCoinControl ? 490 : 465;
|
||||||
|
|
||||||
if (!ResponsiveLayoutUtil.instance.isMobile) {
|
if (!ResponsiveLayoutUtil.instance.isMobile) {
|
||||||
return initialHeight - 66;
|
return initialHeight - 66;
|
||||||
|
|
|
@ -496,7 +496,7 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (sendViewModel.isElectrumWallet)
|
if (sendViewModel.hasCoinControl)
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(top: 6),
|
padding: EdgeInsets.only(top: 6),
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
|
|
|
@ -21,7 +21,6 @@ class TransactionDetailsPage extends BasePage {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
// FIX-ME: Added `context` it was not used here before, maby bug ?
|
|
||||||
return SectionStandardList(
|
return SectionStandardList(
|
||||||
sectionCount: 1,
|
sectionCount: 1,
|
||||||
itemCounter: (int _) => transactionDetailsViewModel.items.length,
|
itemCounter: (int _) => transactionDetailsViewModel.items.length,
|
||||||
|
|
|
@ -6,11 +6,12 @@ import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
|
||||||
class TextFieldListRow extends StatelessWidget {
|
class TextFieldListRow extends StatelessWidget {
|
||||||
TextFieldListRow(
|
TextFieldListRow(
|
||||||
{required this.title,
|
{required this.title,
|
||||||
required this.value,
|
required this.value,
|
||||||
this.titleFontSize = 14,
|
this.titleFontSize = 14,
|
||||||
this.valueFontSize = 16,
|
this.valueFontSize = 16,
|
||||||
this.onSubmitted})
|
this.onSubmitted,
|
||||||
: _textController = TextEditingController() {
|
this.onTapOutside})
|
||||||
|
: _textController = TextEditingController() {
|
||||||
_textController.text = value;
|
_textController.text = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +20,7 @@ class TextFieldListRow extends StatelessWidget {
|
||||||
final double titleFontSize;
|
final double titleFontSize;
|
||||||
final double valueFontSize;
|
final double valueFontSize;
|
||||||
final Function(String value)? onSubmitted;
|
final Function(String value)? onSubmitted;
|
||||||
|
final Function(String value)? onTapOutside;
|
||||||
final TextEditingController _textController;
|
final TextEditingController _textController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -58,6 +60,7 @@ class TextFieldListRow extends StatelessWidget {
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor),
|
color: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor),
|
||||||
border: InputBorder.none),
|
border: InputBorder.none),
|
||||||
|
onTapOutside: (_) => onTapOutside?.call(_textController.text),
|
||||||
onSubmitted: (value) => onSubmitted?.call(value),
|
onSubmitted: (value) => onSubmitted?.call(value),
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
|
|
|
@ -24,7 +24,6 @@ class UnspentCoinsDetailsPage extends BasePage {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
// FIX-ME: Added `context` it was not used here before, maby bug ?
|
|
||||||
return SectionStandardList(
|
return SectionStandardList(
|
||||||
sectionCount: 1,
|
sectionCount: 1,
|
||||||
itemCounter: (int _) => unspentCoinsDetailsViewModel.items.length,
|
itemCounter: (int _) => unspentCoinsDetailsViewModel.items.length,
|
||||||
|
@ -45,6 +44,7 @@ class UnspentCoinsDetailsPage extends BasePage {
|
||||||
return TextFieldListRow(
|
return TextFieldListRow(
|
||||||
title: item.title,
|
title: item.title,
|
||||||
value: item.value,
|
value: item.value,
|
||||||
|
onTapOutside: item.onSubmitted,
|
||||||
onSubmitted: item.onSubmitted,
|
onSubmitted: item.onSubmitted,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,7 @@ class UnspentCoinsListItem extends StatelessWidget {
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
AutoSizeText(
|
AutoSizeText(
|
||||||
address,
|
'${address.substring(0, 5)}...${address.substring(address.length-5)}', // ToDo: Maybe use address label
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: addressColor,
|
color: addressColor,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
|
|
|
@ -172,6 +172,10 @@ abstract class SendViewModelBase with Store {
|
||||||
.where((template) => _isEqualCurrency(template.cryptoCurrency))
|
.where((template) => _isEqualCurrency(template.cryptoCurrency))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
|
@computed
|
||||||
|
bool get hasCoinControl =>
|
||||||
|
_wallet.type == WalletType.bitcoin || _wallet.type == WalletType.litecoin || _wallet.type == WalletType.monero;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
bool get isElectrumWallet =>
|
bool get isElectrumWallet =>
|
||||||
_wallet.type == WalletType.bitcoin || _wallet.type == WalletType.litecoin;
|
_wallet.type == WalletType.bitcoin || _wallet.type == WalletType.litecoin;
|
||||||
|
@ -206,12 +210,12 @@ abstract class SendViewModelBase with Store {
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
List<ContactRecord> get contactsToShow => contactListViewModel.contacts
|
List<ContactRecord> get contactsToShow => contactListViewModel.contacts
|
||||||
.where((element) => selectedCryptoCurrency == null || element.type == selectedCryptoCurrency)
|
.where((element) => element.type == selectedCryptoCurrency)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
List<WalletContact> get walletContactsToShow => contactListViewModel.walletContacts
|
List<WalletContact> get walletContactsToShow => contactListViewModel.walletContacts
|
||||||
.where((element) => selectedCryptoCurrency == null || element.type == selectedCryptoCurrency)
|
.where((element) => element.type == selectedCryptoCurrency)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
|
|
@ -23,6 +23,7 @@ abstract class UnspentCoinsDetailsViewModelBase with Store {
|
||||||
note = unspentCoinsItem.note {
|
note = unspentCoinsItem.note {
|
||||||
items = [
|
items = [
|
||||||
StandartListItem(title: S.current.transaction_details_amount, value: unspentCoinsItem.amount),
|
StandartListItem(title: S.current.transaction_details_amount, value: unspentCoinsItem.amount),
|
||||||
|
StandartListItem(title: S.current.transaction_details_transaction_id, value: unspentCoinsItem.hash),
|
||||||
StandartListItem(title: S.current.widgets_address, value: unspentCoinsItem.address),
|
StandartListItem(title: S.current.widgets_address, value: unspentCoinsItem.address),
|
||||||
TextFieldListItem(
|
TextFieldListItem(
|
||||||
title: S.current.note_tap_to_change,
|
title: S.current.note_tap_to_change,
|
||||||
|
@ -42,19 +43,22 @@ abstract class UnspentCoinsDetailsViewModelBase with Store {
|
||||||
unspentCoinsItem.isSending = !value;
|
unspentCoinsItem.isSending = !value;
|
||||||
}
|
}
|
||||||
await unspentCoinsListViewModel.saveUnspentCoinInfo(unspentCoinsItem);
|
await unspentCoinsListViewModel.saveUnspentCoinInfo(unspentCoinsItem);
|
||||||
}),
|
|
||||||
BlockExplorerListItem(
|
|
||||||
title: S.current.view_in_block_explorer,
|
|
||||||
value: _explorerDescription(unspentCoinsListViewModel.wallet.type),
|
|
||||||
onTap: () {
|
|
||||||
try {
|
|
||||||
final url = Uri.parse(
|
|
||||||
_explorerUrl(unspentCoinsListViewModel.wallet.type, unspentCoinsItem.hash));
|
|
||||||
return launchUrl(url);
|
|
||||||
} catch (e) {}
|
|
||||||
|
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if ([WalletType.bitcoin, WalletType.litecoin].contains(unspentCoinsListViewModel.wallet.type)) {
|
||||||
|
items.add(BlockExplorerListItem(
|
||||||
|
title: S.current.view_in_block_explorer,
|
||||||
|
value: _explorerDescription(unspentCoinsListViewModel.wallet.type),
|
||||||
|
onTap: () {
|
||||||
|
try {
|
||||||
|
final url = Uri.parse(
|
||||||
|
_explorerUrl(unspentCoinsListViewModel.wallet.type, unspentCoinsItem.hash));
|
||||||
|
return launchUrl(url);
|
||||||
|
} catch (e) {}
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _explorerUrl(WalletType type, String txId) {
|
String _explorerUrl(WalletType type, String txId) {
|
||||||
|
|
|
@ -13,7 +13,9 @@ abstract class UnspentCoinsItemBase with Store {
|
||||||
required this.note,
|
required this.note,
|
||||||
required this.isSending,
|
required this.isSending,
|
||||||
required this.amountRaw,
|
required this.amountRaw,
|
||||||
required this.vout});
|
required this.vout,
|
||||||
|
required this.keyImage
|
||||||
|
});
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
String address;
|
String address;
|
||||||
|
@ -38,4 +40,7 @@ abstract class UnspentCoinsItemBase with Store {
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
int vout;
|
int vout;
|
||||||
}
|
|
||||||
|
@observable
|
||||||
|
String? keyImage;
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
import 'package:cw_core/unspent_coins_info.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cake_wallet/entities/unspent_transaction_output.dart';
|
||||||
|
import 'package:cake_wallet/monero/monero.dart';
|
||||||
import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_item.dart';
|
import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_item.dart';
|
||||||
|
import 'package:cw_bitcoin/bitcoin_wallet.dart';
|
||||||
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
import 'package:cw_monero/monero_wallet.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:collection/collection.dart';
|
|
||||||
|
|
||||||
part 'unspent_coins_list_view_model.g.dart';
|
part 'unspent_coins_list_view_model.g.dart';
|
||||||
|
|
||||||
|
@ -14,7 +19,7 @@ abstract class UnspentCoinsListViewModelBase with Store {
|
||||||
UnspentCoinsListViewModelBase(
|
UnspentCoinsListViewModelBase(
|
||||||
{required this.wallet, required Box<UnspentCoinsInfo> unspentCoinsInfo})
|
{required this.wallet, required Box<UnspentCoinsInfo> unspentCoinsInfo})
|
||||||
: _unspentCoinsInfo = unspentCoinsInfo {
|
: _unspentCoinsInfo = unspentCoinsInfo {
|
||||||
bitcoin!.updateUnspents(wallet);
|
_updateUnspents();
|
||||||
}
|
}
|
||||||
|
|
||||||
WalletBase wallet;
|
WalletBase wallet;
|
||||||
|
@ -22,11 +27,10 @@ abstract class UnspentCoinsListViewModelBase with Store {
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
ObservableList<UnspentCoinsItem> get items =>
|
ObservableList<UnspentCoinsItem> get items =>
|
||||||
ObservableList.of(bitcoin!.getUnspents(wallet).map((elem) {
|
ObservableList.of(_getUnspents().map((elem) {
|
||||||
final amount = bitcoin!.formatterBitcoinAmountToString(amount: elem.value) +
|
final amount = formatAmountToString(elem.value) + ' ${wallet.currency.title}';
|
||||||
' ${wallet.currency.title}';
|
|
||||||
|
|
||||||
final info = getUnspentCoinInfo(elem.hash, elem.address, elem.value, elem.vout);
|
final info = getUnspentCoinInfo(elem.hash, elem.address, elem.value, elem.vout, elem.keyImage);
|
||||||
|
|
||||||
return UnspentCoinsItem(
|
return UnspentCoinsItem(
|
||||||
address: elem.address,
|
address: elem.address,
|
||||||
|
@ -36,12 +40,14 @@ abstract class UnspentCoinsListViewModelBase with Store {
|
||||||
note: info?.note ?? '',
|
note: info?.note ?? '',
|
||||||
isSending: info?.isSending ?? true,
|
isSending: info?.isSending ?? true,
|
||||||
amountRaw: elem.value,
|
amountRaw: elem.value,
|
||||||
vout: elem.vout);
|
vout: elem.vout,
|
||||||
|
keyImage: elem.keyImage
|
||||||
|
);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
Future<void> saveUnspentCoinInfo(UnspentCoinsItem item) async {
|
Future<void> saveUnspentCoinInfo(UnspentCoinsItem item) async {
|
||||||
try {
|
try {
|
||||||
final info = getUnspentCoinInfo(item.hash, item.address, item.amountRaw, item.vout);
|
final info = getUnspentCoinInfo(item.hash, item.address, item.amountRaw, item.vout, item.keyImage);
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
final newInfo = UnspentCoinsInfo(
|
final newInfo = UnspentCoinsInfo(
|
||||||
walletId: wallet.id,
|
walletId: wallet.id,
|
||||||
|
@ -51,10 +57,12 @@ abstract class UnspentCoinsListViewModelBase with Store {
|
||||||
vout: item.vout,
|
vout: item.vout,
|
||||||
isFrozen: item.isFrozen,
|
isFrozen: item.isFrozen,
|
||||||
isSending: item.isSending,
|
isSending: item.isSending,
|
||||||
noteRaw: item.note);
|
noteRaw: item.note,
|
||||||
|
keyImage: item.keyImage
|
||||||
|
);
|
||||||
|
|
||||||
await _unspentCoinsInfo.add(newInfo);
|
await _unspentCoinsInfo.add(newInfo);
|
||||||
bitcoin!.updateUnspents(wallet);
|
_updateUnspents();
|
||||||
wallet.updateBalance();
|
wallet.updateBalance();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -63,19 +71,45 @@ abstract class UnspentCoinsListViewModelBase with Store {
|
||||||
info.note = item.note;
|
info.note = item.note;
|
||||||
|
|
||||||
await info.save();
|
await info.save();
|
||||||
bitcoin!.updateUnspents(wallet);
|
_updateUnspents();
|
||||||
wallet.updateBalance();
|
wallet.updateBalance();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e.toString());
|
print(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UnspentCoinsInfo? getUnspentCoinInfo(String hash, String address, int value, int vout) {
|
UnspentCoinsInfo? getUnspentCoinInfo(String hash, String address, int value, int vout, String? keyImage) {
|
||||||
return _unspentCoinsInfo.values.firstWhereOrNull((element) =>
|
return _unspentCoinsInfo.values.firstWhereOrNull((element) =>
|
||||||
element.walletId == wallet.id &&
|
element.walletId == wallet.id &&
|
||||||
element.hash == hash &&
|
element.hash == hash &&
|
||||||
element.address == address &&
|
element.address == address &&
|
||||||
element.value == value &&
|
element.value == value &&
|
||||||
element.vout == vout);
|
element.vout == vout &&
|
||||||
|
element.keyImage == keyImage
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String formatAmountToString(int fullBalance) {
|
||||||
|
if (wallet.type == WalletType.monero)
|
||||||
|
return monero!.formatterMoneroAmountToString(amount: fullBalance);
|
||||||
|
if ([WalletType.bitcoin, WalletType.litecoin].contains(wallet.type))
|
||||||
|
return bitcoin!.formatterBitcoinAmountToString(amount: fullBalance);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void _updateUnspents() {
|
||||||
|
if (wallet.type == WalletType.monero)
|
||||||
|
return monero!.updateUnspents(wallet);
|
||||||
|
if ([WalletType.bitcoin, WalletType.litecoin].contains(wallet.type))
|
||||||
|
return bitcoin!.updateUnspents(wallet);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Unspent> _getUnspents() {
|
||||||
|
if (wallet.type == WalletType.monero)
|
||||||
|
return monero!.getUnspents(wallet);
|
||||||
|
if ([WalletType.bitcoin, WalletType.litecoin].contains(wallet.type))
|
||||||
|
return bitcoin!.getUnspents(wallet);
|
||||||
|
return List.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,10 @@ dev_dependencies:
|
||||||
# check flutter_launcher_icons for usage
|
# check flutter_launcher_icons for usage
|
||||||
pedantic: ^1.8.0
|
pedantic: ^1.8.0
|
||||||
# replace https://github.com/dart-lang/lints#migrating-from-packagepedantic
|
# replace https://github.com/dart-lang/lints#migrating-from-packagepedantic
|
||||||
# translator: ^0.1.7
|
translator:
|
||||||
|
git:
|
||||||
|
url: https://github.com/cake-tech/google-translator.git
|
||||||
|
version: 1.0.0
|
||||||
|
|
||||||
flutter_icons:
|
flutter_icons:
|
||||||
image_path: "assets/images/app_logo.png"
|
image_path: "assets/images/app_logo.png"
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
"please_make_selection": "Bitte treffen Sie unten eine Auswahl zum Erstellen oder Wiederherstellen Ihrer Wallet.",
|
"please_make_selection": "Bitte treffen Sie unten eine Auswahl zum Erstellen oder Wiederherstellen Ihrer Wallet.",
|
||||||
"create_new": "Neue Wallet erstellen",
|
"create_new": "Neue Wallet erstellen",
|
||||||
"restore_wallet": "Wallet wiederherstellen",
|
"restore_wallet": "Wallet wiederherstellen",
|
||||||
"monero_com": "Monero.com by Cake Wallet",
|
"monero_com": "Monero.com von Cake Wallet",
|
||||||
"monero_com_wallet_text": "Awesome wallet for Monero",
|
"monero_com_wallet_text": "Eine großartige Wallet für Monero",
|
||||||
"haven_app": "Haven by Cake Wallet",
|
"haven_app": "Haven von Cake Wallet",
|
||||||
"haven_app_wallet_text": "Awesome wallet for Haven",
|
"haven_app_wallet_text": "Eine großartige Wallet für Haven",
|
||||||
"accounts": "Konten",
|
"accounts": "Konten",
|
||||||
"edit": "Bearbeiten",
|
"edit": "Bearbeiten",
|
||||||
"account": "Konto",
|
"account": "Konto",
|
||||||
|
@ -152,10 +152,10 @@
|
||||||
"restore_wallet_restore_description": "Beschreibung zur Wallet-Wiederherstellung",
|
"restore_wallet_restore_description": "Beschreibung zur Wallet-Wiederherstellung",
|
||||||
"restore_new_seed": "Neuer Seed",
|
"restore_new_seed": "Neuer Seed",
|
||||||
"restore_active_seed": "Aktiver Seed",
|
"restore_active_seed": "Aktiver Seed",
|
||||||
"restore_bitcoin_description_from_seed": "Stellen Sie Ihre Brieftasche aus dem 24-Wort-Kombinationscode wieder her",
|
"restore_bitcoin_description_from_seed": "Stellen Sie Ihre Wallet aus dem 24-Wort-Kombinationscode wieder her",
|
||||||
"restore_bitcoin_description_from_keys": "Stellen Sie Ihre Brieftasche aus der generierten WIF-Zeichenfolge aus Ihren privaten Schlüsseln wieder her",
|
"restore_bitcoin_description_from_keys": "Stellen Sie Ihre Wallet aus der generierten WIF-Zeichenfolge aus Ihren privaten Schlüsseln wieder her",
|
||||||
"restore_bitcoin_title_from_keys": "Aus WIF wiederherstellen",
|
"restore_bitcoin_title_from_keys": "Aus WIF wiederherstellen",
|
||||||
"restore_from_date_or_blockheight": "Bitte geben Sie ein Datum ein, das einige Tage vor dem Erstellen dieser Brieftasche liegt. Oder wenn Sie die Blockhöhe kennen, geben Sie stattdessen diese ein",
|
"restore_from_date_or_blockheight": "Bitte geben Sie ein Datum ein, das einige Tage vor dem Erstellen dieser Wallet liegt. Oder wenn Sie die Blockhöhe kennen, geben Sie stattdessen diese ein",
|
||||||
"seed_reminder": "Bitte notieren Sie diese für den Fall, dass Sie Ihr Telefon verlieren oder es kaputtgeht",
|
"seed_reminder": "Bitte notieren Sie diese für den Fall, dass Sie Ihr Telefon verlieren oder es kaputtgeht",
|
||||||
"seed_title": "Seed",
|
"seed_title": "Seed",
|
||||||
"seed_share": "Seed teilen",
|
"seed_share": "Seed teilen",
|
||||||
|
@ -403,7 +403,7 @@
|
||||||
"buy_bitcoin": "Bitcoin kaufen",
|
"buy_bitcoin": "Bitcoin kaufen",
|
||||||
"buy_with": "Kaufen mit",
|
"buy_with": "Kaufen mit",
|
||||||
"moonpay_alert_text": "Der Wert des Betrags muss größer oder gleich ${minAmount} ${fiatCurrency} sein",
|
"moonpay_alert_text": "Der Wert des Betrags muss größer oder gleich ${minAmount} ${fiatCurrency} sein",
|
||||||
"outdated_electrum_wallet_receive_warning": "Wenn diese Brieftasche einen 12-Wort-Seed hat und in Cake erstellt wurde, zahlen Sie KEINE Bitcoins in diese Brieftasche ein. Alle auf diese Wallet übertragenen BTC können verloren gehen. Erstellen Sie eine neue 24-Wort-Wallet (tippen Sie auf das Menü oben rechts, wählen Sie Wallets, wählen Sie Neue Wallet erstellen und dann Bitcoin) und verschieben Sie Ihre BTC SOFORT dorthin. Neue (24-Wort-)BTC-Wallets von Cake sind sicher",
|
"outdated_electrum_wallet_receive_warning": "Wenn diese Wallet einen 12-Wort-Seed hat und in Cake erstellt wurde, zahlen Sie KEINE Bitcoins in diese Wallet ein. Alle auf diese Wallet übertragenen BTC können verloren gehen. Erstellen Sie eine neue 24-Wort-Wallet (tippen Sie auf das Menü oben rechts, wählen Sie Wallets, wählen Sie Neue Wallet erstellen und dann Bitcoin) und verschieben Sie Ihre BTC SOFORT dorthin. Neue (24-Wort-)BTC-Wallets von Cake sind sicher",
|
||||||
"do_not_show_me": "Zeig mir das nicht noch einmal",
|
"do_not_show_me": "Zeig mir das nicht noch einmal",
|
||||||
"unspent_coins_title": "Nicht ausgegebene Münzen",
|
"unspent_coins_title": "Nicht ausgegebene Münzen",
|
||||||
"unspent_coins_details_title": "Details zu nicht ausgegebenen Münzen",
|
"unspent_coins_details_title": "Details zu nicht ausgegebenen Münzen",
|
||||||
|
@ -596,10 +596,10 @@
|
||||||
"sweeping_wallet_alert": "Das sollte nicht lange dauern. VERLASSEN SIE DIESEN BILDSCHIRM NICHT, ANDERNFALLS KÖNNEN DIE SWEPT-GELDER VERLOREN GEHEN",
|
"sweeping_wallet_alert": "Das sollte nicht lange dauern. VERLASSEN SIE DIESEN BILDSCHIRM NICHT, ANDERNFALLS KÖNNEN DIE SWEPT-GELDER VERLOREN GEHEN",
|
||||||
"decimal_places_error": "Zu viele Nachkommastellen",
|
"decimal_places_error": "Zu viele Nachkommastellen",
|
||||||
"edit_node": "Knoten bearbeiten",
|
"edit_node": "Knoten bearbeiten",
|
||||||
"frozen_balance": "Gefrorenes Gleichgewicht",
|
"frozen_balance": "Gefrorenes Guthaben",
|
||||||
"invoice_details": "Rechnungs-Details",
|
"invoice_details": "Rechnungs-Details",
|
||||||
"donation_link_details": "Details zum Spendenlink",
|
"donation_link_details": "Details zum Spendenlink",
|
||||||
"anonpay_description": "Generieren Sie ${type}. Der Empfänger kann ${method} mit jeder unterstützten Kryptowährung verwenden, und Sie erhalten Geld in dieser Brieftasche.",
|
"anonpay_description": "Generieren Sie ${type}. Der Empfänger kann ${method} mit jeder unterstützten Kryptowährung verwenden, und Sie erhalten Geld in dieser Wallet.",
|
||||||
"create_invoice": "Rechnung erstellen",
|
"create_invoice": "Rechnung erstellen",
|
||||||
"create_donation_link": "Spendenlink erstellen",
|
"create_donation_link": "Spendenlink erstellen",
|
||||||
"optional_email_hint": "Optionale Benachrichtigungs-E-Mail für den Zahlungsempfänger",
|
"optional_email_hint": "Optionale Benachrichtigungs-E-Mail für den Zahlungsempfänger",
|
||||||
|
@ -615,22 +615,22 @@
|
||||||
"prevent_screenshots": "Verhindern Sie Screenshots und Bildschirmaufzeichnungen",
|
"prevent_screenshots": "Verhindern Sie Screenshots und Bildschirmaufzeichnungen",
|
||||||
"profile": "Profil",
|
"profile": "Profil",
|
||||||
"close": "Schließen",
|
"close": "Schließen",
|
||||||
"modify_2fa": "Kuchen 2FA ändern",
|
"modify_2fa": "Cake 2FA ändern",
|
||||||
"disable_cake_2fa": "Kuchen 2FA deaktivieren",
|
"disable_cake_2fa": "Cake 2FA deaktivieren",
|
||||||
"question_to_disable_2fa": "Sind Sie sicher, dass Sie Cake 2FA deaktivieren möchten? Für den Zugriff auf die Brieftasche und bestimmte Funktionen wird kein 2FA-Code mehr benötigt.",
|
"question_to_disable_2fa": "Sind Sie sicher, dass Sie Cake 2FA deaktivieren möchten? Für den Zugriff auf die Wallet und bestimmte Funktionen wird kein 2FA-Code mehr benötigt.",
|
||||||
"disable": "Deaktivieren",
|
"disable": "Deaktivieren",
|
||||||
"setup_2fa": "Setup-Kuchen 2FA",
|
"setup_2fa": "Setup-Cake 2FA",
|
||||||
"verify_with_2fa": "Verifizieren Sie mit Cake 2FA",
|
"verify_with_2fa": "Verifizieren Sie mit Cake 2FA",
|
||||||
"totp_code": "TOTP-Code",
|
"totp_code": "TOTP-Code",
|
||||||
"please_fill_totp": "Bitte geben Sie den 8-stelligen Code ein, der auf Ihrem anderen Gerät vorhanden ist",
|
"please_fill_totp": "Bitte geben Sie den 8-stelligen Code ein, der auf Ihrem anderen Gerät vorhanden ist",
|
||||||
"totp_2fa_success": "Erfolg! Cake 2FA für dieses Wallet aktiviert. Denken Sie daran, Ihren mnemonischen Seed zu speichern, falls Sie den Zugriff auf die Brieftasche verlieren.",
|
"totp_2fa_success": "Erfolg! Cake 2FA für dieses Wallet aktiviert. Denken Sie daran, Ihren mnemonischen Seed zu speichern, falls Sie den Zugriff auf die Wallet verlieren.",
|
||||||
"totp_verification_success": "Verifizierung erfolgreich!",
|
"totp_verification_success": "Verifizierung erfolgreich!",
|
||||||
"totp_2fa_failure": "Falscher Code. Bitte versuchen Sie es mit einem anderen Code oder generieren Sie einen neuen geheimen Schlüssel. Verwenden Sie eine kompatible 2FA-App, die 8-stellige Codes und SHA512 unterstützt.",
|
"totp_2fa_failure": "Falscher Code. Bitte versuchen Sie es mit einem anderen Code oder generieren Sie einen neuen geheimen Schlüssel. Verwenden Sie eine kompatible 2FA-App, die 8-stellige Codes und SHA512 unterstützt.",
|
||||||
"enter_totp_code": "Bitte geben Sie den TOTP-Code ein.",
|
"enter_totp_code": "Bitte geben Sie den TOTP-Code ein.",
|
||||||
"add_secret_code": "Fügen Sie diesen Geheimcode einem anderen Gerät hinzu",
|
"add_secret_code": "Fügen Sie diesen Geheimcode einem anderen Gerät hinzu",
|
||||||
"totp_secret_code": "TOTP-Geheimcode",
|
"totp_secret_code": "TOTP-Geheimcode",
|
||||||
"important_note": "Wichtiger Hinweis",
|
"important_note": "Wichtiger Hinweis",
|
||||||
"setup_2fa_text": "Cake 2FA ist NICHT so sicher wie eine Kühllagerung. 2FA schützt vor grundlegenden Arten von Angriffen, z. B. wenn Ihr Freund Ihren Fingerabdruck bereitstellt, während Sie schlafen.\n\n Cake 2FA schützt NICHT vor einem kompromittierten Gerät durch einen raffinierten Angreifer.\n\n Wenn Sie den Zugriff auf Ihre 2FA-Codes verlieren , VERLIEREN SIE DEN ZUGANG ZU DIESEM WALLET. Sie müssen Ihre Brieftasche aus mnemonic Seed wiederherstellen. SIE MÜSSEN DESHALB IHRE MNEMONISCHEN SEEDS SICHERN! Außerdem kann jemand mit Zugriff auf Ihre mnemonischen Seed(s) Ihr Geld stehlen und Cake 2FA umgehen.\n\n Cake-Supportmitarbeiter können Ihnen nicht helfen, wenn Sie den Zugriff auf Ihre mnemonischen Seed(s) verlieren, da Cake ein Brieftasche ohne Verwahrung.",
|
"setup_2fa_text": "Cake 2FA ist NICHT so sicher wie eine Kühllagerung. 2FA schützt vor grundlegenden Arten von Angriffen, z. B. wenn Ihr Freund Ihren Fingerabdruck bereitstellt, während Sie schlafen.\n\n Cake 2FA schützt NICHT vor einem kompromittierten Gerät durch einen raffinierten Angreifer.\n\n Wenn Sie den Zugriff auf Ihre 2FA-Codes verlieren , VERLIEREN SIE DEN ZUGANG ZU DIESEM WALLET. Sie müssen Ihre Wallet aus mnemonic Seed wiederherstellen. SIE MÜSSEN DESHALB IHRE MNEMONISCHEN SEEDS SICHERN! Außerdem kann jemand mit Zugriff auf Ihre mnemonischen Seed(s) Ihr Geld stehlen und Cake 2FA umgehen.\n\n Cake-Supportmitarbeiter können Ihnen nicht helfen, wenn Sie den Zugriff auf Ihre mnemonischen Seed(s) verlieren, da Cake Wallet eine Wallet ohne treuhänderische Verwahrung ist.",
|
||||||
"setup_totp_recommended": "TOTP einrichten (empfohlen)",
|
"setup_totp_recommended": "TOTP einrichten (empfohlen)",
|
||||||
"disable_buy": "Kaufaktion deaktivieren",
|
"disable_buy": "Kaufaktion deaktivieren",
|
||||||
"disable_sell": "Verkaufsaktion deaktivieren",
|
"disable_sell": "Verkaufsaktion deaktivieren",
|
||||||
|
@ -640,7 +640,7 @@
|
||||||
"high_contrast_theme": "Kontrastreiches Thema",
|
"high_contrast_theme": "Kontrastreiches Thema",
|
||||||
"matrix_green_dark_theme": "Matrix Green Dark Theme",
|
"matrix_green_dark_theme": "Matrix Green Dark Theme",
|
||||||
"monero_light_theme": "Monero Light-Thema",
|
"monero_light_theme": "Monero Light-Thema",
|
||||||
"cake_2fa_preset": "Kuchen 2FA-Voreinstellung",
|
"cake_2fa_preset" : "Cake 2FA-Voreinstellung",
|
||||||
"narrow": "Eng",
|
"narrow": "Eng",
|
||||||
"normal": "Normal",
|
"normal": "Normal",
|
||||||
"aggressive": "Übereifrig",
|
"aggressive": "Übereifrig",
|
||||||
|
|
1
scripts/docker/.gitignore
vendored
Normal file
1
scripts/docker/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
output/
|
26
scripts/docker/Dockerfile
Normal file
26
scripts/docker/Dockerfile
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
FROM ubuntu:20.04
|
||||||
|
LABEL authors="konsti"
|
||||||
|
|
||||||
|
ENV MONERO_BRANCH=release-v0.18.2.2-android
|
||||||
|
RUN apt-get update && \
|
||||||
|
echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections && \
|
||||||
|
apt-get install -y dialog apt-utils curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake clang
|
||||||
|
|
||||||
|
RUN mkdir /opt/android/
|
||||||
|
|
||||||
|
COPY . /opt/android/cakewallet/
|
||||||
|
|
||||||
|
WORKDIR /opt/android/cakewallet/
|
||||||
|
|
||||||
|
|
||||||
|
RUN ./install_ndk.sh
|
||||||
|
|
||||||
|
RUN ./build_iconv.sh
|
||||||
|
RUN ./build_boost.sh
|
||||||
|
RUN ./build_openssl.sh
|
||||||
|
RUN ./build_sodium.sh
|
||||||
|
RUN ./build_unbound.sh
|
||||||
|
RUN ./build_zmq.sh
|
||||||
|
|
||||||
|
|
||||||
|
ENTRYPOINT ["./entrypoint.sh"]
|
1
scripts/docker/build_all.sh
Normal file
1
scripts/docker/build_all.sh
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#!/bin/sh
if [ -z "$APP_ANDROID_TYPE" ]; then
echo "Please set APP_ANDROID_TYPE"
exit 1
fi
DIR=$(dirname "$0")
case $APP_ANDROID_TYPE in
"monero.com") $DIR/build_monero_all.sh ;;
"cakewallet") $DIR/build_monero_all.sh
$DIR/build_haven.sh ;;
"haven") $DIR/build_haven_all.sh ;;
esac
|
16
scripts/docker/build_boost.sh
Normal file
16
scripts/docker/build_boost.sh
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
. ./config.sh
|
||||||
|
BOOST_SRC_DIR=$WORKDIR/boost_1_72_0
|
||||||
|
BOOST_FILENAME=boost_1_72_0.tar.bz2
|
||||||
|
BOOST_VERSION=1.72.0
|
||||||
|
|
||||||
|
for arch in "aarch" "aarch64" "i686" "x86_64"
|
||||||
|
do
|
||||||
|
|
||||||
|
PREFIX=$WORKDIR/prefix_${arch}
|
||||||
|
PATH="${TOOLCHAIN_BASE_DIR}_${arch}/bin:${ORIGINAL_PATH}"
|
||||||
|
./init_boost.sh $arch $PREFIX $BOOST_SRC_DIR $BOOST_FILENAME $BOOST_VERSION
|
||||||
|
./finish_boost.sh $arch $PREFIX $BOOST_SRC_DIR $BOOST_SRC_DIR
|
||||||
|
|
||||||
|
done
|
1
scripts/docker/build_haven.sh
Normal file
1
scripts/docker/build_haven.sh
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#!/bin/sh
. ./config.sh
HAVEN_VERSION=tags/v3.0.7
HAVEN_SRC_DIR=${WORKDIR}/haven
git clone https://github.com/haven-protocol-org/haven-main.git ${HAVEN_SRC_DIR}
git checkout ${HAVEN_VERSION}
cd $HAVEN_SRC_DIR
git submodule init
git submodule update
for arch in "aarch" "aarch64" "i686" "x86_64"
do
FLAGS=""
PREFIX=${WORKDIR}/prefix_${arch}
DEST_LIB_DIR=${PREFIX}/lib/haven
DEST_INCLUDE_DIR=${PREFIX}/include/haven
export CMAKE_INCLUDE_PATH="${PREFIX}/include"
export CMAKE_LIBRARY_PATH="${PREFIX}/lib"
ANDROID_STANDALONE_TOOLCHAIN_PATH="${TOOLCHAIN_BASE_DIR}_${arch}"
PATH="${ANDROID_STANDALONE_TOOLCHAIN_PATH}/bin:${ORIGINAL_PATH}"
mkdir -p $DEST_LIB_DIR
mkdir -p $DEST_INCLUDE_DIR
case $arch in
"aarch" )
CLANG=arm-linux-androideabi-clang
CXXLANG=arm-linux-androideabi-clang++
BUILD_64=OFF
TAG="android-armv7"
ARCH="armv7-a"
ARCH_ABI="armeabi-v7a"
FLAGS="-D CMAKE_ANDROID_ARM_MODE=ON -D NO_AES=true";;
"aarch64" )
CLANG=aarch64-linux-androideabi-clang
CXXLANG=aarch64-linux-androideabi-clang++
BUILD_64=ON
TAG="android-armv8"
ARCH="armv8-a"
ARCH_ABI="arm64-v8a";;
"i686" )
CLANG=i686-linux-androideabi-clang
CXXLANG=i686-linux-androideabi-clang++
BUILD_64=OFF
TAG="android-x86"
ARCH="i686"
ARCH_ABI="x86";;
"x86_64" )
CLANG=x86_64-linux-androideabi-clang
CXXLANG=x86_64-linux-androideabi-clang++
BUILD_64=ON
TAG="android-x86_64"
ARCH="x86-64"
ARCH_ABI="x86_64";;
esac
cd $HAVEN_SRC_DIR
rm -rf ./build/release
mkdir -p ./build/release
cd ./build/release
CC=${CLANG} CXX=${CXXLANG} cmake -D USE_DEVICE_TREZOR=OFF -D BUILD_GUI_DEPS=1 -D BUILD_TESTS=OFF -D ARCH=${ARCH} -D STATIC=ON -D BUILD_64=${BUILD_64} -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D INSTALL_VENDORED_LIBUNBOUND=ON -D BUILD_TAG=${TAG} -D CMAKE_SYSTEM_NAME="Android" -D CMAKE_ANDROID_STANDALONE_TOOLCHAIN="${ANDROID_STANDALONE_TOOLCHAIN_PATH}" -D CMAKE_ANDROID_ARCH_ABI=${ARCH_ABI} $FLAGS ../..
make wallet_api -j$THREADS
find . -path ./lib -prune -o -name '*.a' -exec cp '{}' lib \;
cp -r ./lib/* $DEST_LIB_DIR
cp ../../src/wallet/api/wallet2_api.h $DEST_INCLUDE_DIR
done
|
1
scripts/docker/build_haven_all.sh
Normal file
1
scripts/docker/build_haven_all.sh
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#!/bin/bash
./build_iconv.sh
./build_boost.sh
./build_openssl.sh
./build_sodium.sh
./build_zmq.sh
./build_haven.sh
|
38
scripts/docker/build_iconv.sh
Normal file
38
scripts/docker/build_iconv.sh
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
. ./config.sh
|
||||||
|
export ICONV_FILENAME=libiconv-1.16.tar.gz
|
||||||
|
export ICONV_FILE_PATH=$WORKDIR/$ICONV_FILENAME
|
||||||
|
export ICONV_SRC_DIR=$WORKDIR/libiconv-1.16
|
||||||
|
ICONV_SHA256="e6a1b1b589654277ee790cce3734f07876ac4ccfaecbee8afa0b649cf529cc04"
|
||||||
|
|
||||||
|
curl http://ftp.gnu.org/pub/gnu/libiconv/$ICONV_FILENAME -o $ICONV_FILE_PATH
|
||||||
|
echo $ICONV_SHA256 $ICONV_FILE_PATH | sha256sum -c - || exit 1
|
||||||
|
|
||||||
|
for arch in aarch aarch64 i686 x86_64
|
||||||
|
do
|
||||||
|
|
||||||
|
PREFIX=${WORKDIR}/prefix_${arch}
|
||||||
|
PATH="${TOOLCHAIN_BASE_DIR}_${arch}/bin:${ORIGINAL_PATH}"
|
||||||
|
|
||||||
|
case $arch in
|
||||||
|
"aarch" )
|
||||||
|
CLANG=arm-linux-androideabi-clang
|
||||||
|
CXXLANG=arm-linux-androideabi-clang++
|
||||||
|
HOST="arm-linux-android";;
|
||||||
|
* )
|
||||||
|
CLANG=${arch}-linux-android-clang
|
||||||
|
CXXLANG=${arch}-linux-android-clang++
|
||||||
|
HOST="${arch}-linux-android";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
cd $WORKDIR
|
||||||
|
rm -rf $ICONV_SRC_DIR
|
||||||
|
tar -xzf $ICONV_FILE_PATH -C $WORKDIR
|
||||||
|
cd $ICONV_SRC_DIR
|
||||||
|
CC=${CLANG} CXX=${CXXLANG} ./configure --build=x86_64-linux-gnu --host=${HOST} --prefix=${PREFIX} --disable-rpath
|
||||||
|
make -j$THREADS
|
||||||
|
make install
|
||||||
|
|
||||||
|
done
|
||||||
|
|
69
scripts/docker/build_monero.sh
Normal file
69
scripts/docker/build_monero.sh
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
. ./config.sh
|
||||||
|
|
||||||
|
MONERO_SRC_DIR=${WORKDIR}/monero
|
||||||
|
|
||||||
|
git clone https://github.com/cake-tech/monero.git ${MONERO_SRC_DIR} --branch ${MONERO_BRANCH}
|
||||||
|
cd $MONERO_SRC_DIR
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
|
||||||
|
for arch in "aarch" "aarch64" "i686" "x86_64"
|
||||||
|
do
|
||||||
|
FLAGS=""
|
||||||
|
PREFIX=${WORKDIR}/prefix_${arch}
|
||||||
|
DEST_LIB_DIR=${PREFIX}/lib/monero
|
||||||
|
DEST_INCLUDE_DIR=${PREFIX}/include/monero
|
||||||
|
export CMAKE_INCLUDE_PATH="${PREFIX}/include"
|
||||||
|
export CMAKE_LIBRARY_PATH="${PREFIX}/lib"
|
||||||
|
ANDROID_STANDALONE_TOOLCHAIN_PATH="${TOOLCHAIN_BASE_DIR}_${arch}"
|
||||||
|
PATH="${ANDROID_STANDALONE_TOOLCHAIN_PATH}/bin:${ORIGINAL_PATH}"
|
||||||
|
|
||||||
|
mkdir -p $DEST_LIB_DIR
|
||||||
|
mkdir -p $DEST_INCLUDE_DIR
|
||||||
|
|
||||||
|
case $arch in
|
||||||
|
"aarch" )
|
||||||
|
CLANG=arm-linux-androideabi-clang
|
||||||
|
CXXLANG=arm-linux-androideabi-clang++
|
||||||
|
BUILD_64=OFF
|
||||||
|
TAG="android-armv7"
|
||||||
|
ARCH="armv7-a"
|
||||||
|
ARCH_ABI="armeabi-v7a"
|
||||||
|
FLAGS="-D CMAKE_ANDROID_ARM_MODE=ON -D NO_AES=true";;
|
||||||
|
"aarch64" )
|
||||||
|
CLANG=aarch64-linux-androideabi-clang
|
||||||
|
CXXLANG=aarch64-linux-androideabi-clang++
|
||||||
|
BUILD_64=ON
|
||||||
|
TAG="android-armv8"
|
||||||
|
ARCH="armv8-a"
|
||||||
|
ARCH_ABI="arm64-v8a";;
|
||||||
|
"i686" )
|
||||||
|
CLANG=i686-linux-androideabi-clang
|
||||||
|
CXXLANG=i686-linux-androideabi-clang++
|
||||||
|
BUILD_64=OFF
|
||||||
|
TAG="android-x86"
|
||||||
|
ARCH="i686"
|
||||||
|
ARCH_ABI="x86";;
|
||||||
|
"x86_64" )
|
||||||
|
CLANG=x86_64-linux-androideabi-clang
|
||||||
|
CXXLANG=x86_64-linux-androideabi-clang++
|
||||||
|
BUILD_64=ON
|
||||||
|
TAG="android-x86_64"
|
||||||
|
ARCH="x86-64"
|
||||||
|
ARCH_ABI="x86_64";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
cd $MONERO_SRC_DIR
|
||||||
|
rm -rf ./build/release
|
||||||
|
mkdir -p ./build/release
|
||||||
|
cd ./build/release
|
||||||
|
CC=${CLANG} CXX=${CXXLANG} cmake -D USE_DEVICE_TREZOR=OFF -D BUILD_GUI_DEPS=1 -D BUILD_TESTS=OFF -D ARCH=${ARCH} -D STATIC=ON -D BUILD_64=${BUILD_64} -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D INSTALL_VENDORED_LIBUNBOUND=ON -D BUILD_TAG=${TAG} -D CMAKE_SYSTEM_NAME="Android" -D CMAKE_ANDROID_STANDALONE_TOOLCHAIN="${ANDROID_STANDALONE_TOOLCHAIN_PATH}" -D CMAKE_ANDROID_ARCH_ABI=${ARCH_ABI} $FLAGS ../..
|
||||||
|
|
||||||
|
make wallet_api -j$THREADS
|
||||||
|
find . -path ./lib -prune -o -name '*.a' -exec cp '{}' lib \;
|
||||||
|
|
||||||
|
cp -r ./lib/* $DEST_LIB_DIR
|
||||||
|
cp ../../src/wallet/api/wallet2_api.h $DEST_INCLUDE_DIR
|
||||||
|
done
|
55
scripts/docker/build_openssl.sh
Normal file
55
scripts/docker/build_openssl.sh
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
. ./config.sh
|
||||||
|
OPENSSL_FILENAME=openssl-1.1.1q.tar.gz
|
||||||
|
OPENSSL_FILE_PATH=$WORKDIR/$OPENSSL_FILENAME
|
||||||
|
OPENSSL_SRC_DIR=$WORKDIR/openssl-1.1.1q
|
||||||
|
OPENSSL_SHA256="d7939ce614029cdff0b6c20f0e2e5703158a489a72b2507b8bd51bf8c8fd10ca"
|
||||||
|
ZLIB_DIR=$WORKDIR/zlib
|
||||||
|
ZLIB_TAG=v1.2.11
|
||||||
|
ZLIB_COMMIT_HASH="cacf7f1d4e3d44d871b605da3b647f07d718623f"
|
||||||
|
|
||||||
|
rm -rf $ZLIB_DIR
|
||||||
|
git clone -b $ZLIB_TAG --depth 1 https://github.com/madler/zlib $ZLIB_DIR
|
||||||
|
cd $ZLIB_DIR
|
||||||
|
git reset --hard $ZLIB_COMMIT_HASH
|
||||||
|
CC=clang CXX=clang++ ./configure --static
|
||||||
|
make
|
||||||
|
|
||||||
|
curl https://www.openssl.org/source/$OPENSSL_FILENAME -o $OPENSSL_FILE_PATH
|
||||||
|
echo $OPENSSL_SHA256 $OPENSSL_FILE_PATH | sha256sum -c - || exit 1
|
||||||
|
|
||||||
|
for arch in "aarch" "aarch64" "i686" "x86_64"
|
||||||
|
do
|
||||||
|
PREFIX=$WORKDIR/prefix_${arch}
|
||||||
|
TOOLCHAIN=${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64
|
||||||
|
PATH="${TOOLCHAIN}/bin:${ORIGINAL_PATH}"
|
||||||
|
|
||||||
|
case $arch in
|
||||||
|
"aarch") X_ARCH="android-arm";;
|
||||||
|
"aarch64") X_ARCH="android-arm64";;
|
||||||
|
"i686") X_ARCH="android-x86";;
|
||||||
|
"x86_64") X_ARCH="android-x86_64";;
|
||||||
|
*) X_ARCH="android-${arch}";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
cd $WORKDIR
|
||||||
|
rm -rf $OPENSSL_SRC_DIR
|
||||||
|
tar -xzf $OPENSSL_FILE_PATH -C $WORKDIR
|
||||||
|
cd $OPENSSL_SRC_DIR
|
||||||
|
|
||||||
|
CC=clang ANDROID_NDK=$TOOLCHAIN \
|
||||||
|
./Configure ${X_ARCH} \
|
||||||
|
no-shared no-tests \
|
||||||
|
--with-zlib-include=${PREFIX}/include \
|
||||||
|
--with-zlib-lib=${PREFIX}/lib \
|
||||||
|
--prefix=${PREFIX} \
|
||||||
|
--openssldir=${PREFIX} \
|
||||||
|
-D__ANDROID_API__=$API
|
||||||
|
make -j$THREADS
|
||||||
|
make -j$THREADS install_sw
|
||||||
|
|
||||||
|
done
|
||||||
|
|
30
scripts/docker/build_sodium.sh
Normal file
30
scripts/docker/build_sodium.sh
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
. ./config.sh
|
||||||
|
SODIUM_SRC_DIR=${WORKDIR}/libsodium
|
||||||
|
SODIUM_BRANCH=1.0.16
|
||||||
|
|
||||||
|
for arch in "aarch" "aarch64" "i686" "x86_64"
|
||||||
|
do
|
||||||
|
|
||||||
|
PREFIX=${WORKDIR}/prefix_${arch}
|
||||||
|
PATH="${TOOLCHAIN_BASE_DIR}_${arch}/bin:${ORIGINAL_PATH}"
|
||||||
|
|
||||||
|
case $arch in
|
||||||
|
"aarch" ) TARGET="arm";;
|
||||||
|
"i686" ) TARGET="x86";;
|
||||||
|
* ) TARGET="${arch}";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
HOST="${TARGET}-linux-android"
|
||||||
|
cd $WORKDIR
|
||||||
|
rm -rf $SODIUM_SRC_DIR
|
||||||
|
git clone https://github.com/jedisct1/libsodium.git $SODIUM_SRC_DIR -b $SODIUM_BRANCH
|
||||||
|
cd $SODIUM_SRC_DIR
|
||||||
|
./autogen.sh
|
||||||
|
CC=clang CXX=clang++ ./configure --prefix=${PREFIX} --host=${HOST} --enable-static --disable-shared
|
||||||
|
make -j$THREADS
|
||||||
|
make install
|
||||||
|
|
||||||
|
done
|
||||||
|
|
65
scripts/docker/build_unbound.sh
Normal file
65
scripts/docker/build_unbound.sh
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
. ./config.sh
|
||||||
|
|
||||||
|
EXPAT_VERSION=R_2_4_8
|
||||||
|
EXPAT_HASH="3bab6c09bbe8bf42d84b81563ddbcf4cca4be838"
|
||||||
|
EXPAT_SRC_DIR=$WORKDIR/libexpat
|
||||||
|
|
||||||
|
for arch in "aarch" "aarch64" "i686" "x86_64"
|
||||||
|
do
|
||||||
|
PREFIX=$WORKDIR/prefix_${arch}
|
||||||
|
TOOLCHAIN=${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64
|
||||||
|
PATH="${TOOLCHAIN_BASE_DIR}_${arch}/bin:${ORIGINAL_PATH}"
|
||||||
|
|
||||||
|
cd $WORKDIR
|
||||||
|
rm -rf $EXPAT_SRC_DIR
|
||||||
|
git clone https://github.com/libexpat/libexpat.git -b ${EXPAT_VERSION} ${EXPAT_SRC_DIR}
|
||||||
|
cd $EXPAT_SRC_DIR
|
||||||
|
test `git rev-parse HEAD` = ${EXPAT_HASH} || exit 1
|
||||||
|
cd $EXPAT_SRC_DIR/expat
|
||||||
|
|
||||||
|
case $arch in
|
||||||
|
"aarch") HOST="arm-linux-androideabi";;
|
||||||
|
"i686") HOST="x86-linux-android";;
|
||||||
|
*) HOST="${arch}-linux-android";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
./buildconf.sh
|
||||||
|
CC=clang CXX=clang++ ./configure --enable-static --disable-shared --prefix=${PREFIX} --host=${HOST}
|
||||||
|
make -j$THREADS
|
||||||
|
make -j$THREADS install
|
||||||
|
done
|
||||||
|
|
||||||
|
UNBOUND_VERSION=release-1.16.2
|
||||||
|
UNBOUND_HASH="cbed768b8ff9bfcf11089a5f1699b7e5707f1ea5"
|
||||||
|
UNBOUND_SRC_DIR=$WORKDIR/unbound-1.16.2
|
||||||
|
|
||||||
|
for arch in "aarch" "aarch64" "i686" "x86_64"
|
||||||
|
do
|
||||||
|
PREFIX=$WORKDIR/prefix_${arch}
|
||||||
|
TOOLCHAIN=${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64
|
||||||
|
|
||||||
|
case $arch in
|
||||||
|
"aarch") TOOLCHAIN_BIN_PATH=${TOOLCHAIN_BASE_DIR}_${arch}/arm-linux-androideabi/bin;;
|
||||||
|
*) TOOLCHAIN_BIN_PATH=${TOOLCHAIN_BASE_DIR}_${arch}/${arch}-linux-android/bin;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
PATH="${TOOLCHAIN_BIN_PATH}:${TOOLCHAIN_BASE_DIR}_${arch}/bin:${ORIGINAL_PATH}"
|
||||||
|
echo $PATH
|
||||||
|
cd $WORKDIR
|
||||||
|
rm -rf $UNBOUND_SRC_DIR
|
||||||
|
git clone https://github.com/NLnetLabs/unbound.git -b ${UNBOUND_VERSION} ${UNBOUND_SRC_DIR}
|
||||||
|
cd $UNBOUND_SRC_DIR
|
||||||
|
test `git rev-parse HEAD` = ${UNBOUND_HASH} || exit 1
|
||||||
|
|
||||||
|
case $arch in
|
||||||
|
"aarch") HOST="arm-linux-androideabi";;
|
||||||
|
"i686") HOST="x86-linux-android";;
|
||||||
|
*) HOST="${arch}-linux-android";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CC=clang CXX=clang++ ./configure --prefix=${PREFIX} --host=${HOST} --enable-static --disable-shared --disable-flto --with-ssl=${PREFIX} --with-libexpat=${PREFIX}
|
||||||
|
make -j$THREADS
|
||||||
|
make -j$THREADS install
|
||||||
|
done
|
32
scripts/docker/build_zmq.sh
Normal file
32
scripts/docker/build_zmq.sh
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
. ./config.sh
|
||||||
|
ZMQ_SRC_DIR=$WORKDIR/libzmq
|
||||||
|
ZMQ_BRANCH=v4.3.3
|
||||||
|
ZMQ_COMMIT_HASH=04f5bbedee58c538934374dc45182d8fc5926fa3
|
||||||
|
|
||||||
|
for arch in "aarch" "aarch64" "i686" "x86_64"
|
||||||
|
do
|
||||||
|
|
||||||
|
PREFIX=$WORKDIR/prefix_${arch}
|
||||||
|
PATH="${TOOLCHAIN_BASE_DIR}_${arch}/bin:${ORIGINAL_PATH}"
|
||||||
|
|
||||||
|
case $arch in
|
||||||
|
"aarch" ) TARGET="arm";;
|
||||||
|
"i686" ) TARGET="x86";;
|
||||||
|
* ) TARGET="${arch}";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
|
||||||
|
HOST="${TARGET}-linux-android"
|
||||||
|
cd $WORKDIR
|
||||||
|
rm -rf $ZMQ_SRC_DIR
|
||||||
|
git clone https://github.com/zeromq/libzmq.git ${ZMQ_SRC_DIR} -b ${ZMQ_BRANCH}
|
||||||
|
cd $ZMQ_SRC_DIR
|
||||||
|
git checkout ${ZMQ_COMMIT_HASH}
|
||||||
|
./autogen.sh
|
||||||
|
CC=clang CXX=clang++ ./configure --prefix=${PREFIX} --host=${HOST} --enable-static --disable-shared
|
||||||
|
make -j$THREADS
|
||||||
|
make install
|
||||||
|
|
||||||
|
done
|
11
scripts/docker/config.sh
Normal file
11
scripts/docker/config.sh
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
export API=21
|
||||||
|
export WORKDIR=/opt/android
|
||||||
|
export ANDROID_NDK_ZIP=${WORKDIR}/android-ndk-r17c.zip
|
||||||
|
export ANDROID_NDK_ROOT=${WORKDIR}/android-ndk-r17c
|
||||||
|
export ANDROID_NDK_HOME=$ANDROID_NDK_ROOT
|
||||||
|
export TOOLCHAIN_DIR="${WORKDIR}/toolchain"
|
||||||
|
export TOOLCHAIN_BASE_DIR=$TOOLCHAIN_DIR
|
||||||
|
export ORIGINAL_PATH=$PATH
|
||||||
|
export THREADS=4
|
45
scripts/docker/copy_haven_deps.sh
Normal file
45
scripts/docker/copy_haven_deps.sh
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
WORKDIR=/opt/android
|
||||||
|
CW_DIR=${WORKDIR}/cake_wallet
|
||||||
|
CW_EXRTERNAL_DIR=${CW_DIR}/cw_shared_external/ios/External/android
|
||||||
|
CW_HAVEN_EXTERNAL_DIR=${CW_DIR}/cw_haven/ios/External/android
|
||||||
|
CW_MONERO_EXTERNAL_DIR=${CW_DIR}/cw_monero/ios/External/android
|
||||||
|
for arch in "aarch" "aarch64" "i686" "x86_64"
|
||||||
|
do
|
||||||
|
|
||||||
|
PREFIX=${WORKDIR}/prefix_${arch}
|
||||||
|
ABI=""
|
||||||
|
|
||||||
|
case $arch in
|
||||||
|
"aarch" )
|
||||||
|
ABI="armeabi-v7a";;
|
||||||
|
"aarch64" )
|
||||||
|
ABI="arm64-v8a";;
|
||||||
|
"i686" )
|
||||||
|
ABI="x86";;
|
||||||
|
"x86_64" )
|
||||||
|
ABI="x86_64";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
LIB_DIR=${CW_EXRTERNAL_DIR}/${ABI}/lib
|
||||||
|
INCLUDE_DIR=${CW_EXRTERNAL_DIR}/${ABI}/include
|
||||||
|
LIBANBOUND_PATH=${PREFIX}/lib/libunbound.a
|
||||||
|
|
||||||
|
mkdir -p $LIB_DIR
|
||||||
|
mkdir -p $INCLUDE_DIR
|
||||||
|
|
||||||
|
cp -r ${PREFIX}/lib/* $LIB_DIR
|
||||||
|
cp -r ${PREFIX}/include/* $INCLUDE_DIR
|
||||||
|
|
||||||
|
if [ -f "$LIBANBOUND_PATH" ]; then
|
||||||
|
cp $LIBANBOUND_PATH ${LIB_DIR}/monero
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
mkdir -p ${CW_HAVEN_EXTERNAL_DIR}/include
|
||||||
|
mkdir -p ${CW_MONERO_EXTERNAL_DIR}/include
|
||||||
|
|
||||||
|
cp $CW_EXRTERNAL_DIR/x86/include/monero/wallet2_api.h ${CW_MONERO_EXTERNAL_DIR}/include
|
||||||
|
cp $CW_EXRTERNAL_DIR/x86/include/haven/wallet2_api.h ${CW_HAVEN_EXTERNAL_DIR}/include
|
37
scripts/docker/copy_monero_deps.sh
Normal file
37
scripts/docker/copy_monero_deps.sh
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
WORKDIR=/opt/android
|
||||||
|
CW_EXRTERNAL_DIR=${WORKDIR}/output/android
|
||||||
|
|
||||||
|
for arch in "aarch" "aarch64" "i686" "x86_64"
|
||||||
|
do
|
||||||
|
|
||||||
|
PREFIX=${WORKDIR}/prefix_${arch}
|
||||||
|
ABI=""
|
||||||
|
|
||||||
|
case $arch in
|
||||||
|
"aarch" )
|
||||||
|
ABI="armeabi-v7a";;
|
||||||
|
"aarch64" )
|
||||||
|
ABI="arm64-v8a";;
|
||||||
|
"i686" )
|
||||||
|
ABI="x86";;
|
||||||
|
"x86_64" )
|
||||||
|
ABI="x86_64";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
LIB_DIR=${CW_EXRTERNAL_DIR}/${ABI}/lib
|
||||||
|
INCLUDE_DIR=${CW_EXRTERNAL_DIR}/${ABI}/include
|
||||||
|
LIBANBOUND_PATH=${PREFIX}/lib/libunbound.a
|
||||||
|
|
||||||
|
mkdir -p $LIB_DIR
|
||||||
|
mkdir -p $INCLUDE_DIR
|
||||||
|
|
||||||
|
cp -r ${PREFIX}/lib/* $LIB_DIR
|
||||||
|
cp -r ${PREFIX}/include/* $INCLUDE_DIR
|
||||||
|
|
||||||
|
if [ -f "$LIBANBOUND_PATH" ]; then
|
||||||
|
cp $LIBANBOUND_PATH ${LIB_DIR}/monero
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
9
scripts/docker/docker-compose.yml
Normal file
9
scripts/docker/docker-compose.yml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
version: '3.6'
|
||||||
|
|
||||||
|
services:
|
||||||
|
build_deps:
|
||||||
|
image: build_monero_deps
|
||||||
|
environment:
|
||||||
|
MONERO_BRANCH: release-v0.18.2.2-android
|
||||||
|
volumes:
|
||||||
|
- ./output:/opt/android/output
|
4
scripts/docker/entrypoint.sh
Normal file
4
scripts/docker/entrypoint.sh
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
./build_monero.sh
|
||||||
|
./copy_monero_deps.sh
|
9
scripts/docker/finish_boost.sh
Normal file
9
scripts/docker/finish_boost.sh
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
ARCH=$1
|
||||||
|
PREFIX=$2
|
||||||
|
BOOST_SRC_DIR=$3
|
||||||
|
|
||||||
|
cd $BOOST_SRC_DIR
|
||||||
|
|
||||||
|
./b2 --build-type=minimal link=static runtime-link=static --with-chrono --with-date_time --with-filesystem --with-program_options --with-regex --with-serialization --with-system --with-thread --with-locale --build-dir=android --stagedir=android toolset=clang threading=multi threadapi=pthread target-os=android -sICONV_PATH=${PREFIX} -j$THREADS install
|
22
scripts/docker/init_boost.sh
Normal file
22
scripts/docker/init_boost.sh
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
ARCH=$1
|
||||||
|
PREFIX=$2
|
||||||
|
BOOST_SRC_DIR=$3
|
||||||
|
BOOST_FILENAME=$4
|
||||||
|
BOOST_VERSION=$5
|
||||||
|
BOOST_FILE_PATH=$WORKDIR/$BOOST_FILENAME
|
||||||
|
BOOST_SHA256="59c9b274bc451cf91a9ba1dd2c7fdcaf5d60b1b3aa83f2c9fa143417cc660722"
|
||||||
|
|
||||||
|
if [ ! -e "$BOOST_FILE_PATH" ]; then
|
||||||
|
curl -L http://downloads.sourceforge.net/project/boost/boost/${BOOST_VERSION}/${BOOST_FILENAME} > $BOOST_FILE_PATH
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo $BOOST_SHA256 $BOOST_FILE_PATH | sha256sum -c - || exit 1
|
||||||
|
|
||||||
|
cd $WORKDIR
|
||||||
|
rm -rf $BOOST_SRC_DIR
|
||||||
|
rm -rf $PREFIX/include/boost
|
||||||
|
tar -xvf $BOOST_FILE_PATH -C $WORKDIR
|
||||||
|
cd $BOOST_SRC_DIR
|
||||||
|
./bootstrap.sh --prefix=${PREFIX}
|
18
scripts/docker/install_ndk.sh
Normal file
18
scripts/docker/install_ndk.sh
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
. ./config.sh
|
||||||
|
TOOLCHAIN_DIR=${WORKDIR}/toolchain
|
||||||
|
TOOLCHAIN_A32_DIR=${TOOLCHAIN_DIR}_aarch
|
||||||
|
TOOLCHAIN_A64_DIR=${TOOLCHAIN_DIR}_aarch64
|
||||||
|
TOOLCHAIN_x86_DIR=${TOOLCHAIN_DIR}_i686
|
||||||
|
TOOLCHAIN_x86_64_DIR=${TOOLCHAIN_DIR}_x86_64
|
||||||
|
ANDROID_NDK_SHA256="3f541adbd0330a9205ba12697f6d04ec90752c53d6b622101a2a8a856e816589"
|
||||||
|
|
||||||
|
curl https://dl.google.com/android/repository/android-ndk-r17c-linux-x86_64.zip -o ${ANDROID_NDK_ZIP}
|
||||||
|
echo $ANDROID_NDK_SHA256 $ANDROID_NDK_ZIP | sha256sum -c || exit 1
|
||||||
|
unzip $ANDROID_NDK_ZIP -d $WORKDIR
|
||||||
|
|
||||||
|
${ANDROID_NDK_ROOT}/build/tools/make_standalone_toolchain.py --arch arm64 --api $API --install-dir ${TOOLCHAIN_A64_DIR} --stl=libc++
|
||||||
|
${ANDROID_NDK_ROOT}/build/tools/make_standalone_toolchain.py --arch arm --api $API --install-dir ${TOOLCHAIN_A32_DIR} --stl=libc++
|
||||||
|
${ANDROID_NDK_ROOT}/build/tools/make_standalone_toolchain.py --arch x86 --api $API --install-dir ${TOOLCHAIN_x86_DIR} --stl=libc++
|
||||||
|
${ANDROID_NDK_ROOT}/build/tools/make_standalone_toolchain.py --arch x86_64 --api $API --install-dir ${TOOLCHAIN_x86_64_DIR} --stl=libc++
|
|
@ -59,4 +59,4 @@ cp -r ./lib/* $DEST_LIB_DIR
|
||||||
cp ../../src/wallet/api/wallet2_api.h $DEST_INCLUDE_DIR
|
cp ../../src/wallet/api/wallet2_api.h $DEST_INCLUDE_DIR
|
||||||
popd
|
popd
|
||||||
|
|
||||||
done
|
done
|
||||||
|
|
|
@ -1,66 +1,66 @@
|
||||||
// import 'dart:convert';
|
import 'dart:convert';
|
||||||
// import 'dart:io';
|
import 'dart:io';
|
||||||
//
|
|
||||||
// import 'package:translator/translator.dart';
|
import 'package:translator/translator.dart';
|
||||||
//
|
|
||||||
// const defaultLang = "en";
|
const defaultLang = "en";
|
||||||
// const langs = [
|
const langs = [
|
||||||
// "ar", "bg", "cs", "de", "en", "es", "fr", "ha", "hi", "hr", "id", "it",
|
"ar", "bg", "cs", "de", "en", "es", "fr", "ha", "hi", "hr", "id", "it",
|
||||||
// "ja", "ko", "my", "nl", "pl", "pt", "ru", "th", "tr", "uk", "ur", "yo",
|
"ja", "ko", "my", "nl", "pl", "pt", "ru", "th", "tr", "uk", "ur", "yo",
|
||||||
// "zh-cn" // zh, but Google Translate uses zh-cn for Chinese (Simplified)
|
"zh-cn" // zh, but Google Translate uses zh-cn for Chinese (Simplified)
|
||||||
// ];
|
];
|
||||||
// final translator = GoogleTranslator();
|
final translator = GoogleTranslator();
|
||||||
//
|
|
||||||
// void main(List<String> args) async {
|
void main(List<String> args) async {
|
||||||
// if (args.length != 2) {
|
if (args.length != 2) {
|
||||||
// throw Exception(
|
throw Exception(
|
||||||
// 'Insufficient arguments!\n\nTry to run `./append_translation.dart greetings "Hello World!"`');
|
'Insufficient arguments!\n\nTry to run `./append_translation.dart greetings "Hello World!"`');
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// final name = args.first;
|
final name = args.first;
|
||||||
// final text = args.last;
|
final text = args.last;
|
||||||
//
|
|
||||||
// print('Appending "$name": "$text"');
|
print('Appending "$name": "$text"');
|
||||||
//
|
|
||||||
// for (var lang in langs) {
|
for (var lang in langs) {
|
||||||
// final fileName = getFileName(lang);
|
final fileName = getFileName(lang);
|
||||||
// final translation = await getTranslation(text, lang);
|
final translation = await getTranslation(text, lang);
|
||||||
//
|
|
||||||
// appendArbFile(fileName, name, translation);
|
appendArbFile(fileName, name, translation);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// void appendArbFile(String fileName, String name, String text) {
|
void appendArbFile(String fileName, String name, String text) {
|
||||||
// final file = File(fileName);
|
final file = File(fileName);
|
||||||
// final inputContent = file.readAsStringSync();
|
final inputContent = file.readAsStringSync();
|
||||||
// final arbObj = json.decode(inputContent) as Map<String, dynamic>;
|
final arbObj = json.decode(inputContent) as Map<String, dynamic>;
|
||||||
//
|
|
||||||
// if (arbObj.containsKey(name)) {
|
if (arbObj.containsKey(name)) {
|
||||||
// print("String $name already exists in $fileName!");
|
print("String $name already exists in $fileName!");
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// arbObj.addAll({name: text});
|
arbObj.addAll({name: text});
|
||||||
//
|
|
||||||
// final outputContent = json
|
final outputContent = json
|
||||||
// .encode(arbObj)
|
.encode(arbObj)
|
||||||
// .replaceAll('","', '",\n "')
|
.replaceAll('","', '",\n "')
|
||||||
// .replaceAll('{"', '{\n "')
|
.replaceAll('{"', '{\n "')
|
||||||
// .replaceAll('"}', '"\n}')
|
.replaceAll('"}', '"\n}')
|
||||||
// .replaceAll('":"', '": "');
|
.replaceAll('":"', '": "');
|
||||||
//
|
|
||||||
// file.writeAsStringSync(outputContent);
|
file.writeAsStringSync(outputContent);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
//
|
|
||||||
// Future<String> getTranslation(String text, String lang) async {
|
Future<String> getTranslation(String text, String lang) async {
|
||||||
// if (lang == defaultLang) return text;
|
if (lang == defaultLang) return text;
|
||||||
// return (await translator.translate(text, from: defaultLang, to: lang)).text;
|
return (await translator.translate(text, from: defaultLang, to: lang)).text;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// String getFileName(String lang) {
|
String getFileName(String lang) {
|
||||||
// final shortLang = lang
|
final shortLang = lang
|
||||||
// .split("-")
|
.split("-")
|
||||||
// .first;
|
.first;
|
||||||
// return "./res/values/strings_$shortLang.arb";
|
return "./res/values/strings_$shortLang.arb";
|
||||||
// }
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ Future<void> main(List<String> args) async {
|
||||||
Future<void> generateBitcoin(bool hasImplementation) async {
|
Future<void> generateBitcoin(bool hasImplementation) async {
|
||||||
final outputFile = File(bitcoinOutputPath);
|
final outputFile = File(bitcoinOutputPath);
|
||||||
const bitcoinCommonHeaders = """
|
const bitcoinCommonHeaders = """
|
||||||
|
import 'package:cake_wallet/entities/unspent_transaction_output.dart';
|
||||||
import 'package:cw_core/wallet_credentials.dart';
|
import 'package:cw_core/wallet_credentials.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_core/transaction_priority.dart';
|
import 'package:cw_core/transaction_priority.dart';
|
||||||
|
@ -48,24 +49,6 @@ import 'package:cw_bitcoin/litecoin_wallet_service.dart';
|
||||||
""";
|
""";
|
||||||
const bitcoinCwPart = "part 'cw_bitcoin.dart';";
|
const bitcoinCwPart = "part 'cw_bitcoin.dart';";
|
||||||
const bitcoinContent = """
|
const bitcoinContent = """
|
||||||
class Unspent {
|
|
||||||
Unspent(this.address, this.hash, this.value, this.vout)
|
|
||||||
: isSending = true,
|
|
||||||
isFrozen = false,
|
|
||||||
note = '';
|
|
||||||
|
|
||||||
final String address;
|
|
||||||
final String hash;
|
|
||||||
final int value;
|
|
||||||
final int vout;
|
|
||||||
|
|
||||||
bool isSending;
|
|
||||||
bool isFrozen;
|
|
||||||
String note;
|
|
||||||
|
|
||||||
bool get isP2wpkh => address.startsWith('bc') || address.startsWith('ltc');
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class Bitcoin {
|
abstract class Bitcoin {
|
||||||
TransactionPriority getMediumTransactionPriority();
|
TransactionPriority getMediumTransactionPriority();
|
||||||
|
|
||||||
|
@ -122,6 +105,9 @@ abstract class Bitcoin {
|
||||||
Future<void> generateMonero(bool hasImplementation) async {
|
Future<void> generateMonero(bool hasImplementation) async {
|
||||||
final outputFile = File(moneroOutputPath);
|
final outputFile = File(moneroOutputPath);
|
||||||
const moneroCommonHeaders = """
|
const moneroCommonHeaders = """
|
||||||
|
import 'package:cake_wallet/entities/unspent_transaction_output.dart';
|
||||||
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
|
import 'package:cw_monero/monero_unspent.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:cw_core/wallet_credentials.dart';
|
import 'package:cw_core/wallet_credentials.dart';
|
||||||
|
@ -231,6 +217,9 @@ abstract class Monero {
|
||||||
TransactionPriority deserializeMoneroTransactionPriority({required int raw});
|
TransactionPriority deserializeMoneroTransactionPriority({required int raw});
|
||||||
List<TransactionPriority> getTransactionPriorities();
|
List<TransactionPriority> getTransactionPriorities();
|
||||||
List<String> getMoneroWordList(String language);
|
List<String> getMoneroWordList(String language);
|
||||||
|
|
||||||
|
List<Unspent> getUnspents(Object wallet);
|
||||||
|
void updateUnspents(Object wallet);
|
||||||
|
|
||||||
WalletCredentials createMoneroRestoreWalletFromKeysCredentials({
|
WalletCredentials createMoneroRestoreWalletFromKeysCredentials({
|
||||||
required String name,
|
required String name,
|
||||||
|
@ -252,7 +241,7 @@ abstract class Monero {
|
||||||
void setCurrentAccount(Object wallet, int id, String label, String? balance);
|
void setCurrentAccount(Object wallet, int id, String label, String? balance);
|
||||||
void onStartup();
|
void onStartup();
|
||||||
int getTransactionInfoAccountId(TransactionInfo tx);
|
int getTransactionInfoAccountId(TransactionInfo tx);
|
||||||
WalletService createMoneroWalletService(Box<WalletInfo> walletInfoSource);
|
WalletService createMoneroWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource);
|
||||||
Map<String, String> pendingTransactionInfo(Object transaction);
|
Map<String, String> pendingTransactionInfo(Object transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -650,4 +639,4 @@ Future<void> generateWalletTypes({required bool hasMonero, required bool hasBitc
|
||||||
|
|
||||||
outputContent += '];\n';
|
outputContent += '];\n';
|
||||||
await walletTypesFile.writeAsString(outputContent);
|
await walletTypesFile.writeAsString(outputContent);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue