Go

Το 2.0.0 είναι η πρώτη σταθερή έκδοση των modules της Go, επομένως δεν υπάρχει τίποτα προς μετάβαση. Ο οδηγός μετάβασης στην έκδοση 2.0 καλύπτει τον ίδιο διαχωρισμό δυνατοτήτων για Rust και TypeScript.

Εγκατάσταση

Κάθε backend είναι ένα ξεχωριστό module της Go, οπότε το build και το γράφημα των modules σας περιέχουν μόνο τα backends που εισάγετε:

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 φέρουν ετικέτα go/<module>/v2.0.0 (για παράδειγμα go/signers/memory/v2.0.0). Κάθε module απαιτεί Go 1.25.0, εκτός από το gcpkms, που απαιτεί Go 1.25.8 λόγω του ελάχιστου ορίου που θέτει το google.golang.org/api. Το Ledger υποστηρίζεται μόνο στη Rust και δεν διαθέτει module Go.

Συναλλαγές solana-go v2 και v1

Τα modules βασίζονται στο github.com/solana-foundation/solana-go/v2 v2.0.0 και δέχονται το *solana.Transaction του. Υποστηρίζονται συναλλαγές legacy, v0 και v1 (solana.MessageVersionV1), εκτός από το Fireblocks με UseProgramCall: true, που δέχεται μόνο legacy και v0.

Βασική χρήση

Κάθε signer υλοποιεί τη βασική διεπαφή core.SolanaSigner (Pubkey, SignMessage, IsAvailable). Οι μέθοδοι δέχονται ένα context.Context και μπλοκάρουν. Κάθε backend υλοποιεί επίσης ακριβώς μία διεπαφή δυνατοτήτων:

  • core.TransactionSigner: το SignTransaction υπογράφει τη συναλλαγή σας ως έχει.
  • core.ModifyingSigner: το ModifyAndSignTransaction επιτρέπει στον πάροχο να ξαναγράψει τη συναλλαγή και στη συνέχεια την υπογράφει.
  • core.SendingSigner: το SignAndSendTransaction αναθέτει στον πάροχο την υπογραφή και την αποστολή της.

Κάθε πακέτο backend εκθέτει ένα struct Config και έναν constructor New:

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 και ModifyAndSignTransaction επιστρέφουν ένα core.SignedTransaction (EncodedTransaction, Signature, Completeness). Τα απομακρυσμένα HTTP backends δέχονται προαιρετικά HTTPClient και HTTPClientConfig (χρονικά όρια). Ο προεπιλεγμένος client επιβάλλει HTTPS· αν δώσετε δικό σας, αυτό παρακάμπτεται και η ασφάλειά του αποτελεί δική σας ευθύνη.

Δυνατότητες signer

Ένα backend που δεν μπορεί να υπογράψει συναλλαγή δεν διαθέτει καθόλου μέθοδο SignTransaction, οπότε η δυνατότητα είναι γεγονός χρόνου μεταγλώττισης για τους συγκεκριμένους τύπους και έλεγχος τύπου (type assertion) για ένα core.SolanaSigner:

BackendΔυνατότηταSignMessage
memory, vault, privy, turnkey, awskms, gcpkms, fireblocks, dfns, para, openfortTransactionSignerΝαι
cdpTransactionSignerΜόνο payloads UTF-8
utilaTransactionSignerΑποτυγχάνει με CodeSigningFailed
fordefi black box (fordefi.BlackBoxSigner)TransactionSignerΝαι
fordefi native manual (fordefi.NativeManualSigner)ModifyingSignerΝαι
fordefi native auto (fordefi.NativeAutoSigner)SendingSignerΝαι
crossmintSendingSignerΑποτυγχάνει με 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)
}

Αρχικοποίηση

Δεν υπάρχει ξεχωριστό βήμα Init. Τα Privy, Fireblocks, Dfns, Crossmint, Para, Openfort και Utila επιλύουν τη διεύθυνση του πορτοφολιού μέσα στο New, γι' αυτό οι constructors τους δέχονται ένα context.Context. Δημιουργείτε πάντα τους signers μέσω του New: ένας signer Crossmint, Para ή Utila με μηδενική τιμή αποτυγχάνει με CodeNotInitialized αντί να υπογράψει για τη μηδενική διεύθυνση.

Υπογραφή και αποστολή με οποιονδήποτε signer

