1use std::collections::BTreeMap;
15
16use bitcoin::blockdata::opcodes::all::*;
17use bitcoin::blockdata::script;
18use bitcoin::secp256k1::PublicKey;
19use bitcoin::{OutPoint, Transaction, TxIn, TxOut};
20use bitcoin_scripts::hlc::{HashLock, HashPreimage};
21use bitcoin_scripts::{LockScript, PubkeyScript, WitnessScript};
22use lnp2p::bolt::{ChannelId, Messages};
23use p2p::bolt::ChannelType;
24use wallet::psbt;
25use wallet::psbt::{Psbt, PsbtVersion};
26
27use crate::channel::bolt::util::UpdateReq;
28use crate::channel::bolt::{BoltExt, ChannelState, Error, TxType};
29use crate::channel::tx_graph::TxGraph;
30use crate::{ChannelExtension, Extension};
31
32#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
33#[derive(StrictEncode, StrictDecode)]
34#[cfg_attr(
35 feature = "serde",
36 derive(Serialize, Deserialize),
37 serde(crate = "serde_crate")
38)]
39pub struct HtlcKnown {
40 pub amount: u64,
41 pub preimage: HashPreimage,
42 pub id: u64,
43 pub cltv_expiry: u32,
44}
45
46#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
47#[derive(StrictEncode, StrictDecode)]
48#[cfg_attr(
49 feature = "serde",
50 derive(Serialize, Deserialize),
51 serde(crate = "serde_crate")
52)]
53pub struct HtlcSecret {
54 pub amount: u64,
55 pub hashlock: HashLock,
56 pub id: u64,
57 pub cltv_expiry: u32,
58}
59
60#[derive(Getters, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
61#[derive(StrictEncode, StrictDecode)]
62pub struct Htlc {
63 anchors_zero_fee_htlc_tx: bool,
67
68 offered_htlcs: BTreeMap<u64, HtlcSecret>,
70 received_htlcs: BTreeMap<u64, HtlcSecret>,
71 resolved_htlcs: BTreeMap<u64, HtlcKnown>,
72
73 to_self_delay: u16,
75 local_revocation_basepoint: PublicKey,
76 remote_revocation_basepoint: PublicKey,
77 local_basepoint: PublicKey,
78 remote_basepoint: PublicKey,
79 local_delayed_basepoint: PublicKey,
80
81 channel_id: ChannelId,
83
84 htlc_minimum_msat: u64,
86 max_htlc_value_in_flight_msat: u64,
87 max_accepted_htlcs: u16,
88
89 next_recieved_htlc_id: u64,
90 next_offered_htlc_id: u64,
91}
92
93impl Default for Htlc {
94 fn default() -> Self {
95 Htlc {
96 anchors_zero_fee_htlc_tx: false,
97 offered_htlcs: empty!(),
98 received_htlcs: empty!(),
99 resolved_htlcs: empty!(),
100 to_self_delay: 0,
101 local_revocation_basepoint: dumb_pubkey!(),
102 remote_revocation_basepoint: dumb_pubkey!(),
103 local_basepoint: dumb_pubkey!(),
104 remote_basepoint: dumb_pubkey!(),
105 local_delayed_basepoint: dumb_pubkey!(),
106 channel_id: Default::default(),
107 htlc_minimum_msat: 0,
108 max_htlc_value_in_flight_msat: 0,
109 max_accepted_htlcs: 0,
110 next_recieved_htlc_id: 0,
111 next_offered_htlc_id: 0,
112 }
113 }
114}
115
116impl Htlc {
117 pub fn offer_htlc(
118 &mut self,
119 amount_msat: u64,
120 payment_hash: HashLock,
121 cltv_expiry: u32,
122 ) -> u64 {
123 let htlc_id = self.next_offered_htlc_id;
124 self.next_offered_htlc_id += 1;
125 self.offered_htlcs.insert(htlc_id, HtlcSecret {
126 amount: amount_msat,
127 hashlock: payment_hash,
128 id: htlc_id,
129 cltv_expiry,
130 });
131 htlc_id
132 }
133}
134
135impl Extension<BoltExt> for Htlc {
136 fn identity(&self) -> BoltExt {
137 BoltExt::Htlc
138 }
139
140 fn update_from_local(&mut self, _message: &()) -> Result<(), Error> {
141 Ok(())
143 }
144
145 fn state_change(
146 &mut self,
147 request: &UpdateReq,
148 message: &mut Messages,
149 ) -> Result<(), Error> {
150 match (request, message) {
151 (
152 UpdateReq::PayBolt(_),
153 Messages::UpdateAddHtlc(update_add_htlc),
154 ) => {
155 let htlc_id = self.offer_htlc(
156 update_add_htlc.amount_msat,
157 update_add_htlc.payment_hash,
158 update_add_htlc.cltv_expiry,
159 );
160 update_add_htlc.htlc_id = htlc_id;
161 }
162 (UpdateReq::PayBolt(_), _) => unreachable!(
163 "state change request must match provided LN P2P message"
164 ),
165 }
166 Ok(())
167 }
168
169 fn update_from_peer(&mut self, message: &Messages) -> Result<(), Error> {
170 match message {
171 Messages::OpenChannel(open_channel) => {
172 self.anchors_zero_fee_htlc_tx = open_channel
173 .channel_type
174 .map(ChannelType::has_anchors_zero_fee_htlc_tx)
175 .unwrap_or_default();
176 self.htlc_minimum_msat = open_channel.htlc_minimum_msat;
177 self.max_accepted_htlcs = open_channel.max_accepted_htlcs;
178 self.max_htlc_value_in_flight_msat =
179 open_channel.max_htlc_value_in_flight_msat;
180 self.remote_basepoint = open_channel.htlc_basepoint;
181 self.remote_revocation_basepoint =
182 open_channel.revocation_basepoint;
183 self.local_delayed_basepoint =
184 open_channel.delayed_payment_basepoint;
185 self.to_self_delay = open_channel.to_self_delay;
186 }
187 Messages::AcceptChannel(accept_channel) => {
188 self.anchors_zero_fee_htlc_tx = accept_channel
189 .channel_type
190 .map(ChannelType::has_anchors_zero_fee_htlc_tx)
191 .unwrap_or_default();
192 self.htlc_minimum_msat = accept_channel.htlc_minimum_msat;
193 self.max_accepted_htlcs = accept_channel.max_accepted_htlcs;
194 self.max_htlc_value_in_flight_msat =
195 accept_channel.max_htlc_value_in_flight_msat;
196 self.remote_basepoint = accept_channel.htlc_basepoint;
197 self.remote_revocation_basepoint =
198 accept_channel.revocation_basepoint;
199 self.local_delayed_basepoint =
200 accept_channel.delayed_payment_basepoint;
201 self.to_self_delay = accept_channel.to_self_delay;
202 }
203 Messages::UpdateAddHtlc(message) => {
204 if message.channel_id == self.channel_id {
207 if message.amount_msat == 0
213 || message.amount_msat < self.htlc_minimum_msat
214 {
215 return Err(Error::Htlc(
216 "amount_msat has to be greater than 0".to_string(),
217 ));
218 } else if self.received_htlcs.len()
219 >= self.max_accepted_htlcs as usize
220 {
221 return Err(Error::Htlc(
222 "max no. of HTLC limit exceeded".to_string(),
223 ));
224 } else if message.cltv_expiry > 500000000 {
225 return Err(Error::Htlc(
226 "cltv_expiry limit exceeded".to_string(),
227 ));
228 } else if message.amount_msat.leading_zeros() < 32 {
229 return Err(Error::Htlc(
230 "Leading zeros not satisfied for Bitcoin network"
231 .to_string(),
232 ));
233 } else if message.htlc_id <= self.next_recieved_htlc_id {
234 return Err(Error::Htlc(
235 "HTLC id violation occurred".to_string(),
236 )); } else {
238 let htlc = HtlcSecret {
239 amount: message.amount_msat,
240 hashlock: message.payment_hash,
241 id: message.htlc_id,
242 cltv_expiry: message.cltv_expiry,
243 };
244 self.received_htlcs.insert(htlc.id, htlc);
245
246 self.next_recieved_htlc_id += 1;
247 }
248 } else {
249 return Err(Error::Htlc(
250 "Missmatched channel_id, bad remote node".to_string(),
251 ));
252 }
253 }
254 Messages::UpdateFulfillHtlc(message) => {
255 if message.channel_id == self.channel_id {
256 let offered_htlc =
258 self.received_htlcs.get(&message.htlc_id).ok_or_else(
259 || Error::Htlc("HTLC id didn't match".to_string()),
260 )?;
261
262 if offered_htlc.hashlock
264 == HashLock::from(message.payment_preimage)
265 {
266 self.offered_htlcs.remove(&message.htlc_id);
267 let resolved_htlc = HtlcKnown {
268 amount: offered_htlc.amount,
269 preimage: message.payment_preimage,
270 id: message.htlc_id,
271 cltv_expiry: offered_htlc.cltv_expiry,
272 };
273 self.resolved_htlcs
274 .insert(message.htlc_id, resolved_htlc);
275 }
276 } else {
277 return Err(Error::Htlc(
278 "Missmatched channel_id, bad remote node".to_string(),
279 ));
280 }
281 }
282 Messages::UpdateFailHtlc(message) => {
283 if message.channel_id == self.channel_id {
284 self.offered_htlcs.remove(&message.htlc_id);
285
286 }
288 }
289 Messages::UpdateFailMalformedHtlc(_) => {}
290 Messages::CommitmentSigned(_) => {}
291 Messages::RevokeAndAck(_) => {}
292 Messages::ChannelReestablish(_) => {}
293 _ => {}
294 }
295 Ok(())
296 }
297
298 fn load_state(&mut self, state: &ChannelState) {
299 self.anchors_zero_fee_htlc_tx = state
300 .common_params
301 .channel_type
302 .has_anchors_zero_fee_htlc_tx();
303
304 self.offered_htlcs = state.offered_htlcs.clone();
305 self.received_htlcs = state.received_htlcs.clone();
306 self.resolved_htlcs = state.resolved_htlcs.clone();
307
308 self.to_self_delay = state.remote_params.to_self_delay;
309 self.local_revocation_basepoint =
310 state.local_keys.revocation_basepoint.key;
311 self.remote_revocation_basepoint =
312 state.remote_keys.revocation_basepoint;
313 self.local_basepoint = state.local_keys.payment_basepoint.key;
314 self.remote_basepoint = state.remote_keys.payment_basepoint;
315 self.local_delayed_basepoint =
316 state.local_keys.delayed_payment_basepoint.key;
317
318 self.channel_id = state.active_channel_id.as_slice32().into();
319
320 self.htlc_minimum_msat = state.remote_params.htlc_minimum_msat;
321 self.max_htlc_value_in_flight_msat =
322 state.remote_params.max_htlc_value_in_flight_msat;
323 self.max_accepted_htlcs = state.remote_params.max_accepted_htlcs;
324
325 self.next_recieved_htlc_id = state.last_recieved_htlc_id;
326 self.next_offered_htlc_id = state.last_offered_htlc_id;
327 }
328
329 fn store_state(&self, state: &mut ChannelState) {
330 state.offered_htlcs = self.offered_htlcs.clone();
331 state.received_htlcs = self.received_htlcs.clone();
332 state.resolved_htlcs = self.resolved_htlcs.clone();
333 state.last_recieved_htlc_id = self.next_recieved_htlc_id;
334 state.last_offered_htlc_id = self.next_offered_htlc_id;
335 }
336}
337
338impl ChannelExtension<BoltExt> for Htlc {
339 #[inline]
340 fn new() -> Box<dyn ChannelExtension<BoltExt>>
341 where
342 Self: Sized,
343 {
344 Box::new(Htlc::default())
345 }
346
347 fn build_graph(
348 &self,
349 tx_graph: &mut TxGraph,
350 _as_remote_node: bool,
351 ) -> Result<(), Error> {
352 for (index, offered) in self.offered_htlcs.iter() {
354 let htlc_output = ScriptGenerators::ln_offered_htlc(
355 offered.amount,
356 self.remote_revocation_basepoint,
357 self.local_basepoint,
358 self.remote_basepoint,
359 offered.hashlock,
360 );
361 tx_graph.cmt_outs.push(htlc_output); let htlc_tx = Psbt::ln_htlc(
364 offered.amount,
365 OutPoint::default(),
367 offered.cltv_expiry,
368 self.remote_revocation_basepoint,
369 self.local_delayed_basepoint,
370 self.to_self_delay,
371 );
372 let last_index = tx_graph.last_index(TxType::HtlcTimeout) + 1;
374 tx_graph.insert_tx(
375 TxType::HtlcTimeout,
376 last_index as u64 + index,
377 htlc_tx,
378 );
379 }
380
381 for (index, recieved) in self.received_htlcs.iter() {
383 let htlc_output = ScriptGenerators::ln_received_htlc(
384 recieved.amount,
385 self.remote_revocation_basepoint,
386 self.local_basepoint,
387 self.remote_basepoint,
388 recieved.cltv_expiry,
389 recieved.hashlock,
390 );
391 tx_graph.cmt_outs.push(htlc_output);
392
393 let htlc_tx = Psbt::ln_htlc(
394 recieved.amount,
395 OutPoint::default(),
397 recieved.cltv_expiry,
398 self.remote_revocation_basepoint,
399 self.local_delayed_basepoint,
400 self.to_self_delay,
401 );
402 let last_index = tx_graph.last_index(TxType::HtlcSuccess) + 1;
404 tx_graph.insert_tx(
405 TxType::HtlcSuccess,
406 last_index as u64 + index,
407 htlc_tx,
408 );
409 }
410 Ok(())
411 }
412}
413
414pub trait ScriptGenerators {
415 fn ln_offered_htlc(
416 amount: u64,
417 revocationpubkey: PublicKey,
418 local_htlcpubkey: PublicKey,
419 remote_htlcpubkey: PublicKey,
420 payment_hash: HashLock,
421 ) -> Self;
422
423 fn ln_received_htlc(
424 amount: u64,
425 revocationpubkey: PublicKey,
426 local_htlcpubkey: PublicKey,
427 remote_htlcpubkey: PublicKey,
428 cltv_expiry: u32,
429 payment_hash: HashLock,
430 ) -> Self;
431
432 fn ln_htlc_output(
433 amount: u64,
434 revocationpubkey: PublicKey,
435 local_delayedpubkey: PublicKey,
436 to_self_delay: u16,
437 ) -> Self;
438}
439
440impl ScriptGenerators for LockScript {
441 fn ln_offered_htlc(
442 _: u64,
443 revocationpubkey: PublicKey,
444 local_htlcpubkey: PublicKey,
445 remote_htlcpubkey: PublicKey,
446 payment_hash: HashLock,
447 ) -> Self {
448 script::Builder::new()
449 .push_opcode(OP_DUP)
450 .push_opcode(OP_HASH160)
451 .push_slice(
452 &bitcoin::PublicKey::new(revocationpubkey).pubkey_hash(),
453 )
454 .push_opcode(OP_EQUAL)
455 .push_opcode(OP_IF)
456 .push_opcode(OP_CHECKSIG)
457 .push_opcode(OP_ELSE)
458 .push_key(&bitcoin::PublicKey::new(remote_htlcpubkey))
459 .push_opcode(OP_SWAP)
460 .push_opcode(OP_SIZE)
461 .push_int(32)
462 .push_opcode(OP_EQUAL)
463 .push_opcode(OP_NOTIF)
464 .push_opcode(OP_DROP)
465 .push_int(2)
466 .push_opcode(OP_SWAP)
467 .push_key(&bitcoin::PublicKey::new(local_htlcpubkey))
468 .push_int(2)
469 .push_opcode(OP_CHECKMULTISIG)
470 .push_opcode(OP_ELSE)
471 .push_opcode(OP_HASH160)
472 .push_slice(payment_hash.as_ref())
473 .push_opcode(OP_EQUALVERIFY)
474 .push_opcode(OP_CHECKSIG)
475 .push_opcode(OP_ENDIF)
476 .push_opcode(OP_ENDIF)
477 .into_script()
478 .into()
479 }
480
481 fn ln_received_htlc(
482 _: u64,
483 revocationpubkey: PublicKey,
484 local_htlcpubkey: PublicKey,
485 remote_htlcpubkey: PublicKey,
486 cltv_expiry: u32,
487 payment_hash: HashLock,
488 ) -> Self {
489 script::Builder::new()
490 .push_opcode(OP_DUP)
491 .push_opcode(OP_HASH160)
492 .push_slice(
493 &bitcoin::PublicKey::new(revocationpubkey).pubkey_hash(),
494 )
495 .push_opcode(OP_EQUAL)
496 .push_opcode(OP_IF)
497 .push_opcode(OP_CHECKSIG)
498 .push_opcode(OP_ELSE)
499 .push_key(&bitcoin::PublicKey::new(remote_htlcpubkey))
500 .push_opcode(OP_SWAP)
501 .push_opcode(OP_SIZE)
502 .push_int(32)
503 .push_opcode(OP_EQUAL)
504 .push_opcode(OP_IF)
505 .push_opcode(OP_HASH160)
506 .push_slice(payment_hash.as_ref())
507 .push_opcode(OP_EQUALVERIFY)
508 .push_int(2)
509 .push_opcode(OP_SWAP)
510 .push_key(&bitcoin::PublicKey::new(local_htlcpubkey))
511 .push_int(2)
512 .push_opcode(OP_CHECKMULTISIG)
513 .push_opcode(OP_ELSE)
514 .push_opcode(OP_DROP)
515 .push_int(cltv_expiry as i64)
516 .push_opcode(OP_CLTV)
517 .push_opcode(OP_DROP)
518 .push_opcode(OP_CHECKSIG)
519 .push_opcode(OP_ENDIF)
520 .push_opcode(OP_ENDIF)
521 .into_script()
522 .into()
523 }
524
525 fn ln_htlc_output(
526 _: u64,
527 revocationpubkey: PublicKey,
528 local_delayedpubkey: PublicKey,
529 to_self_delay: u16,
530 ) -> Self {
531 script::Builder::new()
532 .push_opcode(OP_IF)
533 .push_key(&bitcoin::PublicKey::new(revocationpubkey))
534 .push_opcode(OP_ELSE)
535 .push_int(to_self_delay as i64)
536 .push_opcode(OP_CSV)
537 .push_opcode(OP_DROP)
538 .push_key(&bitcoin::PublicKey::new(local_delayedpubkey))
539 .push_opcode(OP_ENDIF)
540 .push_opcode(OP_CHECKSIG)
541 .into_script()
542 .into()
543 }
544}
545
546impl ScriptGenerators for WitnessScript {
547 #[inline]
548 fn ln_offered_htlc(
549 amount: u64,
550 revocationpubkey: PublicKey,
551 local_htlcpubkey: PublicKey,
552 remote_htlcpubkey: PublicKey,
553 payment_hash: HashLock,
554 ) -> Self {
555 LockScript::ln_offered_htlc(
556 amount,
557 revocationpubkey,
558 local_htlcpubkey,
559 remote_htlcpubkey,
560 payment_hash,
561 )
562 .into()
563 }
564
565 #[inline]
566 fn ln_received_htlc(
567 amount: u64,
568 revocationpubkey: PublicKey,
569 local_htlcpubkey: PublicKey,
570 remote_htlcpubkey: PublicKey,
571 cltv_expiry: u32,
572 payment_hash: HashLock,
573 ) -> Self {
574 LockScript::ln_received_htlc(
575 amount,
576 revocationpubkey,
577 local_htlcpubkey,
578 remote_htlcpubkey,
579 cltv_expiry,
580 payment_hash,
581 )
582 .into()
583 }
584
585 #[inline]
586 fn ln_htlc_output(
587 amount: u64,
588 revocationpubkey: PublicKey,
589 local_delayedpubkey: PublicKey,
590 to_self_delay: u16,
591 ) -> Self {
592 LockScript::ln_htlc_output(
593 amount,
594 revocationpubkey,
595 local_delayedpubkey,
596 to_self_delay,
597 )
598 .into()
599 }
600}
601
602impl ScriptGenerators for PubkeyScript {
603 #[inline]
604 fn ln_offered_htlc(
605 amount: u64,
606 revocationpubkey: PublicKey,
607 local_htlcpubkey: PublicKey,
608 remote_htlcpubkey: PublicKey,
609 payment_hash: HashLock,
610 ) -> Self {
611 WitnessScript::ln_offered_htlc(
612 amount,
613 revocationpubkey,
614 local_htlcpubkey,
615 remote_htlcpubkey,
616 payment_hash,
617 )
618 .to_p2wsh()
619 }
620
621 #[inline]
622 fn ln_received_htlc(
623 amount: u64,
624 revocationpubkey: PublicKey,
625 local_htlcpubkey: PublicKey,
626 remote_htlcpubkey: PublicKey,
627 cltv_expiry: u32,
628 payment_hash: HashLock,
629 ) -> Self {
630 WitnessScript::ln_received_htlc(
631 amount,
632 revocationpubkey,
633 local_htlcpubkey,
634 remote_htlcpubkey,
635 cltv_expiry,
636 payment_hash,
637 )
638 .to_p2wsh()
639 }
640
641 #[inline]
642 fn ln_htlc_output(
643 amount: u64,
644 revocationpubkey: PublicKey,
645 local_delayedpubkey: PublicKey,
646 to_self_delay: u16,
647 ) -> Self {
648 WitnessScript::ln_htlc_output(
649 amount,
650 revocationpubkey,
651 local_delayedpubkey,
652 to_self_delay,
653 )
654 .to_p2wsh()
655 }
656}
657
658impl ScriptGenerators for TxOut {
659 #[inline]
660 fn ln_offered_htlc(
661 amount: u64,
662 revocationpubkey: PublicKey,
663 local_htlcpubkey: PublicKey,
664 remote_htlcpubkey: PublicKey,
665 payment_hash: HashLock,
666 ) -> Self {
667 TxOut {
668 value: amount,
669 script_pubkey: PubkeyScript::ln_offered_htlc(
670 amount,
671 revocationpubkey,
672 local_htlcpubkey,
673 remote_htlcpubkey,
674 payment_hash,
675 )
676 .into(),
677 }
678 }
679
680 #[inline]
681 fn ln_received_htlc(
682 amount: u64,
683 revocationpubkey: PublicKey,
684 local_htlcpubkey: PublicKey,
685 remote_htlcpubkey: PublicKey,
686 cltv_expiry: u32,
687 payment_hash: HashLock,
688 ) -> Self {
689 TxOut {
690 value: amount,
691 script_pubkey: PubkeyScript::ln_received_htlc(
692 amount,
693 revocationpubkey,
694 local_htlcpubkey,
695 remote_htlcpubkey,
696 cltv_expiry,
697 payment_hash,
698 )
699 .into(),
700 }
701 }
702
703 #[inline]
704 fn ln_htlc_output(
705 amount: u64,
706 revocationpubkey: PublicKey,
707 local_delayedpubkey: PublicKey,
708 to_self_delay: u16,
709 ) -> Self {
710 TxOut {
711 value: amount,
712 script_pubkey: PubkeyScript::ln_htlc_output(
713 amount,
714 revocationpubkey,
715 local_delayedpubkey,
716 to_self_delay,
717 )
718 .into(),
719 }
720 }
721}
722
723impl ScriptGenerators for psbt::Output {
724 #[inline]
725 fn ln_offered_htlc(
726 amount: u64,
727 revocationpubkey: PublicKey,
728 local_htlcpubkey: PublicKey,
729 remote_htlcpubkey: PublicKey,
730 payment_hash: HashLock,
731 ) -> Self {
732 let witness_script = WitnessScript::ln_offered_htlc(
733 amount,
734 revocationpubkey,
735 local_htlcpubkey,
736 remote_htlcpubkey,
737 payment_hash,
738 )
739 .into();
740 let txout = TxOut::ln_offered_htlc(
741 amount,
742 revocationpubkey,
743 local_htlcpubkey,
744 remote_htlcpubkey,
745 payment_hash,
746 );
747 let output = bitcoin::psbt::Output {
748 witness_script: Some(witness_script),
749 ..Default::default()
750 };
751 psbt::Output::with(0, output, txout)
752 }
753
754 #[inline]
755 fn ln_received_htlc(
756 amount: u64,
757 revocationpubkey: PublicKey,
758 local_htlcpubkey: PublicKey,
759 remote_htlcpubkey: PublicKey,
760 cltv_expiry: u32,
761 payment_hash: HashLock,
762 ) -> Self {
763 let witness_script = WitnessScript::ln_received_htlc(
764 amount,
765 revocationpubkey,
766 local_htlcpubkey,
767 remote_htlcpubkey,
768 cltv_expiry,
769 payment_hash,
770 )
771 .into();
772 let txout = TxOut::ln_received_htlc(
773 amount,
774 revocationpubkey,
775 local_htlcpubkey,
776 remote_htlcpubkey,
777 cltv_expiry,
778 payment_hash,
779 );
780 let output = bitcoin::psbt::Output {
781 witness_script: Some(witness_script),
782 ..Default::default()
783 };
784 psbt::Output::with(0, output, txout)
785 }
786
787 #[inline]
788 fn ln_htlc_output(
789 amount: u64,
790 revocationpubkey: PublicKey,
791 local_delayedpubkey: PublicKey,
792 to_self_delay: u16,
793 ) -> Self {
794 let witness_script = WitnessScript::ln_htlc_output(
795 amount,
796 revocationpubkey,
797 local_delayedpubkey,
798 to_self_delay,
799 )
800 .into();
801 let txout = TxOut::ln_htlc_output(
802 amount,
803 revocationpubkey,
804 local_delayedpubkey,
805 to_self_delay,
806 );
807 let output = bitcoin::psbt::Output {
808 witness_script: Some(witness_script),
809 ..Default::default()
810 };
811 psbt::Output::with(0, output, txout)
812 }
813}
814
815pub trait TxGenerators {
816 fn ln_htlc(
817 amount: u64,
818 outpoint: OutPoint,
819 cltv_expiry: u32,
820 revocationpubkey: PublicKey,
821 local_delayedpubkey: PublicKey,
822 to_self_delay: u16,
823 ) -> Self;
824}
825
826impl TxGenerators for Transaction {
827 fn ln_htlc(
830 amount: u64,
831 outpoint: OutPoint,
832 cltv_expiry: u32,
833 revocationpubkey: PublicKey,
834 local_delayedpubkey: PublicKey,
835 to_self_delay: u16,
836 ) -> Self {
837 let txout = TxOut::ln_htlc_output(
838 amount,
839 revocationpubkey,
840 local_delayedpubkey,
841 to_self_delay,
842 );
843 Transaction {
844 version: 2,
845 lock_time: bitcoin::PackedLockTime(cltv_expiry),
846 input: vec![TxIn {
847 previous_output: outpoint,
848 script_sig: none!(),
849 sequence: bitcoin::Sequence(0),
850 witness: empty!(),
851 }],
852 output: vec![txout],
853 }
854 }
855}
856
857impl TxGenerators for Psbt {
858 fn ln_htlc(
859 amount: u64,
860 outpoint: OutPoint,
861 cltv_expiry: u32,
862 revocationpubkey: PublicKey,
863 local_delayedpubkey: PublicKey,
864 to_self_delay: u16,
865 ) -> Self {
866 let output = psbt::Output::ln_htlc_output(
867 amount,
868 revocationpubkey,
869 local_delayedpubkey,
870 to_self_delay,
871 );
872
873 let mut psbt = Psbt::with(
874 Transaction::ln_htlc(
875 amount,
876 outpoint,
877 cltv_expiry,
878 revocationpubkey,
879 local_delayedpubkey,
880 to_self_delay,
881 ),
882 PsbtVersion::V0,
883 )
884 .expect("Tx has empty sigs so PSBT creation does not fail");
885 psbt.outputs[0] = output;
886 psbt
887 }
888}