Skip to main content

soroban_sdk/
address_payload.rs

1#![cfg(any(test, feature = "hazmat-address"))]
2#![cfg_attr(feature = "docs", doc(cfg(feature = "hazmat-address")))]
3
4//! Address payload extraction and construction.
5//!
6//! This module provides types and functions for extracting raw payloads from
7//! addresses and constructing addresses from raw payloads. This is useful for
8//! cross-chain interoperability where raw addresses need to be passed between
9//! different systems.
10//!
11//! # Warning
12//!
13//! For account addresses, the returned Ed25519 public key corresponds to
14//! the account's master key, which depending on the configuration of that
15//! account may or may not be a signer of the account. Do not use this for
16//! custom Ed25519 signature verification as a form of authentication
17//! because the master key may not be configured the signer of the account.
18
19use crate::{unwrap::UnwrapOptimized, Address, Bytes, BytesN, Env};
20
21/// The payload contained in an [`Address`].
22#[derive(Clone, Debug, PartialEq, Eq)]
23pub enum AddressPayload {
24    /// A 32-byte Ed25519 public key from an account address (G...).
25    ///
26    /// # Warning
27    ///
28    /// The Ed25519 public key corresponds to the account's master key, which
29    /// depending on the configuration of that account may or may not be a
30    /// signer of the account. Do not use this for custom Ed25519 signature
31    /// verification as a form of authentication.
32    AccountIdPublicKeyEd25519(BytesN<32>),
33    /// A 32-byte contract hash from a contract address (C...).
34    ContractIdHash(BytesN<32>),
35}
36
37impl AddressPayload {
38    /// Constructs an [`Address`] from this payload.
39    ///
40    /// This is the inverse of [`from_address`][AddressPayload::from_address].
41    ///
42    /// # Warning
43    ///
44    /// For account addresses, the returned Ed25519 public key corresponds to
45    /// the account's master key, which depending on the configuration of that
46    /// account may or may not be a signer of the account. Do not use this for
47    /// custom Ed25519 signature verification as a form of authentication
48    /// because the master key may not be configured the signer of the account.
49    pub fn to_address(&self, env: &Env) -> Address {
50        use crate::xdr::FromXdr;
51        // Build XDR header and get payload bytes based on payload type:
52        let (header, payload_bytes) = match self {
53            AddressPayload::AccountIdPublicKeyEd25519(bytes) => (
54                [
55                    0, 0, 0, 18, // ScVal::Address
56                    0, 0, 0, 0, // ScAddress::Account
57                    0, 0, 0, 0, // PublicKey::PublicKeyTypeEd25519
58                ]
59                .as_slice(),
60                bytes.as_bytes(),
61            ),
62            AddressPayload::ContractIdHash(bytes) => (
63                [
64                    0, 0, 0, 18, // ScVal::Address
65                    0, 0, 0, 1, // ScAddress::Contract
66                ]
67                .as_slice(),
68                bytes.as_bytes(),
69            ),
70        };
71
72        let mut xdr = Bytes::from_slice(env, header);
73        xdr.append(payload_bytes);
74
75        Address::from_xdr(env, &xdr).unwrap_optimized()
76    }
77
78    /// Extracts an [`AddressPayload`] from an [`Address`].
79    ///
80    /// Returns:
81    /// - For contract addresses (C...), returns [`AddressPayload::ContractIdHash`]
82    ///   containing the 32-byte contract hash.
83    /// - For account addresses (G...), returns [`AddressPayload::AccountIdPublicKeyEd25519`]
84    ///   containing the 32-byte Ed25519 public key.
85    ///
86    /// Returns `None` if the address type is not recognized. This may occur if
87    /// a new address type has been introduced to the network that this version
88    /// of this library is not aware of.
89    ///
90    /// # Warning
91    ///
92    /// For account addresses, the returned Ed25519 public key corresponds to
93    /// the account's master key, which depending on the configuration of that
94    /// account may or may not be a signer of the account. Do not use this for
95    /// custom Ed25519 signature verification as a form of authentication
96    /// because the master key may not be configured the signer of the account.
97    pub fn from_address(address: &Address) -> Option<Self> {
98        use crate::xdr::ToXdr;
99        let xdr = address.to_xdr(address.env());
100        // Skip over ScVal discriminant because we know it is an ScAddress.
101        let xdr = xdr.slice(4..);
102        // Decode ScAddress
103        let addr_type: BytesN<4> = xdr.slice(0..4).try_into().unwrap_optimized();
104        match addr_type.to_array() {
105            // Decode ScAddress::Account
106            [0, 0, 0, 0] => {
107                // Decode PublicKey
108                let public_key_type: BytesN<4> = xdr.slice(4..8).try_into().unwrap_optimized();
109                match public_key_type.to_array() {
110                    // Decode PublicKey::PublicKeyTypeEd25519
111                    [0, 0, 0, 0] => {
112                        let ed25519: BytesN<32> = xdr.slice(8..40).try_into().unwrap_optimized();
113                        Some(AddressPayload::AccountIdPublicKeyEd25519(ed25519))
114                    }
115                    _ => None,
116                }
117            }
118            // Decode ScAddress::Contract
119            [0, 0, 0, 1] => {
120                let hash: BytesN<32> = xdr.slice(4..36).try_into().unwrap_optimized();
121                Some(AddressPayload::ContractIdHash(hash))
122            }
123            _ => None,
124        }
125    }
126}