communities-contracts/certora/specs/CommunityERC721.spec

181 lines
4.8 KiB
Plaintext
Raw Permalink Normal View History

methods {
function balanceOf(address) external returns (uint) envfree;
function ownerOf(uint256 tokenId) external returns (address) envfree;
function transferable() external returns (bool) envfree;
function totalSupply() external returns (uint) envfree;
function maxSupply() external returns (uint) envfree;
function setMaxSupply(uint256 newMaxSupply) external returns (uint);
function mintTo(address[]) external;
function mintedCount() external returns (uint) envfree;
function safeBatchTransferFrom(address from, address[] to, uint256[] tokenIds, bytes data) external;
function countAddressOccurrences(address[], address) external returns (uint) envfree;
function _.onERC721Received(address, address, uint256, bytes) external => NONDET;
}
ghost mathint sumOfBalances {
init_state axiom sumOfBalances == 0;
}
hook Sstore _balances[KEY address addr] uint256 newValue (uint256 oldValue) {
sumOfBalances = sumOfBalances - oldValue + newValue;
}
hook Sload uint256 balance _balances[KEY address addr] {
require sumOfBalances >= to_mathint(balance);
}
function safeAssumptions() {
requireInvariant mintCountGreaterEqualTotalSupplyAndTotalSupplyEqBalances();
}
invariant mintCountGreaterEqualTotalSupplyAndTotalSupplyEqBalances()
to_mathint(mintedCount()) >= to_mathint(totalSupply()) &&
to_mathint(totalSupply()) == sumOfBalances;
rule integrityOfMintTo {
requireInvariant mintCountGreaterEqualTotalSupplyAndTotalSupplyEqBalances();
address[] addresses;
env e;
mathint totalSupply_before = totalSupply();
mathint maxSupply = to_mathint(maxSupply());
address addr;
require totalSupply_before < maxSupply;
require totalSupply_before + addresses.length <= maxSupply;
mathint balance_addr_before = balanceOf(addr);
mathint count = countAddressOccurrences(addresses, addr);
mintTo(e, addresses);
mathint totalSupply_after = totalSupply();
mathint balance_addr_after = balanceOf(addr);
assert totalSupply_after == totalSupply_before + addresses.length;
assert balance_addr_after == balance_addr_before + count;
}
rule maxSupplyCannotBeLowerThanMintedCount() {
require maxSupply() >= mintedCount();
env e;
uint256 newMaxSupply;
setMaxSupply(e, newMaxSupply);
assert maxSupply() >= mintedCount();
}
rule maxSupplyNotLowerThanTotalSupply(env e, method f) {
require maxSupply() >= totalSupply();
requireInvariant mintCountGreaterEqualTotalSupplyAndTotalSupplyEqBalances();
calldataarg args;
f(e, args); // call all public/external functions of a contract
assert maxSupply() >= totalSupply();
}
rule mintToReverts() {
address[] addresses;
env e;
mathint supply_before = totalSupply();
mathint max_supply = maxSupply();
mathint minted_count = mintedCount();
require supply_before <= max_supply;
require minted_count >= supply_before;
mintTo@withrevert(e, addresses);
bool reverted = lastReverted;
assert (supply_before + addresses.length > max_supply) => reverted;
satisfy supply_before == max_supply && addresses.length > 0 && reverted;
}
rule mintToRelations() {
address[] addresses_1;
address[] addresses_2;
env e;
require addresses_1.length == 2;
require addresses_1.length == addresses_2.length;
require addresses_1[0] != addresses_1[1];
require addresses_1[0] == addresses_2[1];
require addresses_1[1] == addresses_2[0];
mathint supply_before = totalSupply();
mathint max_supply = maxSupply();
mathint minted_count = mintedCount();
require supply_before <= max_supply;
require minted_count >= supply_before;
address a;
storage s1 = lastStorage;
mintTo(e, addresses_1);
mathint balance_s1 = balanceOf(a);
mintTo(e, addresses_2) at s1;
mathint balance_s2 = balanceOf(a);
assert balance_s1 == balance_s2;
}
rule safeBatchTransferFromReverts() {
address from;
address[] to;
uint256[] tokenIds;
bytes data;
env e;
mathint supply_before = totalSupply();
mathint max_supply = maxSupply();
mathint minted_count = mintedCount();
require supply_before <= max_supply;
require minted_count >= supply_before;
safeBatchTransferFrom@withrevert(e, from, to, tokenIds, data);
bool reverted = lastReverted;
assert (tokenIds.length != to.length) => reverted;
}
rule safeBatchTransferFromRelations() {
address from;
address[] to;
uint256[] tokenIds;
bytes data;
env e;
require to.length == tokenIds.length;
mathint supply_before = totalSupply();
mathint max_supply = maxSupply();
mathint minted_count = mintedCount();
require supply_before <= max_supply;
require minted_count >= supply_before;
address a;
storage s1 = lastStorage;
safeBatchTransferFrom(e, from, to, tokenIds, data);
mathint balance_s1 = balanceOf(a);
safeBatchTransferFrom(e, from, to, tokenIds, data) at s1;
mathint balance_s2 = balanceOf(a);
assert balance_s1 == balance_s2;
}