Entropy.t.sol 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027
  1. // SPDX-License-Identifier: Apache 2
  2. pragma solidity ^0.8.0;
  3. import "forge-std/Test.sol";
  4. import "@pythnetwork/entropy-sdk-solidity/EntropyStructs.sol";
  5. import "@pythnetwork/entropy-sdk-solidity/EntropyEvents.sol";
  6. import "@pythnetwork/entropy-sdk-solidity/IEntropyConsumer.sol";
  7. import "@pythnetwork/entropy-sdk-solidity/IEntropy.sol";
  8. import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
  9. import "./utils/EntropyTestUtils.t.sol";
  10. import "../contracts/entropy/EntropyUpgradable.sol";
  11. // TODO
  12. // - fuzz test?
  13. contract EntropyTest is Test, EntropyTestUtils, EntropyEvents {
  14. ERC1967Proxy public proxy;
  15. EntropyUpgradable public random;
  16. uint128 pythFeeInWei = 7;
  17. address public provider1 = address(1);
  18. bytes32[] provider1Proofs;
  19. uint128 provider1FeeInWei = 8;
  20. uint64 provider1ChainLength = 100;
  21. bytes provider1Uri = bytes("https://foo.com");
  22. bytes provider1CommitmentMetadata = hex"0100";
  23. address public provider2 = address(2);
  24. bytes32[] provider2Proofs;
  25. uint128 provider2FeeInWei = 20;
  26. bytes provider2Uri = bytes("https://bar.com");
  27. address public user1 = address(3);
  28. address public user2 = address(4);
  29. address public unregisteredProvider = address(7);
  30. uint128 MAX_UINT128 = 2 ** 128 - 1;
  31. bytes32 ALL_ZEROS = bytes32(uint256(0));
  32. address public owner = address(8);
  33. address public admin = address(9);
  34. address public admin2 = address(10);
  35. function setUp() public {
  36. EntropyUpgradable _random = new EntropyUpgradable();
  37. // deploy proxy contract and point it to implementation
  38. proxy = new ERC1967Proxy(address(_random), "");
  39. // wrap in ABI to support easier calls
  40. random = EntropyUpgradable(address(proxy));
  41. random.initialize(owner, admin, pythFeeInWei, provider1, false);
  42. bytes32[] memory hashChain1 = generateHashChain(
  43. provider1,
  44. 0,
  45. provider1ChainLength
  46. );
  47. provider1Proofs = hashChain1;
  48. vm.prank(provider1);
  49. random.register(
  50. provider1FeeInWei,
  51. provider1Proofs[0],
  52. provider1CommitmentMetadata,
  53. provider1ChainLength,
  54. provider1Uri
  55. );
  56. bytes32[] memory hashChain2 = generateHashChain(provider2, 0, 100);
  57. provider2Proofs = hashChain2;
  58. vm.prank(provider2);
  59. random.register(
  60. provider2FeeInWei,
  61. provider2Proofs[0],
  62. hex"0200",
  63. 100,
  64. provider2Uri
  65. );
  66. }
  67. // Test helper method for requesting a random value as user from provider.
  68. function request(
  69. address user,
  70. address provider,
  71. uint randomNumber,
  72. bool useBlockhash
  73. ) public returns (uint64 sequenceNumber) {
  74. sequenceNumber = requestWithFee(
  75. user,
  76. random.getFee(provider),
  77. provider,
  78. randomNumber,
  79. useBlockhash
  80. );
  81. }
  82. function requestWithFee(
  83. address user,
  84. uint fee,
  85. address provider,
  86. uint randomNumber,
  87. bool useBlockhash
  88. ) public returns (uint64 sequenceNumber) {
  89. vm.deal(user, fee);
  90. vm.startPrank(user);
  91. sequenceNumber = random.request{value: fee}(
  92. provider,
  93. random.constructUserCommitment(bytes32(randomNumber)),
  94. useBlockhash
  95. );
  96. vm.stopPrank();
  97. }
  98. function assertRequestReverts(
  99. uint fee,
  100. address provider,
  101. uint randomNumber,
  102. bool useBlockhash
  103. ) public {
  104. // Note: for some reason vm.expectRevert() won't catch errors from the request function (?!),
  105. // even though they definitely revert. Use a try/catch instead for the moment, though the try/catch
  106. // doesn't let you simulate the msg.sender. However, it's fine if the msg.sender is the test contract.
  107. bool requestSucceeds = false;
  108. try
  109. random.request{value: fee}(
  110. provider,
  111. random.constructUserCommitment(bytes32(uint256(randomNumber))),
  112. useBlockhash
  113. )
  114. {
  115. requestSucceeds = true;
  116. } catch {
  117. requestSucceeds = false;
  118. }
  119. assert(!requestSucceeds);
  120. }
  121. function assertRevealSucceeds(
  122. address user,
  123. address provider,
  124. uint64 sequenceNumber,
  125. uint userRandom,
  126. bytes32 providerRevelation,
  127. bytes32 hash
  128. ) public {
  129. vm.prank(user);
  130. bytes32 randomNumber = random.reveal(
  131. provider,
  132. sequenceNumber,
  133. bytes32(userRandom),
  134. providerRevelation
  135. );
  136. assertEq(
  137. randomNumber,
  138. random.combineRandomValues(
  139. bytes32(userRandom),
  140. providerRevelation,
  141. hash
  142. )
  143. );
  144. }
  145. function assertRevealReverts(
  146. address user,
  147. address provider,
  148. uint64 sequenceNumber,
  149. uint userRandom,
  150. bytes32 providerRevelation
  151. ) public {
  152. vm.startPrank(user);
  153. vm.expectRevert();
  154. random.reveal(
  155. provider,
  156. sequenceNumber,
  157. bytes32(uint256(userRandom)),
  158. providerRevelation
  159. );
  160. vm.stopPrank();
  161. }
  162. function assertInvariants() public {
  163. uint expectedBalance = random
  164. .getProviderInfo(provider1)
  165. .accruedFeesInWei +
  166. random.getProviderInfo(provider2).accruedFeesInWei +
  167. random.getAccruedPythFees();
  168. assertEq(address(random).balance, expectedBalance);
  169. EntropyStructs.ProviderInfo memory info1 = random.getProviderInfo(
  170. provider1
  171. );
  172. assert(
  173. info1.originalCommitmentSequenceNumber <=
  174. info1.currentCommitmentSequenceNumber
  175. );
  176. assert(info1.currentCommitmentSequenceNumber < info1.sequenceNumber);
  177. assert(info1.sequenceNumber <= info1.endSequenceNumber);
  178. EntropyStructs.ProviderInfo memory info2 = random.getProviderInfo(
  179. provider2
  180. );
  181. assert(
  182. info2.originalCommitmentSequenceNumber <=
  183. info2.currentCommitmentSequenceNumber
  184. );
  185. assert(info2.sequenceNumber > info2.currentCommitmentSequenceNumber);
  186. assert(info2.sequenceNumber <= info2.endSequenceNumber);
  187. }
  188. function testBasicFlow() public {
  189. vm.roll(17);
  190. uint64 sequenceNumber = request(user2, provider1, 42, false);
  191. assertEq(random.getRequest(provider1, sequenceNumber).blockNumber, 17);
  192. assertEq(
  193. random.getRequest(provider1, sequenceNumber).useBlockhash,
  194. false
  195. );
  196. assertRevealSucceeds(
  197. user2,
  198. provider1,
  199. sequenceNumber,
  200. 42,
  201. provider1Proofs[sequenceNumber],
  202. ALL_ZEROS
  203. );
  204. EntropyStructs.Request memory reqAfterReveal = random.getRequest(
  205. provider1,
  206. sequenceNumber
  207. );
  208. assertEq(reqAfterReveal.sequenceNumber, 0);
  209. // You can only reveal the random number once. This isn't a feature of the contract per se, but it is
  210. // the expected behavior.
  211. assertRevealReverts(
  212. user2,
  213. provider1,
  214. sequenceNumber,
  215. 42,
  216. provider1Proofs[sequenceNumber]
  217. );
  218. }
  219. function testDefaultProvider() public {
  220. vm.roll(20);
  221. uint64 sequenceNumber = request(
  222. user2,
  223. random.getDefaultProvider(),
  224. 42,
  225. false
  226. );
  227. assertEq(random.getRequest(provider1, sequenceNumber).blockNumber, 20);
  228. assertEq(
  229. random.getRequest(provider1, sequenceNumber).useBlockhash,
  230. false
  231. );
  232. assertRevealReverts(
  233. user2,
  234. random.getDefaultProvider(),
  235. sequenceNumber,
  236. 42,
  237. provider2Proofs[sequenceNumber]
  238. );
  239. assertRevealSucceeds(
  240. user2,
  241. random.getDefaultProvider(),
  242. sequenceNumber,
  243. 42,
  244. provider1Proofs[sequenceNumber],
  245. ALL_ZEROS
  246. );
  247. }
  248. function testNoSuchProvider() public {
  249. assertRequestReverts(10000000, unregisteredProvider, 42, false);
  250. }
  251. function testAuthorization() public {
  252. uint64 sequenceNumber = request(user2, provider1, 42, false);
  253. assertEq(random.getRequest(provider1, sequenceNumber).requester, user2);
  254. // user1 not authorized, must be user2.
  255. assertRevealReverts(
  256. user1,
  257. provider1,
  258. sequenceNumber,
  259. 42,
  260. provider1Proofs[sequenceNumber]
  261. );
  262. assertRevealSucceeds(
  263. user2,
  264. provider1,
  265. sequenceNumber,
  266. 42,
  267. provider1Proofs[sequenceNumber],
  268. ALL_ZEROS
  269. );
  270. }
  271. function testAdversarialReveal() public {
  272. uint64 sequenceNumber = request(user2, provider1, 42, false);
  273. // test revealing with the wrong hashes in the same chain
  274. for (uint256 i = 0; i < 10; i++) {
  275. if (i != sequenceNumber) {
  276. assertRevealReverts(
  277. user2,
  278. provider1,
  279. sequenceNumber,
  280. 42,
  281. provider1Proofs[i]
  282. );
  283. }
  284. }
  285. // test revealing with the wrong user revealed value.
  286. for (uint256 i = 0; i < 42; i++) {
  287. assertRevealReverts(
  288. user2,
  289. provider1,
  290. sequenceNumber,
  291. i,
  292. provider1Proofs[sequenceNumber]
  293. );
  294. }
  295. // test revealing sequence numbers that haven't been requested yet.
  296. for (uint64 i = sequenceNumber + 1; i < sequenceNumber + 3; i++) {
  297. assertRevealReverts(
  298. user2,
  299. provider1,
  300. i,
  301. 42,
  302. provider1Proofs[sequenceNumber]
  303. );
  304. assertRevealReverts(user2, provider1, i, 42, provider1Proofs[i]);
  305. }
  306. }
  307. function testConcurrentRequests() public {
  308. uint64 s1 = request(user1, provider1, 1, false);
  309. uint64 s2 = request(user2, provider1, 2, false);
  310. uint64 s3 = request(user1, provider1, 3, false);
  311. uint64 s4 = request(user1, provider1, 4, false);
  312. assertRevealSucceeds(
  313. user1,
  314. provider1,
  315. s3,
  316. 3,
  317. provider1Proofs[s3],
  318. ALL_ZEROS
  319. );
  320. assertInvariants();
  321. uint64 s5 = request(user1, provider1, 5, false);
  322. assertRevealSucceeds(
  323. user1,
  324. provider1,
  325. s4,
  326. 4,
  327. provider1Proofs[s4],
  328. ALL_ZEROS
  329. );
  330. assertInvariants();
  331. assertRevealSucceeds(
  332. user1,
  333. provider1,
  334. s1,
  335. 1,
  336. provider1Proofs[s1],
  337. ALL_ZEROS
  338. );
  339. assertInvariants();
  340. assertRevealSucceeds(
  341. user2,
  342. provider1,
  343. s2,
  344. 2,
  345. provider1Proofs[s2],
  346. ALL_ZEROS
  347. );
  348. assertInvariants();
  349. assertRevealSucceeds(
  350. user1,
  351. provider1,
  352. s5,
  353. 5,
  354. provider1Proofs[s5],
  355. ALL_ZEROS
  356. );
  357. assertInvariants();
  358. }
  359. function testBlockhash() public {
  360. vm.roll(1234);
  361. uint64 sequenceNumber = request(user2, provider1, 42, true);
  362. assertEq(
  363. random.getRequest(provider1, sequenceNumber).blockNumber,
  364. 1234
  365. );
  366. assertEq(
  367. random.getRequest(provider1, sequenceNumber).useBlockhash,
  368. true
  369. );
  370. vm.roll(1235);
  371. assertRevealSucceeds(
  372. user2,
  373. provider1,
  374. sequenceNumber,
  375. 42,
  376. provider1Proofs[sequenceNumber],
  377. blockhash(1234)
  378. );
  379. }
  380. function testNoCheckOnBlockNumberWhenNoBlockHashUsed() public {
  381. vm.roll(1234);
  382. uint64 sequenceNumber = request(user2, provider1, 42, false);
  383. vm.roll(1236);
  384. assertRevealSucceeds(
  385. user2,
  386. provider1,
  387. sequenceNumber,
  388. 42,
  389. provider1Proofs[sequenceNumber],
  390. ALL_ZEROS
  391. );
  392. vm.roll(1234);
  393. sequenceNumber = request(user2, provider1, 42, false);
  394. vm.roll(1234);
  395. assertRevealSucceeds(
  396. user2,
  397. provider1,
  398. sequenceNumber,
  399. 42,
  400. provider1Proofs[sequenceNumber],
  401. ALL_ZEROS
  402. );
  403. vm.roll(1234);
  404. sequenceNumber = request(user2, provider1, 42, false);
  405. vm.roll(1234 + 257);
  406. assertRevealSucceeds(
  407. user2,
  408. provider1,
  409. sequenceNumber,
  410. 42,
  411. provider1Proofs[sequenceNumber],
  412. ALL_ZEROS
  413. );
  414. }
  415. function testCheckOnBlockNumberWhenBlockHashUsed() public {
  416. vm.roll(1234);
  417. uint64 sequenceNumber = request(user2, provider1, 42, true);
  418. vm.roll(1234);
  419. assertRevealReverts(
  420. user2,
  421. provider1,
  422. sequenceNumber,
  423. 42,
  424. provider1Proofs[sequenceNumber]
  425. );
  426. vm.roll(1234 + 257);
  427. assertRevealReverts(
  428. user2,
  429. provider1,
  430. sequenceNumber,
  431. 42,
  432. provider1Proofs[sequenceNumber]
  433. );
  434. vm.roll(1235);
  435. assertRevealSucceeds(
  436. user2,
  437. provider1,
  438. sequenceNumber,
  439. 42,
  440. provider1Proofs[sequenceNumber],
  441. blockhash(1234)
  442. );
  443. }
  444. function testProviderCommitmentRotation() public {
  445. uint userRandom = 42;
  446. uint64 sequenceNumber1 = request(user2, provider1, userRandom, false);
  447. uint64 sequenceNumber2 = request(user2, provider1, userRandom, false);
  448. assertInvariants();
  449. uint64 newHashChainOffset = sequenceNumber2 + 1;
  450. bytes32[] memory newHashChain = generateHashChain(
  451. provider1,
  452. newHashChainOffset,
  453. 10
  454. );
  455. vm.prank(provider1);
  456. random.register(
  457. provider1FeeInWei,
  458. newHashChain[0],
  459. hex"0100",
  460. 10,
  461. provider1Uri
  462. );
  463. assertInvariants();
  464. EntropyStructs.ProviderInfo memory info1 = random.getProviderInfo(
  465. provider1
  466. );
  467. assertEq(info1.endSequenceNumber, newHashChainOffset + 10);
  468. uint64 sequenceNumber3 = request(user2, provider1, 42, false);
  469. // Rotating the provider key uses a sequence number
  470. assertEq(sequenceNumber3, sequenceNumber2 + 2);
  471. // Requests that were in-flight at the time of rotation use the commitment from the time of request
  472. for (uint256 i = 0; i < 10; i++) {
  473. assertRevealReverts(
  474. user2,
  475. provider1,
  476. sequenceNumber1,
  477. userRandom,
  478. newHashChain[i]
  479. );
  480. }
  481. assertRevealSucceeds(
  482. user2,
  483. provider1,
  484. sequenceNumber1,
  485. userRandom,
  486. provider1Proofs[sequenceNumber1],
  487. ALL_ZEROS
  488. );
  489. assertInvariants();
  490. // Requests after the rotation use the new commitment
  491. assertRevealReverts(
  492. user2,
  493. provider1,
  494. sequenceNumber3,
  495. userRandom,
  496. provider1Proofs[sequenceNumber3]
  497. );
  498. assertRevealSucceeds(
  499. user2,
  500. provider1,
  501. sequenceNumber3,
  502. userRandom,
  503. newHashChain[sequenceNumber3 - newHashChainOffset],
  504. ALL_ZEROS
  505. );
  506. assertInvariants();
  507. }
  508. function testOutOfRandomness() public {
  509. // Should be able to request chainLength - 1 random numbers successfully.
  510. for (uint64 i = 0; i < provider1ChainLength - 1; i++) {
  511. request(user1, provider1, i, false);
  512. }
  513. assertRequestReverts(
  514. random.getFee(provider1),
  515. provider1,
  516. provider1ChainLength - 1,
  517. false
  518. );
  519. }
  520. function testGetFee() public {
  521. assertEq(random.getFee(provider1), pythFeeInWei + provider1FeeInWei);
  522. assertEq(random.getFee(provider2), pythFeeInWei + provider2FeeInWei);
  523. // Requesting the fee for a nonexistent provider returns pythFeeInWei. This isn't necessarily desirable behavior,
  524. // but it's unlikely to cause a problem.
  525. assertEq(random.getFee(unregisteredProvider), pythFeeInWei);
  526. // Check that overflowing the fee arithmetic causes the transaction to revert.
  527. vm.prank(provider1);
  528. random.register(
  529. MAX_UINT128,
  530. provider1Proofs[0],
  531. hex"0100",
  532. 100,
  533. provider1Uri
  534. );
  535. vm.expectRevert();
  536. random.getFee(provider1);
  537. }
  538. function testOverflow() public {
  539. // msg.value overflows the uint128 fee variable
  540. assertRequestReverts(2 ** 128, provider1, 42, false);
  541. // block number is too large
  542. vm.roll(2 ** 96);
  543. assertRequestReverts(
  544. pythFeeInWei + provider1FeeInWei,
  545. provider1,
  546. 42,
  547. true
  548. );
  549. }
  550. function testFees() public {
  551. // Insufficient fees causes a revert
  552. assertRequestReverts(0, provider1, 42, false);
  553. assertRequestReverts(
  554. pythFeeInWei + provider1FeeInWei - 1,
  555. provider1,
  556. 42,
  557. false
  558. );
  559. assertRequestReverts(0, provider2, 42, false);
  560. assertRequestReverts(
  561. pythFeeInWei + provider2FeeInWei - 1,
  562. provider2,
  563. 42,
  564. false
  565. );
  566. // Accrue some fees for both providers
  567. for (uint i = 0; i < 3; i++) {
  568. request(user2, provider1, 42, false);
  569. }
  570. request(user2, provider2, 42, false);
  571. // this call overpays for the random number
  572. requestWithFee(
  573. user2,
  574. pythFeeInWei + provider2FeeInWei + 10000,
  575. provider2,
  576. 42,
  577. false
  578. );
  579. assertEq(
  580. random.getProviderInfo(provider1).accruedFeesInWei,
  581. provider1FeeInWei * 3
  582. );
  583. assertEq(
  584. random.getProviderInfo(provider2).accruedFeesInWei,
  585. provider2FeeInWei * 2
  586. );
  587. assertEq(random.getAccruedPythFees(), pythFeeInWei * 5 + 10000);
  588. assertInvariants();
  589. // Reregistering updates the required fees
  590. vm.prank(provider1);
  591. random.register(
  592. 12345,
  593. provider1Proofs[0],
  594. hex"0100",
  595. 100,
  596. provider1Uri
  597. );
  598. assertRequestReverts(pythFeeInWei + 12345 - 1, provider1, 42, false);
  599. requestWithFee(user2, pythFeeInWei + 12345, provider1, 42, false);
  600. uint128 providerOneBalance = provider1FeeInWei * 3 + 12345;
  601. assertEq(
  602. random.getProviderInfo(provider1).accruedFeesInWei,
  603. providerOneBalance
  604. );
  605. assertInvariants();
  606. vm.prank(unregisteredProvider);
  607. vm.expectRevert();
  608. random.withdraw(1000);
  609. vm.prank(provider1);
  610. random.withdraw(1000);
  611. assertEq(
  612. random.getProviderInfo(provider1).accruedFeesInWei,
  613. providerOneBalance - 1000
  614. );
  615. assertInvariants();
  616. vm.prank(provider1);
  617. vm.expectRevert();
  618. random.withdraw(providerOneBalance);
  619. }
  620. function testGetProviderInfo() public {
  621. EntropyStructs.ProviderInfo memory providerInfo1 = random
  622. .getProviderInfo(provider1);
  623. // These two fields aren't used by the Entropy contract itself -- they're just convenient info to store
  624. // on-chain -- so they aren't tested in the other tests.
  625. assertEq(providerInfo1.uri, provider1Uri);
  626. assertEq(providerInfo1.commitmentMetadata, provider1CommitmentMetadata);
  627. }
  628. function testSetProviderFee() public {
  629. assertNotEq(random.getProviderInfo(provider1).feeInWei, 1);
  630. vm.prank(provider1);
  631. random.setProviderFee(1);
  632. assertEq(random.getProviderInfo(provider1).feeInWei, 1);
  633. }
  634. function testSetProviderFeeByUnregistered() public {
  635. vm.prank(unregisteredProvider);
  636. vm.expectRevert();
  637. random.setProviderFee(1);
  638. }
  639. function testSetProviderUri() public {
  640. bytes memory newUri = bytes("https://new.com");
  641. assertNotEq0(random.getProviderInfo(provider1).uri, newUri);
  642. vm.prank(provider1);
  643. random.setProviderUri(newUri);
  644. assertEq0(random.getProviderInfo(provider1).uri, newUri);
  645. }
  646. function testSetProviderUriByUnregistered() public {
  647. bytes memory newUri = bytes("https://new.com");
  648. vm.prank(unregisteredProvider);
  649. vm.expectRevert();
  650. random.setProviderUri(newUri);
  651. }
  652. function testRequestWithCallbackAndReveal() public {
  653. bytes32 userRandomNumber = bytes32(uint(42));
  654. uint fee = random.getFee(provider1);
  655. EntropyStructs.ProviderInfo memory providerInfo = random
  656. .getProviderInfo(provider1);
  657. vm.roll(1234);
  658. vm.deal(user1, fee);
  659. vm.startPrank(user1);
  660. vm.expectEmit(false, false, false, true, address(random));
  661. emit RequestedWithCallback(
  662. provider1,
  663. user1,
  664. providerInfo.sequenceNumber,
  665. userRandomNumber,
  666. EntropyStructs.Request({
  667. provider: provider1,
  668. sequenceNumber: providerInfo.sequenceNumber,
  669. numHashes: SafeCast.toUint32(
  670. providerInfo.sequenceNumber -
  671. providerInfo.currentCommitmentSequenceNumber
  672. ),
  673. commitment: keccak256(
  674. bytes.concat(
  675. random.constructUserCommitment(userRandomNumber),
  676. providerInfo.currentCommitment
  677. )
  678. ),
  679. blockNumber: 1234,
  680. requester: user1,
  681. useBlockhash: false,
  682. isRequestWithCallback: true
  683. })
  684. );
  685. vm.roll(1234);
  686. uint64 assignedSequenceNumber = random.requestWithCallback{value: fee}(
  687. provider1,
  688. userRandomNumber
  689. );
  690. assertEq(
  691. random.getRequest(provider1, assignedSequenceNumber).requester,
  692. user1
  693. );
  694. assertEq(
  695. random.getRequest(provider1, assignedSequenceNumber).provider,
  696. provider1
  697. );
  698. vm.expectRevert(EntropyErrors.InvalidRevealCall.selector);
  699. random.reveal(
  700. provider1,
  701. assignedSequenceNumber,
  702. userRandomNumber,
  703. provider1Proofs[assignedSequenceNumber]
  704. );
  705. vm.stopPrank();
  706. }
  707. function testRequestWithCallbackAndRevealWithCallbackByContract() public {
  708. bytes32 userRandomNumber = bytes32(uint(42));
  709. uint fee = random.getFee(provider1);
  710. EntropyConsumer consumer = new EntropyConsumer(address(random));
  711. vm.deal(user1, fee);
  712. vm.prank(user1);
  713. uint64 assignedSequenceNumber = consumer.requestEntropy{value: fee}(
  714. userRandomNumber
  715. );
  716. EntropyStructs.Request memory req = random.getRequest(
  717. provider1,
  718. assignedSequenceNumber
  719. );
  720. vm.expectEmit(false, false, false, true, address(random));
  721. emit RevealedWithCallback(
  722. req,
  723. userRandomNumber,
  724. provider1Proofs[assignedSequenceNumber],
  725. random.combineRandomValues(
  726. userRandomNumber,
  727. provider1Proofs[assignedSequenceNumber],
  728. 0
  729. )
  730. );
  731. vm.prank(user1);
  732. random.revealWithCallback(
  733. provider1,
  734. assignedSequenceNumber,
  735. userRandomNumber,
  736. provider1Proofs[assignedSequenceNumber]
  737. );
  738. assertEq(consumer.sequence(), assignedSequenceNumber);
  739. assertEq(consumer.provider(), provider1);
  740. assertEq(
  741. consumer.randomness(),
  742. random.combineRandomValues(
  743. userRandomNumber,
  744. provider1Proofs[assignedSequenceNumber],
  745. // No blockhash is being used in callback method. As it
  746. // is being depreceated. Passing 0 for it.
  747. 0
  748. )
  749. );
  750. EntropyStructs.Request memory reqAfterReveal = random.getRequest(
  751. provider1,
  752. assignedSequenceNumber
  753. );
  754. assertEq(reqAfterReveal.sequenceNumber, 0);
  755. }
  756. function testRequestWithCallbackAndRevealWithCallbackByEoa() public {
  757. bytes32 userRandomNumber = bytes32(uint(42));
  758. uint fee = random.getFee(provider1);
  759. vm.deal(user1, fee);
  760. vm.prank(user1);
  761. uint64 assignedSequenceNumber = random.requestWithCallback{value: fee}(
  762. provider1,
  763. userRandomNumber
  764. );
  765. EntropyStructs.Request memory req = random.getRequest(
  766. provider1,
  767. assignedSequenceNumber
  768. );
  769. vm.expectEmit(false, false, false, true, address(random));
  770. emit RevealedWithCallback(
  771. req,
  772. userRandomNumber,
  773. provider1Proofs[assignedSequenceNumber],
  774. random.combineRandomValues(
  775. userRandomNumber,
  776. provider1Proofs[assignedSequenceNumber],
  777. 0
  778. )
  779. );
  780. random.revealWithCallback(
  781. provider1,
  782. assignedSequenceNumber,
  783. userRandomNumber,
  784. provider1Proofs[assignedSequenceNumber]
  785. );
  786. EntropyStructs.Request memory reqAfterReveal = random.getRequest(
  787. provider1,
  788. assignedSequenceNumber
  789. );
  790. assertEq(reqAfterReveal.sequenceNumber, 0);
  791. }
  792. function testRequestAndRevealWithCallback() public {
  793. uint64 sequenceNumber = request(user2, provider1, 42, false);
  794. assertEq(random.getRequest(provider1, sequenceNumber).requester, user2);
  795. vm.expectRevert(EntropyErrors.InvalidRevealCall.selector);
  796. vm.prank(user2);
  797. random.revealWithCallback(
  798. provider1,
  799. sequenceNumber,
  800. bytes32(uint256(42)),
  801. provider1Proofs[sequenceNumber]
  802. );
  803. }
  804. function testRequestWithCallbackAndRevealWithCallbackFailing() public {
  805. bytes32 userRandomNumber = bytes32(uint(42));
  806. uint fee = random.getFee(provider1);
  807. EntropyConsumerFails consumer = new EntropyConsumerFails(
  808. address(random)
  809. );
  810. vm.deal(address(consumer), fee);
  811. vm.startPrank(address(consumer));
  812. uint64 assignedSequenceNumber = random.requestWithCallback{value: fee}(
  813. provider1,
  814. userRandomNumber
  815. );
  816. vm.expectRevert();
  817. random.revealWithCallback(
  818. provider1,
  819. assignedSequenceNumber,
  820. userRandomNumber,
  821. provider1Proofs[assignedSequenceNumber]
  822. );
  823. }
  824. function testFeeManager() public {
  825. address manager = address(12);
  826. // Make sure there are some fees for provider1
  827. request(user1, provider1, 42, false);
  828. // Manager isn't authorized, so can't withdraw or set fee.
  829. vm.prank(manager);
  830. vm.expectRevert();
  831. random.withdrawAsFeeManager(provider1, provider1FeeInWei);
  832. vm.prank(manager);
  833. vm.expectRevert();
  834. random.setProviderFeeAsFeeManager(provider1, 1000);
  835. // You can't set a fee manager from an address that isn't a registered provider.
  836. vm.expectRevert();
  837. random.setFeeManager(address(manager));
  838. // Authorizing the fee manager as the provider enables withdrawing and setting fees.
  839. vm.prank(provider1);
  840. random.setFeeManager(address(manager));
  841. // Withdrawing decrements provider's accrued fees and sends balance to the fee manager.
  842. uint startingBalance = manager.balance;
  843. vm.prank(manager);
  844. random.withdrawAsFeeManager(provider1, provider1FeeInWei);
  845. assertEq(random.getProviderInfo(provider1).accruedFeesInWei, 0);
  846. assertEq(manager.balance, startingBalance + provider1FeeInWei);
  847. // Setting provider fee updates the fee in the ProviderInfo.
  848. vm.prank(manager);
  849. random.setProviderFeeAsFeeManager(provider1, 10101);
  850. assertEq(random.getProviderInfo(provider1).feeInWei, 10101);
  851. // Authorizing a different manager depermissions the previous one.
  852. address manager2 = address(13);
  853. vm.prank(provider1);
  854. random.setFeeManager(address(manager2));
  855. vm.prank(manager);
  856. vm.expectRevert();
  857. random.withdrawAsFeeManager(provider1, provider1FeeInWei);
  858. vm.prank(manager);
  859. vm.expectRevert();
  860. random.setProviderFeeAsFeeManager(provider1, 1000);
  861. }
  862. }
  863. contract EntropyConsumer is IEntropyConsumer {
  864. uint64 public sequence;
  865. bytes32 public randomness;
  866. address public entropy;
  867. address public provider;
  868. constructor(address _entropy) {
  869. entropy = _entropy;
  870. }
  871. function requestEntropy(
  872. bytes32 randomNumber
  873. ) public payable returns (uint64 sequenceNumber) {
  874. address _provider = IEntropy(entropy).getDefaultProvider();
  875. sequenceNumber = IEntropy(entropy).requestWithCallback{
  876. value: msg.value
  877. }(_provider, randomNumber);
  878. }
  879. function getEntropy() internal view override returns (address) {
  880. return entropy;
  881. }
  882. function entropyCallback(
  883. uint64 _sequence,
  884. address _provider,
  885. bytes32 _randomness
  886. ) internal override {
  887. sequence = _sequence;
  888. provider = _provider;
  889. randomness = _randomness;
  890. }
  891. }
  892. contract EntropyConsumerFails is IEntropyConsumer {
  893. uint64 public sequence;
  894. bytes32 public randomness;
  895. address public entropy;
  896. constructor(address _entropy) {
  897. entropy = _entropy;
  898. }
  899. function getEntropy() internal view override returns (address) {
  900. return entropy;
  901. }
  902. function entropyCallback(uint64, address, bytes32) internal pure override {
  903. revert("Callback failed");
  904. }
  905. }