2023-09-27 15:53:10 +00:00
|
|
|
import 'dart:convert';
|
|
|
|
|
2023-09-20 14:12:48 +00:00
|
|
|
import 'package:flutter/foundation.dart';
|
2023-09-18 21:56:57 +00:00
|
|
|
import 'package:flutter_libepiccash/epic_cash.dart' as lib_epiccash;
|
2023-09-20 23:04:37 +00:00
|
|
|
import 'package:mutex/mutex.dart';
|
2023-09-18 21:56:57 +00:00
|
|
|
|
|
|
|
///
|
|
|
|
/// Wrapped up calls to flutter_libepiccash.
|
|
|
|
///
|
|
|
|
/// Should all be static calls (no state stored in this class)
|
|
|
|
///
|
|
|
|
abstract class LibEpiccash {
|
2023-09-20 23:08:22 +00:00
|
|
|
static final Mutex _mutex = Mutex();
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Check if [address] is a valid epiccash address according to libepiccash
|
|
|
|
///
|
2023-09-18 21:56:57 +00:00
|
|
|
static bool validateSendAddress({required String address}) {
|
|
|
|
final String validate = lib_epiccash.validateSendAddress(address);
|
|
|
|
if (int.parse(validate) == 1) {
|
|
|
|
// Check if address contains a domain
|
|
|
|
if (address.contains("@")) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2023-09-20 14:12:48 +00:00
|
|
|
|
2023-09-20 23:04:37 +00:00
|
|
|
///
|
2023-09-26 15:36:21 +00:00
|
|
|
/// Fetch the mnemonic For a new wallet (Only used in the example app)
|
2023-09-20 23:04:37 +00:00
|
|
|
///
|
|
|
|
// TODO: ensure the above documentation comment is correct
|
|
|
|
// TODO: ensure this will always return the mnemonic. If not, this function should throw an exception
|
|
|
|
// TODO: probably remove this as we don't use it in stack wallet. We store the mnemonic separately
|
2023-09-20 14:12:48 +00:00
|
|
|
static String getMnemonic() {
|
2023-09-26 15:36:21 +00:00
|
|
|
try {
|
2023-09-27 15:53:10 +00:00
|
|
|
String mnemonic = lib_epiccash.walletMnemonic();
|
|
|
|
if (mnemonic.isEmpty) {
|
|
|
|
throw Exception("Error getting mnemonic, returned empty string");
|
|
|
|
}
|
|
|
|
return mnemonic;
|
2023-09-26 15:36:21 +00:00
|
|
|
} catch (e) {
|
|
|
|
throw Exception(e.toString());
|
|
|
|
}
|
2023-09-20 14:12:48 +00:00
|
|
|
}
|
|
|
|
|
2023-09-20 23:04:37 +00:00
|
|
|
// Private function wrapper for compute
|
2023-09-20 14:12:48 +00:00
|
|
|
static Future<String> _initializeWalletWrapper(
|
2023-09-20 23:04:37 +00:00
|
|
|
({
|
|
|
|
String config,
|
|
|
|
String mnemonic,
|
|
|
|
String password,
|
|
|
|
String name,
|
|
|
|
}) data,
|
|
|
|
) async {
|
|
|
|
final String initWalletStr = lib_epiccash.initWallet(
|
|
|
|
data.config,
|
|
|
|
data.mnemonic,
|
|
|
|
data.password,
|
|
|
|
data.name,
|
|
|
|
);
|
2023-09-20 14:12:48 +00:00
|
|
|
return initWalletStr;
|
|
|
|
}
|
|
|
|
|
2023-09-20 23:04:37 +00:00
|
|
|
///
|
2023-09-26 15:36:21 +00:00
|
|
|
/// Create a new epiccash wallet.
|
2023-09-20 23:04:37 +00:00
|
|
|
///
|
|
|
|
// TODO: Complete/modify the documentation comment above
|
|
|
|
// TODO: Should return a void future. On error this function should throw and exception
|
2023-09-27 15:53:10 +00:00
|
|
|
static Future<String> initializeNewWallet({
|
2023-09-20 14:12:48 +00:00
|
|
|
required String config,
|
|
|
|
required String mnemonic,
|
|
|
|
required String password,
|
2023-09-20 23:04:37 +00:00
|
|
|
required String name,
|
|
|
|
}) async {
|
2023-09-26 15:36:21 +00:00
|
|
|
try {
|
2023-09-27 15:53:10 +00:00
|
|
|
return await compute(
|
2023-09-26 15:36:21 +00:00
|
|
|
_initializeWalletWrapper,
|
|
|
|
(
|
2023-09-26 23:26:28 +00:00
|
|
|
config: config,
|
|
|
|
mnemonic: mnemonic,
|
|
|
|
password: password,
|
|
|
|
name: name,
|
2023-09-26 15:36:21 +00:00
|
|
|
),
|
|
|
|
);
|
|
|
|
} catch (e) {
|
2023-09-26 23:26:28 +00:00
|
|
|
throw ("Error creating new wallet : ${e.toString()}");
|
2023-09-26 15:36:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Private function wrapper for wallet balances
|
|
|
|
///
|
|
|
|
static Future<String> _walletBalancesWrapper(
|
2023-09-26 23:26:28 +00:00
|
|
|
({String wallet, int refreshFromNode, int minimumConfirmations}) data,
|
|
|
|
) async {
|
|
|
|
return lib_epiccash.getWalletInfo(
|
|
|
|
data.wallet, data.refreshFromNode, data.minimumConfirmations);
|
2023-09-26 15:36:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Get balance information for the currently open wallet
|
|
|
|
///
|
2023-09-27 22:47:26 +00:00
|
|
|
static Future<
|
|
|
|
({
|
|
|
|
double awaitingFinalization,
|
|
|
|
double pending,
|
|
|
|
double spendable,
|
|
|
|
double total
|
|
|
|
})>
|
|
|
|
getWalletBalances(
|
|
|
|
{required String wallet,
|
|
|
|
required int refreshFromNode,
|
|
|
|
required int minimumConfirmations}) async {
|
2023-09-26 23:26:28 +00:00
|
|
|
try {
|
|
|
|
String balances = await compute(_walletBalancesWrapper, (
|
|
|
|
wallet: wallet,
|
|
|
|
refreshFromNode: refreshFromNode,
|
|
|
|
minimumConfirmations: minimumConfirmations,
|
|
|
|
));
|
2023-09-27 15:53:10 +00:00
|
|
|
|
|
|
|
//If balances is valid json return, else return error
|
|
|
|
if (balances.toUpperCase().contains("ERROR")) {
|
|
|
|
throw Exception(balances);
|
|
|
|
}
|
|
|
|
var jsonBalances = json.decode(balances);
|
|
|
|
//Return balances as record
|
|
|
|
({
|
2023-09-27 22:47:26 +00:00
|
|
|
double spendable,
|
|
|
|
double pending,
|
|
|
|
double total,
|
|
|
|
double awaitingFinalization
|
2023-09-27 15:53:10 +00:00
|
|
|
}) balancesRecord = (
|
2023-09-27 22:47:26 +00:00
|
|
|
spendable: jsonBalances['amount_currently_spendable'],
|
|
|
|
pending: jsonBalances['amount_awaiting_finalization'],
|
|
|
|
total: jsonBalances['total'],
|
|
|
|
awaitingFinalization: jsonBalances['amount_awaiting_finalization'],
|
2023-09-27 15:53:10 +00:00
|
|
|
);
|
|
|
|
return balancesRecord;
|
2023-09-26 23:26:28 +00:00
|
|
|
} catch (e) {
|
|
|
|
throw ("Error getting wallet info : ${e.toString()}");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Private function wrapper for scanning output function
|
|
|
|
///
|
|
|
|
static Future<String> _scanOutputsWrapper(
|
|
|
|
({String wallet, int startHeight, int numberOfBlocks}) data,
|
|
|
|
) async {
|
|
|
|
return lib_epiccash.scanOutPuts(
|
|
|
|
data.wallet,
|
|
|
|
data.startHeight,
|
|
|
|
data.numberOfBlocks,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Scan Epic outputs
|
|
|
|
///
|
2023-09-27 22:47:26 +00:00
|
|
|
static Future<String> scanOutputs({
|
2023-09-26 23:26:28 +00:00
|
|
|
required String wallet,
|
|
|
|
required int startHeight,
|
|
|
|
required int numberOfBlocks,
|
|
|
|
}) async {
|
|
|
|
try {
|
2023-09-27 22:47:26 +00:00
|
|
|
return await compute(_scanOutputsWrapper, (
|
2023-09-26 23:26:28 +00:00
|
|
|
wallet: wallet,
|
|
|
|
startHeight: startHeight,
|
|
|
|
numberOfBlocks: numberOfBlocks,
|
|
|
|
));
|
|
|
|
} catch (e) {
|
|
|
|
throw ("Error getting scanning outputs : ${e.toString()}");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Private function wrapper for create transactions
|
|
|
|
///
|
|
|
|
static Future<String> _createTransactionWrapper(
|
|
|
|
({
|
|
|
|
String wallet,
|
|
|
|
int amount,
|
|
|
|
String address,
|
|
|
|
int secretKey,
|
|
|
|
String epicboxConfig,
|
|
|
|
int minimumConfirmations,
|
|
|
|
String note,
|
|
|
|
}) data,
|
|
|
|
) async {
|
|
|
|
return lib_epiccash.createTransaction(
|
|
|
|
data.wallet,
|
|
|
|
data.amount,
|
|
|
|
data.address,
|
|
|
|
data.secretKey,
|
|
|
|
data.epicboxConfig,
|
|
|
|
data.minimumConfirmations,
|
|
|
|
data.note);
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Create an Epic transaction
|
|
|
|
///
|
2023-09-27 22:47:26 +00:00
|
|
|
static Future<String> createTransaction({
|
2023-09-26 23:26:28 +00:00
|
|
|
required String wallet,
|
|
|
|
required int amount,
|
|
|
|
required String address,
|
|
|
|
required int secretKey,
|
|
|
|
required String epicboxConfig,
|
|
|
|
required int minimumConfirmations,
|
|
|
|
required String note,
|
|
|
|
}) async {
|
|
|
|
try {
|
2023-09-27 22:47:26 +00:00
|
|
|
return await compute(_createTransactionWrapper, (
|
2023-09-26 23:26:28 +00:00
|
|
|
wallet: wallet,
|
|
|
|
amount: amount,
|
|
|
|
address: address,
|
|
|
|
secretKey: secretKey,
|
|
|
|
epicboxConfig: epicboxConfig,
|
|
|
|
minimumConfirmations: minimumConfirmations,
|
|
|
|
note: note,
|
|
|
|
));
|
|
|
|
} catch (e) {
|
|
|
|
throw ("Error creating epic transaction : ${e.toString()}");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Private function wrapper for get transactions
|
|
|
|
///
|
|
|
|
static Future<String> _getTransactionsWrapper(
|
|
|
|
({
|
|
|
|
String wallet,
|
|
|
|
int refreshFromNode,
|
|
|
|
}) data,
|
|
|
|
) async {
|
|
|
|
return lib_epiccash.getTransactions(
|
|
|
|
data.wallet,
|
|
|
|
data.refreshFromNode,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
2023-09-27 22:47:26 +00:00
|
|
|
static Future<String> getTransaction({
|
2023-09-26 15:36:21 +00:00
|
|
|
required String wallet,
|
|
|
|
required int refreshFromNode,
|
|
|
|
}) async {
|
|
|
|
try {
|
2023-09-27 22:47:26 +00:00
|
|
|
return await compute(_getTransactionsWrapper, (
|
2023-09-26 23:26:28 +00:00
|
|
|
wallet: wallet,
|
|
|
|
refreshFromNode: refreshFromNode,
|
2023-09-26 15:36:21 +00:00
|
|
|
));
|
|
|
|
} catch (e) {
|
2023-09-26 23:26:28 +00:00
|
|
|
throw ("Error getting epic transaction : ${e.toString()}");
|
2023-09-26 15:36:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-26 23:26:28 +00:00
|
|
|
///
|
|
|
|
/// Private function for cancel transaction function
|
|
|
|
///
|
|
|
|
static Future<String> _cancelTransactionWrapper(
|
|
|
|
({
|
|
|
|
String wallet,
|
|
|
|
String transactionId,
|
|
|
|
}) data,
|
|
|
|
) async {
|
|
|
|
return lib_epiccash.cancelTransaction(
|
|
|
|
data.wallet,
|
|
|
|
data.transactionId,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
2023-09-27 22:47:26 +00:00
|
|
|
/// Cancel current Epic transaction
|
2023-09-26 23:26:28 +00:00
|
|
|
///
|
2023-09-27 22:47:26 +00:00
|
|
|
static Future<String> cancelTransaction({
|
2023-09-26 23:26:28 +00:00
|
|
|
required String wallet,
|
|
|
|
required String transactionId,
|
|
|
|
}) async {
|
|
|
|
try {
|
2023-09-27 22:47:26 +00:00
|
|
|
return await compute(_cancelTransactionWrapper, (
|
2023-09-26 23:26:28 +00:00
|
|
|
wallet: wallet,
|
|
|
|
transactionId: transactionId,
|
|
|
|
));
|
|
|
|
} catch (e) {
|
|
|
|
throw ("Error canceling epic transaction : ${e.toString()}");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-27 22:47:26 +00:00
|
|
|
///
|
|
|
|
/// Private function for address info function
|
|
|
|
///
|
|
|
|
static Future<String> _addressInfoWrapper(
|
2023-09-26 23:26:28 +00:00
|
|
|
({
|
|
|
|
String wallet,
|
|
|
|
int index,
|
|
|
|
String epicboxConfig,
|
|
|
|
}) data,
|
|
|
|
) async {
|
|
|
|
return lib_epiccash.getAddressInfo(
|
|
|
|
data.wallet,
|
|
|
|
data.index,
|
|
|
|
data.epicboxConfig,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-09-27 22:47:26 +00:00
|
|
|
///
|
|
|
|
/// get Epic address info
|
|
|
|
///
|
|
|
|
static Future<String> getAddressInfo({
|
2023-09-26 23:26:28 +00:00
|
|
|
required String wallet,
|
|
|
|
required int index,
|
|
|
|
required String epicboxConfig,
|
|
|
|
}) async {
|
2023-09-27 22:47:26 +00:00
|
|
|
try {
|
|
|
|
return await compute(_addressInfoWrapper, (
|
|
|
|
wallet: wallet,
|
|
|
|
index: index,
|
|
|
|
epicboxConfig: epicboxConfig,
|
|
|
|
));
|
|
|
|
} catch (e) {
|
|
|
|
throw ("Error getting address info : ${e.toString()}");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Private function for getting transaction fees
|
|
|
|
///
|
|
|
|
static Future<String> _transactionFeesWrapper(
|
|
|
|
({
|
|
|
|
String wallet,
|
|
|
|
int amount,
|
|
|
|
int minimumConfirmations,
|
|
|
|
}) data,
|
|
|
|
) async {
|
|
|
|
return lib_epiccash.getTransactionFees(
|
|
|
|
data.wallet,
|
|
|
|
data.amount,
|
|
|
|
data.minimumConfirmations,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// get transaction fees for Epic
|
|
|
|
///
|
|
|
|
static Future<String> getTransactionFees({
|
|
|
|
required String wallet,
|
|
|
|
required int amount,
|
|
|
|
required int minimumConfirmations,
|
|
|
|
}) async {
|
|
|
|
try {
|
|
|
|
return await compute(_transactionFeesWrapper, (
|
|
|
|
wallet: wallet,
|
|
|
|
amount: amount,
|
|
|
|
minimumConfirmations: minimumConfirmations,
|
|
|
|
));
|
|
|
|
} catch (e) {
|
|
|
|
throw ("Error getting transaction fees : ${e.toString()}");
|
|
|
|
}
|
2023-09-26 23:26:28 +00:00
|
|
|
}
|
|
|
|
|
2023-09-26 15:36:21 +00:00
|
|
|
///
|
|
|
|
/// Private function wrapper for recover wallet function
|
|
|
|
///
|
|
|
|
static Future<String> _recoverWalletWrapper(
|
2023-09-26 23:26:28 +00:00
|
|
|
({
|
2023-09-26 15:36:21 +00:00
|
|
|
String config,
|
|
|
|
String password,
|
|
|
|
String mnemonic,
|
|
|
|
String name,
|
2023-09-26 23:26:28 +00:00
|
|
|
}) data,
|
|
|
|
) async {
|
|
|
|
return lib_epiccash.recoverWallet(
|
|
|
|
data.config,
|
|
|
|
data.password,
|
|
|
|
data.mnemonic,
|
|
|
|
data.name,
|
2023-09-20 14:12:48 +00:00
|
|
|
);
|
2023-09-26 15:36:21 +00:00
|
|
|
}
|
2023-09-20 14:12:48 +00:00
|
|
|
|
2023-09-26 15:36:21 +00:00
|
|
|
///
|
|
|
|
/// Recover an Epic wallet using a mnemonic
|
|
|
|
///
|
2023-09-26 23:26:28 +00:00
|
|
|
static Future<void> recoverWallet(
|
|
|
|
{required String config,
|
|
|
|
required String password,
|
|
|
|
required String mnemonic,
|
|
|
|
required String name}) async {
|
2023-09-26 15:36:21 +00:00
|
|
|
try {
|
|
|
|
await compute(_recoverWalletWrapper, (
|
2023-09-26 23:26:28 +00:00
|
|
|
config: config,
|
|
|
|
password: password,
|
|
|
|
mnemonic: mnemonic,
|
|
|
|
name: name,
|
2023-09-26 15:36:21 +00:00
|
|
|
));
|
|
|
|
} catch (e) {
|
2023-09-26 23:26:28 +00:00
|
|
|
throw ("Error recovering wallet : ${e.toString()}");
|
2023-09-26 15:36:21 +00:00
|
|
|
}
|
2023-09-20 14:12:48 +00:00
|
|
|
}
|
2023-09-27 22:47:26 +00:00
|
|
|
|
|
|
|
///
|
|
|
|
/// Private function wrapper for delete wallet function
|
|
|
|
///
|
|
|
|
static Future<String> _deleteWalletWrapper(
|
|
|
|
({
|
|
|
|
String wallet,
|
|
|
|
String config,
|
|
|
|
}) data,
|
|
|
|
) async {
|
|
|
|
return lib_epiccash.deleteWallet(
|
|
|
|
data.wallet,
|
|
|
|
data.config,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Delete an Epic wallet
|
|
|
|
///
|
|
|
|
static Future<String> deleteWallet({
|
|
|
|
required String wallet,
|
|
|
|
required String config,
|
|
|
|
}) async {
|
|
|
|
try {
|
|
|
|
return await compute(_deleteWalletWrapper, (
|
|
|
|
wallet: wallet,
|
|
|
|
config: config,
|
|
|
|
));
|
|
|
|
} catch (e) {
|
|
|
|
throw ("Error deleting wallet : ${e.toString()}");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Private function wrapper for open wallet function
|
|
|
|
///
|
|
|
|
static Future<String> _openWalletWrapper(
|
|
|
|
({
|
|
|
|
String config,
|
|
|
|
String password,
|
|
|
|
}) data,
|
|
|
|
) async {
|
|
|
|
return lib_epiccash.openWallet(
|
|
|
|
data.config,
|
|
|
|
data.password,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Open an Epic wallet
|
|
|
|
///
|
|
|
|
static Future<String> openWallet({
|
|
|
|
required String config,
|
|
|
|
required String password,
|
|
|
|
}) async {
|
|
|
|
try {
|
|
|
|
return await compute(_openWalletWrapper, (
|
|
|
|
config: config,
|
|
|
|
password: password,
|
|
|
|
));
|
|
|
|
} catch (e) {
|
|
|
|
throw ("Error opening wallet : ${e.toString()}");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Private function for txHttpSend function
|
|
|
|
///
|
|
|
|
static Future<String> _txHttpSendWrapper(
|
|
|
|
({
|
|
|
|
String wallet,
|
|
|
|
int selectionStrategyIsAll,
|
|
|
|
int minimumConfirmations,
|
|
|
|
String message,
|
|
|
|
int amount,
|
|
|
|
String address,
|
|
|
|
}) data,
|
|
|
|
) async {
|
|
|
|
return lib_epiccash.txHttpSend(
|
|
|
|
data.wallet,
|
|
|
|
data.selectionStrategyIsAll,
|
|
|
|
data.minimumConfirmations,
|
|
|
|
data.message,
|
|
|
|
data.amount,
|
|
|
|
data.address,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
static Future<String> txHttpSend({
|
|
|
|
required String wallet,
|
|
|
|
required int selectionStrategyIsAll,
|
|
|
|
required int minimumConfirmations,
|
|
|
|
required String message,
|
|
|
|
required int amount,
|
|
|
|
required String address,
|
|
|
|
}) async {
|
|
|
|
try {
|
|
|
|
return await compute(_txHttpSendWrapper, (
|
|
|
|
wallet: wallet,
|
|
|
|
selectionStrategyIsAll: selectionStrategyIsAll,
|
|
|
|
minimumConfirmations: minimumConfirmations,
|
|
|
|
message: message,
|
|
|
|
amount: amount,
|
|
|
|
address: address,
|
|
|
|
));
|
|
|
|
} catch (e) {
|
|
|
|
throw ("Error sending tx HTTP : ${e.toString()}");
|
|
|
|
}
|
|
|
|
}
|
2023-09-18 21:56:57 +00:00
|
|
|
}
|