Go

2.0.0 adalah rilis stabil pertama dari modul Go, jadi tidak ada yang perlu dimigrasikan. Panduan migrasi 2.0 membahas pemisahan kapabilitas yang sama untuk Rust dan TypeScript.

Instalasi

Setiap backend adalah modul Go tersendiri, sehingga build dan grafik modul Anda hanya berisi backend yang Anda impor:

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

Modul diberi tag go/<module>/v2.0.0 (misalnya go/signers/memory/v2.0.0). Setiap modul memerlukan Go 1.25.0, kecuali gcpkms, yang memerlukan Go 1.25.8 karena batas minimum yang ditetapkan oleh google.golang.org/api. Ledger hanya tersedia untuk Rust dan tidak memiliki modul Go.

Transaksi solana-go v2 dan v1

Modul-modul ini dibangun di atas github.com/solana-foundation/solana-go/v2 v2.0.0 dan menerima *solana.Transaction. Transaksi legacy, v0, dan v1 (solana.MessageVersionV1) didukung, kecuali oleh Fireblocks dengan UseProgramCall: true, yang hanya menerima legacy dan v0.

Penggunaan Dasar

Setiap signer mengimplementasikan antarmuka core.SolanaSigner dasar (Pubkey, SignMessage, IsAvailable). Metode menerima context.Context dan bersifat blocking. Setiap backend juga mengimplementasikan tepat satu antarmuka kapabilitas:

  • core.TransactionSigner: SignTransaction menandatangani transaksi Anda apa adanya.
  • core.ModifyingSigner: ModifyAndSignTransaction memungkinkan provider menulis ulang transaksi, lalu menandatanganinya.
  • core.SendingSigner: SignAndSendTransaction meminta provider menandatangani dan menyiarkannya.

Setiap paket backend menyediakan struct Config dan konstruktor 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 dan ModifyAndSignTransaction mengembalikan core.SignedTransaction (EncodedTransaction, Signature, Completeness). Backend HTTP jarak jauh menerima HTTPClient dan HTTPClientConfig opsional (batas waktu). Klien default memberlakukan HTTPS; jika Anda menyediakan klien sendiri, hal itu dilewati, dan Anda bertanggung jawab atas postur keamanannya.

Kapabilitas Signer

Backend yang tidak dapat menandatangani transaksi sama sekali tidak memiliki metode SignTransaction, sehingga kapabilitas merupakan fakta saat kompilasi untuk tipe konkret dan berupa type assertion untuk core.SolanaSigner:

BackendKapabilitasSignMessage
memory, vault, privy, turnkey, awskms, gcpkms, fireblocks, dfns, para, openfortTransactionSignerYa
cdpTransactionSignerHanya payload UTF-8
utilaTransactionSignerGagal dengan CodeSigningFailed
fordefi black box (fordefi.BlackBoxSigner)TransactionSignerYa
fordefi native manual (fordefi.NativeManualSigner)ModifyingSignerYa
fordefi native auto (fordefi.NativeAutoSigner)SendingSignerYa
crossmintSendingSignerGagal dengan 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)
}

Inisialisasi

Tidak ada langkah Init terpisah. Privy, Fireblocks, Dfns, Crossmint, Para, Openfort, dan Utila menentukan alamat wallet di dalam New, itulah sebabnya konstruktor mereka menerima context.Context. Selalu buat signer melalui New: signer Crossmint, Para, atau Utila dengan nilai nol akan gagal dengan CodeNotInitialized alih-alih menandatangani untuk alamat nol.

Tanda Tangan dan Kirim dengan Signer Apa Pun

core.SignAndSendTransaction mengirimkan transaksi ke chain apa pun bentuk signer-nya. SendingSigner menyiarkan melalui providernya dan mengabaikan fungsi kirim; setiap bentuk lainnya menandatangani dan fungsi Anda menyiarkan hasil base64, yang untuk ModifyingSigner adalah transaksi yang ditulis ulang oleh providernya. Core tidak memiliki dependensi 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)
})

Penandatanganan Batch

Penandatanganan batch disediakan sebagai helper bebas, berjalan secara konkuren dengan jeda opsional per permintaan untuk API yang dibatasi lajunya:

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 menerima core.TransactionSigner, sehingga signer yang dikelola siaran (Crossmint, Fordefi native auto) dan Fordefi native manual tidak dapat di-batch melaluinya; panggil satu transaksi pada satu waktu. Signer yang panggilannya menciptakan pekerjaan di sisi provider (Fireblocks dengan UseProgramCall) melaporkannya melalui core.BatchServerSideEffects, dan batch kemudian berjalan secara berurutan.

Konfigurasi Backend

Memory

