diff --git a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/clightning/CLightningJsonModels.scala b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/clightning/CLightningJsonModels.scala index edd18711a7..ca36df7aef 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/clightning/CLightningJsonModels.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/clightning/CLightningJsonModels.scala @@ -345,4 +345,8 @@ object CLightningJsonModels { case class ListTransactionsResults( transactions: Vector[CLightningTransaction] ) extends CLightningJsonModel + + case class SendCustomMessageResult( + status: String + ) extends CLightningJsonModel } diff --git a/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonSerializers.scala b/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonSerializers.scala index 96c100d22c..19167dedee 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonSerializers.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonSerializers.scala @@ -705,6 +705,9 @@ object JsonSerializers { ListTransactionsResults] = Json.reads[ListTransactionsResults] + implicit val SendCustomMessageResultReads: Reads[SendCustomMessageResult] = + Json.reads[SendCustomMessageResult] + implicit val byteVectorWrites: Writes[ByteVector] = Writes[ByteVector](bytes => JsString(bytes.toHex)) diff --git a/clightning-rpc-test/src/test/scala/com/bitcoins/clightning/rpc/CLightningClientPairTest.scala b/clightning-rpc-test/src/test/scala/com/bitcoins/clightning/rpc/CLightningClientPairTest.scala index fcd6443341..796080d940 100644 --- a/clightning-rpc-test/src/test/scala/com/bitcoins/clightning/rpc/CLightningClientPairTest.scala +++ b/clightning-rpc-test/src/test/scala/com/bitcoins/clightning/rpc/CLightningClientPairTest.scala @@ -2,6 +2,7 @@ package com.bitcoins.clightning.rpc import org.bitcoins.core.currency._ import org.bitcoins.core.number._ +import org.bitcoins.core.protocol.BigSizeUInt import org.bitcoins.core.protocol.script.EmptyScriptSignature import org.bitcoins.core.protocol.transaction._ import org.bitcoins.core.psbt.PSBT @@ -9,6 +10,7 @@ import org.bitcoins.core.wallet.fee.SatoshisPerKW import org.bitcoins.testkit.async.TestAsyncUtil import org.bitcoins.testkit.clightning.CLightningRpcTestUtil import org.bitcoins.testkit.fixtures.DualCLightningFixture +import scodec.bits._ import scala.concurrent.Future import scala.concurrent.duration.DurationInt @@ -160,4 +162,18 @@ class CLightningClientPairTest extends DualCLightningFixture { assert(newBalA === oldBalA - sendAmt - feeRate.calc(tx) +- Satoshis(200)) } } + + it must "send a custom message to another peer" in { params => + val (_, clightningA, clightningB) = params + + for { + nodeId <- clightningB.nodeId + result <- clightningA.sendCustomMessage( + nodeId, + BigSizeUInt(48001), + hex"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f") + } yield { + assert(result.status.nonEmpty) + } + } } diff --git a/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/CLightningRpcClient.scala b/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/CLightningRpcClient.scala index 79b2e06df4..5efbddf017 100644 --- a/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/CLightningRpcClient.scala +++ b/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/CLightningRpcClient.scala @@ -8,16 +8,18 @@ import org.bitcoins.commons.serializers.JsonSerializers._ import org.bitcoins.commons.util.NativeProcessFactory import org.bitcoins.core.currency.{CurrencyUnit, Satoshis} import org.bitcoins.core.hd.AddressType -import org.bitcoins.core.protocol.BitcoinAddress +import org.bitcoins.core.protocol._ import org.bitcoins.core.protocol.ln.LnInvoice import org.bitcoins.core.protocol.ln.channel.{FundedChannelId, ShortChannelId} import org.bitcoins.core.protocol.ln.currency.MilliSatoshis import org.bitcoins.core.protocol.ln.node.{NodeId, NodeUri} +import org.bitcoins.core.protocol.tlv._ import org.bitcoins.core.psbt.PSBT import org.bitcoins.core.util.StartStopAsync import org.bitcoins.core.wallet.fee._ import org.bitcoins.crypto.Sha256Digest import play.api.libs.json._ +import scodec.bits._ import java.io.File import java.net.InetSocketAddress @@ -326,6 +328,33 @@ class CLightningRpcClient(val instance: CLightningInstanceLocal, binary: File)( clightningCall[FundChannelCancelResult]("fundchannel_cancel", params) } + def sendCustomMessage( + peer: NodeId, + tpe: BigSizeUInt, + data: ByteVector): Future[SendCustomMessageResult] = { + val tlv = TLV.fromTypeAndValue(tpe, data) + sendCustomMessage(peer, tlv) + } + + def sendCustomMessage( + peer: NodeId, + tlv: TLV): Future[SendCustomMessageResult] = { + val lnMessage = LnMessage[TLV](tlv) + sendCustomMessage(peer, lnMessage) + } + + def sendCustomMessage( + peer: NodeId, + lnMessage: LnMessage[TLV]): Future[SendCustomMessageResult] = { + val params = JsObject( + Vector( + "node_id" -> JsString(peer.toString), + "msg" -> JsString(lnMessage.hex) + )) + + clightningCall[SendCustomMessageResult]("sendcustommsg", params) + } + override val cmd: String = { val logFileConf = instance.logFileOpt .map(f => s"--log-file=${f.getAbsolutePath}")