Το core.SignAndSendTransaction καταχωρεί μια συναλλαγή στην αλυσίδα όποια κι αν είναι η μορφή του signer. Ένας SendingSigner κάνει broadcast μέσω του παρόχου του και αγνοεί τη συνάρτηση αποστολής· κάθε άλλη μορφή υπογράφει και η δική σας συνάρτηση κάνει broadcast το αποτέλεσμα σε base64, το οποίο για έναν ModifyingSigner είναι η συναλλαγή που ξαναέγραψε ο πάροχός του. Το Core δεν έχει εξάρτηση από RPC:

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)
})

Υπογραφή παρτίδας

Η υπογραφή παρτίδας παρέχεται ως ανεξάρτητες βοηθητικές συναρτήσεις, με ταυτόχρονη εκτέλεση και προαιρετική καθυστέρηση ανά αίτημα για API με περιορισμούς ρυθμού:

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 δέχεται ένα core.TransactionSigner, επομένως οι signers με διαχείριση broadcast (Crossmint, Fordefi native auto) και το Fordefi native manual δεν μπορούν να υποβληθούν σε παρτίδα μέσω αυτού· καλέστε τους μία συναλλαγή τη φορά. Ένας signer του οποίου οι κλήσεις δημιουργούν εργασία στην πλευρά του παρόχου (Fireblocks με UseProgramCall) το δηλώνει μέσω του core.BatchServerSideEffects, και η παρτίδα τότε εκτελείται διαδοχικά.

Ρύθμιση backend

Memory

Δώστε ακριβώς ένα από τα PrivateKey (ακατέργαστα bytes), PrivateKeyString (base58 ή ένας πίνακας bytes [1,2,...]) ή PrivateKeyPath (αρχείο keypair του Solana CLI):

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

Η Go δεν προσφέρει αξιόπιστο τρόπο μηδενισμού της μνήμης: ο garbage collector μπορεί να αντιγράψει και να διατηρήσει bytes κλειδιών (keypairs μνήμης και τα κλειδιά που παράγουν τοπικά τα Crossmint και Openfort) μέχρι τη συλλογή. Αντιμετωπίστε ολόκληρη τη μνήμη της διεργασίας ως ευαίσθητη κατά τη χρήση backends τοπικών κλειδιών.

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 του CDP δέχεται μόνο payloads UTF-8.

Crossmint

Το Crossmint είναι μόνο για αποστολή: το API του εκτελεί κάθε εγκεκριμένη συναλλαγή στην πλευρά του διακομιστή, οπότε το *crossmint.Signer διαθέτει SignAndSendTransaction και όχι SignTransaction. Η συναλλαγή σας δεν τροποποιείται ποτέ· η υπογραφή που επιστρέφεται ταυτοποιεί τη συναλλαγή που κατέγραψε το Crossmint, η οποία μπορεί να διαφέρει από τη δική σας αν το Crossmint χορηγεί το κόστος gas.

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 μόνο υπογράφει συναλλαγές· το SignMessage αποτυγχάνει και κάνετε εσείς broadcast της υπογεγραμμένης συναλλαγής.

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 διατίθεται με τρεις τύπους signer, που καθορίζονται κατά τη δημιουργία από τα Config.Chain και Config.PushMode. Και οι τρεις υπογράφουν μηνύματα:

ConfigΤύποςΣημείο εισόδου
Chain μη ορισμένο*fordefi.BlackBoxSignerSignTransaction
Chain ορισμένο, PushMode μη ορισμένο ή PushModeAuto*fordefi.NativeAutoSignerSignAndSendTransaction
Chain ορισμένο, PushMode: PushModeManual*fordefi.NativeManualSignerModifyAndSignTransaction

Το fordefi.New κάνει dispatch ανάλογα με το config και επιστρέφει ένα core.SolanaSigner· τα fordefi.NewBlackBox, fordefi.NewNativeAuto και fordefi.NewNativeManual επιστρέφουν τον συγκεκριμένο τύπο και απορρίπτουν τα config των άλλων τρόπων λειτουργίας. Τα αιτήματα API αυθεντικοποιούνται με υπογραφή αιτήματος ECDSA P-256: δώστε ακριβώς ένα από τα PrivateKeyPEM ή RequestSigner, ώστε το κλειδί να παραμένει σε KMS/HSM.

