Adicionando Novos Signatários ao Kora

Visão Geral da Arquitetura

O Kora utiliza o crate externo solana-keychain para todas as operações de assinatura. Esta arquitetura fornece uma interface de assinatura unificada para assinar transações Solana. Para adicionar um novo signatário ao Kora, você precisará:

  1. Primeiro: Adicionar a implementação do seu signatário ao crate solana-keychain
  2. Segundo: Adicionar suporte de configuração para seu signatário no Kora

Guia de Integração Passo a Passo

Lista de Verificação Rápida de Integração

Parte 1: Adicionar Signatário ao Crate solana-keychain

Parte 2: Adicionar Suporte de Configuração no Kora

  • Atualize a dependência no Cargo.toml para que o crate solana-keychain use a versão mais recente (que inclui seu signatário)
  • Adicione uma struct de configuração para as variáveis de ambiente do seu signatário
  • Atualize o enum SignerTypeConfig em crates/lib/src/signer/config.rs
  • Adicione lógica de validação para a configuração do seu signatário
  • Adicione lógica de construção para criar seu signatário a partir da configuração
  • Exporte a struct de configuração em crates/lib/src/signer/mod.rs
  • (Opcional) Adicione um construtor mock de teste em crates/lib/src/tests/config_mock.rs
  • Atualize os arquivos de configuração de exemplo
  • Atualize os scripts de teste para incluir seu signatário (veja abaixo)
  • Atualize a documentação para incluir seu signatário (veja abaixo)
  • Envie o PR para o repositório do Kora

Adicionar Suporte de Assinante no Kora

Primeiro, certifique-se de que seu assinante é suportado no crate solana-keychain. Caso não seja, siga o guia em: https://github.com/solana-foundation/solana-keychain/blob/main/docs/ADDING_SIGNERS.md

Passo 1: Atualizar o Cargo.toml

Atualize a dependência do Cargo.toml para que o crate solana-keychain use a versão mais recente (que inclui seu assinante):

[dependencies]
solana-keychain = { version = "X.Y.Z", default-features = false, features = [
"all",
"sdk-v3",
] }

Passo 2: Definir Sua Estrutura de Configuração

Em crates/lib/src/signer/config.rs, adicione uma nova estrutura de configuração para seu assinante que define quais variáveis de ambiente são necessárias. Por exemplo:

/// YourService signer configuration
#[derive(Clone, Serialize, Deserialize)]
pub struct YourServiceSignerConfig {
pub api_key_env: String,
pub api_secret_env: String,
pub wallet_id_env: String,
}

Passo 2: Adicionar Seu Assinante ao Enum SignerTypeConfig

Adicione a variante do seu assinante ao enum SignerTypeConfig em crates/lib/src/signer/config.rs:

/// Signer type-specific configuration
#[derive(Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum SignerTypeConfig {
// Existing signer variants
Memory { #[serde(flatten)] config: MemorySignerConfig },
// ... existing variants ...
// Add your signer here
YourService {
#[serde(flatten)]
config: YourServiceSignerConfig,
},
}

Passo 3: Adicionar Lógica de Construção

No mesmo arquivo (config.rs), adicione um método para construir seu assinante a partir da configuração na implementação de SignerConfig:

impl SignerConfig {
pub async fn build_signer_from_config(config: &SignerConfig) -> Result<Signer, KoraError> {
match &config.config {
// ... existing cases
SignerTypeConfig::YourService { config: your_service_config } => {
Self::build_your_service_signer(your_service_config, &config.name).await
}
}
}
// Add this new method
async fn build_your_service_signer(
config: &YourServiceSignerConfig,
signer_name: &str,
) -> Result<Signer, KoraError> {
// Update the environment variable names to match your signer's configuration
let api_key = get_env_var_for_signer(&config.api_key_env, signer_name)?;
let api_secret = get_env_var_for_signer(&config.api_secret_env, signer_name)?;
let wallet_id = get_env_var_for_signer(&config.wallet_id_env, signer_name)?;
// Call the constructor from solana-keychain crate
Signer::from_your_service(api_key, api_secret, wallet_id)
.await
.map_err(|e| {
KoraError::SigningError(format!(
"Failed to create YourService signer '{signer_name}': {}",
sanitize_error!(e)
))
})
}
}

Nota: O nome do método Signer::from_your_service() deve corresponder ao que você implementou no crate solana-keychain.

