analyze-gas-optimization

Skill: analyze-gas-optimization

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "analyze-gas-optimization" with this command: npx skills add iskysun96/aptos-agent-skills/iskysun96-aptos-agent-skills-analyze-gas-optimization

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

  1. Computation Optimization
  • Avoid loops over large collections

  • Cache repeated calculations

  • Use bitwise operations when possible

  • Minimize vector operations

  1. 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<LargeData>(addr);

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

  1. 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)

  1. 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<Update>) { let i = 0; while (i < vector::length(&updates)) { let update = vector::borrow(&updates, i); let data = borrow_global_mut<Data>(update.address); data.value = update.value; i = i + 1; } }

// GOOD: Single storage access with batch update public fun batch_update(account: &signer, updates: vector<Update>) { let data = borrow_global_mut<Data>(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; } }

  1. 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) }

  1. 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>(pool_addr); if (pool.total_shares == 0) { INITIAL_SHARE_PRICE } else { pool.total_assets * PRECISION / pool.total_shares } }

  1. Event Optimization

// BAD: Large event data struct TradeEvent has drop, store { pool: Object<Pool>, trader: address, token_in: Object<Token>, token_out: Object<Token>, amount_in: u64, amount_out: u64, fees: u64, timestamp: u64, metadata: vector<u8>, // 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 }

  1. Collection Optimization

// BAD: Linear search public fun find_item(items: &vector<Item>, id: u64): Option<Item> { 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<u64, Item>, }

public fun find_item(storage: &Storage, id: u64): Option<Item> { 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

  1. 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 &#x3C; 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<User>, }

// After: O(1) lookup struct Registry has key { users: Table<address, User>, user_list: vector<address>, // If iteration needed }

  1. 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<Balance>(signer::address_of(from)); let to_balance = borrow_global_mut<Balance>(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<Balance>(from_addr); assert!(from_balance.value >= amount, E_INSUFFICIENT); // ... rest of logic }

  1. 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

FunctionBeforeAfterSavings
mint50,00035,00030%
transfer30,00025,00017%
swap80,00060,00025%

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

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

generate-tests

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

search-aptos-examples

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

write-contracts

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

deploy-contracts

No summary provided by upstream source.

Repository SourceNeeds Review