What changed, and why it matters
This commit is a code cleanup/refactor for the Epic Cash wallet integration. It replaces direct use of a specific library object with a generic 'dynamic object' wrapper and changes how the wallet is passed around. There is no clear security bug introduced or fixed in the visible diff. The change removes storing a raw wallet handle in secure storage, which could be a minor hardening improvement, but the commit message does not frame it as a security fix.
Treat as a routine refactor. Review the DynamicObject implementation for type safety and ensure the wrapper does not weaken encapsulation or introduce unsafe casting. Verify that removal of the secure-storage wallet handle does not break recovery or deletion flows on existing installs. No immediate security response is indicated by this commit alone.
Security signals we found
Removed storage of raw native wallet handle in secure storage
Changed wallet deletion to operate on the in-memory wallet object rather than a stored string handle
Refactored native interface to use a DynamicObject wrapper instead of raw library type
No explicit security claim in commit title or message
Evidence from the diff
The commit refactors the Epic Cash (epiccash) wallet implementation to wrap the native EpicWallet in a DynamicObject abstraction. It updates EpiccashWallet to hold DynamicObject? _wallet instead of epic.EpicWallet? _wallet, and routes calls through a generated libEpic interface. The interface signatures change from passing String wallet (a handle) to passing DynamicObject wallet. The commit also removes several writes/reads of the raw wallet handle to/from secure storage (${walletId}_wallet). The deleteEpicWallet helper now takes the EpiccashWallet object and uses its internal _wallet dynamic object. Listener management is also moved from static/global methods to instance methods on the wrapped wallet. No explicit vulnerability fix or security-relevant behavior is described in the commit message.
Changed components
lib/wallets/wallet/impl/epiccash_wallet.dartlib/services/wallets.dartlib/wl_gen/interfaces/libepiccash_interface.darttool/wl_templates/EPIC_libepiccash_interface_impl.template.dartcrypto_plugins/flutter_libepiccashInspect captured patch +196 / −205
diff --git a/lib/services/wallets.dart b/lib/services/wallets.dart
index d802842..e1d3814 100644
--- a/lib/services/wallets.dart
+++ b/lib/services/wallets.dart
@@ -126,13 +126,21 @@ class Wallets {
if (info.coin is CryptonoteCurrency) {
await _deleteCryptonoteWalletFilesHelper(info);
} else if (info.coin is Epiccash) {
- final deleteResult = await deleteEpicWallet(
- walletId: walletId,
- secureStore: secureStorage,
- );
- Logging.instance.d(
- "epic wallet: $walletId deleted with result: $deleteResult",
- );
+ if (wallet is! EpiccashWallet) {
+ Logging.instance.e(
+ "epic wallet: $walletId does not appear to exist???",
+ error: Exception(),
+ stackTrace: StackTrace.current,
+ );
+ } else {
+ final deleteResult = await deleteEpicWallet(
+ wallet: wallet,
+ secureStore: secureStorage,
+ );
+ Logging.instance.d(
+ "epic wallet: $walletId deleted with result: $deleteResult",
+ );
+ }
} else if (info.coin is Mimblewimblecoin) {
final deleteResult = await deleteMimblewimblecoinWallet(
walletId: walletId,
diff --git a/lib/wallets/wallet/impl/epiccash_wallet.dart b/lib/wallets/wallet/impl/epiccash_wallet.dart
index e600900..4def973 100644
--- a/lib/wallets/wallet/impl/epiccash_wallet.dart
+++ b/lib/wallets/wallet/impl/epiccash_wallet.dart
@@ -28,6 +28,7 @@ import '../../../services/event_bus/events/global/wallet_sync_status_changed_eve
import '../../../services/event_bus/global_event_bus.dart';
import '../../../utilities/amount/amount.dart';
import '../../../utilities/default_epicboxes.dart';
+import '../../../utilities/dynamic_object.dart';
import '../../../utilities/flutter_secure_storage_interface.dart';
import '../../../utilities/logger.dart';
import '../../../utilities/stack_file_system.dart';
@@ -39,8 +40,6 @@ import '../../models/tx_data.dart';
import '../intermediate/bip39_wallet.dart';
import '../supporting/epiccash_wallet_info_extension.dart';
-import 'package:flutter_libepiccash/flutter_libepiccash.dart' as epic;
-
//
// refactor of https://github.com/cypherstack/stack_wallet/blob/1d9fb4cd069f22492ece690ac788e05b8f8b1209/lib/services/coins/epiccash/epiccash_wallet.dart
//
@@ -51,7 +50,7 @@ class EpiccashWallet extends Bip39Wallet {
NodeModel? _epicNode;
Timer? timer;
- epic.EpicWallet? _wallet;
+ DynamicObject? _wallet;
double highestPercent = 0;
Future<double> get getSyncPercent async {
@@ -78,7 +77,7 @@ class EpiccashWallet extends Bip39Wallet {
Future<void> open() async {
if (_wallet != null) {
Logging.instance.d("Wallet already open, ensuring listener");
- if (!await _wallet!.isEpicboxListenerRunning()) {
+ if (!await libEpic.isEpicboxListenerRunning(wallet: _wallet!)) {
await _listenToEpicbox();
}
return;
@@ -95,21 +94,17 @@ class EpiccashWallet extends Bip39Wallet {
final epicboxConfig = await getEpicBoxConfig();
- _wallet = await epic.EpicWallet.load(
+ _wallet = await libEpic.openWallet(
config: config,
password: password,
epicboxConfig: epicboxConfig.toString(),
);
- // Store wallet handle
- await secureStorageInterface.write(
- key: '${walletId}_wallet',
- value: _wallet!.handle,
- );
-
await _listenToEpicbox();
- Logging.instance.d("Epic wallet opened successfully with persistent isolate");
+ Logging.instance.d(
+ "Epic wallet opened successfully with persistent isolate",
+ );
} catch (e, s) {
Logging.instance.e("Failed to open Epic wallet", error: e, stackTrace: s);
_wallet = null;
@@ -128,7 +123,7 @@ class EpiccashWallet extends Bip39Wallet {
key: '${walletId}_epicboxConfig',
value: stringConfig,
);
- _wallet?.updateEpicboxConfig(stringConfig);
+ libEpic.updateEpicboxConfig(wallet: _wallet!, epicBoxConfig: stringConfig);
// TODO: refresh anything that needs to be refreshed/updated due to epicbox info changed
}
@@ -140,7 +135,8 @@ class EpiccashWallet extends Bip39Wallet {
throw Exception('Wallet not initialized');
}
- final result = await _wallet!.cancelTransaction(
+ final result = await libEpic.cancelTransaction(
+ wallet: _wallet!,
transactionId: txSlateId,
);
Logging.instance.d("cancel $txSlateId result: $result");
@@ -158,7 +154,8 @@ class EpiccashWallet extends Bip39Wallet {
//Get the default Epicbox server and check if it's conected
// bool isEpicboxConnected = await _testEpicboxServer(
- // DefaultEpicBoxes.defaultEpicBoxServer.host, DefaultEpicBoxes.defaultEpicBoxServer.port ?? 443);
+ // DefaultEpicBoxes.defaultEpicBoxServer.host,
+ // DefaultEpicBoxes.defaultEpicBoxServer.port ?? 443);
// if (isEpicboxConnected) {
//Use default server for as Epicbox config
@@ -205,7 +202,8 @@ class EpiccashWallet extends Bip39Wallet {
throw Exception('Wallet not opened. Call open() first.');
}
// Create transaction with returnSlate: true for slatepack mode.
- final result = await _wallet!.createTransaction(
+ final result = await libEpic.createTransaction(
+ wallet: _wallet!,
amount: amount.raw.toInt(),
address: 'slate', // Not used in slate mode.
secretKeyIndex: 0,
@@ -286,7 +284,8 @@ class EpiccashWallet extends Bip39Wallet {
}
// Receive and get updated slate JSON.
- final received = await _wallet!.txReceive(
+ final received = await libEpic.txReceive(
+ wallet: _wallet!,
slateJson: slateJson,
);
@@ -313,7 +312,8 @@ class EpiccashWallet extends Bip39Wallet {
}
// Finalize transaction.
- final finalized = await _wallet!.txFinalize(
+ final finalized = await libEpic.txFinalize(
+ wallet: _wallet!,
slateJson: slateJson,
);
@@ -374,7 +374,8 @@ class EpiccashWallet extends Bip39Wallet {
type = 'Incoming'; // Response slate - this means we're receiving.
} else if (signedParticipants >= participants.length) {
status = 'S3';
- type = 'Outgoing'; // Finalized slate - completed outgoing transaction.
+ type =
+ 'Outgoing'; // Finalized slate - completed outgoing transaction.
}
}
@@ -420,7 +421,8 @@ class EpiccashWallet extends Bip39Wallet {
// Check for common slate fields.
return parsed is Map &&
(parsed.containsKey('id') || parsed.containsKey('slate_id')) &&
- (parsed.containsKey('amount') || parsed.containsKey('participant_data'));
+ (parsed.containsKey('amount') ||
+ parsed.containsKey('participant_data'));
} catch (e) {
return false;
}
@@ -483,9 +485,9 @@ class EpiccashWallet extends Bip39Wallet {
}
try {
_hackedCheckTorNodePrefs();
- final available = info.cachedBalance.spendable.raw.toInt();
- final transactionFees = await _wallet!.getTransactionFees(
+ final transactionFees = await libEpic.getTransactionFees(
+ wallet: _wallet!,
amount: satoshiAmount,
minimumConfirmations: cryptoCurrency.minConfirms,
);
@@ -515,8 +517,9 @@ class EpiccashWallet extends Bip39Wallet {
const int refreshFromNode = 1;
if (!syncMutex.isLocked) {
await syncMutex.protect(() async {
- // How does getWalletBalances start syncing????
- await _wallet!.getBalances(
+ // How does getWalletBalances start syncing?????????!!!!!
+ await libEpic.getWalletBalances(
+ wallet: _wallet!,
refreshFromNode: refreshFromNode,
minimumConfirmations: 10,
);
@@ -540,10 +543,11 @@ class EpiccashWallet extends Bip39Wallet {
throw Exception('Wallet not opened. Call open() first.');
}
const refreshFromNode = 0;
- return (await _wallet!.getBalances(
+ return (await libEpic.getWalletBalances(
+ wallet: _wallet!,
refreshFromNode: refreshFromNode,
minimumConfirmations: cryptoCurrency.minConfirms,
- )).toRecord();
+ ));
}
Future<bool> _testEpicboxServer(EpicBoxConfigModel epicboxConfig) async {
@@ -603,7 +607,8 @@ class EpiccashWallet extends Bip39Wallet {
try {
final int receivingIndex = info.epicData!.receivingIndex;
// TODO: go through pendingarray and processed array and choose the index
- // of the last one that has not been processed, or the index after the one most recently processed;
+ // of the last one that has not been processed, or the index after the
+ // one most recently processed;
return receivingIndex;
} catch (e, s) {
Logging.instance.e("$e $s", error: e, stackTrace: s);
@@ -639,8 +644,10 @@ class EpiccashWallet extends Bip39Wallet {
throw Exception('Wallet not opened. Call open() first.');
}
- final walletAddress = await _wallet!.getAddressInfo(
+ final walletAddress = await libEpic.getAddressInfo(
+ wallet: _wallet!,
index: index,
+ epicboxConfig: epicboxConfig.toString(),
);
Logging.instance.d("WALLET_ADDRESS_IS $walletAddress");
@@ -677,7 +684,7 @@ class EpiccashWallet extends Bip39Wallet {
final needsScanning = lastScannedBlock < chainHeight;
if (needsScanning) {
// Stop listener during active scanning to avoid potential conflicts
- await _wallet!.stopListeners();
+ await libEpic.stopEpicboxListener(wallet: _wallet!);
}
// loop while scanning in chain in chunks (of blocks?)
@@ -686,7 +693,8 @@ class EpiccashWallet extends Bip39Wallet {
"chainHeight: $chainHeight, lastScannedBlock: $lastScannedBlock",
);
- final int nextScannedBlock = await _wallet!.scanOutputs(
+ final int nextScannedBlock = await libEpic.scanOutputs(
+ wallet: _wallet!,
startHeight: lastScannedBlock,
numberOfBlocks: scanChunkSize,
);
@@ -710,7 +718,7 @@ class EpiccashWallet extends Bip39Wallet {
// Ensure listener is running after refresh.
// Use health check to verify the Rust listener task is actually alive,
// not just that we have a pointer (which could be stale).
- if (!await _wallet!.isEpicboxListenerRunning()) {
+ if (!await libEpic.isEpicboxListenerRunning(wallet: _wallet!)) {
Logging.instance.d("Listener not running, starting it...");
await _listenToEpicbox();
} else {
@@ -728,8 +736,11 @@ class EpiccashWallet extends Bip39Wallet {
if (_wallet == null) {
throw Exception('Wallet not opened. Call open() first.');
}
- _wallet!.updateEpicboxConfig(epicboxConfig.toString());
- await _wallet!.startListeners();
+ libEpic.updateEpicboxConfig(
+ wallet: _wallet!,
+ epicBoxConfig: epicboxConfig.toString(),
+ );
+ await libEpic.startEpicboxListener(wallet: _wallet!);
}
// As opposed to fake config?
@@ -829,12 +840,8 @@ class EpiccashWallet extends Bip39Wallet {
}
if (isRestore != true) {
- String? encodedWallet = await secureStorageInterface.read(
- key: "${walletId}_wallet",
- );
-
// check if should create a new wallet
- if (encodedWallet == null) {
+ if (_wallet == null) {
await updateNode();
final mnemonicString = await getMnemonic();
@@ -857,21 +864,14 @@ class EpiccashWallet extends Bip39Wallet {
final String name = walletId;
- _wallet = await epic.EpicWallet.create(
+ _wallet = await libEpic.initializeNewWallet(
config: stringConfig,
mnemonic: mnemonicString,
password: password,
name: name,
- epicboxConfig: epicboxConfig.toString(),
+ epicBoxConfig: epicboxConfig.toString(),
); // Spawns worker isolate
- // Store the wallet handle for listeners
- encodedWallet = _wallet!.handle;
- await secureStorageInterface.write(
- key: '${walletId}_wallet',
- value: encodedWallet,
- );
-
//Store Epic box address info
await _generateAndStoreReceivingAddressForIndex(0);
@@ -908,18 +908,12 @@ class EpiccashWallet extends Bip39Wallet {
);
final epicboxConfig = await getEpicBoxConfig();
- _wallet = await epic.EpicWallet.load(
+ _wallet = await libEpic.openWallet(
config: config,
password: password!,
epicboxConfig: epicboxConfig.toString(),
); // Spawns worker isolate
- // Store the wallet handle for listeners
- await secureStorageInterface.write(
- key: '${walletId}_wallet',
- value: _wallet!.handle,
- );
-
await updateNode();
await _listenToEpicbox();
@@ -959,7 +953,8 @@ class EpiccashWallet extends Bip39Wallet {
if (receiverAddress.startsWith("http://") ||
receiverAddress.startsWith("https://")) {
- final httpResult = await _wallet!.txHttpSend(
+ final httpResult = await libEpic.txHttpSend(
+ wallet: _wallet!,
selectionStrategyIsAll: 0,
minimumConfirmations: cryptoCurrency.minConfirms,
message: txData.noteOnChain ?? "",
@@ -972,22 +967,23 @@ class EpiccashWallet extends Bip39Wallet {
slateJson: '',
);
} else {
- transaction = (await _wallet!.createTransaction(
+ transaction = (await libEpic.createTransaction(
+ wallet: _wallet!,
amount: txData.recipients!.first.amount.raw.toInt(),
address: txData.recipients!.first.address,
secretKeyIndex: 0,
minimumConfirmations: cryptoCurrency.minConfirms,
note: txData.noteOnChain!,
- )).toRecord();
+ ));
}
final Map<String, String> txAddressInfo = {};
txAddressInfo['from'] = (await getCurrentReceivingAddress())!.value;
txAddressInfo['to'] = txData.recipients!.first.address;
- await _putSendToAddresses(
- (commitId: transaction.commitId, slateId: transaction.slateId),
- txAddressInfo,
- );
+ await _putSendToAddresses((
+ commitId: transaction.commitId,
+ slateId: transaction.slateId,
+ ), txAddressInfo);
return txData.copyWith(txid: transaction.slateId);
} catch (e, s) {
@@ -1112,29 +1108,23 @@ class EpiccashWallet extends Bip39Wallet {
// maybe there is some way to tel epic-wallet rust to fully rescan...
final result = await deleteEpicWallet(
- walletId: walletId,
+ wallet: this,
secureStore: secureStorageInterface,
);
Logging.instance.w("Epic rescan temporary delete result: $result");
// Close old wallet before recovery
if (_wallet != null) {
- await _wallet!.close();
+ await libEpic.close(wallet: _wallet!);
_wallet = null;
}
- _wallet = await epic.EpicWallet.recover(
+ _wallet = await libEpic.recoverWallet(
config: stringConfig,
password: password!,
mnemonic: await getMnemonic(),
name: info.walletId,
- epicboxConfig: epicboxConfig.toString(),
- );
-
- // Save wallet handle after recovery
- await secureStorageInterface.write(
- key: '${walletId}_wallet',
- value: _wallet!.handle,
+ epicBoxConfig: epicboxConfig.toString(),
);
await _listenToEpicbox();
@@ -1163,22 +1153,16 @@ class EpiccashWallet extends Bip39Wallet {
// Close old wallet before recovery
if (_wallet != null) {
- await _wallet!.close();
+ await libEpic.close(wallet: _wallet!);
_wallet = null;
}
- _wallet = await epic.EpicWallet.recover(
+ _wallet = await libEpic.recoverWallet(
config: stringConfig,
password: password,
mnemonic: await getMnemonic(),
name: info.walletId,
- epicboxConfig: epicboxConfig.toString(),
- );
-
- // Save wallet handle after recovery
- await secureStorageInterface.write(
- key: '${walletId}_wallet',
- value: _wallet!.handle,
+ epicBoxConfig: epicboxConfig.toString(),
);
await _listenToEpicbox();
@@ -1306,7 +1290,8 @@ class EpiccashWallet extends Bip39Wallet {
// chain height check currently broken
// if ((await chainHeight) != (await storedChainHeight)) {
- // TODO: [prio=med] some kind of quick check if wallet needs to refresh to replace the old refreshIfThereIsNewData call
+ // TODO: [prio=med] some kind of quick check if wallet needs to
+ // refresh to replace the old refreshIfThereIsNewData call
// if (await refreshIfThereIsNewData()) {
unawaited(refresh());
@@ -1391,7 +1376,8 @@ class EpiccashWallet extends Bip39Wallet {
.findAll();
final myAddressesSet = myAddresses.toSet();
- final transactions = await _wallet!.getTransactions(
+ final transactions = await libEpic.getTransactions(
+ wallet: _wallet!,
refreshFromNode: refreshFromNode,
);
@@ -1405,8 +1391,8 @@ class EpiccashWallet extends Bip39Wallet {
libEpic.txTypeIsReceiveCancelled(tx.txType);
final slateId = tx.txSlateId;
final commitId = slatesToCommits[slateId]?['commitId'] as String?;
- final numberOfMessages = tx.messages?.messages.length;
- final onChainNote = tx.messages?.messages.first.message;
+ final numberOfMessages = tx.messages?.length;
+ final onChainNote = tx.messages?.first.message;
final addressFrom = slatesToCommits[slateId]?["from"] as String?;
final addressTo = slatesToCommits[slateId]?["to"] as String?;
@@ -1449,7 +1435,8 @@ class EpiccashWallet extends Bip39Wallet {
output = output.copyWith(
addresses: [
myAddressesSet
- .first, // Must be changed if we ever do more than a single wallet address!!!
+ .first, // Must be changed if we ever do more than a single
+ // wallet address!!!
],
walletOwns: true,
);
@@ -1575,7 +1562,8 @@ class EpiccashWallet extends Bip39Wallet {
Future<void> updateNode() async {
_epicNode = getCurrentNode();
- // TODO: [prio=low] move this out of secure storage if secure storage not needed
+ // TODO: [prio=low] move this out of secure storage if secure storage not
+ // needed
final String stringConfig = await _getConfig();
await secureStorageInterface.write(
key: '${walletId}_config',
@@ -1623,7 +1611,8 @@ class EpiccashWallet extends Bip39Wallet {
@override
Future<Amount> estimateFeeFor(Amount amount, BigInt feeRate) async {
_hackedCheckTorNodePrefs();
- // setting ifErrorEstimateFee doesn't do anything as its not used in the nativeFee function?????
+ // setting ifErrorEstimateFee doesn't do anything as its not used in the
+ // nativeFee function?????
final int currentFee = await _nativeFee(
amount.raw.toInt(),
ifErrorEstimateFee: true,
@@ -1656,7 +1645,7 @@ class EpiccashWallet extends Bip39Wallet {
@override
Future<void> exit() async {
- await _wallet?.stopListeners();
+ if (_wallet != null) await libEpic.stopEpicboxListener(wallet: _wallet!);
timer?.cancel();
timer = null;
@@ -1688,16 +1677,15 @@ class EpiccashWallet extends Bip39Wallet {
}
Future<String> deleteEpicWallet({
- required String walletId,
+ required EpiccashWallet wallet,
required SecureStorageInterface secureStore,
}) async {
- final wallet = await secureStore.read(key: '${walletId}_wallet');
- String? config = await secureStore.read(key: '${walletId}_config');
+ String? config = await secureStore.read(key: '${wallet.walletId}_config');
if (Platform.isIOS) {
final Directory appDir = await StackFileSystem.applicationRootDirectory();
final path = "${appDir.path}/epiccash";
- final String name = walletId.trim();
+ final String name = wallet.walletId.trim();
final walletDir = '$path/$name';
final editConfig = jsonDecode(config as String);
@@ -1706,14 +1694,15 @@ Future<String> deleteEpicWallet({
config = jsonEncode(editConfig);
}
- if (wallet == null) {
- return "Tried to delete non existent epic wallet file with walletId=$walletId";
+ if (config == null) {
+ return "Tried to delete non existent epic wallet file with"
+ " walletId=${wallet.walletId}";
} else {
try {
- return libEpic.deleteWallet(wallet: wallet, config: config!);
+ return libEpic.deleteWallet(wallet: wallet._wallet!, config: config);
} catch (e, s) {
Logging.instance.e("$e\n$s", error: e, stackTrace: s);
- return "deleteEpicWallet($walletId) failed...";
+ return "deleteEpicWallet(${wallet.walletId}) failed...";
}
}
}
diff --git a/lib/wl_gen/interfaces/libepiccash_interface.dart b/lib/wl_gen/interfaces/libepiccash_interface.dart
index ac69b05..f0402ed 100644
--- a/lib/wl_gen/interfaces/libepiccash_interface.dart
+++ b/lib/wl_gen/interfaces/libepiccash_interface.dart
@@ -11,11 +11,12 @@ abstract class LibEpicCashInterface {
bool txTypeIsReceiveCancelled(Enum value);
bool txTypeIsSentCancelled(Enum value);
- Future<String> initializeNewWallet({
+ Future<DynamicObject> initializeNewWallet({
required String config,
required String mnemonic,
required String password,
required String name,
+ required String epicBoxConfig,
});
Future<DynamicObject> openWallet({
@@ -24,15 +25,16 @@ abstract class LibEpicCashInterface {
required String epicboxConfig,
});
- Future<void> recoverWallet({
+ Future<DynamicObject> recoverWallet({
required String config,
required String password,
required String mnemonic,
required String name,
+ required String epicBoxConfig,
});
Future<({String commitId, String slateId})> txHttpSend({
- required String wallet,
+ required DynamicObject wallet,
required int selectionStrategyIsAll,
required int minimumConfirmations,
required String message,
@@ -42,57 +44,47 @@ abstract class LibEpicCashInterface {
Future<({String commitId, String slateId, String slateJson})>
createTransaction({
- required String wallet,
+ required DynamicObject wallet,
required int amount,
required String address,
required int secretKeyIndex,
- required String epicboxConfig,
required int minimumConfirmations,
required String note,
bool returnSlate = false,
});
Future<({String slateId, String commitId, String slateJson})> txReceive({
- required String wallet,
+ required DynamicObject wallet,
required String slateJson,
});
- Future<({String slateId, String commitId})> txFinalize({
- required String wallet,
+ Future<({String slateId, String commitId, String slateJson})> txFinalize({
+ required DynamicObject wallet,
required String slateJson,
});
Future<String> cancelTransaction({
- required String wallet,
+ required DynamicObject wallet,
required String transactionId,
});
Future<List<EpicTransaction>> getTransactions({
- required String wallet,
+ required DynamicObject wallet,
required int refreshFromNode,
});
- void startEpicboxListener({
- required String walletId,
- required String wallet,
- required String epicboxConfig,
- });
-
- void stopEpicboxListener({required String walletId});
-
- void stopAllEpicboxListeners();
+ Future<void> startEpicboxListener({required DynamicObject wallet});
- bool isEpicboxListenerRunning({required String walletId});
+ Future<void> stopEpicboxListener({required DynamicObject wallet});
- List<String> getActiveListenerWalletIds();
+ Future<bool> isEpicboxListenerRunning({required DynamicObject wallet});
Future<bool> validateSendAddress({required String address});
Future<({int fee, bool strategyUseAll, int total})> getTransactionFees({
- required String wallet,
+ required DynamicObject wallet,
required int amount,
required int minimumConfirmations,
- required int available,
});
Future<
@@ -104,26 +96,36 @@ abstract class LibEpicCashInterface {
})
>
getWalletBalances({
- required String wallet,
+ required DynamicObject wallet,
required int refreshFromNode,
required int minimumConfirmations,
});
Future<String> getAddressInfo({
- required String wallet,
+ required DynamicObject wallet,
required int index,
required String epicboxConfig,
});
Future<int> scanOutputs({
- required String wallet,
+ required DynamicObject wallet,
required int startHeight,
required int numberOfBlocks,
});
Future<int> getChainHeight({required String config});
- Future<String> deleteWallet({required String wallet, required String config});
+ Future<void> close({required DynamicObject wallet});
+
+ Future<String> deleteWallet({
+ required DynamicObject wallet,
+ required String config,
+ });
+
+ void updateEpicboxConfig({
+ required DynamicObject wallet,
+ required String epicBoxConfig,
+ });
String getPluginVersion();
}
diff --git a/tool/wl_templates/EPIC_libepiccash_interface_impl.template.dart b/tool/wl_templates/EPIC_libepiccash_interface_impl.template.dart
index e8c67c9..b3a49c1 100644
--- a/tool/wl_templates/EPIC_libepiccash_interface_impl.template.dart
+++ b/tool/wl_templates/EPIC_libepiccash_interface_impl.template.dart
@@ -21,74 +21,78 @@ final class _LibEpicCashInterfaceImpl extends LibEpicCashInterface {
@override
Future<String> cancelTransaction({
- required String wallet,
+ required DynamicObject wallet,
required String transactionId,
}) {
- return LibEpiccash.cancelTransaction(
- wallet: wallet,
+ return wallet.get<EpicWallet>().cancelTransaction(
transactionId: transactionId,
);
}
@override
Future<({String slateId, String commitId, String slateJson})> txReceive({
- required String wallet,
+ required DynamicObject wallet,
required String slateJson,
- }) {
- return LibEpiccash.txReceive(wallet: wallet, slateJson: slateJson);
+ }) async {
+ return (await wallet.get<EpicWallet>().txReceive(
+ slateJson: slateJson,
+ )).toRecord();
}
@override
- Future<({String slateId, String commitId})> txFinalize({
- required String wallet,
+ Future<({String slateId, String commitId, String slateJson})> txFinalize({
+ required DynamicObject wallet,
required String slateJson,
- }) {
- return LibEpiccash.txFinalize(wallet: wallet, slateJson: slateJson);
+ }) async {
+ return (await wallet.get<EpicWallet>().txFinalize(
+ slateJson: slateJson,
+ )).toRecord();
}
@override
Future<({String commitId, String slateId, String slateJson})>
createTransaction({
- required String wallet,
+ required DynamicObject wallet,
required int amount,
required String address,
required int secretKeyIndex,
- required String epicboxConfig,
required int minimumConfirmations,
required String note,
bool returnSlate = false,
- }) {
- return LibEpiccash.createTransaction(
- wallet: wallet,
+ }) async {
+ return (await wallet.get<EpicWallet>().createTransaction(
amount: amount,
address: address,
secretKeyIndex: secretKeyIndex,
- epicboxConfig: epicboxConfig,
minimumConfirmations: minimumConfirmations,
note: note,
returnSlate: returnSlate,
- );
+ )).toRecord();
+ }
+
+ @override
+ void updateEpicboxConfig({
+ required DynamicObject wallet,
+ required String epicBoxConfig,
+ }) {
+ return wallet.get<EpicWallet>().updateEpicboxConfig(epicBoxConfig);
}
@override
Future<String> deleteWallet({
- required String wallet,
+ required DynamicObject wallet,
required String config,
}) {
- return LibEpiccash.deleteWallet(wallet: wallet, config: config);
+ return wallet.get<EpicWallet>().deleteWallet(config: config);
}
@override
Future<String> getAddressInfo({
- required String wallet,
+ required DynamicObject wallet,
required int index,
required String epicboxConfig,
}) {
- return LibEpiccash.getAddressInfo(
- wallet: wallet,
- index: index,
- epicboxConfig: epicboxConfig,
- );
+ return wallet.get<EpicWallet>().getAddressInfo(index: index);
}
@override
@@ -98,26 +102,22 @@ final class _LibEpicCashInterfaceImpl extends LibEpicCashInterface {
@override
Future<({int fee, bool strategyUseAll, int total})> getTransactionFees({
- required String wallet,
+ required DynamicObject wallet,
required int amount,
required int minimumConfirmations,
- required int available,
}) {
- return LibEpiccash.getTransactionFees(
- wallet: wallet,
+ return wallet.get<EpicWallet>().getTransactionFees(
amount: amount,
minimumConfirmations: minimumConfirmations,
- available: available,
);
}
@override
Future<List<EpicTransaction>> getTransactions({
- required String wallet,
+ required DynamicObject wallet,
required int refreshFromNode,
}) async {
- final transactions = await LibEpiccash.getTransactions(
- wallet: wallet,
+ final transactions = await wallet.get<EpicWallet>().getTransactions(
refreshFromNode: refreshFromNode,
);
@@ -166,30 +166,33 @@ final class _LibEpicCashInterfaceImpl extends LibEpicCashInterface {
})
>
getWalletBalances({
- required String wallet,
+ required DynamicObject wallet,
required int refreshFromNode,
required int minimumConfirmations,
}) {
- return LibEpiccash.getWalletBalances(
- wallet: wallet,
+ return wallet.get<EpicWallet>().getBalancesRecord(
refreshFromNode: refreshFromNode,
minimumConfirmations: minimumConfirmations,
);
}
@override
- Future<String> initializeNewWallet({
+ Future<DynamicObject> initializeNewWallet({
required String config,
required String mnemonic,
required String password,
required String name,
- }) {
- return LibEpiccash.initializeNewWallet(
+ required String epicBoxConfig,
+ }) async {
+ final wallet = await EpicWallet.create(
config: config,
mnemonic: mnemonic,
password: password,
name: name,
+ epicboxConfig: epicBoxConfig,
);
+
+ return DynamicObject(wallet);
}
@override
@@ -208,69 +211,54 @@ final class _LibEpicCashInterfaceImpl extends LibEpicCashInterface {
}
@override
- Future<void> recoverWallet({
+ Future<DynamicObject> recoverWallet({
required String config,
required String password,
required String mnemonic,
required String name,
- }) {
- return LibEpiccash.recoverWallet(
+ required String epicBoxConfig,
+ }) async {
+ final wallet = EpicWallet.recover(
config: config,
password: password,
mnemonic: mnemonic,
name: name,
+ epicboxConfig: epicBoxConfig,
);
+
+ return DynamicObject(wallet);
}
@override
Future<int> scanOutputs({
- required String wallet,
+ required DynamicObject wallet,
required int startHeight,
required int numberOfBlocks,
}) {
- return LibEpiccash.scanOutputs(
- wallet: wallet,
+ return wallet.get<EpicWallet>().scanOutputs(
startHeight: startHeight,
numberOfBlocks: numberOfBlocks,
);
}
@override
- void startEpicboxListener({
- required String walletId,
- required String wallet,
- required String epicboxConfig,
- }) {
- return LibEpiccash.startEpicboxListener(
- walletId: walletId,
- wallet: wallet,
- epicboxConfig: epicboxConfig,
- );
- }
-
- @override
- void stopEpicboxListener({required String walletId}) {
- return LibEpiccash.stopEpicboxListener(walletId: walletId);
+ Future<void> startEpicboxListener({required DynamicObject wallet}) {
+ return wallet.get<EpicWallet>().startListener();
}
@override
- void stopAllEpicboxListeners() {
- return LibEpiccash.stopAllEpicboxListeners();
+ Future<void> stopEpicboxListener({required DynamicObject wallet}) {
+ return wallet.get<EpicWallet>().stopListener();
}
@override
- bool isEpicboxListenerRunning({required String walletId}) {
- return LibEpiccash.isEpicboxListenerRunning(walletId: walletId);
- }
-
- @override
- List<String> getActiveListenerWalletIds() {
- return LibEpiccash.getActiveListenerWalletIds();
+ Future<bool> isEpicboxListenerRunning({required DynamicObject wallet}) {
+ return wallet.get<EpicWallet>().isEpicboxListenerRunning();
}
@override
Future<({String commitId, String slateId})> txHttpSend({
- required String wallet,
+ required DynamicObject wallet,
required int selectionStrategyIsAll,
required int minimumConfirmations,
required String message,
@@ -278,8 +266,7 @@ final class _LibEpicCashInterfaceImpl extends LibEpicCashInterface {
required String address,
}) {
try {
- return LibEpiccash.txHttpSend(
- wallet: wallet,
+ return wallet.get<EpicWallet>().txHttpSend(
selectionStrategyIsAll: selectionStrategyIsAll,
minimumConfirmations: minimumConfirmations,
message: message,
@@ -307,8 +294,13 @@ final class _LibEpicCashInterfaceImpl extends LibEpicCashInterface {
}
@override
- bool validateSendAddress({required String address}) {
- return LibEpiccash.validateSendAddress(address: address);
+ Future<bool> validateSendAddress({required String address}) {
+ return EpicWallet.validateSendAddress(address: address);
+ }
+
+ @override
+ Future<void> close({required DynamicObject wallet}) {
+ return wallet.get<EpicWallet>().close();
}
@override
Why this scored 27/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.