bolt3

Lightning transaction and script formats, per BOLT #3 (docs.ppad.tech/bolt3).
git clone git://git.ppad.tech/bolt3.git
Log | Files | Refs | README | LICENSE

Types.hs (12557B)


      1 {-# OPTIONS_HADDOCK prune #-}
      2 {-# LANGUAGE BangPatterns #-}
      3 {-# LANGUAGE DeriveGeneric #-}
      4 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
      5 
      6 -- |
      7 -- Module: Lightning.Protocol.BOLT3.Types
      8 -- Copyright: (c) 2025 Jared Tobin
      9 -- License: MIT
     10 -- Maintainer: Jared Tobin <jared@ppad.tech>
     11 --
     12 -- Core types for BOLT #3 transaction and script formats.
     13 
     14 module Lightning.Protocol.BOLT3.Types (
     15     -- * Monetary amounts
     16     Satoshi(..)
     17   , MilliSatoshi(..)
     18   , msat_to_sat
     19   , sat_to_msat
     20 
     21     -- * Keys and points
     22   , Pubkey(..)
     23   , pubkey
     24   , Seckey(..)
     25   , seckey
     26   , Point(..)
     27   , point
     28 
     29     -- * Hashes
     30   , PaymentHash(..)
     31   , payment_hash
     32   , PaymentPreimage(..)
     33   , payment_preimage
     34 
     35     -- * Transaction primitives
     36   , TxId(..)
     37   , mkTxId
     38   , OutPoint(..)
     39   , Sequence(..)
     40   , Locktime(..)
     41 
     42     -- * Channel parameters
     43   , CommitmentNumber(..)
     44   , commitment_number
     45   , ToSelfDelay(..)
     46   , CltvExpiry(..)
     47   , DustLimit(..)
     48   , FeeratePerKw(..)
     49 
     50     -- * HTLC types
     51   , HTLC(..)
     52   , HTLCDirection(..)
     53 
     54     -- * Basepoints
     55   , Basepoints(..)
     56   , PerCommitmentPoint(..)
     57   , PerCommitmentSecret(..)
     58   , per_commitment_secret
     59   , RevocationBasepoint(..)
     60   , PaymentBasepoint(..)
     61   , DelayedPaymentBasepoint(..)
     62   , HtlcBasepoint(..)
     63 
     64     -- * Derived keys
     65   , LocalPubkey(..)
     66   , RemotePubkey(..)
     67   , LocalDelayedPubkey(..)
     68   , RemoteDelayedPubkey(..)
     69   , LocalHtlcPubkey(..)
     70   , RemoteHtlcPubkey(..)
     71   , RevocationPubkey(..)
     72   , FundingPubkey(..)
     73 
     74     -- * Script
     75   , Script(..)
     76 
     77     -- * Witness (re-exported from ppad-tx)
     78   , Witness(..)
     79 
     80     -- * Channel options
     81   , ChannelFeatures(..)
     82   , has_anchors
     83 
     84     -- * Transaction weights (constants)
     85   , commitment_weight_no_anchors
     86   , commitment_weight_anchors
     87   , htlc_timeout_weight_no_anchors
     88   , htlc_timeout_weight_anchors
     89   , htlc_success_weight_no_anchors
     90   , htlc_success_weight_anchors
     91   , htlc_output_weight
     92 
     93     -- * Dust thresholds (constants)
     94   , dust_p2pkh
     95   , dust_p2sh
     96   , dust_p2wpkh
     97   , dust_p2wsh
     98   , anchor_output_value
     99   ) where
    100 
    101 import Bitcoin.Prim.Tx (TxId(..), mkTxId, OutPoint(..), Witness(..))
    102 import Data.Word (Word16, Word32, Word64)
    103 import qualified Data.ByteString as BS
    104 import GHC.Generics (Generic)
    105 
    106 -- monetary amounts ------------------------------------------------------------
    107 
    108 -- | Amount in satoshis.
    109 newtype Satoshi = Satoshi { unSatoshi :: Word64 }
    110   deriving (Eq, Ord, Show, Generic, Num)
    111 
    112 -- | Amount in millisatoshis.
    113 newtype MilliSatoshi = MilliSatoshi { unMilliSatoshi :: Word64 }
    114   deriving (Eq, Ord, Show, Generic, Num)
    115 
    116 -- | Convert millisatoshis to satoshis (rounds down).
    117 msat_to_sat :: MilliSatoshi -> Satoshi
    118 msat_to_sat (MilliSatoshi m) = Satoshi (m `div` 1000)
    119 {-# INLINE msat_to_sat #-}
    120 
    121 -- | Convert satoshis to millisatoshis.
    122 sat_to_msat :: Satoshi -> MilliSatoshi
    123 sat_to_msat (Satoshi s) = MilliSatoshi (s * 1000)
    124 {-# INLINE sat_to_msat #-}
    125 
    126 -- keys and points -------------------------------------------------------------
    127 
    128 -- | Compressed public key (33 bytes).
    129 newtype Pubkey = Pubkey { unPubkey :: BS.ByteString }
    130   deriving (Eq, Ord, Show, Generic)
    131 
    132 -- | Parse a 33-byte compressed public key.
    133 --
    134 -- Returns Nothing if the input is not exactly 33 bytes.
    135 --
    136 -- >>> pubkey (BS.replicate 33 0x02)
    137 -- Just (Pubkey ...)
    138 -- >>> pubkey (BS.replicate 32 0x02)
    139 -- Nothing
    140 pubkey :: BS.ByteString -> Maybe Pubkey
    141 pubkey bs
    142   | BS.length bs == 33 = Just (Pubkey bs)
    143   | otherwise = Nothing
    144 {-# INLINE pubkey #-}
    145 
    146 -- | Secret key (32 bytes).
    147 newtype Seckey = Seckey { unSeckey :: BS.ByteString }
    148   deriving (Eq, Generic)
    149 
    150 -- Don't show secret keys
    151 instance Show Seckey where
    152   show _ = "Seckey <redacted>"
    153 
    154 -- | Parse a 32-byte secret key.
    155 --
    156 -- Returns Nothing if the input is not exactly 32 bytes.
    157 seckey :: BS.ByteString -> Maybe Seckey
    158 seckey bs
    159   | BS.length bs == 32 = Just (Seckey bs)
    160   | otherwise = Nothing
    161 {-# INLINE seckey #-}
    162 
    163 -- | Elliptic curve point (33-byte compressed form).
    164 newtype Point = Point { unPoint :: BS.ByteString }
    165   deriving (Eq, Ord, Show, Generic)
    166 
    167 -- | Parse a 33-byte elliptic curve point.
    168 --
    169 -- Returns Nothing if the input is not exactly 33 bytes.
    170 point :: BS.ByteString -> Maybe Point
    171 point bs
    172   | BS.length bs == 33 = Just (Point bs)
    173   | otherwise = Nothing
    174 {-# INLINE point #-}
    175 
    176 -- hashes ----------------------------------------------------------------------
    177 
    178 -- | Payment hash (32 bytes, SHA256 of preimage).
    179 newtype PaymentHash = PaymentHash { unPaymentHash :: BS.ByteString }
    180   deriving (Eq, Ord, Show, Generic)
    181 
    182 -- | Parse a 32-byte payment hash.
    183 --
    184 -- Returns Nothing if the input is not exactly 32 bytes.
    185 payment_hash :: BS.ByteString -> Maybe PaymentHash
    186 payment_hash bs
    187   | BS.length bs == 32 = Just (PaymentHash bs)
    188   | otherwise = Nothing
    189 {-# INLINE payment_hash #-}
    190 
    191 -- | Payment preimage (32 bytes).
    192 newtype PaymentPreimage = PaymentPreimage { unPaymentPreimage :: BS.ByteString }
    193   deriving (Eq, Generic)
    194 
    195 instance Show PaymentPreimage where
    196   show _ = "PaymentPreimage <redacted>"
    197 
    198 -- | Parse a 32-byte payment preimage.
    199 --
    200 -- Returns Nothing if the input is not exactly 32 bytes.
    201 payment_preimage :: BS.ByteString -> Maybe PaymentPreimage
    202 payment_preimage bs
    203   | BS.length bs == 32 = Just (PaymentPreimage bs)
    204   | otherwise = Nothing
    205 {-# INLINE payment_preimage #-}
    206 
    207 -- transaction primitives ------------------------------------------------------
    208 
    209 -- | Transaction input sequence number.
    210 newtype Sequence = Sequence { unSequence :: Word32 }
    211   deriving (Eq, Ord, Show, Generic, Num)
    212 
    213 -- | Transaction locktime.
    214 newtype Locktime = Locktime { unLocktime :: Word32 }
    215   deriving (Eq, Ord, Show, Generic, Num)
    216 
    217 -- channel parameters ----------------------------------------------------------
    218 
    219 -- | 48-bit commitment number.
    220 newtype CommitmentNumber = CommitmentNumber { unCommitmentNumber :: Word64 }
    221   deriving (Eq, Ord, Show, Generic, Num)
    222 
    223 -- | Parse a 48-bit commitment number.
    224 --
    225 -- Returns Nothing if the value exceeds 2^48 - 1.
    226 commitment_number :: Word64 -> Maybe CommitmentNumber
    227 commitment_number n
    228   | n <= 281474976710655 = Just (CommitmentNumber n)
    229   | otherwise = Nothing
    230 {-# INLINE commitment_number #-}
    231 
    232 -- | CSV delay for to_local outputs.
    233 newtype ToSelfDelay = ToSelfDelay { unToSelfDelay :: Word16 }
    234   deriving (Eq, Ord, Show, Generic, Num)
    235 
    236 -- | CLTV expiry for HTLCs.
    237 newtype CltvExpiry = CltvExpiry { unCltvExpiry :: Word32 }
    238   deriving (Eq, Ord, Show, Generic, Num)
    239 
    240 -- | Dust limit threshold.
    241 newtype DustLimit = DustLimit { unDustLimit :: Satoshi }
    242   deriving (Eq, Ord, Show, Generic)
    243 
    244 -- | Fee rate in satoshis per 1000 weight units.
    245 newtype FeeratePerKw = FeeratePerKw { unFeeratePerKw :: Word32 }
    246   deriving (Eq, Ord, Show, Generic, Num)
    247 
    248 -- HTLC types ------------------------------------------------------------------
    249 
    250 -- | Direction of an HTLC from the commitment tx owner's perspective.
    251 data HTLCDirection
    252   = HTLCOffered   -- ^ We offered this HTLC (outgoing)
    253   | HTLCReceived  -- ^ We received this HTLC (incoming)
    254   deriving (Eq, Ord, Show, Generic)
    255 
    256 -- | HTLC output details.
    257 --
    258 -- NOTE: No Ord instance is provided. BOLT #3 requires output ordering by
    259 -- amount then scriptPubKey, but scriptPubKey depends on derived keys which
    260 -- are not available here. Use 'sort_outputs' in Tx module for proper BIP69
    261 -- output ordering.
    262 data HTLC = HTLC
    263   { htlc_direction    :: !HTLCDirection
    264   , htlc_amount_msat  :: {-# UNPACK #-} !MilliSatoshi
    265   , htlc_payment_hash :: {-# UNPACK #-} !PaymentHash
    266   , htlc_cltv_expiry  :: {-# UNPACK #-} !CltvExpiry
    267   } deriving (Eq, Show, Generic)
    268 
    269 -- basepoints ------------------------------------------------------------------
    270 
    271 -- | Per-commitment point (used to derive keys).
    272 newtype PerCommitmentPoint = PerCommitmentPoint { unPerCommitmentPoint :: Point }
    273   deriving (Eq, Ord, Show, Generic)
    274 
    275 -- | Per-commitment secret (32 bytes).
    276 newtype PerCommitmentSecret = PerCommitmentSecret
    277   { unPerCommitmentSecret :: BS.ByteString }
    278   deriving (Eq, Generic)
    279 
    280 instance Show PerCommitmentSecret where
    281   show _ = "PerCommitmentSecret <redacted>"
    282 
    283 -- | Parse a 32-byte per-commitment secret.
    284 --
    285 -- Returns Nothing if the input is not exactly 32 bytes.
    286 per_commitment_secret :: BS.ByteString -> Maybe PerCommitmentSecret
    287 per_commitment_secret bs
    288   | BS.length bs == 32 = Just (PerCommitmentSecret bs)
    289   | otherwise = Nothing
    290 {-# INLINE per_commitment_secret #-}
    291 
    292 -- | Revocation basepoint.
    293 newtype RevocationBasepoint = RevocationBasepoint
    294   { unRevocationBasepoint :: Point }
    295   deriving (Eq, Ord, Show, Generic)
    296 
    297 -- | Payment basepoint.
    298 newtype PaymentBasepoint = PaymentBasepoint
    299   { unPaymentBasepoint :: Point }
    300   deriving (Eq, Ord, Show, Generic)
    301 
    302 -- | Delayed payment basepoint.
    303 newtype DelayedPaymentBasepoint = DelayedPaymentBasepoint
    304   { unDelayedPaymentBasepoint :: Point }
    305   deriving (Eq, Ord, Show, Generic)
    306 
    307 -- | HTLC basepoint.
    308 newtype HtlcBasepoint = HtlcBasepoint { unHtlcBasepoint :: Point }
    309   deriving (Eq, Ord, Show, Generic)
    310 
    311 -- | Collection of all basepoints for one party.
    312 data Basepoints = Basepoints
    313   { bp_revocation      :: !RevocationBasepoint
    314   , bp_payment         :: !PaymentBasepoint
    315   , bp_delayed_payment :: !DelayedPaymentBasepoint
    316   , bp_htlc            :: !HtlcBasepoint
    317   } deriving (Eq, Show, Generic)
    318 
    319 -- derived keys ----------------------------------------------------------------
    320 
    321 -- | Local pubkey (derived from payment_basepoint + per_commitment_point).
    322 newtype LocalPubkey = LocalPubkey { unLocalPubkey :: Pubkey }
    323   deriving (Eq, Ord, Show, Generic)
    324 
    325 -- | Remote pubkey (simply the remote's payment_basepoint).
    326 newtype RemotePubkey = RemotePubkey { unRemotePubkey :: Pubkey }
    327   deriving (Eq, Ord, Show, Generic)
    328 
    329 -- | Local delayed pubkey.
    330 newtype LocalDelayedPubkey = LocalDelayedPubkey
    331   { unLocalDelayedPubkey :: Pubkey }
    332   deriving (Eq, Ord, Show, Generic)
    333 
    334 -- | Remote delayed pubkey.
    335 newtype RemoteDelayedPubkey = RemoteDelayedPubkey
    336   { unRemoteDelayedPubkey :: Pubkey }
    337   deriving (Eq, Ord, Show, Generic)
    338 
    339 -- | Local HTLC pubkey.
    340 newtype LocalHtlcPubkey = LocalHtlcPubkey { unLocalHtlcPubkey :: Pubkey }
    341   deriving (Eq, Ord, Show, Generic)
    342 
    343 -- | Remote HTLC pubkey.
    344 newtype RemoteHtlcPubkey = RemoteHtlcPubkey { unRemoteHtlcPubkey :: Pubkey }
    345   deriving (Eq, Ord, Show, Generic)
    346 
    347 -- | Revocation pubkey (derived from revocation_basepoint + per_commitment).
    348 newtype RevocationPubkey = RevocationPubkey { unRevocationPubkey :: Pubkey }
    349   deriving (Eq, Ord, Show, Generic)
    350 
    351 -- | Funding pubkey (used in 2-of-2 multisig).
    352 newtype FundingPubkey = FundingPubkey { unFundingPubkey :: Pubkey }
    353   deriving (Eq, Ord, Show, Generic)
    354 
    355 -- script ----------------------------------------------------------------------
    356 
    357 -- | Bitcoin script (serialized).
    358 newtype Script = Script { unScript :: BS.ByteString }
    359   deriving (Eq, Ord, Show, Generic)
    360 
    361 -- channel options -------------------------------------------------------------
    362 
    363 -- | Channel feature flags relevant to BOLT #3.
    364 data ChannelFeatures = ChannelFeatures
    365   { cf_option_anchors :: !Bool
    366   } deriving (Eq, Show, Generic)
    367 
    368 -- | Check if option_anchors is enabled.
    369 has_anchors :: ChannelFeatures -> Bool
    370 has_anchors = cf_option_anchors
    371 {-# INLINE has_anchors #-}
    372 
    373 -- transaction weights (constants from spec) -----------------------------------
    374 
    375 -- | Base commitment tx weight without option_anchors.
    376 commitment_weight_no_anchors :: Word64
    377 commitment_weight_no_anchors = 724
    378 
    379 -- | Base commitment tx weight with option_anchors.
    380 commitment_weight_anchors :: Word64
    381 commitment_weight_anchors = 1124
    382 
    383 -- | HTLC-timeout tx weight without option_anchors.
    384 htlc_timeout_weight_no_anchors :: Word64
    385 htlc_timeout_weight_no_anchors = 663
    386 
    387 -- | HTLC-timeout tx weight with option_anchors.
    388 htlc_timeout_weight_anchors :: Word64
    389 htlc_timeout_weight_anchors = 666
    390 
    391 -- | HTLC-success tx weight without option_anchors.
    392 htlc_success_weight_no_anchors :: Word64
    393 htlc_success_weight_no_anchors = 703
    394 
    395 -- | HTLC-success tx weight with option_anchors.
    396 htlc_success_weight_anchors :: Word64
    397 htlc_success_weight_anchors = 706
    398 
    399 -- | Weight added per HTLC output in commitment tx.
    400 htlc_output_weight :: Word64
    401 htlc_output_weight = 172
    402 
    403 -- dust thresholds (constants from Bitcoin Core) -------------------------------
    404 
    405 -- | P2PKH dust threshold (546 satoshis).
    406 dust_p2pkh :: Satoshi
    407 dust_p2pkh = Satoshi 546
    408 
    409 -- | P2SH dust threshold (540 satoshis).
    410 dust_p2sh :: Satoshi
    411 dust_p2sh = Satoshi 540
    412 
    413 -- | P2WPKH dust threshold (294 satoshis).
    414 dust_p2wpkh :: Satoshi
    415 dust_p2wpkh = Satoshi 294
    416 
    417 -- | P2WSH dust threshold (330 satoshis).
    418 dust_p2wsh :: Satoshi
    419 dust_p2wsh = Satoshi 330
    420 
    421 -- | Fixed anchor output value (330 satoshis).
    422 anchor_output_value :: Satoshi
    423 anchor_output_value = Satoshi 330