Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
[submodule "crypto_plugins/flutter_libepiccash"]
path = crypto_plugins/flutter_libepiccash
url = https://github.com/cypherstack/flutter_libepiccash.git
[submodule "crypto_plugins/frostdart"]
path = crypto_plugins/frostdart
url = https://github.com/cypherstack/frostdart
[submodule "crypto_plugins/flutter_libmwc"]
path = crypto_plugins/flutter_libmwc
url = https://github.com/cypherstack/flutter_libmwc
[submodule "crypto_plugins/flutter_libepiccash"]
path = crypto_plugins/flutter_libepiccash
url = https://github.com/who-biz/flutter_libepiccash.git
branch = ebox-cancel-tx
2 changes: 2 additions & 0 deletions lib/models/isar/models/blockchain_data/v2/transaction_v2.dart
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ class TransactionV2 {
int? get numberOfMessages =>
_getFromOtherData(key: TxV2OdKeys.numberOfMessages) as int?;
String? get slateId => _getFromOtherData(key: TxV2OdKeys.slateId) as String?;
String? get epicboxId => _getFromOtherData(key: TxV2OdKeys.epicboxId) as String?;
String? get onChainNote =>
_getFromOtherData(key: TxV2OdKeys.onChainNote) as String?;
bool get isCancelled =>
Expand Down Expand Up @@ -409,6 +410,7 @@ abstract final class TxV2OdKeys {
static const isMimblewimblecoinTransaction = "isMimblewimblecoinTransaction";
static const numberOfMessages = "numberOfMessages";
static const slateId = "slateId";
static const epicboxId = "epicboxId";
static const onChainNote = "onChainNote";
static const isCancelled = "isCancelled";
static const contractAddress = "contractAddress";
Expand Down
67 changes: 37 additions & 30 deletions lib/utilities/address_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,45 +44,46 @@ class AddressUtils {
static Map<String, String> _parseUri(String uri) {
final Map<String, String> result = {};
try {
final u = Uri.parse(uri);
if (u.hasScheme) {
result["scheme"] = u.scheme.toLowerCase();
final Uri parsedUri = Uri.parse(uri);

if (parsedUri.hasScheme) {
final String scheme = parsedUri.scheme.toLowerCase();
result["scheme"] = scheme;

// Handle different URI formats.
if (result["scheme"] == "bitcoin" ||
result["scheme"] == "bitcoincash") {
result["address"] = u.path;
result["address"] = parsedUri.path;
} else if (result["scheme"] == "monero") {
// Monero addresses can contain '?' which Uri.parse interprets as query start.
final addressEnd = uri.indexOf(
'?',
7,
); // 7 is the length of "monero:".
if (addressEnd != -1) {
result["address"] = uri.substring(7, addressEnd);
} else {
result["address"] = uri.substring(7);
}
final int addressEnd = uri.indexOf(
"?",
7, // 7 is the length of "monero:".
);
} else {
// Default case, treat path as address.
result["address"] = u.path;
result["address"] = parsedUri.path;
}
} else {
// Plain address, including an Epicbox/Grinbox address containing '@'.
result["address"] = parsedUri.path;
}

// Parse query parameters.
result.addAll(_parseQueryParameters(u.queryParameters));
// Parse query parameters.
result.addAll(_parseQueryParameters(parsedUri.queryParameters));

// Handle Monero-specific fragment (tx_description).
if (u.fragment.isNotEmpty && result["scheme"] == "monero") {
result["tx_description"] = Uri.decodeComponent(u.fragment);
}
// Handle Monero-specific fragment (tx_description).
if (parsedUri.fragment.isNotEmpty && result["scheme"] == "monero") {
result["tx_description"] = Uri.decodeComponent(parsedUri.fragment);
}
} catch (e, s) {
Logging.instance.d(
"Exception caught in parseUri($uri): $e",
"Exception caught in _parseUri($uri): $e",
error: e,
stackTrace: s,
);
}

return result;
}

Expand Down Expand Up @@ -137,6 +138,7 @@ class AddressUtils {
static PaymentUriData? parsePaymentUri(String uri, {Logging? logging}) {
// hacky check its not just a bcash, ecash, or xel address
final parts = uri.split(":");

if (parts.length == 2) {
if ([
"xel",
Expand All @@ -153,20 +155,25 @@ class AddressUtils {
final Map<String, String> parsedData = _parseUri(uri);

// Normalize the URI scheme.
final String scheme = parsedData['scheme'] ?? '';
parsedData.remove('scheme');
final String scheme = parsedData["scheme"] ?? "";
parsedData.remove("scheme");

// Filter out unrecognized parameters.
final filteredParams = _filterParams(parsedData);
final String? address = parsedData["address"];

if (address == null || address.trim().isEmpty) {
return null;
}

final Map<String, String> filteredParams = _filterParams(parsedData);

return PaymentUriData(
scheme: scheme,
address: parsedData['address']!.trim(),
amount: filteredParams['amount'] ?? filteredParams['tx_amount'],
label: filteredParams['label'] ?? filteredParams['recipient_name'],
message: filteredParams['message'] ?? filteredParams['tx_description'],
paymentId: filteredParams['tx_payment_id'],
// Specific to Monero
address: address.trim(),
amount: filteredParams["amount"] ?? filteredParams["tx_amount"],
label: filteredParams["label"] ?? filteredParams["recipient_name"],
message: filteredParams["message"] ?? filteredParams["tx_description"],
paymentId: filteredParams["tx_payment_id"],
additionalParams: filteredParams,
);
} catch (e, s) {
Expand Down
20 changes: 18 additions & 2 deletions lib/wallets/wallet/impl/epiccash_wallet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,12 @@ class EpiccashWallet extends Bip39Wallet {
throw Exception('Wallet not initialized');
}

final result = await libEpic.cancelTransaction(
final epicboxConfig = await getEpicBoxConfig();
final result = await libEpic.cancelEpicboxTransaction(
wallet: _wallet!,
transactionId: txSlateId,
methodIsEpicbox: true,
epicboxConfig: epicboxConfig.toString(),
txSlateId: txSlateId,
);
Logging.instance.d("cancel $txSlateId result: $result");
return result;
Expand Down Expand Up @@ -1386,10 +1389,22 @@ class EpiccashWallet extends Bip39Wallet {
final slatesToCommits = info.epicData?.slatesToCommits ?? {};

for (final tx in transactions) {

Logging.instance.w(
"EPIC TX "
"id=${tx.id} "
"slate=${tx.txSlateId} "
"epicbox_tx_id=${tx.txEpicboxId} "
"type=${tx.txType} "
"sentCancelled=${libEpic.txTypeIsSentCancelled(tx.txType)} "
"receiveCancelled=${libEpic.txTypeIsReceiveCancelled(tx.txType)}",
);

final isIncoming =
libEpic.txTypeIsReceived(tx.txType) ||
libEpic.txTypeIsReceiveCancelled(tx.txType);
final slateId = tx.txSlateId;
final epicboxId = tx.txEpicboxId;
final commitId = slatesToCommits[slateId]?['commitId'] as String?;
final numberOfMessages = tx.messages?.length;
final onChainNote = tx.messages?.first.message;
Expand Down Expand Up @@ -1451,6 +1466,7 @@ class EpiccashWallet extends Bip39Wallet {
"isEpiccashTransaction": true,
"numberOfMessages": numberOfMessages,
"slateId": slateId,
"epicboxId": epicboxId,
"onChainNote": onChainNote,
"isCancelled":
libEpic.txTypeIsSentCancelled(tx.txType) ||
Expand Down
11 changes: 9 additions & 2 deletions lib/wl_gen/interfaces/libepiccash_interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,13 @@ abstract class LibEpicCashInterface {
required String slateJson,
});

Future<String> cancelTransaction({
Future<String> cancelEpicboxTransaction({
required DynamicObject wallet,
required String transactionId,
required bool methodIsEpicbox,
String? epicboxConfig,
int? txId,
String? txSlateId,
String? txEpicboxId,
});

Future<List<EpicTransaction>> getTransactions({
Expand Down Expand Up @@ -135,6 +139,7 @@ class EpicTransaction {
final String parentKeyId;
final int id;
final String? txSlateId;
final String? txEpicboxId;
final Enum txType;
final String creationTs;
final String confirmationTs;
Expand All @@ -155,6 +160,7 @@ class EpicTransaction {
required this.parentKeyId,
required this.id,
this.txSlateId,
this.txEpicboxId,
required this.txType,
required this.creationTs,
required this.confirmationTs,
Expand All @@ -177,6 +183,7 @@ class EpicTransaction {
return 'EpicTransaction('
'id: $id, '
'txSlateId: $txSlateId, '
'txEpicboxId: $txEpicboxId, '
'type: $txType, '
'confirmed: $confirmed, '
'inputs: $numInputs, '
Expand Down
35 changes: 30 additions & 5 deletions tool/wl_templates/EPIC_libepiccash_interface_impl.template.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,25 @@ final class _LibEpicCashInterfaceImpl extends LibEpicCashInterface {
const _LibEpicCashInterfaceImpl();

@override
Future<String> cancelTransaction({
Future<String> cancelEpicboxTransaction({
required DynamicObject wallet,
required String transactionId,
}) {
return wallet.get<EpicWallet>().cancelTransaction(
transactionId: transactionId,
required bool methodIsEpicbox,
String? epicboxConfig,
int? txId,
String? txSlateId,
String? txEpicboxId,
}) async {
final epicWallet = wallet.get<EpicWallet>();

if (epicboxConfig != null) {
epicWallet.updateEpicboxConfig(epicboxConfig);
}

return epicWallet.cancelEpicboxTransaction(
methodIsEpicbox: methodIsEpicbox,
txId: txId,
txSlateId: txSlateId,
txEpicboxId: txEpicboxId,
);
}

Expand Down Expand Up @@ -124,6 +137,17 @@ final class _LibEpicCashInterfaceImpl extends LibEpicCashInterface {
refreshFromNode: refreshFromNode,
);

// Log the flutter_libepiccash Transaction BEFORE converting it.
for (final e in transactions) {
print(
"EPIC INTERFACE TX "
"id=${e.id} "
"txSlateId=${e.txSlateId} "
"txEpicboxId=${e.txEpicboxId} "
"type=${e.txType}",
);
}

return transactions
.map(
(e) => EpicTransaction(
Expand All @@ -138,6 +162,7 @@ final class _LibEpicCashInterfaceImpl extends LibEpicCashInterface {
amountCredited: e.amountCredited,
amountDebited: e.amountDebited,
txSlateId: e.txSlateId,
txEpicboxId: e.txEpicboxId,
fee: e.fee,
ttlCutoffHeight: e.ttlCutoffHeight,
messages: e.messages?.messages
Expand Down