-
Notifications
You must be signed in to change notification settings - Fork 49
/
DrawBuffer.sol
174 lines (143 loc) Β· 6.03 KB
/
DrawBuffer.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.6;
import "@pooltogether/owner-manager-contracts/contracts/Manageable.sol";
import "./interfaces/IDrawBuffer.sol";
import "./interfaces/IDrawBeacon.sol";
import "./libraries/DrawRingBufferLib.sol";
/**
* @title PoolTogether V4 DrawBuffer
* @author PoolTogether Inc Team
* @notice The DrawBuffer provides historical lookups of Draws via a circular ring buffer.
Historical Draws can be accessed on-chain using a drawId to calculate ring buffer storage slot.
The Draw settings can be created by manager/owner and existing Draws can only be updated the owner.
Once a starting Draw has been added to the ring buffer, all following draws must have a sequential Draw ID.
@dev A DrawBuffer store a limited number of Draws before beginning to overwrite (managed via the cardinality) previous Draws.
@dev All mainnet DrawBuffer(s) are updated directly from a DrawBeacon, but non-mainnet DrawBuffer(s) (Matic, Optimism, Arbitrum, etc...)
will receive a cross-chain message, duplicating the mainnet Draw configuration - enabling a prize savings liquidity network.
*/
contract DrawBuffer is IDrawBuffer, Manageable {
using DrawRingBufferLib for DrawRingBufferLib.Buffer;
/// @notice Draws ring buffer max length.
uint16 public constant MAX_CARDINALITY = 256;
/// @notice Draws ring buffer array.
IDrawBeacon.Draw[MAX_CARDINALITY] private drawRingBuffer;
/// @notice Holds ring buffer information
DrawRingBufferLib.Buffer internal bufferMetadata;
/* ============ Deploy ============ */
/**
* @notice Deploy DrawBuffer smart contract.
* @param _owner Address of the owner of the DrawBuffer.
* @param _cardinality Draw ring buffer cardinality.
*/
constructor(address _owner, uint8 _cardinality) Ownable(_owner) {
bufferMetadata.cardinality = _cardinality;
}
/* ============ External Functions ============ */
/// @inheritdoc IDrawBuffer
function getBufferCardinality() external view override returns (uint32) {
return bufferMetadata.cardinality;
}
/// @inheritdoc IDrawBuffer
function getDraw(uint32 drawId) external view override returns (IDrawBeacon.Draw memory) {
return drawRingBuffer[_drawIdToDrawIndex(bufferMetadata, drawId)];
}
/// @inheritdoc IDrawBuffer
function getDraws(uint32[] calldata _drawIds)
external
view
override
returns (IDrawBeacon.Draw[] memory)
{
IDrawBeacon.Draw[] memory draws = new IDrawBeacon.Draw[](_drawIds.length);
DrawRingBufferLib.Buffer memory buffer = bufferMetadata;
for (uint256 index = 0; index < _drawIds.length; index++) {
draws[index] = drawRingBuffer[_drawIdToDrawIndex(buffer, _drawIds[index])];
}
return draws;
}
/// @inheritdoc IDrawBuffer
function getDrawCount() external view override returns (uint32) {
DrawRingBufferLib.Buffer memory buffer = bufferMetadata;
if (buffer.lastDrawId == 0) {
return 0;
}
uint32 bufferNextIndex = buffer.nextIndex;
if (drawRingBuffer[bufferNextIndex].timestamp != 0) {
return buffer.cardinality;
} else {
return bufferNextIndex;
}
}
/// @inheritdoc IDrawBuffer
function getNewestDraw() external view override returns (IDrawBeacon.Draw memory) {
return _getNewestDraw(bufferMetadata);
}
/// @inheritdoc IDrawBuffer
function getOldestDraw() external view override returns (IDrawBeacon.Draw memory) {
// oldest draw should be next available index, otherwise it's at 0
DrawRingBufferLib.Buffer memory buffer = bufferMetadata;
IDrawBeacon.Draw memory draw = drawRingBuffer[buffer.nextIndex];
if (draw.timestamp == 0) {
// if draw is not init, then use draw at 0
draw = drawRingBuffer[0];
}
return draw;
}
/// @inheritdoc IDrawBuffer
function pushDraw(IDrawBeacon.Draw memory _draw)
external
override
onlyManagerOrOwner
returns (uint32)
{
return _pushDraw(_draw);
}
/// @inheritdoc IDrawBuffer
function setDraw(IDrawBeacon.Draw memory _newDraw) external override onlyOwner returns (uint32) {
DrawRingBufferLib.Buffer memory buffer = bufferMetadata;
uint32 index = buffer.getIndex(_newDraw.drawId);
drawRingBuffer[index] = _newDraw;
emit DrawSet(_newDraw.drawId, _newDraw);
return _newDraw.drawId;
}
/* ============ Internal Functions ============ */
/**
* @notice Convert a Draw.drawId to a Draws ring buffer index pointer.
* @dev The getNewestDraw.drawId() is used to calculate a Draws ID delta position.
* @param _drawId Draw.drawId
* @return Draws ring buffer index pointer
*/
function _drawIdToDrawIndex(DrawRingBufferLib.Buffer memory _buffer, uint32 _drawId)
internal
pure
returns (uint32)
{
return _buffer.getIndex(_drawId);
}
/**
* @notice Read newest Draw from the draws ring buffer.
* @dev Uses the lastDrawId to calculate the most recently added Draw.
* @param _buffer Draw ring buffer
* @return IDrawBeacon.Draw
*/
function _getNewestDraw(DrawRingBufferLib.Buffer memory _buffer)
internal
view
returns (IDrawBeacon.Draw memory)
{
return drawRingBuffer[_buffer.getIndex(_buffer.lastDrawId)];
}
/**
* @notice Push Draw onto draws ring buffer history.
* @dev Push new draw onto draws list via authorized manager or owner.
* @param _newDraw IDrawBeacon.Draw
* @return Draw.drawId
*/
function _pushDraw(IDrawBeacon.Draw memory _newDraw) internal returns (uint32) {
DrawRingBufferLib.Buffer memory _buffer = bufferMetadata;
drawRingBuffer[_buffer.nextIndex] = _newDraw;
bufferMetadata = _buffer.push(_newDraw.drawId);
emit DrawSet(_newDraw.drawId, _newDraw);
return _newDraw.drawId;
}
}