This document describes the implementation of Soroban contract parsing and analysis capabilities in GasGuard.
GasGuard now supports comprehensive static analysis of Soroban smart contracts built on the Stellar network. The implementation includes:
- AST-based parsing of Soroban-specific macros (
#[contract],#[contractimpl],#[contracttype]) - Rule-based analysis for gas optimization and security issues
- Integration with existing GasGuard infrastructure
Core data structures representing Soroban contract elements:
pub struct SorobanContract {
pub name: String,
pub contract_types: Vec<SorobanStruct>,
pub implementations: Vec<SorobanImpl>,
pub source: String,
pub file_path: String,
}
pub struct SorobanStruct {
pub name: String,
pub fields: Vec<SorobanField>,
pub line_number: usize,
pub raw_definition: String,
}
pub struct SorobanImpl {
pub target: String,
pub functions: Vec<SorobanFunction>,
pub line_number: usize,
pub raw_definition: String,
}The parser extracts AST-like structures from Soroban contract source code:
pub struct SorobanParser;
impl SorobanParser {
pub fn parse_contract(source: &str, file_path: &str) -> SorobanResult<SorobanContract> {
// Implementation details...
}
}Key parsing capabilities:
- Extract contract names from
#[contract]attributes - Parse
#[contracttype]struct definitions - Parse
#[contractimpl]implementation blocks - Extract function signatures and parameters
- Handle visibility modifiers and return types
Performs static analysis on parsed Soroban contracts:
pub struct SorobanAnalyzer;
impl SorobanAnalyzer {
pub fn analyze_contract(contract: &SorobanContract) -> Vec<RuleViolation> {
// Implementation details...
}
}Analysis capabilities include:
- Unused state variable detection
- Inefficient storage access patterns
- Unbounded loop detection
- Expensive string operation identification
- Missing error handling detection
- Inefficient integer type usage
Specialized rule engine for Soroban contracts:
pub struct SorobanRuleEngine {
rules: HashMap<String, Box<dyn SorobanRule>>,
}
pub trait SorobanRule {
fn id(&self) -> &str;
fn name(&self) -> &str;
fn description(&self) -> &str;
fn severity(&self) -> ViolationSeverity;
fn apply(&self, contract: &SorobanContract) -> Vec<RuleViolation>;
}Built-in rules:
UnusedStateVariablesRule- Detects unused contract stateInefficientStorageAccessRule- Identifies repeated storage operationsUnboundedLoopRule- Flags potentially infinite loopsExpensiveStringOperationsRule- Detects costly string operationsMissingConstructorRule- Ensures proper contract initializationAdminPatternRule- Suggests access control patternsInefficientIntegerTypesRule- Recommends optimal integer sizesMissingErrorHandlingRule- Enforces proper error handling
Extended to support Soroban contract detection and analysis:
pub enum Language {
Rust,
Vyper,
Soroban, // Added support
}
impl Language {
pub fn from_content(content: &str) -> Option<Self> {
// Detect Soroban contracts by looking for soroban_sdk imports
// and Soroban-specific macros
}
}Updated to recognize 'soroban' as a supported language:
private static readonly SUPPORTED_LANGUAGES = ['rust', 'typescript', 'javascript', 'solidity', 'soroban'];Extended to handle Soroban contract patterns specifically:
supportsLanguage(language: Language | string): boolean {
return language === Language.RUST ||
language === Language.SOROBAN ||
language === 'rust' ||
language === 'rs' ||
language === 'soroban';
}use gasguard_rules::{SorobanParser, SorobanAnalyzer};
let contract_code = r#"
use soroban_sdk::{contract, contractimpl, contracttype, Address, Env};
#[contracttype]
pub struct TokenContract {
pub admin: Address,
pub total_supply: u64,
pub balances: Map<Address, u64>,
}
#[contractimpl]
impl TokenContract {
pub fn new(admin: Address, initial_supply: u64) -> Self {
// Implementation
}
pub fn transfer(from: Address, to: Address, amount: u64) {
// Implementation
}
}
"#;
// Parse the contract
let contract = SorobanParser::parse_contract(contract_code, "token.rs")?;
// Analyze for issues
let violations = SorobanAnalyzer::analyze_contract(&contract);
for violation in violations {
println!("Issue: {} at line {}", violation.description, violation.line_number);
}use gasguard_rules::SorobanRuleEngine;
let engine = SorobanRuleEngine::with_default_rules();
let violations = engine.analyze(contract_code, "contract.rs")?;
println!("Found {} issues", violations.len());use gasguard_engine::ContractScanner;
let scanner = ContractScanner::new();
// Automatic language detection
let result = scanner.scan_content(contract_code, "my_contract.rs".to_string())?;
// Or direct Soroban analysis
let soroban_result = scanner.scan_soroban_content(contract_code, "my_contract.rs".to_string())?;The Soroban analyzer detects various issues with specific recommendations:
Detection: Variables declared in contract structs but never referenced in functions Recommendation: Remove unused variables to save ledger storage costs
Detection: Multiple reads/writes to the same storage key without caching Recommendation: Cache storage values in local variables
Detection: Loops without clear termination conditions Recommendation: Add bounds checking or use pagination patterns
Detection: Frequent .to_string() or String::from() calls
Recommendation: Use Symbol or Bytes for fixed data when possible
Detection: State-modifying functions that don't return Result
Recommendation: Return Result<(), Error> for proper error propagation
Detection: Use of u128/i128 when smaller types would suffice
Recommendation: Use appropriate integer sizes (u64, u32, etc.)
Comprehensive tests are included in:
tests/integration_tests.rs- End-to-end integration testspackages/rules/src/soroban/tests.rs- Unit tests for parsing and analysis
Run tests with:
cargo testThe TypeScript API now accepts 'soroban' as a language parameter:
const response = await fetch('/api/analyze', {
method: 'POST',
body: JSON.stringify({
code: sorobanContractCode,
filePath: 'contract.rs',
language: 'soroban'
})
});Planned improvements:
- More sophisticated AST parsing using
syncrate - Cross-function analysis for better unused variable detection
- Integration with Soroban SDK documentation
- Performance optimization rules specific to Stellar's fee model
- Custom rule configuration for different project requirements
To add new Soroban-specific rules:
- Implement a struct that implements the
SorobanRuletrait - Add it to the
SorobanRuleEngine::add_default_rules()method - Include comprehensive tests
- Update documentation
The modular design makes it easy to extend with new analysis capabilities while maintaining compatibility with the existing GasGuard ecosystem.