Skip to content
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ ktlint = "11.3.1"
ktor = "2.2.3"
lightsparkCore = "0.5.0"
lightsparkCrypto = "0.5.0"
uma = "0.1.2"
uma = "0.2.0"
mavenPublish = "0.25.2"
mockitoCore = "5.5.0"
taskTree = "2.1.1"
Expand Down
4 changes: 2 additions & 2 deletions lightspark-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ Start by installing the SDK from maven:
**build.gradle:**
```groovy
dependencies {
implementation "com.lightspark:lightspark-sdk:0.9.0"
implementation "com.lightspark:lightspark-sdk:0.10.0"
}
```

or with **build.gradle.kts:**
```kotlin
dependencies {
implementation("com.lightspark:lightspark-sdk:0.9.0")
implementation("com.lightspark:lightspark-sdk:0.10.0")
}
```

Expand Down
2 changes: 1 addition & 1 deletion lightspark-sdk/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
GROUP=com.lightspark
POM_ARTIFACT_ID=lightspark-sdk
# Don't bump this manually. Run `scripts/versions.main.kt <new_version>` to bump the version instead.
VERSION_NAME=0.9.0
VERSION_NAME=0.10.0

POM_DESCRIPTION=The Lightspark API SDK for Kotlin and Java.
POM_INCEPTION_YEAR=2023
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.lightspark.sdk.model.InvoiceType
import com.lightspark.sdk.model.OutgoingPayment
import com.lightspark.sdk.model.PaymentDirection
import com.lightspark.sdk.model.RiskRating
import com.lightspark.sdk.model.TransactionStatus
import com.lightspark.sdk.model.WithdrawalMode
import com.lightspark.sdk.model.WithdrawalRequest
import java.util.concurrent.CompletableFuture
Expand Down Expand Up @@ -446,6 +447,22 @@ class LightsparkFuturesClient(config: ClientConfig) {
coroutinesClient.screenNode(complianceProvider, nodePubKey)
}

/**
* Fetches the outgoing payments (if any) which have been made for a given invoice.
*
* @param encodedInvoice The encoded invoice to fetch the payments for.
* @param transactionStatuses The transaction statuses to filter the payments by. If null, all payments will be
* returned.
* @return The list of outgoing payments for the invoice.
*/
@Throws(LightsparkException::class, LightsparkAuthenticationException::class)
fun getOutgoingPaymentsForInvoice(
encodedInvoice: String,
transactionStatuses: List<TransactionStatus>? = null,
): CompletableFuture<List<OutgoingPayment>> = coroutineScope.future {
coroutinesClient.getOutgoingPaymentsForInvoice(encodedInvoice, transactionStatuses)
}

/**
* Unlocks a node for use with the SDK for the current application session. This function or [loadNodeSigningKey]
* must be called before any other functions that require node signing keys, including [payInvoice].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import kotlin.coroutines.cancellation.CancellationException

private class FuturesExecutor(private val client: LightsparkFuturesClient) : QueryExecutor {
override fun <T> executeQuery(query: Query<T>): QueryResult<T> = FutureResult(client.executeQuery(query))
override fun <T> just(value: T): QueryResult<T> = FutureResult(CompletableFuture.completedFuture(value))
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,38 @@ class LightsparkCoroutinesClient private constructor(
)
}

/**
* Fetches the outgoing payments (if any) which have been made for a given invoice.
*
* @param encodedInvoice The encoded invoice to fetch the payments for.
* @param transactionStatuses The transaction statuses to filter the payments by. If null, all payments will be
* returned.
* @return The list of outgoing payments for the invoice.
*/
suspend fun getOutgoingPaymentsForInvoice(
encodedInvoice: String,
transactionStatuses: List<TransactionStatus>? = null,
): List<OutgoingPayment> {
requireValidAuth()
return executeQuery(
Query(
OutgoingPaymentsForInvoiceQuery,
{
add("encodedInvoice", encodedInvoice)
transactionStatuses?.let {
add("transactionStatuses", serializerFormat.encodeToJsonElement(it))
}
},
) {
val outputJson =
requireNotNull(it["outgoing_payments_for_invoice"]) { "No payment output found in response" }
val paymentsJson =
requireNotNull(outputJson.jsonObject["payments"]) { "No payments found in response" }
serializerFormat.decodeFromJsonElement(paymentsJson)
},
)
}

