Το 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, helpersgo get github.com/solana-foundation/solana-keychain/go/signers/memory/v2 # Local keypair signergo get github.com/solana-foundation/solana-keychain/go/signers/vault/v2 # HashiCorp Vaultgo get github.com/solana-foundation/solana-keychain/go/signers/awskms/v2 # AWS KMSgo get github.com/solana-foundation/solana-keychain/go/signers/gcpkms/v2 # GCP KMSgo get github.com/solana-foundation/solana-keychain/go/signers/privy/v2 # Privygo get github.com/solana-foundation/solana-keychain/go/signers/turnkey/v2 # Turnkeygo get github.com/solana-foundation/solana-keychain/go/signers/fireblocks/v2 # Fireblocksgo get github.com/solana-foundation/solana-keychain/go/signers/cdp/v2 # Coinbase Developer Platformgo get github.com/solana-foundation/solana-keychain/go/signers/crossmint/v2 # Crossmintgo get github.com/solana-foundation/solana-keychain/go/signers/dfns/v2 # Dfnsgo get github.com/solana-foundation/solana-keychain/go/signers/openfort/v2 # Openfortgo get github.com/solana-foundation/solana-keychain/go/signers/para/v2 # Parago get github.com/solana-foundation/solana-keychain/go/signers/utila/v2 # Utilago 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 transactionreturn 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, openfort | TransactionSigner | Ναι |
| cdp | TransactionSigner | Μόνο payloads UTF-8 |
| utila | TransactionSigner | Αποτυγχάνει με CodeSigningFailed |
fordefi black box (fordefi.BlackBoxSigner) | TransactionSigner | Ναι |
fordefi native manual (fordefi.NativeManualSigner) | ModifyingSigner | Ναι |
fordefi native auto (fordefi.NativeAutoSigner) | SendingSigner | Ναι |
| crossmint | SendingSigner | Αποτυγχάνει με 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 = unboundedRequestDelay: 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 devnetUseProgramCall: 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 Ed25519WalletSecret: "wallet_secret", // base64 PKCS#8 DERAddress: "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.BlackBoxSigner | SignTransaction |
Chain ορισμένο, PushMode μη ορισμένο ή PushModeAuto | *fordefi.NativeAutoSigner | SignAndSendTransaction |
Chain ορισμένο, PushMode: PushModeManual | *fordefi.NativeManualSigner | ModifyAndSignTransaction |
Το 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.ChainSolanaMainnetFee: &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.SignerErrorif 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?