mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-11 13:14:32 +00:00
Merge pull request #677 from cypherstack/wallets-refactor-epic
Wallets refactor epic
This commit is contained in:
commit
4973447703
7 changed files with 1089 additions and 626 deletions
|
@ -61,6 +61,7 @@
|
|||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
B999088F2ABE1E170012A442 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||
E6F536731AC506735EB76340 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
|
@ -140,6 +141,7 @@
|
|||
97C146F01CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B999088F2ABE1E170012A442 /* Runner.entitlements */,
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||
|
@ -321,8 +323,8 @@
|
|||
"${BUILT_PRODUCTS_DIR}/package_info_plus/package_info_plus.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/path_provider_foundation/path_provider_foundation.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/share_plus/share_plus.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/shared_preferences_foundation/shared_preferences_foundation.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/stack_wallet_backup/stack_wallet_backup.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/tor_ffi_plugin/tor_ffi_plugin.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/url_launcher_ios/url_launcher_ios.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/wakelock/wakelock.framework",
|
||||
);
|
||||
|
@ -354,8 +356,8 @@
|
|||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info_plus.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_foundation.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/share_plus.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences_foundation.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/stack_wallet_backup.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/tor_ffi_plugin.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher_ios.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/wakelock.framework",
|
||||
);
|
||||
|
@ -455,6 +457,7 @@
|
|||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
|
@ -645,6 +648,7 @@
|
|||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
|
@ -727,6 +731,7 @@
|
|||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
|
|
10
ios/Runner/Runner.entitlements
Normal file
10
ios/Runner/Runner.entitlements
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
119
lib/models/isar/models/blockchain_data/epic_transaction.dart
Normal file
119
lib/models/isar/models/blockchain_data/epic_transaction.dart
Normal file
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* This file is part of Stack Wallet.
|
||||
*
|
||||
* Copyright (c) 2023 Cypher Stack
|
||||
* All Rights Reserved.
|
||||
* The code is distributed under GPLv3 license, see LICENSE file for details.
|
||||
* Generated by Cypher Stack on 2023-10-03
|
||||
*
|
||||
*/
|
||||
|
||||
class EpicTransaction {
|
||||
final String parentKeyId;
|
||||
final int id;
|
||||
final String? txSlateId;
|
||||
final EpicTransactionType txType;
|
||||
final String creationTs;
|
||||
final String confirmationTs;
|
||||
final bool confirmed;
|
||||
final int numInputs;
|
||||
final int numOutputs;
|
||||
final String amountCredited;
|
||||
final String amountDebited;
|
||||
final String? fee;
|
||||
final String? ttlCutoffHeight;
|
||||
final Messages? messages;
|
||||
final String? storedTx;
|
||||
final String? kernelExcess;
|
||||
final int? kernelLookupMinHeight;
|
||||
final String? paymentProof;
|
||||
|
||||
EpicTransaction({
|
||||
required this.parentKeyId,
|
||||
required this.id,
|
||||
this.txSlateId,
|
||||
required this.txType,
|
||||
required this.creationTs,
|
||||
required this.confirmationTs,
|
||||
required this.confirmed,
|
||||
required this.numInputs,
|
||||
required this.numOutputs,
|
||||
required this.amountCredited,
|
||||
required this.amountDebited,
|
||||
this.fee,
|
||||
this.ttlCutoffHeight,
|
||||
this.messages,
|
||||
this.storedTx,
|
||||
this.kernelExcess,
|
||||
this.kernelLookupMinHeight,
|
||||
this.paymentProof,
|
||||
});
|
||||
|
||||
factory EpicTransaction.fromJson(dynamic json) {
|
||||
// print("THIS JSON IS $json")
|
||||
return EpicTransaction(
|
||||
parentKeyId: json['parent_key_id'] as String,
|
||||
id: int.parse(json!['id'].toString()),
|
||||
txSlateId: json['tx_slate_id'].toString(),
|
||||
txType: EpicTransactionType.values.byName(json['tx_type'] as String),
|
||||
creationTs: json['creation_ts'].toString(),
|
||||
confirmationTs: json['confirmation_ts'].toString(),
|
||||
confirmed: bool.parse(json['confirmed'].toString()),
|
||||
numInputs: int.parse(json['num_inputs'].toString()),
|
||||
numOutputs: int.parse(json['num_outputs'].toString()),
|
||||
amountCredited: json['amount_credited'].toString(),
|
||||
amountDebited: json['amount_debited'].toString(),
|
||||
fee: json['fee'].toString(),
|
||||
ttlCutoffHeight: json['ttl_cutoff_height'].toString(),
|
||||
messages: json['messages'] != null ? Messages.fromJson(json['messages'] as Map<String, dynamic>) : null,
|
||||
storedTx: json['stored_tx'].toString(),
|
||||
kernelExcess: json['kernel_excess'].toString(),
|
||||
kernelLookupMinHeight: json['kernel_lookup_min_height'] == null? null : int.parse(json['kernel_lookup_min_height'].toString()),
|
||||
paymentProof: json['payment_proof'].toString(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Messages {
|
||||
final List<Message> messages;
|
||||
|
||||
Messages({required this.messages});
|
||||
|
||||
factory Messages.fromJson(Map<String, dynamic> json) {
|
||||
final messageList = json['messages'] as List<dynamic>;
|
||||
final messages = messageList.map((message) => Message.fromJson(message as Map<String, dynamic>)).toList();
|
||||
return Messages(messages: messages);
|
||||
}
|
||||
}
|
||||
|
||||
class Message {
|
||||
final String id;
|
||||
final String publicKey;
|
||||
final String? message;
|
||||
final String? messageSig;
|
||||
|
||||
Message({
|
||||
required this.id,
|
||||
required this.publicKey,
|
||||
this.message,
|
||||
this.messageSig,
|
||||
});
|
||||
|
||||
factory Message.fromJson(Map<String, dynamic> json) {
|
||||
return Message(
|
||||
id: json['id'].toString(),
|
||||
publicKey: json['public_key'].toString(),
|
||||
message: json['message'].toString(),
|
||||
messageSig: json['message_sig'].toString(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum EpicTransactionType {
|
||||
//Use Epic transaction type here
|
||||
TxReceived,
|
||||
TxReceivedCancelled,
|
||||
TxSent,
|
||||
TxSentCancelled, // should we keep this?
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -32,4 +32,201 @@ class Epiccash extends Bip39Currency {
|
|||
|
||||
return LibEpiccash.validateSendAddress(address: address);
|
||||
}
|
||||
|
||||
String getMnemonic() {
|
||||
return LibEpiccash.getMnemonic();
|
||||
}
|
||||
|
||||
Future<String?> createNewWallet(
|
||||
({
|
||||
String config,
|
||||
String mnemonic,
|
||||
String password,
|
||||
String name,
|
||||
})? data) async {
|
||||
String result = await LibEpiccash.initializeNewWallet(
|
||||
config: data!.config,
|
||||
mnemonic: data.mnemonic,
|
||||
password: data.password,
|
||||
name: data.name);
|
||||
|
||||
if (result.isNotEmpty) {
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<({double awaitingFinalization, double pending, double spendable, double total})>
|
||||
getWalletInfo(
|
||||
({
|
||||
String wallet,
|
||||
int refreshFromNode,
|
||||
})? data) async {
|
||||
var result = await LibEpiccash.getWalletBalances(
|
||||
wallet: data!.wallet,
|
||||
refreshFromNode: data.refreshFromNode,
|
||||
minimumConfirmations: minConfirms);
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<String?> scanOutputs(
|
||||
({String wallet, int startHeight, int numberOfBlocks})? data) async {
|
||||
var result = await LibEpiccash.scanOutputs(
|
||||
wallet: data!.wallet,
|
||||
startHeight: data.startHeight,
|
||||
numberOfBlocks: data.numberOfBlocks,
|
||||
);
|
||||
|
||||
if (result.isNotEmpty) {
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<String?> createTransaction(
|
||||
({
|
||||
String wallet,
|
||||
int amount,
|
||||
String address,
|
||||
int secretKey,
|
||||
String epicboxConfig,
|
||||
String note,
|
||||
})? data) async {
|
||||
var result = await LibEpiccash.createTransaction(
|
||||
wallet: data!.wallet,
|
||||
amount: data.amount,
|
||||
address: data.address,
|
||||
secretKey: data.secretKey,
|
||||
epicboxConfig: data.epicboxConfig,
|
||||
minimumConfirmations: minConfirms,
|
||||
note: data.note,
|
||||
);
|
||||
|
||||
if (result.isNotEmpty) {
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<String?> getTransaction(
|
||||
({
|
||||
String wallet,
|
||||
int refreshFromNode,
|
||||
})? data) async {
|
||||
var result = await LibEpiccash.getTransaction(
|
||||
wallet: data!.wallet,
|
||||
refreshFromNode: data.refreshFromNode,
|
||||
);
|
||||
|
||||
if (result.isNotEmpty) {
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<String?> cancelTransaction(
|
||||
({
|
||||
String wallet,
|
||||
String transactionId,
|
||||
})? data) async {
|
||||
var result = await LibEpiccash.cancelTransaction(
|
||||
wallet: data!.wallet,
|
||||
transactionId: data.transactionId,
|
||||
);
|
||||
|
||||
if (result.isNotEmpty) {
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<String?> getAddressInfo(
|
||||
({
|
||||
String wallet,
|
||||
int index,
|
||||
String epicboxConfig,
|
||||
})? data) async {
|
||||
var result = await LibEpiccash.getAddressInfo(
|
||||
wallet: data!.wallet,
|
||||
index: data.index,
|
||||
epicboxConfig: data.epicboxConfig,
|
||||
);
|
||||
|
||||
if (result.isNotEmpty) {
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<({int fee, bool strategyUseAll, int total})> transactionFees(
|
||||
({
|
||||
String wallet,
|
||||
int amount,
|
||||
int availableAmount,
|
||||
})? data,
|
||||
) async {
|
||||
var result = await LibEpiccash.getTransactionFees(
|
||||
wallet: data!.wallet,
|
||||
amount: data.amount,
|
||||
minimumConfirmations: minConfirms,
|
||||
available: data.availableAmount,
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<String?> deleteWallet(
|
||||
({
|
||||
String wallet,
|
||||
String config,
|
||||
})? data,
|
||||
) async {
|
||||
var result = await LibEpiccash.deleteWallet(
|
||||
wallet: data!.wallet,
|
||||
config: data.config,
|
||||
);
|
||||
if (result.isNotEmpty) {
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<String?> openWallet(
|
||||
({
|
||||
String config,
|
||||
String password,
|
||||
})? data,
|
||||
) async {
|
||||
var result = await LibEpiccash.openWallet(
|
||||
config: data!.config,
|
||||
password: data.password,
|
||||
);
|
||||
if (result.isNotEmpty) {
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<String?> txHttpSend(
|
||||
({
|
||||
String wallet,
|
||||
int selectionStrategyIsAll,
|
||||
int minimumConfirmations,
|
||||
String message,
|
||||
int amount,
|
||||
String address,
|
||||
})? data,
|
||||
) async {
|
||||
var result = await LibEpiccash.txHttpSend(
|
||||
wallet: data!.wallet,
|
||||
selectionStrategyIsAll: data.selectionStrategyIsAll,
|
||||
minimumConfirmations: data.minimumConfirmations,
|
||||
message: data.message,
|
||||
amount: data.amount,
|
||||
address: data.address,
|
||||
);
|
||||
if (result.isNotEmpty) {
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_libepiccash/epic_cash.dart' as lib_epiccash;
|
||||
import 'package:mutex/mutex.dart';
|
||||
import 'package:stackwallet/models/isar/models/blockchain_data/epic_transaction.dart';
|
||||
|
||||
///
|
||||
/// Wrapped up calls to flutter_libepiccash.
|
||||
|
@ -6,6 +12,11 @@ import 'package:flutter_libepiccash/epic_cash.dart' as lib_epiccash;
|
|||
/// Should all be static calls (no state stored in this class)
|
||||
///
|
||||
abstract class LibEpiccash {
|
||||
static final Mutex _mutex = Mutex();
|
||||
|
||||
///
|
||||
/// Check if [address] is a valid epiccash address according to libepiccash
|
||||
///
|
||||
static bool validateSendAddress({required String address}) {
|
||||
final String validate = lib_epiccash.validateSendAddress(address);
|
||||
if (int.parse(validate) == 1) {
|
||||
|
@ -18,4 +29,606 @@ abstract class LibEpiccash {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Fetch the mnemonic For a new wallet (Only used in the example app)
|
||||
///
|
||||
// TODO: ensure the above documentation comment is correct
|
||||
// TODO: ensure this will always return the mnemonic. If not, this function should throw an exception
|
||||
//Function is used in _getMnemonicList()
|
||||
static String getMnemonic() {
|
||||
try {
|
||||
String mnemonic = lib_epiccash.walletMnemonic();
|
||||
if (mnemonic.isEmpty) {
|
||||
throw Exception("Error getting mnemonic, returned empty string");
|
||||
}
|
||||
return mnemonic;
|
||||
} catch (e) {
|
||||
throw Exception(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// Private function wrapper for compute
|
||||
static Future<String> _initializeWalletWrapper(
|
||||
({
|
||||
String config,
|
||||
String mnemonic,
|
||||
String password,
|
||||
String name,
|
||||
}) data,
|
||||
) async {
|
||||
final String initWalletStr = lib_epiccash.initWallet(
|
||||
data.config,
|
||||
data.mnemonic,
|
||||
data.password,
|
||||
data.name,
|
||||
);
|
||||
return initWalletStr;
|
||||
}
|
||||
|
||||
///
|
||||
/// Create a new epiccash wallet.
|
||||
///
|
||||
// TODO: Complete/modify the documentation comment above
|
||||
// TODO: Should return a void future. On error this function should throw and exception
|
||||
static Future<String> initializeNewWallet({
|
||||
required String config,
|
||||
required String mnemonic,
|
||||
required String password,
|
||||
required String name,
|
||||
}) async {
|
||||
try {
|
||||
return await compute(
|
||||
_initializeWalletWrapper,
|
||||
(
|
||||
config: config,
|
||||
mnemonic: mnemonic,
|
||||
password: password,
|
||||
name: name,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
throw ("Error creating new wallet : ${e.toString()}");
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Private function wrapper for wallet balances
|
||||
///
|
||||
static Future<String> _walletBalancesWrapper(
|
||||
({String wallet, int refreshFromNode, int minimumConfirmations}) data,
|
||||
) async {
|
||||
return lib_epiccash.getWalletInfo(
|
||||
data.wallet, data.refreshFromNode, data.minimumConfirmations);
|
||||
}
|
||||
|
||||
///
|
||||
/// Get balance information for the currently open wallet
|
||||
///
|
||||
static Future<
|
||||
({
|
||||
double awaitingFinalization,
|
||||
double pending,
|
||||
double spendable,
|
||||
double total
|
||||
})>
|
||||
getWalletBalances(
|
||||
{required String wallet,
|
||||
required int refreshFromNode,
|
||||
required int minimumConfirmations}) async {
|
||||
try {
|
||||
String balances = await compute(_walletBalancesWrapper, (
|
||||
wallet: wallet,
|
||||
refreshFromNode: refreshFromNode,
|
||||
minimumConfirmations: minimumConfirmations,
|
||||
));
|
||||
|
||||
//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
|
||||
({
|
||||
double spendable,
|
||||
double pending,
|
||||
double total,
|
||||
double awaitingFinalization
|
||||
}) balancesRecord = (
|
||||
spendable: jsonBalances['amount_currently_spendable'],
|
||||
pending: jsonBalances['amount_awaiting_finalization'],
|
||||
total: jsonBalances['total'],
|
||||
awaitingFinalization: jsonBalances['amount_awaiting_finalization'],
|
||||
);
|
||||
return balancesRecord;
|
||||
} 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
|
||||
///
|
||||
static Future<String> scanOutputs({
|
||||
required String wallet,
|
||||
required int startHeight,
|
||||
required int numberOfBlocks,
|
||||
}) async {
|
||||
try {
|
||||
return await compute(_scanOutputsWrapper, (
|
||||
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 secretKeyIndex,
|
||||
String epicboxConfig,
|
||||
int minimumConfirmations,
|
||||
String note,
|
||||
}) data,
|
||||
) async {
|
||||
return lib_epiccash.createTransaction(
|
||||
data.wallet,
|
||||
data.amount,
|
||||
data.address,
|
||||
data.secretKeyIndex,
|
||||
data.epicboxConfig,
|
||||
data.minimumConfirmations,
|
||||
data.note);
|
||||
}
|
||||
|
||||
///
|
||||
/// Create an Epic transaction
|
||||
///
|
||||
static Future<({String slateId, String commitId})> createTransaction({
|
||||
required String wallet,
|
||||
required int amount,
|
||||
required String address,
|
||||
required int secretKeyIndex,
|
||||
required String epicboxConfig,
|
||||
required int minimumConfirmations,
|
||||
required String note,
|
||||
}) async {
|
||||
try {
|
||||
String result = await compute(_createTransactionWrapper, (
|
||||
wallet: wallet,
|
||||
amount: amount,
|
||||
address: address,
|
||||
secretKeyIndex: secretKeyIndex,
|
||||
epicboxConfig: epicboxConfig,
|
||||
minimumConfirmations: minimumConfirmations,
|
||||
note: note,
|
||||
));
|
||||
|
||||
if (result.toUpperCase().contains("ERROR")) {
|
||||
throw Exception("Error creating transaction ${result.toString()}");
|
||||
}
|
||||
|
||||
//Decode sent tx and return Slate Id
|
||||
final slate0 = jsonDecode(result);
|
||||
final slate = jsonDecode(slate0[0] as String);
|
||||
final part1 = jsonDecode(slate[0] as String);
|
||||
final part2 = jsonDecode(slate[1] as String);
|
||||
|
||||
({String slateId, String commitId}) data = (
|
||||
slateId: part1[0]['tx_slate_id'],
|
||||
commitId: part2['tx']['body']['outputs'][0]['commit'],
|
||||
);
|
||||
|
||||
return data;
|
||||
} 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,
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
static Future<List<EpicTransaction>> getTransactions({
|
||||
required String wallet,
|
||||
required int refreshFromNode,
|
||||
}) async {
|
||||
try {
|
||||
var result = await compute(_getTransactionsWrapper, (
|
||||
wallet: wallet,
|
||||
refreshFromNode: refreshFromNode,
|
||||
));
|
||||
|
||||
if (result.toUpperCase().contains("ERROR")) {
|
||||
throw Exception("Error getting epic transactions ${result.toString()}");
|
||||
}
|
||||
|
||||
//Parse the returned data as an EpicTransaction
|
||||
List<EpicTransaction> finalResult = [];
|
||||
var jsonResult = json.decode(result) as List;
|
||||
|
||||
for (var tx in jsonResult) {
|
||||
EpicTransaction itemTx = EpicTransaction.fromJson(tx);
|
||||
finalResult.add(itemTx);
|
||||
}
|
||||
return finalResult;
|
||||
} catch (e) {
|
||||
throw ("Error getting epic transactions : ${e.toString()}");
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Private function for cancel transaction function
|
||||
///
|
||||
static Future<String> _cancelTransactionWrapper(
|
||||
({
|
||||
String wallet,
|
||||
String transactionId,
|
||||
}) data,
|
||||
) async {
|
||||
return lib_epiccash.cancelTransaction(
|
||||
data.wallet,
|
||||
data.transactionId,
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Cancel current Epic transaction
|
||||
///
|
||||
static Future<String> cancelTransaction({
|
||||
required String wallet,
|
||||
required String transactionId,
|
||||
}) async {
|
||||
try {
|
||||
return await compute(_cancelTransactionWrapper, (
|
||||
wallet: wallet,
|
||||
transactionId: transactionId,
|
||||
));
|
||||
} catch (e) {
|
||||
throw ("Error canceling epic transaction : ${e.toString()}");
|
||||
}
|
||||
}
|
||||
|
||||
static Future<int> _chainHeightWrapper(
|
||||
({
|
||||
String config,
|
||||
}) data,
|
||||
) async {
|
||||
return lib_epiccash.getChainHeight(data.config);
|
||||
}
|
||||
|
||||
static Future<int> getChainHeight({
|
||||
required String config,
|
||||
}) async {
|
||||
try {
|
||||
return await compute(_chainHeightWrapper, (config: config,));
|
||||
} catch (e) {
|
||||
throw ("Error getting chain height : ${e.toString()}");
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Private function for address info function
|
||||
///
|
||||
static Future<String> _addressInfoWrapper(
|
||||
({
|
||||
String wallet,
|
||||
int index,
|
||||
String epicboxConfig,
|
||||
}) data,
|
||||
) async {
|
||||
return lib_epiccash.getAddressInfo(
|
||||
data.wallet,
|
||||
data.index,
|
||||
data.epicboxConfig,
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// get Epic address info
|
||||
///
|
||||
static Future<String> getAddressInfo({
|
||||
required String wallet,
|
||||
required int index,
|
||||
required String epicboxConfig,
|
||||
}) async {
|
||||
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<({int fee, bool strategyUseAll, int total})>
|
||||
getTransactionFees({
|
||||
required String wallet,
|
||||
required int amount,
|
||||
required int minimumConfirmations,
|
||||
required int available,
|
||||
}) async {
|
||||
try {
|
||||
String fees = await compute(_transactionFeesWrapper, (
|
||||
wallet: wallet,
|
||||
amount: amount,
|
||||
minimumConfirmations: minimumConfirmations,
|
||||
));
|
||||
|
||||
if (available == amount) {
|
||||
if (fees.contains("Required")) {
|
||||
var splits = fees.split(" ");
|
||||
Decimal required = Decimal.zero;
|
||||
Decimal available = Decimal.zero;
|
||||
for (int i = 0; i < splits.length; i++) {
|
||||
var word = splits[i];
|
||||
if (word == "Required:") {
|
||||
required = Decimal.parse(splits[i + 1].replaceAll(",", ""));
|
||||
} else if (word == "Available:") {
|
||||
available = Decimal.parse(splits[i + 1].replaceAll(",", ""));
|
||||
}
|
||||
}
|
||||
int largestSatoshiFee =
|
||||
((required - available) * Decimal.fromInt(100000000))
|
||||
.toBigInt()
|
||||
.toInt();
|
||||
var amountSending = amount - largestSatoshiFee;
|
||||
//Get fees for this new amount
|
||||
({
|
||||
String wallet,
|
||||
int amount,
|
||||
}) data = (wallet: wallet, amount: amountSending);
|
||||
fees = await compute(_transactionFeesWrapper, (
|
||||
wallet: wallet,
|
||||
amount: amountSending,
|
||||
minimumConfirmations: minimumConfirmations,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if (fees.toUpperCase().contains("ERROR")) {
|
||||
//Check if the error is an
|
||||
//Throw the returned error
|
||||
throw Exception(fees);
|
||||
}
|
||||
var decodedFees = json.decode(fees);
|
||||
var feeItem = decodedFees[0];
|
||||
({
|
||||
bool strategyUseAll,
|
||||
int total,
|
||||
int fee,
|
||||
}) feeRecord = (
|
||||
strategyUseAll: feeItem['selection_strategy_is_use_all'],
|
||||
total: feeItem['total'],
|
||||
fee: feeItem['fee'],
|
||||
);
|
||||
return feeRecord;
|
||||
} catch (e) {
|
||||
throw (e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Private function wrapper for recover wallet function
|
||||
///
|
||||
static Future<String> _recoverWalletWrapper(
|
||||
({
|
||||
String config,
|
||||
String password,
|
||||
String mnemonic,
|
||||
String name,
|
||||
}) data,
|
||||
) async {
|
||||
return lib_epiccash.recoverWallet(
|
||||
data.config,
|
||||
data.password,
|
||||
data.mnemonic,
|
||||
data.name,
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Recover an Epic wallet using a mnemonic
|
||||
///
|
||||
static Future<void> recoverWallet(
|
||||
{required String config,
|
||||
required String password,
|
||||
required String mnemonic,
|
||||
required String name}) async {
|
||||
try {
|
||||
await compute(_recoverWalletWrapper, (
|
||||
config: config,
|
||||
password: password,
|
||||
mnemonic: mnemonic,
|
||||
name: name,
|
||||
));
|
||||
} catch (e) {
|
||||
throw (e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// 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 commitId, String slateId})> txHttpSend({
|
||||
required String wallet,
|
||||
required int selectionStrategyIsAll,
|
||||
required int minimumConfirmations,
|
||||
required String message,
|
||||
required int amount,
|
||||
required String address,
|
||||
}) async {
|
||||
try {
|
||||
var result = await compute(_txHttpSendWrapper, (
|
||||
wallet: wallet,
|
||||
selectionStrategyIsAll: selectionStrategyIsAll,
|
||||
minimumConfirmations: minimumConfirmations,
|
||||
message: message,
|
||||
amount: amount,
|
||||
address: address,
|
||||
));
|
||||
if (result.toUpperCase().contains("ERROR")) {
|
||||
throw Exception("Error creating transaction ${result.toString()}");
|
||||
}
|
||||
|
||||
//Decode sent tx and return Slate Id
|
||||
final slate0 = jsonDecode(result);
|
||||
final slate = jsonDecode(slate0[0] as String);
|
||||
final part1 = jsonDecode(slate[0] as String);
|
||||
final part2 = jsonDecode(slate[1] as String);
|
||||
|
||||
({String slateId, String commitId}) data = (
|
||||
slateId: part1[0]['tx_slate_id'],
|
||||
commitId: part2['tx']['body']['outputs'][0]['commit'],
|
||||
);
|
||||
|
||||
return data;
|
||||
} catch (e) {
|
||||
throw ("Error sending tx HTTP : ${e.toString()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
</dict>
|
||||
|
|
Loading…
Reference in a new issue