TypeScript

Está a atualizar da versão 1.x? Consulte o guia de migração para a 2.0.

Instalação

Instale o pacote umbrella ou signatários individuais conforme necessário:

# Umbrella package (includes all signers)
pnpm add @solana/keychain
# Or install individual packages
pnpm add @solana/keychain-core # Core interfaces (required for custom signers)
pnpm add @solana/keychain-memory # Local keypair signer
pnpm add @solana/keychain-vault # HashiCorp Vault
pnpm add @solana/keychain-aws-kms # AWS KMS
pnpm add @solana/keychain-gcp-kms # GCP KMS
pnpm add @solana/keychain-privy # Privy
pnpm add @solana/keychain-turnkey # Turnkey
pnpm add @solana/keychain-fireblocks # Fireblocks
pnpm add @solana/keychain-cdp # Coinbase Developer Platform
pnpm add @solana/keychain-crossmint # Crossmint
pnpm add @solana/keychain-dfns # Dfns
pnpm add @solana/keychain-openfort # Openfort
pnpm add @solana/keychain-para # Para
pnpm add @solana/keychain-utila # Utila
pnpm add @solana/keychain-fordefi # Fordefi
# Kit client plugins (keychainSigner / keychainPayer / keychainIdentity)
pnpm add @solana/keychain-kit-plugin

Requer @solana/kit 8.1 ou posterior. As transações v1 (createTransactionMessage({ version: 1 })) são suportadas, exceto pela Fireblocks com useProgramCall: true, que aceita apenas legacy e v0.

Uso Básico

Factory Unificada (Recomendada para aplicações que desejam suportar múltiplos signatários)

Use createKeychainSigner com uma configuração discriminada para criar qualquer backend:

import { createKeychainSigner } from "@solana/keychain";
import { signTransactionWithSigners } from "@solana/signers"; // requires @solana/signers >= 8.1
const signer = await createKeychainSigner({
backend: "privy",
appId: "your-app-id",
appSecret: "your-app-secret",
walletId: "your-wallet-id"
});
// Sign an already-compiled transaction
const signedTx = await signTransactionWithSigners(
[signer],
compiledTransaction
);

Ou instale um pacote de signatário individual para uma pegada de dependências menor:

import { createPrivySigner } from "@solana/keychain-privy";
const signer = await createPrivySigner({
appId: "your-app-id",
appSecret: "your-app-secret",
walletId: "your-wallet-id"
});

Usando com Mensagens de Transação

Todos os backends, exceto Crossmint e o modo nativo da Fordefi, devolvem um SolanaTransactionSigner, que é um TransactionPartialSigner do Kit e funciona com os auxiliares de partial-signer de @solana/signers apresentados abaixo. Os backends com broadcast gerido são abordados em Capacidades do Signer.

import type { SolanaTransactionSigner } from "@solana/keychain-core";
import { signTransactionMessageWithSigners } from "@solana/signers";
import {
createTransactionMessage,
setTransactionMessageFeePayerSigner,
pipe
} from "@solana/kit";
async function signWithKeychain(signer: SolanaTransactionSigner) {
// Check availability (useful for remote signers)
if (!(await signer.isAvailable())) {
throw new Error("Signer offline");
}
// Use with @solana/kit transaction builder
const transaction = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(signer, tx)
// ... set a lifetime and add instructions
);
// Sign with the standard signers API
const signedTx = await signTransactionMessageWithSigners(transaction);
return signedTx;
}

Assinar e enviar com qualquer Signer

signAndSendTransaction de @solana/keychain-core coloca uma transação na blockchain, independentemente do formato do signer. Os signers de envio fazem o broadcast através do respetivo provedor; qualquer outro formato utiliza o sendTransaction que fornecer (o core não tem dependência de RPC):

import { signAndSendTransaction } from "@solana/keychain-core";
const signature = await signAndSendTransaction(signer, transaction, {
sendTransaction: (tx) =>
sendAndConfirmTransaction(tx, { commitment: "confirmed" })
});

Usando com um Kit Client (plugin keychainSigner)

@solana/keychain-kit-plugin instala um keychain signer diretamente em um Kit client, configurando-o como payer e identity para que você pule a configuração manual de pipe mostrada acima:

import { createClient } from "@solana/kit";
import { keychainSigner } from "@solana/keychain-kit-plugin";
const client = await createClient().use(
keychainSigner({
backend: "privy",
appId: process.env.PRIVY_APP_ID!,
appSecret: process.env.PRIVY_APP_SECRET!,
walletId: process.env.PRIVY_WALLET_ID!
})
);
client.payer; // SolanaTransactionSigner, also a Kit TransactionPartialSigner
client.identity; // same signer instance

