@@ -25,8 +25,7 @@ These events notify you about Bitcoin transactions affecting your onchain wallet
2525- ** Use Case** : Show "Payment incoming!" notification immediately
2626- ** Fields** :
2727 - ` txid ` : Transaction ID
28- - ` amountSats ` : Net amount (positive for incoming, negative for outgoing)
29- - ` context ` : Type of transaction (channel-related or regular wallet)
28+ - ` details ` : ` TransactionDetails ` object with comprehensive transaction information
3029
3130#### ` OnchainTransactionConfirmed `
3231- ** When** : Transaction receives blockchain confirmations
@@ -36,14 +35,27 @@ These events notify you about Bitcoin transactions affecting your onchain wallet
3635 - ` blockHash ` : Block hash where confirmed
3736 - ` blockHeight ` : Block height
3837 - ` confirmationTime ` : Unix timestamp
39- - ` context ` : Transaction type
38+ - ` details ` : ` TransactionDetails ` object with comprehensive transaction information
4039
41- #### ` OnchainTransactionUnconfirmed `
42- - ** When** : Previously confirmed transaction becomes unconfirmed (blockchain reorg)
40+ #### ` OnchainTransactionReplaced `
41+ - ** When** : Transaction is replaced via Replace-By-Fee (RBF)
42+ - ** Use Case** : Update UI to show the transaction was replaced
43+ - ** Fields** :
44+ - ` txid ` : Transaction ID of the replacement transaction
45+
46+ #### ` OnchainTransactionReorged `
47+ - ** When** : Previously confirmed transaction becomes unconfirmed due to blockchain reorg
4348- ** Use Case** : Mark transaction as pending again
4449- ** Fields** :
4550 - ` txid ` : Transaction ID
4651
52+ #### ` OnchainTransactionEvicted `
53+ - ** When** : Transaction is evicted from the mempool (no longer unconfirmed and not confirmed)
54+ - ** Use Case** : Mark transaction as evicted, potentially allow user to rebroadcast
55+ - ** Fields** :
56+ - ` txid ` : Transaction ID
57+ - ** Note** : Works with all chain sources (Esplora, Electrum, and BitcoindRpc)
58+
4759### 2. Sync Events
4860
4961Track synchronization progress and completion:
@@ -77,13 +89,30 @@ Track synchronization progress and completion:
7789 - ` oldTotalLightningBalanceSats ` : Previous Lightning balance
7890 - ` newTotalLightningBalanceSats ` : New Lightning balance
7991
80- ### 4. Transaction Context
92+ ### 4. Transaction Details
8193
82- The ` TransactionContext ` enum helps identify what type of transaction you're dealing with :
94+ The ` TransactionDetails ` struct provides comprehensive information about transactions, allowing you to analyze transaction purposes yourself :
8395
84- - ` RegularWallet ` : Normal Bitcoin transaction
85- - ` ChannelFunding ` : Opening a Lightning channel
86- - ` ChannelClosure ` : Closing a Lightning channel
96+ #### ` TransactionDetails `
97+ - ` amountSats ` : Net amount in satoshis (positive for incoming, negative for outgoing)
98+ - ` inputs ` : Array of ` TxInput ` objects
99+ - ` outputs ` : Array of ` TxOutput ` objects
100+
101+ #### ` TxInput `
102+ - ` txid ` : Previous transaction ID being spent
103+ - ` vout ` : Output index being spent
104+ - ` scriptsig ` : Script signature (hex-encoded)
105+ - ` witness ` : Witness stack (array of hex-encoded strings)
106+ - ` sequence ` : Sequence number
107+
108+ #### ` TxOutput `
109+ - ` scriptpubkey ` : Script public key (hex-encoded)
110+ - ` scriptpubkeyType ` : Script type (e.g., "p2wpkh", "p2wsh", "p2tr")
111+ - ` scriptpubkeyAddress ` : Bitcoin address (if decodable)
112+ - ` value ` : Value in satoshis
113+ - ` n ` : Output index
114+
115+ ** Note** : You can analyze transaction inputs and outputs to detect channel funding, channel closures, and other transaction types. This provides more flexibility than the previous ` TransactionContext ` enum.
87116
88117---
89118
@@ -119,14 +148,20 @@ class WalletEventHandler {
119148
120149 func handleEvent (_ event : Event) {
121150 switch event {
122- case .onchainTransactionReceived (let txid, let amountSats, let context):
123- handleIncomingTransaction (txid : txid, amount : amountSats, context : context)
151+ case .onchainTransactionReceived (let txid, let details):
152+ handleIncomingTransaction (txid : txid, details : details)
153+
154+ case .onchainTransactionConfirmed (let txid, let blockHash, let blockHeight, let confirmationTime, let details):
155+ handleConfirmedTransaction (txid : txid, height : blockHeight, details : details)
124156
125- case .onchainTransactionConfirmed (let txid, let blockHash, let blockHeight, let confirmationTime, let context ):
126- handleConfirmedTransaction (txid : txid, height : blockHeight, context : context )
157+ case .onchainTransactionReplaced (let txid):
158+ handleReplacedTransaction (txid : txid)
127159
128- case .onchainTransactionUnconfirmed (let txid):
129- handleUnconfirmedTransaction (txid : txid)
160+ case .onchainTransactionReorged (let txid):
161+ handleReorgedTransaction (txid : txid)
162+
163+ case .onchainTransactionEvicted (let txid):
164+ handleEvictedTransaction (txid : txid)
130165
131166 case .syncProgress (let syncType, let progressPercent, let currentBlock, let targetBlock):
132167 updateSyncProgress (type : syncType, percent : progressPercent)
@@ -150,18 +185,18 @@ class WalletEventHandler {
150185#### Example 1: Real-time Transaction Notifications
151186
152187``` swift
153- func handleIncomingTransaction (txid : String , amount : Int64 , context : TransactionContext ) {
188+ func handleIncomingTransaction (txid : String , details : TransactionDetails ) {
154189 DispatchQueue.main .async {
155- if amount > 0 {
190+ if details.amountSats > 0 {
156191 // Incoming payment
157192 self .showNotification (
158193 title : " Payment Received!" ,
159- body : " Incoming payment of \( amount ) sats (unconfirmed)" ,
194+ body : " Incoming payment of \( details. amountSats ) sats (unconfirmed)" ,
160195 txid : txid
161196 )
162197
163198 // Update UI to show pending transaction
164- self .addPendingTransaction (txid : txid, amount : amount )
199+ self .addPendingTransaction (txid : txid, amount : details. amountSats )
165200
166201 // Play sound or haptic feedback
167202 self .playPaymentReceivedSound ()
@@ -170,19 +205,16 @@ func handleIncomingTransaction(txid: String, amount: Int64, context: Transaction
170205 self .updateTransactionStatus (txid : txid, status : .broadcasting )
171206 }
172207
173- // Check if this is channel-related
174- switch context {
175- case .channelFunding (let channelId, _ , let counterpartyNodeId):
176- print (" Channel \( channelId ) funding transaction detected" )
177- case .channelClosure (let channelId, _ , _ ):
178- print (" Channel \( channelId ) closing transaction detected" )
179- case .regularWallet :
180- print (" Regular wallet transaction" )
208+ // Analyze transaction to detect channel-related transactions
209+ if self .isChannelFundingTransaction (details : details) {
210+ print (" Channel funding transaction detected" )
211+ } else if self .isChannelClosureTransaction (details : details) {
212+ print (" Channel closure transaction detected" )
181213 }
182214 }
183215}
184216
185- func handleConfirmedTransaction (txid : String , height : UInt32 , context : TransactionContext ) {
217+ func handleConfirmedTransaction (txid : String , height : UInt32 , details : TransactionDetails ) {
186218 DispatchQueue.main .async {
187219 // Update transaction status
188220 self .updateTransactionStatus (txid : txid, status : .confirmed (height : height))
@@ -198,6 +230,54 @@ func handleConfirmedTransaction(txid: String, height: UInt32, context: Transacti
198230 self .refreshTransactionList ()
199231 }
200232}
233+
234+ func handleReplacedTransaction (txid : String ) {
235+ DispatchQueue.main .async {
236+ self .updateTransactionStatus (txid : txid, status : .replaced )
237+ self .showNotification (
238+ title : " Transaction Replaced" ,
239+ body : " Transaction was replaced via RBF" ,
240+ txid : txid
241+ )
242+ }
243+ }
244+
245+ func handleReorgedTransaction (txid : String ) {
246+ DispatchQueue.main .async {
247+ self .updateTransactionStatus (txid : txid, status : .pending )
248+ self .showNotification (
249+ title : " Transaction Unconfirmed" ,
250+ body : " Transaction became unconfirmed due to reorg" ,
251+ txid : txid
252+ )
253+ }
254+ }
255+
256+ func handleEvictedTransaction (txid : String ) {
257+ DispatchQueue.main .async {
258+ self .updateTransactionStatus (txid : txid, status : .evicted )
259+ self .showNotification (
260+ title : " Transaction Evicted" ,
261+ body : " Transaction was evicted from mempool" ,
262+ txid : txid
263+ )
264+ // Optionally allow user to rebroadcast
265+ self .promptRebroadcast (txid : txid)
266+ }
267+ }
268+
269+ // Helper functions to analyze transaction details
270+ func isChannelFundingTransaction (details : TransactionDetails) -> Bool {
271+ // Analyze inputs/outputs to detect channel funding
272+ // This is a simplified example - implement based on your needs
273+ return details.outputs .count == 2 && details.amountSats > 0
274+ }
275+
276+ func isChannelClosureTransaction (details : TransactionDetails) -> Bool {
277+ // Analyze inputs/outputs to detect channel closure
278+ // This is a simplified example - implement based on your needs
279+ return details.inputs .count > 0 && details.outputs .count >= 2
280+ }
201281```
202282
203283#### Example 2: Sync Progress Bar
@@ -325,23 +405,23 @@ class WalletEventHandler(private val node: Node) {
325405 private fun handleEvent (event : Event ) {
326406 when (event) {
327407 is Event .OnchainTransactionReceived -> {
328- handleIncomingTransaction(
329- event.txid,
330- event.amountSats,
331- event.context
332- )
408+ handleIncomingTransaction(event.txid, event.details)
333409 }
334410
335411 is Event .OnchainTransactionConfirmed -> {
336- handleConfirmedTransaction(
337- event.txid,
338- event.blockHeight,
339- event.context
340- )
412+ handleConfirmedTransaction(event.txid, event.blockHeight, event.details)
413+ }
414+
415+ is Event .OnchainTransactionReplaced -> {
416+ handleReplacedTransaction(event.txid)
417+ }
418+
419+ is Event .OnchainTransactionReorged -> {
420+ handleReorgedTransaction(event.txid)
341421 }
342422
343- is Event .OnchainTransactionUnconfirmed -> {
344- handleUnconfirmedTransaction (event.txid)
423+ is Event .OnchainTransactionEvicted -> {
424+ handleEvictedTransaction (event.txid)
345425 }
346426
347427 is Event .SyncProgress -> {
@@ -380,18 +460,18 @@ class WalletEventHandler(private val node: Node) {
380460``` kotlin
381461class TransactionNotificationManager (private val context : Context ) {
382462
383- fun handleIncomingTransaction (txid : String , amountSats : Long , context : TransactionContext ) {
463+ fun handleIncomingTransaction (txid : String , details : TransactionDetails ) {
384464 GlobalScope .launch(Dispatchers .Main ) {
385- if (amountSats > 0 ) {
465+ if (details. amountSats > 0 ) {
386466 // Incoming payment
387467 showNotification(
388468 title = " Payment Received!" ,
389- message = " Incoming payment of $amountSats sats (unconfirmed)" ,
469+ message = " Incoming payment of ${details. amountSats} sats (unconfirmed)" ,
390470 txid = txid
391471 )
392472
393473 // Update transaction list
394- addPendingTransaction(txid, amountSats)
474+ addPendingTransaction(txid, details. amountSats)
395475
396476 // Play sound
397477 playPaymentSound()
@@ -400,22 +480,16 @@ class TransactionNotificationManager(private val context: Context) {
400480 updateTransactionStatus(txid, TransactionStatus .BROADCASTING )
401481 }
402482
403- // Check transaction type
404- when (context) {
405- is TransactionContext .ChannelFunding -> {
406- Log .d(" Wallet" , " Channel ${context.channelId} funding transaction" )
407- }
408- is TransactionContext .ChannelClosure -> {
409- Log .d(" Wallet" , " Channel ${context.channelId} closing transaction" )
410- }
411- is TransactionContext .RegularWallet -> {
412- Log .d(" Wallet" , " Regular wallet transaction" )
413- }
483+ // Analyze transaction to detect channel-related transactions
484+ if (isChannelFundingTransaction(details)) {
485+ Log .d(" Wallet" , " Channel funding transaction detected" )
486+ } else if (isChannelClosureTransaction(details)) {
487+ Log .d(" Wallet" , " Channel closure transaction detected" )
414488 }
415489 }
416490 }
417491
418- fun handleConfirmedTransaction (txid : String , height : UInt , context : TransactionContext ) {
492+ fun handleConfirmedTransaction (txid : String , height : UInt , details : TransactionDetails ) {
419493 GlobalScope .launch(Dispatchers .Main ) {
420494 // Update status
421495 updateTransactionStatus(txid, TransactionStatus .CONFIRMED )
@@ -429,6 +503,59 @@ class TransactionNotificationManager(private val context: Context) {
429503
430504 // Vibrate
431505 vibrate()
506+
507+ // Refresh transaction list
508+ refreshTransactionList()
509+ }
510+ }
511+
512+ fun handleReplacedTransaction (txid : String ) {
513+ GlobalScope .launch(Dispatchers .Main ) {
514+ updateTransactionStatus(txid, TransactionStatus .REPLACED )
515+ showNotification(
516+ title = " Transaction Replaced" ,
517+ message = " Transaction was replaced via RBF" ,
518+ txid = txid
519+ )
520+ }
521+ }
522+
523+ fun handleReorgedTransaction (txid : String ) {
524+ GlobalScope .launch(Dispatchers .Main ) {
525+ updateTransactionStatus(txid, TransactionStatus .PENDING )
526+ showNotification(
527+ title = " Transaction Unconfirmed" ,
528+ message = " Transaction became unconfirmed due to reorg" ,
529+ txid = txid
530+ )
531+ }
532+ }
533+
534+ fun handleEvictedTransaction (txid : String ) {
535+ GlobalScope .launch(Dispatchers .Main ) {
536+ updateTransactionStatus(txid, TransactionStatus .EVICTED )
537+ showNotification(
538+ title = " Transaction Evicted" ,
539+ message = " Transaction was evicted from mempool" ,
540+ txid = txid
541+ )
542+ // Optionally allow user to rebroadcast
543+ promptRebroadcast(txid)
544+ }
545+ }
546+
547+ // Helper functions to analyze transaction details
548+ private fun isChannelFundingTransaction (details : TransactionDetails ): Boolean {
549+ // Analyze inputs/outputs to detect channel funding
550+ // This is a simplified example - implement based on your needs
551+ return details.outputs.size == 2 && details.amountSats > 0
552+ }
553+
554+ private fun isChannelClosureTransaction (details : TransactionDetails ): Boolean {
555+ // Analyze inputs/outputs to detect channel closure
556+ // This is a simplified example - implement based on your needs
557+ return details.inputs.isNotEmpty() && details.outputs.size >= 2
558+ }
432559 }
433560 }
434561
0 commit comments