@@ -58,6 +58,15 @@ interface LightningMessage {
5858 FundingCreated .type -> FundingCreated .read(stream)
5959 FundingSigned .type -> FundingSigned .read(stream)
6060 FundingLocked .type -> FundingLocked .read(stream)
61+ TxAddInput .type -> TxAddInput .read(stream)
62+ TxAddOutput .type -> TxAddOutput .read(stream)
63+ TxRemoveInput .type -> TxRemoveInput .read(stream)
64+ TxRemoveOutput .type -> TxRemoveOutput .read(stream)
65+ TxComplete .type -> TxComplete .read(stream)
66+ TxSignatures .type -> TxSignatures .read(stream)
67+ TxInitRbf .type -> TxInitRbf .read(stream)
68+ TxAckRbf .type -> TxAckRbf .read(stream)
69+ TxAbort .type -> TxAbort .read(stream)
6170 CommitSig .type -> CommitSig .read(stream)
6271 RevokeAndAck .type -> RevokeAndAck .read(stream)
6372 UpdateAddHtlc .type -> UpdateAddHtlc .read(stream)
@@ -123,6 +132,9 @@ interface HtlcSettlementMessage : UpdateMessage {
123132 val id: Long
124133}
125134
135+ sealed class InteractiveTxMessage : LightningMessage
136+ sealed class InteractiveTxConstructionMessage : InteractiveTxMessage ()
137+
126138interface HasTemporaryChannelId : LightningMessage {
127139 val temporaryChannelId: ByteVector32
128140}
@@ -131,6 +143,10 @@ interface HasChannelId : LightningMessage {
131143 val channelId: ByteVector32
132144}
133145
146+ interface HasSerialId : LightningMessage {
147+ val serialId: Long
148+ }
149+
134150interface HasChainHash : LightningMessage {
135151 val chainHash: ByteVector32
136152}
@@ -288,6 +304,261 @@ data class Pong(val data: ByteVector) : SetupMessage {
288304 }
289305}
290306
307+ data class TxAddInput (
308+ override val channelId : ByteVector32 ,
309+ override val serialId : Long ,
310+ val previousTx : Transaction ,
311+ val previousTxOutput : Long ,
312+ val sequence : Long ,
313+ val tlvs : TlvStream <TxAddInputTlv > = TlvStream .empty()
314+ ) : InteractiveTxConstructionMessage(), HasChannelId, HasSerialId {
315+ override val type: Long get() = TxAddInput .type
316+
317+ override fun write (out : Output ) {
318+ LightningCodecs .writeBytes(channelId.toByteArray(), out )
319+ LightningCodecs .writeU64(serialId, out )
320+ val encodedTx = Transaction .write(previousTx)
321+ LightningCodecs .writeU16(encodedTx.size, out )
322+ LightningCodecs .writeBytes(encodedTx, out )
323+ LightningCodecs .writeU32(previousTxOutput.toInt(), out )
324+ LightningCodecs .writeU32(sequence.toInt(), out )
325+ }
326+
327+ companion object : LightningMessageReader <TxAddInput > {
328+ const val type: Long = 66
329+
330+ override fun read (input : Input ): TxAddInput = TxAddInput (
331+ LightningCodecs .bytes(input, 32 ).byteVector32(),
332+ LightningCodecs .u64(input),
333+ Transaction .read(LightningCodecs .bytes(input, LightningCodecs .u16(input))),
334+ LightningCodecs .u32(input).toLong(),
335+ LightningCodecs .u32(input).toLong(),
336+ )
337+ }
338+ }
339+
340+ data class TxAddOutput (
341+ override val channelId : ByteVector32 ,
342+ override val serialId : Long ,
343+ val amount : Satoshi ,
344+ val pubkeyScript : ByteVector ,
345+ val tlvs : TlvStream <TxAddOutputTlv > = TlvStream .empty()
346+ ) : InteractiveTxConstructionMessage(), HasChannelId, HasSerialId {
347+ override val type: Long get() = TxAddOutput .type
348+
349+ override fun write (out : Output ) {
350+ LightningCodecs .writeBytes(channelId.toByteArray(), out )
351+ LightningCodecs .writeU64(serialId, out )
352+ LightningCodecs .writeU64(amount.toLong(), out )
353+ LightningCodecs .writeU16(pubkeyScript.size(), out )
354+ LightningCodecs .writeBytes(pubkeyScript, out )
355+ }
356+
357+ companion object : LightningMessageReader <TxAddOutput > {
358+ const val type: Long = 67
359+
360+ override fun read (input : Input ): TxAddOutput = TxAddOutput (
361+ LightningCodecs .bytes(input, 32 ).byteVector32(),
362+ LightningCodecs .u64(input),
363+ LightningCodecs .u64(input).sat,
364+ LightningCodecs .bytes(input, LightningCodecs .u16(input)).byteVector(),
365+ )
366+ }
367+ }
368+
369+ data class TxRemoveInput (
370+ override val channelId : ByteVector32 ,
371+ override val serialId : Long ,
372+ val tlvs : TlvStream <TxRemoveInputTlv > = TlvStream .empty()
373+ ) : InteractiveTxConstructionMessage(), HasChannelId, HasSerialId {
374+ override val type: Long get() = TxRemoveInput .type
375+
376+ override fun write (out : Output ) {
377+ LightningCodecs .writeBytes(channelId.toByteArray(), out )
378+ LightningCodecs .writeU64(serialId, out )
379+ }
380+
381+ companion object : LightningMessageReader <TxRemoveInput > {
382+ const val type: Long = 68
383+
384+ override fun read (input : Input ): TxRemoveInput = TxRemoveInput (
385+ LightningCodecs .bytes(input, 32 ).byteVector32(),
386+ LightningCodecs .u64(input),
387+ )
388+ }
389+ }
390+
391+ data class TxRemoveOutput (
392+ override val channelId : ByteVector32 ,
393+ override val serialId : Long ,
394+ val tlvs : TlvStream <TxRemoveOutputTlv > = TlvStream .empty()
395+ ) : InteractiveTxConstructionMessage(), HasChannelId, HasSerialId {
396+ override val type: Long get() = TxRemoveOutput .type
397+
398+ override fun write (out : Output ) {
399+ LightningCodecs .writeBytes(channelId.toByteArray(), out )
400+ LightningCodecs .writeU64(serialId, out )
401+ }
402+
403+ companion object : LightningMessageReader <TxRemoveOutput > {
404+ const val type: Long = 69
405+
406+ override fun read (input : Input ): TxRemoveOutput = TxRemoveOutput (
407+ LightningCodecs .bytes(input, 32 ).byteVector32(),
408+ LightningCodecs .u64(input),
409+ )
410+ }
411+ }
412+
413+ data class TxComplete (
414+ override val channelId : ByteVector32 ,
415+ val tlvs : TlvStream <TxCompleteTlv > = TlvStream .empty()
416+ ) : InteractiveTxConstructionMessage(), HasChannelId {
417+ override val type: Long get() = TxComplete .type
418+
419+ override fun write (out : Output ) = LightningCodecs .writeBytes(channelId.toByteArray(), out )
420+
421+ companion object : LightningMessageReader <TxComplete > {
422+ const val type: Long = 70
423+
424+ override fun read (input : Input ): TxComplete = TxComplete (LightningCodecs .bytes(input, 32 ).byteVector32())
425+ }
426+ }
427+
428+ data class TxSignatures (
429+ override val channelId : ByteVector32 ,
430+ val txId : ByteVector32 ,
431+ val witnesses : List <ScriptWitness >,
432+ val tlvs : TlvStream <TxSignaturesTlv > = TlvStream .empty()
433+ ) : InteractiveTxMessage(), HasChannelId {
434+ override val type: Long get() = TxSignatures .type
435+
436+ override fun write (out : Output ) {
437+ LightningCodecs .writeBytes(channelId.toByteArray(), out )
438+ LightningCodecs .writeBytes(txId.toByteArray(), out )
439+ LightningCodecs .writeU16(witnesses.size, out )
440+ witnesses.forEach { witness ->
441+ LightningCodecs .writeU16(witness.stack.size, out )
442+ witness.stack.forEach { element ->
443+ LightningCodecs .writeU16(element.size(), out )
444+ LightningCodecs .writeBytes(element.toByteArray(), out )
445+ }
446+ }
447+ }
448+
449+ companion object : LightningMessageReader <TxSignatures > {
450+ const val type: Long = 71
451+
452+ override fun read (input : Input ): TxSignatures {
453+ val channelId = LightningCodecs .bytes(input, 32 ).byteVector32()
454+ val txId = LightningCodecs .bytes(input, 32 ).byteVector32()
455+ val witnessCount = LightningCodecs .u16(input)
456+ val witnesses = ArrayList <ScriptWitness >(witnessCount)
457+ for (i in 1 .. witnessCount) {
458+ val stackSize = LightningCodecs .u16(input)
459+ val stack = ArrayList <ByteVector >(stackSize)
460+ for (j in 1 .. stackSize) {
461+ val elementSize = LightningCodecs .u16(input)
462+ stack + = LightningCodecs .bytes(input, elementSize).byteVector()
463+ }
464+ witnesses + = ScriptWitness (stack.toList())
465+ }
466+ return TxSignatures (channelId, txId, witnesses)
467+ }
468+ }
469+ }
470+
471+ data class TxInitRbf (
472+ override val channelId : ByteVector32 ,
473+ val lockTime : Long ,
474+ val feerate : FeeratePerKw ,
475+ val tlvs : TlvStream <TxInitRbfTlv > = TlvStream .empty()
476+ ) : InteractiveTxMessage(), HasChannelId {
477+ constructor (channelId: ByteVector32 , lockTime: Long , feerate: FeeratePerKw , fundingContribution: Satoshi ) : this (channelId, lockTime, feerate, TlvStream (listOf (TxInitRbfTlv .SharedOutputContributionTlv (fundingContribution))))
478+
479+ @Transient
480+ val fundingContribution = tlvs.get<TxInitRbfTlv .SharedOutputContributionTlv >()?.amount ? : 0 .sat
481+
482+ override val type: Long get() = TxInitRbf .type
483+
484+ override fun write (out : Output ) {
485+ LightningCodecs .writeBytes(channelId.toByteArray(), out )
486+ LightningCodecs .writeU32(lockTime.toInt(), out )
487+ LightningCodecs .writeU32(feerate.toLong().toInt(), out )
488+ TlvStreamSerializer (false , readers).write(tlvs, out )
489+ }
490+
491+ companion object : LightningMessageReader <TxInitRbf > {
492+ const val type: Long = 72
493+
494+ @Suppress(" UNCHECKED_CAST" )
495+ val readers = mapOf (TxInitRbfTlv .SharedOutputContributionTlv .tag to TxInitRbfTlv .SharedOutputContributionTlv .Companion as TlvValueReader <TxInitRbfTlv >)
496+
497+ override fun read (input : Input ): TxInitRbf = TxInitRbf (
498+ LightningCodecs .bytes(input, 32 ).byteVector32(),
499+ LightningCodecs .u32(input).toLong(),
500+ FeeratePerKw (LightningCodecs .u32(input).toLong().sat),
501+ TlvStreamSerializer (false , readers).read(input),
502+ )
503+ }
504+ }
505+
506+ data class TxAckRbf (
507+ override val channelId : ByteVector32 ,
508+ val tlvs : TlvStream <TxAckRbfTlv > = TlvStream .empty()
509+ ) : InteractiveTxMessage(), HasChannelId {
510+ constructor (channelId: ByteVector32 , fundingContribution: Satoshi ) : this (channelId, TlvStream (listOf (TxAckRbfTlv .SharedOutputContributionTlv (fundingContribution))))
511+
512+ @Transient
513+ val fundingContribution = tlvs.get<TxAckRbfTlv .SharedOutputContributionTlv >()?.amount ? : 0 .sat
514+
515+ override val type: Long get() = TxAckRbf .type
516+
517+ override fun write (out : Output ) {
518+ LightningCodecs .writeBytes(channelId.toByteArray(), out )
519+ TlvStreamSerializer (false , readers).write(tlvs, out )
520+ }
521+
522+ companion object : LightningMessageReader <TxAckRbf > {
523+ const val type: Long = 73
524+
525+ @Suppress(" UNCHECKED_CAST" )
526+ val readers = mapOf (TxAckRbfTlv .SharedOutputContributionTlv .tag to TxAckRbfTlv .SharedOutputContributionTlv .Companion as TlvValueReader <TxAckRbfTlv >)
527+
528+ override fun read (input : Input ): TxAckRbf = TxAckRbf (
529+ LightningCodecs .bytes(input, 32 ).byteVector32(),
530+ TlvStreamSerializer (false , readers).read(input),
531+ )
532+ }
533+ }
534+
535+ data class TxAbort (
536+ override val channelId : ByteVector32 ,
537+ val data : ByteVector ,
538+ val tlvs : TlvStream <TxAbortTlv > = TlvStream .empty()
539+ ) : InteractiveTxMessage(), HasChannelId {
540+ constructor (channelId: ByteVector32 , message: String? ) : this (channelId, ByteVector (message?.encodeToByteArray() ? : ByteArray (0 )))
541+
542+ fun toAscii (): String = data.toByteArray().decodeToString()
543+
544+ override val type: Long get() = TxAbort .type
545+
546+ override fun write (out : Output ) {
547+ LightningCodecs .writeBytes(channelId, out )
548+ LightningCodecs .writeU16(data.size(), out )
549+ LightningCodecs .writeBytes(data, out )
550+ }
551+
552+ companion object : LightningMessageReader <TxAbort > {
553+ const val type: Long = 74
554+
555+ override fun read (input : Input ): TxAbort = TxAbort (
556+ LightningCodecs .bytes(input, 32 ).byteVector32(),
557+ LightningCodecs .bytes(input, LightningCodecs .u16(input)).byteVector(),
558+ )
559+ }
560+ }
561+
291562@Serializable
292563data class OpenChannel (
293564 @Contextual override val chainHash : ByteVector32 ,
@@ -1353,7 +1624,6 @@ data class PhoenixAndroidLegacyInfo(
13531624 }
13541625}
13551626
1356- @OptIn(ExperimentalUnsignedTypes ::class )
13571627data class PhoenixAndroidLegacyMigrate (
13581628 val newNodeId : PublicKey
13591629) : LightningMessage {
@@ -1372,7 +1642,6 @@ data class PhoenixAndroidLegacyMigrate(
13721642 }
13731643}
13741644
1375- @OptIn(ExperimentalUnsignedTypes ::class )
13761645@Serializable
13771646data class OnionMessage (
13781647 @Contextual val blindingKey : PublicKey ,
0 commit comments