Λειτουργία native auto: το Fordefi μπορεί να αντικαταστήσει το blockhash και τα τέλη, και στη συνέχεια υπογράφει και κάνει broadcast. Δέχεται μόνο μη υπογεγραμμένη συναλλαγή της οποίας ο μοναδικός απαιτούμενος signer είναι το vault.

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: ορίστε PushMode: fordefi.PushModeManual. Το Fordefi ξαναγράφει το μήνυμα (πρόσφατο blockhash, εντολές τελών Compute Budget) και το υπογράφει χωρίς broadcast. Το ModifyAndSignTransaction αντικαθιστά το tx με τη συναλλαγή που υπέγραψε το Fordefi: συνεχίστε πάντα από αυτήν. Το Fordefi πρέπει να είναι ο πληρωτής των τελών και να υπογράφει πριν από οποιονδήποτε άλλο απαιτούμενο signer, καθώς η αναδιατύπωση ακυρώνει τις υπάρχουσες υπογραφές. Η αναδιατύπωση δεν παρουσιάζεται ως diff, οπότε ελέγξτε το αποτέλεσμα πριν το broadcast.

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: αφήστε το Chain μη ορισμένο. Το Fordefi υπογράφει τα ακριβή bytes του μηνύματός σας και δεν κάνει broadcast. Χρησιμοποιήστε την με vault Fordefi black box.

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),
})

Γιατί δεν υπάρχει ενιαίο πακέτο

Η Rust έχει ένα enum Signer και η TypeScript το createKeychainSigner· η Go σκόπιμα δεν έχει κανένα από τα δύο. Η Go δεν εξαλείφει νεκρό κώδικα μέσω ενός switch δυναμικής επιλογής κατά το runtime, οπότε ένα ενιαίο πακέτο θα εισήγαγε το SDK κάθε προμηθευτή backend (AWS, GCP και τα υπόλοιπα) στο build κάθε χρήστη. Η εισαγωγή του πακέτου backend που χρειάζεστε είναι ο επιλογέας. Για να επιλέξετε backend κατά το runtime, γράψτε το switch στον δικό σας κώδικα μόνο για τα backends που υποστηρίζετε και κρατήστε το αποτέλεσμα ως core.SolanaSigner.

Διαχείριση σφαλμάτων

Κάθε σφάλμα είναι ένα *core.SignerError με σταθερό Code (CodeConfigError, CodeHTTPError, CodeRemoteAPIError, CodeSigningFailed, CodeNotInitialized, CodeBroadcastUnconfirmed και άλλα). Το Error() επιστρέφει μόνο ένα σταθερό μήνυμα ανά κωδικό, ποτέ υλικό κλειδιών ή ακατέργαστες απαντήσεις παρόχου. Αντιστοιχίστε με errors.As, errors.Is(err, &core.SignerError{Code: ...}) ή core.CodeOf(err).

Στο Crossmint και στη λειτουργία Fordefi native auto, μια αποτυχία δεν σημαίνει ότι δεν καταχωρήθηκε τίποτα. Όταν ο πάροχος ενδέχεται να έχει αποδεχτεί τη συναλλαγή, ο κωδικός είναι core.CodeBroadcastUnconfirmed ("SIGNER_BROADCAST_UNCONFIRMED"). Το ProviderTxID ορίζεται όταν η δημιουργία έγινε αποδεκτή και το IdempotencyKey φέρει το κλειδί που προκύπτει από το μήνυμα. Η επαναποστολή της πανομοιότυπης (byte προς byte) συναλλαγής είναι ασφαλής· μια συναλλαγή που ξαναχτίστηκε (για παράδειγμα με νέο blockhash) αποτελεί νέα μεταφορά. Το core.SignAndSendTransaction αναφέρει επίσης αυτόν τον κωδικό όταν η συνάρτηση αποστολής σας αποτυγχάνει, με την υπογραφή του πληρωτή τελών στο TransactionSignature. Το Fireblocks PROGRAM_CALL είναι μόνο για υπογραφή και δεν στέλνει κλειδί· αναφέρει αυτόν τον κωδικό μόνο όταν ένα poll δείξει ότι το Fireblocks έκανε broadcast παρ' όλα αυτά.

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.
}

Δείτε το μοντέλο ασφαλείας για το τι εγγυάται κάθε μορφή υπογραφής, το README της Go για την πλήρη λίστα modules, και το pkg.go.dev για την τεκμηρίωση του API.

Προσθήκη προσαρμοσμένων signers

Υλοποιήστε το core.SolanaSigner συν ακριβώς μία διεπαφή δυνατοτήτων και μην προσθέσετε καμία μέθοδο που το backend σας δεν μπορεί να υποστηρίξει: οι καλούντες εντοπίζουν τη δυνατότητα με type assertion. Δείτε τον οδηγό προσθήκης signers για να ενσωματώσετε επιπλέον υπηρεσίες διαχείρισης κλειδιών.

Is this page helpful?

© 2026 Ίδρυμα Solana. Με επιφύλαξη παντός δικαιώματος.