{"id":1137,"date":"2025-09-09T16:07:52","date_gmt":"2025-09-09T14:07:52","guid":{"rendered":"https:\/\/ackee.xyz\/blog\/?p=1137"},"modified":"2025-09-09T16:07:52","modified_gmt":"2025-09-09T14:07:52","slug":"a-beginners-guide-to-manually-guided-fuzzing","status":"publish","type":"post","link":"https:\/\/ackee.xyz\/blog\/a-beginners-guide-to-manually-guided-fuzzing\/","title":{"rendered":"A Beginner&#8217;s Guide to Manually Guided Fuzzing"},"content":{"rendered":"<h2 dir=\"auto\" data-line=\"4\">Introduction<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"4\">Manually guided fuzzing (MGF) is a testing methodology that finds critical vulnerabilities by systematically testing smart contract behavior through guided test scenarios.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"6\">Unlike traditional fuzzing that relies on randomness alone, MGF allows developers to define specific test flows and invariants, providing more targeted and effective vulnerability detection.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"8\">Learn MGF to strengthen your smart contract security.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"10\">Comprehensive documentation: <a href=\"https:\/\/ackee.xyz\/wake\/docs\/latest\/testing-framework\/fuzzing\/#fuzzing\" target=\"_blank\" rel=\"noopener\">Wake Testing Framework &#8211; Fuzzing<\/a><\/p>\n<h2 dir=\"auto\" data-line=\"13\">Comparison With Foundry Fuzz Testing and Invariant Testing<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"15\">In any smart contract test, the most critical element is defining clear invariants &#8211; properties that should always remain true regardless of the contract&#8217;s state changes.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"17\">The Wake manually guided fuzzing approach compares expected behavior (defined in Python) against actual contract behavior, without relying on the contract&#8217;s internal logic.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"19\">This methodology forces testers to verify behavior at every step, ensuring comprehensive coverage and catching edge cases that other testing approaches might miss.<\/p>\n<h3 dir=\"auto\" data-line=\"22\">Wake MGF lifecycle<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"24\">Wake MGF follows a different execution lifecycle compared to Foundry&#8217;s fuzz tests or invariant tests.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"26\">The Wake MGF execution lifecycle:<\/p>\n<p dir=\"auto\" data-line=\"26\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-1148 \" src=\"https:\/\/abchprod.wpengine.com\/wp-content\/uploads\/2025\/09\/mgf_lifecycle-e1757340582484.png\" alt=\"\" width=\"533\" height=\"1042\" srcset=\"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2025\/09\/mgf_lifecycle-e1757340582484.png 1207w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2025\/09\/mgf_lifecycle-e1757340582484-154x300.png 154w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2025\/09\/mgf_lifecycle-e1757340582484-524x1024.png 524w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2025\/09\/mgf_lifecycle-e1757340582484-768x1500.png 768w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2025\/09\/mgf_lifecycle-e1757340582484-786x1536.png 786w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2025\/09\/mgf_lifecycle-e1757340582484-1048x2048.png 1048w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2025\/09\/mgf_lifecycle-e1757340582484-370x723.png 370w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2025\/09\/mgf_lifecycle-e1757340582484-760x1485.png 760w\" sizes=\"auto, (max-width: 533px) 100vw, 533px\" \/><\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"28\">Where:<\/p>\n<ul>\n<li class=\"code-line\" dir=\"auto\" data-line=\"29\"><code class=\"codehl\">flow_count<\/code> defines the number of flow function calls executed after each <code class=\"codehl\">pre_sequence<\/code> function (contract initialization)<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"30\"><code class=\"codehl\">sequence_count<\/code> defines the number of complete test sequences to execute<\/li>\n<\/ul>\n<p class=\"code-line\" dir=\"auto\" data-line=\"32\">Each sequence consists of one <code class=\"codehl\">pre_sequence<\/code> followed by the specified number of <code class=\"codehl\">flow<\/code> function calls.<\/p>\n<p dir=\"auto\" data-line=\"32\">Learn more about <a href=\"https:\/\/ackee.xyz\/wake\/docs\/latest\/testing-framework\/fuzzing\/#execution-hooks\" target=\"_blank\" rel=\"noopener\">execution hooks<\/a> in Wake.<\/p>\n<h2 dir=\"auto\" data-line=\"36\">Implementation Guide<\/h2>\n<h3 dir=\"auto\" data-line=\"38\">Prerequisites<\/h3>\n<ul>\n<li class=\"code-line\" dir=\"auto\" data-line=\"40\">Wake framework installed on your system<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"41\">Basic understanding of Python and Solidity<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"42\">A Solidity project ready for testing or use the code in the <a href=\"#appendix---full-code\">Appendix<\/a>.<\/li>\n<\/ul>\n<h3 dir=\"auto\" data-line=\"44\">Full Source Code<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"45\">Full source code available in the <a href=\"#appendix---full-code\">Appendix<\/a>.<\/p>\n<h3 dir=\"auto\" data-line=\"47\">1. Compile the project with Wake<\/h3>\n<ol>\n<li class=\"code-line\" dir=\"auto\" data-line=\"46\">Run <code class=\"codehl\">$ wake up<\/code> to compile your Solidity contracts and generate Python type definitions<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"47\">The pytypes are automatically generated in the <code class=\"codehl\">pytypes<\/code> directory<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"48\">Create your test file: <code class=\"codehl\">tests\/test_fuzz.py<\/code><\/li>\n<\/ol>\n<p class=\"code-line\" dir=\"auto\" data-line=\"50\">The pytypes provide Python interfaces for your Solidity contracts, enabling type-safe interaction during testing.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"52\"><strong>Action item<\/strong>: Set up your project structure with the test file in the correct location.<\/p>\n<h3 dir=\"auto\" data-line=\"54\">2. Import Wake<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"55\">Import Wake testing.<\/p>\n<pre><code class=\"language-python\">from wake.testing import *\nfrom wake.testing.fuzzing import *<\/code><\/pre>\n<h3 dir=\"auto\" data-line=\"62\">3. Import pytypes<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"64\">Import pytypes by looking at the pytypes directory and importing your contract pytypes.<\/p>\n<pre><code class=\"language-python\">from pytypes.contracts.Token import Token<\/code><\/pre>\n<h3 dir=\"auto\" data-line=\"70\">4. Define the Test Class and Call From the Test<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"71\">Fuzzing base class <code class=\"codehl\">FuzzTest<\/code> is defined in <code class=\"codehl\">wake.testing.fuzzing<\/code>.<\/p>\n<pre><code class=\"language-python\">from wake.testing import *\nfrom wake.testing.fuzzing import *\n\nimport logging\nlogger = logging.getLogger(__name__)\nlogger.setLevel(logging.INFO)\n\nfrom pytypes.contracts.Token import Token\n\ndef revert_handler(e: RevertError):\n    if e.tx is not None:\n        print(e.tx.call_trace)\n\nclass TokenFuzz(FuzzTest):\n\n    def pre_sequence(self):\n        pass\n\n    @flow()\n    def flow_example(self):\n        pass\n\n    @invariant()\n    def invariant_example(self):\n        pass\n\n\n@chain.connect()\n@on_revert(revert_handler)\ndef test_default():\n    TokenFuzz.run(sequences_count=1, flows_count=100)<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"107\">The following sections detail how to implement logic within the <code class=\"codehl\">TokenFuzz<\/code> class.<\/p>\n<h3 dir=\"auto\" data-line=\"110\">5. Contract Initialization and Python State Definition<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"112\">The <code class=\"codehl\">pre_sequence<\/code> function serves as the setup phase for each test sequence:<\/p>\n<ol>\n<li class=\"code-line\" dir=\"auto\" data-line=\"114\"><strong>Deploy contracts<\/strong>: Initialize the contracts you want to test<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"115\"><strong>Define actors<\/strong>: Set up accounts that will interact with your contracts<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"116\"><strong>Initialize Python state<\/strong>: Create data structures to track expected contract state<\/li>\n<\/ol>\n<p class=\"code-line\" dir=\"auto\" data-line=\"118\">This separation ensures each test sequence starts with a clean, known state.<\/p>\n<pre><code class=\"language-python\">class TokenFuzz(FuzzTest):\n\n    token_owner: Account\n    token: Token\n    token_balances: dict[Account, int]\n\n    def pre_sequence(self):\n        self.token_owner = random_account()\n        self.token = Token.deploy(from_=self.token_owner)\n        self.token_balances = defaultdict(int)<\/code><\/pre>\n<h3 dir=\"auto\" data-line=\"133\">6. Defining Flows<\/h3>\n<h4 dir=\"auto\" data-line=\"135\">What is a flow function?<\/h4>\n<p class=\"code-line\" dir=\"auto\" data-line=\"137\">Flow functions are the core of MGF testing. Each flow function generates test inputs, executes contract calls, validates behavior, and updates Python state to mirror contract changes.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"139\">Flow functions simulate real-world usage patterns and edge cases by systematically testing different input combinations and execution paths.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"143\">This is the flow function.<\/p>\n<pre><code class=\"language-python\">@flow()\ndef flow_mint_tokens(self):\n    ##1. prepare random input\n    recipient = random_account() # or random.choice(list(chain.accounts) + [self.token])\n    amount = random_int(0, 10**30)\n    actor = random_account()\n\n    ##2. run transaction\n    with may_revert() as e:\n        tx = self.token.mintTokens(recipient, amount, from_=actor)\n    if e.value is not None:\n        ## 3. check revert\n        if actor != self.token_owner:\n            assert e.value == Token.NotAuthorized(actor.address)\n            return &quot;Not authorized&quot;\n        assert False\n\n    ##4. check events\n    events = [e for e in tx.events if isinstance(e, Token.TokensMinted)]\n    assert len(events) == 1\n    assert events[0].to == recipient.address\n    assert events[0].amount == amount\n\n    ##5. update python state\n    self.token_balances[recipient] += amount\n\n    ##6. logging for debug\n    logger.info(f&quot;Minted {amount} tokens to {recipient.address}&quot;)<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"175\">Follow this structured approach in every flow function:<\/p>\n<ul>\n<li class=\"code-line\" dir=\"auto\" data-line=\"177\">Prepare random input<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"178\">Execute transaction with revert handling<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"179\">Validate events and assertions<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"180\">Update Python state<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"181\">Add logging for debugging (if necessary)<\/li>\n<\/ul>\n<h4 dir=\"auto\" data-line=\"183\">Step 1: Prepare random input<\/h4>\n<p class=\"code-line\" dir=\"auto\" data-line=\"185\">Generate test inputs using Wake&#8217;s built-in random functions like <code class=\"codehl\">random_account()<\/code>, <code class=\"codehl\">random_int(min, max)<\/code>, and <code class=\"codehl\">random_bytes(length)<\/code>. These functions ensure comprehensive test coverage across different input scenarios.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"187\">Full documentation: <a href=\"https:\/\/ackee.xyz\/wake\/docs\/latest\/testing-framework\/fuzzing\/#random-functions\">https:\/\/ackee.xyz\/wake\/docs\/latest\/testing-framework\/fuzzing\/#random-functions<\/a><\/p>\n<h4 dir=\"auto\" data-line=\"190\">Step 2: Execute transaction with revert handling<\/h4>\n<p class=\"code-line\" dir=\"auto\" data-line=\"192\">Use the <code class=\"codehl\">may_revert()<\/code> context manager to handle both successful and failing transactions. This enables branching logic for success\/failure cases. Use <code class=\"codehl\">assert False<\/code> to catch unexpected revert conditions, and return descriptive strings for expected reverts to track test statistics.<\/p>\n<pre><code class=\"language-python\">with may_revert() as e:\n    tx = self.token.mintTokens(recipient, amount, from_=actor)\nif e.value is not None:\n    if condition:\n        # assert e.value == RevertError()\n        return &quot;Reason&quot;\n    elif other_condition:\n        # assert e.value == RevertOtherError()\n        return &quot;OtherReason&quot;\n    assert False<\/code><\/pre>\n<h4 dir=\"auto\" data-line=\"207\">Step 3: Check events and assertions<\/h4>\n<p class=\"code-line\" dir=\"auto\" data-line=\"209\">Always check errors.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"210\">Always check events for the testing target.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"212\">Events and RevertErrors can be checked in these ways:<\/p>\n<pre><code class=\"language-python\">events = [e for e in tx.events if e == Token.TokensMinted(recipient.address, amount)]\nassert len(events) == 1<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"212\">Or filter by event and assert parameters<\/p>\n<pre><code class=\"language-python\">events = [e for e in tx.events if isinstance(e, Token.TokensMinted)]\nassert len(events) == 1\nassert events[0].to == recipient.address\nassert events[0].amount == amount<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"225\">The <code class=\"codehl\">isinstance()<\/code> approach is recommended for complex validation scenarios, such as transactions that emit multiple events or when parameter values require complex calculations. This method provides precise error reporting, showing exactly which parameters failed assertion checks.<\/p>\n<h4 dir=\"auto\" data-line=\"230\">Step 4: Update Python state<\/h4>\n<p class=\"code-line\" dir=\"auto\" data-line=\"232\">Mirror the contract&#8217;s state changes in your Python variables. This parallel state tracking enables accurate invariant checking. Never derive state updates from view functions &#8211; always update based on the known effects of your transactions.<\/p>\n<h3 dir=\"auto\" data-line=\"235\">Invariant Functions<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"237\">Invariant functions validate that critical properties hold true throughout contract execution. They compare your Python state against the actual contract state using view functions.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"239\">For complex protocols, invariants may include sophisticated logic to verify multi-contract interactions. Never modify state within invariant functions. If state-changing operations are required for validation, use <code class=\"codehl\">snapshot_and_revert()<\/code> to avoid affecting the test sequence.<\/p>\n<h3 dir=\"auto\" data-line=\"241\">Definition of Invariants in MGF<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"242\">Check view functions with Python state.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"244\">Check invariant statements and conditional invariants.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"246\">All <code class=\"codehl\">@invariant()<\/code> functions are called after each <code class=\"codehl\">@flow<\/code> function call.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"248\">No state changes in these functions.<\/p>\n<pre><code class=\"language-python\">@invariant()\ndef invariant_token_balances(self):\n    for account in list(self.token_balances.keys()) + [self.token]:\n        assert self.token.getBalance(account.address) == self.token_balances[account]\n\n@invariant()\ndef invariant_token_owner(self):\n    assert self.token.owner() == self.token_owner.address<\/code><\/pre>\n<h3 dir=\"auto\" data-line=\"264\">Running The Test<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"266\">Run the test:<\/p>\n<pre><code class=\"codehl\">$ wake test tests\/test_token_fuzz.py<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"268\">This is a running example with a smaller flow_number.<\/p>\n<div style=\"width: 1170px;\" class=\"wp-video\"><video class=\"wp-video-shortcode\" id=\"video-1137-1\" width=\"1170\" height=\"699\" preload=\"metadata\" controls=\"controls\"><source type=\"video\/mp4\" src=\"https:\/\/abchprod.wpengine.com\/wp-content\/uploads\/2025\/09\/mgf_run.mp4?_=1\" \/><a href=\"https:\/\/abchprod.wpengine.com\/wp-content\/uploads\/2025\/09\/mgf_run.mp4\">https:\/\/abchprod.wpengine.com\/wp-content\/uploads\/2025\/09\/mgf_run.mp4<\/a><\/video><\/div>\n<p class=\"code-line\" dir=\"auto\" data-line=\"268\">Use debug mode when the test fails:<\/p>\n<pre><code class=\"codehl\">$ wake test tests\/test_token_fuzz.py -d<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"270\">The execution shows the random seed hex value. You can use this hex value to reproduce the same test, including failures.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"272\">Set a specific random seed for reproducible testing:<\/p>\n<pre><code class=\"codehl\">$ wake test tests\/test_token_fuzz.py -S 235ab3<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"274\">More fuzzing tips and professional methodology: <a href=\"https:\/\/x.com\/WakeFramework\">follow @wakeframework on X<\/a>.<\/p>\n<h2 dir=\"auto\" data-line=\"276\">Conclusion<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"278\">Manually guided fuzzing provides a systematic approach to verify contract behavior while offering deep insight into contract logic and edge cases.<\/p>\n<h2 dir=\"auto\" data-line=\"280\">Appendix &#8211; Full Code<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"282\">token.sol<\/p>\n<pre><code class=\"language-solidity\">\/\/ SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n\ncontract Token {\n    address public immutable owner;\n    mapping(address =&gt; uint256) public tokenBalance;\n\n    event Transfer(address indexed from, address indexed to, uint256 value);\n    event TokensMinted(address indexed to, uint256 amount);\n\n    error NotEnoughTokens(uint256 requested, uint256 balance);\n    error NotAuthorized(address caller);\n\n    constructor() {\n        owner = msg.sender;\n    }\n\n    modifier onlyOwner() {\n        if (msg.sender != owner) {\n            revert NotAuthorized(msg.sender);\n        }\n        _;\n    }\n\n    function mintTokens(address recipient, uint256 amount) external onlyOwner {\n        tokenBalance[recipient] += amount;\n        emit TokensMinted(recipient, amount);\n    }\n\n    function transfer(address to, uint256 amount) external {\n        if (tokenBalance[msg.sender] &lt; amount) {\n            revert NotEnoughTokens(amount, tokenBalance[msg.sender]);\n        }\n\n        tokenBalance[msg.sender] -= amount;\n        tokenBalance[to] += amount;\n\n        emit Transfer(msg.sender, to, amount);\n    }\n\n    function transferWithBytes(bytes calldata data) external {\n        (address to, uint256 amount) = abi.decode(data, (address, uint256));\n        if (tokenBalance[msg.sender] &lt; amount) {\n            revert NotEnoughTokens(amount, tokenBalance[msg.sender]);\n        }\n        tokenBalance[msg.sender] -= amount;\n        tokenBalance[to] += amount;\n        emit Transfer(msg.sender, to, amount);\n    }\n\n    function getBalance(address account) external view returns (uint256) {\n        return tokenBalance[account];\n    }\n}<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"341\">test_token_fuzz.py<\/p>\n<pre><code class=\"language-python\">from wake.testing import *\nfrom collections import defaultdict\nfrom wake.testing.fuzzing import *\n\nfrom pytypes.contracts.Token import Token\n\nimport logging\nlogger = logging.getLogger(__name__)\nlogger.setLevel(logging.INFO)\n\n# Print failing tx call trace\ndef revert_handler(e: RevertError):\n    if e.tx is not None:\n        print(e.tx.call_trace)\nclass TokenFuzz(FuzzTest):\n\n    token_owner: Account\n    token: Token\n    token_balances: dict[Account, int]\n\n    def pre_sequence(self):\n        self.token_owner = random_account()\n        self.token = Token.deploy(from_=self.token_owner)\n        self.token_balances = defaultdict(int)\n\n    @flow()\n    def flow_mint_tokens(self):\n        ## prepare random input\n        recipient = random_account() # or list(chain.accounts) + [self.token]\n        amount = random_int(0, 10**30)\n        actor = random_account()\n\n        ## run transaction\n        with may_revert() as e:\n            tx = self.token.mintTokens(recipient.address, amount, from_=actor)\n        if e.value is not None:\n            if actor != self.token_owner:\n                assert e.value == Token.NotAuthorized(actor.address)\n                return &quot;Not authorized&quot;\n            assert False\n\n        ## check events\n        events = [e for e in tx.events if isinstance(e, Token.TokensMinted)]\n        assert len(events) == 1\n        assert events[0].to == recipient.address\n        assert events[0].amount == amount\n\n        ## update python state\n        self.token_balances[recipient] += amount\n\n        logger.info(f&quot;Minted {amount} tokens to {recipient.address}&quot;)\n\n    @flow()\n    def flow_transfer_tokens(self):\n        recipient = random_account()\n        amount = random_int(0, 10**30)\n        actor = random_account()\n        with may_revert() as e:\n            tx = self.token.transfer(recipient.address, amount, from_=actor)\n\n        if e.value is not None:\n            if self.token_balances[actor] &lt; amount:\n                assert e.value == Token.NotEnoughTokens(amount, self.token_balances[actor])\n                return &quot;Not enough tokens&quot;\n            assert False\n\n        events = [e for e in tx.events if isinstance(e, Token.Transfer)]\n        assert len(events) == 1\n        assert events[0].from_ == actor.address\n        assert events[0].to == recipient.address\n        assert events[0].value == amount\n\n        self.token_balances[recipient] += amount\n        self.token_balances[actor] -= amount\n\n        logger.info(f&quot;Transferred {amount} tokens from {actor.address} to {recipient.address}&quot;)\n\n\n    @flow()\n    def flow_transfer_tokens_with_bytes(self):\n        recipient = random_account()\n        amount = random_int(0, 10**30)\n        actor = random_account()\n        with may_revert() as e:\n            tx = self.token.transferWithBytes(abi.encode(recipient.address, uint256(amount)), from_=actor)\n        if e.value is not None:\n            if self.token_balances[actor] &lt; amount:\n                assert e.value == Token.NotEnoughTokens(amount, self.token_balances[actor])\n                return &quot;Not enough tokens&quot;\n            assert False\n\n        events = [e for e in tx.events if isinstance(e, Token.Transfer)]\n        assert len(events) == 1\n        assert events[0].from_ == actor.address\n        assert events[0].to == recipient.address\n        assert events[0].value == amount\n\n        self.token_balances[recipient] += amount\n        self.token_balances[actor] -= amount\n\n        logger.info(f&quot;Transferred {amount} tokens from {actor.address} to {recipient.address}&quot;)\n\n    @invariant()\n    def invariant_token_balances(self):\n        for account in list(self.token_balances.keys()) + [self.token]:\n            assert self.token.getBalance(account.address) == self.token_balances[account]\n\n\n    @invariant()\n    def invariant_token_owner(self):\n        assert self.token.owner() == self.token_owner.address\n\n\n\n@chain.connect()\ndef test_default():\n    TokenFuzz.run(sequences_count=10, flows_count=10000)<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Manually guided fuzzing (MGF) is a testing methodology that finds critical vulnerabilities by systematically testing smart contract behavior through guided test scenarios. Unlike traditional fuzzing that relies on randomness alone, MGF allows developers to define specific test flows and invariants, providing more targeted and effective vulnerability detection. Learn MGF to strengthen your smart contract security. Comprehensive documentation: Wake Testing Framework &#8211;&hellip;<\/p>\n","protected":false},"author":24,"featured_media":755,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[61,10,63,103],"tags":[87,156,88,28,102,104],"class_list":["post-1137","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-education","category-ethereum","category-tutorial","category-wake","tag-education","tag-fuzz-testing","tag-how-to","tag-smart-contract","tag-tutorial","tag-wake"],"aioseo_notices":[],"featured_image_src":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2024\/06\/4-600x400.png","featured_image_src_square":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2024\/06\/4-600x600.png","author_info":{"display_name":"Naoki Yoshida","author_link":"https:\/\/ackee.xyz\/blog\/author\/naoki-yoshida\/"},"_links":{"self":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts\/1137","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/users\/24"}],"replies":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/comments?post=1137"}],"version-history":[{"count":0,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts\/1137\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media\/755"}],"wp:attachment":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media?parent=1137"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/categories?post=1137"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/tags?post=1137"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}