Skip to content

Commit 7221ddd

Browse files
authored
Merge pull request #61 from pooltogether/pool-2496-optimism-add-contract-to-bridge-draw
Add contracts to bridge draw
2 parents 23e3e13 + 1e54a9f commit 7221ddd

9 files changed

+1187
-2
lines changed

contracts/DrawDispatcher.sol

+161
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
// SPDX-License-Identifier: GPL-3.0
2+
3+
pragma solidity 0.8.6;
4+
5+
import { IDrawBeacon } from "@pooltogether/v4-core/contracts/interfaces/IDrawBeacon.sol";
6+
import { IDrawBuffer } from "@pooltogether/v4-core/contracts/interfaces/IDrawBuffer.sol";
7+
8+
import { ISingleMessageDispatcher } from "./interfaces/ISingleMessageDispatcher.sol";
9+
10+
/**
11+
* @title PoolTogether V4 DrawDispatcher
12+
* @author PoolTogether Inc Team
13+
* @notice The DrawDispatcher smart contract relies on ERC-5164 to dispatch draws from Ethereum to another L1 or L2
14+
* where Chainlink VRF 2.0 may not be available to compute draws.
15+
*/
16+
contract DrawDispatcher {
17+
/**
18+
* @notice Emitted when the `draw` has been dispatched.
19+
* @param dispatcher Address of the dispatcher on Ethereum that dispatched the draw
20+
* @param toChainId ID of the receiving chain
21+
* @param drawExecutor Address of the DrawExecutor on the receiving chain that will push the draw onto the DrawBuffer
22+
* @param draw Draw that was dispatched
23+
*/
24+
event DrawDispatched(
25+
ISingleMessageDispatcher indexed dispatcher,
26+
uint256 indexed toChainId,
27+
address indexed drawExecutor,
28+
IDrawBeacon.Draw draw
29+
);
30+
31+
/**
32+
* @notice Emitted when the `draws` have been dispatched.
33+
* @param dispatcher Address of the dispatcher on Ethereum that dispatched the draws
34+
* @param toChainId ID of the receiving chain
35+
* @param drawExecutor Address of the DrawExecutor on the receiving chain that will push the draws onto the DrawBuffer
36+
* @param draws Draws that were dispatched
37+
*/
38+
event DrawsDispatched(
39+
ISingleMessageDispatcher indexed dispatcher,
40+
uint256 indexed toChainId,
41+
address indexed drawExecutor,
42+
IDrawBeacon.Draw[] draws
43+
);
44+
45+
/// @notice DrawBuffer from which draws are retrieved.
46+
IDrawBuffer public immutable drawBuffer;
47+
48+
/**
49+
* @notice DrawDispatcher constructor.
50+
* @param _drawBuffer Address of the DrawBuffer from which draws are retrieved
51+
*/
52+
constructor(IDrawBuffer _drawBuffer) {
53+
require(address(_drawBuffer) != address(0), "DD/drawBuffer-not-zero-address");
54+
55+
drawBuffer = _drawBuffer;
56+
}
57+
58+
/**
59+
* @notice Retrieves and dispatch the newest recorded draw.
60+
* @param _dispatcher Address of the dispatcher on Ethereum that will be used to dispatch the draw
61+
* @param _toChainId ID of the receiving chain
62+
* @param _drawExecutor Address of the DrawExecutor on the receiving chain that will push the draw onto the DrawBuffer
63+
*/
64+
function dispatchNewestDraw(
65+
ISingleMessageDispatcher _dispatcher,
66+
uint256 _toChainId,
67+
address _drawExecutor
68+
) external {
69+
IDrawBeacon.Draw memory _newestDraw = drawBuffer.getNewestDraw();
70+
_dispatchDraw(_dispatcher, _toChainId, _drawExecutor, _newestDraw);
71+
}
72+
73+
/**
74+
* @notice Retrieves and dispatch draw.
75+
* @dev Will revert if the draw does not exist.
76+
* @param _dispatcher Address of the dispatcher on Ethereum that will be used to dispatch the draw
77+
* @param _toChainId ID of the receiving chain
78+
* @param _drawExecutor Address of the DrawExecutor on the receiving chain that will push the draw onto the DrawBuffer
79+
* @param _drawId Id of the draw to dispatch
80+
*/
81+
function dispatchDraw(
82+
ISingleMessageDispatcher _dispatcher,
83+
uint256 _toChainId,
84+
address _drawExecutor,
85+
uint32 _drawId
86+
) external {
87+
require(_drawId > 0, "DD/drawId-gt-zero");
88+
89+
IDrawBeacon.Draw memory _draw = drawBuffer.getDraw(_drawId);
90+
_dispatchDraw(_dispatcher, _toChainId, _drawExecutor, _draw);
91+
}
92+
93+
/**
94+
* @notice Retrieves and dispatch draws.
95+
* @dev `_drawIds` must be ordered in ascending and contiguous order.
96+
* @dev Will revert if one of the draw does not exist.
97+
* @param _dispatcher Address of the dispatcher on Ethereum that will be used to dispatch the draw
98+
* @param _toChainId ID of the receiving chain
99+
* @param _drawExecutor Address of the DrawExecutor on the receiving chain that will push the draw onto the DrawBuffer
100+
* @param _drawIds Array of draw ids to dispatch
101+
*/
102+
function dispatchDraws(
103+
ISingleMessageDispatcher _dispatcher,
104+
uint256 _toChainId,
105+
address _drawExecutor,
106+
uint32[] calldata _drawIds
107+
) external {
108+
IDrawBeacon.Draw[] memory _draws = drawBuffer.getDraws(_drawIds);
109+
110+
_dispatchMessage(
111+
_dispatcher,
112+
_toChainId,
113+
_drawExecutor,
114+
abi.encodeWithSignature("pushDraws((uint256,uint32,uint64,uint64,uint32)[])", _draws)
115+
);
116+
117+
emit DrawsDispatched(_dispatcher, _toChainId, _drawExecutor, _draws);
118+
}
119+
120+
/**
121+
* @notice Dispatch the passed `draw`.
122+
* @param _dispatcher Address of the dispatcher on Ethereum that will be used to dispatch the draw
123+
* @param _toChainId ID of the receiving chain
124+
* @param _drawExecutor Address of the DrawExecutor on the receiving chain that will push the draw onto the DrawBuffer
125+
* @param _draw Draw to dispatch
126+
*/
127+
function _dispatchDraw(
128+
ISingleMessageDispatcher _dispatcher,
129+
uint256 _toChainId,
130+
address _drawExecutor,
131+
IDrawBeacon.Draw memory _draw
132+
) internal {
133+
_dispatchMessage(
134+
_dispatcher,
135+
_toChainId,
136+
_drawExecutor,
137+
abi.encodeWithSignature("pushDraw((uint256,uint32,uint64,uint64,uint32))", _draw)
138+
);
139+
140+
emit DrawDispatched(_dispatcher, _toChainId, _drawExecutor, _draw);
141+
}
142+
143+
/**
144+
* @notice Dispatch encoded call.
145+
* @param _dispatcher Address of the dispatcher on Ethereum that will dispatch the call
146+
* @param _toChainId ID of the receiving chain
147+
* @param _drawExecutor Address of the DrawExecutor on the receiving chain that will receive the call
148+
* @param _data Calldata to dispatch
149+
*/
150+
function _dispatchMessage(
151+
ISingleMessageDispatcher _dispatcher,
152+
uint256 _toChainId,
153+
address _drawExecutor,
154+
bytes memory _data
155+
) internal {
156+
require(address(_dispatcher) != address(0), "DD/dispatcher-not-zero-address");
157+
require(_drawExecutor != address(0), "DD/drawExecutor-not-zero-address");
158+
159+
_dispatcher.dispatchMessage(_toChainId, _drawExecutor, _data);
160+
}
161+
}