O plugin aceita a mesma configuração com etiqueta de backend que createKeychainSigner, exceto Crossmint e o modo nativo da Fordefi (com chain definido). Esses backends reescrevem a transação no lado do servidor, pelo que não podem atuar como payer ou identity do cliente; o plugin rejeita-os em tempo de compilação e em tempo de execução. Apenas o backend para o qual encaminha é incluído no pacote (os pacotes de backend são carregados através de import() dinâmico).

Use keychainPayer ou keychainIdentity para definir apenas um papel e misturar backends em um único client:

import { createClient } from "@solana/kit";
import { keychainIdentity, keychainPayer } from "@solana/keychain-kit-plugin";
const client = await createClient()
.use(
keychainPayer({
backend: "memory",
privateKeyPath: `${process.env.HOME}/.config/solana/id.json`
})
)
.use(keychainIdentity({ backend: "turnkey", ...turnkeyConfig }));

Já tem um SolanaTransactionSigner? É um TransactionPartialSigner do Kit válido, pelo que pode instalá-lo com @solana/kit-plugin-signer em vez disso (pnpm add @solana/kit-plugin-signer):

import { createClient } from "@solana/kit";
import { signer } from "@solana/kit-plugin-signer";
import { createKeychainSigner } from "@solana/keychain";
const mySigner = await createKeychainSigner({
backend: "vault",
...vaultConfig
});
const client = createClient().use(signer(mySigner));

Cancelamento e broadcasts não confirmados

signTransactions, modifyAndSignTransactions, signAndSendTransactions e signMessages aceitam todos { abortSignal } como segundo argumento. Abortar interrompe a espera; não desfaz o trabalho que um provedor já aceitou.

No modo nativo automático da Crossmint e da Fordefi, uma falha não significa que nada tenha sido processado. Quando o provedor pode ter aceitado a transação, o código de erro é SignerErrorCode.BROADCAST_UNCONFIRMED ("SIGNER_BROADCAST_UNCONFIRMED"). context.providerTransactionId é definido quando a criação foi aceite, e context.idempotencyKey contém a chave derivada da mensagem. Reenviar a transação com bytes idênticos é seguro; uma transação reconstruída (por exemplo, com um novo blockhash) é uma nova transferência. providerMayHaveAccepted(error) e providerStatus(error) de @solana/keychain-core ajudam a classificar o erro. Concilie com o provedor antes de tentar novamente.

Configuração de Backend

Memória

Indique exatamente um de keyPair, privateKey, privateKeyString ou privateKeyPath:

import { createMemorySigner } from "@solana/keychain-memory";
const signer = await createMemorySigner({
privateKeyPath: "/path/to/id.json"
});

HashiCorp Vault

import { createVaultSigner } from "@solana/keychain-vault";
const signer = createVaultSigner({
vaultAddr: "https://vault.example.com:8200",
vaultToken: "hvs.xxxxx",
keyName: "my-solana-key",
publicKey: "base58_public_key"
});

AWS KMS

import { createAwsKmsSigner } from "@solana/keychain-aws-kms";
const signer = createAwsKmsSigner({
keyId: "alias/my-solana-key",
publicKey: "base58_public_key",
region: "us-east-1" // optional
});

GCP KMS

import { createGcpKmsSigner } from "@solana/keychain-gcp-kms";
const signer = createGcpKmsSigner({
keyName:
"projects/my-project/locations/us-east1/keyRings/my-ring/cryptoKeys/my-key/cryptoKeyVersions/1",
publicKey: "base58_public_key"
});

Privy

import { createPrivySigner } from "@solana/keychain-privy";
const signer = await createPrivySigner({
appId: "app_id",
appSecret: "app_secret",
walletId: "wallet_id"
});

Turnkey

import { createTurnkeySigner } from "@solana/keychain-turnkey";
const signer = createTurnkeySigner({
apiPublicKey: "api_public_key",
apiPrivateKey: "api_private_key",
organizationId: "org_id",
privateKeyId: "private_key_id",
publicKey: "base58_public_key"
});

Fireblocks

import { createFireblocksSigner } from "@solana/keychain-fireblocks";
const signer = await createFireblocksSigner({
apiKey: "api_key",
privateKeyPem: "-----BEGIN RSA PRIVATE KEY-----\n...",
vaultAccountId: "0",
assetId: "SOL" // or "SOL_TEST" for devnet
});

CDP (Coinbase Developer Platform)

