PulseGasBenchmark.t.sol 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. // SPDX-License-Identifier: Apache 2
  2. pragma solidity ^0.8.0;
  3. import "forge-std/Test.sol";
  4. import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
  5. import "../contracts/pulse/PulseUpgradeable.sol";
  6. import "../contracts/pulse/IPulse.sol";
  7. import "../contracts/pulse/PulseState.sol";
  8. import "../contracts/pulse/PulseEvents.sol";
  9. import "../contracts/pulse/PulseErrors.sol";
  10. import "./utils/PulseTestUtils.t.sol";
  11. contract PulseGasBenchmark is Test, PulseTestUtils {
  12. ERC1967Proxy public proxy;
  13. PulseUpgradeable public pulse;
  14. IPulseConsumer public consumer;
  15. address public owner;
  16. address public admin;
  17. address public pyth;
  18. address public defaultProvider;
  19. uint96 constant PYTH_FEE = 1 wei;
  20. uint96 constant DEFAULT_PROVIDER_FEE_PER_GAS = 1 wei;
  21. uint96 constant DEFAULT_PROVIDER_BASE_FEE = 1 wei;
  22. uint96 constant DEFAULT_PROVIDER_FEE_PER_FEED = 10 wei;
  23. function setUp() public {
  24. owner = address(1);
  25. admin = address(2);
  26. pyth = address(3);
  27. defaultProvider = address(4);
  28. PulseUpgradeable _pulse = new PulseUpgradeable();
  29. proxy = new ERC1967Proxy(address(_pulse), "");
  30. pulse = PulseUpgradeable(address(proxy));
  31. pulse.initialize(
  32. owner,
  33. admin,
  34. PYTH_FEE,
  35. pyth,
  36. defaultProvider,
  37. false,
  38. 15
  39. );
  40. vm.prank(defaultProvider);
  41. pulse.registerProvider(
  42. DEFAULT_PROVIDER_BASE_FEE,
  43. DEFAULT_PROVIDER_FEE_PER_FEED,
  44. DEFAULT_PROVIDER_FEE_PER_GAS
  45. );
  46. consumer = new VoidPulseConsumer(address(proxy));
  47. }
  48. // Estimate how much gas is used by all of the data mocking functionality in the other gas benchmarks.
  49. // Subtract this amount from the gas benchmarks to estimate the true usage of the pulse flow.
  50. function testDataMocking() public {
  51. uint64 timestamp = SafeCast.toUint64(block.timestamp);
  52. createPriceIds();
  53. PythStructs.PriceFeed[] memory priceFeeds = createMockPriceFeeds(
  54. timestamp
  55. );
  56. mockParsePriceFeedUpdates(pyth, priceFeeds);
  57. createMockUpdateData(priceFeeds);
  58. }
  59. function testBasicFlow() public {
  60. uint64 timestamp = SafeCast.toUint64(block.timestamp);
  61. bytes32[] memory priceIds = createPriceIds();
  62. uint32 callbackGasLimit = 100000;
  63. uint96 totalFee = pulse.getFee(
  64. defaultProvider,
  65. callbackGasLimit,
  66. priceIds
  67. );
  68. vm.deal(address(consumer), 1 ether);
  69. vm.prank(address(consumer));
  70. uint64 sequenceNumber = pulse.requestPriceUpdatesWithCallback{
  71. value: totalFee
  72. }(defaultProvider, timestamp, priceIds, callbackGasLimit);
  73. PythStructs.PriceFeed[] memory priceFeeds = createMockPriceFeeds(
  74. timestamp
  75. );
  76. mockParsePriceFeedUpdates(pyth, priceFeeds);
  77. bytes[] memory updateData = createMockUpdateData(priceFeeds);
  78. pulse.executeCallback(
  79. defaultProvider,
  80. sequenceNumber,
  81. updateData,
  82. priceIds
  83. );
  84. }
  85. }
  86. // A simple consumer that does nothing with the price updates.
  87. // Used to estimate the gas usage of the pulse flow.
  88. contract VoidPulseConsumer is IPulseConsumer {
  89. address private _pulse;
  90. constructor(address pulse) {
  91. _pulse = pulse;
  92. }
  93. function getPulse() internal view override returns (address) {
  94. return _pulse;
  95. }
  96. function pulseCallback(
  97. uint64 sequenceNumber,
  98. PythStructs.PriceFeed[] memory priceFeeds
  99. ) internal override {}
  100. }