Go

2.0.0 is de eerste stabiele release van de Go-modules, dus er valt niets te migreren. De 2.0-migratiegids behandelt dezelfde opsplitsing in mogelijkheden voor Rust en TypeScript.

Installatie

Elke backend is een eigen Go-module, zodat je build en je modulegrafiek alleen de backends bevatten die je importeert:

go get github.com/solana-foundation/solana-keychain/go/core/v2 # Interfaces, errors, helpers
go get github.com/solana-foundation/solana-keychain/go/signers/memory/v2 # Local keypair signer
go get github.com/solana-foundation/solana-keychain/go/signers/vault/v2 # HashiCorp Vault
go get github.com/solana-foundation/solana-keychain/go/signers/awskms/v2 # AWS KMS
go get github.com/solana-foundation/solana-keychain/go/signers/gcpkms/v2 # GCP KMS
go get github.com/solana-foundation/solana-keychain/go/signers/privy/v2 # Privy
go get github.com/solana-foundation/solana-keychain/go/signers/turnkey/v2 # Turnkey
go get github.com/solana-foundation/solana-keychain/go/signers/fireblocks/v2 # Fireblocks
go get github.com/solana-foundation/solana-keychain/go/signers/cdp/v2 # Coinbase Developer Platform
go get github.com/solana-foundation/solana-keychain/go/signers/crossmint/v2 # Crossmint
go get github.com/solana-foundation/solana-keychain/go/signers/dfns/v2 # Dfns
go get github.com/solana-foundation/solana-keychain/go/signers/openfort/v2 # Openfort
go get github.com/solana-foundation/solana-keychain/go/signers/para/v2 # Para
go get github.com/solana-foundation/solana-keychain/go/signers/utila/v2 # Utila
go get github.com/solana-foundation/solana-keychain/go/signers/fordefi/v2 # Fordefi

Modules worden getagd als go/<module>/v2.0.0 (bijvoorbeeld go/signers/memory/v2.0.0). Elke module vereist Go 1.25.0, behalve gcpkms, die Go 1.25.8 vereist vanwege de ondergrens die door google.golang.org/api wordt bepaald. Ledger is alleen beschikbaar voor Rust en heeft geen Go-module.

solana-go v2 en v1-transacties

De modules zijn gebouwd op github.com/solana-foundation/solana-go/v2 v2.0.0 en accepteren de bijbehorende *solana.Transaction. Legacy-, v0- en v1-transacties (solana.MessageVersionV1) worden ondersteund, behalve door Fireblocks met UseProgramCall: true, dat alleen legacy en v0 accepteert.

Basisgebruik

Elke signer implementeert de basis- core.SolanaSigner-interface (Pubkey, SignMessage, IsAvailable). Methoden nemen een context.Context en blokkeren. Daarnaast implementeert elke backend precies één interface voor een mogelijkheid:

  • core.TransactionSigner: SignTransaction ondertekent je transactie zoals aangeleverd.
  • core.ModifyingSigner: ModifyAndSignTransaction laat de provider de transactie herschrijven en ondertekent die vervolgens.
  • core.SendingSigner: SignAndSendTransaction laat de provider de transactie ondertekenen en uitzenden.

Elk backendpakket biedt een Config-struct en een New-constructor:

import (
"context"
"fmt"
"github.com/solana-foundation/solana-go/v2"
"github.com/solana-foundation/solana-keychain/go/core/v2"
"github.com/solana-foundation/solana-keychain/go/signers/memory/v2"
)
func signWithKeychain(ctx context.Context, tx *solana.Transaction) error {
signer, err := memory.New(memory.Config{PrivateKeyPath: "/path/to/id.json"})
if err != nil {
return err
}
if !signer.IsAvailable(ctx) {
return core.NewSignerError(core.CodeNotAvailable, "signer offline")
}
result, err := signer.SignTransaction(ctx, tx)
if err != nil {
return err
}
fmt.Println("signature:", result.Signature)
fmt.Println("complete:", result.IsComplete())
// result.EncodedTransaction is the base64 wire transaction
return nil
}

