2.0.0 là bản phát hành ổn định đầu tiên của các module Go, vì vậy không có gì cần migrate. Hướng dẫn migrate lên 2.0 đề cập đến cách phân tách capability tương tự cho Rust và TypeScript.
Cài đặt
Mỗi backend là một Go module riêng, nên bản build và đồ thị module của bạn chỉ chứa các backend mà bạn import:
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
Các module được gắn tag go/<module>/v2.0.0 (ví dụ
go/signers/memory/v2.0.0). Mọi module đều yêu cầu Go 1.25.0, ngoại trừ gcpkms,
yêu cầu Go 1.25.8 do mức tối thiểu được đặt bởi google.golang.org/api.
Ledger chỉ dành cho Rust và không có Go module.
Giao dịch solana-go v2 và v1
Các module được xây dựng trên
github.com/solana-foundation/solana-go/v2
v2.0.0 và nhận *solana.Transaction của thư viện này. Hỗ trợ các giao dịch legacy, v0 và v1
(solana.MessageVersionV1), ngoại trừ Fireblocks
với UseProgramCall: true, vốn chỉ chấp nhận legacy và v0.
Cách sử dụng cơ bản
Mọi signer đều triển khai
interface core.SolanaSigner
cơ sở (Pubkey, SignMessage, IsAvailable). Các phương thức nhận context.Context và
là blocking. Mỗi backend cũng triển khai đúng một capability interface:
core.TransactionSigner:SignTransactionký giao dịch của bạn đúng như đã cung cấp.core.ModifyingSigner:ModifyAndSignTransactioncho phép nhà cung cấp viết lại giao dịch, rồi ký giao dịch đó.core.SendingSigner:SignAndSendTransactionđể nhà cung cấp ký và broadcast giao dịch.
Mỗi package backend cung cấp một struct Config và một 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 và ModifyAndSignTransaction trả về một
core.SignedTransaction (EncodedTransaction, Signature, Completeness).
Các backend HTTP từ xa chấp nhận HTTPClient và HTTPClientConfig
(timeout) tùy chọn. Client mặc định bắt buộc dùng HTTPS; nếu bạn tự cung cấp client thì quy tắc này bị bỏ qua,
và bạn tự chịu trách nhiệm về tình trạng bảo mật của client đó.
Capability của Signer
Một backend không thể ký giao dịch sẽ hoàn toàn không có phương thức SignTransaction,
nên capability là một điều được xác định tại thời điểm biên dịch đối với các kiểu cụ thể và là một type
assertion đối với core.SolanaSigner:
| Backend | Capability | SignMessage |
|---|---|---|
| memory, vault, privy, turnkey, awskms, gcpkms, fireblocks, dfns, para, openfort | TransactionSigner | Có |
| cdp | TransactionSigner | Chỉ payload UTF-8 |
| utila | TransactionSigner | Thất bại với CodeSigningFailed |
fordefi black box (fordefi.BlackBoxSigner) | TransactionSigner | Có |
fordefi native manual (fordefi.NativeManualSigner) | ModifyingSigner | Có |
fordefi native auto (fordefi.NativeAutoSigner) | SendingSigner | Có |
| crossmint | SendingSigner | Thất bại với 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)}
Khởi tạo
Không có bước Init riêng. Privy, Fireblocks, Dfns, Crossmint, Para,
Openfort và Utila xác định địa chỉ ví bên trong New, đó là lý do các
constructor của chúng nhận context.Context. Hãy luôn tạo signer thông qua New: một
signer Crossmint, Para hoặc Utila ở giá trị zero sẽ thất bại với CodeNotInitialized
thay vì ký cho địa chỉ zero.
Ký và gửi với bất kỳ Signer nào
core.SignAndSendTransaction đưa giao dịch lên chuỗi bất kể signer có
dạng nào. SendingSigner broadcast thông qua nhà cung cấp của nó và bỏ qua hàm gửi;
mọi dạng khác sẽ ký và hàm của bạn broadcast kết quả base64, đối với ModifyingSigner
đó là giao dịch mà nhà cung cấp đã viết lại.
Core không phụ thuộc vào 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)})
Ký hàng loạt
Việc ký hàng loạt được cung cấp dưới dạng các hàm helper tự do, chạy đồng thời với độ trễ tùy chọn giữa các yêu cầu dành cho các API bị giới hạn tốc độ:
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 nhận một core.TransactionSigner, vì vậy các
signer do broadcast quản lý (Crossmint, Fordefi native auto) và Fordefi native
manual không thể được xử lý hàng loạt qua hàm này; hãy gọi từng giao dịch một. Một
signer mà các lệnh gọi tạo ra công việc phía nhà cung cấp (Fireblocks với UseProgramCall)
sẽ báo cáo điều đó thông qua core.BatchServerSideEffects, và khi đó lô sẽ chạy
tuần tự.
Cấu hình Backend
Memory
Cung cấp đúng một trong các tùy chọn PrivateKey (byte thô), PrivateKeyString (base58 hoặc
mảng byte [1,2,...]) hoặc PrivateKeyPath (tệp keypair của 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 không cung cấp cách đáng tin cậy để xóa trắng bộ nhớ: bộ thu gom rác có thể sao chép và giữ lại các byte khóa cho đến khi được thu gom (keypair trong memory, và các khóa mà Crossmint và Openfort tạo ra cục bộ). Hãy coi toàn bộ bộ nhớ của tiến trình là dữ liệu nhạy cảm khi sử dụng các backend khóa cục bộ.
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 của CDP chỉ chấp nhận payload UTF-8.
Crossmint
Crossmint chỉ hỗ trợ gửi: API của nó thực thi mọi giao dịch đã được phê duyệt
ở phía máy chủ, nên *crossmint.Signer có SignAndSendTransaction mà không có
SignTransaction. Giao dịch của bạn không bao giờ bị sửa đổi; chữ ký được trả về
xác định giao dịch mà Crossmint đã đưa lên chuỗi, có thể khác với giao dịch của bạn nếu
Crossmint tài trợ phí 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 chỉ ký giao dịch; SignMessage sẽ thất bại, và bạn tự broadcast giao dịch
đã ký.
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 có ba loại signer, được cố định khi khởi tạo bởi Config.Chain và
Config.PushMode. Cả ba đều ký được thông điệp:
| Config | Kiểu | Điểm vào |
|---|---|---|
Chain không được đặt | *fordefi.BlackBoxSigner | SignTransaction |
Chain được đặt, PushMode không được đặt hoặc là PushModeAuto | *fordefi.NativeAutoSigner | SignAndSendTransaction |
Chain được đặt, PushMode: PushModeManual | *fordefi.NativeManualSigner | ModifyAndSignTransaction |
fordefi.New điều phối theo cấu hình và trả về một core.SolanaSigner;
fordefi.NewBlackBox, fordefi.NewNativeAuto và fordefi.NewNativeManual
trả về kiểu cụ thể và từ chối cấu hình của các chế độ khác. Các yêu cầu API được
xác thực bằng chữ ký yêu cầu ECDSA P-256: hãy cung cấp đúng một trong
PrivateKeyPEM, hoặc một RequestSigner để giữ khóa đó trong KMS/HSM.
Chế độ native auto: Fordefi có thể thay thế blockhash và phí, sau đó ký và broadcast. Chế độ này chỉ chấp nhận giao dịch chưa ký mà signer bắt buộc duy nhất là 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)
Chế độ native manual: đặt PushMode: fordefi.PushModeManual. Fordefi viết lại
thông điệp (blockhash gần nhất, các instruction phí Compute Budget) và ký mà
không broadcast. ModifyAndSignTransaction thay thế tx bằng
giao dịch mà Fordefi đã ký: hãy luôn tiếp tục từ giao dịch đó. Fordefi phải là bên
trả phí và phải ký trước mọi signer bắt buộc khác, vì việc viết lại làm vô hiệu
các chữ ký hiện có. Việc viết lại không có diff, nên hãy kiểm tra kết quả trước khi
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)
Chế độ black box: để Chain không được đặt. Fordefi ký chính xác các byte thông điệp của bạn
và không broadcast. Hãy dùng chế độ này với vault black box của 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),})
Vì sao không có Umbrella Package
Rust có enum Signer và TypeScript có createKeychainSigner; Go
cố ý không có cả hai. Go không loại bỏ dead code qua một
switch điều phối lúc chạy, nên một umbrella sẽ buộc SDK của nhà cung cấp cho mọi backend (AWS, GCP
và các nhà cung cấp còn lại) phải đi vào bản build của mọi consumer. Import package backend mà bạn
cần chính là bộ chọn. Để chọn backend lúc chạy, hãy viết switch trong code của riêng bạn
chỉ cho những backend bạn hỗ trợ, và giữ kết quả dưới dạng một
core.SolanaSigner.
Xử lý lỗi
Mọi lỗi đều là một *core.SignerError với Code ổn định (CodeConfigError,
CodeHTTPError, CodeRemoteAPIError, CodeSigningFailed,
CodeNotInitialized, CodeBroadcastUnconfirmed và các mã khác). Error() chỉ trả về
một thông điệp cố định cho mỗi mã, không bao giờ trả về dữ liệu khóa hay phản hồi thô từ nhà cung cấp.
Đối chiếu bằng errors.As, errors.Is(err, &core.SignerError{Code: ...}) hoặc
core.CodeOf(err).
Với Crossmint và chế độ native auto của Fordefi, một lỗi không có nghĩa là không có gì
được đưa lên chuỗi. Khi nhà cung cấp có thể đã chấp nhận giao dịch, mã sẽ là
core.CodeBroadcastUnconfirmed ("SIGNER_BROADCAST_UNCONFIRMED").
ProviderTxID được đặt khi yêu cầu tạo đã được chấp nhận, và IdempotencyKey mang
khóa được suy ra từ thông điệp. Gửi lại giao dịch giống hệt từng byte là
an toàn; một giao dịch được dựng lại (ví dụ với blockhash mới) là một lần chuyển mới.
core.SignAndSendTransaction cũng báo cáo mã này khi hàm gửi của bạn
thất bại, cùng chữ ký của fee payer trong TransactionSignature. Fireblocks
PROGRAM_CALL chỉ ký và không gửi khóa; nó chỉ báo cáo mã này khi một lần
poll cho thấy Fireblocks vẫn đã 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.}
Xem mô hình bảo mật để biết mỗi dạng ký đảm bảo điều gì, README của Go để xem danh sách module đầy đủ, và pkg.go.dev để xem tài liệu tham khảo API.
Thêm Signer tùy chỉnh
Triển khai core.SolanaSigner cùng đúng một capability interface, và đừng thêm
phương thức nào mà backend của bạn không thể đáp ứng: bên gọi phát hiện capability bằng type assertion.
Xem hướng dẫn Thêm Signer để tích hợp
các dịch vụ quản lý khóa bổ sung.
Is this page helpful?