🎁 Get the FREE AI Skills Starter Guide β€” Subscribe β†’
BytesAgainBytesAgain
πŸ¦€ ClawHub

Analyze Gas Optimization

by @iskysun96

Analyze and optimize Aptos Move contracts for gas efficiency, identifying expensive operations and suggesting optimizations. Triggers on: 'optimize gas', 're...

Versionv1.0.0
Downloads767
TERMINAL
clawhub install analyze-gas-optimization

πŸ“– About This Skill


name: analyze-gas-optimization description: "Analyze and optimize Aptos Move contracts for gas efficiency, identifying expensive operations and suggesting optimizations. Triggers on: 'optimize gas', 'reduce gas costs', 'gas analysis', 'make contract cheaper', 'gas efficiency', 'analyze gas usage', 'reduce transaction costs'." license: MIT metadata: author: aptos-labs version: "1.0" category: move tags: ["gas", "optimization", "performance", "costs"] priority: high

Skill: analyze-gas-optimization

Analyze and optimize Aptos Move contracts for gas efficiency, identifying expensive operations and suggesting optimizations.

When to Use This Skill

Trigger phrases:

  • "optimize gas", "reduce gas costs", "gas analysis"
  • "make contract cheaper", "gas efficiency"
  • "analyze gas usage", "gas optimization"
  • "reduce transaction costs"
  • Use cases:

  • Before mainnet deployment
  • When transaction costs are high
  • When optimizing for high-frequency operations
  • When building DeFi protocols with many transactions
  • Core Gas Optimization Principles

    1. Storage Optimization

  • Minimize stored data size
  • Use efficient data structures
  • Pack struct fields efficiently
  • Remove unnecessary fields
  • 2. Computation Optimization

  • Avoid loops over large collections
  • Cache repeated calculations
  • Use bitwise operations when possible
  • Minimize vector operations
  • 3. Reference Optimization

  • Prefer borrowing over moving when possible
  • Use & and &mut efficiently
  • Avoid unnecessary copies
  • Gas Cost Analysis

    Expensive Operations

    #### 1. Global Storage Operations

    // EXPENSIVE: Writing to global storage
    move_to(account, large_struct);

    // EXPENSIVE: Reading and writing let data = borrow_global_mut(addr);

    // EXPENSIVE: Checking existence if (exists(addr)) { ... }

    #### 2. Vector Operations

    // EXPENSIVE: Growing vectors dynamically
    vector::push_back(&mut vec, item); // O(n) worst case

    // EXPENSIVE: Searching vectors vector::contains(&vec, &item); // O(n)

    // EXPENSIVE: Removing from middle vector::remove(&mut vec, index); // O(n)

    #### 3. String Operations

    // EXPENSIVE: String concatenation
    string::append(&mut s1, s2);

    // EXPENSIVE: UTF8 validation string::utf8(bytes);

    Optimization Patterns

    #### 1. Batch Operations

    // BAD: Multiple storage accesses
    public fun update_values(account: &signer, updates: vector) {
        let i = 0;
        while (i < vector::length(&updates)) {
            let update = vector::borrow(&updates, i);
            let data = borrow_global_mut(update.address);
            data.value = update.value;
            i = i + 1;
        }
    }

    // GOOD: Single storage access with batch update public fun batch_update(account: &signer, updates: vector) { let data = borrow_global_mut(signer::address_of(account)); let i = 0; while (i < vector::length(&updates)) { let update = vector::borrow(&updates, i); // Update in memory update_memory_data(data, update); i = i + 1; } }

    #### 2. Storage Packing

    // BAD: Wasteful storage
    struct UserData has key {
        active: bool,      // 1 byte used, 7 wasted
        level: u8,         // 1 byte used, 7 wasted
        score: u64,        // 8 bytes
        timestamp: u64,    // 8 bytes
        // Total: 32 bytes (50% wasted)
    }

    // GOOD: Packed storage struct UserData has key { // Pack small fields together flags: u8, // Bits: [active, reserved...] level: u8, reserved: u16, // Future use score: u64, timestamp: u64, // Total: 20 bytes (37.5% saved) }

    #### 3. Lazy Evaluation

    // BAD: Always compute expensive value
    struct Pool has key {
        total_shares: u64,
        total_assets: u64,
        // Computed on every update
        share_price: u64,
    }

    // GOOD: Compute only when needed struct Pool has key { total_shares: u64, total_assets: u64, // Don't store computed values }

    public fun get_share_price(pool_addr: address): u64 { let pool = borrow_global(pool_addr); if (pool.total_shares == 0) { INITIAL_SHARE_PRICE } else { pool.total_assets * PRECISION / pool.total_shares } }

    #### 4. Event Optimization

    // BAD: Large event data
    struct TradeEvent has drop, store {
        pool: Object,
        trader: address,
        token_in: Object,
        token_out: Object,
        amount_in: u64,
        amount_out: u64,
        fees: u64,
        timestamp: u64,
        metadata: vector, // Large metadata
    }

    // GOOD: Minimal event data struct TradeEvent has drop, store { pool_id: u64, // Use ID instead of Object trader: address, amounts: u128, // Pack amount_in and amount_out fees: u64, // Compute other data from state }

    #### 5. Collection Optimization

    // BAD: Linear search
    public fun find_item(items: &vector, id: u64): Option {
        let i = 0;
        while (i < vector::length(items)) {
            let item = vector::borrow(items, i);
            if (item.id == id) {
                return option::some(*item)
            };
            i = i + 1;
        }
        option::none()
    }

    // GOOD: Use Table for O(1) lookup struct Storage has key { items: Table, }

    public fun find_item(storage: &Storage, id: u64): Option { if (table::contains(&storage.items, id)) { option::some(*table::borrow(&storage.items, id)) } else { option::none() } }

    Gas Measurement

    1. Transaction Simulation

    # Simulate to get gas estimate
    aptos move run-function \
        --function-id 0x1::module::function \
        --args ... \
        --simulate

    Output includes:

    - gas_unit_price

    - max_gas_amount

    - gas_used

    2. Gas Profiling

    #[test]
    public fun test_gas_usage() {
        // Measure gas for operation
        let gas_before = gas::remaining_gas();
        expensive_operation();
        let gas_used = gas_before - gas::remaining_gas();

    // Assert reasonable gas usage assert!(gas_used < MAX_ACCEPTABLE_GAS, E_TOO_EXPENSIVE); }

    Optimization Checklist

    Storage Checklist

  • [ ] Pack struct fields to minimize size
  • [ ] Use appropriate integer sizes (u8, u16, u32, u64)
  • [ ] Remove unnecessary fields
  • [ ] Consider off-chain storage for large data
  • [ ] Use events instead of storage for logs
  • Computation Checklist

  • [ ] Cache repeated calculations
  • [ ] Minimize loops over collections
  • [ ] Use early returns to skip unnecessary work
  • [ ] Batch similar operations
  • [ ] Avoid redundant checks
  • Collection Checklist

  • [ ] Use Table/TableWithLength for key-value lookups
  • [ ] Use SmartTable for large collections
  • [ ] Limit vector sizes
  • [ ] Consider pagination for large results
  • [ ] Use appropriate data structures
  • Best Practices

  • [ ] Profile before and after optimization
  • [ ] Test gas usage in unit tests
  • [ ] Document gas costs for public functions
  • [ ] Consider gas costs in contract design
  • [ ] Monitor mainnet gas usage
  • Common Gas Optimizations

    1. Replace Vectors with Tables

    // Before: O(n) search
    struct Registry has key {
        users: vector,
    }

    // After: O(1) lookup struct Registry has key { users: Table, user_list: vector

    , // If iteration needed }

    2. Minimize Storage Reads

    // Before: Multiple reads
    public fun transfer(from: &signer, to: address, amount: u64) {
        assert!(get_balance(signer::address_of(from)) >= amount, E_INSUFFICIENT);
        let from_balance = borrow_global_mut(signer::address_of(from));
        let to_balance = borrow_global_mut(to);
        // ...
    }

    // After: Single read with validation public fun transfer(from: &signer, to: address, amount: u64) { let from_addr = signer::address_of(from); let from_balance = borrow_global_mut(from_addr); assert!(from_balance.value >= amount, E_INSUFFICIENT); // ... rest of logic }

    3. Use Bitwise Flags

    // Before: Multiple bool fields (8 bytes each)
    struct Settings has copy, drop, store {
        is_active: bool,
        is_paused: bool,
        is_initialized: bool,
        allows_deposits: bool,
    }

    // After: Single u8 (1 byte) struct Settings has copy, drop, store { flags: u8, // Bit 0: active, 1: paused, 2: initialized, 3: deposits }

    const FLAG_ACTIVE: u8 = 1; // 0b00000001 const FLAG_PAUSED: u8 = 2; // 0b00000010 const FLAG_INITIALIZED: u8 = 4; // 0b00000100 const FLAG_DEPOSITS: u8 = 8; // 0b00001000

    public fun is_active(settings: &Settings): bool { (settings.flags & FLAG_ACTIVE) != 0 }

    Gas Optimization Report Template

    # Gas Optimization Report

    Summary

  • Current average gas: X units
  • Optimized average gas: Y units
  • Savings: Z% reduction
  • Optimizations Applied

    1. Storage Optimization

  • Packed struct fields (saved X bytes)
  • Replaced vectors with tables (O(n) β†’ O(1))
  • Removed redundant fields
  • 2. Computation Optimization

  • Cached price calculations (saved X operations)
  • Batched updates (N calls β†’ 1 call)
  • Early returns in validation
  • 3. Event Optimization

  • Reduced event size from X to Y bytes
  • Removed redundant event fields
  • Measurements

    | Function | Before | After | Savings | | -------- | ------ | ------ | ------- | | mint | 50,000 | 35,000 | 30% | | transfer | 30,000 | 25,000 | 17% | | swap | 80,000 | 60,000 | 25% |

    Recommendations

    1. Consider further optimizations for high-frequency functions 2. Monitor mainnet usage patterns 3. Set up gas usage alerts

    Integration Notes

  • Works with security-audit to ensure optimizations don't compromise security
  • Use with generate-tests to verify optimizations maintain correctness
  • Apply before deploy-contracts for mainnet deployments
  • Reference STORAGE_OPTIMIZATION.md for detailed patterns
  • NEVER Rules

  • ❌ NEVER optimize away security checks (access control, input validation)
  • ❌ NEVER deploy optimized code without re-testing
  • ❌ NEVER read .env or ~/.aptos/config.yaml during gas analysis (contain private keys)
  • References

  • Aptos Gas Schedule: https://github.com/aptos-labs/aptos-core/blob/main/aptos-move/aptos-gas-schedule
  • Move VM Gas Metering: https://github.com/aptos-labs/aptos-core/tree/main/aptos-move/aptos-vm
  • Gas Optimization Patterns: Check daily-move repository for real examples
  • πŸ“‹ Tips & Best Practices

  • [ ] Profile before and after optimization
  • [ ] Test gas usage in unit tests
  • [ ] Document gas costs for public functions
  • [ ] Consider gas costs in contract design
  • [ ] Monitor mainnet gas usage