Skip to content

BuildAndSendDeclareTxn

Builds, signs, estimates fees, and sends a declare transaction to register a new contract class on Starknet. This method handles the entire declaration process including nonce management, fee estimation, and transaction signing automatically. The returned class hash can be used to deploy contract instances.

Method Signature

func (account *Account) BuildAndSendDeclareTxn(
	ctx context.Context,
	casmClass *contracts.CasmClass,
	contractClass *contracts.ContractClass,
	opts *TxnOptions,
) (rpc.AddDeclareTransactionResponse, error)

Source: transaction.go

Parameters

  • ctx (context.Context): Context for request cancellation and timeout
  • casmClass (*contracts.CasmClass): Compiled CASM (Cairo Assembly) class generated from Sierra compilation
  • contractClass (*contracts.ContractClass): Sierra contract class containing the high-level contract definition
  • opts (*TxnOptions): Transaction options for fee estimation and execution. Pass nil to use default values

Returns

  • rpc.AddDeclareTransactionResponse: Response containing transaction hash and declared class hash
  • error: Error if declaration fails

AddDeclareTransactionResponse Structure

Source: types_transaction_response.go

The returned response contains:

type AddDeclareTransactionResponse struct {
	Hash      *felt.Felt `json:"transaction_hash"`
	ClassHash *felt.Felt `json:"class_hash"`
}
Fields:
  • Hash (*felt.Felt): Transaction hash of the declare transaction
  • ClassHash (*felt.Felt): Class hash of the declared contract (used for deployment)

Usage Example

package main
 
import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"math/big"
	"os"
 
	"github.com/NethermindEth/starknet.go/account"
	"github.com/NethermindEth/starknet.go/contracts"
	"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)
	}
 
	sierraFile, err := os.ReadFile("contract.sierra.json")
	if err != nil {
		log.Fatal("Failed to read sierra file:", err)
	}
 
	var contractClass contracts.ContractClass
	if err := json.Unmarshal(sierraFile, &contractClass); err != nil {
		log.Fatal("Failed to unmarshal contract class:", err)
	}
 
	casmClass, err := contracts.UnmarshalCasmClass("contract.casm.json")
	if err != nil {
		log.Fatal("Failed to unmarshal casm class:", err)
	}
 
	opts := &account.TxnOptions{
		FeeMultiplier: 1.5,
		TipMultiplier: 1.0,
	}
 
	response, err := accnt.BuildAndSendDeclareTxn(
		ctx,
		casmClass,
		&contractClass,
		opts,
	)
	if err != nil {
		log.Fatal("Failed to declare contract:", err)
	}
 
	fmt.Printf("Declare Transaction Successful:\n")
	fmt.Printf("Transaction Hash: %s\n", response.Hash.String())
	fmt.Printf("Class Hash:       %s\n", response.ClassHash.String())
	fmt.Printf("\nUse this class hash to deploy contract instances\n")
}

Error Handling

response, err := acc.BuildAndSendDeclareTxn(ctx, casmClass, contractClass, opts)
if err != nil {
	switch {
	case errors.Is(err, rpc.ErrClassAlreadyDeclared):
		log.Println("Contract class already declared on network")
	case errors.Is(err, rpc.ErrInvalidContractClass):
		log.Println("Invalid contract class format")
	case errors.Is(err, rpc.ErrInsufficientAccountBalance):
		log.Println("Insufficient balance to pay transaction fees")
	default:
		log.Printf("Failed to declare contract: %v", err)
	}
	return
}
 
fmt.Printf("Declared successfully with class hash: %s\n", response.ClassHash.String())

Common Use Cases

  • Register a new contract class on Starknet before deploying instances
  • Declare upgraded versions of existing contracts with new class hashes
  • Deploy libraries or base contracts that will be used by other contracts
  • Essential first step before using DeployContractWithUDC to create contract instances
  • Automatically handles nonce management, fee estimation, and signing in one method call