Universal Deployer Contract (UDC)

The Universal Deployer Contract (UDC) is a singleton smart contract that wraps the deploy syscall to expose it to any contract that doesn’t implement it, such as account contracts. You can think of it as a standardized generic factory for Starknet contracts.

And since Starknet has no deployment transaction type, it offers a standardized way to deploy smart contracts by following the standard deployer interface and emitting a ContractDeployed event.

For more information see the proposal for the standard deployer interface. For details on the motivation and the decision making process, see the Universal Deployer Contract proposal.

UDC address

The UDC address is 0x041a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf in Mainnet, Sepolia testnet, and starknet-devnet. This address might change in the future when it is migrated to a modern version of Cairo.

Interface

trait IUniversalDeployer {
    fn deployContract(
        class_hash: ClassHash,
        salt: felt252,
        unique: bool,
        calldata: Span<felt252>
    ) -> ContractAddress;
}

Deploying a contract with the UDC

Procedure
  1. Declare the contract with a DECLARE transaction, or ensure that the contract has been declared.

    For more information, see the DECLARE transaction.

  2. Call the deployContract function in the UDC.

Example implementation in Cairo:
#[starknet::interface]
trait IUniversalDeployer<TContractState> {
    fn deployContract(
        ref self: TContractState,
        class_hash: ClassHash,
        salt: felt252,
        unique: bool,
        calldata: Span<felt252>
    ) -> ContractAddress; }

const UDC_ADDRESS: felt252 = 0x041a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf;

fn deploy() -> ContractAddress {
    let dispatcher = IUniversalDeployerDispatcher {
        contract_address: UDC_ADDRESS.try_into().unwrap()
    };

    // deployment parameters
    let class_hash = class_hash_const::<
       0x5c478ee27f2112411f86f207605b2e2c58cdb647bac0df27f660ef2252359c6
    >();
    let salt = 1234567879;
    let unique = false;
    let mut calldata = array![];

    // the UDC returns the deployed contract address
    dispatcher.deployContract(class_hash, salt, unique, calldata.span())
}

Deployment types

The Universal Deployer Contract offers two types of addresses to deploy: origin-dependent and origin-independent. As the names suggest, the origin-dependent type includes the deployer’s address in the address calculation, whereas, the origin-independent type does not. The unique boolean parameter ultimately determines the type of deployment.

When deploying a contract that uses get_caller_address in the constructor calldata, remember that the UDC, not the account, deploys that contract. Therefore, querying get_caller_address in a contract’s constructor returns the UDC’s address, not the account’s address.

Origin-dependent

By making deployments dependent upon the origin address, users can reserve a whole address space to prevent someone else from taking ownership of the address.

Only the owner of the origin address can deploy to those addresses.

Achieving this type of deployment necessitates that the origin sets unique to true in the deployContract call. Under the hood, the function call leverages the origin’s address and creates a hashchain by hashing the origin’s address with the given salt.

To deploy a unique contract address pass:

let deployed_addr = udc.deployContract(class_hash, salt, true, calldata.span());

Origin-independent

Origin-independent contract deployments create contract addresses independent of the deployer and the UDC instance. Instead, only the class hash, salt, and constructor arguments determine the address. This type of deployment enables redeployments of accounts and known systems across multiple networks. To deploy a reproducible deployment, set unique to false.

let deployed_addr = udc.deployContract(class_hash, salt, false, calldata.span());

Deploying the UDC

The UDC has already been deployed on most networks and development environments. The standard requires the UDC to be deployed passing deploy_from_zero=true and salt=0 as arguments to the deploy syscall. This results in a deterministic and predictable address across all instances of Starknet, facilitating SDK integration and reproducibility of deployments.

API specification

deployContract method

Deploy a contract through the Universal Deployer Contract.

fn deployContract(
    classHash: ClassHash,
    salt: felt252,
    unique: bool,
    calldata: Span<felt252>
) -> ContractAddress

ContractDeployed event

Emitted when deployer deploys a contract through the Universal Deployer Contract.

#[derive(Drop, starknet::Event)]
struct ContractDeployed {
    address: ContractAddress,
    deployer: ContractAddress,
    unique: bool,
    classHash: ClassHash,
    calldata: Span<felt252>,
    salt: felt252,
}