import { createCdpSigner } from "@solana/keychain-cdp";
const signer = await createCdpSigner({
cdpApiKeyId: "api_key_id",
cdpApiKeySecret: "api_key_secret",
cdpWalletSecret: "wallet_secret",
address: "base58_address",
network: "solana" // or "solana-devnet"; required for address lookup tables
});

Crossmint

import { createCrossmintSigner } from "@solana/keychain-crossmint";
const signer = await createCrossmintSigner({
apiKey: "api_key",
walletLocator: "wallet_locator"
});

A Crossmint é apenas de envio. A sua API executa sempre uma transação aprovada no lado do servidor e patrocina o gas, pelo que o signer expõe apenas signAndSendTransactions(): não tem signTransactions() nem signMessages(), e não pode ser instalado com @solana/keychain-kit-plugin. A assinatura devolvida identifica a transação que a Crossmint processou.

const [signature] = await signer.signAndSendTransactions([transaction]);
// or: await signAndSendTransactionMessageWithSigners(transactionMessage);

Dfns

import { createDfnsSigner } from "@solana/keychain-dfns";
const signer = await createDfnsSigner({
authToken: "auth_token",
credId: "cred_id",
privateKeyPem: "-----BEGIN EC PRIVATE KEY-----\n...",
walletId: "wallet_id"
});

Openfort

import { createOpenfortSigner } from "@solana/keychain-openfort";
const signer = await createOpenfortSigner({
secretKey: "sk_...",
walletSecret: "wallet_secret",
accountId: "account_id"
});

Para

import { createParaSigner } from "@solana/keychain-para";
const signer = await createParaSigner({
apiKey: "api_key",
walletId: "wallet_id"
});

Utila

A Utila apenas assina transações; não tem signMessages().

import { createUtilaSigner } from "@solana/keychain-utila";
const signer = await createUtilaSigner({
serviceAccountEmail: "sa@example.com",
serviceAccountPrivateKeyPem: "-----BEGIN PRIVATE KEY-----\n...",
vaultId: "vault_id",
walletId: "wallet_id",
network: "networks/solana-devnet"
});

Fordefi

A Fordefi tem três modos de assinatura, definidos na construção por chain e pushMode. Cada modo expõe exatamente um método de transação, e os três assinam mensagens:

ModoConfiguraçãoTipoMétodo
Black boxchain não definidoFordefiBlackBoxSignersignTransactions()
Nativo automáticochain definido, pushMode omitido ou "auto"FordefiNativeSignersignAndSendTransactions()
Nativo manualchain definido, pushMode: "manual"FordefiNativeManualSignermodifyAndSignTransactions()

Os pedidos à API são autenticados com uma assinatura de pedido ECDSA P-256: forneça a chave de assinatura como privateKeyPem, ou mantenha-a num KMS/HSM passando um requestSigner.

Modo nativo automático (recomendado para uso on-chain): defina chain e a Fordefi assina e faz o broadcast da própria transação. Como a Fordefi pode substituir o blockhash ou as taxas antes de assinar, o signer é um TransactionSendingSigner do Kit: utilize-o com signAndSendTransactionMessageWithSigners, não com o fluxo de partial-signer apresentado acima. O modo nativo automático aceita apenas uma transação não assinada cujo único signatário necessário seja o vault, e não pode ser utilizado com @solana/keychain-kit-plugin.

import { createFordefiSigner } from "@solana/keychain-fordefi";
import { signAndSendTransactionMessageWithSigners } from "@solana/signers";
import { readFileSync } from "node:fs";
const signer = await createFordefiSigner({
accessToken: process.env.FORDEFI_ACCESS_TOKEN!,
vaultId: process.env.FORDEFI_VAULT_ID!,
publicKey: process.env.FORDEFI_PUBLIC_KEY!, // Solana vault address (base58)
privateKeyPem: readFileSync("./secret/private.pem", "utf8"),
chain: "solana_devnet", // or "solana_mainnet"
fee: { type: "custom", priority_fee: "1000" } // optional
});
const signature =
await signAndSendTransactionMessageWithSigners(transactionMessage);

Modo nativo manual: defina chain e pushMode: "manual". A Fordefi reescreve a mensagem (blockhash recente, instruções de taxa do Compute Budget) e assina-a, mas não faz o broadcast. modifyAndSignTransactions() devolve a transação que a Fordefi assinou, a qual substitui a que submeteu: continue sempre a partir da transação devolvida. A Fordefi tem de ser o pagador das taxas e tem de assinar antes de qualquer outro signatário necessário. A reescrita não é comparada com o original, por isso inspecione o resultado antes de fazer o broadcast.

