Skip to content

SignDeclareTransaction

Signs a declare transaction by calculating the transaction hash and signing it with the account's private key. This method automatically sets the Signature field on the transaction with the resulting (r, s) signature components. Supports V1, V2, V3, and BroadcastDeclareTxnV3 declare transactions.

Method Signature

func (account *Account) SignDeclareTransaction(
	ctx context.Context,
	tx rpc.DeclareTxnType,
) error

Source: signature.go

Parameters

  • ctx (context.Context): Context for cancellation and timeout
  • tx (rpc.DeclareTxnType): Declare transaction to sign (DeclareTxnV1, DeclareTxnV2, DeclareTxnV3, or BroadcastDeclareTxnV3)

Returns

  • error: Error if signing fails or transaction type is invalid

Usage Example

package main
 
import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"math/big"
	"os"
 
	"github.com/NethermindEth/juno/core/felt"
	"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")
	}
 
	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)
	}
 
	content, err := os.ReadFile("contracts/cairo0/hello_starknet_compiled.json")
	if err != nil {
		fmt.Printf("Note: Contract file not found, using mock data for demonstration\n\n")
 
		nonce, err := accnt.Nonce(ctx)
		if err != nil {
			log.Fatal("Failed to get nonce:", err)
		}
 
		mockClassHash, _ := utils.HexToFelt("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef")
		mockCompiledClassHash, _ := utils.HexToFelt("0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd")
 
		declareTxn := &rpc.DeclareTxnV3{
			Nonce:   nonce,
			Type:    rpc.TransactionTypeDeclare,
			Version: rpc.TransactionV3,
			ResourceBounds: &rpc.ResourceBoundsMapping{
				L1Gas: rpc.ResourceBounds{
					MaxAmount:       "0x0",
					MaxPricePerUnit: "0x0",
				},
				L1DataGas: rpc.ResourceBounds{
					MaxAmount:       "0x0",
					MaxPricePerUnit: "0x0",
				},
				L2Gas: rpc.ResourceBounds{
					MaxAmount:       "0x0",
					MaxPricePerUnit: "0x0",
				},
			},
			Tip:                   "0x0",
			PayMasterData:         []*felt.Felt{},
			AccountDeploymentData: []*felt.Felt{},
			NonceDataMode:         rpc.DAModeL1,
			FeeMode:               rpc.DAModeL1,
			SenderAddress:         accountAddressFelt,
			ClassHash:             mockClassHash,
			CompiledClassHash:     mockCompiledClassHash,
			Signature:             []*felt.Felt{},
		}
 
		fmt.Printf("Sender:              %s\n", declareTxn.SenderAddress.String())
		fmt.Printf("Nonce:               %d\n", declareTxn.Nonce.Uint64())
		fmt.Printf("Class Hash:          %s\n", declareTxn.ClassHash.String())
		fmt.Printf("Compiled Class Hash: %s\n", declareTxn.CompiledClassHash.String())
		fmt.Printf("Signature (before):  %v\n\n", declareTxn.Signature)
 
		err = accnt.SignDeclareTransaction(ctx, declareTxn)
		if err != nil {
			log.Fatal("Failed to sign declare transaction:", err)
		}
 
		fmt.Printf("Signature components:\n")
		fmt.Printf("  r: %s\n", declareTxn.Signature[0].String())
		fmt.Printf("  s: %s\n", declareTxn.Signature[1].String())
 
	} else {
		var class contracts.ContractClass
		if err := json.Unmarshal(content, &class); err != nil {
			log.Fatal("Failed to unmarshal contract class:", err)
		}
 
		fmt.Printf("Contract class loaded with %d entry points\n", len(class.EntryPointsByType.External))
	}
}

Error Handling

err := acc.SignDeclareTransaction(ctx, declareTx)
if err != nil {
	switch {
	case errors.Is(err, account.ErrInvalidTransactionType):
		log.Println("Invalid declare transaction type")
	case errors.Is(err, account.ErrHashCalculationFailed):
		log.Println("Failed to calculate transaction hash")
	case errors.Is(err, account.ErrSigningFailed):
		log.Println("Failed to sign transaction")
	default:
		log.Printf("Failed to sign declare transaction: %v", err)
	}
	return
}

Common Use Cases

  • Sign manually constructed declare transactions before sending
  • Low-level transaction signing for advanced workflows
  • Usually handled automatically by BuildAndSendDeclareTxn
  • Custom transaction flows requiring manual signing control
  • Testing and debugging declare transaction signing