StorageAt
Retrieves the storage value of a contract at a specific key and block state. This method allows you to read the persistent state variables stored in a contract's storage.
Method Signature
func (provider *Provider) StorageAt(
ctx context.Context,
contractAddress *felt.Felt,
key string,
blockID BlockID,
) (string, error)Source: contract.go
Parameters
ctx(context.Context): Context for request cancellation and timeoutcontractAddress(*felt.Felt): The address of the contractkey(string): The storage key to retrieve (can be a variable name or hex string)blockID(BlockID): Block identifier (number, hash, or tag)
Returns
string: The storage value at the given key (as hex string)error: Error if the request fails
Type Definitions
BlockID
The blockID parameter specifies which block state to query. You can identify a block in three ways:
type BlockID struct {
Number *uint64 `json:"block_number,omitempty"`
Hash *felt.Felt `json:"block_hash,omitempty"`
Tag BlockTag `json:"tag,omitempty"`
}Source: types_block.go
There are helper functions for creating BlockID. So Instead of manually creating the BlockID struct, use these convenience functions.
-
By Block Number - Get a specific block by its height
blockID := rpc.WithBlockNumber(123456)Source: block.go
-
By Block Hash - Get a specific block by its hash
hash, _ := new(felt.Felt).SetString("0x1234...") blockID := rpc.WithBlockHash(hash)Source: block.go
-
By Block Tag - Get a dynamic block reference
blockID := rpc.WithBlockTag("latest") // Latest accepted block blockID := rpc.WithBlockTag("pending") // Block currently being builtSource: block.go
Usage Example
package main
import (
"context"
"encoding/hex"
"fmt"
"log"
"math/big"
"os"
"strings"
"github.com/NethermindEth/starknet.go/rpc"
"github.com/NethermindEth/starknet.go/utils"
"github.com/joho/godotenv"
)
func main() {
// Load environment variables from .env file
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
// Get RPC URL from environment variable
rpcURL := os.Getenv("STARKNET_RPC_URL")
if rpcURL == "" {
log.Fatal("STARKNET_RPC_URL not found in .env file")
}
// Initialize provider
provider, err := rpc.NewProvider(context.Background(), rpcURL)
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
// ETH contract address on Starknet (SPELOIA)
ethContract, err := utils.HexToFelt("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7")
if err != nil {
log.Fatal(err)
}
// Read token name from storage using variable name
// The method automatically converts "ERC20_name" to its storage key
nameValue, err := provider.StorageAt(ctx, ethContract, "ERC20_name", rpc.WithBlockTag("latest"))
if err != nil {
log.Fatal(err)
}
// Decode the hex-encoded string to readable text
tokenName := decodeShortString(nameValue)
fmt.Printf("Token Name: %s (raw: %s)\n", tokenName, nameValue)
// Read token symbol from storage
symbolValue, err := provider.StorageAt(ctx, ethContract, "ERC20_symbol", rpc.WithBlockTag("latest"))
if err != nil {
log.Fatal(err)
}
tokenSymbol := decodeShortString(symbolValue)
fmt.Printf("Token Symbol: %s (raw: %s)\n", tokenSymbol, symbolValue)
// Read decimals value and convert to integer
decimalsValue, err := provider.StorageAt(ctx, ethContract, "ERC20_decimals", rpc.WithBlockTag("latest"))
if err != nil {
log.Fatal(err)
}
decimals := new(big.Int)
decimals.SetString(strings.TrimPrefix(decimalsValue, "0x"), 16)
fmt.Printf("Token Decimals: %s (raw: %s)\n", decimals.String(), decimalsValue)
// Query historical total supply at a specific block number
totalSupplyValue, err := provider.StorageAt(ctx, ethContract, "ERC20_total_supply", rpc.WithBlockNumber(100000))
if err != nil {
log.Fatal(err)
}
totalSupply := new(big.Int)
totalSupply.SetString(strings.TrimPrefix(totalSupplyValue, "0x"), 16)
fmt.Printf("Total Supply at block 100000: %s (raw: %s)\n", totalSupply.String(), totalSupplyValue)
}
// decodeShortString decodes a hex-encoded short string (Cairo felt string)
func decodeShortString(hexStr string) string {
hexStr = strings.TrimPrefix(hexStr, "0x")
if len(hexStr)%2 != 0 {
hexStr = "0" + hexStr
}
bytes, err := hex.DecodeString(hexStr)
if err != nil {
return ""
}
return string(bytes)
}Error Handling
storageValue, err := provider.StorageAt(ctx, contractAddress, key, blockID)
if err != nil {
if errors.Is(err, rpc.ErrContractNotFound) {
log.Printf("Contract not found at address: %s", contractAddress)
return
}
if errors.Is(err, rpc.ErrBlockNotFound) {
log.Printf("Block not found")
return
}
log.Printf("Error retrieving storage: %v", err)
return
}
fmt.Printf("Storage value: %s\n", storageValue)Common Use Cases
- ead public state variables from deployed contracts.
- Check token balances stored in contract storage.
- Retrieve contract configuration values and settings.

