@@ -4,6 +4,7 @@ open NBitcoin
44
55open DotNetLightning.Utils
66open DotNetLightning.Transactions
7+ open DotNetLightning.Transactions .Transactions
78open DotNetLightning.Crypto
89open DotNetLightning.Chain
910open DotNetLightning.Serialization .Msgs
@@ -437,6 +438,109 @@ module RemoteForceClose =
437438 return obscuredCommitmentNumber
438439 }
439440
441+ let createPunishmentTx ( perCommitmentSecret : PerCommitmentSecret )
442+ ( commitments : Commitments )
443+ ( localChannelPrivKeys : ChannelPrivKeys )
444+ ( network : Network )
445+ : TransactionBuilder =
446+
447+ let localChannelPubKeys = commitments.LocalParams.ChannelPubKeys
448+ let remoteChannelPubKeys = commitments.RemoteParams.ChannelPubKeys
449+
450+ let perCommitmentPoint = perCommitmentSecret.PerCommitmentPoint()
451+
452+ let localCommitmentPubKeys =
453+ perCommitmentPoint.DeriveCommitmentPubKeys localChannelPubKeys
454+
455+ let remoteCommitmentPubKeys =
456+ perCommitmentPoint.DeriveCommitmentPubKeys remoteChannelPubKeys
457+
458+ let transactionBuilder = createTransactionBuilder network
459+
460+ let toRemoteScriptPubKey =
461+ localCommitmentPubKeys
462+ .PaymentPubKey
463+ .RawPubKey()
464+ .WitHash.ScriptPubKey
465+
466+ let toLocalScriptPubKey =
467+ Scripts.toLocalDelayed
468+ localCommitmentPubKeys.RevocationPubKey
469+ commitments.RemoteParams.ToSelfDelay
470+ remoteCommitmentPubKeys.DelayedPaymentPubKey
471+
472+ let toLocalWitScriptPubKey = toLocalScriptPubKey.WitHash.ScriptPubKey
473+
474+ let commitFee = commitTxFee
475+ commitments.RemoteParams.DustLimitSatoshis
476+ commitments.RemoteCommit.Spec
477+
478+ let ( toLocalAmount , toRemoteAmount ) =
479+ if ( commitments.LocalParams.IsFunder) then
480+ ( commitments.RemoteCommit.Spec.ToLocal.Satoshi
481+ |> Money.Satoshis),
482+ ( commitments.RemoteCommit.Spec.ToRemote.Satoshi
483+ |> Money.Satoshis) - commitFee
484+ else
485+ ( commitments.RemoteCommit.Spec.ToLocal.Satoshi
486+ |> Money.Satoshis) - commitFee,
487+ ( commitments.RemoteCommit.Spec.ToRemote.Satoshi
488+ |> Money.Satoshis)
489+
490+ let outputs =
491+ seq {
492+ if toLocalAmount > commitments.RemoteParams.DustLimitSatoshis then
493+ yield TxOut( toLocalAmount, toLocalWitScriptPubKey)
494+
495+ if toRemoteAmount > commitments.LocalParams.DustLimitSatoshis then
496+ yield TxOut( toRemoteAmount, toRemoteScriptPubKey)
497+ }
498+ |> Seq.sortWith TxOut.LexicographicCompare
499+
500+ let toRemoteIndex =
501+ outputs
502+ |> Seq.findIndex ( fun out -> out.ScriptPubKey = toRemoteScriptPubKey)
503+
504+ let toRemoteTxOut : TxOut =
505+ outputs
506+ |> Seq.item toRemoteIndex
507+
508+ let localPaymentPrivKey =
509+ perCommitmentPoint.DerivePaymentPrivKey localChannelPrivKeys.PaymentBasepointSecret
510+
511+ ( transactionBuilder.AddKeys( localPaymentPrivKey.RawKey()))
512+ .AddCoins( Coin
513+ ( commitments.RemoteCommit.TxId.Value,
514+ toRemoteIndex |> uint32,
515+ toRemoteTxOut.Value,
516+ toRemoteTxOut.ScriptPubKey))
517+ |> ignore
518+
519+ let toLocalIndex =
520+ outputs
521+ |> Seq.findIndex ( fun out -> out.ScriptPubKey = toLocalWitScriptPubKey)
522+
523+ let toLocalTxOut : TxOut =
524+ outputs
525+ |> Seq.item toLocalIndex
526+
527+ let revocationPrivKey =
528+ perCommitmentSecret.DeriveRevocationPrivKey localChannelPrivKeys.RevocationBasepointSecret
529+
530+ transactionBuilder.Extensions.Add( CommitmentToLocalExtension())
531+ |> ignore
532+
533+ ( transactionBuilder.AddKeys( revocationPrivKey.RawKey()))
534+ .AddCoins( ScriptCoin
535+ ( commitments.RemoteCommit.TxId.Value,
536+ toLocalIndex |> uint32,
537+ toLocalTxOut.Value,
538+ toLocalWitScriptPubKey,
539+ toLocalScriptPubKey))
540+ |> ignore
541+
542+ transactionBuilder
543+
440544 let tryGetFundsFromRemoteCommitmentTx ( commitments : Commitments )
441545 ( localChannelPrivKeys : ChannelPrivKeys )
442546 ( network : Network )
0 commit comments