انتقل إلى المحتوى الرئيسي
بلوكتشينMar 28, 2026

Deep EVM #17: اختبار عقود Huff — اختبارات Fork في Foundry وتأكيدات الغاز

OS
Open Soft Team

Engineering Team

تحدي اختبار Huff

عقود Huff ليس لها ABI قياسي ولا أنواع Solidity — إنها مجرد بايتكود. كيف تكتب اختبارات لها؟ الإجابة: Foundry مع foundry-huff.

إعداد بيئة الاختبار

forge init huff-project
forge install huff-language/foundry-huff

في foundry.toml:

[profile.default]
src = "src"
test = "test"
libs = ["lib"]
ffi = true  # مطلوب لـ foundry-huff

نشر عقد Huff في الاختبار

// test/TokenSwap.t.sol
import {Test} from "forge-std/Test.sol";
import {HuffDeployer} from "foundry-huff/HuffDeployer.sol";

contract TokenSwapTest is Test {
    address public swapContract;
    
    function setUp() public {
        swapContract = HuffDeployer.deploy("TokenSwap");
    }
    
    function testOwner() public {
        (bool success, bytes memory data) = swapContract.staticcall(
            abi.encodeWithSignature("owner()")
        );
        assertTrue(success);
        address owner = abi.decode(data, (address));
        assertEq(owner, address(this));
    }
}

اختبارات Fork

اختبارات Fork تنفذ ضد حالة شبكة رئيسية حقيقية:

function testSwapOnMainnetFork() public {
    vm.createSelectFork("mainnet", 18_000_000);
    
    address weth = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
    address usdc = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
    
    // إعداد الرصيد
    deal(weth, address(this), 10 ether);
    IERC20(weth).approve(swapContract, type(uint256).max);
    
    // تنفيذ المبادلة
    (bool success,) = swapContract.call(
        abi.encodeWithSignature(
            "swap(address,address,uint256)",
            weth, usdc, 1 ether
        )
    );
    assertTrue(success);
    
    // تحقق من النتيجة
    uint256 usdcBalance = IERC20(usdc).balanceOf(address(this));
    assertGt(usdcBalance, 0);
}

تأكيدات الغاز

تتبع استهلاك الغاز ومنع التراجع:

function testGasConsumption() public {
    uint256 gasBefore = gasleft();
    
    (bool success,) = swapContract.call(
        abi.encodeWithSignature("owner()")
    );
    assertTrue(success);
    
    uint256 gasUsed = gasBefore - gasleft();
    
    // تأكد أن الغاز لا يتجاوز الحد
    assertLt(gasUsed, 5000, "owner() يستهلك غاز أكثر من المتوقع");
}

مع --gas-report:

forge test --gas-report

اختبار التراجعات

function testRevertOnZeroAmount() public {
    (bool success,) = swapContract.call(
        abi.encodeWithSignature(
            "swap(address,address,uint256)",
            address(0x1), address(0x2), 0
        )
    );
    assertFalse(success, "يجب أن يتراجع عند المبلغ صفر");
}

function testRevertOnUnknownSelector() public {
    (bool success,) = swapContract.call(
        abi.encodeWithSelector(bytes4(0xdeadbeef))
    );
    assertFalse(success, "يجب أن يتراجع عند محدد غير معروف");
}

اختبارات الطفرات (Mutation Testing)

تأكد من أن اختباراتك تكتشف الأخطاء فعلاً عن طريق إدخال طفرات مقصودة في البايتكود وتحقق من فشل الاختبارات.

استراتيجيات التغطية

بما أن Huff ليس لها أداة تغطية مدمجة:

  1. اختبر كل محدد — تأكد من وجود اختبار لكل دالة
  2. اختبر الحالات الحدية — أصفار، قيم قصوى، عناوين صفرية
  3. اختبر التراجعات — كل مسار revert يجب أن يُختبر
  4. اختبر التفاعلات — استدعاءات متتالية، حالات مختلفة

الخلاصة

Foundry يوفر بيئة اختبار ممتازة لعقود Huff عبر foundry-huff. اختبارات Fork تضمن التوافق مع الشبكة الرئيسية، وتأكيدات الغاز تمنع التراجع في الأداء. القاعدة: إذا لم تستطع اختباره، لا تنشره.