forked from interlay/interbtc-clients
-
Notifications
You must be signed in to change notification settings - Fork 0
/
addr.rs
103 lines (88 loc) · 3.36 KB
/
addr.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use crate::{BtcAddress, H160};
use bitcoin::{
Address, ConversionError, Hash, Network, Payload, PubkeyHash, Script, ScriptHash, WPubkeyHash, WScriptHash,
};
pub trait PartialAddress: Sized + Eq + PartialOrd {
/// Decode the `PartialAddress` from the `Payload` type.
///
/// # Arguments
/// * `payload` - Bitcoin payload (P2PKH, P2SH, P2WPKH)
fn from_payload(payload: Payload) -> Result<Self, ConversionError>;
/// Encode the `PartialAddress` into the `Payload` type.
fn to_payload(&self) -> Result<Payload, ConversionError>;
/// Decode the `PartialAddress` from the `Address` type.
///
/// # Arguments
/// * `address` - Bitcoin address
fn from_address(address: Address) -> Result<Self, ConversionError>;
/// Encode the `PartialAddress` as an address that the bitcoin rpc can use.
///
/// # Arguments
/// * `network` - network to prefix
fn to_address(&self, network: Network) -> Result<Address, ConversionError>;
}
impl PartialAddress for BtcAddress {
fn from_payload(payload: Payload) -> Result<Self, ConversionError> {
match payload {
Payload::PubkeyHash(hash) => Ok(Self::P2PKH(H160::from(hash.as_hash().into_inner()))),
Payload::ScriptHash(hash) => Ok(Self::P2SH(H160::from(hash.as_hash().into_inner()))),
Payload::WitnessProgram { version: _, program } => {
if program.len() == 20 {
Ok(Self::P2WPKHv0(H160::from_slice(program.as_slice())))
} else {
Err(ConversionError::InvalidPayload)
}
}
}
}
fn to_payload(&self) -> Result<Payload, ConversionError> {
let script = match self {
Self::P2PKH(hash) => Script::new_p2pkh(&PubkeyHash::from_slice(hash.as_bytes())?),
Self::P2SH(hash) => Script::new_p2sh(&ScriptHash::from_slice(hash.as_bytes())?),
Self::P2WPKHv0(hash) => Script::new_v0_wpkh(&WPubkeyHash::from_slice(hash.as_bytes())?),
Self::P2WSHv0(hash) => Script::new_v0_wsh(&WScriptHash::from_slice(hash.as_bytes())?),
};
Ok(Payload::from_script(&script)?)
}
fn from_address(address: Address) -> Result<Self, ConversionError> {
Self::from_payload(address.payload)
}
fn to_address(&self, network: Network) -> Result<Address, ConversionError> {
let payload = self.to_payload()?;
Ok(Address { payload, network })
}
}
impl PartialAddress for Payload {
fn from_payload(payload: Payload) -> Result<Self, ConversionError> {
Ok(payload)
}
fn to_payload(&self) -> Result<Payload, ConversionError> {
Ok(self.clone())
}
fn from_address(address: Address) -> Result<Self, ConversionError> {
Ok(address.payload)
}
fn to_address(&self, network: Network) -> Result<Address, ConversionError> {
Ok(Address {
network,
payload: self.clone(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
#[test]
fn test_encode_and_decode_payload() {
let addr = "bcrt1q6v2c7q7uv8vu6xle2k9ryfj3y3fuuy4rqnl50f";
assert_eq!(
addr,
Payload::from_address(Address::from_str(addr).unwrap())
.unwrap()
.to_address(Network::Regtest)
.unwrap()
.to_string()
);
}
}