From 5d8a39b165d20cfbebe98ea46945f6fcca5b919f Mon Sep 17 00:00:00 2001 From: Pierrick Turelier Date: Mon, 26 Jun 2023 19:01:56 -0500 Subject: [PATCH] feat(DrawAuctionDispatcher): add fork tests --- lcov.info | 370 +++++++++++------- src/DrawAuctionDispatcher.sol | 154 +++++--- src/RNGRequestor.sol | 2 +- test/DrawAuction.t.sol | 5 + test/RNGRequestor.t.sol | 2 +- test/auctions/Auctions.t.sol | 2 +- ...tionDispatcherEthereumToOptimismFork.t.sol | 272 +++++++++++++ 7 files changed, 616 insertions(+), 191 deletions(-) create mode 100644 test/fork/DrawAuctionDispatcherEthereumToOptimismFork.t.sol diff --git a/lcov.info b/lcov.info index 1a02388..5c86259 100644 --- a/lcov.info +++ b/lcov.info @@ -1,65 +1,139 @@ TN: SF:src/DrawAuction.sol -FN:60,DrawAuction.prizePool -FN:69,DrawAuction.reward +FN:59,DrawAuction.prizePool +FN:68,DrawAuction.reward FN:81,DrawAuction._afterAuctionEnds FNDA:1,DrawAuction.prizePool FNDA:7,DrawAuction.reward FNDA:3,DrawAuction._afterAuctionEnds FNF:3 FNH:3 -DA:61,1 -DA:70,7 -DA:82,3 -DA:83,3 +DA:60,1 +DA:69,7 DA:85,3 -DA:86,3 DA:87,3 DA:89,3 -DA:91,3 -DA:93,3 -DA:95,3 -DA:96,3 -DA:98,3 -DA:99,2 -DA:101,1 -DA:102,1 +DA:90,3 +DA:92,3 +DA:93,2 +DA:95,1 +DA:96,1 +DA:99,3 +DA:100,3 +DA:101,3 +DA:103,3 +DA:104,3 DA:105,3 -DA:106,3 DA:107,3 -DA:109,3 -DA:110,3 -DA:111,3 -DA:113,3 -LF:23 -LH:23 +LF:17 +LH:17 +end_of_record +TN: +SF:src/DrawAuctionDispatcher.sol +FN:106,DrawAuctionDispatcher.dispatcher +FN:114,DrawAuctionDispatcher.drawAuctionExecutor +FN:122,DrawAuctionDispatcher.toChainId +FN:133,DrawAuctionDispatcher.setDispatcher +FN:142,DrawAuctionDispatcher.setDrawAuctionExecutor +FN:155,DrawAuctionDispatcher._afterAuctionEnds +FN:185,DrawAuctionDispatcher._setDispatcher +FN:195,DrawAuctionDispatcher._setDrawAuctionExecutor +FNDA:3,DrawAuctionDispatcher.dispatcher +FNDA:3,DrawAuctionDispatcher.drawAuctionExecutor +FNDA:2,DrawAuctionDispatcher.toChainId +FNDA:5,DrawAuctionDispatcher.setDispatcher +FNDA:9,DrawAuctionDispatcher.setDrawAuctionExecutor +FNDA:1,DrawAuctionDispatcher._afterAuctionEnds +FNDA:3,DrawAuctionDispatcher._setDispatcher +FNDA:9,DrawAuctionDispatcher._setDrawAuctionExecutor +FNF:8 +FNH:8 +DA:107,3 +DA:115,3 +DA:123,2 +DA:134,3 +DA:143,9 +DA:159,1 +DA:170,1 +DA:186,3 +DA:187,1 +DA:188,1 +DA:196,9 +DA:197,9 +DA:198,9 +LF:13 +LH:13 +end_of_record +TN: +SF:src/DrawAuctionExecutor.sol +FN:125,DrawAuctionExecutor.originChainId +FN:133,DrawAuctionExecutor.drawAuctionDispatcher +FN:141,DrawAuctionExecutor.prizePool +FN:152,DrawAuctionExecutor.setDrawAuctionDispatcher +FN:167,DrawAuctionExecutor._checkSender +FN:87,DrawAuctionExecutor.completeAuction +FNDA:0,DrawAuctionExecutor.originChainId +FNDA:0,DrawAuctionExecutor.drawAuctionDispatcher +FNDA:0,DrawAuctionExecutor.prizePool +FNDA:8,DrawAuctionExecutor.setDrawAuctionDispatcher +FNDA:0,DrawAuctionExecutor._checkSender +FNDA:0,DrawAuctionExecutor.completeAuction +FNF:6 +FNH:1 +DA:92,0 +DA:94,0 +DA:96,0 +DA:98,0 +DA:99,0 +DA:101,0 +DA:102,0 +DA:104,0 +DA:105,0 +DA:108,0 +DA:109,0 +DA:110,0 +DA:112,0 +DA:113,0 +DA:114,0 +DA:116,0 +DA:126,0 +DA:134,0 +DA:142,0 +DA:153,8 +DA:154,8 +DA:156,8 +DA:168,0 +DA:169,0 +DA:170,0 +LF:25 +LH:3 end_of_record TN: SF:src/RNGRequestor.sol -FN:164,RNGRequestor.startRNGRequest -FN:186,RNGRequestor.completeRNGRequest -FN:198,RNGRequestor.cancelRNGRequest -FN:215,RNGRequestor.isRNGRequested -FN:223,RNGRequestor.isRNGCompleted -FN:231,RNGRequestor.isRNGTimedOut -FN:239,RNGRequestor.canStartRNGRequest -FN:247,RNGRequestor.canCompleteRNGRequest -FN:257,RNGRequestor.getRNGLockBlock -FN:266,RNGRequestor.getRNGRequestId -FN:274,RNGRequestor.getRNGTimeout -FN:282,RNGRequestor.getRNGService -FN:294,RNGRequestor.setRNGService -FN:304,RNGRequestor.setRNGTimeout -FN:314,RNGRequestor._afterRNGStart -FN:321,RNGRequestor._afterRNGComplete -FN:327,RNGRequestor._currentTime -FN:335,RNGRequestor._isRNGRequested -FN:343,RNGRequestor._isRNGCompleted -FN:351,RNGRequestor._isRNGTimedOut -FN:363,RNGRequestor._setRNGService -FN:373,RNGRequestor._setRNGTimeout -FNDA:17,RNGRequestor.startRNGRequest -FNDA:6,RNGRequestor.completeRNGRequest +FN:163,RNGRequestor.startRNGRequest +FN:185,RNGRequestor.completeRNGRequest +FN:197,RNGRequestor.cancelRNGRequest +FN:214,RNGRequestor.isRNGRequested +FN:222,RNGRequestor.isRNGCompleted +FN:230,RNGRequestor.isRNGTimedOut +FN:238,RNGRequestor.canStartRNGRequest +FN:246,RNGRequestor.canCompleteRNGRequest +FN:256,RNGRequestor.getRNGLockBlock +FN:265,RNGRequestor.getRNGRequestId +FN:273,RNGRequestor.getRNGTimeout +FN:281,RNGRequestor.getRNGService +FN:293,RNGRequestor.setRNGService +FN:303,RNGRequestor.setRNGTimeout +FN:313,RNGRequestor._afterRNGStart +FN:320,RNGRequestor._afterRNGComplete +FN:326,RNGRequestor._currentTime +FN:334,RNGRequestor._isRNGRequested +FN:342,RNGRequestor._isRNGCompleted +FN:350,RNGRequestor._isRNGTimedOut +FN:362,RNGRequestor._setRNGService +FN:372,RNGRequestor._setRNGTimeout +FNDA:18,RNGRequestor.startRNGRequest +FNDA:7,RNGRequestor.completeRNGRequest FNDA:2,RNGRequestor.cancelRNGRequest FNDA:2,RNGRequestor.isRNGRequested FNDA:2,RNGRequestor.isRNGCompleted @@ -74,86 +148,109 @@ FNDA:2,RNGRequestor.setRNGService FNDA:2,RNGRequestor.setRNGTimeout FNDA:11,RNGRequestor._afterRNGStart FNDA:1,RNGRequestor._afterRNGComplete -FNDA:19,RNGRequestor._currentTime -FNDA:29,RNGRequestor._isRNGRequested -FNDA:8,RNGRequestor._isRNGCompleted +FNDA:20,RNGRequestor._currentTime +FNDA:31,RNGRequestor._isRNGRequested +FNDA:9,RNGRequestor._isRNGCompleted FNDA:4,RNGRequestor._isRNGTimedOut FNDA:2,RNGRequestor._setRNGService FNDA:2,RNGRequestor._setRNGTimeout FNF:22 FNH:22 -DA:165,16 -DA:167,16 -DA:168,1 -DA:171,16 -DA:172,16 -DA:173,16 -DA:174,16 -DA:176,16 -DA:178,16 -DA:187,4 -DA:188,4 -DA:190,4 -DA:192,4 -DA:194,4 -DA:199,2 +DA:164,17 +DA:166,17 +DA:167,1 +DA:170,17 +DA:171,17 +DA:172,17 +DA:173,17 +DA:175,17 +DA:177,17 +DA:186,5 +DA:187,5 +DA:189,5 +DA:191,5 +DA:193,5 +DA:198,2 +DA:200,1 DA:201,1 -DA:202,1 -DA:204,1 -DA:206,1 -DA:216,2 -DA:224,2 -DA:232,2 -DA:240,2 -DA:248,2 -DA:258,3 -DA:267,3 -DA:275,3 -DA:283,3 -DA:295,2 -DA:305,2 -DA:328,19 -DA:336,29 -DA:344,8 -DA:352,4 -DA:353,1 -DA:355,3 -DA:364,2 +DA:203,1 +DA:205,1 +DA:215,2 +DA:223,2 +DA:231,2 +DA:239,2 +DA:247,2 +DA:257,3 +DA:266,3 +DA:274,3 +DA:282,3 +DA:294,2 +DA:304,2 +DA:327,20 +DA:335,31 +DA:343,9 +DA:351,4 +DA:352,1 +DA:354,3 +DA:363,2 +DA:364,1 DA:365,1 -DA:366,1 -DA:374,2 +DA:373,2 +DA:374,1 DA:375,1 -DA:376,1 LF:42 LH:42 end_of_record TN: +SF:src/abstract/ExecutorAware.sol +FN:37,ExecutorAware.isTrustedExecutor +FN:47,ExecutorAware._messageId +FN:61,ExecutorAware._fromChainId +FN:75,ExecutorAware._msgSender +FNDA:0,ExecutorAware.isTrustedExecutor +FNDA:0,ExecutorAware._messageId +FNDA:0,ExecutorAware._fromChainId +FNDA:0,ExecutorAware._msgSender +FNF:4 +FNH:0 +DA:38,0 +DA:50,0 +DA:52,0 +DA:64,0 +DA:66,0 +DA:76,0 +DA:78,0 +DA:80,0 +LF:8 +LH:0 +end_of_record +TN: SF:src/auctions/Auction.sol FN:104,Auction.getPhase -FN:116,Auction._afterAuctionEnds -FN:124,Auction._getPhases -FN:133,Auction._getPhase -FN:147,Auction._setPhase +FN:117,Auction._afterAuctionEnds +FN:128,Auction._getPhases +FN:137,Auction._getPhase +FN:151,Auction._setPhase FN:87,Auction.auctionDuration FN:95,Auction.getPhases -FNDA:1,Auction.getPhase +FNDA:2,Auction.getPhase FNDA:1,Auction._afterAuctionEnds FNDA:1,Auction._getPhases -FNDA:11,Auction._getPhase -FNDA:14,Auction._setPhase +FNDA:12,Auction._getPhase +FNDA:16,Auction._setPhase FNDA:2,Auction.auctionDuration FNDA:1,Auction.getPhases FNF:7 FNH:7 DA:88,2 DA:96,1 -DA:105,1 -DA:125,1 -DA:134,11 -DA:153,14 -DA:160,14 -DA:162,14 -DA:164,14 +DA:105,2 +DA:129,1 +DA:138,12 +DA:157,16 +DA:164,16 +DA:166,16 +DA:168,16 LF:9 LH:9 end_of_record @@ -161,55 +258,54 @@ TN: SF:src/auctions/TwoStepsAuction.sol FN:37,TwoStepsAuction._afterRNGStart FN:47,TwoStepsAuction._afterRNGComplete -FNDA:6,TwoStepsAuction._afterRNGStart -FNDA:4,TwoStepsAuction._afterRNGComplete +FNDA:7,TwoStepsAuction._afterRNGStart +FNDA:5,TwoStepsAuction._afterRNGComplete FNF:2 FNH:2 -DA:38,6 -DA:39,6 -DA:48,4 -DA:49,4 -DA:51,4 -LF:5 -LH:5 +DA:38,7 +DA:39,7 +DA:48,5 +DA:54,5 +DA:56,5 +DA:57,5 +DA:58,5 +DA:60,5 +LF:8 +LH:8 end_of_record TN: SF:src/libraries/RewardLib.sol -FN:24,RewardLib.rewards -FN:55,RewardLib.reward -FN:83,RewardLib._reward +FN:22,RewardLib.rewards +FN:53,RewardLib.reward +FN:81,RewardLib._reward FNDA:3,RewardLib.rewards FNDA:22,RewardLib.reward FNDA:28,RewardLib._reward FNF:3 FNH:3 -DA:29,3 +DA:27,3 +DA:28,3 DA:30,3 DA:32,3 -DA:34,3 +DA:33,3 DA:35,3 -DA:37,3 -DA:38,6 -DA:41,3 -DA:60,22 +DA:36,6 +DA:39,3 +DA:58,22 +DA:59,22 DA:61,22 DA:63,22 -DA:65,22 -DA:91,28 -DA:92,5 +DA:89,28 +DA:90,5 DA:95,23 -DA:96,23 -DA:100,23 -DA:101,14 -DA:106,23 -DA:107,2 -DA:111,21 -DA:112,4 -DA:118,21 -DA:119,3 -DA:122,21 -DA:123,21 -DA:125,21 -LF:27 -LH:27 +DA:96,14 +DA:101,23 +DA:102,2 +DA:106,21 +DA:107,4 +DA:113,21 +DA:114,3 +DA:117,21 +LF:23 +LH:23 end_of_record diff --git a/src/DrawAuctionDispatcher.sol b/src/DrawAuctionDispatcher.sol index 5511336..99ca191 100644 --- a/src/DrawAuctionDispatcher.sol +++ b/src/DrawAuctionDispatcher.sol @@ -5,7 +5,9 @@ import { PrizePool } from "v5-prize-pool/PrizePool.sol"; import { Auction, AuctionLib } from "src/auctions/Auction.sol"; import { TwoStepsAuction, RNGInterface } from "src/auctions/TwoStepsAuction.sol"; +import { ISingleMessageDispatcher } from "src/interfaces/ISingleMessageDispatcher.sol"; import { RewardLib } from "src/libraries/RewardLib.sol"; +import { console2 } from "forge-std/Test.sol"; /** * @title PoolTogether V5 DrawAuctionDispatcher @@ -19,75 +21,112 @@ contract DrawAuctionDispatcher is TwoStepsAuction { /** * @notice Event emitted when the dispatcher is set. - * @param dispatcher Address of the dispatcher on Ethereum that will dispatch the phases and random number + * @param dispatcher Instance of the dispatcher on Ethereum that will dispatch the phases and random number */ event DispatcherSet(ISingleMessageDispatcher indexed dispatcher); + /** + * @notice Event emitted when the drawAuctionExecutor is set. + * @param drawAuctionExecutor Address of the drawAuctionExecutor on the receiving chain that will complete the Draw + */ + event DrawAuctionExecutorSet(address indexed drawAuctionExecutor); + /** * @notice Event emitted when the RNG and auction phases have been dispatched. - * @param dispatcher Address of the dispatcher on Ethereum that dispatched the phases and random number + * @param dispatcher Instance of the dispatcher on Ethereum that dispatched the phases and random number * @param toChainId ID of the receiving chain * @param drawAuctionExecutor Address of the DrawAuctionExecutor on the receiving chain that will award the auction and complete the Draw * @param phases Array of auction phases * @param randomNumber Random number computed by the RNG */ - event RNGDispatched( + event AuctionDispatched( ISingleMessageDispatcher indexed dispatcher, uint256 indexed toChainId, address indexed drawAuctionExecutor, - AuctionLib.Phases[] phases, + AuctionLib.Phase[] phases, uint256 randomNumber ); + /* ============ Custom Errors ============ */ - /* ============ Variables ============ */ + /// @notice Thrown when the Dispatcher address passed to the constructor is zero address. + error DispatcherZeroAddress(); - /// @notice Address of the dispatcher on Ethereum - ISingleMessageDispatcher internal _dispatcher; + /// @notice Thrown when the toChainId passed to the constructor is zero. + error ToChainIdZero(); - /// @notice Instance of the PrizePool to compute Draw for. - PrizePool internal immutable _prizePool; + /// @notice Thrown when the DrawAuctionExecutor address passed to the constructor is zero address. + error DrawAuctionExecutorZeroAddress(); - /* ============ Custom Errors ============ */ + /* ============ Variables ============ */ - /// @notice Thrown when the Dispatcher address passed to the constructor is zero address. - error DispatcherZeroAddress(); + /// @notice Instance of the dispatcher on Ethereum + ISingleMessageDispatcher internal _dispatcher; + + /// @notice ID of the receiving chain + uint256 internal immutable _toChainId; - /// @notice Thrown when the PrizePool address passed to the constructor is zero address. - error PrizePoolZeroAddress(); + /// @notice Address of the DrawAuctionExecutor to compute Draw for. + address internal _drawAuctionExecutor; /* ============ Constructor ============ */ /** * @notice Contract constructor. - * @param dispatcher_ Address of the dispatcher on Ethereum that will dispatch the phases and random number - * @param rng_ Address of the RNG service + * @param dispatcher_ Instance of the dispatcher on Ethereum that will dispatch the phases and random number + * @param toChainId_ ID of the receiving chain + * @param rng_ Instance of the RNG service * @param rngTimeout_ Time in seconds before an RNG request can be cancelled - * @param prizePool_ Address of the prize pool * @param _auctionPhases Number of auction phases * @param auctionDuration_ Duration of the auction in seconds * @param _owner Address of the DrawAuctionDispatcher owner */ constructor( ISingleMessageDispatcher dispatcher_, + uint256 toChainId_, RNGInterface rng_, uint32 rngTimeout_, - PrizePool prizePool_, uint8 _auctionPhases, uint32 auctionDuration_, address _owner ) TwoStepsAuction(rng_, rngTimeout_, _auctionPhases, auctionDuration_, _owner) { - if (address(prizePool_) == address(0)) revert PrizePoolZeroAddress(); - _prizePool = prizePool_; - _setDispatcher(dispatcher_); + + if (toChainId_ == 0) revert ToChainIdZero(); + _toChainId = toChainId_; } /* ============ External Functions ============ */ - /* ============ Setter Functions ============ */ + /* ============ Getters ============ */ - /** + /** + * @notice Get the dispatcher. + * @return Instance of the dispatcher + */ + function dispatcher() external view returns (ISingleMessageDispatcher) { + return _dispatcher; + } + + /** + * @notice Get the drawAuctionExecutor address on the receiving chain. + * @return Address of the DrawAuctionExecutor on the receiving chain + */ + function drawAuctionExecutor() external view returns (address) { + return _drawAuctionExecutor; + } + + /** + * @notice Get the toChainId. + * @return ID of the receiving chain + */ + function toChainId() external view returns (uint256) { + return _toChainId; + } + + /* ============ Setters ============ */ + + /** * @notice Set the dispatcher. * @dev Only callable by the owner. * @param dispatcher_ Address of the dispatcher @@ -96,6 +135,15 @@ contract DrawAuctionDispatcher is TwoStepsAuction { _setDispatcher(dispatcher_); } + /** + * @notice Set the drawAuctionExecutor. + * @dev Only callable by the owner. + * @param drawAuctionExecutor_ Address of the drawAuctionExecutor + */ + function setDrawAuctionExecutor(address drawAuctionExecutor_) external onlyOwner { + _setDrawAuctionExecutor(drawAuctionExecutor_); + } + /* ============ Internal Functions ============ */ /* ============ Hooks ============ */ @@ -105,34 +153,28 @@ contract DrawAuctionDispatcher is TwoStepsAuction { * @param _auctionPhases Array of auction phases * @param _randomNumber Random number generated by the RNG service */ - function _afterAuctionEnds(AuctionLib.Phase[] memory _auctionPhases, uint256 _randomNumber) internal override { - _dispatchMessage( - _toChainId, - _drawExecutor, - abi.encodeWithSignature("pushDraw((uint256,uint32,uint64,uint64,uint32))", _draw) - ); - - emit RNGDispatched(_auctionPhases, _randomNumber); - } - - /* ============ Dispatch ============ */ - - /** - * @notice Dispatch encoded call. - * @param _dispatcher Address of the dispatcher on Ethereum that will dispatch the call - * @param _toChainId ID of the receiving chain - * @param _drawExecutor Address of the DrawExecutor on the receiving chain that will receive the call - * @param _data Calldata to dispatch - */ - function _dispatchMessage( - uint256 _toChainId, - address _drawExecutor, - bytes memory _data - ) internal { - require(address(_dispatcher) != address(0), "DD/dispatcher-not-zero-address"); - require(_drawExecutor != address(0), "DD/drawExecutor-not-zero-address"); - - _dispatcher.dispatchMessage(_toChainId, _drawExecutor, _data); + function _afterAuctionEnds( + AuctionLib.Phase[] memory _auctionPhases, + uint256 _randomNumber + ) internal override { + _dispatcher.dispatchMessage( + _toChainId, + _drawAuctionExecutor, + abi.encodeWithSignature( + "completeAuction((uint8,uint64,uint64,address)[],uint32,uint256)", + _auctionPhases, + _auctionDuration, + _randomNumber + ) + ); + + emit AuctionDispatched( + _dispatcher, + _toChainId, + _drawAuctionExecutor, + _auctionPhases, + _randomNumber + ); } /* ============ Setters ============ */ @@ -146,4 +188,14 @@ contract DrawAuctionDispatcher is TwoStepsAuction { _dispatcher = dispatcher_; emit DispatcherSet(dispatcher_); } + + /** + * @notice Set the drawAuctionExecutor. + * @param drawAuctionExecutor_ Address of the drawAuctionExecutor + */ + function _setDrawAuctionExecutor(address drawAuctionExecutor_) internal { + if (drawAuctionExecutor_ == address(0)) revert DrawAuctionExecutorZeroAddress(); + _drawAuctionExecutor = drawAuctionExecutor_; + emit DrawAuctionExecutorSet(drawAuctionExecutor_); + } } diff --git a/src/RNGRequestor.sol b/src/RNGRequestor.sol index 8638b74..1164464 100644 --- a/src/RNGRequestor.sol +++ b/src/RNGRequestor.sol @@ -282,7 +282,7 @@ contract RNGRequestor is Ownable { return _rng; } - /* ============ Setter Functions ============ */ + /* ============ Setters ============ */ /** * @notice Sets the RNG service used to generate random numbers. diff --git a/test/DrawAuction.t.sol b/test/DrawAuction.t.sol index d293978..6775991 100644 --- a/test/DrawAuction.t.sol +++ b/test/DrawAuction.t.sol @@ -11,6 +11,11 @@ import { Helpers, RNGInterface } from "test/helpers/Helpers.t.sol"; contract DrawAuctionTest is Helpers { /* ============ Events ============ */ + event AuctionRewardsDistributed( + uint8[] phaseIds, + address[] rewardRecipients, + uint256[] rewardAmounts + ); /* ============ Variables ============ */ diff --git a/test/RNGRequestor.t.sol b/test/RNGRequestor.t.sol index 79ddf93..d1a7335 100644 --- a/test/RNGRequestor.t.sol +++ b/test/RNGRequestor.t.sol @@ -258,7 +258,7 @@ contract RNGRequestorTest is Helpers { assertEq(address(rngRequestor.getRNGService()), address(rng)); } - /* ============ Setter Functions ============ */ + /* ============ Setters ============ */ /* ============ setRNGService ============ */ function testSetRNGService() public { diff --git a/test/auctions/Auctions.t.sol b/test/auctions/Auctions.t.sol index 92201fa..3943837 100644 --- a/test/auctions/Auctions.t.sol +++ b/test/auctions/Auctions.t.sol @@ -81,7 +81,7 @@ contract AuctionTest is Test { assertEq(_phase.recipient, _recipient); } - /* ============ Setter Functions ============ */ + /* ============ Setters ============ */ function testSetPhase() public { uint8 _phaseId = 0; diff --git a/test/fork/DrawAuctionDispatcherEthereumToOptimismFork.t.sol b/test/fork/DrawAuctionDispatcherEthereumToOptimismFork.t.sol new file mode 100644 index 0000000..3a2b596 --- /dev/null +++ b/test/fork/DrawAuctionDispatcherEthereumToOptimismFork.t.sol @@ -0,0 +1,272 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.17; + +import { ERC20Mock } from "openzeppelin/mocks/ERC20Mock.sol"; + +import { UD2x18, SD1x18, ConstructorParams, PrizePool, TieredLiquidityDistributor, TwabController } from "v5-prize-pool/PrizePool.sol"; + +import { DrawAuctionDispatcher, ISingleMessageDispatcher } from "src/DrawAuctionDispatcher.sol"; +import { DrawAuctionExecutor } from "src/DrawAuctionExecutor.sol"; +import { AuctionLib } from "src/libraries/AuctionLib.sol"; +import { Helpers, RNGInterface } from "test/helpers/Helpers.t.sol"; +import { console2 } from "forge-std/Test.sol"; + +contract DrawAuctionDispatcherEthereumToOptimismForkTest is Helpers { + /* ============ Events ============ */ + + event DispatcherSet(ISingleMessageDispatcher indexed dispatcher); + event DrawAuctionExecutorSet(address indexed drawAuctionExecutor); + + event AuctionDispatched( + ISingleMessageDispatcher indexed dispatcher, + uint256 indexed toChainId, + address indexed drawAuctionExecutor, + AuctionLib.Phase[] phases, + uint256 randomNumber + ); + + /* ============ Variables ============ */ + + uint256 public mainnetFork; + uint256 public optimismFork; + + address public proxyOVML1CrossDomainMessenger = 0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1; + address public l2CrossDomainMessenger = 0x4200000000000000000000000000000000000007; + + uint256 public nonce = 1; + uint256 public toChainId = 10; + uint256 public fromChainId = 1; + + ISingleMessageDispatcher public dispatcher = + ISingleMessageDispatcher(address(0xa8f85bAB964D7e6bE938B54Bf4b29A247A88CD9d)); + address public executor = 0x890a87E71E731342a6d10e7628bd1F0733ce3296; + + DrawAuctionDispatcher public drawAuctionDispatcher; + DrawAuctionExecutor public drawAuctionExecutor; + + ERC20Mock public prizeToken; + PrizePool public prizePool; + RNGInterface public rng = RNGInterface(address(1)); + + uint32 public auctionDuration = 3 hours; + uint32 public rngTimeOut = 1 hours; + uint32 public drawPeriodSeconds = 1 days; + uint256 public randomNumber = 123456789; + address public recipient = address(this); + + /* ============ Setup ============ */ + + function setUp() public { + mainnetFork = vm.createFork(vm.rpcUrl("mainnet")); + optimismFork = vm.createFork(vm.rpcUrl("optimism")); + + vm.warp(0); + } + + function deployDrawAuctionDispatcher() public { + vm.selectFork(mainnetFork); + + drawAuctionDispatcher = new DrawAuctionDispatcher( + dispatcher, + toChainId, + rng, + rngTimeOut, + 2, + auctionDuration, + address(this) + ); + + vm.makePersistent(address(drawAuctionDispatcher)); + } + + function deployDrawAuctionExecutor() public { + vm.selectFork(optimismFork); + + drawAuctionExecutor = new DrawAuctionExecutor(fromChainId, executor, prizePool); + + vm.makePersistent(address(drawAuctionExecutor)); + } + + function deployPrizePool() public { + vm.selectFork(optimismFork); + + prizeToken = new ERC20Mock(); + + prizePool = new PrizePool( + ConstructorParams({ + prizeToken: prizeToken, + twabController: TwabController(address(0)), + drawManager: address(0), + grandPrizePeriodDraws: uint32(365), + drawPeriodSeconds: drawPeriodSeconds, + firstDrawStartsAt: uint64(block.timestamp), + numberOfTiers: uint8(3), // minimum number of tiers + tierShares: 100, + canaryShares: 10, + reserveShares: 10, + claimExpansionThreshold: UD2x18.wrap(0.9e18), // claim threshold of 90% + smoothing: SD1x18.wrap(0.9e18) // alpha + }) + ); + + vm.makePersistent(address(prizePool)); + } + + function deployAll() public { + deployDrawAuctionDispatcher(); + deployPrizePool(); + deployDrawAuctionExecutor(); + } + + function setDrawAuctionExecutor() public { + vm.selectFork(mainnetFork); + drawAuctionDispatcher.setDrawAuctionExecutor(address(drawAuctionExecutor)); + } + + function setDrawAuctionDispatcher() public { + vm.selectFork(optimismFork); + drawAuctionExecutor.setDrawAuctionDispatcher(address(drawAuctionDispatcher)); + } + + function setPrizePoolDrawManager() public { + vm.selectFork(optimismFork); + prizePool.setDrawManager(address(drawAuctionDispatcher)); + } + + function setAll() public { + setDrawAuctionExecutor(); + setDrawAuctionDispatcher(); + setPrizePoolDrawManager(); + } + + /* ============ Auction Dispatch ============ */ + function testAfterAuctionEnds() public { + deployAll(); + setAll(); + + uint256 _reserveAmount = 200e18; + + vm.selectFork(optimismFork); + + prizeToken.mint(address(prizePool), _reserveAmount * 110); + prizePool.contributePrizeTokens(address(2), _reserveAmount * 110); + + vm.selectFork(mainnetFork); + + vm.warp(drawPeriodSeconds + auctionDuration / 2); + + uint32 _requestId = uint32(1); + uint32 _lockBlock = uint32(block.number); + + _mockStartRNGRequest(address(rng), address(0), 0, _requestId, _lockBlock); + + drawAuctionDispatcher.startRNGRequest(recipient); + + uint64 _warpTimestamp = uint64(drawPeriodSeconds + auctionDuration); + vm.warp(_warpTimestamp); + + _mockCompleteRNGRequest(address(rng), _requestId, randomNumber); + + AuctionLib.Phase[] memory _auctionPhases = new AuctionLib.Phase[](2); + _auctionPhases[0] = drawAuctionDispatcher.getPhase(0); + _auctionPhases[1] = _getPhase(1, _auctionPhases[0].endTime, _warpTimestamp, recipient); + + vm.expectEmit(); + emit AuctionDispatched( + drawAuctionDispatcher.dispatcher(), + drawAuctionDispatcher.toChainId(), + drawAuctionDispatcher.drawAuctionExecutor(), + _auctionPhases, + randomNumber + ); + + drawAuctionDispatcher.completeRNGRequest(recipient); + } + + /* ============ Getters ============ */ + + function testGetters() public { + deployAll(); + setAll(); + + assertEq(address(drawAuctionDispatcher.dispatcher()), address(dispatcher)); + assertEq(drawAuctionDispatcher.drawAuctionExecutor(), address(drawAuctionExecutor)); + assertEq(drawAuctionDispatcher.toChainId(), toChainId); + } + + /* ============ Setters ============ */ + + /* ============ setDispatcher ============ */ + function testSetDispatcher() public { + deployAll(); + setAll(); + + ISingleMessageDispatcher _dispatcher = ISingleMessageDispatcher(address(2)); + + vm.expectEmit(); + emit DispatcherSet(_dispatcher); + + drawAuctionDispatcher.setDispatcher(_dispatcher); + + assertEq(address(drawAuctionDispatcher.dispatcher()), address(_dispatcher)); + } + + function testSetDispatcherFailAddressZero() public { + deployAll(); + setAll(); + + ISingleMessageDispatcher _dispatcher = ISingleMessageDispatcher(address(0)); + + vm.expectRevert(abi.encodeWithSelector(DrawAuctionDispatcher.DispatcherZeroAddress.selector)); + drawAuctionDispatcher.setDispatcher(_dispatcher); + } + + function testSetDispatcherFailNotOwner() public { + deployAll(); + setAll(); + + ISingleMessageDispatcher _dispatcher = ISingleMessageDispatcher(address(2)); + + vm.startPrank(address(4)); + + vm.expectRevert(bytes("Ownable/caller-not-owner")); + drawAuctionDispatcher.setDispatcher(_dispatcher); + } + + /* ============ setDrawAuctionExecutor ============ */ + function testSetDrawAuctionExecutor() public { + deployAll(); + setAll(); + + address _drawAuctionExecutor = address(3); + + vm.expectEmit(); + emit DrawAuctionExecutorSet(_drawAuctionExecutor); + + drawAuctionDispatcher.setDrawAuctionExecutor(_drawAuctionExecutor); + + assertEq(address(drawAuctionDispatcher.drawAuctionExecutor()), address(_drawAuctionExecutor)); + } + + function testSetDrawAuctionExecutorFailAddressZero() public { + deployAll(); + setAll(); + + ISingleMessageDispatcher _dispatcher = ISingleMessageDispatcher(address(0)); + + vm.expectRevert(abi.encodeWithSelector(DrawAuctionDispatcher.DispatcherZeroAddress.selector)); + drawAuctionDispatcher.setDispatcher(_dispatcher); + } + + function testSetDrawAuctionExecutorFailNotOwner() public { + deployAll(); + setAll(); + + ISingleMessageDispatcher _dispatcher = ISingleMessageDispatcher(address(3)); + + vm.startPrank(address(4)); + + vm.expectRevert(bytes("Ownable/caller-not-owner")); + drawAuctionDispatcher.setDispatcher(_dispatcher); + } +}