DeployContractWithUDC
Deploys a contract instance using the Universal Deployer Contract (UDC). This method builds and sends an invoke transaction to the UDC, which creates a new contract instance from a previously declared class hash. The deployment address is deterministic based on the class hash, salt, and optionally the deployer's address.
Method Signature
func (account *Account) DeployContractWithUDC(
ctx context.Context,
classHash *felt.Felt,
constructorCalldata []*felt.Felt,
txnOpts *TxnOptions,
udcOpts *UDCOptions,
) (rpc.AddInvokeTransactionResponse, *felt.Felt, error)Source: transaction.go
Parameters
ctx(context.Context): Context for request cancellation and timeoutclassHash(*felt.Felt): Class hash of the previously declared contract to deployconstructorCalldata([]*felt.Felt): Parameters passed to the contract constructor. Passnilif no constructortxnOpts(*TxnOptions): Transaction options for fee estimation and execution. Passnilto use default valuesudcOpts(*UDCOptions): UDC-specific deployment options (salt, origin independence). Passnilfor random salt and default settings
Returns
rpc.AddInvokeTransactionResponse: Response containing the transaction hash*felt.Felt: Salt used for deployment (useful for calculating deployed address)error: Error if deployment fails
AddInvokeTransactionResponse Structure
Source: types_transaction_response.go
The returned response contains:
type AddInvokeTransactionResponse struct {
Hash *felt.Felt `json:"transaction_hash"`
}Hash(*felt.Felt): Transaction hash of the deployment transaction
UDCOptions Structure
Source: udc.go
type UDCOptions struct {
Salt *felt.Felt // Salt for address computation. Random if not provided
OriginIndependent bool // If true, address is origin-independent (deployer address not included)
UDCVersion UDCVersion // UDC version (UDCCairoV0 or UDCCairoV2)
}Salt(*felt.Felt): Custom salt for deterministic address generation. Ifnil, a random salt is generatedOriginIndependent(bool): Controls whether deployer address affects deployment address.false= deployer-dependent,true= origin-independentUDCVersion(UDCVersion): UDC contract version to use (defaults to UDCCairoV0 if not specified)
Usage Example
package main
import (
"context"
"fmt"
"log"
"math/big"
"os"
"time"
"github.com/NethermindEth/juno/core/felt"
"github.com/NethermindEth/starknet.go/account"
"github.com/NethermindEth/starknet.go/rpc"
"github.com/NethermindEth/starknet.go/utils"
"github.com/joho/godotenv"
)
func main() {
ctx := context.Background()
if err := godotenv.Load(); err != nil {
log.Fatal("Failed to load .env file:", err)
}
rpcURL := os.Getenv("STARKNET_RPC_URL")
if rpcURL == "" {
log.Fatal("STARKNET_RPC_URL not set in .env file")
}
provider, err := rpc.NewProvider(ctx, rpcURL)
if err != nil {
log.Fatal("Failed to create provider:", err)
}
accountAddress := os.Getenv("ACCOUNT_ADDRESS")
publicKey := os.Getenv("ACCOUNT_PUBLIC_KEY")
privateKey := os.Getenv("ACCOUNT_PRIVATE_KEY")
if accountAddress == "" || publicKey == "" || privateKey == "" {
log.Fatal("ACCOUNT_ADDRESS, ACCOUNT_PUBLIC_KEY, or ACCOUNT_PRIVATE_KEY not set in .env")
}
ks := account.NewMemKeystore()
privKeyBI, ok := new(big.Int).SetString(privateKey, 0)
if !ok {
log.Fatal("Failed to parse private key")
}
ks.Put(publicKey, privKeyBI)
accountAddressFelt, err := utils.HexToFelt(accountAddress)
if err != nil {
log.Fatal("Failed to parse account address:", err)
}
accnt, err := account.NewAccount(
provider,
accountAddressFelt,
publicKey,
ks,
account.CairoV2,
)
if err != nil {
log.Fatal("Failed to create account:", err)
}
erc20ClassHash, err := utils.HexToFelt("0x073d71c37e20c569186445d2c497d2195b4c0be9a255d72dbad86662fcc63ae6")
if err != nil {
log.Fatal("Failed to parse ERC20 class hash:", err)
}
name, err := utils.StringToByteArrFelt("MyToken")
if err != nil {
log.Fatal("Failed to convert name:", err)
}
symbol, err := utils.StringToByteArrFelt("MTK")
if err != nil {
log.Fatal("Failed to convert symbol:", err)
}
initialSupply, err := utils.HexToU256Felt("0xd3c21bcecceda1000000")
if err != nil {
log.Fatal("Failed to convert supply:", err)
}
recipient := accnt.Address
owner := accnt.Address
constructorCalldata := make([]*felt.Felt, 0, 20)
constructorCalldata = append(constructorCalldata, name...)
constructorCalldata = append(constructorCalldata, symbol...)
constructorCalldata = append(constructorCalldata, initialSupply...)
constructorCalldata = append(constructorCalldata, recipient, owner)
txnOpts := &account.TxnOptions{
FeeMultiplier: 1.5,
TipMultiplier: 1.0,
}
udcOpts := &utils.UDCOptions{
Salt: nil,
OriginIndependent: false,
UDCVersion: utils.UDCCairoV2,
}
response, salt, err := accnt.DeployContractWithUDC(
ctx,
erc20ClassHash,
constructorCalldata,
txnOpts,
udcOpts,
)
if err != nil {
log.Fatal("Failed to deploy contract:", err)
}
fmt.Printf("Deploy Transaction Successful:\n")
fmt.Printf("Transaction Hash: %s\n", response.Hash.String())
fmt.Printf("Salt Used: %s\n", salt.String())
deployedAddress := utils.PrecomputeAddressForUDC(
erc20ClassHash,
salt,
constructorCalldata,
utils.UDCCairoV2,
accnt.Address,
)
fmt.Printf("Deployed Address: %s\n", deployedAddress.String())
txReceipt, err := accnt.WaitForTransactionReceipt(
ctx,
response.Hash,
3*time.Second,
)
if err != nil {
log.Fatal("Failed to get transaction receipt:", err)
}
fmt.Printf("Block Number: %d\n", txReceipt.BlockNumber)
fmt.Printf("Execution Status: %s\n", txReceipt.ExecutionStatus)
fmt.Printf("Finality Status: %s\n", txReceipt.FinalityStatus)
}Error Handling
response, salt, err := acc.DeployContractWithUDC(ctx, classHash, calldata, txnOpts, udcOpts)
if err != nil {
switch {
case errors.Is(err, rpc.ErrClassHashNotFound):
log.Println("Class hash not declared on network")
case errors.Is(err, rpc.ErrInsufficientAccountBalance):
log.Println("Insufficient balance to pay deployment fees")
case errors.Is(err, rpc.ErrInvalidCallData):
log.Println("Invalid constructor calldata")
default:
log.Printf("Failed to deploy contract: %v", err)
}
return
}
fmt.Printf("Contract deployed successfully at transaction: %s\n", response.Hash.String())Common Use Cases
- Deploy contract instances from previously declared class hashes
- Create deterministic contract addresses using specific salts
- Deploy contracts with origin-independent addresses for address reservation
- Deploy multiple instances of the same contract class with different constructor parameters
- Recommended method for deploying contracts on Starknet (versus direct deployment)

