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 розсилає її через свого провайдера та ігнорує функцію
надсилання; усі інші типи лише підписують, а ваша функція розсилає результат у 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.}
Див. модель безпеки щодо гарантій кожного типу підписання, README для Go щодо повного списку модулів і pkg.go.dev щодо довідника API.
Додавання власних підписувачів
Реалізуйте core.SolanaSigner та рівно один інтерфейс можливостей і не додавайте
методів, які ваш бекенд не може виконати: виклики визначають можливості через type assertion.
Див. посібник із додавання підписувачів, щоб інтегрувати
додаткові сервіси керування ключами.
Is this page helpful?