Skip to content

Security: AugustMoreau/augustium

Security

docs/SECURITY.md

Security Best Practices

Essential security guidelines for Augustium smart contract development.

Table of Contents

Overview

Augustium is designed with security as a priority, providing built-in protections against common smart contract vulnerabilities. However, developers still need to follow best practices to ensure their contracts are secure.

Built-in Safety Features

Automatic Overflow Protection

// Augustium automatically checks for overflows
let result = a + b;  // Throws error on overflow

// Manual overflow checking also available
let result = a.checked_add(b).require("Addition overflow")?;

Reentrancy Protection

// Augustium prevents reentrancy by default
contract MyContract {
    #[nonreentrant]
    pub fn withdraw(amount: u256) {
        require(balances[msg.sender] >= amount);
        balances[msg.sender] -= amount;
        
        // External call is safe - reentrancy is prevented
        msg.sender.call{value: amount}("");
    }
}

Memory Safety

// No null pointer dereferences
let maybe_value: Option<u256> = get_value();
match maybe_value {
    Some(value) => use_value(value),
    None => handle_empty(),
}

// Bounds checking on arrays
let item = array[index];  // Automatically checks bounds

Gas Limit Protection

// Automatic gas limit checks prevent infinite loops
for i in 0..user_input {
    // Gas is tracked and execution stops if limit reached
    expensive_operation();
}

Common Vulnerabilities

1. Integer Overflow/Underflow

❌ Vulnerable (in other languages):

// This could overflow in Solidity
uint256 result = a + b;

✅ Safe in Augustium:

// Augustium automatically prevents overflow
let result = a + b;  // Safe - will revert on overflow

// Or use explicit safe math
use std::math::SafeMath;
let result = SafeMath::safe_add(a, b)?;

2. Reentrancy Attacks

❌ Vulnerable pattern:

// Don't do this - update state after external calls
pub fn withdraw(amount: u256) {
    require(balances[msg.sender] >= amount);
    
    // External call before state update - dangerous!
    msg.sender.call{value: amount}("");
    
    balances[msg.sender] -= amount;  // Too late!
}

✅ Secure pattern:

// Augustium's built-in protection + best practices
#[nonreentrant]
pub fn withdraw(amount: u256) {
    require(balances[msg.sender] >= amount);
    
    // Update state FIRST
    balances[msg.sender] -= amount;
    
    // Then make external call
    msg.sender.call{value: amount}("");
}

3. Access Control Issues

❌ Missing access control:

pub fn admin_function() {
    // Anyone can call this!
    self_destruct();
}

✅ Proper access control:

use std::access::Ownable;

contract MyContract extends Ownable {
    #[only_owner]
    pub fn admin_function() {
        // Only owner can call this
        self_destruct();
    }
    
    // Or custom modifiers
    modifier only_admin() {
        require(admins[msg.sender], "Not an admin");
        _;
    }
    
    #[only_admin]
    pub fn sensitive_function() {
        // Protected function
    }
}

4. Unchecked External Calls

❌ Not checking return values:

// Ignoring return value is dangerous
token.transfer(recipient, amount);

✅ Always check returns:

// Check the return value
let success = token.transfer(recipient, amount);
require(success, "Transfer failed");

// Or use ? operator for automatic error handling
token.transfer(recipient, amount)?;

Secure Coding Patterns

1. Checks-Effects-Interactions

pub fn withdraw(amount: u256) {
    // CHECKS: Validate inputs and conditions
    require(amount > 0, "Amount must be positive");
    require(balances[msg.sender] >= amount, "Insufficient balance");
    require(!paused, "Contract is paused");
    
    // EFFECTS: Update contract state
    balances[msg.sender] -= amount;
    total_supply -= amount;
    
    // INTERACTIONS: External calls last
    msg.sender.call{value: amount}("");
    
    emit Withdrawal(msg.sender, amount);
}

2. Pull Over Push Pattern

❌ Push pattern (can fail):

pub fn distribute_rewards(recipients: Vec<address>, amounts: Vec<u256>) {
    for (i, recipient) in recipients.iter().enumerate() {
        // If one transfer fails, all fail
        recipient.call{value: amounts[i]}("");
    }
}

✅ Pull pattern (safer):

contract RewardDistributor {
    pending_rewards: mapping<address, u256>;
    
    pub fn set_rewards(recipients: Vec<address>, amounts: Vec<u256>) {
        // Just record the rewards
        for (i, recipient) in recipients.iter().enumerate() {
            pending_rewards[*recipient] += amounts[i];
        }
    }
    
    pub fn claim_rewards() {
        let amount = pending_rewards[msg.sender];
        require(amount > 0, "No rewards pending");
        
        pending_rewards[msg.sender] = 0;
        msg.sender.call{value: amount}("");
    }
}

3. Rate Limiting

