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}