Skip to main content

Overview

Address is a universal opaque identifier used in Soroban contracts. It can represent either a Stellar account or a contract. Address can be used as:
  • An input argument (e.g., to identify a payment recipient)
  • A data key (e.g., to store balances)
  • An authentication & authorization source
Internally, Address may represent:
  • A Stellar account (using Ed25519 public key)
  • A contract (identified by contract hash)

Creating Addresses

from_str()

Creates an Address from a Stellar strkey.
pub fn from_str(env: &Env, strkey: &str) -> Address
Supported strkey types:
  • Account keys: G... (Ed25519 public keys)
  • Contract keys: C... (Contract identifiers)
Example:
let address = Address::from_str(
    &env,
    "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF"
);

from_string()

Creates an Address from a String containing a Stellar strkey.
pub fn from_string(strkey: &String) -> Self
Example:
let strkey = String::from_str(&env, "GAAA...");
let address = Address::from_string(&strkey);

from_string_bytes()

Creates an Address from bytes containing a Stellar strkey.
pub fn from_string_bytes(strkey: &Bytes) -> Self

generate() (Test Only)

Generates a random Address for testing.
let address = Address::generate(&env);

Authorization

require_auth()

Ensures that this Address has authorized the invocation of the current contract with all invocation arguments.
pub fn require_auth(&self)
During on-chain execution, the Soroban host performs authentication (verifies signatures) and ensures replay prevention. Panics: If the invocation is not authorized. Example:
pub fn transfer(env: Env, from: Address, to: Address, amount: i128) {
    from.require_auth();
    // Transfer logic...
}

require_auth_for_args()

Ensures that this Address has authorized the invocation with specific arguments.
pub fn require_auth_for_args(&self, args: Vec<Val>)
The arguments don’t have to match the contract invocation arguments. However, it’s best practice to have a well-defined, deterministic mapping between invocation arguments and require_auth arguments. Panics: If the invocation is not authorized. Example:
pub fn approve(env: Env, from: Address, spender: Address, amount: i128) {
    from.require_auth_for_args((spender.clone(), amount).into_val(&env));
    // Approval logic...
}

Conversion Methods

to_string()

Converts this Address into the corresponding Stellar strkey.
pub fn to_string(&self) -> String
Example:
let strkey = address.to_string();

to_payload()

Extracts the payload from the address.
pub fn to_payload(&self) -> Option<AddressPayload>
Returns:
  • For contract addresses (C...): AddressPayload::ContractIdHash containing the 32-byte contract hash
  • For account addresses (G...): AddressPayload::AccountIdPublicKeyEd25519 containing the 32-byte Ed25519 public key
  • None if the address type is not recognized
For account addresses, the returned Ed25519 public key corresponds to the account’s master key, which may not be a signer of the account depending on the account’s configuration. Do not use this for custom Ed25519 signature verification as a form of authentication.

from_payload()

Constructs an Address from an AddressPayload.
pub fn from_payload(env: &Env, payload: AddressPayload) -> Address
This is the inverse of to_payload().

Query Methods

executable()

Returns the executable type of this address, if any.
pub fn executable(&self) -> Option<Executable>
For Wasm contracts, this returns the hash of the contract code. For built-in contracts, this returns the executable type (StellarAsset or Account). Returns:
  • None when the contract or account does not exist
  • Some(Executable::Wasm(BytesN<32>)) for Wasm contracts
  • Some(Executable::StellarAsset) for Stellar Asset contracts
  • Some(Executable::Account) for account contracts
Example:
match address.executable() {
    Some(Executable::Wasm(hash)) => {
        // Contract exists and uses Wasm
    }
    Some(Executable::StellarAsset) => {
        // Built-in Stellar Asset contract
    }
    None => {
        // Contract does not exist
    }
}

exists()

Returns whether this address exists in the ledger.
pub fn exists(&self) -> bool
For contract addresses, this means there is a corresponding contract instance deployed. For account addresses, this means the account entry exists in the ledger. Example:
if !address.exists() {
    panic!("Address does not exist");
}

Internal Methods

env()

Returns a reference to the Env.
pub fn env(&self) -> &Env

as_val() / to_val()

Convert to/from Val representation.
pub fn as_val(&self) -> &Val
pub fn to_val(&self) -> Val

as_object() / to_object()

Convert to/from AddressObject representation.
pub fn as_object(&self) -> &AddressObject
pub fn to_object(&self) -> AddressObject

Traits

Address implements the following traits:
  • Clone
  • Debug
  • Eq, PartialEq
  • Ord, PartialOrd

Examples

Basic Usage

use soroban_sdk::{contract, contractimpl, Address, Env};

#[contract]
pub struct TokenContract;

#[contractimpl]
impl TokenContract {
    pub fn transfer(env: Env, from: Address, to: Address, amount: i128) {
        from.require_auth();
        
        let from_balance = get_balance(&env, &from);
        let to_balance = get_balance(&env, &to);
        
        set_balance(&env, &from, from_balance - amount);
        set_balance(&env, &to, to_balance + amount);
    }
}

Testing with Generated Addresses

#[test]
fn test_transfer() {
    let env = Env::default();
    let contract_id = env.register(TokenContract, ());
    let client = TokenContractClient::new(&env, &contract_id);
    
    env.mock_all_auths();
    
    let user1 = Address::generate(&env);
    let user2 = Address::generate(&env);
    
    client.transfer(&user1, &user2, &1000);
}

MuxedAddress

MuxedAddress is a union type that represents either a regular Address or a “multiplexed” address consisting of a regular address plus a u64 ID. This allows representing virtual accounts that manage multiple off-chain balances with a single on-chain balance entry.

When to Use MuxedAddress

  • Token transfers supporting non-custodial accounts (e.g., exchange support)
  • Off-chain balance tracking where the ID identifies virtual sub-accounts
  • Event emission where the ID helps off-chain processors distinguish accounts
MuxedAddress should only be used in special cases like token interfaces. Prefer using regular Address unless multiplexing support is necessary.

Creating MuxedAddress

use soroban_sdk::{Address, MuxedAddress, Env};

let env = Env::default();
let address = Address::generate(&env);

// Create a muxed address with ID 12345
let muxed = MuxedAddress::new(&env, &address, 12345u64);

Compatibility

MuxedAddress is compatible with Address at the contract interface level:
  • Contracts accepting MuxedAddress can receive Address arguments
  • Upgrading from Address to MuxedAddress doesn’t break existing clients
  • Only Stellar accounts can be multiplexed (not contract addresses)
MuxedAddress cannot be used as a storage key to prevent accidental key space fragmentation.

Example: Token Transfer

use soroban_sdk::{contract, contractimpl, Address, MuxedAddress, Env};

#[contract]
pub struct TokenContract;

#[contractimpl]
impl TokenContract {
    // Accepts both Address and MuxedAddress
    pub fn transfer(env: Env, from: Address, to: MuxedAddress, amount: i128) {
        from.require_auth();
        
        // Extract the base address from MuxedAddress
        let to_address = to.address();
        
        // Get mux ID if present (returns Option<u64>)
        if let Some(id) = to.mux_id() {
            // Emit event with ID for off-chain processing
            env.events().publish(("transfer", id), (&from, &to_address, amount));
        }
        
        // Perform transfer to base address
        // ... transfer logic
    }
}

Key Methods

  • new(env: &Env, address: &Address, id: u64) - Create multiplexed address
  • from_address(env: &Env, address: &Address) - Create from regular address
  • address(&self) -> Address - Extract base address
  • mux_id(&self) -> Option<u64> - Get multiplexing ID if present

See Also