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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
use crate::{
    error::*,
    util::{const_ptr_as_ref, mut_ptr_as_mut},
};
use ergo_lib::ergotree_ir::chain::address as addr;

/// Address wrapper
pub struct Address(pub(crate) ergo_lib::ergotree_ir::chain::address::Address);
pub type AddressPtr = *mut Address;
pub type ConstAddressPtr = *const Address;

/// Decode (base58) testnet address from string, checking that address is from the testnet
pub unsafe fn address_from_testnet(
    address_str: &str,
    address_out: *mut AddressPtr,
) -> Result<(), Error> {
    let address_out = mut_ptr_as_mut(address_out, "address_out")?;

    let encoder = addr::AddressEncoder::new(addr::NetworkPrefix::Testnet);
    let result = encoder.parse_address_from_str(address_str);

    match result {
        Ok(address) => {
            *address_out = Box::into_raw(Box::new(Address(address)));
            Ok(())
        }
        Err(err) => Err(Error::misc(err)),
    }
}

/// Decode (base58) mainnet address from string, checking that address is from the mainnet
pub unsafe fn address_from_mainnet(
    address_str: &str,
    address_out: *mut AddressPtr,
) -> Result<(), Error> {
    let address_out = mut_ptr_as_mut(address_out, "address_out")?;

    let encoder = addr::AddressEncoder::new(addr::NetworkPrefix::Mainnet);
    let result = encoder.parse_address_from_str(address_str);

    match result {
        Ok(address) => {
            *address_out = Box::into_raw(Box::new(Address(address)));
            Ok(())
        }
        Err(err) => Err(Error::misc(err)),
    }
}

/// Decode (base58) address from string without checking the network prefix
pub unsafe fn address_from_base58(
    address_str: &str,
    address_out: *mut AddressPtr,
) -> Result<(), Error> {
    let address_out = mut_ptr_as_mut(address_out, "address_out")?;
    let result = addr::AddressEncoder::unchecked_parse_address_from_str(address_str);
    match result {
        Ok(address) => {
            *address_out = Box::into_raw(Box::new(Address(address)));
            Ok(())
        }
        Err(err) => Err(Error::misc(err)),
    }
}

/// Encode address as base58 string
pub unsafe fn address_to_base58(
    address: ConstAddressPtr,
    network_prefix: NetworkPrefix,
) -> Result<String, Error> {
    let address = const_ptr_as_ref(address, "address")?;
    Ok(addr::AddressEncoder::encode_address_as_string(
        addr::NetworkPrefix::from(network_prefix),
        &address.0,
    ))
}

/// Get the type of the address
pub unsafe fn address_type_prefix(address: ConstAddressPtr) -> Result<AddressTypePrefix, Error> {
    let address = const_ptr_as_ref(address, "address")?;
    Ok(address.0.address_type_prefix().into())
}

/// Create address from ErgoTree
pub unsafe fn address_from_ergo_tree(
    ergo_tree_ptr: crate::ergo_tree::ConstErgoTreePtr,
    address_out: *mut AddressPtr,
) -> Result<(), Error> {
    let ergo_tree = const_ptr_as_ref(ergo_tree_ptr, "ergo_tree_ptr")?;
    let result = addr::Address::recreate_from_ergo_tree(&ergo_tree.0);
    match result {
        Ok(address) => {
            *address_out = Box::into_raw(Box::new(Address(address)));
            Ok(())
        }
        Err(err) => Err(Error::misc(err)),
    }
}

/// Drop the `Address`
pub unsafe fn address_delete(address: AddressPtr) {
    if !address.is_null() {
        let boxed = Box::from_raw(address);
        std::mem::drop(boxed);
    }
}

/// Network type
#[repr(u8)]
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
pub enum NetworkPrefix {
    /// Mainnet
    Mainnet = 0,
    /// Testnet
    Testnet = 16,
}

impl From<NetworkPrefix> for addr::NetworkPrefix {
    fn from(v: NetworkPrefix) -> Self {
        use addr::NetworkPrefix::*;
        match v {
            NetworkPrefix::Mainnet => Mainnet,
            NetworkPrefix::Testnet => Testnet,
        }
    }
}

impl From<addr::NetworkPrefix> for NetworkPrefix {
    fn from(v: addr::NetworkPrefix) -> Self {
        use NetworkPrefix::*;
        match v {
            addr::NetworkPrefix::Mainnet => Mainnet,
            addr::NetworkPrefix::Testnet => Testnet,
        }
    }
}

#[repr(u8)]
pub enum AddressTypePrefix {
    /// 0x01 - Pay-to-PublicKey(P2PK) address
    P2Pk = 1,
    /// 0x02 - Pay-to-Script-Hash(P2SH)
    Pay2Sh = 2,
    /// 0x03 - Pay-to-Script(P2S)
    Pay2S = 3,
}

impl From<AddressTypePrefix> for addr::AddressTypePrefix {
    fn from(v: AddressTypePrefix) -> Self {
        use addr::AddressTypePrefix::*;
        match v {
            AddressTypePrefix::P2Pk => P2Pk,
            AddressTypePrefix::Pay2Sh => Pay2Sh,
            AddressTypePrefix::Pay2S => Pay2S,
        }
    }
}

impl From<addr::AddressTypePrefix> for AddressTypePrefix {
    fn from(v: addr::AddressTypePrefix) -> Self {
        use AddressTypePrefix::*;
        match v {
            addr::AddressTypePrefix::P2Pk => P2Pk,
            addr::AddressTypePrefix::Pay2Sh => Pay2Sh,
            addr::AddressTypePrefix::Pay2S => Pay2S,
        }
    }
}