SignTransaction en ModifyAndSignTransaction geven een core.SignedTransaction terug (EncodedTransaction, Signature, Completeness). Externe HTTP-backends accepteren een optionele HTTPClient en HTTPClientConfig (time-outs). De standaardclient dwingt HTTPS af; als je een eigen client meegeeft, wordt dat omzeild en ben je zelf verantwoordelijk voor de beveiliging ervan.

Mogelijkheden van signers

Een backend die geen transactie kan ondertekenen, heeft helemaal geen SignTransaction-methode. Of een mogelijkheid beschikbaar is, staat dus bij concrete typen al tijdens het compileren vast en wordt bij een core.SolanaSigner bepaald via een type assertion:

BackendMogelijkheidSignMessage
memory, vault, privy, turnkey, awskms, gcpkms, fireblocks, dfns, para, openfortTransactionSignerJa
cdpTransactionSignerAlleen UTF-8-payloads
utilaTransactionSignerMislukt met CodeSigningFailed
fordefi black box (fordefi.BlackBoxSigner)TransactionSignerJa
fordefi native manual (fordefi.NativeManualSigner)ModifyingSignerJa
fordefi native auto (fordefi.NativeAutoSigner)SendingSignerJa
crossmintSendingSignerMislukt met CodeSigningFailed
switch s := signer.(type) {
case core.SendingSigner:
sig, err := s.SignAndSendTransaction(ctx, tx)
case core.ModifyingSigner:
signed, err := s.ModifyAndSignTransaction(ctx, tx)
case core.TransactionSigner:
signed, err := s.SignTransaction(ctx, tx)
}

Initialisatie

Er is geen aparte Init-stap. Privy, Fireblocks, Dfns, Crossmint, Para, Openfort en Utila bepalen het walletadres binnen New, en daarom nemen hun constructors een context.Context. Bouw signers altijd via New: een Crossmint-, Para- of Utila-signer met nulwaarde mislukt met CodeNotInitialized in plaats van te ondertekenen voor het nuladres.

Ondertekenen en verzenden met elke signer

core.SignAndSendTransaction brengt een transactie on-chain, ongeacht het type signer. Een SendingSigner zendt uit via zijn provider en negeert de verzendfunctie; bij elk ander type ondertekent de signer en zendt jouw functie het base64-resultaat uit. Bij een ModifyingSigner is dat de transactie die de provider heeft herschreven. Core heeft geen RPC-afhankelijkheid:

import "github.com/solana-foundation/solana-go/v2/rpc"
client := rpc.New("https://api.devnet.solana.com")
sig, err := core.SignAndSendTransaction(ctx, signer, tx,
func(ctx context.Context, encoded string) (solana.Signature, error) {
return client.SendEncodedTransaction(ctx, encoded)
})

Batchondertekening

Batchondertekening wordt aangeboden als losse helpers, gelijktijdig en met een optionele vertraging per verzoek voor API's met rate limits:

sigs, err := core.SignMessages(ctx, signer, [][]byte{msg1, msg2}, core.BatchOptions{
MaxConcurrency: 4, // 0 = unbounded
RequestDelay: 50 * time.Millisecond,
})
signed, err := core.SignTransactions(ctx, signer, txs, core.BatchOptions{})

core.SignTransactions neemt een core.TransactionSigner, dus de signers die zelf uitzenden (Crossmint, Fordefi native auto) en Fordefi native manual kunnen niet via deze functie in batches worden verwerkt; roep ze één transactie per keer aan. Een signer waarvan de aanroepen werk aan de providerkant veroorzaken (Fireblocks met UseProgramCall) meldt dat via core.BatchServerSideEffects, waarna de batch sequentieel wordt uitgevoerd.

Backend-configuratie

Memory

Geef precies één van de volgende op: PrivateKey (ruwe bytes), PrivateKeyString (base58 of een [1,2,...]-bytearray) of PrivateKeyPath (Solana CLI-keypair-bestand):

