Skip to content

Deploy Account

This guide demonstrates how to deploy a new account on Starknet using Starknet.go.

Prerequisites

  • Go 1.23 or higher
  • Starknet.go installed
  • A Starknet RPC endpoint (from Alchemy, Infura, or your own Juno node)

Overview

This example uses a pre-existing OpenZeppelin account class on the Sepolia network to deploy a new account contract.

Steps:

  1. Create a .env file with your RPC URL
  2. Run the example to generate keys and precompute the address
  3. Fund the precomputed address using a Starknet faucet
  4. Press Enter to deploy the account
  5. Wait for transaction confirmation

At this point your account should be deployed on testnet, and you can use a block explorer like Voyager to view your transaction.

Setup

Create a .env file in your project root:

STARKNET_RPC_URL=<your-rpc-endpoint-url>

Code Example

main.go
package main
 
import (
	"context"
	"fmt"
	"os"
	"strings"
	"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"
)
 
// OpenZeppelin Account Class Hash in Sepolia
var predeployedClassHash = "0x61dac032f228abef9c6626f995015233097ae253a7f72d68552db02f2971b8f"
 
func main() {
	// Load environment variables from .env file
	if err := godotenv.Load(); err != nil {
		fmt.Println("Warning: .env file not found, using environment variables")
	}
 
	rpcURL := os.Getenv("STARKNET_RPC_URL")
	if rpcURL == "" {
		panic("STARKNET_RPC_URL environment variable is not set")
	}
 
	ctx := context.Background()
 
	// Initialize the client
	client, err := rpc.NewProvider(ctx, rpcURL)
	if err != nil {
		panic(err)
	}
 
	// Generate random keys for the new account
	ks, pub, privKey := account.GetRandomKeys()
	fmt.Printf("Generated public key: %v\n", pub)
	fmt.Printf("Generated private key: %v\n", privKey)
 
	// Set up the account (using pub as temporary address)
	accnt, err := account.NewAccount(client, pub, pub.String(), ks, account.CairoV2)
	if err != nil {
		panic(err)
	}
 
	classHash, err := utils.HexToFelt(predeployedClassHash)
	if err != nil {
		panic(err)
	}
 
	// Build and estimate fees for the deploy account transaction
	deployAccountTxn, precomputedAddress, err := accnt.BuildAndEstimateDeployAccountTxn(
		ctx,
		pub,
		classHash,
		[]*felt.Felt{pub},
		nil,
	)
	if err != nil {
		panic(err)
	}
 
	fmt.Printf("Precomputed address: %s\n", precomputedAddress.String())
 
	// Save the generated credentials to the .env file
	if err := saveCredentialsToEnv(privKey, pub, precomputedAddress); err != nil {
		fmt.Printf("Warning: Failed to save credentials to .env: %v\n", err)
	} else {
		fmt.Println("Credentials saved to .env file")
	}
 
	// Calculate fee in STRK
	overallFee, err := utils.ResBoundsMapToOverallFee(
		deployAccountTxn.ResourceBounds,
		1,
		deployAccountTxn.Tip,
	)
	if err != nil {
		panic(err)
	}
	feeInSTRK := utils.FRIToSTRK(overallFee)
 
	// Wait for user to fund the account
	fmt.Println("\nThe account needs STRK to deploy.")
	fmt.Printf("Send approximately %f STRK to: %s\n", feeInSTRK, precomputedAddress.String())
	fmt.Println("You can use the Starknet faucet: https://starknet-faucet.vercel.app/")
	fmt.Println("\nPress Enter after funding the account...")
	fmt.Scanln()
 
	// Send transaction to the network
	resp, err := accnt.SendTransaction(ctx, deployAccountTxn)
	if err != nil {
		fmt.Println("Error sending transaction:")
		panic(err)
	}
 
	fmt.Println("Deploy transaction submitted!")
	fmt.Printf("Transaction hash: %s\n", resp.Hash.String())
	fmt.Printf("Contract address: %s\n", resp.ContractAddress.String())
 
	// Wait for transaction confirmation
	fmt.Print("Waiting for confirmation")
	receipt, err := waitForTransaction(ctx, client, resp.Hash)
	if err != nil {
		fmt.Printf("\nWarning: Could not confirm transaction: %v\n", err)
		fmt.Println("Check the transaction status on Voyager or Starkscan.")
	} else {
		fmt.Printf("\n\nAccount deployed successfully!\n")
		fmt.Printf("Block number: %d\n", receipt.BlockNumber)
		fmt.Printf("Status: %s\n", receipt.FinalityStatus)
	}
}
 
// saveCredentialsToEnv saves the generated account credentials to the .env file
func saveCredentialsToEnv(privKey, pubKey, address *felt.Felt) error {
	envMap := make(map[string]string)
	if data, err := os.ReadFile(".env"); err == nil {
		for _, line := range strings.Split(string(data), "\n") {
			if parts := strings.SplitN(line, "=", 2); len(parts) == 2 {
				envMap[parts[0]] = parts[1]
			}
		}
	}
 
	envMap["ACCOUNT_PRIVATE_KEY"] = privKey.String()
	envMap["ACCOUNT_PUBLIC_KEY"] = pubKey.String()
	envMap["ACCOUNT_ADDRESS"] = address.String()
 
	var content strings.Builder
	for key, value := range envMap {
		content.WriteString(fmt.Sprintf("%s=%s\n", key, value))
	}
 
	return os.WriteFile(".env", []byte(content.String()), 0644)
}
 
// waitForTransaction polls the network until the transaction is confirmed
func waitForTransaction(ctx context.Context, client *rpc.Provider, txHash *felt.Felt) (*rpc.TransactionReceiptWithBlockInfo, error) {
	for i := 0; i < 60; i++ {
		receipt, err := client.TransactionReceipt(ctx, txHash)
		if err == nil {
			if receipt.FinalityStatus == rpc.TxnFinalityStatusAcceptedOnL2 ||
				receipt.FinalityStatus == rpc.TxnFinalityStatusAcceptedOnL1 {
				return receipt, nil
			}
		}
		time.Sleep(5 * time.Second)
		fmt.Print(".")
	}
	return nil, fmt.Errorf("transaction confirmation timeout")
}

Explanation

  1. Load the RPC URL from environment variables
  2. Initialize a Starknet RPC client with context
  3. Generate random cryptographic keys using account.GetRandomKeys()
  4. Create an account instance to sign the deploy transaction
  5. Build and estimate fees for the deployment
  6. Save credentials to .env for future use
  7. Wait for user to fund the precomputed address
  8. Send the deploy transaction
  9. Poll for transaction confirmation

Best Practices

  • Always store private keys securely
  • Use environment variables for sensitive information
  • Save generated credentials immediately after creation
  • Wait for transaction confirmation before proceeding

Common Issues

  • RPC spec version mismatch: Ensure your RPC provider version matches starknet.go requirements
  • Insufficient funds: The precomputed address needs STRK before deployment
  • Transaction timeout: Network congestion may cause delays; check block explorers