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...
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:
Use cases:
Core Gas Optimization Principles
1. Storage Optimization
2. Computation Optimization
3. Reference Optimization
& and &mut efficientlyGas 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 ... \
--simulateOutput 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
Computation Checklist
Collection Checklist
Best Practices
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 ReportSummary
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
security-audit to ensure optimizations don't compromise securitygenerate-tests to verify optimizations maintain correctnessdeploy-contracts for mainnet deploymentsSTORAGE_OPTIMIZATION.md for detailed patternsNEVER Rules
.env or ~/.aptos/config.yaml during gas analysis (contain private keys)