Το 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 εκθέτει μια δομή 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).
Τα απομακρυσμένα backends HTTP δέχονται προαιρετικά 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 μεταδίδει μέσω του παρόχου του και αγνοεί τη
συνάρτηση αποστολής· κάθε άλλη μορφή υπογράφει και η δική σας συνάρτηση μεταδίδει το
αποτέλεσμα σε 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)})
Υπογραφή σε παρτίδες
Η υπογραφή σε παρτίδες παρέχεται ως ανεξάρτητες βοηθητικές συναρτήσεις, ταυτόχρονα, με προαιρετική κλιμακωτή καθυστέρηση ανά αίτημα για APIs με περιορισμούς ρυθμού:
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 που διαχειρίζονται οι ίδιοι τη μετάδοση (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 των κλειδιών (τα keypair του memory και τα κλειδιά που παράγουν τοπικά τα 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 αποτυγχάνει και τη υπογεγραμμένη
συναλλαγή τη μεταδίδετε εσείς.
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 επιλέγει με βάση το config και επιστρέφει ένα core.SolanaSigner·
τα fordefi.NewBlackBox, fordefi.NewNativeAuto και fordefi.NewNativeManual
επιστρέφουν τον συγκεκριμένο τύπο και απορρίπτουν τα config των άλλων τρόπων λειτουργίας. Τα αιτήματα API
authenticate με υπογραφή αιτήματος ECDSA P-256: δώστε ακριβώς ένα από τα
PrivateKeyPEM ή έναν RequestSigner για να διατηρείτε αυτό το κλειδί σε KMS/HSM.
Λειτουργία native auto: το Fordefi μπορεί να αντικαταστήσει το blockhash και τις προμήθειες και στη συνέχεια υπογράφει και μεταδίδει. Δέχεται μόνο μη υπογεγραμμένη συναλλαγή της οποίας ο μοναδικός απαιτούμενος 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) και το υπογράφει
χωρίς να το μεταδώσει. Το ModifyAndSignTransaction αντικαθιστά το tx με τη
συναλλαγή που υπέγραψε το Fordefi: συνεχίστε πάντα από αυτήν. Το Fordefi πρέπει να είναι ο
πληρωτής των προμηθειών και να υπογράφει πριν από οποιονδήποτε άλλο απαιτούμενο signer, καθώς η επανεγγραφή ακυρώνει
τις υπάρχουσες υπογραφές. Η επανεγγραφή δεν συγκρίνεται (diff), γι' αυτό ελέγξτε το αποτέλεσμα πριν από τη
μετάδοση.
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 του μηνύματός σας
και δεν το μεταδίδει. Χρησιμοποιήστε την με ένα vault black box του Fordefi.
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 δεν αφαιρεί νεκρό κώδικα (dead-code elimination) πέρα από έναν διακλαδωτή
δυναμικής επιλογής (switch) κατά το runtime, οπότε ένα συγκεντρωτικό πακέτο θα εξανάγκαζε το SDK κάθε προμηθευτή (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 φέρει
το κλειδί που προκύπτει από το μήνυμα. Η επαναποστολή της συναλλαγής με πανομοιότυπα bytes είναι
ασφαλής· μια συναλλαγή που ξαναχτίστηκε (για παράδειγμα με νέο blockhash) είναι νέα μεταφορά.
Το core.SignAndSendTransaction αναφέρει επίσης αυτόν τον κωδικό όταν η συνάρτηση αποστολής σας
αποτυγχάνει, με την υπογραφή του πληρωτή προμηθειών στο TransactionSignature. Το Fireblocks
PROGRAM_CALL είναι μόνο για υπογραφή και δεν στέλνει κλειδί· αναφέρει αυτόν τον κωδικό μόνο όταν ένα
poll δείξει ότι το Fireblocks μετέδωσε παρ' όλα αυτά.
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?