communities-contracts/specs/mvp/CollectibleV1.spec

102 lines
2.7 KiB
Ruby

methods {
balanceOf(address) returns (uint) envfree;
ownerOf(uint256 tokenId) returns (address) envfree;
transferable() returns (bool) envfree;
totalSupply() returns (uint) envfree;
owner() returns (address) envfree;
maxSupply() returns (uint) envfree;
}
/* rule sanity(env e, method f) { */
/* calldataarg args; */
/* f(e, args); */
/* assert false; */
/* } */
rule mintTo_FromOwner {
address owner;
address recipient_1;
address recipient_2;
env e;
require recipient_1 != recipient_2;
require e.msg.sender == owner;
require owner() == owner;
require maxSupply() == 100000;
require totalSupply() == 0;
require balanceOf(recipient_1) == 0;
require balanceOf(recipient_2) == 0;
assert balanceOf(recipient_1) == 0, "balance of recipient_1 should be 0";
assert balanceOf(recipient_2) == 0, "balance of recipient_2 should be 0";
mintTo(e, [recipient_1, recipient_2]);
assert balanceOf(recipient_1) == 1, "balance of recipient_1 should be 1";
assert balanceOf(recipient_2) == 1, "balance of recipient_2 should be 1";
}
rule transferNFT_validOwner {
address sender;
address recipient;
uint token_id;
env e;
require e.msg.sender == sender;
require sender != recipient;
require ownerOf(token_id) == sender;
require transferable() == true;
mathint balance_sender_before = balanceOf(sender);
mathint balance_recipient_before = balanceOf(recipient);
transferFrom(e, sender, recipient, token_id);
assert ownerOf(token_id) == recipient;
assert balanceOf(sender) == balance_sender_before - 1;
/* assert balanceOf(recipient) == balance_recipient_before + 1; */
}
rule transferNFT_invalidOwner {
address sender;
address recipient;
uint token_id;
env e;
require e.msg.sender == sender;
require sender != recipient;
require ownerOf(token_id) != sender;
require transferable() == true;
transferFrom@withrevert(e, sender, recipient, token_id);
assert lastReverted, "transfer should revert when the sender is not the owner of tokenId";
}
rule transferSoulbound {
address sender;
address recipient;
uint token_id;
env e;
require e.msg.sender == sender;
require sender != recipient;
require ownerOf(token_id) == sender;
require transferable() == false;
mathint balance_sender_before = balanceOf(sender);
mathint balance_recipient_before = balanceOf(recipient);
transferFrom@withrevert(e, sender, recipient, token_id);
assert lastReverted, "transfer should revert if it's a Soulbound token";
}
rule maxSupplyNotLowerThanTotalSupply(env e, method f) {
require maxSupply() >= totalSupply();
calldataarg args;
f(e, args); // call all public/external functions of a contract
assert maxSupply() >= totalSupply();
}