import "github.com/solana-foundation/solana-keychain/go/signers/memory/v2"
signer, err := memory.New(memory.Config{
PrivateKeyPath: "/path/to/id.json",
})

Go biedt geen betrouwbare manier om geheugen op nul te zetten: de garbage collector kan sleutelbytes kopiëren en bewaren tot de volgende opruiming (memory-keypairs en de sleutels die Crossmint en Openfort lokaal afleiden). Behandel het volledige procesgeheugen als gevoelig wanneer je backends met lokale sleutels gebruikt.

HashiCorp Vault

import "github.com/solana-foundation/solana-keychain/go/signers/vault/v2"
signer, err := vault.New(vault.Config{
VaultAddr: "https://vault.example.com:8200",
Token: "hvs.xxxxx",
KeyName: "my-solana-key",
Pubkey: "base58_public_key",
})

AWS KMS

import "github.com/solana-foundation/solana-keychain/go/signers/awskms/v2"
signer, err := awskms.New(ctx, awskms.Config{
KeyID: "alias/my-solana-key",
PublicKey: "base58_public_key",
Region: "us-east-1", // optional
})

GCP KMS

import "github.com/solana-foundation/solana-keychain/go/signers/gcpkms/v2"
signer, err := gcpkms.New(ctx, gcpkms.Config{
KeyName: "projects/my-project/locations/us-east1/keyRings/my-ring/cryptoKeys/my-key/cryptoKeyVersions/1",
PublicKey: "base58_public_key",
})
if err != nil {
return err
}
defer signer.Close()

Privy

import "github.com/solana-foundation/solana-keychain/go/signers/privy/v2"
signer, err := privy.New(ctx, privy.Config{
AppID: "app_id",
AppSecret: "app_secret",
WalletID: "wallet_id",
})

Turnkey

import "github.com/solana-foundation/solana-keychain/go/signers/turnkey/v2"
signer, err := turnkey.New(turnkey.Config{
APIPublicKey: "api_public_key",
APIPrivateKey: "api_private_key",
OrganizationID: "org_id",
PrivateKeyID: "private_key_id",
PublicKey: "base58_public_key",
})

Fireblocks

import "github.com/solana-foundation/solana-keychain/go/signers/fireblocks/v2"
signer, err := fireblocks.New(ctx, fireblocks.Config{
APIKey: "api_key",
PrivateKeyPEM: "-----BEGIN RSA PRIVATE KEY-----\n...",
VaultAccountID: "0",
AssetID: "SOL", // or "SOL_TEST" for devnet
UseProgramCall: false, // true signs via sign-only PROGRAM_CALL (legacy/v0, hot wallet)
})

CDP (Coinbase Developer Platform)

import "github.com/solana-foundation/solana-keychain/go/signers/cdp/v2"
signer, err := cdp.New(cdp.Config{
APIKeyID: "api_key_id",
APIKeySecret: "api_key_secret", // base64 Ed25519
WalletSecret: "wallet_secret", // base64 PKCS#8 DER
Address: "base58_address",
Network: cdp.NetworkMainnet, // or cdp.NetworkDevnet; required for address lookup tables
})

SignMessage van CDP accepteert alleen UTF-8-payloads.

Crossmint

Crossmint kan alleen uitzenden: de API voert elke goedgekeurde transactie aan de serverkant uit, dus *crossmint.Signer heeft SignAndSendTransaction en geen SignTransaction. Je transactie wordt nooit gewijzigd; de teruggegeven handtekening identificeert de transactie die Crossmint heeft verwerkt, en die kan afwijken van de jouwe als Crossmint de gas sponsort.

import "github.com/solana-foundation/solana-keychain/go/signers/crossmint/v2"
signer, err := crossmint.New(ctx, crossmint.Config{
APIKey: "api_key",
WalletLocator: "wallet_locator",
SignerSecret: "", // optional xmsk1_ secret: auto-approves what Crossmint presents
})
sig, err := signer.SignAndSendTransaction(ctx, tx)

Dfns

