Merge pull request #677 from cypherstack/wallets-refactor-epic

Wallets refactor epic
This commit is contained in:
julian-CStack 2023-10-06 09:08:40 -06:00 committed by GitHub
commit 4973447703
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 1089 additions and 626 deletions

View file

@ -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)";

View 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>

View 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

View file

@ -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;
}
}

View file

@ -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()}");
}
}
}

View file

@ -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>