Skip to content

Commit

Permalink
manual merge
Browse files Browse the repository at this point in the history
  • Loading branch information
ggrieco-tob committed May 28, 2024
2 parents d8adacb + 987c7db commit db606c1
Show file tree
Hide file tree
Showing 22 changed files with 144 additions and 71 deletions.
46 changes: 46 additions & 0 deletions .github/workflows/echidna.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,28 @@ jobs:
crytic-args: --ignore-compile
contract: CryticERC20ExternalHarness

- name: Compile ERC721 Foundry example
working-directory: tests/ERC721/foundry
run: forge build --build-info

- name: Run Echidna against ERC721 Internal Foundry example
uses: crytic/echidna-action@v2
with:
echidna-workdir: ./tests/ERC721/foundry
files: .
config: ./echidna-config.yaml
crytic-args: --ignore-compile
contract: CryticERC721InternalHarness

- name: Run Echidna against ERC721 External Foundry example
uses: crytic/echidna-action@v2
with:
echidna-workdir: ./tests/ERC721/foundry
files: .
config: ./echidna-config-ext.yaml
crytic-args: --ignore-compile
contract: CryticERC721ExternalHarness

- name: Compile ERC4646 Foundry example
working-directory: tests/ERC4626/foundry
run: forge build --build-info
Expand Down Expand Up @@ -99,6 +121,30 @@ jobs:
crytic-args: --ignore-compile
contract: CryticERC20ExternalHarness

- name: Install dependencies and compile ERC721 example
working-directory: tests/ERC721/hardhat
run: |
npm ci
npx hardhat compile --force
- name: Run Echidna for Internal tests
uses: crytic/echidna-action@v2
with:
echidna-workdir: ./tests/ERC721/hardhat
files: .
config: ./tests/echidna-config.yaml
crytic-args: --ignore-compile
contract: CryticERC721InternalHarness

- name: Run Echidna for External tests
uses: crytic/echidna-action@v2
with:
echidna-workdir: ./tests/ERC721/hardhat
files: .
config: ./tests/echidna-config-ext.yaml
crytic-args: --ignore-compile
contract: CryticERC721ExternalHarness