contracts/DrawExecutor.sol

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// SPDX-License-Identifier: GPL-3.0
2+
3+
pragma solidity 0.8.6;
4+
5+
import "@pooltogether/v4-core/contracts/interfaces/IDrawBuffer.sol";
6+
7+
import { ExecutorAware } from "./abstract/ExecutorAware.sol";
8+
9+
/**
10+
* @title PoolTogether V4 DrawExecutor
11+
* @author PoolTogether Inc Team
12+
* @notice The DrawExecutor smart contract relies on ERC-5164 to receive draws from Ethereum
13+
* and push them onto the DrawBuffer.
14+
* @dev This contract does not ensure draw ordering and draws should always be bridged in ascending and contiguous order.
15+
*/
16+
contract DrawExecutor is ExecutorAware {
17+
/**
18+
* @notice Emitted when the `draw` has been pushed.
19+
* @param draw Draw that was pushed
20+
*/
21+
event DrawPushed(IDrawBeacon.Draw draw);
22+
23+
/**
24+
* @notice Emitted when the `draws` have been pushed.
25+
* @param draws Draws that were pushed
26+
*/
27+
event DrawsPushed(IDrawBeacon.Draw[] draws);
28+
29+
/// @notice ID of the origin chain.
30+
uint256 public immutable originChainId;
31+
32+
/// @notice DrawDispatcher contract on the origin chain that dispatch the draws.
33+
address public immutable drawDispatcher;
34+
35+
/// @notice DrawBuffer onto which draws are pushed.
36+
IDrawBuffer public immutable drawBuffer;
37+
38+
/**
39+
* @notice DrawExecutor constructor.
40+
* @param _originChainId ID of the origin chain
41+
* @param _drawDispatcher Address of the DrawDispatcher on the origin chain that dispatch the draws
42+
* @param _executor Address of the ERC-5164 contract that executes the bridged calls
43+
* @param _drawBuffer Address of the DrawBuffer onto which draws are pushed
44+
*/
45+
constructor(
46+
uint256 _originChainId,
47+
address _drawDispatcher,
48+
address _executor,
49+
IDrawBuffer _drawBuffer
50+
) ExecutorAware(_executor) {
51+
require(_originChainId != 0, "DE/originChainId-not-zero");
52+
require(address(_drawDispatcher) != address(0), "DE/drawDispatcher-not-zero-adrs");
53+
require(address(_drawBuffer) != address(0), "DE/drawBuffer-not-zero-address");
54+
55+
originChainId = _originChainId;
56+
drawDispatcher = _drawDispatcher;
57+
drawBuffer = _drawBuffer;
58+
}
59+
60+
/**
61+
* @notice Push `draw` onto the DrawBuffer.
62+
* @dev Only the `executor` is able to call this function.
63+
* @param _draw Draw to push
64+
*/
65+
function pushDraw(IDrawBeacon.Draw calldata _draw) external {
66+
_checkSender();
67+
68+
drawBuffer.pushDraw(_draw);
69+
70+
emit DrawPushed(_draw);
71+
}
72+
73+
/**
74+
* @notice Push `draws` onto the DrawBuffer.
75+
* @dev Only the `executor` is able to call this function.
76+
* @dev `draws` must be ordered in ascending and contiguous order.
77+
* @param _draws Draws to push
78+
*/
79+
function pushDraws(IDrawBeacon.Draw[] calldata _draws) external {
80+
_checkSender();
81+
82+
uint256 _drawsLength = _draws.length;
83+
84+
for (uint256 i; i < _drawsLength; i++) {
85+
drawBuffer.pushDraw(_draws[i]);
86+
}
87+
88+
emit DrawsPushed(_draws);
89+
}
90+
91+
/**
92+
* @notice Checks that:
93+
* - the call has been dispatched from the supported chain
94+
* - the sender on the receiving chain is the executor
95+
* - the sender on the origin chain is the DrawDispatcher
96+
*/
97+
function _checkSender() internal view {
98+
require(_fromChainId() == originChainId, "DE/l1-chainId-not-supported");
99+
require(isTrustedExecutor(msg.sender), "DE/l2-sender-not-executor");
100+
require(_msgSender() == address(drawDispatcher), "DE/l1-sender-not-dispatcher");
101+
}
102+
}

