use super::*;
use crate::legacy_address::ExtendedAddr;
use bech32::ToBase32;
use ed25519_bip32::XPub;
pub(crate) fn variable_nat_decode(bytes: &[u8]) -> Option<(u64, usize)> {
let mut output = 0u128;
let mut bytes_read = 0;
for byte in bytes {
output = (output << 7) | (byte & 0x7F) as u128;
if output > u64::MAX.into() {
return None;
}
bytes_read += 1;
if (byte & 0x80) == 0 {
return Some((output as u64, bytes_read));
}
}
None
}
pub(crate) fn variable_nat_encode(mut num: u64) -> Vec<u8> {
let mut output = vec![num as u8 & 0x7F];
num /= 128;
while num > 0 {
output.push((num & 0x7F) as u8 | 0x80);
num /= 128;
}
output.reverse();
output
}
#[wasm_bindgen]
#[derive(Debug, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct NetworkInfo {
network_id: u8,
protocol_magic: u32,
}
#[wasm_bindgen]
impl NetworkInfo {
pub fn new(network_id: u8, protocol_magic: u32) -> Self {
Self {
network_id,
protocol_magic,
}
}
pub fn network_id(&self) -> u8 {
self.network_id
}
pub fn protocol_magic(&self) -> u32 {
self.protocol_magic
}
pub fn testnet_preview() -> NetworkInfo {
NetworkInfo {
network_id: 0b0000,
protocol_magic: 2,
}
}
pub fn testnet_preprod() -> NetworkInfo {
NetworkInfo {
network_id: 0b0000,
protocol_magic: 1,
}
}
#[deprecated(
since = "11.2.0",
note = "Use `.testnet_preview` or `.testnet_preprod`"
)]
pub fn testnet() -> NetworkInfo {
NetworkInfo {
network_id: 0b0000,
protocol_magic: 1097911063,
}
}
pub fn mainnet() -> NetworkInfo {
NetworkInfo {
network_id: 0b0001,
protocol_magic: 764824073,
}
}
}
#[derive(
Debug,
Clone,
Hash,
Eq,
Ord,
PartialEq,
PartialOrd,
serde::Serialize,
serde::Deserialize,
JsonSchema,
)]
pub enum CredType {
Key(Ed25519KeyHash),
Script(ScriptHash),
}
#[wasm_bindgen]
#[repr(u8)]
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum CredKind {
Key,
Script,
}
#[wasm_bindgen]
#[derive(
Debug,
Clone,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
serde::Serialize,
serde::Deserialize,
JsonSchema,
)]
pub struct Credential(pub(crate) CredType);
#[wasm_bindgen]
impl Credential {
pub fn from_keyhash(hash: &Ed25519KeyHash) -> Self {
Credential(CredType::Key(hash.clone()))
}
pub fn from_scripthash(hash: &ScriptHash) -> Self {
Credential(CredType::Script(hash.clone()))
}
pub fn to_keyhash(&self) -> Option<Ed25519KeyHash> {
match &self.0 {
CredType::Key(hash) => Some(hash.clone()),
CredType::Script(_) => None,
}
}
pub fn to_scripthash(&self) -> Option<ScriptHash> {
match &self.0 {
CredType::Key(_) => None,
CredType::Script(hash) => Some(hash.clone()),
}
}
pub fn kind(&self) -> CredKind {
match &self.0 {
CredType::Key(_) => CredKind::Key,
CredType::Script(_) => CredKind::Script,
}
}
pub fn has_script_hash(&self) -> bool {
match &self.0 {
CredType::Key(_) => false,
CredType::Script(_) => true,
}
}
fn to_raw_bytes(&self) -> Vec<u8> {
match &self.0 {
CredType::Key(hash) => hash.to_bytes(),
CredType::Script(hash) => hash.to_bytes(),
}
}
}
impl_to_from!(Credential);
impl cbor_event::se::Serialize for Credential {
fn serialize<'se, W: Write>(
&self,
serializer: &'se mut Serializer<W>,
) -> cbor_event::Result<&'se mut Serializer<W>> {
serializer.write_array(cbor_event::Len::Len(2))?;
match &self.0 {
CredType::Key(keyhash) => {
serializer.write_unsigned_integer(0u64)?;
serializer.write_bytes(keyhash.to_bytes())
}
CredType::Script(scripthash) => {
serializer.write_unsigned_integer(1u64)?;
serializer.write_bytes(scripthash.to_bytes())
}
}
}
}
impl Deserialize for Credential {
fn deserialize<R: BufRead + Seek>(raw: &mut Deserializer<R>) -> Result<Self, DeserializeError> {
(|| -> Result<_, DeserializeError> {
let len = raw.array()?;
if let cbor_event::Len::Len(n) = len {
if n != 2 {
return Err(DeserializeFailure::CBOR(cbor_event::Error::WrongLen(
2,
len,
"[id, hash]",
))
.into());
}
}
let cred_type = match raw.unsigned_integer()? {
0 => CredType::Key(Ed25519KeyHash::deserialize(raw)?),
1 => CredType::Script(ScriptHash::deserialize(raw)?),
n => {
return Err(DeserializeFailure::FixedValueMismatch {
found: Key::Uint(n),
expected: Key::Uint(0),
}
.into());
}
};
if let cbor_event::Len::Indefinite = len {
if raw.special()? != CBORSpecial::Break {
return Err(DeserializeFailure::EndingBreakMissing.into());
}
}
Ok(Credential(cred_type))
})()
.map_err(|e| e.annotate("StakeCredential"))
}
}
#[derive(Debug, Clone, Eq, Ord, PartialEq, PartialOrd)]
pub(crate) enum AddrType {
Base(BaseAddress),
Ptr(PointerAddress),
Enterprise(EnterpriseAddress),
Reward(RewardAddress),
Byron(ByronAddress),
}
#[wasm_bindgen]
#[derive(Debug, Clone, Eq, Ord, PartialEq, PartialOrd)]
pub struct ByronAddress(pub(crate) ExtendedAddr);
#[wasm_bindgen]
impl ByronAddress {
pub fn to_base58(&self) -> String {
format!("{}", self.0)
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut addr_bytes = Serializer::new_vec();
self.0.serialize(&mut addr_bytes).unwrap();
addr_bytes.finalize()
}
pub fn from_bytes(bytes: Vec<u8>) -> Result<ByronAddress, JsError> {
let mut raw = Deserializer::from(std::io::Cursor::new(bytes));
let extended_addr = ExtendedAddr::deserialize(&mut raw)?;
Ok(ByronAddress(extended_addr))
}
pub fn byron_protocol_magic(&self) -> u32 {
match self.0.attributes.protocol_magic {
Some(x) => x,
None => NetworkInfo::mainnet().protocol_magic(), }
}
pub fn attributes(&self) -> Vec<u8> {
let mut attributes_bytes = Serializer::new_vec();
self.0.attributes.serialize(&mut attributes_bytes).unwrap();
attributes_bytes.finalize()
}
pub fn network_id(&self) -> Result<u8, JsError> {
let protocol_magic = self.byron_protocol_magic();
match protocol_magic {
magic if magic == NetworkInfo::mainnet().protocol_magic() => {
Ok(NetworkInfo::mainnet().network_id())
}
magic if magic == NetworkInfo::testnet().protocol_magic() => {
Ok(NetworkInfo::testnet().network_id())
}
magic if magic == NetworkInfo::testnet_preprod().protocol_magic() => {
Ok(NetworkInfo::testnet_preprod().network_id())
}
magic if magic == NetworkInfo::testnet_preview().protocol_magic() => {
Ok(NetworkInfo::testnet_preview().network_id())
}
_ => Err(JsError::from_str(
&format! {"Unknown network {}", protocol_magic},
)),
}
}
pub fn from_base58(s: &str) -> Result<ByronAddress, JsError> {
use std::str::FromStr;
ExtendedAddr::from_str(s)
.map_err(|e| JsError::from_str(&format! {"{:?}", e}))
.map(ByronAddress)
}
pub fn icarus_from_key(key: &Bip32PublicKey, protocol_magic: u32) -> ByronAddress {
let mut out = [0u8; 64];
out.clone_from_slice(&key.as_bytes());
let filtered_protocol_magic = if protocol_magic == NetworkInfo::mainnet().protocol_magic() {
None
} else {
Some(protocol_magic)
};
ByronAddress(ExtendedAddr::new_simple(
&XPub::from_bytes(out),
filtered_protocol_magic,
))
}
pub fn is_valid(s: &str) -> bool {
use std::str::FromStr;
match ExtendedAddr::from_str(s) {
Ok(_v) => true,
Err(_err) => false,
}
}
pub fn to_address(&self) -> Address {
Address(AddrType::Byron(self.clone()))
}
pub fn from_address(addr: &Address) -> Option<ByronAddress> {
match &addr.0 {
AddrType::Byron(byron) => Some(byron.clone()),
_ => None,
}
}
}
#[wasm_bindgen]
#[derive(Debug, Clone, Eq, Ord, PartialEq, PartialOrd)]
pub struct Address(pub(crate) AddrType);
from_bytes!(Address, data, { Self::from_bytes_impl(data.as_ref()) });
to_from_json!(Address);
impl serde::Serialize for Address {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let bech32 = self
.to_bech32(None)
.map_err(|e| serde::ser::Error::custom(format!("to_bech32: {:?}", e)))?;
serializer.serialize_str(&bech32)
}
}
impl<'de> serde::de::Deserialize<'de> for Address {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let bech32 = <String as serde::de::Deserialize>::deserialize(deserializer)?;
Address::from_bech32(&bech32).map_err(|_e| {
serde::de::Error::invalid_value(
serde::de::Unexpected::Str(&bech32),
&"bech32 address string",
)
})
}
}
impl JsonSchema for Address {
fn schema_name() -> String {
String::from("Address")
}
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
String::json_schema(gen)
}
fn is_referenceable() -> bool {
String::is_referenceable()
}
}
#[wasm_bindgen]
impl Address {
pub fn to_hex(&self) -> String {
hex::encode(self.to_bytes())
}
pub fn from_hex(hex_str: &str) -> Result<Address, JsError> {
match hex::decode(hex_str) {
Ok(data) => Ok(Self::from_bytes_impl(data.as_ref())?),
Err(e) => Err(JsError::from_str(&e.to_string())),
}
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut buf = Vec::new();
match &self.0 {
AddrType::Base(base) => {
let header: u8 = ((base.payment.kind() as u8) << 4)
| ((base.stake.kind() as u8) << 5)
| (base.network & 0xF);
buf.push(header);
buf.extend(base.payment.to_raw_bytes());
buf.extend(base.stake.to_raw_bytes());
}
AddrType::Ptr(ptr) => {
let header: u8 =
0b0100_0000 | ((ptr.payment.kind() as u8) << 4) | (ptr.network & 0xF);
buf.push(header);
buf.extend(ptr.payment.to_raw_bytes());
buf.extend(variable_nat_encode(from_bignum(&ptr.stake.slot)));
buf.extend(variable_nat_encode(from_bignum(&ptr.stake.tx_index)));
buf.extend(variable_nat_encode(from_bignum(&ptr.stake.cert_index)));
}
AddrType::Enterprise(enterprise) => {
let header: u8 = 0b0110_0000
| ((enterprise.payment.kind() as u8) << 4)
| (enterprise.network & 0xF);
buf.push(header);
buf.extend(enterprise.payment.to_raw_bytes());
}
AddrType::Reward(reward) => {
let header: u8 =
0b1110_0000 | ((reward.payment.kind() as u8) << 4) | (reward.network & 0xF);
buf.push(header);
buf.extend(reward.payment.to_raw_bytes());
}
AddrType::Byron(byron) => buf.extend(byron.to_bytes()),
}
buf
}
fn from_bytes_impl(data: &[u8]) -> Result<Address, DeserializeError> {
use std::convert::TryInto;
(|| -> Result<Self, DeserializeError> {
let header = data[0];
let network = header & 0x0F;
const HASH_LEN: usize = Ed25519KeyHash::BYTE_COUNT;
assert_eq!(ScriptHash::BYTE_COUNT, HASH_LEN);
let read_addr_cred = |bit: u8, pos: usize| {
let hash_bytes: [u8; HASH_LEN] = data[pos..pos + HASH_LEN].try_into().unwrap();
let x = if header & (1 << bit) == 0 {
Credential::from_keyhash(&Ed25519KeyHash::from(hash_bytes))
} else {
Credential::from_scripthash(&ScriptHash::from(hash_bytes))
};
x
};
let addr = match (header & 0xF0) >> 4 {
0b0000 | 0b0001 | 0b0010 | 0b0011 => {
const BASE_ADDR_SIZE: usize = 1 + HASH_LEN * 2;
if data.len() < BASE_ADDR_SIZE {
return Err(cbor_event::Error::NotEnough(data.len(), BASE_ADDR_SIZE).into());
}
if data.len() > BASE_ADDR_SIZE {
return Err(cbor_event::Error::TrailingData.into());
}
AddrType::Base(BaseAddress::new(
network,
&read_addr_cred(4, 1),
&read_addr_cred(5, 1 + HASH_LEN),
))
}
0b0100 | 0b0101 => {
const PTR_ADDR_MIN_SIZE: usize = 1 + HASH_LEN + 1 + 1 + 1;
if data.len() < PTR_ADDR_MIN_SIZE {
return Err(
cbor_event::Error::NotEnough(data.len(), PTR_ADDR_MIN_SIZE).into()
);
}
let mut byte_index = 1;
let payment_cred = read_addr_cred(4, 1);
byte_index += HASH_LEN;
let (slot, slot_bytes) =
variable_nat_decode(&data[byte_index..]).ok_or(DeserializeError::new(
"Address.Pointer.slot",
DeserializeFailure::VariableLenNatDecodeFailed,
))?;
byte_index += slot_bytes;
let (tx_index, tx_bytes) =
variable_nat_decode(&data[byte_index..]).ok_or(DeserializeError::new(
"Address.Pointer.tx_index",
DeserializeFailure::VariableLenNatDecodeFailed,
))?;
byte_index += tx_bytes;
let (cert_index, cert_bytes) =
variable_nat_decode(&data[byte_index..]).ok_or(DeserializeError::new(
"Address.Pointer.cert_index",
DeserializeFailure::VariableLenNatDecodeFailed,
))?;
byte_index += cert_bytes;
if byte_index < data.len() {
return Err(cbor_event::Error::TrailingData.into());
}
AddrType::Ptr(PointerAddress::new(
network,
&payment_cred,
&Pointer::new_pointer(
&to_bignum(slot),
&to_bignum(tx_index),
&to_bignum(cert_index),
),
))
}
0b0110 | 0b0111 => {
const ENTERPRISE_ADDR_SIZE: usize = 1 + HASH_LEN;
if data.len() < ENTERPRISE_ADDR_SIZE {
return Err(
cbor_event::Error::NotEnough(data.len(), ENTERPRISE_ADDR_SIZE).into(),
);
}
if data.len() > ENTERPRISE_ADDR_SIZE {
return Err(cbor_event::Error::TrailingData.into());
}
AddrType::Enterprise(EnterpriseAddress::new(network, &read_addr_cred(4, 1)))
}
0b1110 | 0b1111 => {
const REWARD_ADDR_SIZE: usize = 1 + HASH_LEN;
if data.len() < REWARD_ADDR_SIZE {
return Err(
cbor_event::Error::NotEnough(data.len(), REWARD_ADDR_SIZE).into()
);
}
if data.len() > REWARD_ADDR_SIZE {
return Err(cbor_event::Error::TrailingData.into());
}
AddrType::Reward(RewardAddress::new(network, &read_addr_cred(4, 1)))
}
0b1000 => {
match ByronAddress::from_bytes(data.to_vec()) {
Ok(addr) => AddrType::Byron(addr),
Err(e) => {
return Err(cbor_event::Error::CustomError(
e.as_string().unwrap_or_default(),
)
.into())
}
}
}
_ => return Err(DeserializeFailure::BadAddressType(header).into()),
};
Ok(Address(addr))
})()
.map_err(|e| e.annotate("Address"))
}
pub fn to_bech32(&self, prefix: Option<String>) -> Result<String, JsError> {
let final_prefix = match prefix {
Some(prefix) => prefix,
None => {
let prefix_header = match &self.0 {
AddrType::Reward(_) => "stake",
_ => "addr",
};
let prefix_tail = match self.network_id()? {
id if id == NetworkInfo::testnet().network_id() => "_test",
id if id == NetworkInfo::testnet_preprod().network_id() => "_test",
id if id == NetworkInfo::testnet_preview().network_id() => "_test",
_ => "",
};
format!("{}{}", prefix_header, prefix_tail)
}
};
bech32::encode(&final_prefix, self.to_bytes().to_base32())
.map_err(|e| JsError::from_str(&format! {"{:?}", e}))
}
pub fn from_bech32(bech_str: &str) -> Result<Address, JsError> {
let (_hrp, u5data) =
bech32::decode(bech_str).map_err(|e| JsError::from_str(&e.to_string()))?;
let data: Vec<u8> = bech32::FromBase32::from_base32(&u5data).unwrap();
Ok(Self::from_bytes_impl(data.as_ref())?)
}
pub fn network_id(&self) -> Result<u8, JsError> {
match &self.0 {
AddrType::Base(a) => Ok(a.network),
AddrType::Enterprise(a) => Ok(a.network),
AddrType::Ptr(a) => Ok(a.network),
AddrType::Reward(a) => Ok(a.network),
AddrType::Byron(a) => a.network_id(),
}
}
}
impl cbor_event::se::Serialize for Address {
fn serialize<'se, W: Write>(
&self,
serializer: &'se mut Serializer<W>,
) -> cbor_event::Result<&'se mut Serializer<W>> {
serializer.write_bytes(self.to_bytes())
}
}
impl Deserialize for Address {
fn deserialize<R: BufRead>(raw: &mut Deserializer<R>) -> Result<Self, DeserializeError> {
Self::from_bytes_impl(raw.bytes()?.as_ref())
}
}
#[wasm_bindgen]
#[derive(Debug, Clone, Eq, Ord, PartialEq, PartialOrd)]
pub struct BaseAddress {
network: u8,
payment: Credential,
stake: Credential,
}
#[wasm_bindgen]
impl BaseAddress {
pub fn new(network: u8, payment: &Credential, stake: &Credential) -> Self {
Self {
network,
payment: payment.clone(),
stake: stake.clone(),
}
}
pub fn payment_cred(&self) -> Credential {
self.payment.clone()
}
pub fn stake_cred(&self) -> Credential {
self.stake.clone()
}
pub fn to_address(&self) -> Address {
Address(AddrType::Base(self.clone()))
}
pub fn from_address(addr: &Address) -> Option<BaseAddress> {
match &addr.0 {
AddrType::Base(base) => Some(base.clone()),
_ => None,
}
}
}
#[wasm_bindgen]
#[derive(Debug, Clone, Eq, Ord, PartialEq, PartialOrd)]
pub struct EnterpriseAddress {
network: u8,
payment: Credential,
}
#[wasm_bindgen]
impl EnterpriseAddress {
pub fn new(network: u8, payment: &Credential) -> Self {
Self {
network,
payment: payment.clone(),
}
}
pub fn payment_cred(&self) -> Credential {
self.payment.clone()
}
pub fn to_address(&self) -> Address {
Address(AddrType::Enterprise(self.clone()))
}
pub fn from_address(addr: &Address) -> Option<EnterpriseAddress> {
match &addr.0 {
AddrType::Enterprise(enterprise) => Some(enterprise.clone()),
_ => None,
}
}
}
#[wasm_bindgen]
#[derive(Debug, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct RewardAddress {
network: u8,
payment: Credential,
}
#[wasm_bindgen]
impl RewardAddress {
pub fn new(network: u8, payment: &Credential) -> Self {
Self {
network,
payment: payment.clone(),
}
}
pub fn payment_cred(&self) -> Credential {
self.payment.clone()
}
pub fn to_address(&self) -> Address {
Address(AddrType::Reward(self.clone()))
}
pub fn from_address(addr: &Address) -> Option<RewardAddress> {
match &addr.0 {
AddrType::Reward(reward) => Some(reward.clone()),
_ => None,
}
}
}
impl serde::Serialize for RewardAddress {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let bech32 = self
.to_address()
.to_bech32(None)
.map_err(|e| serde::ser::Error::custom(format!("to_bech32: {:?}", e)))?;
serializer.serialize_str(&bech32)
}
}
impl<'de> serde::de::Deserialize<'de> for RewardAddress {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let bech32 = <String as serde::de::Deserialize>::deserialize(deserializer)?;
match Address::from_bech32(&bech32)
.ok()
.map(|addr| RewardAddress::from_address(&addr))
{
Some(Some(ra)) => Ok(ra),
_ => Err(serde::de::Error::invalid_value(
serde::de::Unexpected::Str(&bech32),
&"bech32 reward address string",
)),
}
}
}
impl JsonSchema for RewardAddress {
fn schema_name() -> String {
String::from("RewardAddress")
}
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
String::json_schema(gen)
}
fn is_referenceable() -> bool {
String::is_referenceable()
}
}
impl cbor_event::se::Serialize for RewardAddress {
fn serialize<'se, W: Write>(
&self,
serializer: &'se mut Serializer<W>,
) -> cbor_event::Result<&'se mut Serializer<W>> {
self.to_address().serialize(serializer)
}
}
impl Deserialize for RewardAddress {
fn deserialize<R: BufRead>(raw: &mut Deserializer<R>) -> Result<Self, DeserializeError> {
(|| -> Result<Self, DeserializeError> {
let bytes = raw.bytes()?;
match Address::from_bytes_impl(bytes.as_ref())?.0 {
AddrType::Reward(ra) => Ok(ra),
_other_address => Err(DeserializeFailure::BadAddressType(bytes[0]).into()),
}
})()
.map_err(|e| e.annotate("RewardAddress"))
}
}
#[wasm_bindgen]
#[derive(Debug, Clone, Eq, Ord, PartialEq, PartialOrd)]
pub struct Pointer {
pub(crate) slot: BigNum,
pub(crate) tx_index: BigNum,
pub(crate) cert_index: BigNum,
}
#[wasm_bindgen]
impl Pointer {
#[deprecated(
since = "10.1.0",
note = "Underlying value capacity of ttl (BigNum u64) bigger then Slot32. Use new_pointer instead."
)]
pub fn new(slot: Slot32, tx_index: TransactionIndex, cert_index: CertificateIndex) -> Self {
Self {
slot: slot.into(),
tx_index: tx_index.into(),
cert_index: cert_index.into(),
}
}
pub fn new_pointer(slot: &SlotBigNum, tx_index: &BigNum, cert_index: &BigNum) -> Self {
Self {
slot: slot.clone(),
tx_index: tx_index.clone(),
cert_index: cert_index.clone(),
}
}
pub fn slot(&self) -> Result<u32, JsError> {
self.slot.clone().try_into()
}
pub fn tx_index(&self) -> Result<u32, JsError> {
self.tx_index.clone().try_into()
}
pub fn cert_index(&self) -> Result<u32, JsError> {
self.cert_index.clone().try_into()
}
pub fn slot_bignum(&self) -> BigNum {
self.slot.clone()
}
pub fn tx_index_bignum(&self) -> BigNum {
self.tx_index.clone()
}
pub fn cert_index_bignum(&self) -> BigNum {
self.cert_index.clone()
}
}
#[wasm_bindgen]
#[derive(Debug, Clone, Eq, Ord, PartialEq, PartialOrd)]
pub struct PointerAddress {
pub(crate) network: u8,
pub(crate) payment: Credential,
pub(crate) stake: Pointer,
}
#[wasm_bindgen]
impl PointerAddress {
pub fn new(network: u8, payment: &Credential, stake: &Pointer) -> Self {
Self {
network,
payment: payment.clone(),
stake: stake.clone(),
}
}
pub fn payment_cred(&self) -> Credential {
self.payment.clone()
}
pub fn stake_pointer(&self) -> Pointer {
self.stake.clone()
}
pub fn to_address(&self) -> Address {
Address(AddrType::Ptr(self.clone()))
}
pub fn from_address(addr: &Address) -> Option<PointerAddress> {
match &addr.0 {
AddrType::Ptr(ptr) => Some(ptr.clone()),
_ => None,
}
}
}