suspend fun <T> executeQuery(query: Query<T>): T {
return requester.executeQuery(query)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,22 @@ class LightsparkSyncClient constructor(config: ClientConfig) {
asyncClient.screenNode(complianceProvider, nodePubKey)
}

/**
* Fetches the outgoing payments (if any) which have been made for a given invoice.
*
* @param encodedInvoice The encoded invoice to fetch the payments for.
* @param transactionStatuses The transaction statuses to filter the payments by. If null, all payments will be
* returned.
* @return The list of outgoing payments for the invoice.
*/
@Throws(LightsparkException::class, LightsparkAuthenticationException::class, CancellationException::class)
fun getOutgoingPaymentsForInvoice(
encodedInvoice: String,
transactionStatuses: List<TransactionStatus>? = null,
): List<OutgoingPayment> = runBlocking {
asyncClient.getOutgoingPaymentsForInvoice(encodedInvoice, transactionStatuses)
}

fun <T> executeQuery(query: Query<T>): T = runBlocking { asyncClient.executeQuery(query) }

fun setBitcoinNetwork(network: BitcoinNetwork) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.lightspark.sdk.graphql

import com.lightspark.sdk.model.OutgoingPayment

const val OutgoingPaymentsForInvoiceQuery = """
query OutgoingPaymentsForInvoice(
${'$'}encodedInvoice: ID!,
${'$'}transactionStatuses: [TransactionStatus!] = null
) {
outgoing_payments_for_invoice(input: {
encoded_invoice: ${'$'}encodedInvoice,
statuses: ${'$'}transactionStatuses
}) {
payments {
...OutgoingPaymentFragment
}
}
}

${OutgoingPayment.FRAGMENT}
"""
Original file line number Diff line number Diff line change
Expand Up @@ -1116,6 +1116,7 @@ query FetchAccountToTransactionsConnection(${'$'}first: Int, ${'$'}after: String
currency_amount_preferred_currency_value_approx: preferred_currency_value_approx
}
}
outgoing_payment_payment_preimage: payment_preimage
}
... on RoutingTransaction {
type: __typename
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright ©, 2023-present, Lightspark Group, Inc. - All Rights Reserved
@file:Suppress("ktlint:standard:max-line-length")

package com.lightspark.sdk.model

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

/**
*
*/
@Serializable
@SerialName("ChannelSnapshot")
data class ChannelSnapshot(
@SerialName("channel_snapshot_local_balance")
val localBalance: CurrencyAmount? = null,
@SerialName("channel_snapshot_local_unsettled_balance")
val localUnsettledBalance: CurrencyAmount? = null,
@SerialName("channel_snapshot_local_channel_reserve")
val localChannelReserve: CurrencyAmount? = null,
) {
companion object {
const val FRAGMENT = """
fragment ChannelSnapshotFragment on ChannelSnapshot {
type: __typename
channel_snapshot_local_balance: local_balance {
type: __typename
currency_amount_original_value: original_value
currency_amount_original_unit: original_unit
currency_amount_preferred_currency_unit: preferred_currency_unit
currency_amount_preferred_currency_value_rounded: preferred_currency_value_rounded
currency_amount_preferred_currency_value_approx: preferred_currency_value_approx
}
channel_snapshot_local_unsettled_balance: local_unsettled_balance {
type: __typename
currency_amount_original_value: original_value
currency_amount_original_unit: original_unit
currency_amount_preferred_currency_unit: preferred_currency_unit
currency_amount_preferred_currency_value_rounded: preferred_currency_value_rounded
currency_amount_preferred_currency_value_approx: preferred_currency_value_approx
}
channel_snapshot_local_channel_reserve: local_channel_reserve {
type: __typename
currency_amount_original_value: original_value
currency_amount_original_unit: original_unit
currency_amount_preferred_currency_unit: preferred_currency_unit
currency_amount_preferred_currency_value_rounded: preferred_currency_value_rounded
currency_amount_preferred_currency_value_approx: preferred_currency_value_approx
}
}"""
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import kotlinx.serialization.Serializable

/**
*
* @param id The id of the message.
* @param signature The signature of the message.
*/
@Serializable
@SerialName("IdAndSignature")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ fragment LightningTransactionFragment on LightningTransaction {
currency_amount_preferred_currency_value_approx: preferred_currency_value_approx
}
}
outgoing_payment_payment_preimage: payment_preimage
}
... on RoutingTransaction {
type: __typename
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import kotlinx.serialization.json.jsonObject
* @param failureReason If applicable, the reason why the payment failed.
* @param failureMessage If applicable, user-facing error message describing why the payment failed.
* @param umaPostTransactionData The post transaction data which can be used in KYT payment registration.
* @param paymentPreimage The preimage of the payment.
*/
@Serializable
@SerialName("OutgoingPayment")
Expand Down Expand Up @@ -61,6 +62,8 @@ data class OutgoingPayment(
val failureMessage: RichText? = null,
@SerialName("outgoing_payment_uma_post_transaction_data")
val umaPostTransactionData: List<PostTransactionData>? = null,
@SerialName("outgoing_payment_payment_preimage")
val paymentPreimage: String? = null,
) : LightningTransaction, Transaction, Entity {
@JvmOverloads
fun getAttemptsQuery(first: Int? = null, after: String? = null): Query<OutgoingPaymentToAttemptsConnection> {
Expand Down Expand Up @@ -107,6 +110,33 @@ query FetchOutgoingPaymentToAttemptsConnection(${'$'}entity_id: ID!, ${'$'}first
outgoing_payment_attempt_outgoing_payment: outgoing_payment {
id
}
outgoing_payment_attempt_channel_snapshot: channel_snapshot {
type: __typename
channel_snapshot_local_balance: local_balance {
type: __typename
currency_amount_original_value: original_value
currency_amount_original_unit: original_unit
currency_amount_preferred_currency_unit: preferred_currency_unit
currency_amount_preferred_currency_value_rounded: preferred_currency_value_rounded
currency_amount_preferred_currency_value_approx: preferred_currency_value_approx
}
channel_snapshot_local_unsettled_balance: local_unsettled_balance {
type: __typename
currency_amount_original_value: original_value
currency_amount_original_unit: original_unit
currency_amount_preferred_currency_unit: preferred_currency_unit
currency_amount_preferred_currency_value_rounded: preferred_currency_value_rounded
currency_amount_preferred_currency_value_approx: preferred_currency_value_approx
}
channel_snapshot_local_channel_reserve: local_channel_reserve {
type: __typename
currency_amount_original_value: original_value
currency_amount_original_unit: original_unit
currency_amount_preferred_currency_unit: preferred_currency_unit
currency_amount_preferred_currency_value_rounded: preferred_currency_value_rounded
currency_amount_preferred_currency_value_approx: preferred_currency_value_approx
}
}
}
}
}
Expand Down Expand Up @@ -434,6 +464,7 @@ fragment OutgoingPaymentFragment on OutgoingPayment {
currency_amount_preferred_currency_value_approx: preferred_currency_value_approx
}
}
outgoing_payment_payment_preimage: payment_preimage
}"""
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import kotlinx.serialization.json.jsonObject
* @param resolvedAt The time the outgoing payment attempt failed or succeeded.
* @param amount The total amount of funds required to complete a payment over this route. This value includes the cumulative fees for each hop. As a result, the attempt extended to the first-hop in the route will need to have at least this much value, otherwise the route will fail at an intermediate node due to an insufficient amount.
* @param fees The sum of the fees paid at each hop within the route of this attempt. In the case of a one-hop payment, this value will be zero as we don't need to pay a fee to ourselves.
* @param channelSnapshot The channel snapshot at the time the outgoing payment attempt was made.
*/
@Serializable
@SerialName("OutgoingPaymentAttempt")
Expand All @@ -49,6 +50,8 @@ data class OutgoingPaymentAttempt(
val amount: CurrencyAmount? = null,
@SerialName("outgoing_payment_attempt_fees")
val fees: CurrencyAmount? = null,
@SerialName("outgoing_payment_attempt_channel_snapshot")
val channelSnapshot: ChannelSnapshot? = null,
) : Entity {
@JvmOverloads
fun getHopsQuery(first: Int? = null, after: String? = null): Query<OutgoingPaymentAttemptToHopsConnection> {
Expand Down Expand Up @@ -162,6 +165,33 @@ fragment OutgoingPaymentAttemptFragment on OutgoingPaymentAttempt {
outgoing_payment_attempt_outgoing_payment: outgoing_payment {
id
}
outgoing_payment_attempt_channel_snapshot: channel_snapshot {
type: __typename
channel_snapshot_local_balance: local_balance {
type: __typename
currency_amount_original_value: original_value
currency_amount_original_unit: original_unit
currency_amount_preferred_currency_unit: preferred_currency_unit
currency_amount_preferred_currency_value_rounded: preferred_currency_value_rounded
currency_amount_preferred_currency_value_approx: preferred_currency_value_approx
}
channel_snapshot_local_unsettled_balance: local_unsettled_balance {
type: __typename
currency_amount_original_value: original_value
currency_amount_original_unit: original_unit
currency_amount_preferred_currency_unit: preferred_currency_unit
currency_amount_preferred_currency_value_rounded: preferred_currency_value_rounded
currency_amount_preferred_currency_value_approx: preferred_currency_value_approx
}
channel_snapshot_local_channel_reserve: local_channel_reserve {
type: __typename
currency_amount_original_value: original_value
currency_amount_original_unit: original_unit
currency_amount_preferred_currency_unit: preferred_currency_unit
currency_amount_preferred_currency_value_rounded: preferred_currency_value_rounded
currency_amount_preferred_currency_value_approx: preferred_currency_value_approx
}
}
}"""
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import kotlinx.serialization.Serializable