contracts/abstract/ExecutorAware.sol

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// SPDX-License-Identifier: GPL-3.0
2+
3+
pragma solidity 0.8.6;
4+
5+
/**
6+
* @title ExecutorAware abstract contract
7+
* @notice The ExecutorAware contract allows contracts on a receiving chain to execute messages from an origin chain.
8+
* These messages are sent by the `MessageDispatcher` contract which live on the origin chain.
9+
* The `MessageExecutor` contract on the receiving chain executes these messages
10+
* and then forward them to an ExecutorAware contract on the receiving chain.
11+
* @dev This contract implements EIP-2771 (https://eips.ethereum.org/EIPS/eip-2771)
12+
* to ensure that messages are sent by a trusted `MessageExecutor` contract.
13+
*/
14+
abstract contract ExecutorAware {
15+
/* ============ Variables ============ */
16+
17+
/// @notice Address of the trusted executor contract.
18+
address public immutable trustedExecutor;
19+
20+
/* ============ Constructor ============ */
21+
22+
/**
23+
* @notice ExecutorAware constructor.
24+
* @param _executor Address of the `MessageExecutor` contract
25+
*/
26+
constructor(address _executor) {
27+
require(_executor != address(0), "executor-not-zero-address");
28+
trustedExecutor = _executor;
29+
}
30+
31+
/* ============ External Functions ============ */
32+
33+
/**
34+
* @notice Check which executor this contract trust.
35+
* @param _executor Address to check
36+
*/
37+
function isTrustedExecutor(address _executor) public view returns (bool) {
38+
return _executor == trustedExecutor;
39+
}
40+
41+
/* ============ Internal Functions ============ */
42+
43+
/**
44+
* @notice Retrieve messageId from message data.
45+
* @return _msgDataMessageId ID uniquely identifying the message that was executed
46+
*/
47+
function _messageId() internal pure returns (bytes32 _msgDataMessageId) {
48+
_msgDataMessageId;
49+
50+
if (msg.data.length >= 84) {
51+
assembly {
52+
_msgDataMessageId := calldataload(sub(calldatasize(), 84))
53+
}
54+
}
55+
}
56+
57+
/**
58+
* @notice Retrieve fromChainId from message data.
59+
* @return _msgDataFromChainId ID of the chain that dispatched the messages
60+
*/
61+
function _fromChainId() internal pure returns (uint256 _msgDataFromChainId) {
62+
_msgDataFromChainId;
63+
64+
if (msg.data.length >= 52) {
65+
assembly {
66+
_msgDataFromChainId := calldataload(sub(calldatasize(), 52))
67+
}
68+
}
69+
}
70+
71+
/**
72+
* @notice Retrieve signer address from message data.
73+
* @return _signer Address of the signer
74+
*/
75+
function _msgSender() internal view returns (address payable _signer) {
76+
_signer = payable(msg.sender);
77+
78+
if (msg.data.length >= 20 && isTrustedExecutor(_signer)) {
79+
assembly {
80+
_signer := shr(96, calldataload(sub(calldatasize(), 20)))
81+
}
82+
}
83+
}
84+
}

0 commit comments

Comments
 (0)