ergo_lib_c_core/
address.rs

1use crate::ergo_tree::{ErgoTree, ErgoTreePtr};
2use crate::{
3    error::*,
4    util::{const_ptr_as_ref, mut_ptr_as_mut},
5};
6use ergo_lib::ergo_chain_types::EcPoint;
7use ergo_lib::ergotree_ir::chain::address as addr;
8use ergo_lib::ergotree_ir::ergo_tree::ErgoTree as InternalErgoTree;
9use ergo_lib::ergotree_ir::serialization::SigmaSerializable;
10use ergo_lib::ergotree_ir::sigma_protocol::sigma_boolean::ProveDlog;
11
12/// Address wrapper
13pub struct Address(pub(crate) ergo_lib::ergotree_ir::chain::address::Address);
14pub type AddressPtr = *mut Address;
15pub type ConstAddressPtr = *const Address;
16
17/// Decode (base58) testnet address from string, checking that address is from the testnet
18pub unsafe fn address_from_testnet(
19    address_str: &str,
20    address_out: *mut AddressPtr,
21) -> Result<(), Error> {
22    let address_out = mut_ptr_as_mut(address_out, "address_out")?;
23
24    let encoder = addr::AddressEncoder::new(addr::NetworkPrefix::Testnet);
25    let result = encoder.parse_address_from_str(address_str);
26
27    match result {
28        Ok(address) => {
29            *address_out = Box::into_raw(Box::new(Address(address)));
30            Ok(())
31        }
32        Err(err) => Err(Error::misc(err)),
33    }
34}
35
36/// Decode (base58) mainnet address from string, checking that address is from the mainnet
37pub unsafe fn address_from_mainnet(
38    address_str: &str,
39    address_out: *mut AddressPtr,
40) -> Result<(), Error> {
41    let address_out = mut_ptr_as_mut(address_out, "address_out")?;
42
43    let encoder = addr::AddressEncoder::new(addr::NetworkPrefix::Mainnet);
44    let result = encoder.parse_address_from_str(address_str);
45
46    match result {
47        Ok(address) => {
48            *address_out = Box::into_raw(Box::new(Address(address)));
49            Ok(())
50        }
51        Err(err) => Err(Error::misc(err)),
52    }
53}
54
55/// Decode (base58) address from string without checking the network prefix
56pub unsafe fn address_from_base58(
57    address_str: &str,
58    address_out: *mut AddressPtr,
59) -> Result<(), Error> {
60    let address_out = mut_ptr_as_mut(address_out, "address_out")?;
61    let result = addr::AddressEncoder::unchecked_parse_address_from_str(address_str);
62    match result {
63        Ok(address) => {
64            *address_out = Box::into_raw(Box::new(Address(address)));
65            Ok(())
66        }
67        Err(err) => Err(Error::misc(err)),
68    }
69}
70
71/// Encode address as base58 string
72pub unsafe fn address_to_base58(
73    address: ConstAddressPtr,
74    network_prefix: NetworkPrefix,
75) -> Result<String, Error> {
76    let address = const_ptr_as_ref(address, "address")?;
77    Ok(addr::AddressEncoder::encode_address_as_string(
78        addr::NetworkPrefix::from(network_prefix),
79        &address.0,
80    ))
81}
82
83/// Get the type of the address
84pub unsafe fn address_type_prefix(address: ConstAddressPtr) -> Result<AddressTypePrefix, Error> {
85    let address = const_ptr_as_ref(address, "address")?;
86    Ok(address.0.address_type_prefix().into())
87}
88
89/// Create address from ErgoTree
90pub unsafe fn address_from_ergo_tree(
91    ergo_tree_ptr: crate::ergo_tree::ConstErgoTreePtr,
92    address_out: *mut AddressPtr,
93) -> Result<(), Error> {
94    let ergo_tree = const_ptr_as_ref(ergo_tree_ptr, "ergo_tree_ptr")?;
95    let result = addr::Address::recreate_from_ergo_tree(&ergo_tree.0);
96    match result {
97        Ok(address) => {
98            *address_out = Box::into_raw(Box::new(Address(address)));
99            Ok(())
100        }
101        Err(err) => Err(Error::misc(err)),
102    }
103}
104
105/// Get ergo tree for address
106pub unsafe fn address_to_ergo_tree(
107    address_ptr: ConstAddressPtr,
108    ergo_tree_out: *mut ErgoTreePtr,
109) -> Result<(), Error> {
110    let address = const_ptr_as_ref(address_ptr, "address_ptr")?;
111    let ergo_tree_out = mut_ptr_as_mut(ergo_tree_out, "ergo_tree_out")?;
112    let ergo_tree: InternalErgoTree = address.0.script().map_err(Error::misc)?;
113    *ergo_tree_out = Box::into_raw(Box::new(ErgoTree(ergo_tree)));
114    Ok(())
115}
116
117/// Create address from public key bytes
118pub unsafe fn address_from_public_key(
119    bytes_ptr: *const u8,
120    len: usize,
121    address_out: *mut AddressPtr,
122) -> Result<(), Error> {
123    let address_out = mut_ptr_as_mut(address_out, "address_out")?;
124    let bytes = std::slice::from_raw_parts(bytes_ptr, len);
125    let address = EcPoint::sigma_parse_bytes(bytes)
126        .map(|point| ergo_lib::ergotree_ir::chain::address::Address::P2Pk(ProveDlog::new(point)))
127        .map_err(Error::misc)?;
128    *address_out = Box::into_raw(Box::new(Address(address)));
129    Ok(())
130}
131
132/// Drop the `Address`
133pub unsafe fn address_delete(address: AddressPtr) {
134    if !address.is_null() {
135        let boxed = Box::from_raw(address);
136        std::mem::drop(boxed);
137    }
138}
139
140/// Network type
141#[repr(u8)]
142#[derive(PartialEq, Eq, Debug, Clone, Copy)]
143pub enum NetworkPrefix {
144    /// Mainnet
145    Mainnet = 0,
146    /// Testnet
147    Testnet = 16,
148}
149
150impl From<NetworkPrefix> for addr::NetworkPrefix {
151    fn from(v: NetworkPrefix) -> Self {
152        use addr::NetworkPrefix::*;
153        match v {
154            NetworkPrefix::Mainnet => Mainnet,
155            NetworkPrefix::Testnet => Testnet,
156        }
157    }
158}
159
160impl From<addr::NetworkPrefix> for NetworkPrefix {
161    fn from(v: addr::NetworkPrefix) -> Self {
162        use NetworkPrefix::*;
163        match v {
164            addr::NetworkPrefix::Mainnet => Mainnet,
165            addr::NetworkPrefix::Testnet => Testnet,
166        }
167    }
168}
169
170#[repr(u8)]
171pub enum AddressTypePrefix {
172    /// 0x01 - Pay-to-PublicKey(P2PK) address
173    P2Pk = 1,
174    /// 0x02 - Pay-to-Script-Hash(P2SH)
175    Pay2Sh = 2,
176    /// 0x03 - Pay-to-Script(P2S)
177    Pay2S = 3,
178}
179
180impl From<AddressTypePrefix> for addr::AddressTypePrefix {
181    fn from(v: AddressTypePrefix) -> Self {
182        use addr::AddressTypePrefix::*;
183        match v {
184            AddressTypePrefix::P2Pk => P2Pk,
185            AddressTypePrefix::Pay2Sh => Pay2Sh,
186            AddressTypePrefix::Pay2S => Pay2S,
187        }
188    }
189}
190
191impl From<addr::AddressTypePrefix> for AddressTypePrefix {
192    fn from(v: addr::AddressTypePrefix) -> Self {
193        use AddressTypePrefix::*;
194        match v {
195            addr::AddressTypePrefix::P2Pk => P2Pk,
196            addr::AddressTypePrefix::Pay2Sh => Pay2Sh,
197            addr::AddressTypePrefix::Pay2S => Pay2S,
198        }
199    }
200}