Berikan tepat satu dari PrivateKey (byte mentah), PrivateKeyString (base58 atau array byte [1,2,...]), atau PrivateKeyPath (file 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 tidak menyediakan cara yang andal untuk mengosongkan memori: garbage collector dapat menyalin dan mempertahankan byte kunci (keypair memory, serta kunci yang diturunkan Crossmint dan Openfort secara lokal) hingga pengumpulan terjadi. Perlakukan seluruh memori proses sebagai data sensitif saat menggunakan backend kunci lokal.

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 milik CDP hanya menerima payload UTF-8.

Crossmint

Crossmint hanya mengirim: API-nya mengeksekusi setiap transaksi yang disetujui di sisi server, sehingga *crossmint.Signer memiliki SignAndSendTransaction dan tidak ada SignTransaction. Transaksi Anda tidak pernah dimodifikasi; signature yang dikembalikan mengidentifikasi transaksi yang didaratkan Crossmint, yang mungkin berbeda dari transaksi Anda jika Crossmint menanggung biaya 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 hanya menandatangani transaksi; SignMessage gagal, dan Anda menyiarkan transaksi yang sudah ditandatangani itu sendiri.

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 hadir dalam tiga tipe signer, yang ditetapkan saat konstruksi oleh Config.Chain dan Config.PushMode. Ketiganya menandatangani pesan:

ConfigTipeTitik masuk
Chain tidak diatur*fordefi.BlackBoxSignerSignTransaction
Chain diatur, PushMode tidak diatur atau PushModeAuto*fordefi.NativeAutoSignerSignAndSendTransaction
Chain diatur, PushMode: PushModeManual*fordefi.NativeManualSignerModifyAndSignTransaction

fordefi.New melakukan dispatch berdasarkan config dan mengembalikan core.SolanaSigner; fordefi.NewBlackBox, fordefi.NewNativeAuto, dan fordefi.NewNativeManual mengembalikan tipe konkret dan menolak config dari mode lain. Permintaan API diautentikasi dengan signature permintaan ECDSA P-256: berikan tepat satu dari PrivateKeyPEM, atau RequestSigner untuk menyimpan kunci tersebut di KMS/HSM.

Mode native auto: Fordefi dapat mengganti blockhash dan biaya, lalu menandatangani dan menyiarkan. Mode ini hanya menerima transaksi yang belum ditandatangani dengan satu-satunya signer yang diperlukan adalah 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)

Mode native manual: atur PushMode: fordefi.PushModeManual. Fordefi menulis ulang pesan (recent blockhash, instruksi biaya Compute Budget) dan menandatanganinya tanpa menyiarkan. ModifyAndSignTransaction mengganti tx dengan transaksi yang ditandatangani Fordefi: selalu lanjutkan dari transaksi tersebut. Fordefi harus menjadi fee payer dan harus menandatangani sebelum signer lain yang diperlukan, karena penulisan ulang membatalkan signature yang ada. Penulisan ulang tidak di-diff, jadi periksa hasilnya sebelum menyiarkan.

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)

Mode black box: biarkan Chain tidak diatur. Fordefi menandatangani byte pesan Anda secara persis dan tidak menyiarkan. Gunakan ini dengan 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),
})

Mengapa Tidak Ada Paket Umbrella

Rust memiliki enum Signer dan TypeScript memiliki createKeychainSigner; Go sengaja tidak memiliki keduanya. Go tidak melakukan dead-code-elimination melewati switch dispatch runtime, sehingga paket umbrella akan memaksa SDK vendor setiap backend (AWS, GCP, dan lainnya) masuk ke build setiap konsumen. Mengimpor paket backend yang Anda butuhkan adalah penyelektornya. Untuk memilih backend saat runtime, tulis switch di kode Anda sendiri hanya untuk backend yang Anda dukung, dan simpan hasilnya sebagai core.SolanaSigner.

Penanganan Error

Setiap error adalah *core.SignerError dengan Code yang stabil (CodeConfigError, CodeHTTPError, CodeRemoteAPIError, CodeSigningFailed, CodeNotInitialized, CodeBroadcastUnconfirmed, dan lainnya). Error() hanya mengembalikan pesan tetap per kode, tidak pernah materi kunci atau respons mentah provider. Cocokkan dengan errors.As, errors.Is(err, &core.SignerError{Code: ...}), atau core.CodeOf(err).

Pada Crossmint dan mode native auto Fordefi, kegagalan tidak berarti tidak ada yang mendarat. Ketika provider mungkin telah menerima transaksi, kodenya adalah core.CodeBroadcastUnconfirmed ("SIGNER_BROADCAST_UNCONFIRMED"). ProviderTxID diatur ketika pembuatan diterima, dan IdempotencyKey membawa kunci yang diturunkan dari pesan. Mengirim ulang transaksi yang identik byte demi byte adalah aman; transaksi yang dibangun ulang (misalnya dengan blockhash baru) adalah transfer baru. core.SignAndSendTransaction juga melaporkan kode ini ketika fungsi kirim Anda gagal, dengan signature fee-payer di TransactionSignature. Fireblocks PROGRAM_CALL hanya menandatangani dan tidak mengirim kunci; ia melaporkan kode ini hanya ketika polling menunjukkan Fireblocks tetap menyiarkan.

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

Lihat model keamanan untuk jaminan dari setiap bentuk penandatanganan, README Go untuk daftar modul lengkap, dan pkg.go.dev untuk referensi API.

Menambahkan Signer Kustom

Implementasikan core.SolanaSigner ditambah tepat satu antarmuka kapabilitas, dan jangan menambahkan metode yang tidak dapat dipenuhi backend Anda: pemanggil mendeteksi kapabilitas melalui type assertion. Lihat panduan Adding Signers untuk mengintegrasikan layanan manajemen kunci tambahan.

Is this page helpful?

© 2026 Yayasan Solana. Semua hak dilindungi.