ERC1155.spec 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  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
  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. // Set approval 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
  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
  94. /////////////////////////////////////////////////
  95. // STATUS -
  96. // cannot transfer more than `from` balance (safeTransferFrom version)
  97. rule cannotTransferMoreSingle(env e){
  98. address from; address to; uint256 id; uint256 amount; bytes data;
  99. uint256 balanceBefore = balanceOf(from, id);
  100. safeTransferFrom@withrevert(e, from, to, id, amount, data);
  101. assert amount > balanceBefore => lastReverted, "Achtung! Scammer!";
  102. assert to == 0 => lastReverted, "Achtung! Scammer!";
  103. }
  104. // STATUS -
  105. // cannot transfer more than allowed (safeBatchTransferFrom version)
  106. rule cannotTransferMoreBatch(env e){
  107. address from; address to; uint256[] ids; uint256[] amounts; bytes data;
  108. uint256 idToCheck1; uint256 amountToCheck1;
  109. uint256 idToCheck2; uint256 amountToCheck2;
  110. uint256 idToCheck3; uint256 amountToCheck3;
  111. uint256 balanceBefore1 = balanceOf(from, idToCheck1);
  112. uint256 balanceBefore2 = balanceOf(from, idToCheck2);
  113. uint256 balanceBefore3 = balanceOf(from, idToCheck3);
  114. require ids.length == 3;
  115. require amounts.length == 3;
  116. require ids[0] == idToCheck1; require amounts[0] == amountToCheck1;
  117. require ids[1] == idToCheck2; require amounts[1] == amountToCheck2;
  118. require ids[2] == idToCheck3; require amounts[2] == amountToCheck3;
  119. safeBatchTransferFrom@withrevert(e, from, to, ids, amounts, data);
  120. assert (amountToCheck1 > balanceBefore1 || amountToCheck2 > balanceBefore2 || amountToCheck2 > balanceBefore2) => lastReverted, "Achtung! Scammer!";
  121. }
  122. // STATUS - (added debug vars)
  123. // safeBatchTransferFrom should revert if `to` is 0 address or if arrays length is different
  124. rule revertOfTransferBatch(env e){
  125. address from; address to; uint256[] ids; uint256[] amounts; bytes data;
  126. uint256 idTMP = ids.length;
  127. uint256 amountsTMP = amounts.length;
  128. safeBatchTransferFrom@withrevert(e, from, to, ids, amounts, data);
  129. assert ids.length != amounts.length => lastReverted, "Achtung! Scammer!";
  130. assert to == 0 => lastReverted, "Achtung! Scammer!";
  131. }
  132. // STATUS - verified
  133. // Sender calling safeTransferFrom should only reduce 'from' balance and not other's if sending amount is greater than 0
  134. rule transferBalanceReduceEffect(env e){
  135. address from; address to; address other;
  136. uint256 id; uint256 amount;
  137. bytes data;
  138. require other != to;
  139. require amount > 0;
  140. uint256 otherBalanceBefore = balanceOf(other, id);
  141. safeTransferFrom(e, from, to, id, amount, data);
  142. uint256 otherBalanceAfter = balanceOf(other, id);
  143. assert from != other => otherBalanceBefore == otherBalanceAfter, "Don't touch my money!";
  144. }
  145. // STATUS -
  146. // Sender calling safeTransferFrom should only reduce 'to' balance and not other's if sending amount is greater than 0
  147. rule transferBalanceIncreaseEffect(env e){
  148. address from; address to; address other;
  149. uint256 id; uint256 amount;
  150. bytes data;
  151. require from != other;
  152. uint256 otherBalanceBefore = balanceOf(other, id);
  153. safeTransferFrom(e, from, to, id, amount, data);
  154. uint256 otherBalanceAfter = balanceOf(other, id);
  155. assert other != to => otherBalanceBefore == otherBalanceAfter, "Don't touch my money!";
  156. }
  157. // STATUS -
  158. // Sender calling safeTransferFrom should only reduce 'from' balance and not other's if sending amount is greater than 0
  159. rule transferBatchBalanceFromEffect(env e){
  160. address from; address to; address other;
  161. uint256[] ids; uint256[] amounts;
  162. uint256 id1; uint256 amount1; uint256 id2; uint256 amount2; uint256 id3; uint256 amount3;
  163. bytes data;
  164. require other != to;
  165. // require ids.length == 3;
  166. // require amounts.length == 3;
  167. // require ids[0] == id1; require ids[1] == id2; require ids[2] == id3;
  168. // require amounts[0] == amount1; require amounts[1] == amount2; require amounts[2] == amount3;
  169. // require amount1 > 0; require amount2 > 0; require amount3 > 0;
  170. uint256 otherBalanceBefore1 = balanceOf(other, id1);
  171. uint256 otherBalanceBefore2 = balanceOf(other, id2);
  172. uint256 otherBalanceBefore3 = balanceOf(other, id3);
  173. safeBatchTransferFrom(e, from, to, ids, amounts, data);
  174. uint256 otherBalanceAfter1 = balanceOf(other, id1);
  175. uint256 otherBalanceAfter2 = balanceOf(other, id2);
  176. uint256 otherBalanceAfter3 = balanceOf(other, id3);
  177. assert from != other => (otherBalanceBefore1 == otherBalanceAfter1
  178. && otherBalanceBefore2 == otherBalanceAfter2
  179. && otherBalanceBefore3 == otherBalanceAfter3), "Don't touch my money!";
  180. }
  181. // STATUS -
  182. // Sender calling safeBatchTransferFrom should only reduce 'to' balance and not other's if sending amount is greater than 0
  183. rule transferBatchBalanceToEffect(env e){
  184. address from; address to; address other;
  185. uint256[] ids; uint256[] amounts;
  186. uint256 id1; uint256 amount1; uint256 id2; uint256 amount2; uint256 id3; uint256 amount3;
  187. bytes data;
  188. require other != from;
  189. // require ids.length == 3;
  190. // require amounts.length == 3;
  191. // require ids[0] == id1; require ids[1] == id2; require ids[2] == id3;
  192. // require amounts[0] == amount1; require amounts[1] == amount2; require amounts[2] == amount3;
  193. // require amount1 > 0; require amount2 > 0; require amount3 > 0;
  194. uint256 otherBalanceBefore1 = balanceOf(other, id1);
  195. uint256 otherBalanceBefore2 = balanceOf(other, id2);
  196. uint256 otherBalanceBefore3 = balanceOf(other, id3);
  197. safeBatchTransferFrom(e, from, to, ids, amounts, data);
  198. uint256 otherBalanceAfter1 = balanceOf(other, id1);
  199. uint256 otherBalanceAfter2 = balanceOf(other, id2);
  200. uint256 otherBalanceAfter3 = balanceOf(other, id3);
  201. assert other != to => (otherBalanceBefore1 == otherBalanceAfter1
  202. && otherBalanceBefore2 == otherBalanceAfter2
  203. && otherBalanceBefore3 == otherBalanceAfter3), "Don't touch my money!";
  204. }
  205. // STATUS - verified
  206. // cannot transfer without approval (safeTransferFrom version)
  207. rule noTransferForNotApproved(env e) {
  208. address from; address operator;
  209. address to; uint256 id; uint256 amount; bytes data;
  210. require from != e.msg.sender;
  211. bool approve = isApprovedForAll(from, e.msg.sender);
  212. safeTransferFrom@withrevert(e, from, to, id, amount, data);
  213. assert !approve => lastReverted, "You don't have king's approval!";
  214. }
  215. // STATUS -
  216. // cannot transfer without approval (safeBatchTransferFrom version)
  217. rule noTransferBatchForNotApproved(env e) {
  218. address from; address operator; address to;
  219. bytes data;
  220. uint256[] ids; uint256[] amounts;
  221. require from != e.msg.sender;
  222. bool approve = isApprovedForAll(from, e.msg.sender);
  223. safeBatchTransferFrom@withrevert(e, from, to, ids, amounts, data);
  224. assert !approve => lastReverted, "You don't have king's approval!";
  225. }
  226. // STATUS -
  227. // safeTransferFrom doesn't affect any approval
  228. rule noTransferEffectOnApproval(env e){
  229. address from; address to;
  230. address owner; address operator;
  231. uint256 id; uint256 amount;
  232. bytes data;
  233. bool approveBefore = isApprovedForAll(owner, operator);
  234. safeTransferFrom(e, from, to, id, amount, data);
  235. bool approveAfter = isApprovedForAll(owner, operator);
  236. assert approveBefore == approveAfter, "Something was effected";
  237. }
  238. // STATUS -
  239. // safeTransferFrom doesn't affect any approval
  240. rule noTransferBatchEffectOnApproval(env e){
  241. address from; address to;
  242. address owner; address operator;
  243. uint256[] ids; uint256[] amounts;
  244. bytes data;
  245. bool approveBefore = isApprovedForAll(owner, operator);
  246. safeBatchTransferFrom(e, from, to, ids, amounts, data);
  247. bool approveAfter = isApprovedForAll(owner, operator);
  248. assert approveBefore == approveAfter, "Something was effected";
  249. }
  250. /////////////////////////////////////////////////
  251. // Mint
  252. /////////////////////////////////////////////////
  253. // STATUS - verified
  254. // the user cannot mint more than max_uint256
  255. rule cantMintMoreSingle(env e){
  256. address to; uint256 id; uint256 amount; bytes data;
  257. require to_mathint(balanceOf(to, id) + amount) > max_uint256;
  258. _mint@withrevert(e, to, id, amount, data);
  259. assert lastReverted, "Don't be too greedy!";
  260. }
  261. // STATUS - verified
  262. // the user cannot mint more than max_uint256 (batch version)
  263. rule cantMintMoreBatch(env e){
  264. address to; bytes data;
  265. uint256 id1; uint256 id2; uint256 id3;
  266. uint256 amount1; uint256 amount2; uint256 amount3;
  267. uint256[] ids; uint256[] amounts;
  268. require ids.length == 3;
  269. require amounts.length == 3;
  270. require ids[0] == id1; require ids[1] == id2; require ids[2] == id3;
  271. require amounts[0] == amount1; require amounts[1] == amount2; require amounts[2] == amount3;
  272. require to_mathint(balanceOf(to, id1) + amount1) > max_uint256
  273. || to_mathint(balanceOf(to, id2) + amount2) > max_uint256
  274. || to_mathint(balanceOf(to, id3) + amount3) > max_uint256;
  275. _mintBatch@withrevert(e, to, ids, amounts, data);
  276. assert lastReverted, "Don't be too greedy!";
  277. }
  278. // rule mintRevert(env e){
  279. // address operator;
  280. // address from;
  281. // address to;
  282. // uint256 id;
  283. // uint256 amount;
  284. // bytes data;
  285. //
  286. // require operator == e.msg.sender;
  287. // require from == 0;
  288. //
  289. // _doSafeTransferAcceptanceCheck@withrevert(operator, from, to, id, amount, data);
  290. //
  291. // bool acceptanceCheck = lastReverted;
  292. //
  293. // _mint@withrevert(e, to, id, amount, data);
  294. //
  295. // bool mintRevert = lastReverted;
  296. //
  297. // assert acceptanceCheck => mintRevert, "reverts are wrong";
  298. // }
  299. /////////////////////////////////////////////////
  300. // Burn
  301. /////////////////////////////////////////////////
  302. // STATUS -
  303. // check that burn updates `from` balance correctly
  304. rule burnCorrectWork(env e){
  305. address from; uint256 id; uint256 amount;
  306. uint256 otherBalanceBefore = balanceOf(from, id);
  307. _burn(e, from, id, amount);
  308. uint256 otherBalanceAfter = balanceOf(from, id);
  309. assert otherBalanceBefore == otherBalanceAfter + amount, "Something is wrong";
  310. }
  311. // STATUS -
  312. // check that burnBatch updates `from` balance correctly
  313. rule burnBatchCorrectWork(env e){
  314. address from;
  315. uint256 id1; uint256 id2; uint256 id3;
  316. uint256 amount1; uint256 amount2; uint256 amount3;
  317. uint256[] ids; uint256[] amounts;
  318. require ids.length == 3;
  319. require amounts.length == 3;
  320. require id1 != id2 && id2 != id3 && id3 != id1;
  321. require ids[0] == id1; require ids[1] == id2; require ids[2] == id3;
  322. require amounts[0] == amount1; require amounts[1] == amount2; require amounts[2] == amount3;
  323. uint256 otherBalanceBefore1 = balanceOf(from, id1);
  324. uint256 otherBalanceBefore2 = balanceOf(from, id2);
  325. uint256 otherBalanceBefore3 = balanceOf(from, id3);
  326. _burnBatch(e, from, ids, amounts);
  327. uint256 otherBalanceAfter1 = balanceOf(from, id1);
  328. uint256 otherBalanceAfter2 = balanceOf(from, id2);
  329. uint256 otherBalanceAfter3 = balanceOf(from, id3);
  330. assert otherBalanceBefore1 == otherBalanceAfter1 + amount1
  331. && otherBalanceBefore2 == otherBalanceAfter2 + amount2
  332. && otherBalanceBefore3 == otherBalanceAfter3 + amount3
  333. , "Something is wrong";
  334. }
  335. // STATUS - verified
  336. // the user cannot mint more than max_uint256
  337. rule cantBurnMoreSingle(env e){
  338. address from; uint256 id; uint256 amount;
  339. require to_mathint(balanceOf(from, id) - amount) < 0;
  340. _burn@withrevert(e, from, id, amount);
  341. assert lastReverted, "Don't be too greedy!";
  342. }
  343. // STATUS -
  344. // burn changes only `from` balance
  345. rule cantBurnOtherBalances(env e){
  346. address from; uint256 id; uint256 amount;
  347. address other;
  348. uint256 otherBalanceBefore = balanceOf(other, id);
  349. _burn(e, from, id, amount);
  350. uint256 otherBalanceAfter = balanceOf(other, id);
  351. assert other != from => otherBalanceBefore == otherBalanceAfter, "I like to see your money disappearing";
  352. }
  353. // STATUS - verified
  354. // the user cannot mint more than max_uint256 (batch version)
  355. rule cantBurnMoreBatch(env e){
  356. address from;
  357. uint256 id1; uint256 id2; uint256 id3;
  358. uint256 amount1; uint256 amount2; uint256 amount3;
  359. uint256[] ids; uint256[] amounts;
  360. require ids.length == 3;
  361. require ids[0] == id1; require ids[1] == id2; require ids[2] == id3;
  362. require amounts[0] == amount1; require amounts[1] == amount2; require amounts[2] == amount3;
  363. require to_mathint(balanceOf(from, id1) - amount1) < 0
  364. || to_mathint(balanceOf(from, id2) - amount2) < 0
  365. || to_mathint(balanceOf(from, id3) - amount3) < 0 ;
  366. _burnBatch@withrevert(e, from, ids, amounts);
  367. assert lastReverted, "Don't be too greedy!";
  368. }
  369. // STATUS -
  370. // burnBatch changes only `from` balance
  371. rule cantBurnbatchOtherBalances(env e){
  372. address from;
  373. uint256 id1; uint256 id2; uint256 id3;
  374. uint256 amount1; uint256 amount2; uint256 amount3;
  375. uint256[] ids; uint256[] amounts;
  376. address other;
  377. require ids.length == 3;
  378. require amounts.length == 3;
  379. require ids[0] == id1; require ids[1] == id2; require ids[2] == id3;
  380. require amounts[0] == amount1; require amounts[1] == amount2; require amounts[2] == amount3;
  381. uint256 otherBalanceBefore1 = balanceOf(other, id1);
  382. uint256 otherBalanceBefore2 = balanceOf(other, id2);
  383. uint256 otherBalanceBefore3 = balanceOf(other, id3);
  384. _burnBatch(e, from, ids, amounts);
  385. uint256 otherBalanceAfter1 = balanceOf(other, id1);
  386. uint256 otherBalanceAfter2 = balanceOf(other, id2);
  387. uint256 otherBalanceAfter3 = balanceOf(other, id3);
  388. assert other != from => (otherBalanceBefore1 == otherBalanceAfter1
  389. || otherBalanceBefore2 == otherBalanceAfter2
  390. || otherBalanceBefore3 == otherBalanceAfter3)
  391. , "I like to see your money disappearing";
  392. }