- name: Install dependencies and compile ERC4626 example
working-directory: tests/ERC4626/hardhat
run: |
Expand Down
2 changes: 1 addition & 1 deletion PROPERTIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ This file lists all the currently implemented Echidna property tests for ERC20,
| ABDKMATH-071 | [pow_test_base_one](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1290) | One to the power of any number should be one. |
| ABDKMATH-072 | [pow_test_product_same_base](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1298) | Product of powers of the same base property |
| ABDKMATH-073 | [pow_test_power_of_an_exponentiation](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1310) | Power of an exponentiation property |
| ABDKMATH-074 | [pow_test_product_same_base](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1322) | Distributive property for power of a product |
| ABDKMATH-074 | [pow_test_distributive](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1322) | Distributive property for power of a product |
| ABDKMATH-075 | [pow_test_values](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1336) | Power result should increase or decrease (in absolute value) depending on exponent's absolute value. |
| ABDKMATH-076 | [pow_test_sign](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1352) | Power result sign should change according to the exponent sign. |
| ABDKMATH-077 | [pow_test_maximum_base](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1382) | Power edge case: Power of the maximum value should revert if exponent > 1. |
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ contract TestProperties is PropertiesAsserts {

# HEVM cheat codes support

Since version 2.0.5, Echidna supports [HEVM cheat codes](https://hevm.dev/controlling-the-unit-testing-environment.html#cheat-codes). This repository contains a [`Hevm.sol`](contracts/util/Hevm.sol) contract that exposes cheat codes for easy integration into contracts under test.
Since version 2.0.5, Echidna supports [HEVM cheat codes](https://hevm.dev/ds-test-tutorial.html#supported-cheat-codes). This repository contains a [`Hevm.sol`](contracts/util/Hevm.sol) contract that exposes cheat codes for easy integration into contracts under test.

Cheat codes should be used with care, since they can alter the execution environment in ways that are not expected, and may introduce false positives or false negatives.

Expand Down
13 changes: 4 additions & 9 deletions contracts/ERC4626/util/TestERC20Token.sol
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
pragma solidity ^0.8.0;

contract TestERC20Token {
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(
address indexed owner,
address indexed spender,
uint256 amount
);
import {IERC20} from "../../util/IERC20.sol";

contract TestERC20Token is IERC20 {
string public name;
string public symbol;
uint256 public decimals;
uint8 public decimals;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;

constructor(string memory _name, string memory _symbol, uint256 _decimals) {
constructor(string memory _name, string memory _symbol, uint8 _decimals) {
name = _name;
symbol = _symbol;
decimals = _decimals;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ abstract contract CryticERC721ExternalBasicProperties is CryticERC721ExternalTes
require(selfBalance > 0);
require(target != address(this));
require(target != msg.sender);
require(target != address(0));

uint tokenId = token.tokenOfOwnerByIndex(msg.sender, 0);

Expand All @@ -65,6 +66,7 @@ abstract contract CryticERC721ExternalBasicProperties is CryticERC721ExternalTes
require(selfBalance > 0);
require(target != address(this));
require(target != msg.sender);
require(target != address(0));
uint tokenId = token.tokenOfOwnerByIndex(msg.sender, 0);

hevm.prank(msg.sender);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,31 @@ abstract contract CryticERC721ExternalMintableProperties is CryticERC721External

////////////////////////////////////////
// Properties
// mint increases the total supply
function test_ERC721_external_mintIncreasesSupply() public virtual {
// mint increases the total supply.
function test_ERC721_external_mintIncreasesSupply(uint256 amount) public virtual {
require(token.isMintableOrBurnable());

uint256 selfBalance = token.balanceOf(address(this));
uint256 oldTotalSupply = token.totalSupply();

try token._customMint(address(this)) {
assertEq(oldTotalSupply + 1, token.totalSupply(), "Total supply was not correctly increased");
assertEq(selfBalance + 1, token.balanceOf(address(this)), "Receiver supply was not correctly increased");
try token._customMint(address(this), amount) {
assertEq(oldTotalSupply + amount, token.totalSupply(), "Total supply was not correctly increased");
assertEq(selfBalance + amount, token.balanceOf(address(this)), "Receiver supply was not correctly increased");
} catch {
assertWithMsg(false, "Minting unexpectedly reverted");
}
}

// mint creates a fresh token
function test_ERC721_external_mintCreatesFreshToken() public virtual {
// mint creates a fresh token.
function test_ERC721_external_mintCreatesFreshToken(uint256 amount) public virtual {
require(token.isMintableOrBurnable());

uint256 selfBalance = token.balanceOf(address(this));
try token._customMint(address(this)) {
try token._customMint(address(this), amount) {
uint256 tokenId = token.tokenOfOwnerByIndex(address(this), selfBalance);
assertWithMsg(token.ownerOf(tokenId) == address(this), "Token ID was not minted to receiver");
assertWithMsg(!token.usedId(tokenId), "Token ID minted is not new");
assertEq(selfBalance + 1, token.balanceOf(address(this)), "Receiver supply was not correctly increased");
assertEq(selfBalance + amount, token.balanceOf(address(this)), "Receiver supply was not correctly increased");
} catch {
assertWithMsg(false, "Minting unexpectedly reverted");
}
Expand Down
6 changes: 4 additions & 2 deletions contracts/ERC721/external/test/ERC721Compliant.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ contract ERC721Compliant is ERC721, ERC721Enumerable, IERC721Internal {
_burn(tokenId);
}

function _customMint(address to) public virtual {
_mint(to, counter++);
function _customMint(address to, uint256 amount) public virtual {
for(uint256 i; i < amount; i++) {
_mint(to, counter++);
}
}

// The following functions are overrides required by Solidity.
Expand Down
6 changes: 4 additions & 2 deletions contracts/ERC721/external/util/ERC721IncorrectBasic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,10 @@ contract ERC721IncorrectBasic is Context, ERC165, IERC721, IERC721Metadata {
_mint(to, counter++);
}

function _customMint(address to) external {
mint(to);
function _customMint(address to, uint256 amount) external {
for(uint256 i; i < amount; i++) {
mint(to);
}
}

/**
Expand Down
6 changes: 4 additions & 2 deletions contracts/ERC721/external/util/ERC721IncorrectBurnable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,10 @@ contract ERC721IncorrectBurnable is Context, ERC165, IERC721, IERC721Metadata {
_burn(tokenId);
}

function _customMint(address to) external {
mint(to);
function _customMint(address to, uint256 amount) external {
for(uint256 i; i < amount; i++) {
mint(to);
}
}

/**
Expand Down
6 changes: 4 additions & 2 deletions contracts/ERC721/external/util/ERC721IncorrectMintable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,10 @@ contract ERC721IncorrectMintable is Context, ERC165, IERC721, IERC721Metadata {
_mint(to, id);
}

function _customMint(address to) external {
mint(to);
function _customMint(address to, uint256 amount) external {
for(uint256 i; i < amount; i++) {
mint(to);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ abstract contract CryticERC721BasicProperties is CryticERC721TestBase {
require(selfBalance > 0);
require(target != address(this));
require(target != msg.sender);
require(target != address(0));
uint tokenId = tokenOfOwnerByIndex(msg.sender, 0);

hevm.prank(msg.sender);
Expand All @@ -67,6 +68,7 @@ abstract contract CryticERC721BasicProperties is CryticERC721TestBase {
require(selfBalance > 0);
require(target != address(this));
require(target != msg.sender);
require(target != address(0));
uint tokenId = tokenOfOwnerByIndex(msg.sender, 0);

hevm.prank(msg.sender);
Expand Down
22 changes: 12 additions & 10 deletions contracts/ERC721/internal/properties/ERC721MintableProperties.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,32 @@ abstract contract CryticERC721MintableProperties is CryticERC721TestBase {

////////////////////////////////////////
// Properties
// mint increases the total supply
function test_ERC721_mintIncreasesSupply() public virtual {
// mint increases the total supply.
function test_ERC721_mintIncreasesSupply(uint256 amount) public virtual {
require(isMintableOrBurnable);

uint256 selfBalance = balanceOf(msg.sender);
uint256 oldTotalSupply = totalSupply();
_customMint(msg.sender);
_customMint(msg.sender, amount);

assertEq(oldTotalSupply + 1, totalSupply(), "Total supply was not correctly increased");
assertEq(selfBalance + 1, balanceOf(msg.sender), "Receiver supply was not correctly increased");
assertEq(oldTotalSupply + amount, totalSupply(), "Total supply was not correctly increased");
assertEq(selfBalance + amount, balanceOf(msg.sender), "Receiver supply was not correctly increased");
}

// mint creates a fresh token
function test_ERC721_mintCreatesFreshToken() public virtual {
// mint creates a fresh token.
function test_ERC721_mintCreatesFreshToken(uint256 amount) public virtual {
require(isMintableOrBurnable);

uint256 selfBalance = balanceOf(msg.sender);
_customMint(msg.sender);
_customMint(msg.sender, amount);

assertEq(selfBalance + 1, balanceOf(msg.sender), "Receiver supply was not correctly increased");
assertEq(selfBalance + amount, balanceOf(msg.sender), "Receiver supply was not correctly increased");

uint256 tokenId = tokenOfOwnerByIndex(msg.sender, selfBalance);
assertWithMsg(ownerOf(tokenId) == msg.sender, "Token ID was not minted to receiver");

}

// Wrappers
function _customMint(address to) internal virtual;
function _customMint(address to, uint256 amount) internal virtual;
}
6 changes: 4 additions & 2 deletions contracts/ERC721/internal/test/standard/ERC721BasicTests.sol
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,10 @@ contract ERC721BasicTestsInternal is CryticERC721BasicProperties {
return super.supportsInterface(interfaceId);
}

function _customMint(address to) internal virtual {
mint(to);
function _customMint(address to, uint256 amount) internal virtual {
for(uint256 i; i < amount; i++) {
mint(to);
}
}
}

Expand Down
6 changes: 4 additions & 2 deletions contracts/ERC721/internal/test/standard/ERC721Compliant.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ contract ERC721Compliant is CryticERC721InternalPropertyTests {
return super.supportsInterface(interfaceId);
}

function _customMint(address to) internal virtual override {
mint(to);
function _customMint(address to, uint256 amount) internal virtual override {
for(uint256 i; i < amount; i++) {
mint(to);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,10 @@ contract ERC721MintableTestsInternal is CryticERC721MintableProperties {
return super.supportsInterface(interfaceId);
}

function _customMint(address to) internal virtual override {
mint(to);
function _customMint(address to, uint256 amount) internal virtual override {
for(uint256 i; i < amount; i++) {
mint(to);
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion contracts/ERC721/util/IERC721Internal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ interface IERC721Internal is IERC721, IERC721Enumerable {
function isMintableOrBurnable() external returns (bool);
function burn(uint256 tokenId) external;
function usedId(uint256 tokenId) external view returns (bool);
function _customMint(address to) external;
function _customMint(address to, uint256 amount) external;
}
8 changes: 4 additions & 4 deletions contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1079,8 +1079,8 @@ contract CryticABDKMath64x64Properties {
function inv_test_minimum() public view {
int128 inv_minimum;

try this.inv(MAX_64x64) {
inv_minimum = this.inv(MAX_64x64);
try this.inv(MIN_64x64) {
inv_minimum = this.inv(MIN_64x64);
assert(equal_within_precision(abs(inv_minimum), ZERO_FP, 10));
} catch {
// Unexpected, the function must not revert
Expand Down Expand Up @@ -1312,9 +1312,9 @@ contract CryticABDKMath64x64Properties {
assert(equal_within_precision(x_a_b, x_ab, 2));
}

// Test for power of a product
// Test for distributive property for power of a product
// (x * y) ** a == x ** a * y ** a
function pow_test_product_same_base(
function pow_test_distributive(
int128 x,
int128 y,
uint256 a
Expand Down
23 changes: 21 additions & 2 deletions contracts/util/Hevm.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,24 @@ interface IHevm {
// Set block.number to newNumber
function roll(uint256 newNumber) external;

// Add the condition b to the assumption base for the current branch
// This function is almost identical to require
function assume(bool b) external;

// Sets the eth balance of usr to amt
function deal(address usr, uint256 amt) external;

// Loads a storage slot from an address
function load(address where, bytes32 slot) external returns (bytes32);

// Stores a value to an address' storage slot
function store(address where, bytes32 slot, bytes32 value) external;

// Signs data (privateKey, digest) => (r, v, s)
// Signs data (privateKey, digest) => (v, r, s)
function sign(
uint256 privateKey,
bytes32 digest
) external returns (uint8 r, bytes32 v, bytes32 s);
) external returns (uint8 v, bytes32 r, bytes32 s);

// Gets address for a given private key
function addr(uint256 privateKey) external returns (address addr);
Expand All @@ -30,6 +37,18 @@ interface IHevm {

// Performs the next smart contract call with specified `msg.sender`
function prank(address newSender) external;

// Creates a new fork with the given endpoint and the latest block and returns the identifier of the fork
function createFork(string calldata urlOrAlias) external returns (uint256);

// Takes a fork identifier created by createFork and sets the corresponding forked state as active
function selectFork(uint256 forkId) external;

// Returns the identifier of the current fork
function activeFork() external returns (uint256);

// Labels the address in traces
function label(address addr, string calldata label) external;
}

IHevm constant hevm = IHevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
Loading

0 comments on commit db606c1

Please sign in to comment.