import "github.com/solana-foundation/solana-keychain/go/signers/dfns/v2"
signer, err := dfns.New(ctx, dfns.Config{
AuthToken: "auth_token",
CredID: "cred_id",
PrivateKeyPEM: "-----BEGIN EC PRIVATE KEY-----\n...",
WalletID: "wallet_id",
})

Openfort

import "github.com/solana-foundation/solana-keychain/go/signers/openfort/v2"
signer, err := openfort.New(ctx, openfort.Config{
SecretKey: "sk_live_...",
AccountID: "acc_...",
WalletSecret: "wallet_secret", // base64 PKCS#8 DER or PEM
})

Para

import "github.com/solana-foundation/solana-keychain/go/signers/para/v2"
signer, err := para.New(ctx, para.Config{
APIKey: "sk_...",
WalletID: "wallet_id",
})

Utila

Utila ondertekent alleen transacties; SignMessage mislukt, en je zendt de ondertekende transactie zelf uit.

import "github.com/solana-foundation/solana-keychain/go/signers/utila/v2"
signer, err := utila.New(ctx, utila.Config{
ServiceAccountEmail: "sa@example.com",
ServiceAccountPrivateKeyPEM: "-----BEGIN PRIVATE KEY-----\n...",
VaultID: "vault_id",
WalletID: "wallet_id",
Network: "networks/solana-devnet",
})

Fordefi

Fordefi bestaat in drie signertypen, die bij de constructie worden bepaald door Config.Chain en Config.PushMode. Alle drie ondertekenen berichten:

ConfigTypeStartpunt
Chain niet ingesteld*fordefi.BlackBoxSignerSignTransaction
Chain ingesteld, PushMode niet ingesteld of PushModeAuto*fordefi.NativeAutoSignerSignAndSendTransaction
Chain ingesteld, PushMode: PushModeManual*fordefi.NativeManualSignerModifyAndSignTransaction

fordefi.New kiest op basis van de config en geeft een core.SolanaSigner terug; fordefi.NewBlackBox, fordefi.NewNativeAuto en fordefi.NewNativeManual geven het concrete type terug en weigeren de configs van de andere modi. API-verzoeken worden geauthenticeerd met een ECDSA P-256-verzoekhandtekening: geef precies één van de volgende op: PrivateKeyPEM, of een RequestSigner om die sleutel in een KMS/HSM te houden.

Native auto-modus: Fordefi kan de blockhash en de fees vervangen, en ondertekent en zendt de transactie vervolgens uit. De modus accepteert alleen een niet-ondertekende transactie waarvan de enige vereiste ondertekenaar de vault is.

import "github.com/solana-foundation/solana-keychain/go/signers/fordefi/v2"
signer, err := fordefi.NewNativeAuto(ctx, fordefi.Config{
AccessToken: os.Getenv("FORDEFI_ACCESS_TOKEN"),
VaultID: os.Getenv("FORDEFI_VAULT_ID"),
PublicKey: os.Getenv("FORDEFI_PUBLIC_KEY"), // Solana vault address (base58)
PrivateKeyPEM: string(pemBytes),
Chain: fordefi.ChainSolanaDevnet, // or fordefi.ChainSolanaMainnet
Fee: &fordefi.Fee{
Type: fordefi.FeeTypePriority,
PriorityLevel: fordefi.PriorityMedium,
},
})
sig, err := signer.SignAndSendTransaction(ctx, tx)

Native manual-modus: stel PushMode: fordefi.PushModeManual in. Fordefi herschrijft het bericht (recente blockhash, Compute Budget-feeinstructies) en ondertekent het zonder uit te zenden. ModifyAndSignTransaction vervangt tx door de transactie die Fordefi heeft ondertekend: ga altijd verder met die transactie. Fordefi moet de fee payer zijn en moet vóór alle andere vereiste ondertekenaars tekenen, omdat de herschrijving bestaande handtekeningen ongeldig maakt. Het verschil met het origineel wordt niet bepaald, dus controleer het resultaat voordat je uitzendt.