import { createFordefiSigner } from "@solana/keychain-fordefi";
import { readFileSync } from "node:fs";
const signer = await createFordefiSigner({
accessToken: process.env.FORDEFI_ACCESS_TOKEN!,
vaultId: process.env.FORDEFI_VAULT_ID!,
publicKey: process.env.FORDEFI_PUBLIC_KEY!,
privateKeyPem: readFileSync("./secret/private.pem", "utf8"),
chain: "solana_devnet",
pushMode: "manual"
});
const [signedTransaction] = await signer.modifyAndSignTransactions([
transaction
]);

Modo caixa-preta: omita chain. O Fordefi assina bytes brutos e não transmite a transação; você mesmo monta e envia a transação. Use este modo com um cofre caixa-preta do Fordefi.

import { createFordefiSigner } from "@solana/keychain-fordefi";
import { readFileSync } from "node:fs";
const signer = await createFordefiSigner({
accessToken: process.env.FORDEFI_ACCESS_TOKEN!,
vaultId: process.env.FORDEFI_BB_VAULT_ID!,
publicKey: process.env.FORDEFI_BB_PUBLIC_KEY!,
privateKeyPem: readFileSync("./secret/private.pem", "utf8")
});

Capacidades do Signer

@solana/keychain-core define uma interface por cada formato de signer do Kit. Cada uma acrescenta isAvailable(): Promise<boolean> à interface correspondente de @solana/signers:

  • SolanaTransactionSigner (TransactionPartialSigner do Kit): devolve assinaturas para uma transação que lhe pertence.
  • SolanaModifyingSigner (TransactionModifyingSigner do Kit): reescreve a transação, assina-a e devolve a nova transação sem fazer broadcast.
  • SolanaSendingSigner (TransactionSendingSigner do Kit): assina e faz broadcast através do respetivo provedor.
  • SolanaMessageSigner (MessagePartialSigner do Kit): assina mensagens off-chain. É independente dos formatos de transação.

SolanaSigner é a união dos três formatos de transação. O tipo de retorno de cada factory indica o formato exato do respetivo backend. Quando a configuração só é conhecida em tempo de execução, restrinja o tipo com isSolanaTransactionSigner, isSolanaModifyingSigner, isSolanaSendingSigner ou isSolanaMessageSigner. signerCapabilities(signer) indica as quatro capacidades de uma só vez.

BackendFormato
memory, vault, aws-kms, gcp-kms, privy, turnkey, fireblocks, cdp, dfns, para, openfort, fordefi (black box)SolanaTransactionSigner & SolanaMessageSigner
utilaSolanaTransactionSigner (sem assinatura de mensagens)
fordefi (nativo manual)SolanaModifyingSigner & SolanaMessageSigner
fordefi (nativo automático)SolanaSendingSigner & SolanaMessageSigner
crossmintSolanaSendingSigner (sem assinatura de mensagens)
import {
isSolanaSendingSigner,
isSolanaTransactionSigner
} from "@solana/keychain-core";
if (isSolanaSendingSigner(signer)) {
await signer.signAndSendTransactions([transaction]);
} else if (isSolanaTransactionSigner(signer)) {
await signer.signTransactions([transaction]);
}

Criando Signers Personalizados

Implemente as interfaces de capacidades que o seu backend suporta:

import type {
SolanaMessageSigner,
SolanaTransactionSigner
} from "@solana/keychain-core";
import type { Address } from "@solana/addresses";
import type {
MessagePartialSignerConfig,
SignableMessage,
TransactionPartialSignerConfig
} from "@solana/signers";
import type { Transaction } from "@solana/transactions";
class MyCustomSigner implements SolanaTransactionSigner, SolanaMessageSigner {
constructor(readonly address: Address) {}
async isAvailable(): Promise<boolean> {
return await myBackend.healthCheck();
}
async signMessages(
messages: readonly SignableMessage[],
config?: MessagePartialSignerConfig
) {
return await myBackend.signMessages(messages, config?.abortSignal);
}
async signTransactions(
transactions: readonly Transaction[],
config?: TransactionPartialSignerConfig
) {
return await myBackend.signTransactions(transactions, config?.abortSignal);
}
}

Implemente apenas o que o seu backend suporta. O Kit classifica os signers pelos métodos que existem, por isso nunca adicione um método que apenas lança uma exceção.

Consulte o guia de Adição de Signers para integrar serviços adicionais de gerenciamento de chaves.

Is this page helpful?

© 2026 Fundação Solana. Todos os direitos reservados.