Skip to content

Commit 60093c6

Browse files
committed
wip: support submarine swap in bifrost
* messages resembles those of [peerswap protocol](https://github.com/ElementsProject/peerswap/blob/master/docs/peer-protocol.md#the-swap_in_request-message) * It does not support compatibility with peerswap daemon * LNPBP specification is not ready yet.
1 parent 0063e2c commit 60093c6

File tree

4 files changed

+356
-0
lines changed

4 files changed

+356
-0
lines changed

lnp2p/src/bifrost/mod.rs

+45
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ mod app;
172172
mod channel;
173173
mod ctrl;
174174
mod msg;
175+
mod peerswap;
175176
mod proposals;
176177
mod types;
177178

@@ -185,6 +186,7 @@ use internet2::{CreateUnmarshaller, Payload, Unmarshall, Unmarshaller};
185186
use lnpbp::bech32::Blob;
186187
pub use msg::Msg;
187188
use once_cell::sync::Lazy;
189+
pub use peerswap::*;
188190
pub use proposals::*;
189191
use strict_encoding::{self, StrictDecode, StrictEncode};
190192
pub use types::{
@@ -257,6 +259,49 @@ pub enum Messages {
257259

258260
#[api(type = 0x0028)]
259261
CloseChannel(CloseChannel),
262+
263+
#[api(type = 0x0040)]
264+
SwapInRequest(SwapInRequestMsg),
265+
266+
#[api(type = 0x0041)]
267+
SwapInAgreement(SwapInAgreementMsg),
268+
269+
#[api(type = 0x0042)]
270+
SwapOutRequest(SwapOutRequestMsg),
271+
272+
#[api(type = 0x0043)]
273+
SwapOutAgreement(SwapOutAgreementMsg),
274+
275+
#[api(type = 0x0044)]
276+
OpeningTxBroadcasted(OpeningTxBroadcastedMsg),
277+
278+
#[api(type = 0x0045)]
279+
Cancel(CancelMsg),
280+
281+
#[api(type = 0x0046)]
282+
CoopClose(CoopCloseMsg),
283+
}
284+
285+
impl Messages {
286+
pub fn swap_id(&self) -> Option<&SwapId> {
287+
match self {
288+
Self::SwapInRequest(SwapInRequestMsg { swap_id, .. })
289+
| Self::SwapOutRequest(SwapOutRequestMsg { swap_id, .. })
290+
| Self::SwapInAgreement(SwapInAgreementMsg { swap_id, .. })
291+
| Self::SwapOutAgreement(SwapOutAgreementMsg { swap_id, .. })
292+
| Self::OpeningTxBroadcasted(OpeningTxBroadcastedMsg {
293+
swap_id,
294+
..
295+
})
296+
| Self::Cancel(CancelMsg { swap_id, .. })
297+
| Self::CoopClose(CoopCloseMsg { swap_id, .. }) => Some(swap_id),
298+
_ => None,
299+
}
300+
}
301+
302+
pub fn is_swap_msg(&self) -> bool {
303+
self.swap_id().is_some()
304+
}
260305
}
261306

262307
impl StrictEncode for Messages {

lnp2p/src/bifrost/peerswap.rs

+300
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
// LNP P2P library, plmeneting both bolt (BOLT) and Bifrost P2P messaging
2+
// system for Lightning network protocol (LNP)
3+
//
4+
// Written in 2020-2021 by
5+
// Dr. Maxim Orlovsky <[email protected]>
6+
//
7+
// To the extent possible under law, the author(s) have dedicated all
8+
// copyright and related and neighboring rights to this software to
9+
// the public domain worldwide. This software is distributed without
10+
// any warranty.
11+
//
12+
// You should have received a copy of the MIT License
13+
// along with this software.
14+
// If not, see <https://opensource.org/licenses/MIT>.
15+
16+
use amplify::{Display, Slice32};
17+
use bitcoin::hashes::{sha256, sha256t};
18+
use bitcoin::Txid;
19+
use lnpbp::chain::AssetId;
20+
use secp256k1::{PublicKey, SecretKey};
21+
#[cfg(feature = "serde")]
22+
use serde_with::{As, DisplayFromStr};
23+
24+
use crate::bolt;
25+
26+
pub const PROTOCOL_VERSION: u16 = 1;
27+
pub const BIFROST_APP_PEERSWAP: u16 = 0x8008;
28+
29+
// SHA256("bifrost:swap")
30+
const SWAP_ID_MIDSTATE: [u8; 32] = [
31+
0x4e, 0x2e, 0x6e, 0xb2, 0xa3, 0xda, 0x16, 0xbc, 0x03, 0xe3, 0x38, 0x30,
32+
0xb3, 0xfa, 0xae, 0x6f, 0xe2, 0x76, 0x00, 0x1b, 0x2e, 0x79, 0xf1, 0x8f,
33+
0xd3, 0x8c, 0x43, 0xdc, 0x79, 0xfb, 0x99, 0xdd,
34+
];
35+
36+
/// Tag used for [`SwapId`] hash type
37+
pub struct SwapIdTag;
38+
39+
impl sha256t::Tag for SwapIdTag {
40+
#[inline]
41+
fn engine() -> sha256::HashEngine {
42+
let midstate = sha256::Midstate::from_inner(SWAP_ID_MIDSTATE);
43+
sha256::HashEngine::from_midstate(midstate, 64)
44+
}
45+
}
46+
47+
#[derive(
48+
Clone,
49+
Copy,
50+
PartialEq,
51+
Eq,
52+
PartialOrd,
53+
Ord,
54+
Hash,
55+
Debug,
56+
Display,
57+
Default,
58+
Wrapper,
59+
From,
60+
NetworkEncode,
61+
NetworkDecode
62+
)]
63+
#[display(LowerHex)]
64+
#[wrapper(FromStr, LowerHex, UpperHex, BorrowSlice)]
65+
#[cfg_attr(
66+
feature = "serde",
67+
serde_as,
68+
derive(Serialize, Deserialize),
69+
serde(crate = "serde_crate", transparent)
70+
)]
71+
pub struct SwapId(
72+
#[cfg_attr(feature = "serde", serde(with = "As::<DisplayFromStr>"))]
73+
Slice32,
74+
);
75+
76+
impl SwapId {
77+
#[inline]
78+
pub fn random() -> Self {
79+
SwapId::from(Slice32::random())
80+
}
81+
}
82+
83+
#[derive(
84+
Clone,
85+
PartialEq,
86+
Eq,
87+
PartialOrd,
88+
Ord,
89+
Hash,
90+
Debug,
91+
Display,
92+
NetworkEncode,
93+
NetworkDecode
94+
)]
95+
#[cfg_attr(
96+
feature = "serde",
97+
serde_as,
98+
derive(Serialize, Deserialize),
99+
serde(crate = "serde_crate")
100+
)]
101+
#[display(Debug)]
102+
#[network_encoding(use_tlv)]
103+
pub struct SwapInRequestMsg {
104+
pub protocol_version: u64,
105+
pub swap_id: SwapId,
106+
pub asset: Option<AssetId>,
107+
pub network: String,
108+
pub scid: bolt::ChannelId,
109+
pub amount: u64,
110+
pub pubkey: PublicKey,
111+
}
112+
113+
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, Error)]
114+
#[display(doc_comments)]
115+
pub enum ValidationError {
116+
/// Network and asset has different value.
117+
NetworkMismatch,
118+
119+
/// Unknown Network {0}
120+
UnknownNetwork(String),
121+
}
122+
123+
impl SwapInRequestMsg {
124+
pub fn validate(&self) -> Result<(), ValidationError> {
125+
let _network_ok = {
126+
match self.network.as_str() {
127+
"mainnet" => Ok(()),
128+
"testnet" => Ok(()),
129+
"testnet3" => Ok(()),
130+
"signet" => Ok(()),
131+
"regtest" => Ok(()),
132+
x => Err(ValidationError::UnknownNetwork(x.to_string())),
133+
}
134+
}?;
135+
136+
Ok(())
137+
}
138+
}
139+
140+
#[derive(
141+
Clone,
142+
PartialEq,
143+
Eq,
144+
PartialOrd,
145+
Ord,
146+
Debug,
147+
Display,
148+
NetworkEncode,
149+
NetworkDecode
150+
)]
151+
#[cfg_attr(
152+
feature = "serde",
153+
serde_as,
154+
derive(Serialize, Deserialize),
155+
serde(crate = "serde_crate")
156+
)]
157+
#[display(Debug)]
158+
#[network_encoding(use_tlv)]
159+
pub struct SwapInAgreementMsg {
160+
pub protocol_version: u64,
161+
pub swap_id: SwapId,
162+
pub pubkey: PublicKey,
163+
pub premium: u64,
164+
}
165+
166+
#[derive(
167+
Clone,
168+
PartialEq,
169+
Eq,
170+
Hash,
171+
Ord,
172+
PartialOrd,
173+
Debug,
174+
Display,
175+
NetworkEncode,
176+
NetworkDecode
177+
)]
178+
#[cfg_attr(
179+
feature = "serde",
180+
serde_as,
181+
derive(Serialize, Deserialize),
182+
serde(crate = "serde_crate")
183+
)]
184+
#[display(Debug)]
185+
#[network_encoding(use_tlv)]
186+
pub struct SwapOutRequestMsg {
187+
pub protocol_version: u64,
188+
pub swap_id: SwapId,
189+
pub asset: Option<AssetId>,
190+
pub network: String,
191+
pub scid: bolt::ChannelId,
192+
pub amount: u64,
193+
pub pubkey: PublicKey,
194+
}
195+
196+
#[derive(
197+
Clone,
198+
PartialEq,
199+
Eq,
200+
Hash,
201+
Ord,
202+
PartialOrd,
203+
Debug,
204+
Display,
205+
NetworkEncode,
206+
NetworkDecode
207+
)]
208+
#[cfg_attr(
209+
feature = "serde",
210+
serde_as,
211+
derive(Serialize, Deserialize),
212+
serde(crate = "serde_crate")
213+
)]
214+
#[display(Debug)]
215+
#[network_encoding(use_tlv)]
216+
pub struct SwapOutAgreementMsg {
217+
pub protocol_version: u64,
218+
pub swap_id: SwapId,
219+
pub pubkey: PublicKey,
220+
pub payreq: String,
221+
}
222+
223+
#[derive(
224+
Clone,
225+
PartialEq,
226+
Eq,
227+
Hash,
228+
Ord,
229+
PartialOrd,
230+
Debug,
231+
Display,
232+
NetworkEncode,
233+
NetworkDecode
234+
)]
235+
#[cfg_attr(
236+
feature = "serde",
237+
serde_as,
238+
derive(Serialize, Deserialize),
239+
serde(crate = "serde_crate")
240+
)]
241+
#[display(Debug)]
242+
#[network_encoding(use_tlv)]
243+
pub struct OpeningTxBroadcastedMsg {
244+
pub swap_id: SwapId,
245+
pub payreq: String,
246+
pub tx_id: Txid,
247+
pub script_out: u64,
248+
pub blinding_key: SecretKey,
249+
}
250+
251+
#[derive(
252+
Clone,
253+
PartialEq,
254+
Eq,
255+
Hash,
256+
Ord,
257+
PartialOrd,
258+
Debug,
259+
Display,
260+
NetworkEncode,
261+
NetworkDecode
262+
)]
263+
#[cfg_attr(
264+
feature = "serde",
265+
serde_as,
266+
derive(Serialize, Deserialize),
267+
serde(crate = "serde_crate")
268+
)]
269+
#[display(Debug)]
270+
#[network_encoding(use_tlv)]
271+
pub struct CancelMsg {
272+
pub swap_id: SwapId,
273+
pub message: String,
274+
}
275+
276+
#[derive(
277+
Clone,
278+
PartialEq,
279+
Eq,
280+
Hash,
281+
Ord,
282+
PartialOrd,
283+
Debug,
284+
Display,
285+
NetworkEncode,
286+
NetworkDecode
287+
)]
288+
#[cfg_attr(
289+
feature = "serde",
290+
serde_as,
291+
derive(Serialize, Deserialize),
292+
serde(crate = "serde_crate")
293+
)]
294+
#[display(Debug)]
295+
#[network_encoding(use_tlv)]
296+
pub struct CoopCloseMsg {
297+
pub swap_id: SwapId,
298+
pub message: String,
299+
pub privkey: SecretKey,
300+
}

lnp2p/src/bifrost/types.rs

+6
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ impl sha256t::Tag for ChannelIdTag {
5959
)]
6060
#[wrapper(Debug, LowerHex, BorrowSlice)]
6161
#[wrapper(Index, IndexRange, IndexFrom, IndexTo, IndexFull)]
62+
#[cfg_attr(
63+
feature = "serde",
64+
serde_as,
65+
derive(Serialize, Deserialize),
66+
serde(crate = "serde_crate", transparent)
67+
)]
6268
pub struct ChannelId(sha256t::Hash<ChannelIdTag>);
6369

6470
impl ChannelId {

lnp2p/src/bolt/types.rs

+5
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,11 @@ pub struct Alias(
326326
)]
327327
#[derive(LightningEncode, LightningDecode)]
328328
#[cfg_attr(feature = "strict_encoding", derive(NetworkEncode, NetworkDecode))]
329+
#[cfg_attr(
330+
feature = "serde",
331+
derive(Serialize, Deserialize),
332+
serde(crate = "serde_crate")
333+
)]
329334
#[display("{block_height}x{tx_index}x{output_index}")]
330335
pub struct ShortChannelId {
331336
pub block_height: u24,

0 commit comments

Comments
 (0)