Passo 4: Adicionar Lógica de Validação

Adicione validação para a configuração do seu assinante no método validate_individual_signer_config:

impl SignerConfig {
pub fn validate_individual_signer_config(&self, index: usize) -> Result<(), KoraError> {
// ... existing validation
match &self.config {
// ... existing cases
SignerTypeConfig::YourService { config } => {
Self::validate_your_service_config(config, &self.name)
}
}
}
// Add this new validation method
fn validate_your_service_config(
config: &YourServiceSignerConfig,
signer_name: &str,
) -> Result<(), KoraError> {
// Update the environment variable names to match your signer's configuration
let env_vars = [
("api_key_env", &config.api_key_env),
("api_secret_env", &config.api_secret_env),
("wallet_id_env", &config.wallet_id_env),
];
for (field_name, env_var) in env_vars {
if env_var.is_empty() {
return Err(KoraError::ValidationError(format!(
"YourService signer '{signer_name}' must specify non-empty {field_name}"
)));
}
}
Ok(())
}
}

Passo 5: Exportar Sua Configuração

Adicione sua nova estrutura de configuração às exportações do módulo em crates/lib/src/signer/mod.rs (ou no topo do arquivo se for pública):

pub use config::{
MemorySignerConfig,
PrivySignerConfig,
SignerTypeConfig,
TurnkeySignerConfig,
VaultSignerConfig,
YourServiceSignerConfig, // Add this
// ... other exports
};

Testando Sua Integração

Adicionar Construtor de Mock de Teste

Para facilitar os testes, adicione um método construtor a SignerPoolConfigBuilder em crates/lib/src/tests/config_mock.rs:

impl SignerPoolConfigBuilder {
// ... existing methods
pub fn with_your_service_signer(
mut self,
name: String,
api_key_env: String,
api_secret_env: String,
wallet_id_env: String,
weight: Option<u32>,
) -> Self {
let signer = SignerConfig {
name,
weight,
config: SignerTypeConfig::YourService {
config: YourServiceSignerConfig {
api_key_env,
api_secret_env,
wallet_id_env,
},
},
};
self.config.signers.push(signer);
self
}
}

Isso permite que outros testes criem facilmente configurações simuladas que incluam o seu assinante:

use crate::tests::config_mock::SignerPoolConfigBuilder;
let config = SignerPoolConfigBuilder::new()
.with_your_service_signer(
"yourservice_test".to_string(),
"YOUR_SERVICE_API_KEY".to_string(),
"YOUR_SERVICE_API_SECRET".to_string(),
"YOUR_SERVICE_WALLET_ID".to_string(),
Some(1)
)
.build();

Variáveis de Ambiente

Adicione as variáveis de ambiente de exemplo aos seguintes ficheiros:

  • .env.example (raiz do projeto)
  • .env (raiz do projeto, para testes locais)
  • ./sdks/ts/.env.example
  • ./sdks/ts/.env
# YourService Signer Configuration
YOUR_SERVICE_API_KEY=your_api_key_here
YOUR_SERVICE_API_SECRET=your_api_secret_here
YOUR_SERVICE_WALLET_ID=your_wallet_id_here

Testes de Integração

Cada fase de integração é o seu próprio alvo [[test]] em tests/Cargo.toml. Cada alvo inicia uma surfnet incorporada e um nó Kora através de harness_context, inicializados do zero. O Kora mantém a configuração num estado global do processo, pelo que um novo assinante precisa de um novo alvo em vez de um novo módulo num já existente.

1. Adicionar um Fixture de Assinante

Crie uma configuração de assinante em tests/src/common/fixtures/:

# tests/src/common/fixtures/signers-your-service.toml
[signer_pool]
strategy = "round_robin"
[[signers]]
name = "yourservice_main"
type = "your_service"
api_key_env = "YOUR_SERVICE_API_KEY"
api_secret_env = "YOUR_SERVICE_API_SECRET"
wallet_id_env = "YOUR_SERVICE_WALLET_ID"

2. Adicionar um Alvo de Teste

Registe a fase em tests/Cargo.toml:

[[test]]
name = "your_service"
path = "your_service/main.rs"

Depois, crie tests/your_service/main.rs. Este ficheiro aponta o harness para o seu fixture e tem de conter pelo menos um #[tokio::test] que teste o assinante:

#[path = "../src/common/mod.rs"]
mod common;
use common::*;
use jsonrpsee::rpc_params;
pub async fn ctx() -> TestContext {
harness_context(KoraSpec {
config: "tests/src/common/fixtures/kora-test.toml",
signers: "tests/src/common/fixtures/signers-your-service.toml",
initialize_payments_atas: false,
})
.await
}
#[tokio::test]
async fn test_your_service_signs_as_fee_payer() {
let ctx = ctx().await;
let response: serde_json::Value = ctx
.rpc_call("getPayerSigner", rpc_params![])
.await
.expect("Failed to get payer signer");
response.assert_success();
assert!(response["signer_address"].as_str().is_some());
}

Adicione também um teste signTransaction para que o fluxo de assinatura do assinante seja executado, e não apenas a procura de chaves. tests/multi_signer/ é um exemplo completo a partir do qual pode copiar.

3. Executar Testes

just install
export YOUR_SERVICE_API_KEY="your_key"
export YOUR_SERVICE_API_SECRET="your_secret"
export YOUR_SERVICE_WALLET_ID="your_wallet"
# Run only your phase
cargo test -p tests --test your_service
# Run every integration phase
just integration-test

Requisitos de Documentação

Ao submeter o seu PR, inclua:

1. Atualizar o Guia de Assinantes

Adicione documentação do assinante seguindo o guia ADDING_SIGNERS.md, explicando os pré-requisitos, configuração e utilização.

## YourService Signer
[YourService](https://yourservice.com) provides [brief description of your
service].
### Prerequisites
- YourService account
- API credentials
- Funded wallet
### Setup
1. Get your API credentials from [dashboard link]
2. Create a wallet...
3. Configure environment variables:
\```bash YOUR_SERVICE_API_KEY="your_api_key"
YOUR_SERVICE_API_SECRET="your_api_secret"
YOUR_SERVICE_WALLET_ID="your_wallet_id" \```
### Configure signers.toml
\```toml [signer_pool] strategy = "round_robin"
[[signers]] name = "yourservice_main" type = "your_service" api_key_env =
"YOUR_SERVICE_API_KEY" api_secret_env = "YOUR_SERVICE_API_SECRET" wallet_id_env
= "YOUR_SERVICE_WALLET_ID" weight = 1 \```
### Run Kora with YourService Signer
\```bash kora rpc start --signers-config signers.toml \```

2. Atualizar o README

Adicione o seu serviço à lista de signatários do README principal.

Lista de Verificação para Submissão

  • O seu signatário é suportado no crate solana-keychain
  • Dependência solana-keychain atualizada no Cargo.toml para a versão mais recente
  • Adicionada a struct de configuração para o seu signatário
  • Adicionada a variante SignerTypeConfig
  • Adicionada lógica de build em build_signer_from_config
  • Adicionada lógica de validação em validate_individual_signer_config
  • Struct de configuração exportada em mod.rs
  • (Opcional) Adicionado método mock builder de teste em config_mock.rs
  • Código compila sem avisos
  • Todos os testes passam (just test)
  • Documentação adicionada seguindo ADDING_SIGNERS.md
  • Ficheiros de configuração de exemplo criados (.toml e .env.example)
  • Sem valores ou segredos codificados
  • Mensagens de erro são úteis
  • Segue as convenções de nomenclatura Rust (snake_case)
  • Linting passa (make lint)
  • Contacte a equipa Kora com as Chaves de API para testes de integração

Obter Ajuda

  • Para implementação de signatários: Abra uma issue no repositório solana-keychain
  • Para integração com o Kora: Abra uma issue no repositório Kora para discussões de design
  • Junte-se aos nossos canais de comunidade
  • Reveja as configurações de signatários existentes em crates/lib/src/signer/config.rs

Exemplo de Estrutura de PR

Para o repositório Kora:

feat(signer): add YourService signer configuration support
- Add YourServiceSignerConfig struct
- Add YourService variant to SignerTypeConfig enum
- Add build and validation logic for YourService
- Add example configuration files
- Add documentation to SIGNERS.md
- Add integration tests

Bem-vindo ao ecossistema Kora! Estamos entusiasmados por ter a sua solução de gestão de chaves como parte da plataforma.

Is this page helpful?

© 2026 Fundação Solana. Todos os direitos reservados.
Adicionando Novos Signatários ao Kora | Solana