contract RateLimited {
    last_call: mapping<address, u256>;
    cooldown: u256 = 3600;  // 1 hour
    
    modifier rate_limit() {
        require(
            block.timestamp >= last_call[msg.sender] + cooldown,
            "Rate limit exceeded"
        );
        last_call[msg.sender] = block.timestamp;
        _;
    }
    
    #[rate_limit]
    pub fn sensitive_function() {
        // Can only be called once per hour per address
    }
}

4. Circuit Breakers

contract CircuitBreaker {
    stopped: bool = false;
    owner: address;
    
    modifier only_owner() {
        require(msg.sender == owner, "Not owner");
        _;
    }
    
    modifier stop_in_emergency() {
        require(!stopped, "Contract is stopped");
        _;
    }
    
    #[only_owner]
    pub fn emergency_stop() {
        stopped = true;
        emit EmergencyStop();
    }
    
    #[only_owner]
    pub fn resume() {
        stopped = false;
        emit Resume();
    }
    
    #[stop_in_emergency]
    pub fn normal_function() {
        // Normal operations
    }
}

Testing for Security

1. Unit Tests

// tests/security_test.aug
use std::test::TestFramework;

test "prevents overflow" {
    let contract = MyContract::new();
    
    // This should fail safely
    let result = contract.add_large_numbers(U256::MAX, 1);
    assert!(result.is_err(), "Should prevent overflow");
}

test "access control works" {
    let contract = MyContract::new();
    
    // Non-owner should not be able to call admin functions
    set_caller(non_owner_address);
    let result = contract.admin_function();
    assert!(result.is_err(), "Should reject non-owner");
}

test "reentrancy protection" {
    let contract = MyContract::new();
    
    // Simulate reentrancy attack
    let attack_result = simulate_reentrancy_attack(&contract);
    assert!(attack_result.is_err(), "Should prevent reentrancy");
}

2. Fuzzing Tests

# Generate random test cases
august fuzz --contract MyContract --iterations 10000

# Test specific functions
august fuzz --function withdraw --min-amount 0 --max-amount 1000000

3. Property-Based Testing

test "invariant: total supply equals sum of balances" {
    let contract = MyContract::new();
    
    // After any sequence of operations
    for _ in 0..100 {
        random_operation(&contract);
        
        let total = contract.total_supply();
        let sum_balances = sum_all_balances(&contract);
        assert_eq!(total, sum_balances, "Invariant violated");
    }
}

Audit Checklist

Pre-Audit Checklist

  • All functions have proper access controls
  • External calls are made after state updates
  • Integer operations use safe math or overflow checks
  • Return values from external calls are checked
  • Contract has emergency stop mechanisms
  • Rate limiting on sensitive functions
  • Input validation on all public functions
  • No hardcoded addresses or values
  • Comprehensive test coverage (>90%)
  • Documentation for all public functions

Code Review Questions

  1. Can this function be called by unauthorized users?
  2. What happens if external calls fail?
  3. Are there any integer overflow possibilities?
  4. Can this function be called in a loop to drain resources?
  5. What are the gas limits for this function?
  6. Are there any race conditions?
  7. What happens in edge cases (zero values, max values)?
  8. Can the contract state become inconsistent?

Automated Security Scanning

# Run built-in security scanner
august scan --security contract.aug

# Check for common vulnerabilities
august check --vulnerability-scan

# Generate security report
august report --security --output security-report.html

Deployment Security

1. Testnet Testing

# Always test on testnet first
august deploy --network goerli --verify

# Run security tests on deployed contract
august security-test --contract 0x123... --network goerli

2. Mainnet Deployment

# Use hardware wallet for mainnet
august deploy --network mainnet --hardware-wallet

# Multi-signature deployment
august deploy --network mainnet --multisig 0xabc...

3. Post-Deployment Monitoring

# Monitor contract for unusual activity
august monitor --contract 0x123... --alerts security-alerts.json

# Set up automated alerts
august alert-setup --contract 0x123... --slack-webhook https://...

4. Upgrade Safety

// Use proxy patterns for upgradeable contracts
contract MyContractV1 {
    // Initial implementation
}

contract MyContractProxy {
    implementation: address;
    
    #[only_owner]
    pub fn upgrade(new_implementation: address) {
        // Validate new implementation
        require(is_valid_implementation(new_implementation), "Invalid impl");
        
        implementation = new_implementation;
        emit Upgraded(new_implementation);
    }
}

Security Resources

Tools

  • Augustium Security Scanner - Built-in vulnerability detection
  • Formal Verification - Mathematical proof of correctness
  • Fuzzing Framework - Automated test case generation
  • Gas Analysis - Detect expensive operations

External Audits

Consider professional audits for:

  • High-value contracts (>$1M TVL)
  • Complex DeFi protocols
  • Governance systems
  • Cross-chain bridges

Security Communities

  • Augustium Security Forum - Discussion of best practices
  • Bug Bounty Programs - Reward security researchers
  • Security Working Group - Latest threat intelligence

Remember: Security is an ongoing process, not a one-time check. Stay updated on latest threats and best practices!

There aren’t any published security advisories