Descripción General de la Arquitectura
Kora utiliza el crate externo
solana-keychain para
todas las operaciones de firma. Esta arquitectura proporciona una interfaz de
firma unificada para firmar transacciones de Solana. Para agregar un nuevo
firmante a Kora, necesitarás:
- Primero: Agregar tu implementación de firmante al crate
solana-keychain - Segundo: Agregar soporte de configuración para tu firmante en Kora
Guía de Integración Paso a Paso
Lista de Verificación Rápida de Integración
Parte 1: Agregar Firmante al Crate solana-keychain
- Implementar tu firmante siguiendo la guía de integración de solana-keychain
- Esperar la aprobación del PR y la publicación del crate
Parte 2: Agregar Soporte de Configuración en Kora
- Actualizar la dependencia en Cargo.toml para que el crate
solana-keychainuse la versión más reciente (que incluye tu firmante) - Agregar estructura de configuración para las variables de entorno de tu firmante
- Actualizar el enum
SignerTypeConfigencrates/lib/src/signer/config.rs - Agregar lógica de validación para la configuración de tu firmante
- Agregar lógica de construcción para crear tu firmante a partir de la configuración
- Exportar la estructura de configuración en
crates/lib/src/signer/mod.rs - (Opcional) Agregar constructor de mock de prueba en
crates/lib/src/tests/config_mock.rs - Actualizar los archivos de configuración de ejemplo
- Actualizar los scripts de prueba para incluir tu firmante (ver abajo)
- Actualizar la documentación para incluir tu firmante (ver abajo)
- Enviar PR al repositorio de Kora
Añadir Soporte de Firmante en Kora
Primero, asegúrate de que tu firmante esté soportado en el crate
solana-keychain. Si no lo está, sigue la guía en:
https://github.com/solana-foundation/solana-keychain/blob/main/docs/ADDING_SIGNERS.md
Paso 1: Actualizar Cargo.toml
Actualiza la dependencia en Cargo.toml para que el crate solana-keychain use
la versión más reciente (que incluya tu firmante):
[dependencies]solana-keychain = { version = "X.Y.Z", default-features = false, features = ["all","sdk-v3",] }
Paso 2: Definir Tu Struct de Configuración
En crates/lib/src/signer/config.rs, añade un nuevo struct de configuración
para tu firmante que defina qué variables de entorno se necesitan. Por ejemplo:
/// 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,}
Paso 2: Añadir Tu Firmante al Enum SignerTypeConfig
Añade la variante de tu firmante al enum SignerTypeConfig en
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 variantsMemory { #[serde(flatten)] config: MemorySignerConfig },// ... existing variants ...// Add your signer hereYourService {#[serde(flatten)]config: YourServiceSignerConfig,},}
Paso 3: Añadir Lógica de Construcción
En el mismo archivo (config.rs), añade un método para construir tu firmante
desde la configuración en la implementación de SignerConfig:
impl SignerConfig {pub async fn build_signer_from_config(config: &SignerConfig) -> Result<Signer, KoraError> {match &config.config {// ... existing casesSignerTypeConfig::YourService { config: your_service_config } => {Self::build_your_service_signer(your_service_config, &config.name).await}}}// Add this new methodasync fn build_your_service_signer(config: &YourServiceSignerConfig,signer_name: &str,) -> Result<Signer, KoraError> {// Update the environment variable names to match your signer's configurationlet 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 crateSigner::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: El nombre del método Signer::from_your_service() debe coincidir con
lo que implementaste en el crate solana-keychain.
Paso 4: Añadir Lógica de Validación
Añade la validación para la configuración de tu firmante en el método
validate_individual_signer_config:
impl SignerConfig {pub fn validate_individual_signer_config(&self, index: usize) -> Result<(), KoraError> {// ... existing validationmatch &self.config {// ... existing casesSignerTypeConfig::YourService { config } => {Self::validate_your_service_config(config, &self.name)}}}// Add this new validation methodfn validate_your_service_config(config: &YourServiceSignerConfig,signer_name: &str,) -> Result<(), KoraError> {// Update the environment variable names to match your signer's configurationlet 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(())}}
Paso 5: Exportar Tu Configuración
Añade tu nuevo struct de configuración a las exportaciones del módulo en
crates/lib/src/signer/mod.rs (o en la parte superior del archivo si es
público):
pub use config::{MemorySignerConfig,PrivySignerConfig,SignerTypeConfig,TurnkeySignerConfig,VaultSignerConfig,YourServiceSignerConfig, // Add this// ... other exports};
Probar Tu Integración
Añadir Constructor Mock de Prueba
Para facilitar las pruebas, añade un método constructor a
SignerPoolConfigBuilder en crates/lib/src/tests/config_mock.rs:
impl SignerPoolConfigBuilder {// ... existing methodspub 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}}
Esto permite que otras pruebas creen fácilmente configuraciones simuladas que incluyan tu firmante:
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();
Variables de Entorno
Añade las variables de entorno de ejemplo a los siguientes archivos:
.env.example(raíz del proyecto).env(raíz del proyecto, para pruebas locales)./sdks/ts/.env.example./sdks/ts/.env
# YourService Signer ConfigurationYOUR_SERVICE_API_KEY=your_api_key_hereYOUR_SERVICE_API_SECRET=your_api_secret_hereYOUR_SERVICE_WALLET_ID=your_wallet_id_here
Pruebas de Integración
Cada fase de integración es su propio target [[test]] en tests/Cargo.toml. Cada
target inicia un surfnet embebido y un nodo de Kora mediante harness_context,
partiendo desde cero. Kora mantiene la configuración en un estado global del proceso, por lo que un nuevo firmante
necesita un nuevo target en lugar de un nuevo módulo dentro de uno existente.
1. Añadir un fixture de firmante
Crea una configuración de firmante en 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. Añadir un target de pruebas
Registra la fase en tests/Cargo.toml:
[[test]]name = "your_service"path = "your_service/main.rs"
Luego crea tests/your_service/main.rs. Este archivo apunta el harness a tu fixture
y debe contener al menos un #[tokio::test] que ejercite el firmante:
#[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());}
Añade también una prueba de signTransaction para que se ejecute la ruta de firma del firmante, y no solo
la búsqueda de claves. tests/multi_signer/ es un ejemplo completo del que puedes partir.
3. Ejecutar Pruebas
just installexport YOUR_SERVICE_API_KEY="your_key"export YOUR_SERVICE_API_SECRET="your_secret"export YOUR_SERVICE_WALLET_ID="your_wallet"# Run only your phasecargo test -p tests --test your_service# Run every integration phasejust integration-test
Requisitos de Documentación
Al enviar tu PR, incluye:
1. Actualizar la Guía de Firmantes
Añade documentación del firmante siguiendo la guía
ADDING_SIGNERS.md,
explicando los requisitos previos, la configuración y el uso.
## YourService Signer[YourService](https://yourservice.com) provides [brief description of yourservice].### Prerequisites- YourService account- API credentials- Funded wallet### Setup1. 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. Actualizar el README
Añade tu servicio a la lista de firmantes del README principal.
Lista de verificación para la entrega
- Tu firmante está soportado en el crate
solana-keychain - Dependencia
solana-keychainactualizada en Cargo.toml a la última versión - Añadida la estructura de configuración para tu firmante
- Añadida la variante
SignerTypeConfig - Añadida la lógica de compilación en
build_signer_from_config - Añadida la lógica de validación en
validate_individual_signer_config - Estructura de configuración exportada en
mod.rs - (Opcional) Añadido el método constructor de mock de prueba en
config_mock.rs - El código compila sin advertencias
- Todas las pruebas pasan (
just test) - Documentación añadida siguiendo
ADDING_SIGNERS.md - Archivos de configuración de ejemplo creados (
.tomle.env.example) - Sin valores codificados de forma fija ni secretos
- Los mensajes de error son útiles
- Sigue las convenciones de nomenclatura de Rust (snake_case)
- El linting pasa (
make lint) - Contacta al equipo de Kora con las claves de API para las pruebas de integración
Obtener ayuda
- Para la implementación del firmante: Abre un issue en el repositorio
solana-keychain - Para la integración con Kora: Abre un issue en el repositorio de Kora para discusiones de diseño
- Únete a nuestros canales de la comunidad
- Revisa las configuraciones de firmantes existentes en
crates/lib/src/signer/config.rs
Estructura de PR de ejemplo
Para el repositorio de 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
¡Bienvenido al ecosistema de Kora! Nos entusiasma contar con tu solución de gestión de claves como parte de la plataforma.
Is this page helpful?