ERC1155.spec 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772
  1. methods {
  2. isApprovedForAll(address, address) returns(bool) envfree
  3. balanceOf(address, uint256) returns(uint256) envfree
  4. balanceOfBatch(address[], uint256[]) returns(uint256[]) envfree
  5. _doSafeBatchTransferAcceptanceCheck(address, address, address, uint256[], uint256[], bytes) envfree
  6. _doSafeTransferAcceptanceCheck(address, address, address, uint256, uint256, bytes) envfree
  7. setApprovalForAll(address, bool)
  8. safeTransferFrom(address, address, uint256, uint256, bytes)
  9. safeBatchTransferFrom(address, address, uint256[], uint256[], bytes)
  10. _mint(address, uint256, uint256, bytes)
  11. _mintBatch(address, uint256[], uint256[], bytes)
  12. _burn(address, uint256, uint256)
  13. _burnBatch(address, uint256[], uint256[])
  14. }
  15. /////////////////////////////////////////////////
  16. // Approval (4/4)
  17. /////////////////////////////////////////////////
  18. // STATUS - verified
  19. // Function $f, which is not setApprovalForAll, should not change approval
  20. rule unexpectedAllowanceChange(method f, env e) filtered { f -> f.selector != setApprovalForAll(address, bool).selector } {
  21. address account; address operator;
  22. bool approveBefore = isApprovedForAll(account, operator);
  23. calldataarg args;
  24. f(e, args);
  25. bool approveAfter = isApprovedForAll(account, operator);
  26. assert approveBefore == approveAfter, "You couldn't get king's approval this way!";
  27. }
  28. // STATUS - verified
  29. // approval can be changed only by owner
  30. rule onlyOwnerCanApprove(env e){
  31. address owner; address operator; bool approved;
  32. bool aprovalBefore = isApprovedForAll(owner, operator);
  33. setApprovalForAll(e, operator, approved);
  34. bool aprovalAfter = isApprovedForAll(owner, operator);
  35. assert aprovalBefore != aprovalAfter => owner == e.msg.sender, "There should be only one owner";
  36. }
  37. // STATUS - verified
  38. // Chech that isApprovedForAll() revertes in planned scenarios and no more.
  39. rule approvalRevertCases(env e){
  40. address account; address operator;
  41. isApprovedForAll@withrevert(account, operator);
  42. assert !lastReverted, "Houston, we have a problem";
  43. }
  44. // STATUS - verified
  45. // setApproval changes only one approval
  46. rule onlyOneAllowanceChange(method f, env e) {
  47. address owner; address operator; address user;
  48. bool approved;
  49. bool userApproveBefore = isApprovedForAll(owner, user);
  50. setApprovalForAll(e, operator, approved);
  51. bool userApproveAfter = isApprovedForAll(owner, user);
  52. assert userApproveBefore != userApproveAfter => (e.msg.sender == owner && operator == user), "Imposter!";
  53. }
  54. /////////////////////////////////////////////////
  55. // Balance (3/3)
  56. /////////////////////////////////////////////////
  57. // STATUS - verified
  58. // Function $f, which is not one of transfers, mints and burns, should not change balanceOf of a user
  59. rule unexpectedBalanceChange(method f, env e)
  60. filtered { f -> f.selector != safeTransferFrom(address, address, uint256, uint256, bytes).selector
  61. && f.selector != safeBatchTransferFrom(address, address, uint256[], uint256[], bytes).selector
  62. && f.selector != _mint(address, uint256, uint256, bytes).selector
  63. && f.selector != _mintBatch(address, uint256[], uint256[], bytes).selector
  64. && f.selector != _burn(address, uint256, uint256).selector
  65. && f.selector != _burnBatch(address, uint256[], uint256[]).selector
  66. && f.selector != burn(address, uint256, uint256).selector
  67. && f.selector != burnBatch(address, uint256[], uint256[]).selector } {
  68. address from; uint256 id;
  69. uint256 balanceBefore = balanceOf(from, id);
  70. calldataarg args;
  71. f(e, args);
  72. uint256 balanceAfter = balanceOf(from, id);
  73. assert balanceBefore == balanceAfter, "How you dare to take my money?";
  74. }
  75. // STATUS - verified
  76. // Chech that `balanceOf()` revertes in planned scenarios and no more (only if `account` is 0)
  77. rule balanceOfRevertCases(env e){
  78. address account; uint256 id;
  79. balanceOf@withrevert(account, id);
  80. assert lastReverted => account == 0, "Houston, we have a problem";
  81. }
  82. // STATUS - verified
  83. // Chech that `balanceOfBatch()` revertes in planned scenarios and no more (only if at least one of `account`s is 0)
  84. rule balanceOfBatchRevertCases(env e){
  85. address[] accounts; uint256[] ids;
  86. address account1; address account2; address account3;
  87. uint256 id1; uint256 id2; uint256 id3;
  88. require accounts.length == 3;
  89. require ids.length == 3;
  90. require accounts[0] == account1; require accounts[1] == account2; require accounts[2] == account3;
  91. balanceOfBatch@withrevert(accounts, ids);
  92. assert lastReverted => (account1 == 0 || account2 == 0 || account3 == 0), "Houston, we have a problem";
  93. }
  94. /////////////////////////////////////////////////
  95. // Transfer (13/13)
  96. /////////////////////////////////////////////////
  97. // STATUS - verified
  98. // transfer additivity
  99. rule transferAdditivity(env e){
  100. address from; address to; uint256 id; bytes data;
  101. uint256 amount; uint256 amount1; uint256 amount2;
  102. require amount == amount1 + amount2;
  103. storage initialStorage = lastStorage;
  104. safeTransferFrom(e, from, to, id, amount, data);
  105. uint256 balanceAfterSingleTransaction = balanceOf(to, id);
  106. safeTransferFrom(e, from, to, id, amount1, data) at initialStorage;
  107. safeTransferFrom(e, from, to, id, amount2, data);
  108. uint256 balanceAfterDoubleTransaction = balanceOf(to, id);
  109. assert balanceAfterSingleTransaction == balanceAfterDoubleTransaction, "Not additive";
  110. }
  111. // STATUS - verified
  112. // safeTransferFrom updates `from` and `to` balances
  113. rule transferCorrectness(env e){
  114. address from; address to; uint256 id; uint256 amount; bytes data;
  115. require to != from;
  116. uint256 fromBalanceBefore = balanceOf(from, id);
  117. uint256 toBalanceBefore = balanceOf(to, id);
  118. safeTransferFrom(e, from, to, id, amount, data);
  119. uint256 fromBalanceAfter = balanceOf(from, id);
  120. uint256 toBalanceAfter = balanceOf(to, id);
  121. assert fromBalanceBefore == fromBalanceAfter + amount, "Something wet wrong";
  122. assert toBalanceBefore == toBalanceAfter - amount, "Something wet wrong";
  123. }
  124. // STATUS - verified
  125. // safeBatchTransferFrom updates `from` and `to` balances)
  126. rule transferBatchCorrectness(env e){
  127. address from; address to; uint256[] ids; uint256[] amounts; bytes data;
  128. uint256 idToCheck1; uint256 amountToCheck1;
  129. uint256 idToCheck2; uint256 amountToCheck2;
  130. uint256 idToCheck3; uint256 amountToCheck3;
  131. require to != from;
  132. require idToCheck1 != idToCheck2 && idToCheck3 != idToCheck2 && idToCheck1 != idToCheck3;
  133. require ids.length == 3;
  134. require amounts.length == 3;
  135. require ids[0] == idToCheck1; require amounts[0] == amountToCheck1;
  136. require ids[1] == idToCheck2; require amounts[1] == amountToCheck2;
  137. require ids[2] == idToCheck3; require amounts[2] == amountToCheck3;
  138. uint256 fromBalanceBefore1 = balanceOf(from, idToCheck1);
  139. uint256 fromBalanceBefore2 = balanceOf(from, idToCheck2);
  140. uint256 fromBalanceBefore3 = balanceOf(from, idToCheck3);
  141. uint256 toBalanceBefore1 = balanceOf(to, idToCheck1);
  142. uint256 toBalanceBefore2 = balanceOf(to, idToCheck2);
  143. uint256 toBalanceBefore3 = balanceOf(to, idToCheck3);
  144. safeBatchTransferFrom(e, from, to, ids, amounts, data);
  145. uint256 fromBalanceAfter1 = balanceOf(from, idToCheck1);
  146. uint256 fromBalanceAfter2 = balanceOf(from, idToCheck2);
  147. uint256 fromBalanceAfter3 = balanceOf(from, idToCheck3);
  148. uint256 toBalanceAfter1 = balanceOf(to, idToCheck1);
  149. uint256 toBalanceAfter2 = balanceOf(to, idToCheck2);
  150. uint256 toBalanceAfter3 = balanceOf(to, idToCheck3);
  151. assert (fromBalanceBefore1 == fromBalanceAfter1 + amountToCheck1)
  152. && (fromBalanceBefore2 == fromBalanceAfter2 + amountToCheck2)
  153. && (fromBalanceBefore3 == fromBalanceAfter3 + amountToCheck3), "Something wet wrong";
  154. assert (toBalanceBefore1 == toBalanceAfter1 - amountToCheck1)
  155. && (toBalanceBefore2 == toBalanceAfter2 - amountToCheck2)
  156. && (toBalanceBefore3 == toBalanceAfter3 - amountToCheck3), "Something wet wrong";
  157. }
  158. // STATUS - verified
  159. // cannot transfer more than `from` balance (safeTransferFrom version)
  160. rule cannotTransferMoreSingle(env e){
  161. address from; address to; uint256 id; uint256 amount; bytes data;
  162. uint256 balanceBefore = balanceOf(from, id);
  163. safeTransferFrom@withrevert(e, from, to, id, amount, data);
  164. assert amount > balanceBefore => lastReverted, "Achtung! Scammer!";
  165. }
  166. // STATUS - verified
  167. // cannot transfer more than allowed (safeBatchTransferFrom version)
  168. rule cannotTransferMoreBatch(env e){
  169. address from; address to; uint256[] ids; uint256[] amounts; bytes data;
  170. uint256 idToCheck1; uint256 amountToCheck1;
  171. uint256 idToCheck2; uint256 amountToCheck2;
  172. uint256 idToCheck3; uint256 amountToCheck3;
  173. uint256 balanceBefore1 = balanceOf(from, idToCheck1);
  174. uint256 balanceBefore2 = balanceOf(from, idToCheck2);
  175. uint256 balanceBefore3 = balanceOf(from, idToCheck3);
  176. require ids.length == 3;
  177. require amounts.length == 3;
  178. require ids[0] == idToCheck1; require amounts[0] == amountToCheck1;
  179. require ids[1] == idToCheck2; require amounts[1] == amountToCheck2;
  180. require ids[2] == idToCheck3; require amounts[2] == amountToCheck3;
  181. safeBatchTransferFrom@withrevert(e, from, to, ids, amounts, data);
  182. assert (amountToCheck1 > balanceBefore1 || amountToCheck2 > balanceBefore2 || amountToCheck3 > balanceBefore3) => lastReverted, "Achtung! Scammer!";
  183. }
  184. // STATUS - verified
  185. // Sender calling safeTransferFrom should only reduce 'from' balance and not other's if sending amount is greater than 0
  186. rule transferBalanceReduceEffect(env e){
  187. address from; address to; address other;
  188. uint256 id; uint256 amount;
  189. bytes data;
  190. require other != to;
  191. uint256 otherBalanceBefore = balanceOf(other, id);
  192. safeTransferFrom(e, from, to, id, amount, data);
  193. uint256 otherBalanceAfter = balanceOf(other, id);
  194. assert from != other => otherBalanceBefore == otherBalanceAfter, "Don't touch my money!";
  195. }
  196. // STATUS - verified
  197. // Sender calling safeTransferFrom should only increase 'to' balance and not other's if sending amount is greater than 0
  198. rule transferBalanceIncreaseEffect(env e){
  199. address from; address to; address other;
  200. uint256 id; uint256 amount;
  201. bytes data;
  202. require from != other;
  203. uint256 otherBalanceBefore = balanceOf(other, id);
  204. safeTransferFrom(e, from, to, id, amount, data);
  205. uint256 otherBalanceAfter = balanceOf(other, id);
  206. assert other != to => otherBalanceBefore == otherBalanceAfter, "Don't touch my money!";
  207. }
  208. // STATUS - verified
  209. // Sender calling safeTransferFrom should only reduce 'from' balance and not other's if sending amount is greater than 0
  210. rule transferBatchBalanceFromEffect(env e){
  211. address from; address to; address other;
  212. uint256[] ids; uint256[] amounts;
  213. uint256 id1; uint256 amount1; uint256 id2; uint256 amount2; uint256 id3; uint256 amount3;
  214. bytes data;
  215. require other != to;
  216. uint256 otherBalanceBefore1 = balanceOf(other, id1);
  217. uint256 otherBalanceBefore2 = balanceOf(other, id2);
  218. uint256 otherBalanceBefore3 = balanceOf(other, id3);
  219. safeBatchTransferFrom(e, from, to, ids, amounts, data);
  220. uint256 otherBalanceAfter1 = balanceOf(other, id1);
  221. uint256 otherBalanceAfter2 = balanceOf(other, id2);
  222. uint256 otherBalanceAfter3 = balanceOf(other, id3);
  223. assert from != other => (otherBalanceBefore1 == otherBalanceAfter1
  224. && otherBalanceBefore2 == otherBalanceAfter2
  225. && otherBalanceBefore3 == otherBalanceAfter3), "Don't touch my money!";
  226. }
  227. // STATUS - verified
  228. // Sender calling safeBatchTransferFrom should only increase 'to' balance and not other's if sending amount is greater than 0
  229. rule transferBatchBalanceToEffect(env e){
  230. address from; address to; address other;
  231. uint256[] ids; uint256[] amounts;
  232. uint256 id1; uint256 amount1; uint256 id2; uint256 amount2; uint256 id3; uint256 amount3;
  233. bytes data;
  234. require other != from;
  235. uint256 otherBalanceBefore1 = balanceOf(other, id1);
  236. uint256 otherBalanceBefore2 = balanceOf(other, id2);
  237. uint256 otherBalanceBefore3 = balanceOf(other, id3);
  238. safeBatchTransferFrom(e, from, to, ids, amounts, data);
  239. uint256 otherBalanceAfter1 = balanceOf(other, id1);
  240. uint256 otherBalanceAfter2 = balanceOf(other, id2);
  241. uint256 otherBalanceAfter3 = balanceOf(other, id3);
  242. assert other != to => (otherBalanceBefore1 == otherBalanceAfter1
  243. && otherBalanceBefore2 == otherBalanceAfter2
  244. && otherBalanceBefore3 == otherBalanceAfter3), "Don't touch my money!";
  245. }
  246. // STATUS - verified
  247. // cannot transfer without approval (safeTransferFrom version)
  248. rule noTransferForNotApproved(env e) {
  249. address from; address operator;
  250. address to; uint256 id; uint256 amount; bytes data;
  251. require from != e.msg.sender;
  252. bool approve = isApprovedForAll(from, e.msg.sender);
  253. safeTransferFrom@withrevert(e, from, to, id, amount, data);
  254. assert !approve => lastReverted, "You don't have king's approval!";
  255. }
  256. // STATUS - verified
  257. // cannot transfer without approval (safeBatchTransferFrom version)
  258. rule noTransferBatchForNotApproved(env e) {
  259. address from; address operator; address to;
  260. bytes data;
  261. uint256[] ids; uint256[] amounts;
  262. require from != e.msg.sender;
  263. bool approve = isApprovedForAll(from, e.msg.sender);
  264. safeBatchTransferFrom@withrevert(e, from, to, ids, amounts, data);
  265. assert !approve => lastReverted, "You don't have king's approval!";
  266. }
  267. // STATUS - verified
  268. // safeTransferFrom doesn't affect any approval
  269. rule noTransferEffectOnApproval(env e){
  270. address from; address to;
  271. address owner; address operator;
  272. uint256 id; uint256 amount;
  273. bytes data;
  274. bool approveBefore = isApprovedForAll(owner, operator);
  275. safeTransferFrom(e, from, to, id, amount, data);
  276. bool approveAfter = isApprovedForAll(owner, operator);
  277. assert approveBefore == approveAfter, "Something was effected";
  278. }
  279. // STATUS - verified
  280. // safeTransferFrom doesn't affect any approval
  281. rule noTransferBatchEffectOnApproval(env e){
  282. address from; address to;
  283. address owner; address operator;
  284. uint256[] ids; uint256[] amounts;
  285. bytes data;
  286. bool approveBefore = isApprovedForAll(owner, operator);
  287. safeBatchTransferFrom(e, from, to, ids, amounts, data);
  288. bool approveAfter = isApprovedForAll(owner, operator);
  289. assert approveBefore == approveAfter, "Something was effected";
  290. }
  291. /////////////////////////////////////////////////
  292. // Mint (7/9)
  293. /////////////////////////////////////////////////
  294. // STATUS - verified
  295. // Additivity of _mint: _mint(a); _mint(b) has same effect as _mint(a+b)
  296. rule mintAdditivity(env e){
  297. address to; uint256 id; uint256 amount; uint256 amount1; uint256 amount2; bytes data;
  298. require amount == amount1 + amount2;
  299. storage initialStorage = lastStorage;
  300. _mint(e, to, id, amount, data);
  301. uint256 balanceAfterSingleTransaction = balanceOf(to, id);
  302. _mint(e, to, id, amount1, data) at initialStorage;
  303. _mint(e, to, id, amount2, data);
  304. uint256 balanceAfterDoubleTransaction = balanceOf(to, id);
  305. assert balanceAfterSingleTransaction == balanceAfterDoubleTransaction, "Not additive";
  306. }
  307. // STATUS - verified
  308. // Chech that `_mint()` revertes in planned scenario(s) (only if `to` is 0)
  309. rule mintRevertCases(env e){
  310. address to; uint256 id; uint256 amount; bytes data;
  311. _mint@withrevert(e, to, id, amount, data);
  312. assert to == 0 => lastReverted, "Should revert";
  313. }
  314. // STATUS - verified
  315. // Chech that `_mintBatch()` revertes in planned scenario(s) (only if `to` is 0 or arrays have different length)
  316. rule mintBatchRevertCases(env e){
  317. address to; uint256[] ids; uint256[] amounts; bytes data;
  318. require ids.length < 1000000000;
  319. require amounts.length < 1000000000;
  320. _mintBatch@withrevert(e, to, ids, amounts, data);
  321. assert (ids.length != amounts.length || to == 0) => lastReverted, "Should revert";
  322. }
  323. // STATUS - verified
  324. // Check that mint updates `to` balance correctly
  325. rule mintCorrectWork(env e){
  326. address to; uint256 id; uint256 amount; bytes data;
  327. uint256 otherBalanceBefore = balanceOf(to, id);
  328. _mint(e, to, id, amount, data);
  329. uint256 otherBalanceAfter = balanceOf(to, id);
  330. assert otherBalanceBefore == otherBalanceAfter - amount, "Something is wrong";
  331. }
  332. // STATUS - verified
  333. // check that mintBatch updates `bootcamp participantsfrom` balance correctly
  334. rule mintBatchCorrectWork(env e){
  335. address to;
  336. uint256 id1; uint256 id2; uint256 id3;
  337. uint256 amount1; uint256 amount2; uint256 amount3;
  338. uint256[] ids; uint256[] amounts;
  339. bytes data;
  340. require ids.length == 3;
  341. require amounts.length == 3;
  342. require id1 != id2 && id2 != id3 && id3 != id1;
  343. require ids[0] == id1; require ids[1] == id2; require ids[2] == id3;
  344. require amounts[0] == amount1; require amounts[1] == amount2; require amounts[2] == amount3;
  345. uint256 otherBalanceBefore1 = balanceOf(to, id1);
  346. uint256 otherBalanceBefore2 = balanceOf(to, id2);
  347. uint256 otherBalanceBefore3 = balanceOf(to, id3);
  348. _mintBatch(e, to, ids, amounts, data);
  349. uint256 otherBalanceAfter1 = balanceOf(to, id1);
  350. uint256 otherBalanceAfter2 = balanceOf(to, id2);
  351. uint256 otherBalanceAfter3 = balanceOf(to, id3);
  352. assert otherBalanceBefore1 == otherBalanceAfter1 - amount1
  353. && otherBalanceBefore2 == otherBalanceAfter2 - amount2
  354. && otherBalanceBefore3 == otherBalanceAfter3 - amount3
  355. , "Something is wrong";
  356. }
  357. // STATUS - verified
  358. // The user cannot mint more than max_uint256
  359. rule cantMintMoreSingle(env e){
  360. address to; uint256 id; uint256 amount; bytes data;
  361. require to_mathint(balanceOf(to, id) + amount) > max_uint256;
  362. _mint@withrevert(e, to, id, amount, data);
  363. assert lastReverted, "Don't be too greedy!";
  364. }
  365. // STATUS - verified
  366. // the user cannot mint more than max_uint256 (batch version)
  367. rule cantMintMoreBatch(env e){
  368. address to; bytes data;
  369. uint256 id1; uint256 id2; uint256 id3;
  370. uint256 amount1; uint256 amount2; uint256 amount3;
  371. uint256[] ids; uint256[] amounts;
  372. require ids.length == 3;
  373. require amounts.length == 3;
  374. require ids[0] == id1; require ids[1] == id2; require ids[2] == id3;
  375. require amounts[0] == amount1; require amounts[1] == amount2; require amounts[2] == amount3;
  376. require to_mathint(balanceOf(to, id1) + amount1) > max_uint256
  377. || to_mathint(balanceOf(to, id2) + amount2) > max_uint256
  378. || to_mathint(balanceOf(to, id3) + amount3) > max_uint256;
  379. _mintBatch@withrevert(e, to, ids, amounts, data);
  380. assert lastReverted, "Don't be too greedy!";
  381. }
  382. // STATUS - verified
  383. // `_mint()` changes only `to` balance
  384. rule cantMintOtherBalances(env e){
  385. address to; uint256 id; uint256 amount; bytes data;
  386. address other;
  387. uint256 otherBalanceBefore = balanceOf(other, id);
  388. _mint(e, to, id, amount, data);
  389. uint256 otherBalanceAfter = balanceOf(other, id);
  390. assert other != to => otherBalanceBefore == otherBalanceAfter, "I like to see your money disappearing";
  391. }
  392. // STATUS - verified
  393. // mintBatch changes only `to` balance
  394. rule cantMintBatchOtherBalances(env e){
  395. address to;
  396. uint256 id1; uint256 id2; uint256 id3;
  397. uint256[] ids; uint256[] amounts;
  398. address other;
  399. bytes data;
  400. uint256 otherBalanceBefore1 = balanceOf(other, id1);
  401. uint256 otherBalanceBefore2 = balanceOf(other, id2);
  402. uint256 otherBalanceBefore3 = balanceOf(other, id3);
  403. _mintBatch(e, to, ids, amounts, data);
  404. uint256 otherBalanceAfter1 = balanceOf(other, id1);
  405. uint256 otherBalanceAfter2 = balanceOf(other, id2);
  406. uint256 otherBalanceAfter3 = balanceOf(other, id3);
  407. assert other != to => (otherBalanceBefore1 == otherBalanceAfter1
  408. && otherBalanceBefore2 == otherBalanceAfter2
  409. && otherBalanceBefore3 == otherBalanceAfter3)
  410. , "I like to see your money disappearing";
  411. }
  412. /////////////////////////////////////////////////
  413. // Burn (9/9)
  414. /////////////////////////////////////////////////
  415. // STATUS - verified
  416. // Additivity of _burn: _burn(a); _burn(b) has same effect as _burn(a+b)
  417. rule burnAdditivity(env e){
  418. address from; uint256 id; uint256 amount; uint256 amount1; uint256 amount2;
  419. require amount == amount1 + amount2;
  420. storage initialStorage = lastStorage;
  421. _burn(e, from, id, amount);
  422. uint256 balanceAfterSingleTransaction = balanceOf(from, id);
  423. _burn(e, from, id, amount1) at initialStorage;
  424. _burn(e, from, id, amount2);
  425. uint256 balanceAfterDoubleTransaction = balanceOf(from, id);
  426. assert balanceAfterSingleTransaction == balanceAfterDoubleTransaction, "Not additive";
  427. }
  428. // STATUS - verified
  429. // Chech that `_burn()` revertes in planned scenario(s) (if `from` is 0)
  430. rule burnRevertCases(env e){
  431. address from; uint256 id; uint256 amount;
  432. _burn@withrevert(e, from, id, amount);
  433. assert from == 0 => lastReverted, "Should revert";
  434. }
  435. // STATUS - verified
  436. // Chech that `balanceOf()` revertes in planned scenario(s) (if `from` is 0 or arrays have different length)
  437. rule burnBatchRevertCases(env e){
  438. address from; uint256[] ids; uint256[] amounts;
  439. require ids.length < 1000000000;
  440. require amounts.length < 1000000000;
  441. _burnBatch@withrevert(e, from, ids, amounts);
  442. assert (from == 0 || ids.length != amounts.length) => lastReverted, "Should revert";
  443. }
  444. // STATUS - verified
  445. // check that burn updates `from` balance correctly
  446. rule burnCorrectWork(env e){
  447. address from; uint256 id; uint256 amount;
  448. uint256 otherBalanceBefore = balanceOf(from, id);
  449. _burn(e, from, id, amount);
  450. uint256 otherBalanceAfter = balanceOf(from, id);
  451. assert otherBalanceBefore == otherBalanceAfter + amount, "Something is wrong";
  452. }
  453. // STATUS - verified
  454. // check that burnBatch updates `from` balance correctly
  455. rule burnBatchCorrectWork(env e){
  456. address from;
  457. uint256 id1; uint256 id2; uint256 id3;
  458. uint256 amount1; uint256 amount2; uint256 amount3;
  459. uint256[] ids; uint256[] amounts;
  460. require ids.length == 3;
  461. require id1 != id2 && id2 != id3 && id3 != id1;
  462. require ids[0] == id1; require ids[1] == id2; require ids[2] == id3;
  463. require amounts[0] == amount1; require amounts[1] == amount2; require amounts[2] == amount3;
  464. uint256 otherBalanceBefore1 = balanceOf(from, id1);
  465. uint256 otherBalanceBefore2 = balanceOf(from, id2);
  466. uint256 otherBalanceBefore3 = balanceOf(from, id3);
  467. _burnBatch(e, from, ids, amounts);
  468. uint256 otherBalanceAfter1 = balanceOf(from, id1);
  469. uint256 otherBalanceAfter2 = balanceOf(from, id2);
  470. uint256 otherBalanceAfter3 = balanceOf(from, id3);
  471. assert otherBalanceBefore1 == otherBalanceAfter1 + amount1
  472. && otherBalanceBefore2 == otherBalanceAfter2 + amount2
  473. && otherBalanceBefore3 == otherBalanceAfter3 + amount3
  474. , "Something is wrong";
  475. }
  476. // STATUS - verified
  477. // the user cannot burn more than they have
  478. rule cantBurnMoreSingle(env e){
  479. address from; uint256 id; uint256 amount;
  480. require to_mathint(balanceOf(from, id) - amount) < 0;
  481. _burn@withrevert(e, from, id, amount);
  482. assert lastReverted, "Don't be too greedy!";
  483. }
  484. // STATUS - verified
  485. // the user cannot burn more than they have (batch version)
  486. rule cantBurnMoreBatch(env e){
  487. address from;
  488. uint256 id1; uint256 id2; uint256 id3;
  489. uint256 amount1; uint256 amount2; uint256 amount3;
  490. uint256[] ids; uint256[] amounts;
  491. require ids.length == 3;
  492. require ids[0] == id1; require ids[1] == id2; require ids[2] == id3;
  493. require amounts[0] == amount1; require amounts[1] == amount2; require amounts[2] == amount3;
  494. require to_mathint(balanceOf(from, id1) - amount1) < 0
  495. || to_mathint(balanceOf(from, id2) - amount2) < 0
  496. || to_mathint(balanceOf(from, id3) - amount3) < 0 ;
  497. _burnBatch@withrevert(e, from, ids, amounts);
  498. assert lastReverted, "Don't be too greedy!";
  499. }
  500. // STATUS - verified
  501. // burn changes only `from` balance
  502. rule cantBurnOtherBalances(env e){
  503. address from; uint256 id; uint256 amount;
  504. address other;
  505. uint256 otherBalanceBefore = balanceOf(other, id);
  506. _burn(e, from, id, amount);
  507. uint256 otherBalanceAfter = balanceOf(other, id);
  508. assert other != from => otherBalanceBefore == otherBalanceAfter, "I like to see your money disappearing";
  509. }
  510. // STATUS - verified
  511. // burnBatch changes only `from` balance
  512. rule cantBurnBatchOtherBalances(env e){
  513. address from;
  514. uint256 id1; uint256 id2; uint256 id3;
  515. uint256 amount1; uint256 amount2; uint256 amount3;
  516. uint256[] ids; uint256[] amounts;
  517. address other;
  518. uint256 otherBalanceBefore1 = balanceOf(other, id1);
  519. uint256 otherBalanceBefore2 = balanceOf(other, id2);
  520. uint256 otherBalanceBefore3 = balanceOf(other, id3);
  521. _burnBatch(e, from, ids, amounts);
  522. uint256 otherBalanceAfter1 = balanceOf(other, id1);
  523. uint256 otherBalanceAfter2 = balanceOf(other, id2);
  524. uint256 otherBalanceAfter3 = balanceOf(other, id3);
  525. assert other != from => (otherBalanceBefore1 == otherBalanceAfter1
  526. && otherBalanceBefore2 == otherBalanceAfter2
  527. && otherBalanceBefore3 == otherBalanceAfter3)
  528. , "I like to see your money disappearing";
  529. }