Update `breez_sdk_spark_flutter` to v0.23.0 and adjust pubspec overrides (#3558)
What changed, and why it matters
This commit updates the Breez Lightning SDK used by Cake Wallet from version 0.14.0 to 0.23.0 and tweaks the wallet code to match the new SDK's API. It is a routine dependency upgrade, not a clearly labeled security fix. The update could include bug fixes or security improvements from the upstream SDK, but the commit itself does not describe any specific vulnerability or attack.
Review the upstream Breez SDK v0.23.0 release notes and changelog for security fixes between v0.14.0 and v0.23.0. Verify the pinned git refs in pubspec_overrides.yaml match official signed tags or commits. Test Lightning wallet flows (receive, send, deposit claim/refund) for regressions. Consider whether the old SDK version had known vulnerabilities that prompted the upgrade.
Security signals we found
Dependency version bump of a third-party Lightning SDK (breez_sdk_spark_flutter v0.14.0 -> v0.23.0)
API migration changes in Lightning wallet integration
Added null-safety guard for claimDeposit response payment
No vendor security disclosure or CVE reference present
Evidence from the diff
The diff bumps the breez_sdk_spark_flutter dependency from v0.14.0 to v0.23.0 in both cw_bitcoin/pubspec.yaml and pubspec_overrides.yaml, and refactors cw_bitcoin/lib/lightning/lightning_wallet.dart to align with the newer SDK API. Notable code changes include wrapping raw payment strings in PaymentRequest.input(...), adding a null check on claimDeposit response, making several request objects const, and minor style/constructor reordering. No explicit security bug is fixed or disclosed in the commit message or diff.
Changed components
cw_bitcoin/lib/lightning/lightning_wallet.dartcw_bitcoin/pubspec.yamlpubspec_overrides.yamlBreez Lightning SDK integrationInspect captured patch +73 / −55
diff --git a/cw_bitcoin/lib/lightning/lightning_wallet.dart b/cw_bitcoin/lib/lightning/lightning_wallet.dart
index ea9399c6..49b4979e 100644
--- a/cw_bitcoin/lib/lightning/lightning_wallet.dart
+++ b/cw_bitcoin/lib/lightning/lightning_wallet.dart
@@ -17,6 +17,16 @@ bool _breezSdkSparkLibUninitialized = true;
Stream<LogEntry>? _logStream;
class LightningWallet {
+ LightningWallet({
+ required this.mnemonic,
+ required this.apiKey,
+ required this.lnurlDomain,
+ this.network = Network.mainnet,
+ this.passphrase,
+ this.seedBytes,
+ this.cachedAddress,
+ });
+
final String mnemonic;
final String? passphrase;
final Uint8List? seedBytes;
@@ -29,16 +39,6 @@ class LightningWallet {
static int MAX_RETRIES = 10;
- LightningWallet({
- required this.mnemonic,
- this.passphrase,
- this.seedBytes,
- required this.apiKey,
- required this.lnurlDomain,
- this.network = Network.mainnet,
- this.cachedAddress,
- });
-
static bool get isAvailable => Platform.isIOS || Platform.isAndroid || Platform.isMacOS;
Currency get currency => CryptoCurrency.btcln;
@@ -87,10 +87,11 @@ class LightningWallet {
? Seed.entropy(seedBytes!)
: Seed.mnemonic(mnemonic: mnemonic, passphrase: passphrase);
final config = defaultConfig(network: Network.mainnet).copyWith(
- lnurlDomain: lnurlDomain,
- apiKey: apiKey,
- privateEnabledDefault: true,
- maxDepositClaimFee: MaxFee.rate(satPerVbyte: BigInt.from(5)));
+ lnurlDomain: lnurlDomain,
+ apiKey: apiKey,
+ privateEnabledDefault: true,
+ maxDepositClaimFee: MaxFee.rate(satPerVbyte: BigInt.from(5)),
+ );
final connectRequest = ConnectRequest(
config: config,
@@ -110,7 +111,7 @@ class LightningWallet {
printV(e);
}
- await sdk.syncWallet(request: SyncWalletRequest());
+ await sdk.syncWallet(request: const SyncWalletRequest());
return true;
} catch (e) {
@@ -139,31 +140,33 @@ class LightningWallet {
}
} catch (_) {} // No need to log here since it should be in the lightning log
retries++;
- await Future.delayed(Duration(milliseconds: 500));
+ await Future.delayed(const Duration(milliseconds: 500));
}
return cachedAddress;
}
Future<String> getDepositAddress() async => (await sdk.receivePayment(
- request: ReceivePaymentRequest(paymentMethod: ReceivePaymentMethod.bitcoinAddress())))
- .paymentRequest;
+ request: const ReceivePaymentRequest(paymentMethod: ReceivePaymentMethod.bitcoinAddress()),
+ ))
+ .paymentRequest;
Future<Money> getBalance() async {
try {
- return Money((await sdk.getInfo(request: GetInfoRequest(ensureSynced: true))).balanceSats,
- CryptoCurrency.btcln);
+ return Money(
+ (await sdk.getInfo(request: const GetInfoRequest(ensureSynced: true))).balanceSats,
+ CryptoCurrency.btcln,
+ );
} on SdkError_Generic catch (_) {
} on SdkError_NetworkError catch (_) {}
return Money.zero(CryptoCurrency.btcln);
}
- Future<String> registerAddress(String username) async {
- return (await sdk.registerLightningAddress(
- request: RegisterLightningAddressRequest(username: username)))
- .lightningAddress;
- }
+ Future<String> registerAddress(String username) async => (await sdk.registerLightningAddress(
+ request: RegisterLightningAddressRequest(username: username),
+ ))
+ .lightningAddress;
Future<String?> getBolt11Invoice(BigInt? amount, String description) async {
try {
@@ -180,7 +183,9 @@ class LightningWallet {
} on SdkError_NetworkError catch (_) {
return null;
} on SdkError_SparkError catch (e) {
- if (!e.field0.contains("dns") && !e.field0.contains("TimedOut")) rethrow;
+ if (!e.field0.contains("dns") && !e.field0.contains("TimedOut")) {
+ rethrow;
+ }
return null;
}
}
@@ -196,17 +201,22 @@ class LightningWallet {
}
}
- Future<PendingLightningTransaction> createTransaction(String address, BigInt? amountSats,
- BitcoinTransactionPriority? priority, bool feesIncluded) async {
+ Future<PendingLightningTransaction> createTransaction(
+ String address,
+ BigInt? amountSats,
+ BitcoinTransactionPriority? priority,
+ bool feesIncluded,
+ ) async {
final inputType = await sdk.parse(input: address);
final feePolicy = feesIncluded ? FeePolicy.feesIncluded : FeePolicy.feesExcluded;
if (inputType is InputType_Bolt11Invoice) {
final request = PrepareSendPaymentRequest(
- paymentRequest: inputType.field0.invoice.bolt11,
- amount: amountSats,
- feePolicy: feePolicy);
+ paymentRequest: PaymentRequest.input(input: inputType.field0.invoice.bolt11),
+ amount: amountSats,
+ feePolicy: feePolicy,
+ );
final prepareResponse = await sdk.prepareSendPayment(request: request);
final paymentMethod = prepareResponse.paymentMethod;
@@ -227,7 +237,8 @@ class LightningWallet {
commitOverride: () async {
try {
final res = await sdk.sendPayment(
- request: SendPaymentRequest(prepareResponse: prepareResponse));
+ request: SendPaymentRequest(prepareResponse: prepareResponse),
+ );
printV(res.payment.status.name);
return res.payment.id;
} on SdkError_SparkError catch (e) {
@@ -240,7 +251,7 @@ class LightningWallet {
);
}
} else if (inputType is InputType_LightningAddress || inputType is InputType_LnurlPay) {
- final optionalValidateSuccessActionUrl = true;
+ const optionalValidateSuccessActionUrl = true;
PrepareLnurlPayRequest request;
if (inputType is InputType_LightningAddress) {
@@ -274,7 +285,7 @@ class LightningWallet {
);
} else if (inputType is InputType_BitcoinAddress) {
final request = PrepareSendPaymentRequest(
- paymentRequest: inputType.field0.address,
+ paymentRequest: PaymentRequest.input(input: inputType.field0.address),
amount: amountSats,
feePolicy: feePolicy,
);
@@ -309,7 +320,8 @@ class LightningWallet {
final options =
SendPaymentOptions.bitcoinAddress(confirmationSpeed: onchainConfirmationSpeed);
final res = await sdk.sendPayment(
- request: SendPaymentRequest(prepareResponse: prepareResponse, options: options));
+ request: SendPaymentRequest(prepareResponse: prepareResponse, options: options),
+ );
return res.payment.id;
},
);
@@ -326,7 +338,7 @@ class LightningWallet {
// statusFilter: [PaymentStatus.completed],
fromTimestamp:
fromDate != null ? BigInt.from((fromDate.millisecondsSinceEpoch / 1000).round()) : null,
- assetFilter: AssetFilter.bitcoin(),
+ assetFilter: const AssetFilter.bitcoin(),
offset: 0,
limit: 50,
sortAscending: false, // Sort order (true = oldest first, false = newest first)
@@ -357,7 +369,7 @@ class LightningWallet {
///
Future<List<Map<String, dynamic>>> getUnclaimedDeposits() async {
final unclaimedDeposits = <Map<String, dynamic>>[];
- final response = await sdk.listUnclaimedDeposits(request: ListUnclaimedDepositsRequest());
+ final response = await sdk.listUnclaimedDeposits(request: const ListUnclaimedDepositsRequest());
for (final deposit in response.deposits) {
final unclaimedDeposit = {
"txId": deposit.txid,
@@ -380,7 +392,7 @@ class LightningWallet {
return unclaimedDeposits;
}
- Future<ElectrumTransactionInfo> claimDeposit(String txId, int vout, BigInt newFee) async {
+ Future<ElectrumTransactionInfo?> claimDeposit(String txId, int vout, BigInt newFee) async {
final response = await sdk.claimDeposit(
request: ClaimDepositRequest(
txid: txId,
@@ -389,11 +401,18 @@ class LightningWallet {
),
);
- return _getElectrumTransactionInfoFromPayment(response.payment);
+ if (response.payment == null) {
+ return null;
+ }
+ return _getElectrumTransactionInfoFromPayment(response.payment!);
}
Future<String> refundDeposit(
- String txId, int vout, String destinationAddress, BigInt feeRate) async {
+ String txId,
+ int vout,
+ String destinationAddress,
+ BigInt feeRate,
+ ) async {
final response = await sdk.refundDeposit(
request: RefundDepositRequest(
txid: txId,
@@ -464,17 +483,16 @@ class LightningWallet {
);
}
- ElectrumTransactionInfo _getElectrumTransactionInfoFromDepositInfo(DepositInfo deposit) {
- return ElectrumTransactionInfo(
- WalletType.bitcoin,
- id: deposit.txid,
- amount: Money(deposit.amountSats, currency),
- direction: TransactionDirection.incoming,
- isPending: true,
- fee: Money.zero(currency),
- date: DateTime.now(),
- confirmations: 0,
- additionalInfo: {"isLightning": true, "isSparkDeposit": true},
- );
- }
+ ElectrumTransactionInfo _getElectrumTransactionInfoFromDepositInfo(DepositInfo deposit) =>
+ ElectrumTransactionInfo(
+ WalletType.bitcoin,
+ id: deposit.txid,
+ amount: Money(deposit.amountSats, currency),
+ direction: TransactionDirection.incoming,
+ isPending: true,
+ fee: Money.zero(currency),
+ date: DateTime.now(),
+ confirmations: 0,
+ additionalInfo: {"isLightning": true, "isSparkDeposit": true},
+ );
}
diff --git a/cw_bitcoin/pubspec.yaml b/cw_bitcoin/pubspec.yaml
index 46a8992c..b447dda6 100644
--- a/cw_bitcoin/pubspec.yaml
+++ b/cw_bitcoin/pubspec.yaml
@@ -72,7 +72,7 @@ dependencies:
breez_sdk_spark_flutter:
git:
url: https://github.com/breez/breez-sdk-spark-flutter
- ref: v0.14.0
+ ref: v0.23.0
dev_dependencies:
flutter_test:
diff --git a/pubspec_overrides.yaml b/pubspec_overrides.yaml
index b3b236a4..b91e7dc8 100644
--- a/pubspec_overrides.yaml
+++ b/pubspec_overrides.yaml
@@ -120,7 +120,7 @@ dependency_overrides:
breez_sdk_spark_flutter:
git:
url: https://github.com/breez/breez-sdk-spark-flutter
- ref: e18b6437daaf0572de6aea2439c2ec4d22658bbb
+ ref: 5943a3e773203f21728f87f1c0779040db8f2c28
bs58:
git:
url: https://github.com/litaoh/base58
Why this scored 29/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.