Swap-in wallet functionalities
This commit is contained in:
parent
2e22c0b80c
commit
d7333c87ad
@ -8,7 +8,6 @@ import fr.acinq.bitcoin.utils.Either
|
|||||||
import fr.acinq.bitcoin.utils.toEither
|
import fr.acinq.bitcoin.utils.toEither
|
||||||
import fr.acinq.lightning.BuildVersions
|
import fr.acinq.lightning.BuildVersions
|
||||||
import fr.acinq.lightning.Lightning.randomBytes32
|
import fr.acinq.lightning.Lightning.randomBytes32
|
||||||
import fr.acinq.lightning.Lightning.randomKey
|
|
||||||
import fr.acinq.lightning.NodeParams
|
import fr.acinq.lightning.NodeParams
|
||||||
import fr.acinq.lightning.bin.db.SqlitePaymentsDb
|
import fr.acinq.lightning.bin.db.SqlitePaymentsDb
|
||||||
import fr.acinq.lightning.bin.db.WalletPaymentId
|
import fr.acinq.lightning.bin.db.WalletPaymentId
|
||||||
@ -22,6 +21,7 @@ import fr.acinq.lightning.channel.states.ChannelStateWithCommitments
|
|||||||
import fr.acinq.lightning.channel.states.Closed
|
import fr.acinq.lightning.channel.states.Closed
|
||||||
import fr.acinq.lightning.channel.states.Closing
|
import fr.acinq.lightning.channel.states.Closing
|
||||||
import fr.acinq.lightning.channel.states.ClosingFeerates
|
import fr.acinq.lightning.channel.states.ClosingFeerates
|
||||||
|
import fr.acinq.lightning.channel.states.Normal
|
||||||
import fr.acinq.lightning.io.Peer
|
import fr.acinq.lightning.io.Peer
|
||||||
import fr.acinq.lightning.io.WrappedChannelCommand
|
import fr.acinq.lightning.io.WrappedChannelCommand
|
||||||
import fr.acinq.lightning.payment.Bolt11Invoice
|
import fr.acinq.lightning.payment.Bolt11Invoice
|
||||||
@ -43,7 +43,12 @@ import io.ktor.server.request.*
|
|||||||
import io.ktor.server.response.*
|
import io.ktor.server.response.*
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
import io.ktor.server.websocket.*
|
import io.ktor.server.websocket.*
|
||||||
|
import kotlinx.coroutines.CompletableDeferred
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
import kotlinx.coroutines.flow.filterNotNull
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@ -114,7 +119,10 @@ class Api(private val nodeParams: NodeParams, private val peer: Peer, private va
|
|||||||
.filterNot { it is Closing || it is Closed }
|
.filterNot { it is Closing || it is Closed }
|
||||||
.map { it.commitments.active.first().availableBalanceForSend(it.commitments.params, it.commitments.changes) }
|
.map { it.commitments.active.first().availableBalanceForSend(it.commitments.params, it.commitments.changes) }
|
||||||
.sum().truncateToSatoshi()
|
.sum().truncateToSatoshi()
|
||||||
call.respond(Balance(balance, nodeParams.feeCredit.value))
|
val swapInBalance = peer.swapInWallet.wallet.walletStateFlow
|
||||||
|
.map { it.totalBalance }
|
||||||
|
.distinctUntilChanged().first()
|
||||||
|
call.respond(Balance(balance, nodeParams.feeCredit.value, swapInBalance))
|
||||||
}
|
}
|
||||||
get("listchannels") {
|
get("listchannels") {
|
||||||
call.respond(peer.channels.values.toList())
|
call.respond(peer.channels.values.toList())
|
||||||
@ -181,6 +189,15 @@ class Api(private val nodeParams: NodeParams, private val peer: Peer, private va
|
|||||||
call.respond(OutgoingPayment(it))
|
call.respond(OutgoingPayment(it))
|
||||||
} ?: call.respond(HttpStatusCode.NotFound)
|
} ?: call.respond(HttpStatusCode.NotFound)
|
||||||
}
|
}
|
||||||
|
delete("payments/incoming/{paymentHash}") {
|
||||||
|
val paymentHash = call.parameters.getByteVector32("paymentHash")
|
||||||
|
val success = paymentDb.removeIncomingPayment(paymentHash)
|
||||||
|
if (success) {
|
||||||
|
call.respondText("Payment successfully deleted", status = HttpStatusCode.OK)
|
||||||
|
} else {
|
||||||
|
call.respondText("Payment not found or failed to delete", status = HttpStatusCode.NotFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
post("payinvoice") {
|
post("payinvoice") {
|
||||||
val formParameters = call.receiveParameters()
|
val formParameters = call.receiveParameters()
|
||||||
val overrideAmount = formParameters["amountSat"]?.let { it.toLongOrNull() ?: invalidType("amountSat", "integer") }?.sat?.toMilliSatoshi()
|
val overrideAmount = formParameters["amountSat"]?.let { it.toLongOrNull() ?: invalidType("amountSat", "integer") }?.sat?.toMilliSatoshi()
|
||||||
@ -214,6 +231,84 @@ class Api(private val nodeParams: NodeParams, private val peer: Peer, private va
|
|||||||
val offer = formParameters.getOffer("offer")
|
val offer = formParameters.getOffer("offer")
|
||||||
call.respond(offer)
|
call.respond(offer)
|
||||||
}
|
}
|
||||||
|
get("/getfinaladdress"){
|
||||||
|
val finalAddress = peer.finalWallet.finalAddress
|
||||||
|
call.respond(finalAddress)
|
||||||
|
}
|
||||||
|
get("/getswapinaddress") {
|
||||||
|
try {
|
||||||
|
val swapInWalletStateFlow = peer.swapInWallet.wallet.walletStateFlow
|
||||||
|
swapInWalletStateFlow
|
||||||
|
.map { it.lastDerivedAddress }
|
||||||
|
.filterNotNull()
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.collect { (address, derived) ->
|
||||||
|
call.respond(SwapInAddress(address, derived.index))
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
call.respond(HttpStatusCode.InternalServerError, "Error fetching swap-in address")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get("/finalwalletbalance") {
|
||||||
|
try {
|
||||||
|
val currentBlockHeight: Long = peer.currentTipFlow.filterNotNull().first().toLong()
|
||||||
|
val walletStateFlow = peer.finalWallet.wallet.walletStateFlow
|
||||||
|
val utxosFlow = walletStateFlow.map { walletState ->
|
||||||
|
walletState.utxos.groupBy { utxo ->
|
||||||
|
val confirmations = currentBlockHeight - utxo.blockHeight + 1
|
||||||
|
when {
|
||||||
|
confirmations < 1 -> "unconfirmed"
|
||||||
|
confirmations < 3 -> "weaklyConfirmed"
|
||||||
|
else -> "deeplyConfirmed"
|
||||||
|
}
|
||||||
|
}.mapValues { entry ->
|
||||||
|
entry.value.sumOf { it.amount.toLong() }
|
||||||
|
}
|
||||||
|
}.distinctUntilChanged()
|
||||||
|
val balancesByConfirmation = utxosFlow.first()
|
||||||
|
val response = WalletBalance(
|
||||||
|
unconfirmed = balancesByConfirmation["unconfirmed"] ?: 0L,
|
||||||
|
weaklyConfirmed = balancesByConfirmation["weaklyConfirmed"] ?: 0L,
|
||||||
|
deeplyConfirmed = balancesByConfirmation["deeplyConfirmed"] ?: 0L
|
||||||
|
)
|
||||||
|
|
||||||
|
call.respond(response)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
call.respond(HttpStatusCode.InternalServerError, "Error fetching Final wallet balance")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get("/swapinwalletbalance") {
|
||||||
|
try {
|
||||||
|
val currentBlockHeight: Long = peer.currentTipFlow.filterNotNull().first().toLong()
|
||||||
|
val walletStateFlow = peer.swapInWallet.wallet.walletStateFlow
|
||||||
|
val utxosFlow = walletStateFlow.map { walletState ->
|
||||||
|
walletState.utxos.groupBy { utxo ->
|
||||||
|
val confirmations = currentBlockHeight - utxo.blockHeight + 1
|
||||||
|
when {
|
||||||
|
confirmations < 1 -> "unconfirmed"
|
||||||
|
confirmations < 3 -> "weaklyConfirmed"
|
||||||
|
else -> "deeplyConfirmed"
|
||||||
|
}
|
||||||
|
}.mapValues { entry ->
|
||||||
|
entry.value.sumOf { it.amount.toLong() }
|
||||||
|
}
|
||||||
|
}.distinctUntilChanged()
|
||||||
|
val balancesByConfirmation = utxosFlow.first()
|
||||||
|
val response = WalletBalance(
|
||||||
|
unconfirmed = balancesByConfirmation["unconfirmed"] ?: 0L,
|
||||||
|
weaklyConfirmed = balancesByConfirmation["weaklyConfirmed"] ?: 0L,
|
||||||
|
deeplyConfirmed = balancesByConfirmation["deeplyConfirmed"] ?: 0L
|
||||||
|
)
|
||||||
|
call.respond(response)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
call.respond(HttpStatusCode.InternalServerError, "Error fetching Swapin wallet balance")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get("/swapintransactions") {
|
||||||
|
val wallet = peer.swapInWallet.wallet
|
||||||
|
val walletState = wallet.walletStateFlow.value
|
||||||
|
call.respond(walletState.utxos.toString()) //no serializable json structure for this
|
||||||
|
}
|
||||||
post("sendtoaddress") {
|
post("sendtoaddress") {
|
||||||
val res = kotlin.runCatching {
|
val res = kotlin.runCatching {
|
||||||
val formParameters = call.receiveParameters()
|
val formParameters = call.receiveParameters()
|
||||||
@ -231,6 +326,44 @@ class Api(private val nodeParams: NodeParams, private val peer: Peer, private va
|
|||||||
is Either.Left -> call.respondText(res.value.message.toString())
|
is Either.Left -> call.respondText(res.value.message.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
post("/splicein") {//Manual splice-in
|
||||||
|
val formParameters = call.receiveParameters()
|
||||||
|
val amountSat = formParameters.getLong("amountSat").msat //the splice in command will send all the balance in wallet
|
||||||
|
val feerate = FeeratePerKw(FeeratePerByte(formParameters.getLong("feerateSatByte").sat))
|
||||||
|
val walletInputs = peer.swapInWallet.wallet.walletStateFlow.value.utxos
|
||||||
|
|
||||||
|
val suitableChannel = peer.channels.values
|
||||||
|
.filterIsInstance<Normal>()
|
||||||
|
.firstOrNull { it.commitments.availableBalanceForReceive() > amountSat }
|
||||||
|
?: return@post call.respond(HttpStatusCode.BadRequest, "No suitable channel available for splice-in")
|
||||||
|
|
||||||
|
if (walletInputs.isEmpty()) {
|
||||||
|
return@post call.respond(HttpStatusCode.BadRequest, "No wallet inputs available for splice-in,swap-in wallet balance too low")
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
val spliceCommand = ChannelCommand.Commitment.Splice.Request(
|
||||||
|
replyTo = CompletableDeferred(),
|
||||||
|
spliceIn = walletInputs.let { it1 ->
|
||||||
|
ChannelCommand.Commitment.Splice.Request.SpliceIn(
|
||||||
|
it1, amountSat)
|
||||||
|
},
|
||||||
|
spliceOut = null,
|
||||||
|
requestRemoteFunding = null,
|
||||||
|
feerate = feerate
|
||||||
|
)
|
||||||
|
|
||||||
|
peer.send(WrappedChannelCommand(suitableChannel.channelId, spliceCommand))
|
||||||
|
|
||||||
|
when (val response = spliceCommand.replyTo.await()) {
|
||||||
|
is ChannelCommand.Commitment.Splice.Response.Created -> call.respondText("Splice-in successful: transaction ID ${response.fundingTxId}", status = HttpStatusCode.OK)
|
||||||
|
is ChannelCommand.Commitment.Splice.Response.Failure -> call.respondText("Splice-in failed: $response", status = HttpStatusCode.BadRequest)
|
||||||
|
else -> call.respondText("Splice-in failed: unexpected response type", status = HttpStatusCode.InternalServerError)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
call.respond(HttpStatusCode.InternalServerError, "Failed to process splice-in: ${e.localizedMessage}")
|
||||||
|
}
|
||||||
|
}
|
||||||
post("closechannel") {
|
post("closechannel") {
|
||||||
val formParameters = call.receiveParameters()
|
val formParameters = call.receiveParameters()
|
||||||
val channelId = formParameters.getByteVector32("channelId")
|
val channelId = formParameters.getByteVector32("channelId")
|
||||||
|
@ -37,6 +37,8 @@ import fr.acinq.lightning.bin.json.ApiType
|
|||||||
import fr.acinq.lightning.bin.logs.FileLogWriter
|
import fr.acinq.lightning.bin.logs.FileLogWriter
|
||||||
import fr.acinq.lightning.bin.logs.TimestampFormatter
|
import fr.acinq.lightning.bin.logs.TimestampFormatter
|
||||||
import fr.acinq.lightning.bin.logs.stringTimestamp
|
import fr.acinq.lightning.bin.logs.stringTimestamp
|
||||||
|
import fr.acinq.lightning.blockchain.electrum.ElectrumClient
|
||||||
|
import fr.acinq.lightning.blockchain.electrum.ElectrumWatcher
|
||||||
import fr.acinq.lightning.blockchain.mempool.MempoolSpaceClient
|
import fr.acinq.lightning.blockchain.mempool.MempoolSpaceClient
|
||||||
import fr.acinq.lightning.blockchain.mempool.MempoolSpaceWatcher
|
import fr.acinq.lightning.blockchain.mempool.MempoolSpaceWatcher
|
||||||
import fr.acinq.lightning.crypto.LocalKeyManager
|
import fr.acinq.lightning.crypto.LocalKeyManager
|
||||||
@ -48,6 +50,7 @@ import fr.acinq.lightning.io.TcpSocket
|
|||||||
import fr.acinq.lightning.logging.LoggerFactory
|
import fr.acinq.lightning.logging.LoggerFactory
|
||||||
import fr.acinq.lightning.payment.LiquidityPolicy
|
import fr.acinq.lightning.payment.LiquidityPolicy
|
||||||
import fr.acinq.lightning.utils.Connection
|
import fr.acinq.lightning.utils.Connection
|
||||||
|
import fr.acinq.lightning.utils.ServerAddress
|
||||||
import fr.acinq.lightning.utils.msat
|
import fr.acinq.lightning.utils.msat
|
||||||
import fr.acinq.lightning.utils.sat
|
import fr.acinq.lightning.utils.sat
|
||||||
import fr.acinq.lightning.utils.toByteVector
|
import fr.acinq.lightning.utils.toByteVector
|
||||||
@ -270,9 +273,26 @@ class Phoenixd : CliktCommand() {
|
|||||||
val paymentsDb = SqlitePaymentsDb(database)
|
val paymentsDb = SqlitePaymentsDb(database)
|
||||||
|
|
||||||
val mempoolSpace = MempoolSpaceClient(mempoolSpaceUrl, loggerFactory)
|
val mempoolSpace = MempoolSpaceClient(mempoolSpaceUrl, loggerFactory)
|
||||||
val watcher = MempoolSpaceWatcher(mempoolSpace, scope, loggerFactory, pollingInterval = mempoolPollingInterval)
|
//val watcher = MempoolSpaceWatcher(mempoolSpace, scope, loggerFactory, pollingInterval = mempoolPollingInterval)
|
||||||
|
|
||||||
|
val electrumClient = ElectrumClient(scope, nodeParams.loggerFactory)
|
||||||
|
val serverAddress = ServerAddress("electrum.acinq.co", 50002, TcpSocket.TLS.UNSAFE_CERTIFICATES)
|
||||||
|
val socketBuilder = TcpSocket.Builder()
|
||||||
|
|
||||||
|
runBlocking {
|
||||||
|
val connected = electrumClient.connect(serverAddress, socketBuilder)
|
||||||
|
if (!connected) {
|
||||||
|
consoleLog(yellow("Failed to connect to Electrum server"))
|
||||||
|
return@runBlocking
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
consoleLog(yellow("Successfully Connected to Electrum Server"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val electrumWatcher = ElectrumWatcher(electrumClient, scope, nodeParams.loggerFactory)
|
||||||
val peer = Peer(
|
val peer = Peer(
|
||||||
nodeParams = nodeParams, walletParams = lsp.walletParams, client = mempoolSpace, watcher = watcher, db = object : Databases {
|
nodeParams = nodeParams, walletParams = lsp.walletParams, client = mempoolSpace, watcher = electrumWatcher, db = object : Databases {
|
||||||
override val channels: ChannelsDb get() = channelsDb
|
override val channels: ChannelsDb get() = channelsDb
|
||||||
override val payments: PaymentsDb get() = paymentsDb
|
override val payments: PaymentsDb get() = paymentsDb
|
||||||
}, socketBuilder = TcpSocket.Builder(), scope
|
}, socketBuilder = TcpSocket.Builder(), scope
|
||||||
@ -302,7 +322,10 @@ class Phoenixd : CliktCommand() {
|
|||||||
peer.connectionState.dropWhile { it is Connection.CLOSED }.collect {
|
peer.connectionState.dropWhile { it is Connection.CLOSED }.collect {
|
||||||
when (it) {
|
when (it) {
|
||||||
Connection.ESTABLISHING -> consoleLog(yellow("connecting to lightning peer..."))
|
Connection.ESTABLISHING -> consoleLog(yellow("connecting to lightning peer..."))
|
||||||
Connection.ESTABLISHED -> consoleLog(yellow("connected to lightning peer"))
|
Connection.ESTABLISHED -> {
|
||||||
|
consoleLog(yellow("connected to lightning peer"))
|
||||||
|
peer.startWatchSwapInWallet()
|
||||||
|
}
|
||||||
is Connection.CLOSED -> consoleLog(yellow("disconnected from lightning peer"))
|
is Connection.CLOSED -> consoleLog(yellow("disconnected from lightning peer"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,8 +66,17 @@ sealed class ApiType {
|
|||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Balance(@SerialName("balanceSat") val amount: Satoshi, @SerialName("feeCreditSat") val feeCredit: Satoshi) : ApiType()
|
data class Balance(@SerialName("balanceSat") val amount: Satoshi, @SerialName("feeCreditSat") val feeCredit: Satoshi, @SerialName("swapInSat") val swapInBalance: Satoshi?) : ApiType()
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SwapInAddress(@SerialName("address") val address: String, @SerialName("index") val index: Int) : ApiType()
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class WalletBalance(
|
||||||
|
val unconfirmed: Long,
|
||||||
|
val weaklyConfirmed: Long,
|
||||||
|
val deeplyConfirmed: Long
|
||||||
|
) : ApiType()
|
||||||
@Serializable
|
@Serializable
|
||||||
data class GeneratedInvoice(@SerialName("amountSat") val amount: Satoshi?, val paymentHash: ByteVector32, val serialized: String) : ApiType()
|
data class GeneratedInvoice(@SerialName("amountSat") val amount: Satoshi?, val paymentHash: ByteVector32, val serialized: String) : ApiType()
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@ fun main(args: Array<String>) =
|
|||||||
ListOutgoingPayments(),
|
ListOutgoingPayments(),
|
||||||
GetIncomingPayment(),
|
GetIncomingPayment(),
|
||||||
ListIncomingPayments(),
|
ListIncomingPayments(),
|
||||||
|
DeleteIncomingPayment(),
|
||||||
CreateInvoice(),
|
CreateInvoice(),
|
||||||
GetOffer(),
|
GetOffer(),
|
||||||
PayInvoice(),
|
PayInvoice(),
|
||||||
@ -55,7 +56,13 @@ fun main(args: Array<String>) =
|
|||||||
DecodeInvoice(),
|
DecodeInvoice(),
|
||||||
DecodeOffer(),
|
DecodeOffer(),
|
||||||
SendToAddress(),
|
SendToAddress(),
|
||||||
CloseChannel()
|
CloseChannel(),
|
||||||
|
GetFinalAddress(),
|
||||||
|
GetSwapInAddress(),
|
||||||
|
GetFinalWalletBalance(),
|
||||||
|
GetSwapInWalletBalance(),
|
||||||
|
GetSwapInTransactions(),
|
||||||
|
ManualSpliceIn()
|
||||||
)
|
)
|
||||||
.main(args)
|
.main(args)
|
||||||
|
|
||||||
@ -190,6 +197,13 @@ class ListIncomingPayments : PhoenixCliCommand(name = "listincomingpayments", he
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DeleteIncomingPayment : PhoenixCliCommand(name = "deleteincomingpayment", help = "Delete an incoming payment") {
|
||||||
|
private val paymentHash by option("--paymentHash", "--h").convert { ByteVector32.fromValidHex(it) }.required()
|
||||||
|
override suspend fun httpRequest() = commonOptions.httpClient.use {
|
||||||
|
it.delete(url = commonOptions.baseUrl / "payments/incoming/$paymentHash")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class CreateInvoice : PhoenixCliCommand(name = "createinvoice", help = "Create a Lightning invoice", printHelpOnEmptyArgs = true) {
|
class CreateInvoice : PhoenixCliCommand(name = "createinvoice", help = "Create a Lightning invoice", printHelpOnEmptyArgs = true) {
|
||||||
private val amountSat by option("--amountSat").long()
|
private val amountSat by option("--amountSat").long()
|
||||||
private val description by mutuallyExclusiveOptions(
|
private val description by mutuallyExclusiveOptions(
|
||||||
@ -273,6 +287,36 @@ class DecodeOffer : PhoenixCliCommand(name = "decodeoffer", help = "Decode a Lig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class GetFinalAddress : PhoenixCliCommand(name = "getfinaladdress", help = "Retrieve the final wallet address", printHelpOnEmptyArgs = true) {
|
||||||
|
override suspend fun httpRequest() = commonOptions.httpClient.use {
|
||||||
|
it.get(url = commonOptions.baseUrl / "getfinaladdress")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GetSwapInAddress : PhoenixCliCommand(name = "getswapinaddress", help = "Retrieve the current swap-in address from the wallet", printHelpOnEmptyArgs = true) {
|
||||||
|
override suspend fun httpRequest() = commonOptions.httpClient.use {
|
||||||
|
it.get(url = commonOptions.baseUrl / "getswapinaddress")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GetFinalWalletBalance : PhoenixCliCommand(name = "getfinalwalletbalance", help = "Retrieve the final wallet balance", printHelpOnEmptyArgs = true) {
|
||||||
|
override suspend fun httpRequest() = commonOptions.httpClient.use {
|
||||||
|
it.get(url = commonOptions.baseUrl / "finalwalletbalance")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GetSwapInWalletBalance : PhoenixCliCommand(name = "getswapinwalletbalance", help = "Retrieve the swap-in wallet balance", printHelpOnEmptyArgs = true) {
|
||||||
|
override suspend fun httpRequest() = commonOptions.httpClient.use {
|
||||||
|
it.get(url = commonOptions.baseUrl / "swapinwalletbalance")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GetSwapInTransactions : PhoenixCliCommand(name = "getswapintransactions", help = "List transactions for the swap-in wallet", printHelpOnEmptyArgs = true) {
|
||||||
|
override suspend fun httpRequest() = commonOptions.httpClient.use {
|
||||||
|
it.get(url = commonOptions.baseUrl / "swapintransactions")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class SendToAddress : PhoenixCliCommand(name = "sendtoaddress", help = "Send to a Bitcoin address", printHelpOnEmptyArgs = true) {
|
class SendToAddress : PhoenixCliCommand(name = "sendtoaddress", help = "Send to a Bitcoin address", printHelpOnEmptyArgs = true) {
|
||||||
private val amountSat by option("--amountSat").long().required()
|
private val amountSat by option("--amountSat").long().required()
|
||||||
private val address by option("--address").required().check { runCatching { Base58Check.decode(it) }.isSuccess || runCatching { Bech32.decodeWitnessAddress(it) }.isSuccess }
|
private val address by option("--address").required().check { runCatching { Base58Check.decode(it) }.isSuccess || runCatching { Bech32.decodeWitnessAddress(it) }.isSuccess }
|
||||||
@ -289,6 +333,21 @@ class SendToAddress : PhoenixCliCommand(name = "sendtoaddress", help = "Send to
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ManualSpliceIn : PhoenixCliCommand(name = "splicein", help = "Splice in funds to a channel using all available balance in the wallet", printHelpOnEmptyArgs = true) {
|
||||||
|
private val amountSat by option("--amountSat").long().required() //not necessarily required, come back to it
|
||||||
|
private val feerateSatByte by option("--feerateSatByte").int().required()
|
||||||
|
|
||||||
|
override suspend fun httpRequest() = commonOptions.httpClient.use {
|
||||||
|
it.submitForm(
|
||||||
|
url = (commonOptions.baseUrl / "splicein").toString(),
|
||||||
|
formParameters = parameters {
|
||||||
|
append("amountSat", amountSat.toString())
|
||||||
|
append("feerateSatByte", feerateSatByte.toString())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class CloseChannel : PhoenixCliCommand(name = "closechannel", help = "Close channel", printHelpOnEmptyArgs = true) {
|
class CloseChannel : PhoenixCliCommand(name = "closechannel", help = "Close channel", printHelpOnEmptyArgs = true) {
|
||||||
private val channelId by option("--channelId").convert { it.toByteVector32() }.required()
|
private val channelId by option("--channelId").convert { it.toByteVector32() }.required()
|
||||||
private val address by option("--address").required().check { runCatching { Base58Check.decode(it) }.isSuccess || runCatching { Bech32.decodeWitnessAddress(it) }.isSuccess }
|
private val address by option("--address").required().check { runCatching { Base58Check.decode(it) }.isSuccess || runCatching { Bech32.decodeWitnessAddress(it) }.isSuccess }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user