Overview
This standard describes a standard Universal Deployer Contract (UDC).
Motivation
Account contracts are very critical components of the StarkNet ecosystem, since a bug in any implementation —let alone a widespread one— could be disastrous. Therefore maximal caution is in order. In this spirit trimming account responsibilities should be considered to simplify implementations, minimizing their bug/attack surface.
To allow accounts to deploy contracts without compromising security, this standard proposes to move that functionality to an external, specialized deployer contract. And since it makes no sense to deploy a new deployer contract for each account, this should be a singleton Universal Deployer Contract (UDC).
Implementation
%lang starknet
from starkware.starknet.common.syscalls import get_caller_address, deploy
from starkware.cairo.common.cairo_builtins import HashBuiltin
from starkware.cairo.common.hash import hash2
from starkware.cairo.common.bool import FALSE
@event
func ContractDeployed(
contractAddress: felt,
deployer: felt,
classHash: felt,
salt: felt
):
end
@external
func deploy_contract{
syscall_ptr: felt*,
pedersen_ptr: HashBuiltin*,
range_check_ptr,
} (
class_hash: felt,
salt: felt,
constructor_calldata_len: felt,
constructor_calldata: felt*,
) -> (contract_address: felt):
let (deployer) = get_caller_address()
let (unique_salt) = hash2{hash_ptr=pedersen_ptr}(deployer, salt)
let (contract_address) = deploy(
class_hash=class_hash,
contract_address_salt=unique_salt,
constructor_calldata_size=constructor_calldata_len,
constructor_calldata=constructor_calldata,
deploy_from_zero=FALSE
)
ContractDeployed.emit(
contractAddress=contract_address,
deployer=deployer,
classHash=class_hash,
salt=salt
)
return (contract_address=contract_address)
end
Salt
A naive implementation of the UDC could simply expose the deploy syscall, but that would allow any adversarial party to abuse the fact that the UDC has its own address –a constant parameter for the syscall– making the target address space accessible to anyone.
To avoid address takeovers (a.k.a. squatting), the UDC hashes the caller contract address together with the salt parameter, reserving a portion of the target address space for each caller address.
Deployment
The UDC must be deployed using deploy_from_zero=TRUE
to guarantee having the same deterministic address across all instances of StarkNet networks, facilitating tooling, interoperability and a schelling point where to find the right contract with the standard functionality.