|
|
|
@ -0,0 +1,563 @@ |
|
|
|
|
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 |
|
|
|
|
///////////////////////////////////////////////// |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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 |
|
|
|
|
// chech in which scenarios (if any) isApprovedForAll() revertes |
|
|
|
|
rule approvalRevertCases(env e){ |
|
|
|
|
address account; address operator; |
|
|
|
|
isApprovedForAll@withrevert(account, operator); |
|
|
|
|
assert !lastReverted, "Houston, we have a problem"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// STATUS - verified |
|
|
|
|
// Set approval 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 |
|
|
|
|
///////////////////////////////////////////////// |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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 |
|
|
|
|
// chech in which scenarios balanceOf() revertes |
|
|
|
|
rule balanceOfRevertCases(env e){ |
|
|
|
|
address account; uint256 id; |
|
|
|
|
balanceOf@withrevert(account, id); |
|
|
|
|
assert lastReverted => account == 0, "Houston, we have a problem"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// STATUS - verified |
|
|
|
|
// chech in which scenarios balanceOfBatch() revertes |
|
|
|
|
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 |
|
|
|
|
///////////////////////////////////////////////// |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// STATUS - |
|
|
|
|
// 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!"; |
|
|
|
|
assert to == 0 => lastReverted, "Achtung! Scammer!"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// STATUS - |
|
|
|
|
// 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 || amountToCheck2 > balanceBefore2) => lastReverted, "Achtung! Scammer!"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// STATUS - (added debug vars) |
|
|
|
|
// safeBatchTransferFrom should revert if `to` is 0 address or if arrays length is different |
|
|
|
|
rule revertOfTransferBatch(env e){ |
|
|
|
|
address from; address to; uint256[] ids; uint256[] amounts; bytes data; |
|
|
|
|
|
|
|
|
|
uint256 idTMP = ids.length; |
|
|
|
|
uint256 amountsTMP = amounts.length; |
|
|
|
|
|
|
|
|
|
safeBatchTransferFrom@withrevert(e, from, to, ids, amounts, data); |
|
|
|
|
|
|
|
|
|
assert ids.length != amounts.length => lastReverted, "Achtung! Scammer!"; |
|
|
|
|
assert to == 0 => 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; |
|
|
|
|
require amount > 0; |
|
|
|
|
|
|
|
|
|
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 - |
|
|
|
|
// Sender calling safeTransferFrom should only reduce '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 - |
|
|
|
|
// 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; |
|
|
|
|
|
|
|
|
|
// 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 amount1 > 0; require amount2 > 0; require amount3 > 0; |
|
|
|
|
|
|
|
|
|
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 - |
|
|
|
|
// Sender calling safeBatchTransferFrom should only reduce '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; |
|
|
|
|
|
|
|
|
|
// 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 amount1 > 0; require amount2 > 0; require amount3 > 0; |
|
|
|
|
|
|
|
|
|
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 - |
|
|
|
|
// 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 - |
|
|
|
|
// 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 - |
|
|
|
|
// 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 |
|
|
|
|
///////////////////////////////////////////////// |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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!"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// rule mintRevert(env e){ |
|
|
|
|
// address operator; |
|
|
|
|
// address from; |
|
|
|
|
// address to; |
|
|
|
|
// uint256 id; |
|
|
|
|
// uint256 amount; |
|
|
|
|
// bytes data; |
|
|
|
|
// |
|
|
|
|
// require operator == e.msg.sender; |
|
|
|
|
// require from == 0; |
|
|
|
|
// |
|
|
|
|
// _doSafeTransferAcceptanceCheck@withrevert(operator, from, to, id, amount, data); |
|
|
|
|
// |
|
|
|
|
// bool acceptanceCheck = lastReverted; |
|
|
|
|
// |
|
|
|
|
// _mint@withrevert(e, to, id, amount, data); |
|
|
|
|
// |
|
|
|
|
// bool mintRevert = lastReverted; |
|
|
|
|
// |
|
|
|
|
// assert acceptanceCheck => mintRevert, "reverts are wrong"; |
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////// |
|
|
|
|
// Burn |
|
|
|
|
///////////////////////////////////////////////// |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// STATUS - |
|
|
|
|
// 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 - |
|
|
|
|
// 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 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(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 mint more than max_uint256 |
|
|
|
|
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 - |
|
|
|
|
// 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 |
|
|
|
|
// the user cannot mint more than max_uint256 (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 - |
|
|
|
|
// 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; |
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
|
|
|
|
|
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"; |
|
|
|
|
} |