Aritmética Segura
Las cantidades de tokens, las tarifas y los cálculos de participación nunca deben desbordarse silenciosamente. En la cadena, utiliza checked_*, saturating_* o comprobaciones explícitas de límites y mapea los fallos a ProgramError.
Receta
let total = base
.checked_add(fee)
.ok_or(ProgramError::InvalidArgument)?;Cuándo usar esto:
- Al agregar saldos, participaciones o índices de recompensas.
- Al calcular tarifas como un porcentaje de lamports o unidades de token.
- Al implementar contabilidad de bóvedas o distribuciones prorrateadas.
Ejemplo Funcional
use solana_program::program_error::ProgramError;
pub fn apply_fee(amount: u64, bps: u64) -> Result<u64, ProgramError> {
if bps > 10_000 {
return Err(ProgramError::InvalidArgument);
}
let fee = amount
.checked_mul(bps)
.and_then(|v| v.checked_div(10_000))
.ok_or(ProgramError::InvalidArgument)?;
amount
.checked_sub(fee)
.ok_or(ProgramError::InvalidArgument)
}Lo que esto demuestra:
- La tarifa en puntos base utiliza multiplicación/división verificada en dos pasos.
- Comprobación de límites de
bpsantes de las operaciones matemáticas. - Los errores se presentan como
InvalidArgumentpara la decodificación del cliente.
Análisis Profundo
Elección de API
| Método | Comportamiento |
|---|---|
checked_add | None en caso de desbordamiento |
saturating_add | Se limita a MAX |
wrapping_add | Raro en la cadena - señal de alerta de auditoría |
Patrones Financieros
- Utiliza intermedios
u128para multiplicación/división cuando el producto excedeu64. - Documenta el redondeo (hacia abajo vs. hacia arriba) para las divisiones de tarifas.
Notas de Rust
let wide = (a as u128).checked_mul(b as u128)?;Trampas
- Operaciones sin verificar -
a + bse desborda en producción sin comprobaciones de desbordamiento en algunos contextos. Solución: Siempre usachecked_*para fondos de usuario. - Uso incorrecto de saturación -
saturating_subpuede ocultar la insolvencia. Solución: Usachecked_subcuando el saldo no debe ser menor que cero. - División por cero - Rust entra en pánico con
/ 0incluso en la cadena. Solución: Protege el divisor explícitamente. - Truncamiento de conversión -
as u64desdeu128trunca silenciosamente. Solución: Comprueba los límites detry_into. - Confusión con signo - Las cantidades de tokens no tienen signo; evita
i64a menos que sea necesario. Solución: indefinido
Alternativas
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
spl-math / crates de punto fijo | Matemáticas de curva DEX | Contadores simples |
u128 en todas partes | Precisión intermedia | Bucles ajustados sensibles a CU |
| Precomputación fuera de la cadena | Valores solo para visualización | Saldos autorizados |
Preguntas Frecuentes
¿Rust verifica el desbordamiento en SBF?
No confíes en ello; utiliza matemáticas verificadas explícitas.
¿Cuándo está bien la saturación?
Límites en estadísticas de juego, no en saldos de tokens.
¿Patrón de puntos base?
Multiplicar y luego dividir por 10000 con operaciones verificadas.
¿Costo de CU de u128?
Ligeramente mayor; aún más barato que los exploits.
¿Ayudantes de Anchor?
Usa checked de Rust std en manejadores de instrucciones.
¿Comparar antes de restar?
Aún usa checked_sub después de la comparación para seguridad contra condiciones de carrera.
¿Matemáticas de punto flotante?
Evita f64 para cantidades de tokens; ataques de redondeo.
¿Módulo para fragmentos?
Comprueba que el divisor no sea cero.
¿Herramientas de auditoría?
Busca +, -, * en u64 en rutas de instrucciones.
¿Negación?
No hay cantidades de tokens negativas; rechaza entradas con signo.
¿Sumas por lotes?
Fold verificado: patrón try_fold.
¿Probar el desbordamiento?
Prueba unitaria los casos límite de u64::MAX en el host.
Relacionado
- Patrones de Tarifas y Tesorería - Recolección de tarifas
- Bóveda y Depósito en Garantía - Seguimiento de saldos
- Mejores Prácticas de Rust para Solana - Hábitos de seguridad
Versiones de Stack: Esta página fue escrita para Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0, y LiteSVM 0.6.x.