Langsung ke konten utama
BlockchainMar 28, 2026

Testing Kontrak Huff dengan Foundry Fork Test dan Asersi Gas

OS
Open Soft Team

Engineering Team

Mengapa Testing Kontrak Huff Berbeda

Kontrak Huff beroperasi di tingkat opcode mentah — tanpa pemeriksaan overflow, tanpa revert message, tanpa guardrail Solidity. Ini berarti testing menjadi lebih kritis: satu kesalahan stack akan menyebabkan perilaku yang tidak terduga tanpa error message yang berguna.

Foundry adalah framework testing terbaik untuk kontrak Huff karena:

  1. foundry-huff — Plugin yang mengkompilasi dan men-deploy file .huff dalam test Solidity
  2. Fork testing — Simulasikan terhadap state mainnet nyata
  3. Gas reporting — Lacak biaya gas per fungsi
  4. Fuzzing — Temukan edge case dengan input acak

Setup foundry-huff

forge install huff-language/foundry-huff

Tambahkan ke foundry.toml:

[profile.default]
ffi = true  # Diperlukan untuk kompilasi Huff

Contoh deployment di test:

import {HuffDeployer} from "foundry-huff/HuffDeployer.sol";

contract MyHuffTest is Test {
    address public target;
    
    function setUp() public {
        target = HuffDeployer.deploy("src/MyContract");
    }
    
    function testBasicFunction() public {
        (bool ok, bytes memory data) = target.call(
            abi.encodeWithSignature("getValue()")
        );
        assertTrue(ok);
        uint256 value = abi.decode(data, (uint256));
        assertEq(value, 42);
    }
}

Fork Testing Terhadap Mainnet

Fork test memungkinkan Anda menguji kontrak Huff terhadap state blockchain nyata — termasuk token balance, pool reserves, dan harga oracle.

contract ForkTest is Test {
    address constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
    address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
    address constant UNISWAP_PAIR = 0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc;
    
    address bot;
    
    function setUp() public {
        // Fork mainnet pada block tertentu
        vm.createSelectFork("mainnet", 18_000_000);
        bot = HuffDeployer.deploy("src/SwapBot");
        
        // Berikan WETH ke bot
        deal(WETH, bot, 10 ether);
    }
    
    function testSwapExactIn() public {
        uint256 balanceBefore = IERC20(USDC).balanceOf(address(this));
        
        // Panggil bot untuk swap WETH -> USDC
        (bool ok,) = bot.call(
            abi.encodePacked(
                uint8(0x01),      // opcode: swapExactIn
                uint256(1 ether)  // amount
            )
        );
        assertTrue(ok, "Swap gagal");
        
        uint256 balanceAfter = IERC20(USDC).balanceOf(address(this));
        assertGt(balanceAfter, balanceBefore, "Tidak menerima USDC");
    }
}

Keuntungan Fork Testing

  • State nyata — Reserves pool, oracle price, token balance semuanya nyata
  • Reprodusibilitas — Pin ke block tertentu untuk hasil deterministik
  • Edge case — Temukan masalah dengan token non-standar (USDT, rebase token)

Asersi Gas

Untuk kontrak Huff, gas adalah metrik kualitas utama. Foundry menyediakan snapshot gas:

function testGasSwap() public {
    uint256 gasBefore = gasleft();
    
    (bool ok,) = bot.call(
        abi.encodePacked(uint8(0x01), uint256(1 ether))
    );
    assertTrue(ok);
    
    uint256 gasUsed = gasBefore - gasleft();
    
    // Asersi batas gas
    assertLt(gasUsed, 80_000, "Swap melebihi batas gas");
    
    // Snapshot untuk tracking regresi
    emit log_named_uint("Gas swap", gasUsed);
}

Gas Snapshot untuk CI/CD

# Buat snapshot awal
forge snapshot

# Bandingkan dengan snapshot sebelumnya
forge snapshot --diff

Output menunjukkan fungsi mana yang gas-nya berubah:

testGasSwap() (gas: -150) ✓
testGasTransfer() (gas: +30) ⚠

Fuzzing Kontrak Huff

Fuzzing sangat penting untuk kontrak Huff karena tidak ada pemeriksaan otomatis:

function testFuzz_SwapAmount(uint256 amount) public {
    // Batasi input ke range yang masuk akal
    amount = bound(amount, 0.001 ether, 100 ether);
    deal(WETH, bot, amount);
    
    (bool ok,) = bot.call(
        abi.encodePacked(uint8(0x01), amount)
    );
    
    // Swap harus selalu berhasil untuk jumlah yang valid
    assertTrue(ok, "Swap gagal untuk jumlah valid");
}

function testFuzz_InvalidCalldata(bytes calldata data) public {
    // Kontrak harus menangani calldata invalid dengan baik
    (bool ok,) = bot.call(data);
    // Boleh gagal, tetapi tidak boleh hang atau berperilaku aneh
    // Verifikasi state tidak berubah
}

Jalankan dengan iterasi tinggi:

forge test --match-test testFuzz -vvv --fuzz-runs 10000

Testing Asersi Stack

Untuk memverifikasi bahwa makro Huff menangani stack dengan benar:

function testStackBalance() public {
    // Test bahwa kontrak mengembalikan nilai yang benar
    // untuk berbagai input — jika stack tidak seimbang,
    // hasilnya akan salah
    for (uint256 i = 0; i < 100; i++) {
        (bool ok, bytes memory data) = target.call(
            abi.encodeWithSignature("compute(uint256)", i)
        );
        assertTrue(ok);
        uint256 result = abi.decode(data, (uint256));
        assertEq(result, expectedResult(i));
    }
}

Testing Keamanan

function testReentrancy() public {
    // Deploy kontrak penyerang yang mencoba reentrancy
    Attacker attacker = new Attacker(bot);
    
    // Berikan dana ke attacker
    deal(WETH, address(attacker), 10 ether);
    
    // Serangan harus gagal
    vm.expectRevert();
    attacker.attack();
}

function testUnauthorizedAccess() public {
    // Panggil fungsi admin dari non-operator
    vm.prank(address(0xdead));
    (bool ok,) = bot.call(
        abi.encodePacked(uint8(0x03))  // withdraw
    );
    assertFalse(ok, "Non-operator berhasil memanggil withdraw");
}

Best Practice Testing Huff

  1. 100% path coverage — Test setiap cabang JUMPI di kontrak
  2. Boundary testing — Test dengan 0, 1, MAX_UINT256, dan nilai batas lainnya
  3. Gas regression — Jalankan gas snapshot di CI untuk mendeteksi regresi
  4. Fork test — Selalu test terhadap state mainnet nyata
  5. Fuzzing — Minimal 10.000 iterasi per fungsi
  6. Negative testing — Verifikasi bahwa calldata invalid ditangani dengan benar
  7. Dokumentasi test — Setiap test harus menjelaskan skenario apa yang diverifikasi

Kesimpulan

Testing kontrak Huff memerlukan pendekatan yang lebih ketat dari testing Solidity karena tidak ada safety net. Foundry dengan foundry-huff memberikan toolchain lengkap: fork testing untuk akurasi state, asersi gas untuk regresi, dan fuzzing untuk edge case. Investasi dalam test suite yang komprehensif membayar dirinya sendiri dengan mencegah bug yang mahal di produksi.