2.0.0 — це перший стабільний випуск модулів Go, тож мігрувати нічого не потрібно. У посібнику з міграції на 2.0 описано той самий поділ можливостей для Rust і TypeScript.
Встановлення
Кожен бекенд — це окремий модуль Go, тому ваша збірка та граф модулів містять лише ті бекенди, які ви імпортуєте:
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
Модулі позначаються тегами go/<module>/v2.0.0 (наприклад,
go/signers/memory/v2.0.0). Кожен модуль потребує Go 1.25.0, окрім gcpkms,
який потребує Go 1.25.8 через мінімальну версію, визначену в google.golang.org/api.
Ledger працює лише з Rust і не має модуля Go.
Транзакції solana-go v2 та v1
Модулі побудовано на
github.com/solana-foundation/solana-go/v2
v2.0.0, і вони приймають його *solana.Transaction. Підтримуються транзакції
legacy, v0 і v1 (solana.MessageVersionV1), окрім Fireblocks із
UseProgramCall: true, який приймає лише legacy та v0.
Базове використання
Кожен підписувач реалізує базовий
інтерфейс core.SolanaSigner
(Pubkey, SignMessage, IsAvailable). Методи приймають context.Context і
є блокувальними. Крім того, кожен бекенд реалізує рівно один інтерфейс можливостей:
core.TransactionSigner:SignTransactionпідписує вашу транзакцію як є.core.ModifyingSigner:ModifyAndSignTransactionдозволяє провайдеру переписати транзакцію, після чого підписує її.core.SendingSigner:SignAndSendTransactionдоручає провайдеру підписати та розіслати її в мережу.
Кожен пакет бекенду надає структуру Config і конструктор 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-бекенди приймають необов’язкові HTTPClient та HTTPClientConfig
(тайм-аути). Клієнт за замовчуванням вимагає HTTPS; якщо ви передасте власний, ця перевірка обходиться,
і відповідальність за його безпеку лежить на вас.
Можливості підписувачів
Бекенд, який не може підписати транзакцію, взагалі не має методу SignTransaction,
тому можливість — це факт, відомий на етапі компіляції для конкретних типів, і
перевірка типу (type assertion) для core.SolanaSigner:
| Бекенд | Можливість | SignMessage |
|---|---|---|
| memory, vault, privy, turnkey, awskms, gcpkms, fireblocks, dfns, para, openfort | TransactionSigner | Так |
| cdp | TransactionSigner | Лише дані 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, тому їхні
конструктори приймають context.Context. Завжди створюйте підписувачів через New: підписувач
Crossmint, Para або Utila з нульовим значенням завершується помилкою CodeNotInitialized,
а не підписує для нульової адреси.
Підписання й надсилання з будь-яким підписувачем
core.SignAndSendTransaction доставляє транзакцію в мережу незалежно від
типу підписувача. SendingSigner розсилає через свого провайдера й ігнорує функцію
надсилання; будь-який інший тип підписує, а вашa функція розсилає результат у форматі 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, тому
підписувачі з керованим розсиланням (Crossmint, Fordefi native auto) і Fordefi native
manual не можна обробляти пакетами через нього; викликайте їх по одній транзакції. Підписувач,
виклики якого створюють роботу на боці провайдера (Fireblocks з UseProgramCall),
повідомляє про це через core.BatchServerSideEffects, і тоді пакет виконується
послідовно.
Конфігурація бекендів
Memory
Вкажіть рівно одне з: PrivateKey (сирі байти), PrivateKeyString (base58 або
масив байтів [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 не надає надійного способу занулити пам’ять: збирач сміття може копіювати й зберігати байти ключів (memory keypair, а також ключі, які Crossmint і Openfort виводять локально) до наступного збирання. Вважайте всю пам’ять процесу чутливою, коли використовуєте бекенди з локальними ключами.
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 приймає лише дані UTF-8.
Crossmint
Crossmint працює лише на надсилання: його API виконує кожну схвалену транзакцію
на стороні сервера, тому *crossmint.Signer має SignAndSendTransaction і не має
SignTransaction. Вашу транзакцію ніколи не змінюють; повернений підпис
ідентифікує транзакцію, яку Crossmint записав у мережу, і вона може відрізнятися від вашої, якщо
Crossmint спонсорує газ.
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 має три типи підписувачів, які визначаються під час створення через Config.Chain та
Config.PushMode. Усі три підписують повідомлення:
| Config | Тип | Точка входу |
|---|---|---|
Chain не задано | *fordefi.BlackBoxSigner | SignTransaction |
Chain задано, PushMode не задано або PushModeAuto | *fordefi.NativeAutoSigner | SignAndSendTransaction |
Chain задано, PushMode: PushModeManual | *fordefi.NativeManualSigner | ModifyAndSignTransaction |
fordefi.New обирає тип за конфігурацією та повертає core.SolanaSigner;
fordefi.NewBlackBox, fordefi.NewNativeAuto і fordefi.NewNativeManual
повертають конкретний тип і відхиляють конфігурації інших режимів. Запити до API
автентифікуються підписом запиту ECDSA P-256: вкажіть рівно одне з
PrivateKeyPEM або RequestSigner, щоб зберігати цей ключ у KMS/HSM.
Режим native auto: Fordefi може замінити blockhash і комісії, після чого підписує й розсилає транзакцію. Він приймає лише непідписану транзакцію, єдиним необхідним підписувачем якої є сховище (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 переписує
повідомлення (recent blockhash, інструкції комісій Compute Budget) і підписує його
без розсилання. ModifyAndSignTransaction замінює tx на
транзакцію, яку підписав Fordefi: завжди продовжуйте роботу з нею. Fordefi має бути платником
комісії та має підписати раніше за будь-якого іншого необхідного підписувача, оскільки переписування анулює
існуючі підписи. Різниця після переписування не обчислюється, тому перевіряйте результат перед
розсиланням.
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 підписує точні байти вашого повідомлення
і не розсилає його. Використовуйте це зі сховищем 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) під час виконання, тому узагальнювальний пакет примусив би додати SDK постачальників усіх бекендів (AWS, GCP
та решти) до збірки кожного споживача. Імпорт потрібного вам пакета бекенду
і є вибором. Щоб обирати бекенд під час виконання, напишіть switch у власному
коді лише для бекендів, які ви підтримуєте, і зберігайте результат як
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 містить
ключ, виведений із повідомлення. Повторне надсилання побайтово ідентичної транзакції
безпечне; перебудована (наприклад, з новим blockhash) — це новий переказ.
core.SignAndSendTransaction також повідомляє цей код, коли ваша функція надсилання
завершується помилкою, із підписом платника комісії в TransactionSignature. Fireblocks
PROGRAM_CALL лише підписує й не надсилає ключ; він повідомляє цей код, лише якщо
опитування показує, що 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.}
Дивіться модель безпеки щодо гарантій кожного типу підписання, Go README щодо повного списку модулів і pkg.go.dev щодо довідника API.
Додавання власних підписувачів
Реалізуйте core.SolanaSigner та рівно один інтерфейс можливостей і не додавайте
методів, які ваш бекенд не може виконати: виклики визначають можливості через type assertion.
Див. посібник із додавання підписувачів, щоб інтегрувати
додаткові сервіси керування ключами.
Is this page helpful?