Decompiled with EVMDecompiler
Published on July 3, 2025
We successfully reconstructed a complete ERC-721 enumeration function from raw bytecode, demonstrating how our decompiler preserves complex control flow, memory allocation patterns, and business logic. This case study shows how bytecode-only contracts can be audited effectively, providing security researchers with the tools needed to analyze unverified smart contracts.
balanceOf, ownerOfwhile loop over tokenId <= maxSupplysupplyLimit to maxSupply for clarityfunction walletOfOwner(address _owner) public view returns (uint256[] memory) {
    uint256 ownerTokenCount = balanceOf(_owner);
    uint256[] memory ownedTokenIds = new uint256[](ownerTokenCount);
    uint256 currentTokenId = 1;
    uint256 ownedTokenIndex = 0;
    while (ownedTokenIndex < ownerTokenCount && currentTokenId <= supplyLimit) {
        address currentTokenOwner = ownerOf(currentTokenId);
        if (currentTokenOwner == _owner) {
            ownedTokenIds[ownedTokenIndex] = currentTokenId;
            ownedTokenIndex++;
        }
        currentTokenId++;
    }
    return ownedTokenIds;
}function walletOfOwner(address _owner) public view returns (uint256[] memory) {
    uint256 ownerTokenCount = balanceOf(_owner);
    uint256[] memory ownedTokenIds = new uint256[](ownerTokenCount);
    uint256 currentTokenId = 1;
    uint256 ownedTokenIndex = 0;
    while (ownedTokenIndex < ownerTokenCount && currentTokenId <= maxSupply) {
        address currentTokenOwner = ownerOf(currentTokenId);
        if (currentTokenOwner == _owner) {
            ownedTokenIds[ownedTokenIndex] = currentTokenId;
            ownedTokenIndex++;
        }
        currentTokenId++;
    }
    return ownedTokenIds;
}This pattern is common in NFT projects. Recovering the exact loop bounds, array allocation, and conditional writes is critical for audits because subtle deviations (off-by-one bounds, unchecked owners, or unsafe memory writes) often hide bugs or gas bombs. The output here mirrors the original’s semantics while clarifying naming (maxSupply vs supplyLimit) for readability.
while conditionsnew uint256[](count) patternsownerOf(tokenId) call sites and equality checks to guard writes