ERC1155.spec 26 KB

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