123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877 |
- methods {
- isApprovedForAll(address, address) returns(bool) envfree
- balanceOf(address, uint256) returns(uint256) envfree
- balanceOfBatch(address[], uint256[]) returns(uint256[]) envfree
- _doSafeBatchTransferAcceptanceCheck(address, address, address, uint256[], uint256[], bytes) envfree
- _doSafeTransferAcceptanceCheck(address, address, address, uint256, uint256, bytes) envfree
- setApprovalForAll(address, bool)
- safeTransferFrom(address, address, uint256, uint256, bytes)
- safeBatchTransferFrom(address, address, uint256[], uint256[], bytes)
- mint(address, uint256, uint256, bytes)
- mintBatch(address, uint256[], uint256[], bytes)
- burn(address, uint256, uint256)
- burnBatch(address, uint256[], uint256[])
- }
- /////////////////////////////////////////////////
- // Approval (4/4)
- /////////////////////////////////////////////////
- // STATUS - verified
- // Function $f, which is not setApprovalForAll, should not change approval
- rule unexpectedAllowanceChange(method f, env e) filtered { f -> f.selector != setApprovalForAll(address, bool).selector } {
- address account; address operator;
- bool approveBefore = isApprovedForAll(account, operator);
- calldataarg args;
- f(e, args);
- bool approveAfter = isApprovedForAll(account, operator);
- assert approveBefore == approveAfter, "You couldn't get king's approval this way!";
- }
- // STATUS - verified
- // approval can be changed only by owner
- rule onlyOwnerCanApprove(env e){
- address owner; address operator; bool approved;
- bool aprovalBefore = isApprovedForAll(owner, operator);
- setApprovalForAll(e, operator, approved);
- bool aprovalAfter = isApprovedForAll(owner, operator);
- assert aprovalBefore != aprovalAfter => owner == e.msg.sender, "There should be only one owner";
- }
- // STATUS - verified
- // Check that isApprovedForAll() revertes in planned scenarios and no more.
- rule approvalRevertCases(env e){
- address account; address operator;
- isApprovedForAll@withrevert(account, operator);
- assert !lastReverted, "Houston, we have a problem";
- }
- // STATUS - verified
- // setApproval changes only one approval
- rule onlyOneAllowanceChange(method f, env e) {
- address owner; address operator; address user;
- bool approved;
- bool userApproveBefore = isApprovedForAll(owner, user);
- setApprovalForAll(e, operator, approved);
- bool userApproveAfter = isApprovedForAll(owner, user);
- assert userApproveBefore != userApproveAfter => (e.msg.sender == owner && operator == user), "Imposter!";
- }
- /////////////////////////////////////////////////
- // Balance (3/3)
- /////////////////////////////////////////////////
- // STATUS - verified
- // Function $f, which is not one of transfers, mints and burns, should not change balanceOf of a user
- rule unexpectedBalanceChange(method f, env e)
- filtered { f -> f.selector != safeTransferFrom(address, address, uint256, uint256, bytes).selector
- && f.selector != safeBatchTransferFrom(address, address, uint256[], uint256[], bytes).selector
- && f.selector != mint(address, uint256, uint256, bytes).selector
- && f.selector != mintBatch(address, uint256[], uint256[], bytes).selector
- && f.selector != burn(address, uint256, uint256).selector
- && f.selector != burnBatch(address, uint256[], uint256[]).selector } {
- address from; uint256 id;
- uint256 balanceBefore = balanceOf(from, id);
- calldataarg args;
- f(e, args);
- uint256 balanceAfter = balanceOf(from, id);
- assert balanceBefore == balanceAfter, "How you dare to take my money?";
- }
- // STATUS - verified
- // Check that `balanceOf()` revertes in planned scenarios and no more (only if `account` is 0)
- rule balanceOfRevertCases(env e){
- address account; uint256 id;
- balanceOf@withrevert(account, id);
- assert lastReverted => account == 0, "Houston, we have a problem";
- }
- // STATUS - verified
- // Check that `balanceOfBatch()` revertes in planned scenarios and no more (only if at least one of `account`s is 0)
- rule balanceOfBatchRevertCases(env e){
- address[] accounts; uint256[] ids;
- address account1; address account2; address account3;
- uint256 id1; uint256 id2; uint256 id3;
- require accounts.length == 3;
- require ids.length == 3;
- require accounts[0] == account1; require accounts[1] == account2; require accounts[2] == account3;
- balanceOfBatch@withrevert(accounts, ids);
- assert lastReverted => (account1 == 0 || account2 == 0 || account3 == 0), "Houston, we have a problem";
- }
- /////////////////////////////////////////////////
- // Transfer (13/13)
- /////////////////////////////////////////////////
- // STATUS - verified
- // transfer additivity
- rule transferAdditivity(env e){
- address from; address to; uint256 id; bytes data;
- uint256 amount; uint256 amount1; uint256 amount2;
- require amount == amount1 + amount2;
- storage initialStorage = lastStorage;
- safeTransferFrom(e, from, to, id, amount, data);
- uint256 balanceAfterSingleTransaction = balanceOf(to, id);
- safeTransferFrom(e, from, to, id, amount1, data) at initialStorage;
- safeTransferFrom(e, from, to, id, amount2, data);
- uint256 balanceAfterDoubleTransaction = balanceOf(to, id);
- assert balanceAfterSingleTransaction == balanceAfterDoubleTransaction, "Not additive";
- }
- // STATUS - verified
- // safeTransferFrom updates `from` and `to` balances
- rule transferCorrectness(env e){
- address from; address to; uint256 id; uint256 amount; bytes data;
- require to != from;
- uint256 fromBalanceBefore = balanceOf(from, id);
- uint256 toBalanceBefore = balanceOf(to, id);
- safeTransferFrom(e, from, to, id, amount, data);
- uint256 fromBalanceAfter = balanceOf(from, id);
- uint256 toBalanceAfter = balanceOf(to, id);
- assert fromBalanceBefore == fromBalanceAfter + amount, "Something wet wrong";
- assert toBalanceBefore == toBalanceAfter - amount, "Something wet wrong";
- }
- // STATUS - verified
- // safeBatchTransferFrom updates `from` and `to` balances)
- rule transferBatchCorrectness(env e){
- address from; address to; uint256[] ids; uint256[] amounts; bytes data;
- uint256 idToCheck1; uint256 amountToCheck1;
- uint256 idToCheck2; uint256 amountToCheck2;
- uint256 idToCheck3; uint256 amountToCheck3;
- require to != from;
- require idToCheck1 != idToCheck2 && idToCheck3 != idToCheck2 && idToCheck1 != idToCheck3;
- require ids.length == 3;
- require amounts.length == 3;
- require ids[0] == idToCheck1; require amounts[0] == amountToCheck1;
- require ids[1] == idToCheck2; require amounts[1] == amountToCheck2;
- require ids[2] == idToCheck3; require amounts[2] == amountToCheck3;
- uint256 fromBalanceBefore1 = balanceOf(from, idToCheck1);
- uint256 fromBalanceBefore2 = balanceOf(from, idToCheck2);
- uint256 fromBalanceBefore3 = balanceOf(from, idToCheck3);
- uint256 toBalanceBefore1 = balanceOf(to, idToCheck1);
- uint256 toBalanceBefore2 = balanceOf(to, idToCheck2);
- uint256 toBalanceBefore3 = balanceOf(to, idToCheck3);
- safeBatchTransferFrom(e, from, to, ids, amounts, data);
- uint256 fromBalanceAfter1 = balanceOf(from, idToCheck1);
- uint256 fromBalanceAfter2 = balanceOf(from, idToCheck2);
- uint256 fromBalanceAfter3 = balanceOf(from, idToCheck3);
- uint256 toBalanceAfter1 = balanceOf(to, idToCheck1);
- uint256 toBalanceAfter2 = balanceOf(to, idToCheck2);
- uint256 toBalanceAfter3 = balanceOf(to, idToCheck3);
- assert (fromBalanceBefore1 == fromBalanceAfter1 + amountToCheck1)
- && (fromBalanceBefore2 == fromBalanceAfter2 + amountToCheck2)
- && (fromBalanceBefore3 == fromBalanceAfter3 + amountToCheck3), "Something wet wrong";
- assert (toBalanceBefore1 == toBalanceAfter1 - amountToCheck1)
- && (toBalanceBefore2 == toBalanceAfter2 - amountToCheck2)
- && (toBalanceBefore3 == toBalanceAfter3 - amountToCheck3), "Something wet wrong";
- }
- // STATUS - verified
- // cannot transfer more than `from` balance (safeTransferFrom version)
- rule cannotTransferMoreSingle(env e){
- address from; address to; uint256 id; uint256 amount; bytes data;
- uint256 balanceBefore = balanceOf(from, id);
- safeTransferFrom@withrevert(e, from, to, id, amount, data);
- assert amount > balanceBefore => lastReverted, "Achtung! Scammer!";
- }
- // STATUS - verified
- // cannot transfer more than allowed (safeBatchTransferFrom version)
- rule cannotTransferMoreBatch(env e){
- address from; address to; uint256[] ids; uint256[] amounts; bytes data;
- uint256 idToCheck1; uint256 amountToCheck1;
- uint256 idToCheck2; uint256 amountToCheck2;
- uint256 idToCheck3; uint256 amountToCheck3;
- uint256 balanceBefore1 = balanceOf(from, idToCheck1);
- uint256 balanceBefore2 = balanceOf(from, idToCheck2);
- uint256 balanceBefore3 = balanceOf(from, idToCheck3);
- require ids.length == 3;
- require amounts.length == 3;
- require ids[0] == idToCheck1; require amounts[0] == amountToCheck1;
- require ids[1] == idToCheck2; require amounts[1] == amountToCheck2;
- require ids[2] == idToCheck3; require amounts[2] == amountToCheck3;
- safeBatchTransferFrom@withrevert(e, from, to, ids, amounts, data);
- assert (amountToCheck1 > balanceBefore1 || amountToCheck2 > balanceBefore2 || amountToCheck3 > balanceBefore3) => lastReverted, "Achtung! Scammer!";
- }
- // STATUS - verified
- // Sender calling safeTransferFrom should only reduce 'from' balance and not other's if sending amount is greater than 0
- rule transferBalanceReduceEffect(env e){
- address from; address to; address other;
- uint256 id; uint256 amount;
- bytes data;
- require other != to;
- uint256 otherBalanceBefore = balanceOf(other, id);
- safeTransferFrom(e, from, to, id, amount, data);
- uint256 otherBalanceAfter = balanceOf(other, id);
- assert from != other => otherBalanceBefore == otherBalanceAfter, "Don't touch my money!";
- }
- // STATUS - verified
- // Sender calling safeTransferFrom should only increase 'to' balance and not other's if sending amount is greater than 0
- rule transferBalanceIncreaseEffect(env e){
- address from; address to; address other;
- uint256 id; uint256 amount;
- bytes data;
- require from != other;
- uint256 otherBalanceBefore = balanceOf(other, id);
- safeTransferFrom(e, from, to, id, amount, data);
- uint256 otherBalanceAfter = balanceOf(other, id);
- assert other != to => otherBalanceBefore == otherBalanceAfter, "Don't touch my money!";
- }
- // STATUS - verified
- // Sender calling safeTransferFrom should only reduce 'from' balance and not other's if sending amount is greater than 0
- rule transferBatchBalanceFromEffect(env e){
- address from; address to; address other;
- uint256[] ids; uint256[] amounts;
- uint256 id1; uint256 amount1; uint256 id2; uint256 amount2; uint256 id3; uint256 amount3;
- bytes data;
- require other != to;
- uint256 otherBalanceBefore1 = balanceOf(other, id1);
- uint256 otherBalanceBefore2 = balanceOf(other, id2);
- uint256 otherBalanceBefore3 = balanceOf(other, id3);
- safeBatchTransferFrom(e, from, to, ids, amounts, data);
- uint256 otherBalanceAfter1 = balanceOf(other, id1);
- uint256 otherBalanceAfter2 = balanceOf(other, id2);
- uint256 otherBalanceAfter3 = balanceOf(other, id3);
- assert from != other => (otherBalanceBefore1 == otherBalanceAfter1
- && otherBalanceBefore2 == otherBalanceAfter2
- && otherBalanceBefore3 == otherBalanceAfter3), "Don't touch my money!";
- }
- // STATUS - verified
- // Sender calling safeBatchTransferFrom should only increase 'to' balance and not other's if sending amount is greater than 0
- rule transferBatchBalanceToEffect(env e){
- address from; address to; address other;
- uint256[] ids; uint256[] amounts;
- uint256 id1; uint256 amount1; uint256 id2; uint256 amount2; uint256 id3; uint256 amount3;
- bytes data;
- require other != from;
- uint256 otherBalanceBefore1 = balanceOf(other, id1);
- uint256 otherBalanceBefore2 = balanceOf(other, id2);
- uint256 otherBalanceBefore3 = balanceOf(other, id3);
- safeBatchTransferFrom(e, from, to, ids, amounts, data);
- uint256 otherBalanceAfter1 = balanceOf(other, id1);
- uint256 otherBalanceAfter2 = balanceOf(other, id2);
- uint256 otherBalanceAfter3 = balanceOf(other, id3);
- assert other != to => (otherBalanceBefore1 == otherBalanceAfter1
- && otherBalanceBefore2 == otherBalanceAfter2
- && otherBalanceBefore3 == otherBalanceAfter3), "Don't touch my money!";
- }
- // STATUS - verified
- // cannot transfer without approval (safeTransferFrom version)
- rule noTransferForNotApproved(env e) {
- address from; address operator;
- address to; uint256 id; uint256 amount; bytes data;
- require from != e.msg.sender;
- bool approve = isApprovedForAll(from, e.msg.sender);
- safeTransferFrom@withrevert(e, from, to, id, amount, data);
- assert !approve => lastReverted, "You don't have king's approval!";
- }
- // STATUS - verified
- // cannot transfer without approval (safeBatchTransferFrom version)
- rule noTransferBatchForNotApproved(env e) {
- address from; address operator; address to;
- bytes data;
- uint256[] ids; uint256[] amounts;
- require from != e.msg.sender;
- bool approve = isApprovedForAll(from, e.msg.sender);
- safeBatchTransferFrom@withrevert(e, from, to, ids, amounts, data);
- assert !approve => lastReverted, "You don't have king's approval!";
- }
- // STATUS - verified
- // safeTransferFrom doesn't affect any approval
- rule noTransferEffectOnApproval(env e){
- address from; address to;
- address owner; address operator;
- uint256 id; uint256 amount;
- bytes data;
- bool approveBefore = isApprovedForAll(owner, operator);
- safeTransferFrom(e, from, to, id, amount, data);
- bool approveAfter = isApprovedForAll(owner, operator);
- assert approveBefore == approveAfter, "Something was effected";
- }
- // STATUS - verified
- // safeTransferFrom doesn't affect any approval
- rule noTransferBatchEffectOnApproval(env e){
- address from; address to;
- address owner; address operator;
- uint256[] ids; uint256[] amounts;
- bytes data;
- bool approveBefore = isApprovedForAll(owner, operator);
- safeBatchTransferFrom(e, from, to, ids, amounts, data);
- bool approveAfter = isApprovedForAll(owner, operator);
- assert approveBefore == approveAfter, "Something was effected";
- }
- /////////////////////////////////////////////////
- // Mint (7/9)
- /////////////////////////////////////////////////
- // STATUS - verified
- // Additivity of mint: mint(a); mint(b) has same effect as mint(a+b)
- rule mintAdditivity(env e){
- address to; uint256 id; uint256 amount; uint256 amount1; uint256 amount2; bytes data;
- require amount == amount1 + amount2;
- storage initialStorage = lastStorage;
- mint(e, to, id, amount, data);
- uint256 balanceAfterSingleTransaction = balanceOf(to, id);
- mint(e, to, id, amount1, data) at initialStorage;
- mint(e, to, id, amount2, data);
- uint256 balanceAfterDoubleTransaction = balanceOf(to, id);
- assert balanceAfterSingleTransaction == balanceAfterDoubleTransaction, "Not additive";
- }
- // STATUS - verified
- // Check that `mint()` revertes in planned scenario(s) (only if `to` is 0)
- rule mintRevertCases(env e){
- address to; uint256 id; uint256 amount; bytes data;
- mint@withrevert(e, to, id, amount, data);
- assert to == 0 => lastReverted, "Should revert";
- }
- // STATUS - verified
- // Check that `mintBatch()` revertes in planned scenario(s) (only if `to` is 0 or arrays have different length)
- rule mintBatchRevertCases(env e){
- address to; uint256[] ids; uint256[] amounts; bytes data;
- require ids.length < 1000000000;
- require amounts.length < 1000000000;
- mintBatch@withrevert(e, to, ids, amounts, data);
- assert (ids.length != amounts.length || to == 0) => lastReverted, "Should revert";
- }
- // STATUS - verified
- // Check that mint updates `to` balance correctly
- rule mintCorrectWork(env e){
- address to; uint256 id; uint256 amount; bytes data;
- uint256 otherBalanceBefore = balanceOf(to, id);
- mint(e, to, id, amount, data);
- uint256 otherBalanceAfter = balanceOf(to, id);
- assert otherBalanceBefore == otherBalanceAfter - amount, "Something is wrong";
- }
- // STATUS - verified
- // check that mintBatch updates `bootcamp participantsfrom` balance correctly
- rule mintBatchCorrectWork(env e){
- address to;
- uint256 id1; uint256 id2; uint256 id3;
- uint256 amount1; uint256 amount2; uint256 amount3;
- uint256[] ids; uint256[] amounts;
- bytes data;
- require ids.length == 3;
- require amounts.length == 3;
- require id1 != id2 && id2 != id3 && id3 != id1;
- require ids[0] == id1; require ids[1] == id2; require ids[2] == id3;
- require amounts[0] == amount1; require amounts[1] == amount2; require amounts[2] == amount3;
- uint256 otherBalanceBefore1 = balanceOf(to, id1);
- uint256 otherBalanceBefore2 = balanceOf(to, id2);
- uint256 otherBalanceBefore3 = balanceOf(to, id3);
- mintBatch(e, to, ids, amounts, data);
- uint256 otherBalanceAfter1 = balanceOf(to, id1);
- uint256 otherBalanceAfter2 = balanceOf(to, id2);
- uint256 otherBalanceAfter3 = balanceOf(to, id3);
- assert otherBalanceBefore1 == otherBalanceAfter1 - amount1
- && otherBalanceBefore2 == otherBalanceAfter2 - amount2
- && otherBalanceBefore3 == otherBalanceAfter3 - amount3
- , "Something is wrong";
- }
- // STATUS - verified
- // The user cannot mint more than max_uint256
- rule cantMintMoreSingle(env e){
- address to; uint256 id; uint256 amount; bytes data;
- require to_mathint(balanceOf(to, id) + amount) > max_uint256;
- mint@withrevert(e, to, id, amount, data);
- assert lastReverted, "Don't be too greedy!";
- }
- // STATUS - verified
- // the user cannot mint more than max_uint256 (batch version)
- rule cantMintMoreBatch(env e){
- address to; bytes data;
- uint256 id1; uint256 id2; uint256 id3;
- uint256 amount1; uint256 amount2; uint256 amount3;
- uint256[] ids; uint256[] amounts;
- require ids.length == 3;
- require amounts.length == 3;
- require ids[0] == id1; require ids[1] == id2; require ids[2] == id3;
- require amounts[0] == amount1; require amounts[1] == amount2; require amounts[2] == amount3;
- require to_mathint(balanceOf(to, id1) + amount1) > max_uint256
- || to_mathint(balanceOf(to, id2) + amount2) > max_uint256
- || to_mathint(balanceOf(to, id3) + amount3) > max_uint256;
- mintBatch@withrevert(e, to, ids, amounts, data);
- assert lastReverted, "Don't be too greedy!";
- }
- // STATUS - verified
- // `mint()` changes only `to` balance
- rule cantMintOtherBalances(env e){
- address to; uint256 id; uint256 amount; bytes data;
- address other;
- uint256 otherBalanceBefore = balanceOf(other, id);
- mint(e, to, id, amount, data);
- uint256 otherBalanceAfter = balanceOf(other, id);
- assert other != to => otherBalanceBefore == otherBalanceAfter, "I like to see your money disappearing";
- }
- // STATUS - verified
- // mintBatch changes only `to` balance
- rule cantMintBatchOtherBalances(env e){
- address to;
- uint256 id1; uint256 id2; uint256 id3;
- uint256[] ids; uint256[] amounts;
- address other;
- bytes data;
- uint256 otherBalanceBefore1 = balanceOf(other, id1);
- uint256 otherBalanceBefore2 = balanceOf(other, id2);
- uint256 otherBalanceBefore3 = balanceOf(other, id3);
- mintBatch(e, to, ids, amounts, data);
- uint256 otherBalanceAfter1 = balanceOf(other, id1);
- uint256 otherBalanceAfter2 = balanceOf(other, id2);
- uint256 otherBalanceAfter3 = balanceOf(other, id3);
- assert other != to => (otherBalanceBefore1 == otherBalanceAfter1
- && otherBalanceBefore2 == otherBalanceAfter2
- && otherBalanceBefore3 == otherBalanceAfter3)
- , "I like to see your money disappearing";
- }
- /////////////////////////////////////////////////
- // Burn (9/9)
- /////////////////////////////////////////////////
- // STATUS - verified
- // Additivity of burn: burn(a); burn(b) has same effect as burn(a+b)
- rule burnAdditivity(env e){
- address from; uint256 id; uint256 amount; uint256 amount1; uint256 amount2;
- require amount == amount1 + amount2;
- storage initialStorage = lastStorage;
- burn(e, from, id, amount);
- uint256 balanceAfterSingleTransaction = balanceOf(from, id);
- burn(e, from, id, amount1) at initialStorage;
- burn(e, from, id, amount2);
- uint256 balanceAfterDoubleTransaction = balanceOf(from, id);
- assert balanceAfterSingleTransaction == balanceAfterDoubleTransaction, "Not additive";
- }
- // STATUS - verified
- // Check that `burn()` revertes in planned scenario(s) (if `from` is 0)
- rule burnRevertCases(env e){
- address from; uint256 id; uint256 amount;
- burn@withrevert(e, from, id, amount);
- assert from == 0 => lastReverted, "Should revert";
- }
- // STATUS - verified
- // Check that `balanceOf()` revertes in planned scenario(s) (if `from` is 0 or arrays have different length)
- rule burnBatchRevertCases(env e){
- address from; uint256[] ids; uint256[] amounts;
- require ids.length < 1000000000;
- require amounts.length < 1000000000;
- burnBatch@withrevert(e, from, ids, amounts);
- assert (from == 0 || ids.length != amounts.length) => lastReverted, "Should revert";
- }
- // STATUS - verified
- // check that burn updates `from` balance correctly
- rule burnCorrectWork(env e){
- address from; uint256 id; uint256 amount;
- uint256 otherBalanceBefore = balanceOf(from, id);
- burn(e, from, id, amount);
- uint256 otherBalanceAfter = balanceOf(from, id);
- assert otherBalanceBefore == otherBalanceAfter + amount, "Something is wrong";
- }
- // STATUS - verified
- // check that burnBatch updates `from` balance correctly
- rule burnBatchCorrectWork(env e){
- address from;
- uint256 id1; uint256 id2; uint256 id3;
- uint256 amount1; uint256 amount2; uint256 amount3;
- uint256[] ids; uint256[] amounts;
- require ids.length == 3;
- require id1 != id2 && id2 != id3 && id3 != id1;
- require ids[0] == id1; require ids[1] == id2; require ids[2] == id3;
- require amounts[0] == amount1; require amounts[1] == amount2; require amounts[2] == amount3;
- uint256 otherBalanceBefore1 = balanceOf(from, id1);
- uint256 otherBalanceBefore2 = balanceOf(from, id2);
- uint256 otherBalanceBefore3 = balanceOf(from, id3);
- burnBatch(e, from, ids, amounts);
- uint256 otherBalanceAfter1 = balanceOf(from, id1);
- uint256 otherBalanceAfter2 = balanceOf(from, id2);
- uint256 otherBalanceAfter3 = balanceOf(from, id3);
- assert otherBalanceBefore1 == otherBalanceAfter1 + amount1
- && otherBalanceBefore2 == otherBalanceAfter2 + amount2
- && otherBalanceBefore3 == otherBalanceAfter3 + amount3
- , "Something is wrong";
- }
- // STATUS - verified
- // the user cannot burn more than they have
- rule cantBurnMoreSingle(env e){
- address from; uint256 id; uint256 amount;
- require to_mathint(balanceOf(from, id) - amount) < 0;
- burn@withrevert(e, from, id, amount);
- assert lastReverted, "Don't be too greedy!";
- }
- // STATUS - verified
- // the user cannot burn more than they have (batch version)
- rule cantBurnMoreBatch(env e){
- address from;
- uint256 id1; uint256 id2; uint256 id3;
- uint256 amount1; uint256 amount2; uint256 amount3;
- uint256[] ids; uint256[] amounts;
- require ids.length == 3;
- require ids[0] == id1; require ids[1] == id2; require ids[2] == id3;
- require amounts[0] == amount1; require amounts[1] == amount2; require amounts[2] == amount3;
- require to_mathint(balanceOf(from, id1) - amount1) < 0
- || to_mathint(balanceOf(from, id2) - amount2) < 0
- || to_mathint(balanceOf(from, id3) - amount3) < 0 ;
- burnBatch@withrevert(e, from, ids, amounts);
- assert lastReverted, "Don't be too greedy!";
- }
- // STATUS - verified
- // burn changes only `from` balance
- rule cantBurnOtherBalances(env e){
- address from; uint256 id; uint256 amount;
- address other;
- uint256 otherBalanceBefore = balanceOf(other, id);
- burn(e, from, id, amount);
- uint256 otherBalanceAfter = balanceOf(other, id);
- assert other != from => otherBalanceBefore == otherBalanceAfter, "I like to see your money disappearing";
- }
- // STATUS - verified
- // burnBatch changes only `from` balance
- rule cantBurnBatchOtherBalances(env e){
- address from;
- uint256 id1; uint256 id2; uint256 id3;
- uint256 amount1; uint256 amount2; uint256 amount3;
- uint256[] ids; uint256[] amounts;
- address other;
- uint256 otherBalanceBefore1 = balanceOf(other, id1);
- uint256 otherBalanceBefore2 = balanceOf(other, id2);
- uint256 otherBalanceBefore3 = balanceOf(other, id3);
- burnBatch(e, from, ids, amounts);
- uint256 otherBalanceAfter1 = balanceOf(other, id1);
- uint256 otherBalanceAfter2 = balanceOf(other, id2);
- uint256 otherBalanceAfter3 = balanceOf(other, id3);
- assert other != from => (otherBalanceBefore1 == otherBalanceAfter1
- && otherBalanceBefore2 == otherBalanceAfter2
- && otherBalanceBefore3 == otherBalanceAfter3)
- , "I like to see your money disappearing";
- }
- /////////////////////////////////////////////////
- // The rules below were added to this base ERC1155 spec as part of a later
- // project with OpenZeppelin covering various ERC1155 extensions.
- /////////////////////////////////////////////////
- /// The result of transferring a single token must be equivalent whether done
- /// via safeTransferFrom or safeBatchTransferFrom.
- rule singleTokenSafeTransferFromSafeBatchTransferFromEquivalence {
- storage beforeTransfer = lastStorage;
- env e;
- address holder; address recipient;
- uint256 token; uint256 transferAmount; bytes data;
- uint256[] tokens; uint256[] transferAmounts;
- mathint holderStartingBalance = balanceOf(holder, token);
- mathint recipientStartingBalance = balanceOf(recipient, token);
- require tokens.length == 1; require transferAmounts.length == 1;
- require tokens[0] == token; require transferAmounts[0] == transferAmount;
- // transferring via safeTransferFrom
- safeTransferFrom(e, holder, recipient, token, transferAmount, data) at beforeTransfer;
- mathint holderSafeTransferFromBalanceChange = holderStartingBalance - balanceOf(holder, token);
- mathint recipientSafeTransferFromBalanceChange = balanceOf(recipient, token) - recipientStartingBalance;
- // transferring via safeBatchTransferFrom
- safeBatchTransferFrom(e, holder, recipient, tokens, transferAmounts, data) at beforeTransfer;
- mathint holderSafeBatchTransferFromBalanceChange = holderStartingBalance - balanceOf(holder, token);
- mathint recipientSafeBatchTransferFromBalanceChange = balanceOf(recipient, token) - recipientStartingBalance;
- assert holderSafeTransferFromBalanceChange == holderSafeBatchTransferFromBalanceChange
- && recipientSafeTransferFromBalanceChange == recipientSafeBatchTransferFromBalanceChange,
- "Transferring a single token via safeTransferFrom or safeBatchTransferFrom must be equivalent";
- }
- /// The results of transferring multiple tokens must be equivalent whether done
- /// separately via safeTransferFrom or together via safeBatchTransferFrom.
- rule multipleTokenSafeTransferFromSafeBatchTransferFromEquivalence {
- storage beforeTransfers = lastStorage;
- env e;
- address holder; address recipient; bytes data;
- uint256 tokenA; uint256 tokenB; uint256 tokenC;
- uint256 transferAmountA; uint256 transferAmountB; uint256 transferAmountC;
- uint256[] tokens; uint256[] transferAmounts;
- mathint holderStartingBalanceA = balanceOf(holder, tokenA);
- mathint holderStartingBalanceB = balanceOf(holder, tokenB);
- mathint holderStartingBalanceC = balanceOf(holder, tokenC);
- mathint recipientStartingBalanceA = balanceOf(recipient, tokenA);
- mathint recipientStartingBalanceB = balanceOf(recipient, tokenB);
- mathint recipientStartingBalanceC = balanceOf(recipient, tokenC);
- require tokens.length == 3; require transferAmounts.length == 3;
- require tokens[0] == tokenA; require transferAmounts[0] == transferAmountA;
- require tokens[1] == tokenB; require transferAmounts[1] == transferAmountB;
- require tokens[2] == tokenC; require transferAmounts[2] == transferAmountC;
- // transferring via safeTransferFrom
- safeTransferFrom(e, holder, recipient, tokenA, transferAmountA, data) at beforeTransfers;
- safeTransferFrom(e, holder, recipient, tokenB, transferAmountB, data);
- safeTransferFrom(e, holder, recipient, tokenC, transferAmountC, data);
- mathint holderSafeTransferFromBalanceChangeA = holderStartingBalanceA - balanceOf(holder, tokenA);
- mathint holderSafeTransferFromBalanceChangeB = holderStartingBalanceB - balanceOf(holder, tokenB);
- mathint holderSafeTransferFromBalanceChangeC = holderStartingBalanceC - balanceOf(holder, tokenC);
- mathint recipientSafeTransferFromBalanceChangeA = balanceOf(recipient, tokenA) - recipientStartingBalanceA;
- mathint recipientSafeTransferFromBalanceChangeB = balanceOf(recipient, tokenB) - recipientStartingBalanceB;
- mathint recipientSafeTransferFromBalanceChangeC = balanceOf(recipient, tokenC) - recipientStartingBalanceC;
- // transferring via safeBatchTransferFrom
- safeBatchTransferFrom(e, holder, recipient, tokens, transferAmounts, data) at beforeTransfers;
- mathint holderSafeBatchTransferFromBalanceChangeA = holderStartingBalanceA - balanceOf(holder, tokenA);
- mathint holderSafeBatchTransferFromBalanceChangeB = holderStartingBalanceB - balanceOf(holder, tokenB);
- mathint holderSafeBatchTransferFromBalanceChangeC = holderStartingBalanceC - balanceOf(holder, tokenC);
- mathint recipientSafeBatchTransferFromBalanceChangeA = balanceOf(recipient, tokenA) - recipientStartingBalanceA;
- mathint recipientSafeBatchTransferFromBalanceChangeB = balanceOf(recipient, tokenB) - recipientStartingBalanceB;
- mathint recipientSafeBatchTransferFromBalanceChangeC = balanceOf(recipient, tokenC) - recipientStartingBalanceC;
- assert holderSafeTransferFromBalanceChangeA == holderSafeBatchTransferFromBalanceChangeA
- && holderSafeTransferFromBalanceChangeB == holderSafeBatchTransferFromBalanceChangeB
- && holderSafeTransferFromBalanceChangeC == holderSafeBatchTransferFromBalanceChangeC
- && recipientSafeTransferFromBalanceChangeA == recipientSafeBatchTransferFromBalanceChangeA
- && recipientSafeTransferFromBalanceChangeB == recipientSafeBatchTransferFromBalanceChangeB
- && recipientSafeTransferFromBalanceChangeC == recipientSafeBatchTransferFromBalanceChangeC,
- "Transferring multiple tokens via safeTransferFrom or safeBatchTransferFrom must be equivalent";
- }
- /// If transfer methods do not revert, the input arrays must be the same length.
- rule transfersHaveSameLengthInputArrays {
- env e;
- address recipient; bytes data;
- uint256[] tokens; uint256[] transferAmounts;
- uint max_int = 0xffffffffffffffffffffffffffffffff;
- require tokens.length >= 0 && tokens.length <= max_int;
- require transferAmounts.length >= 0 && transferAmounts.length <= max_int;
- safeBatchTransferFrom(e, _, recipient, tokens, transferAmounts, data);
- uint256 tokensLength = tokens.length;
- uint256 transferAmountsLength = transferAmounts.length;
- assert tokens.length == transferAmounts.length,
- "If transfer methods do not revert, the input arrays must be the same length";
- }
|