/**
*
* @param provider The compliance provider that is going to screen the node. You need to be a customer of the selected provider and store the API key on the Lightspark account setting page.
* @param paymentId The Lightspark ID of the lightning payment you want to register. It can be the id of either an OutgoingPayment or an IncomingPayment.
* @param nodePubkey The public key of the counterparty lightning node, which would be the public key of the recipient node if it is to register an outgoing payment, or the public key of the sender node if it is to register an incoming payment.
* @param direction Indicates whether this payment is an OutgoingPayment or an IncomingPayment.
*/
@Serializable
@SerialName("RegisterPaymentInput")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import kotlinx.serialization.Serializable

/**
*
* @param channelId The unique identifier of the channel.
* @param perCommitmentSecret The per-commitment secret to be released.
* @param perCommitmentIndex The index associated with the per-commitment secret.
*/
@Serializable
@SerialName("ReleaseChannelPerCommitmentSecretInput")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import kotlinx.serialization.Serializable

/**
*
* @param channelId The channel object after the per-commitment secret release operation.
*/
@Serializable
@SerialName("ReleaseChannelPerCommitmentSecretOutput")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import kotlinx.serialization.Serializable

/**
*
* @param invoiceId The invoice of the transaction.
*/
@Serializable
@SerialName("ReleasePaymentPreimageOutput")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ enum class RemoteSigningSubEventType(val rawValue: String) {

REQUEST_INVOICE_PAYMENT_HASH("REQUEST_INVOICE_PAYMENT_HASH"),

REVEAL_COUNTERPARTY_PER_COMMITMENT_SECRET("REVEAL_COUNTERPARTY_PER_COMMITMENT_SECRET"),

/**
* This is an enum value that represents values that could be added in the future.
* Clients should support unknown values as more of them could be added without notice.
Expand Down
Loading