signer, err := fordefi.NewNativeManual(ctx, fordefi.Config{
AccessToken: os.Getenv("FORDEFI_ACCESS_TOKEN"),
VaultID: os.Getenv("FORDEFI_VAULT_ID"),
PublicKey: os.Getenv("FORDEFI_PUBLIC_KEY"),
PrivateKeyPEM: string(pemBytes),
Chain: fordefi.ChainSolanaDevnet,
PushMode: fordefi.PushModeManual,
})
signed, err := signer.ModifyAndSignTransaction(ctx, tx)

Black box-modus: laat Chain niet ingesteld. Fordefi ondertekent exact de bytes van je bericht en zendt niet uit. Gebruik dit met een Fordefi black box-vault.

signer, err := fordefi.NewBlackBox(ctx, fordefi.Config{
AccessToken: os.Getenv("FORDEFI_ACCESS_TOKEN"),
VaultID: os.Getenv("FORDEFI_BB_VAULT_ID"),
PublicKey: os.Getenv("FORDEFI_BB_PUBLIC_KEY"),
PrivateKeyPEM: string(pemBytes),
})

Waarom er geen overkoepelend pakket is

Rust heeft een Signer-enum en TypeScript heeft createKeychainSigner; Go heeft bewust geen van beide. Go verwijdert geen dode code over een runtime dispatch-switch heen, dus een overkoepelend pakket zou de vendor-SDK van elke backend (AWS, GCP en de rest) in de build van elke consument dwingen. Het importeren van het backendpakket dat je nodig hebt, is de selector. Wil je runtime een backend kiezen, schrijf dan in je eigen code de switch over alleen de backends die je ondersteunt, en bewaar het resultaat als een core.SolanaSigner.

Foutafhandeling

Elke fout is een *core.SignerError met een stabiele Code (CodeConfigError, CodeHTTPError, CodeRemoteAPIError, CodeSigningFailed, CodeNotInitialized, CodeBroadcastUnconfirmed en andere). Error() geeft per code alleen een vaste melding terug, nooit sleutelmateriaal of ruwe providerresponses. Vergelijk met errors.As, errors.Is(err, &core.SignerError{Code: ...}) of core.CodeOf(err).

Bij Crossmint en Fordefi native auto-modus betekent een fout niet dat er niets is verwerkt. Als de provider de transactie mogelijk heeft geaccepteerd, is de code core.CodeBroadcastUnconfirmed ("SIGNER_BROADCAST_UNCONFIRMED"). ProviderTxID wordt ingesteld wanneer het aanmaken is geaccepteerd, en IdempotencyKey bevat de sleutel die van het bericht is afgeleid. Het opnieuw verzenden van de byte-identieke transactie is veilig; een opnieuw opgebouwde transactie (bijvoorbeeld met een nieuwe blockhash) is een nieuwe overdracht. core.SignAndSendTransaction meldt deze code ook wanneer je verzendfunctie faalt, met de handtekening van de fee payer in TransactionSignature. Fireblocks PROGRAM_CALL ondertekent alleen en verstuurt geen sleutel; het meldt deze code alleen wanneer een poll laat zien dat Fireblocks toch heeft uitgezonden.

sig, err := core.SignAndSendTransaction(ctx, signer, tx, send)
var se *core.SignerError
if errors.As(err, &se) && se.Code == core.CodeBroadcastUnconfirmed {
// Reconcile se.ProviderTxID, se.IdempotencyKey or se.TransactionSignature
// with the provider before retrying.
}

Zie het beveiligingsmodel voor wat elk type ondertekening garandeert, de Go README voor de volledige lijst met modules, en pkg.go.dev voor de API-referentie.

Eigen signers toevoegen

Implementeer core.SolanaSigner plus precies één interface voor een mogelijkheid, en voeg geen methode toe die je backend niet kan waarmaken: aanroepers stellen de mogelijkheden vast via een type assertion. Zie de gids voor het toevoegen van signers om extra sleutelbeheerdiensten te integreren.

Is this page helpful?

© 2026 Solana Foundation. Alle rechten voorbehouden.