viem-goviem-go

Private Key Account

Create an account from a private key for signing transactions and messages locally

A Private Key Account is an account that can sign transactions and messages with a given private key. In viem-go, signing uses go-ethereum/crypto (secp256k1).

Import

import "github.com/ChefBingbong/viem-go/accounts"

Usage

Pass a 32-byte hex private key (with or without 0x prefix) to PrivateKeyToAccount:

import "github.com/ChefBingbong/viem-go/accounts"
account, err := accounts.PrivateKeyToAccount(
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Address: %s
", account.GetAddress())
// Address: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
fmt.Printf("Public Key: %s
", account.GetPublicKey())

The key in the example is valid for testing only. Do not use it for real funds.

Generating private keys

Generate a cryptographically secure random private key with GeneratePrivateKey. It returns a hex string (no error); it panics only on a broken RNG.

import "github.com/ChefBingbong/viem-go/accounts"
privateKey := accounts.GeneratePrivateKey()
// "0x..." (64 hex characters)
account, err := accounts.PrivateKeyToAccount(privateKey)
if err != nil {
log.Fatal(err)
}

For deterministic tests, use GeneratePrivateKeyWithEntropy(entropy []byte) — it returns an error if the 32-byte entropy is not a valid secp256k1 private key.

Signing messages

Sign an EIP-191 personal message:

import "github.com/ChefBingbong/viem-go/utils/signature"
msg := signature.NewSignableMessage("Hello, Ethereum!")
sig, err := account.SignMessage(msg)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Signature: %s
", sig)

For raw bytes use signature.NewSignableMessageRaw(bytes) or signature.NewSignableMessageRawHex(hexString).

Signing transactions

Sign a transaction (legacy, EIP-2930, EIP-1559, etc.). The account returns the serialized signed transaction ready for broadcast.

import (
"github.com/ChefBingbong/viem-go/utils/transaction"
"math/big"
)
tx := &transaction.Transaction{
To: "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
Value: big.NewInt(1e18),
Gas: 21000,
GasPrice: big.NewInt(20e9),
Nonce: 0,
ChainId: 1,
}
signedTx, err := account.SignTransaction(tx)
if err != nil {
log.Fatal(err)
}
// signedTx is hex-encoded (e.g. 0x02...) ready for eth_sendRawTransaction

Signing typed data (EIP-712)

import (
"github.com/ChefBingbong/viem-go/utils/signature"
"math/big"
)
typedData := signature.TypedDataDefinition{
Domain: signature.TypedDataDomain{
Name: "Ether Mail",
Version: "1",
ChainId: big.NewInt(1),
VerifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
},
Types: map[string][]signature.TypedDataField{
"Person": {{Name: "name", Type: "string"}, {Name: "wallet", Type: "address"}},
"Mail": {{Name: "from", Type: "Person"}, {Name: "to", Type: "Person"}, {Name: "contents", Type: "string"}},
},
PrimaryType: "Mail",
Message: map[string]any{
"from": map[string]any{"name": "Alice", "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"},
"to": map[string]any{"name": "Bob", "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"},
"contents": "Hello, Bob!",
},
}
sig, err := account.SignTypedData(typedData)
if err != nil {
log.Fatal(err)
}

Signing authorizations (EIP-7702)

Private key accounts can sign EIP-7702 authorization requests via SignAuthorization:

signedAuth, err := account.SignAuthorization(accounts.AuthorizationRequest{
    Address: account.GetAddress(),
    ChainId: 1,
    Nonce:   0,
})

Parameters

privateKey

  • Type: string
  • Format: 32-byte hex, with or without 0x prefix (64 hex characters after optional prefix).

The private key must be valid secp256k1 (e.g. not zero, in range).

account, err := accounts.PrivateKeyToAccount("0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80")
// or
account, err := accounts.PrivateKeyToAccount("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80")

opts (optional)

  • Type: ...PrivateKeyToAccountOptions

In viem-go, PrivateKeyToAccountOptions is a struct that can be extended later (e.g. nonce manager). Currently you can omit it or pass an empty struct.

Return type

  • Go: PrivateKeyToAccount(privateKey string, opts ...PrivateKeyToAccountOptions) (*PrivateKeyAccount, error)
  • Must variant: MustPrivateKeyToAccount(privateKey string, opts ...PrivateKeyToAccountOptions) *PrivateKeyAccount — panics on error.

Error handling

Possible errors: ErrInvalidPrivateKey (invalid format or not valid secp256k1). viem-go does not define a separate ErrPrivateKeyLength; invalid length is reported as ErrInvalidPrivateKey.

account, err := accounts.PrivateKeyToAccount(privateKey)
if err != nil {
if errors.Is(err, accounts.ErrInvalidPrivateKey) {
log.Println("Invalid private key format or value")
return
}
log.Fatal(err)
}