Aritmética Segura
Valores de token, taxas e cálculos de participação nunca devem fazer wrap silenciosamente. On-chain, use checked_*, saturating_* ou checagens explícitas de limites e mapeie falhas para ProgramError.
Receita
let total = base
.checked_add(fee)
.ok_or(ProgramError::InvalidArgument)?;Quando usar:
- Agregar saldos, participações ou índices de recompensa.
- Calcular taxas como percentual de lamports ou unidades de token.
- Implementar contabilidade de vault ou distribuições pro-rata.
Exemplo 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)
}O que isso demonstra:
- Taxa em basis points usa mul/div verificados em dois passos.
- Checagem de limite
bpsantes da math. - Erros aparecem como
InvalidArgumentpara decodificação do cliente.
Aprofundamento
Escolha de API
| Método | Comportamento |
|---|---|
checked_add | None em overflow |
saturating_add | Limita em MAX |
wrapping_add | Raro on-chain - red flag de auditoria |
Padrões Financeiros
- Use intermediários u128 para mul-div quando produto excede u64.
- Documente arredondamento (floor vs ceil) para divisões de taxa.
Notas Rust
let wide = (a as u128).checked_mul(b as u128)?;Armadilhas
- Ops sem verificação -
a + bfaz wrap em release sem overflow checks em alguns contextos. Correção: Semprechecked_*para fundos de usuário. - Uso incorreto de saturating -
saturating_subpode esconder insolvência. Correção: Usechecked_subquando saldo não pode underflow. - Divisão por zero - Rust faz panic em
/ 0mesmo on-chain. Correção: Guarde divisor explicitamente. - Truncamento de cast -
as u64de u128 trunca silenciosamente. Correção: Cheque limites comtry_into. - Confusão com signed - Valores de token são unsigned - evite
i64a menos que necessário. Correção: indefinido
Alternativas
| Alternativa | Use quando | Não use quando |
|---|---|---|
| spl-math / crates fixed-point | Math de curva DEX | Contadores simples |
| u128 em todo lugar | Precisão intermediária | Loops apertados sensíveis a CU |
| Pré-compute off-chain | Valores só de display | Saldos autoritativos |
FAQs
Rust verifica overflow em SBF?
Não confie nisso - use math verificada explícita.
Quando saturating é OK?
Caps em stats de gameplay, não saldos de token.
Padrão basis points?
mul depois div 10000 com ops verificados.
Custo de CU u128?
Ligeiramente maior - ainda mais barato que exploits.
Helpers Anchor?
Use checked std Rust nos handlers de instrução.
Comparar antes de subtrair?
Ainda use checked_sub após compare por segurança de race.
Math com float?
Evite f64 para valores de token - ataques de arredondamento.
Módulo para shards?
Verifique divisor não zero.
Ferramentas de auditoria?
Busque +, -, * em u64 em caminhos de instrução.
Negação?
Sem valores negativos de token - rejeite inputs signed.
Somas em batch?
Fold verificado: padrão try_fold.
Testar overflow?
Teste unitário edge cases u64::MAX no host.
Relacionado
- Fee & Treasury Patterns - Coleta de taxas
- Vault & Escrow - Rastreamento de saldo
- Rust for Solana Best Practices - Hábitos de segurança
Versões da stack: Esta página foi 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 e LiteSVM 0.6.x.