153 lines
4.6 KiB
Rust
153 lines
4.6 KiB
Rust
/// Seems like quite a lot of code just to pullout `from_bech32` on address
|
|
/// This is mostly extracted from private function of pallas_addresses
|
|
use anyhow::{Result, anyhow};
|
|
use pallas_addresses;
|
|
pub use pallas_addresses::Network;
|
|
use pallas_primitives::NetworkId;
|
|
|
|
use crate::utils::v2a;
|
|
|
|
/// Network
|
|
|
|
pub fn network_from_id(id: NetworkId) -> Network {
|
|
match id {
|
|
NetworkId::Testnet => Network::Testnet,
|
|
NetworkId::Mainnet => Network::Mainnet,
|
|
}
|
|
}
|
|
|
|
fn parse_network(header: u8) -> Network {
|
|
let masked = header & 0b0000_1111;
|
|
|
|
match masked {
|
|
0b_0000_0000 => Network::Testnet,
|
|
0b_0000_0001 => Network::Mainnet,
|
|
_ => Network::Other(masked),
|
|
}
|
|
}
|
|
|
|
/// Credential
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub enum Credential {
|
|
Key([u8; 28]),
|
|
Script([u8; 28]),
|
|
}
|
|
|
|
impl Into<pallas_addresses::ShelleyPaymentPart> for Credential {
|
|
fn into(self) -> pallas_addresses::ShelleyPaymentPart {
|
|
match self {
|
|
Credential::Key(hash) => pallas_addresses::ShelleyPaymentPart::Key(hash.into()),
|
|
Credential::Script(hash) => pallas_addresses::ShelleyPaymentPart::Script(hash.into()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Into<pallas_addresses::ShelleyDelegationPart> for Credential {
|
|
fn into(self) -> pallas_addresses::ShelleyDelegationPart {
|
|
match self {
|
|
Credential::Key(hash) => pallas_addresses::ShelleyDelegationPart::Key(hash.into()),
|
|
Credential::Script(hash) => {
|
|
pallas_addresses::ShelleyDelegationPart::Script(hash.into())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Address
|
|
|
|
#[derive(Debug)]
|
|
pub struct Address {
|
|
pub network: Network,
|
|
pub payment: Credential,
|
|
pub delegation: Option<Credential>,
|
|
}
|
|
|
|
impl Address {
|
|
pub fn new(network: Network, payment: Credential, delegation: Option<Credential>) -> Self {
|
|
Self {
|
|
network,
|
|
payment,
|
|
delegation,
|
|
}
|
|
}
|
|
|
|
pub fn from_bech32(s: &str) -> Result<Self> {
|
|
let (_, bytes) = bech32::decode(s)?;
|
|
let x = Address::try_from(bytes)?;
|
|
Ok(x)
|
|
}
|
|
|
|
pub fn to_bech32(self) -> String {
|
|
Into::<pallas_addresses::ShelleyAddress>::into(self)
|
|
.to_bech32()
|
|
.unwrap()
|
|
}
|
|
}
|
|
|
|
impl TryFrom<Vec<u8>> for Address {
|
|
fn try_from(bytes: Vec<u8>) -> std::result::Result<Self, Self::Error> {
|
|
let header = *bytes.first().expect("Missing bytes");
|
|
let network = parse_network(header);
|
|
let payment: [u8; 28] = v2a(bytes[1..=28].to_vec())?.into();
|
|
let delegation = v2a(bytes[28..].to_vec());
|
|
match header & 0b1111_0000 {
|
|
0b0000_0000 => Ok(Address::new(
|
|
network,
|
|
Credential::Key(payment),
|
|
Some(Credential::Key(delegation?.into())),
|
|
)),
|
|
0b0001_0000 => Ok(Address::new(
|
|
network,
|
|
Credential::Script(payment),
|
|
Some(Credential::Key(delegation?.into())),
|
|
)),
|
|
0b0010_0000 => Ok(Address::new(
|
|
network,
|
|
Credential::Key(payment),
|
|
Some(Credential::Script(delegation?.into())),
|
|
)),
|
|
0b0011_0000 => Ok(Address::new(
|
|
network,
|
|
Credential::Script(payment),
|
|
Some(Credential::Script(delegation?.into())),
|
|
)),
|
|
0b0110_0000 => Ok(Address::new(network, Credential::Key(payment), None)),
|
|
0b0111_0000 => Ok(Address::new(network, Credential::Script(payment), None)),
|
|
_ => Err(anyhow!("Header not supported")),
|
|
}
|
|
}
|
|
|
|
type Error = anyhow::Error;
|
|
}
|
|
|
|
impl Into<pallas_addresses::ShelleyAddress> for Address {
|
|
fn into(self) -> pallas_addresses::ShelleyAddress {
|
|
let network = self.network;
|
|
pallas_addresses::ShelleyAddress::new(
|
|
network,
|
|
self.payment.into(),
|
|
self.delegation
|
|
.map_or(pallas_addresses::ShelleyDelegationPart::Null, |x| x.into()),
|
|
)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn parse_bech32() {
|
|
let testnet = "addr_test1vqpymjsk49r6p9f2f6d3gm04ther0ka7ts8jsv8dukg4nvgcdjxy9";
|
|
let addr0 = Address::from_bech32(testnet).unwrap();
|
|
let mainnet = "addr1vypymjsk49r6p9f2f6d3gm04ther0ka7ts8jsv8dukg4nvgr9x6tq";
|
|
let addr1 = Address::from_bech32(mainnet).unwrap();
|
|
assert_eq!(addr0.delegation, addr1.delegation, "oops");
|
|
let sa0: pallas_addresses::ShelleyAddress = addr0.into();
|
|
assert_eq!(sa0.to_bech32().unwrap(), testnet, "oops");
|
|
let sa1: pallas_addresses::ShelleyAddress = addr1.into();
|
|
assert_eq!(sa1.to_bech32().unwrap(), mainnet, "oops");
|
|
}
|
|
}
|