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
104
105
106
107
108
109
110
111
112
113
use crate::{BtcAddress, H160};
use bitcoin::{
json::bitcoin::ScriptBuf, Address, ConversionError, Hash, Network, Payload, PubkeyHash, ScriptHash, WPubkeyHash,
WScriptHash,
};
pub trait PartialAddress: Sized + Eq + PartialOrd {
fn from_payload(payload: Payload) -> Result<Self, ConversionError>;
fn to_payload(&self) -> Result<Payload, ConversionError>;
fn from_address(address: Address) -> Result<Self, ConversionError>;
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.to_byte_array()))),
Payload::ScriptHash(hash) => Ok(Self::P2SH(H160::from(hash.to_byte_array()))),
Payload::WitnessProgram(witness_program) => {
let program = witness_program.program();
if program.len() == 20 {
Ok(Self::P2WPKHv0(H160::from_slice(program.as_bytes())))
} else {
Err(ConversionError::InvalidPayload)
}
}
_ => {
Err(ConversionError::InvalidFormat)
}
}
}
fn to_payload(&self) -> Result<Payload, ConversionError> {
let script = match self {
Self::P2PKH(hash) => ScriptBuf::new_p2pkh(&PubkeyHash::from_slice(hash.as_bytes())?),
Self::P2SH(hash) => ScriptBuf::new_p2sh(&ScriptHash::from_slice(hash.as_bytes())?),
Self::P2WPKHv0(hash) => ScriptBuf::new_v0_p2wpkh(&WPubkeyHash::from_slice(hash.as_bytes())?),
Self::P2WSHv0(hash) => ScriptBuf::new_v0_p2wsh(&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::new(network, payload))
}
}
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::new(network, 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()
.require_network(Network::Regtest)
.unwrap()
)
.unwrap()
.to_address(Network::Regtest)
.unwrap()
.to_string()
);
}
}