Skip to content

Commit

Permalink
Merge pull request breez#953 from breez/savage-reverse-swap-notification
Browse files Browse the repository at this point in the history
Add Reverse Swap notification
  • Loading branch information
dangeross authored Jul 7, 2024
2 parents b7c4f1a + fb13b8f commit 8563ff8
Show file tree
Hide file tree
Showing 26 changed files with 690 additions and 136 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ object Constants {
const val SHUTDOWN_DELAY_MS = 60 * 1000L

// Notification Channels
const val NOTIFICATION_CHANNEL_ADDRESS_TXS_CONFIRMED = "ADDRESS_TXS_CONFIRMED"
const val NOTIFICATION_CHANNEL_FOREGROUND_SERVICE = "FOREGROUND_SERVICE"
const val NOTIFICATION_CHANNEL_LNURL_PAY = "LNURL_PAY"
const val NOTIFICATION_CHANNEL_PAYMENT_RECEIVED = "PAYMENT_RECEIVED"
const val NOTIFICATION_CHANNEL_SWAP_TX_CONFIRMED = "SWAP_TX_CONFIRMED"

// Notification Ids
const val NOTIFICATION_ID_FOREGROUND_SERVICE = 100
Expand All @@ -28,6 +28,14 @@ object Constants {
const val MESSAGE_TYPE_PAYMENT_RECEIVED = "payment_received"

// Resource Identifiers
const val ADDRESS_TXS_CONFIRMED_NOTIFICATION_CHANNEL_DESCRIPTION =
"address_txs_confirmed_notification_channel_description"
const val ADDRESS_TXS_CONFIRMED_NOTIFICATION_CHANNEL_NAME =
"address_txs_confirmed_notification_channel_name"
const val ADDRESS_TXS_CONFIRMED_WORKGROUP_ID = "txs_confirmed"
const val ADDRESS_TXS_CONFIRMED_WORKGROUP_DESCRIPTION =
"address_txs_confirmed_work_group_description"
const val ADDRESS_TXS_CONFIRMED_WORKGROUP_NAME = "address_txs_confirmed_work_group_name"
const val FOREGROUND_SERVICE_NOTIFICATION_CHANNEL_DESCRIPTION =
"foreground_service_notification_channel_description"
const val FOREGROUND_SERVICE_NOTIFICATION_CHANNEL_NAME =
Expand Down Expand Up @@ -65,22 +73,21 @@ object Constants {
const val OFFLINE_PAYMENTS_WORKGROUP_DESCRIPTION =
"offline_payments_work_group_description"
const val OFFLINE_PAYMENTS_WORKGROUP_NAME = "offline_payments_work_group_name"
const val SWAP_TX_CONFIRMED_NOTIFICATION_CHANNEL_DESCRIPTION =
"swap_tx_confirmed_notification_channel_description"
const val SWAP_TX_CONFIRMED_NOTIFICATION_CHANNEL_NAME =
"swap_tx_confirmed_notification_channel_name"
const val SWAP_TX_CONFIRMED_NOTIFICATION_FAILURE_TEXT =
"swap_tx_confirmed_notification_failure_text"
const val SWAP_TX_CONFIRMED_NOTIFICATION_FAILURE_TITLE =
"swap_tx_confirmed_notification_failure_title"
const val SWAP_TX_CONFIRMED_NOTIFICATION_TITLE =
"swap_tx_confirmed_notification_title"
const val SWAP_TX_CONFIRMED_WORKGROUP_ID = "swap_tx"
const val SWAP_TX_CONFIRMED_WORKGROUP_DESCRIPTION =
"swap_tx_confirmed_work_group_description"
const val SWAP_TX_CONFIRMED_WORKGROUP_NAME = "swap_tx_confirmed_work_group_name"

// Resource Identifier Defaults
const val DEFAULT_ADDRESS_TXS_CONFIRMED_NOTIFICATION_CHANNEL_DESCRIPTION =
"Notifications for confirmed transactions when the application is in the background"
const val DEFAULT_ADDRESS_TXS_CONFIRMED_NOTIFICATION_CHANNEL_NAME =
"Confirmed Transactions"
const val DEFAULT_ADDRESS_TXS_CONFIRMED_WORKGROUP_DESCRIPTION =
"Required to handle confirmed transactions when the application is in the background"
const val DEFAULT_ADDRESS_TXS_CONFIRMED_WORKGROUP_NAME = "Confirmed Transactions"
const val DEFAULT_FOREGROUND_SERVICE_NOTIFICATION_CHANNEL_DESCRIPTION =
"Shown when the application is in the background"
const val DEFAULT_FOREGROUND_SERVICE_NOTIFICATION_CHANNEL_NAME =
Expand Down Expand Up @@ -114,17 +121,10 @@ object Constants {
const val DEFAULT_OFFLINE_PAYMENTS_WORKGROUP_DESCRIPTION =
"Required to receive payments when the application is in the background"
const val DEFAULT_OFFLINE_PAYMENTS_WORKGROUP_NAME = "Offline Payments"
const val DEFAULT_SWAP_TX_CONFIRMED_NOTIFICATION_CHANNEL_DESCRIPTION =
"Notifications for received swaps when the application is in the background"
const val DEFAULT_SWAP_TX_CONFIRMED_NOTIFICATION_CHANNEL_NAME =
"Received Swaps"
const val DEFAULT_SWAP_TX_CONFIRMED_NOTIFICATION_FAILURE_TEXT =
"Tap to complete swap"
const val DEFAULT_SWAP_TX_CONFIRMED_NOTIFICATION_FAILURE_TITLE =
"Swap Ongoing"
const val DEFAULT_SWAP_TX_CONFIRMED_NOTIFICATION_TITLE =
"Swap Confirmed"
const val DEFAULT_SWAP_TX_CONFIRMED_WORKGROUP_DESCRIPTION =
"Required to handle swaps when the application is in the background"
const val DEFAULT_SWAP_TX_CONFIRMED_WORKGROUP_NAME = "Swap Transactions"
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ import breez_sdk_notification.Constants.NOTIFICATION_ID_FOREGROUND_SERVICE
import breez_sdk_notification.Constants.SERVICE_TIMEOUT_MS
import breez_sdk_notification.Constants.SHUTDOWN_DELAY_MS
import breez_sdk_notification.NotificationHelper.Companion.notifyForegroundService
import breez_sdk_notification.job.ConfirmTransactionJob
import breez_sdk_notification.job.Job
import breez_sdk_notification.job.LnurlPayInfoJob
import breez_sdk_notification.job.LnurlPayInvoiceJob
import breez_sdk_notification.job.ReceivePaymentJob
import breez_sdk_notification.job.RedeemSwapJob
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -147,7 +147,7 @@ abstract class ForegroundService : SdkForegroundService, EventListener, Service(
return Message.createFromIntent(intent)?.let { message ->
message.payload?.let { payload ->
when (message.type) {
MESSAGE_TYPE_ADDRESS_TXS_CONFIRMED -> RedeemSwapJob(
MESSAGE_TYPE_ADDRESS_TXS_CONFIRMED -> ConfirmTransactionJob(
applicationContext,
this,
payload,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import breez_sdk_notification.Constants.ADDRESS_TXS_CONFIRMED_NOTIFICATION_CHANNEL_DESCRIPTION
import breez_sdk_notification.Constants.ADDRESS_TXS_CONFIRMED_NOTIFICATION_CHANNEL_NAME
import breez_sdk_notification.Constants.ADDRESS_TXS_CONFIRMED_WORKGROUP_DESCRIPTION
import breez_sdk_notification.Constants.ADDRESS_TXS_CONFIRMED_WORKGROUP_ID
import breez_sdk_notification.Constants.ADDRESS_TXS_CONFIRMED_WORKGROUP_NAME
import breez_sdk_notification.Constants.DEFAULT_ADDRESS_TXS_CONFIRMED_NOTIFICATION_CHANNEL_DESCRIPTION
import breez_sdk_notification.Constants.DEFAULT_ADDRESS_TXS_CONFIRMED_NOTIFICATION_CHANNEL_NAME
import breez_sdk_notification.Constants.DEFAULT_ADDRESS_TXS_CONFIRMED_WORKGROUP_DESCRIPTION
import breez_sdk_notification.Constants.DEFAULT_ADDRESS_TXS_CONFIRMED_WORKGROUP_NAME
import breez_sdk_notification.Constants.DEFAULT_FOREGROUND_SERVICE_NOTIFICATION_CHANNEL_DESCRIPTION
import breez_sdk_notification.Constants.DEFAULT_FOREGROUND_SERVICE_NOTIFICATION_CHANNEL_NAME
import breez_sdk_notification.Constants.DEFAULT_FOREGROUND_SERVICE_NOTIFICATION_TITLE
Expand All @@ -29,10 +38,6 @@ import breez_sdk_notification.Constants.DEFAULT_OFFLINE_PAYMENTS_WORKGROUP_DESCR
import breez_sdk_notification.Constants.DEFAULT_OFFLINE_PAYMENTS_WORKGROUP_NAME
import breez_sdk_notification.Constants.DEFAULT_PAYMENT_RECEIVED_NOTIFICATION_CHANNEL_DESCRIPTION
import breez_sdk_notification.Constants.DEFAULT_PAYMENT_RECEIVED_NOTIFICATION_CHANNEL_NAME
import breez_sdk_notification.Constants.DEFAULT_SWAP_TX_CONFIRMED_NOTIFICATION_CHANNEL_DESCRIPTION
import breez_sdk_notification.Constants.DEFAULT_SWAP_TX_CONFIRMED_NOTIFICATION_CHANNEL_NAME
import breez_sdk_notification.Constants.DEFAULT_SWAP_TX_CONFIRMED_WORKGROUP_DESCRIPTION
import breez_sdk_notification.Constants.DEFAULT_SWAP_TX_CONFIRMED_WORKGROUP_NAME
import breez_sdk_notification.Constants.FOREGROUND_SERVICE_NOTIFICATION_CHANNEL_DESCRIPTION
import breez_sdk_notification.Constants.FOREGROUND_SERVICE_NOTIFICATION_CHANNEL_NAME
import breez_sdk_notification.Constants.FOREGROUND_SERVICE_NOTIFICATION_TITLE
Expand All @@ -41,10 +46,10 @@ import breez_sdk_notification.Constants.LNURL_PAY_NOTIFICATION_CHANNEL_NAME
import breez_sdk_notification.Constants.LNURL_PAY_WORKGROUP_DESCRIPTION
import breez_sdk_notification.Constants.LNURL_PAY_WORKGROUP_ID
import breez_sdk_notification.Constants.LNURL_PAY_WORKGROUP_NAME
import breez_sdk_notification.Constants.NOTIFICATION_CHANNEL_ADDRESS_TXS_CONFIRMED
import breez_sdk_notification.Constants.NOTIFICATION_CHANNEL_FOREGROUND_SERVICE
import breez_sdk_notification.Constants.NOTIFICATION_CHANNEL_LNURL_PAY
import breez_sdk_notification.Constants.NOTIFICATION_CHANNEL_PAYMENT_RECEIVED
import breez_sdk_notification.Constants.NOTIFICATION_CHANNEL_SWAP_TX_CONFIRMED
import breez_sdk_notification.Constants.NOTIFICATION_COLOR
import breez_sdk_notification.Constants.NOTIFICATION_ICON
import breez_sdk_notification.Constants.NOTIFICATION_ID_FOREGROUND_SERVICE
Expand All @@ -53,11 +58,6 @@ import breez_sdk_notification.Constants.OFFLINE_PAYMENTS_WORKGROUP_ID
import breez_sdk_notification.Constants.OFFLINE_PAYMENTS_WORKGROUP_NAME
import breez_sdk_notification.Constants.PAYMENT_RECEIVED_NOTIFICATION_CHANNEL_DESCRIPTION
import breez_sdk_notification.Constants.PAYMENT_RECEIVED_NOTIFICATION_CHANNEL_NAME
import breez_sdk_notification.Constants.SWAP_TX_CONFIRMED_NOTIFICATION_CHANNEL_DESCRIPTION
import breez_sdk_notification.Constants.SWAP_TX_CONFIRMED_NOTIFICATION_CHANNEL_NAME
import breez_sdk_notification.Constants.SWAP_TX_CONFIRMED_WORKGROUP_DESCRIPTION
import breez_sdk_notification.Constants.SWAP_TX_CONFIRMED_WORKGROUP_ID
import breez_sdk_notification.Constants.SWAP_TX_CONFIRMED_WORKGROUP_NAME
import breez_sdk_notification.ResourceHelper.Companion.getColor
import breez_sdk_notification.ResourceHelper.Companion.getDrawable
import breez_sdk_notification.ResourceHelper.Companion.getString
Expand Down Expand Up @@ -194,20 +194,20 @@ class NotificationHelper {
group = LNURL_PAY_WORKGROUP_ID
}
val swapTxConfirmedNotificationChannel = NotificationChannel(
"${applicationId}.${NOTIFICATION_CHANNEL_SWAP_TX_CONFIRMED}",
"${applicationId}.${NOTIFICATION_CHANNEL_ADDRESS_TXS_CONFIRMED}",
getString(
context,
SWAP_TX_CONFIRMED_NOTIFICATION_CHANNEL_NAME,
DEFAULT_SWAP_TX_CONFIRMED_NOTIFICATION_CHANNEL_NAME
ADDRESS_TXS_CONFIRMED_NOTIFICATION_CHANNEL_NAME,
DEFAULT_ADDRESS_TXS_CONFIRMED_NOTIFICATION_CHANNEL_NAME
),
NotificationManager.IMPORTANCE_DEFAULT
).apply {
description = getString(
context,
SWAP_TX_CONFIRMED_NOTIFICATION_CHANNEL_DESCRIPTION,
DEFAULT_SWAP_TX_CONFIRMED_NOTIFICATION_CHANNEL_DESCRIPTION
ADDRESS_TXS_CONFIRMED_NOTIFICATION_CHANNEL_DESCRIPTION,
DEFAULT_ADDRESS_TXS_CONFIRMED_NOTIFICATION_CHANNEL_DESCRIPTION
)
group = SWAP_TX_CONFIRMED_WORKGROUP_ID
group = ADDRESS_TXS_CONFIRMED_WORKGROUP_ID
}
notificationManager.createNotificationChannels(
listOf(
Expand Down Expand Up @@ -241,11 +241,11 @@ class NotificationHelper {
),
)
val swapTxConfirmedNotificationChannelGroup = NotificationChannelGroup(
SWAP_TX_CONFIRMED_WORKGROUP_ID,
ADDRESS_TXS_CONFIRMED_WORKGROUP_ID,
getString(
context,
SWAP_TX_CONFIRMED_WORKGROUP_NAME,
DEFAULT_SWAP_TX_CONFIRMED_WORKGROUP_NAME
ADDRESS_TXS_CONFIRMED_WORKGROUP_NAME,
DEFAULT_ADDRESS_TXS_CONFIRMED_WORKGROUP_NAME
),
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
Expand All @@ -261,8 +261,8 @@ class NotificationHelper {
)
swapTxConfirmedNotificationChannelGroup.description = getString(
context,
SWAP_TX_CONFIRMED_WORKGROUP_DESCRIPTION,
DEFAULT_SWAP_TX_CONFIRMED_WORKGROUP_DESCRIPTION
ADDRESS_TXS_CONFIRMED_WORKGROUP_DESCRIPTION,
DEFAULT_ADDRESS_TXS_CONFIRMED_WORKGROUP_DESCRIPTION
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package breez_sdk_notification.job
import android.content.Context
import breez_sdk.BlockingBreezServices
import breez_sdk.BreezEvent
import breez_sdk.ReverseSwapStatus
import breez_sdk_notification.Constants.DEFAULT_SWAP_TX_CONFIRMED_NOTIFICATION_FAILURE_TEXT
import breez_sdk_notification.Constants.DEFAULT_SWAP_TX_CONFIRMED_NOTIFICATION_FAILURE_TITLE
import breez_sdk_notification.Constants.DEFAULT_SWAP_TX_CONFIRMED_NOTIFICATION_TITLE
import breez_sdk_notification.Constants.NOTIFICATION_CHANNEL_SWAP_TX_CONFIRMED
import breez_sdk_notification.Constants.NOTIFICATION_CHANNEL_ADDRESS_TXS_CONFIRMED
import breez_sdk_notification.Constants.SWAP_TX_CONFIRMED_NOTIFICATION_FAILURE_TEXT
import breez_sdk_notification.Constants.SWAP_TX_CONFIRMED_NOTIFICATION_FAILURE_TITLE
import breez_sdk_notification.Constants.SWAP_TX_CONFIRMED_NOTIFICATION_TITLE
Expand All @@ -22,38 +23,63 @@ data class AddressTxsConfirmedRequest(
val address: String,
)

class RedeemSwapJob(
class ConfirmTransactionJob(
private val context: Context,
private val fgService: SdkForegroundService,
private val payload: String,
private val logger: ServiceLogger,
private var bitcoinAddress: String? = null,
) : Job {
companion object {
private const val TAG = "RedeemSwapJob"
private const val TAG = "ConfirmTransactionJob"
}

override fun start(breezSDK: BlockingBreezServices) {
try {
val request = Json.decodeFromString(AddressTxsConfirmedRequest.serializer(), payload)
this.bitcoinAddress = request.address
breezSDK.redeemSwap(request.address)
logger.log(TAG, "Found swap for ${request.address}", "INFO")
} catch (e: Exception) {
logger.log(TAG, "Failed to manually redeem swap notification: ${e.message}", "WARN")
notifyFailure()
logger.log(TAG, "Failed to decode payload: ${e.message}", "WARN")
}

this.bitcoinAddress?.let {address ->
try {
breezSDK.redeemSwap(address)
logger.log(TAG, "Found swap for $address", "INFO")
return
} catch (e: Exception) {
logger.log(TAG, "Failed to redeem swap: ${e.message}", "WARN")
}

try {
breezSDK.processReverseSwap(address)
logger.log(TAG, "Found reverse swap for $address", "INFO")
return
} catch (e: Exception) {
logger.log(TAG, "Failed to process reverse swap: ${e.message}", "WARN")
}
}

fgService.onFinished(this)
}

override fun onEvent(e: BreezEvent) {
this.bitcoinAddress?.let {address ->
when (e) {
is BreezEvent.ReverseSwapUpdated -> {
val revSwapInfo = e.details
logger.log(TAG, "Received reverse swap updated event: ${revSwapInfo.id} current address: $address status: ${revSwapInfo.status}", "TRACE")
if (revSwapInfo.status == ReverseSwapStatus.COMPLETED_SEEN || revSwapInfo.status == ReverseSwapStatus.COMPLETED_CONFIRMED) {
notifySuccess(address)
}
}

is BreezEvent.SwapUpdated -> {
val swapInfo = e.details
logger.log(TAG, "Received swap updated event: ${swapInfo.bitcoinAddress} current address: $address status: ${swapInfo.status}", "TRACE")
if (swapInfo.bitcoinAddress == address) {
if (swapInfo.paidMsat.toLong() > 0) {
notifySuccessAndShutdown(address)
notifySuccess(address)
}
}
}
Expand All @@ -67,11 +93,11 @@ class RedeemSwapJob(
notifyFailure()
}

private fun notifySuccessAndShutdown(address: String) {
logger.log(TAG, "Swap address $address redeemed successfully", "INFO")
private fun notifySuccess(address: String) {
logger.log(TAG, "Address $address processed successfully", "INFO")
notifyChannel(
context,
NOTIFICATION_CHANNEL_SWAP_TX_CONFIRMED,
NOTIFICATION_CHANNEL_ADDRESS_TXS_CONFIRMED,
getString(
context,
SWAP_TX_CONFIRMED_NOTIFICATION_TITLE,
Expand All @@ -83,10 +109,10 @@ class RedeemSwapJob(

private fun notifyFailure() {
this.bitcoinAddress?.let{address ->
logger.log(TAG, "Swap address $address not redeemed", "INFO")
logger.log(TAG, "Address $address processing failed", "INFO")
notifyChannel(
context,
NOTIFICATION_CHANNEL_SWAP_TX_CONFIRMED,
NOTIFICATION_CHANNEL_ADDRESS_TXS_CONFIRMED,
getString(
context,
SWAP_TX_CONFIRMED_NOTIFICATION_FAILURE_TITLE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import Foundation

struct Constants {
// Notification Threads
static let NOTIFICATION_THREAD_ADDRESS_TXS_CONFIRMED = "ADDRESS_TXS_CONFIRMED"
static let NOTIFICATION_THREAD_LNURL_PAY = "LNURL_PAY"
static let NOTIFICATION_THREAD_PAYMENT_RECEIVED = "PAYMENT_RECEIVED"
static let NOTIFICATION_THREAD_SWAP_TX_CONFIRMED = "SWAP_TX_CONFIRMED"

// Message Data
static let MESSAGE_DATA_TYPE = "notification_type"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ open class SDKNotificationService: UNNotificationServiceExtension {
self.logger.log(tag: TAG, line: "\(notificationType) data string: \(payload)", level: "INFO")
switch(notificationType) {
case Constants.MESSAGE_TYPE_ADDRESS_TXS_CONFIRMED:
return RedeemSwapTask(payload: payload, logger: self.logger, contentHandler: contentHandler, bestAttemptContent: bestAttemptContent)
return ConfirmTransactionTask(payload: payload, logger: self.logger, contentHandler: contentHandler, bestAttemptContent: bestAttemptContent)
case Constants.MESSAGE_TYPE_LNURL_PAY_INFO:
return LnurlPayInfoTask(payload: payload, logger: self.logger, config: self.config, contentHandler: contentHandler, bestAttemptContent: bestAttemptContent)
case Constants.MESSAGE_TYPE_LNURL_PAY_INVOICE:
Expand Down
Loading

0 comments on commit 8563ff8

Please sign in to comment.