refactor: use Option<String> for SendResult.transaction_id

This commit is contained in:
Forte11Cuba
2026-04-01 20:14:11 -06:00
parent 362e45e40f
commit 588a127f9a
5 changed files with 41 additions and 25 deletions
+29 -16
View File
@@ -987,15 +987,21 @@ class WalletProvider extends ChangeNotifier {
// Save token metadata using the deterministic transaction ID returned by CDK
// (SHA-256 of sorted proof Y values — no racy listTransactions needed)
if (result.transactionId.isNotEmpty) {
await _txMetaStorage.save(
result.transactionId,
TransactionMeta(
type: TransactionType.cashu,
token: result.token.encoded,
),
);
debugPrint('Token guardado para tx ${result.transactionId}');
// Best-effort: don't fail the send if metadata persistence fails
final txId = result.transactionId;
if (txId != null && txId.isNotEmpty) {
try {
await _txMetaStorage.save(
txId,
TransactionMeta(
type: TransactionType.cashu,
token: result.token.encoded,
),
);
debugPrint('Token guardado para tx $txId');
} catch (e) {
debugPrint('Error guardando send metadata: $e');
}
}
notifyListeners();
@@ -1124,7 +1130,7 @@ class WalletProvider extends ChangeNotifier {
amount: amount,
description: description,
).listen(
(quote) {
(quote) async {
// Guardar invoice temprano en SharedPreferences
if (quote.state == MintQuoteState.unpaid) {
invoiceBolt11 = quote.request;
@@ -1133,8 +1139,10 @@ class WalletProvider extends ChangeNotifier {
// Cuando se completa, guardar metadata, confetti, limpiar pending
if (quote.state == MintQuoteState.issued && invoiceBolt11 != null) {
_saveMintMetadata(wallet, invoiceBolt11!, quote.transactionId);
_removePendingMintInvoice(quote.id);
final saved = await _saveMintMetadata(wallet, invoiceBolt11!, quote.transactionId);
// Only remove pending invoice if metadata was saved;
// otherwise _matchPendingMintInvoices can recover it on next startup
if (saved) _removePendingMintInvoice(quote.id);
}
// Reenviar a la UI (si sigue escuchando)
@@ -1368,8 +1376,8 @@ class WalletProvider extends ChangeNotifier {
}
/// Guarda metadata para una transacción de mint (Lightning deposit).
/// Uses the deterministic transaction ID from CDK when available.
Future<void> _saveMintMetadata(Wallet wallet, String invoice, String? transactionId) async {
/// Returns true if metadata was actually saved.
Future<bool> _saveMintMetadata(Wallet wallet, String invoice, String? transactionId) async {
try {
if (transactionId != null && transactionId.isNotEmpty) {
await _txMetaStorage.save(
@@ -1380,13 +1388,18 @@ class WalletProvider extends ChangeNotifier {
),
);
debugPrint('Mint metadata guardada para tx $transactionId');
confettiController.fire();
notifyListeners();
return true;
} else {
debugPrint('Mint metadata: no transaction ID available');
confettiController.fire();
notifyListeners();
return false;
}
confettiController.fire();
notifyListeners();
} catch (e) {
debugPrint('Error guardando mint metadata: $e');
return false;
}
}
+4 -2
View File
@@ -271,9 +271,11 @@ class SendOptions {
/// listTransactions lookup.
class SendResult {
final Token token;
final String transactionId;
const SendResult({required this.token, required this.transactionId});
/// Deterministic transaction ID (None if computation failed)
final String? transactionId;
const SendResult({required this.token, this.transactionId});
@override
int get hashCode => token.hashCode ^ transactionId.hashCode;
+3 -3
View File
@@ -3298,7 +3298,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
throw Exception('unexpected arr length: expect 2 but see ${arr.length}');
return SendResult(
token: dco_decode_token(arr[0]),
transactionId: dco_decode_String(arr[1]),
transactionId: dco_decode_opt_String(arr[1]),
);
}
@@ -4398,7 +4398,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
SendResult sse_decode_send_result(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
var var_token = sse_decode_token(deserializer);
var var_transactionId = sse_decode_String(deserializer);
var var_transactionId = sse_decode_opt_String(deserializer);
return SendResult(token: var_token, transactionId: var_transactionId);
}
@@ -5493,7 +5493,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
void sse_encode_send_result(SendResult self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
sse_encode_token(self.token, serializer);
sse_encode_String(self.transactionId, serializer);
sse_encode_opt_String(self.transactionId, serializer);
}
@protected
+3 -2
View File
@@ -158,7 +158,7 @@ impl Wallet {
let proofs = cdk_token.proofs(&keysets)?;
let tx_id = TransactionId::try_from(proofs)
.map(|id| id.to_string())
.unwrap_or_default();
.ok();
let token_str = cdk_token.to_string();
self.update_balance_streams().await;
@@ -500,7 +500,8 @@ impl Wallet {
/// listTransactions lookup.
pub struct SendResult {
pub token: Token,
pub transaction_id: String,
/// Deterministic transaction ID (None if computation failed)
pub transaction_id: Option<String>,
}
pub struct MintQuote {
+2 -2
View File
@@ -3954,7 +3954,7 @@ impl SseDecode for crate::api::wallet::SendResult {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
let mut var_token = <crate::api::token::Token>::sse_decode(deserializer);
let mut var_transactionId = <String>::sse_decode(deserializer);
let mut var_transactionId = <Option<String>>::sse_decode(deserializer);
return crate::api::wallet::SendResult {
token: var_token,
transaction_id: var_transactionId,
@@ -5609,7 +5609,7 @@ impl SseEncode for crate::api::wallet::SendResult {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
<crate::api::token::Token>::sse_encode(self.token, serializer);
<String>::sse_encode(self.transaction_id, serializer);
<Option<String>>::sse_encode(self.transaction_id, serializer);
}
}