Skip to content

Commit

Permalink
test: add halmos-cheatcodes example test (#136)
Browse files Browse the repository at this point in the history
  • Loading branch information
daejunpark committed Jul 21, 2023
1 parent fec4bba commit 690e3b4
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 0 deletions.
10 changes: 10 additions & 0 deletions tests/expected/all.json
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,16 @@
"num_bounded_loops": null
}
],
"test/Token.t.sol:TokenTest": [
{
"name": "checkBalanceInvariant()",
"exitcode": 1,
"num_models": 2,
"num_paths": null,
"time": null,
"num_bounded_loops": null
}
],
"test/UnsupportedOpcode.t.sol:X": [
{
"name": "checkFoo()",
Expand Down
59 changes: 59 additions & 0 deletions tests/test/Token.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.0 <0.9.0;

import {SymTest} from "halmos-cheatcodes/SymTest.sol";
import {Test} from "forge-std/Test.sol";

/// @custom:halmos --solver-timeout-assertion 60000
contract TokenTest is SymTest, Test {
Token token;

function setUp() public {
token = new Token();

// set the balances of three arbitrary accounts to arbitrary symbolic values
for (uint i = 0; i < 3; i++) {
address receiver = svm.createAddress('receiver');
uint256 amount = svm.createUint256('amount');
token.transfer(receiver, amount);
}
}

function checkBalanceInvariant() public {
// consider two arbitrary distinct accounts
address caller = svm.createAddress('caller');
address others = svm.createAddress('others');
vm.assume(others != caller);

// record their current balances
uint256 oldBalanceCaller = token.balanceOf(caller);
uint256 oldBalanceOthers = token.balanceOf(others);

// consider an arbitrary function call to the token from the caller
vm.prank(caller);
bytes memory data = svm.createBytes(100, 'data');
(bool success,) = address(token).call(data);
vm.assume(success);

// ensure that the caller cannot spend others' tokens
assert(token.balanceOf(caller) <= oldBalanceCaller);
assert(token.balanceOf(others) >= oldBalanceOthers);
}
}

contract Token {
mapping(address => uint) public balanceOf;

constructor() {
balanceOf[msg.sender] = 1e27;
}

function transfer(address to, uint amount) public {
_transfer(msg.sender, to, amount);
}

function _transfer(address from, address to, uint amount) public {
balanceOf[from] -= amount;
balanceOf[to] += amount;
}
}

0 comments on commit 690e3b4

Please sign in to comment.