my question is simple. I'm Auditing the Ethernaut22 Contract: here for code https://ethernaut.openzeppelin.com/level/0x9CB391dbcD447E645D6Cb55dE6ca23164130D008
Ethernaut22.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract Ethernaut22 is Ownable{
address public token1;
address public token2;
constructor() {}
function setTokens(address _token1, address _token2) public onlyOwner {
token1 = _token1;
token2 = _token2;
}
function addLiquidity(address token_address, uint amount) public onlyOwner {
IERC20(token_address).transferFrom(msg.sender, address(this), amount);
}
function swap(address from, address to, uint amount) public {
require((from == token1 && to == token2) || (from == token2 && to == token1), "Invalid tokens");
require(IERC20(from).balanceOf(msg.sender) >= amount, "Not enough to swap");
uint swapAmount = getSwapPrice(from, to, amount);
IERC20(from).transferFrom(msg.sender, address(this), amount);
IERC20(to).approve(address(this), swapAmount);
IERC20(to).transferFrom(address(this), msg.sender, swapAmount);
}
function getSwapPrice(address from, address to, uint amount) public view returns(uint){
return((amount * IERC20(to).balanceOf(address(this)))/IERC20(from).balanceOf(address(this)));
}
function approve(address spender, uint amount) public {
Ethernaut22Token(token1).approve(msg.sender, spender, amount);
Ethernaut22Token(token2).approve(msg.sender, spender, amount);
}
function balanceOf(address token, address account) public view returns (uint){
return IERC20(token).balanceOf(account);
}
}
contract Ethernaut22Token is ERC20 {
address private _dex;
constructor(
address dexInstance,
string memory name,
string memory symbol,
uint256 initialSupply
)ERC20(name, symbol){
_mint(msg.sender, initialSupply);
_dex = dexInstance;
}
function approve(address owner, address spender, uint256 amount) public {
require(owner != _dex, "InvalidApprover");
super._approve(owner, spender, amount);
}
}
There are many errors in this code, but i would like to understand something from my echidna fuzzing
This is the code:
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../Ethernaut22.sol";
import "@crytic/properties/contracts/util/Hevm.sol";
//Fuzzing Ethernaut22 Contract
//
contract fuzzerEthernaut22 is Ethernaut22{
address constant deployer = address(0x20000);
address constant dist = address(0x30000);
address token1Address;
address token2Address;
constructor(){
token1Address = address(new Ethernaut22Token(address(this), "Token1", "TKN1", 110));
token2Address = address(new Ethernaut22Token(address(this), "Token2", "TKN2", 110));
Ethernaut22Token(token1Address).transfer(deployer, 110);
Ethernaut22Token(token2Address).transfer(deployer, 110);
}
function checkOwner()public{
address actualOwner = owner();
assert(owner() == deployer);
}
function checkBalance()public{
uint amount1 = Ethernaut22Token(token1Address).balanceOf(deployer);
assert(amount1 == 110);
}
function check2Balance()public{
uint amount2 = Ethernaut22Token(token2Address).balanceOf(deployer);
assert(amount2 == 110);
}
----ERROR HERE-----
//False-Negative?
function check_access_from_another_address_on_set_tokens_function()public{
hevm.prank(dist);
setTokens(token1Address, token2Address);
assert(token1 == address(0));
assert(token2 == address(0));
}
}
and this is also my config.yaml file
testMode: assertion
testLimit: 50000
deployer: "0x20000"
sender: ["0x20000" ,"0x30000"]
psender: "0x20000"
cryticArgs: ['--solc-remaps', '@=node_modules/@']
filterFunctions: ["fuzzerEthernaut22.transferOwnership(address)", "fuzzerEthernaut22.renounceOwnership()"]
filterBlacklist: true
If i run Echidna via my config.yaml i got an error in function check_access_from_another_address_on_set_tokens_function()public{}
Scope of the property is to check the possibility to set tokens if sender it's not the owner contract.
If token 1 and token 2 are equals to 0, this means, dist, it's not been able to set tokens because is not the owner.
The error i got is:
approve(address,uint256): passed!
token2(): passed!
addLiquidity(address,uint256): passed!
check_access_from_another_address_on_set_tokens_function(): failed!
Call sequence:
check_access_from_another_address_on_set_tokens_function()
Event sequence: Panic(1): Using assert.
owner(): passed!
check2Balance(): passed!
getSwapPrice(address,address,uint256): passed!
checkBalance(): passed!
setTokens(address,address): passed!
checkOwner(): passed!
token1(): passed!
swap(address,address,uint256): passed!
balanceOf(address,address): passed!
AssertionFailed(..): passed!
Unique instructions: 3129
Unique codehashes: 2
Corpus size: 18
Seed: 1397477069376912808
It's looks like, i can't recognize my hevm.prank(dist) to call function from another address, so the sender is still the deployer.
At the same time, following the echidna documentation, should be typical case of false negative coming from the use of Hevm.
Can someone explain me why i got this? Thanks in advice, have a nice day