-
Notifications
You must be signed in to change notification settings - Fork 27
/
CountdownGriefing.sol
164 lines (126 loc) · 5.51 KB
/
CountdownGriefing.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
pragma solidity ^0.5.0;
import "../helpers/openzeppelin-solidity/math/SafeMath.sol";
import "../helpers/openzeppelin-solidity/token/ERC20/IERC20.sol";
import "../modules/Countdown.sol";
import "../modules/Griefing.sol";
import "../modules/EventMetadata.sol";
import "../modules/Operated.sol";
import "../modules/Template.sol";
/* Immediately engage with specific buyer
* - Stake can be increased at any time.
* - Request to end agreement and recover stake requires cooldown period to complete.
* - Counterparty can greif the staker at predefined ratio.
*
* NOTE:
* - This top level contract should only perform access control and state transitions
*
*/
contract CountdownGriefing is Countdown, Griefing, EventMetadata, Operated, Template {
using SafeMath for uint256;
Data private _data;
struct Data {
address staker;
address counterparty;
}
event Initialized(address operator, address staker, address counterparty, uint256 ratio, Griefing.RatioType ratioType, uint256 countdownLength, bytes metadata);
function initialize(
address operator,
address staker,
address counterparty,
uint256 ratio,
Griefing.RatioType ratioType,
uint256 countdownLength,
bytes memory metadata
) public initializeTemplate() {
// set storage values
_data.staker = staker;
_data.counterparty = counterparty;
// set operator
if (operator != address(0)) {
Operated._setOperator(operator);
Operated._activateOperator();
}
// set griefing ratio
Griefing._setRatio(staker, ratio, ratioType);
// set countdown length
Countdown._setLength(countdownLength);
// set metadata
if (metadata.length != 0) {
EventMetadata._setMetadata(metadata);
}
// log initialization params
emit Initialized(operator, staker, counterparty, ratio, ratioType, countdownLength, metadata);
}
// state functions
function setMetadata(bytes memory metadata) public {
// restrict access
require(isStaker(msg.sender) || Operated.isActiveOperator(msg.sender), "only staker or active operator");
// update metadata
EventMetadata._setMetadata(metadata);
}
function increaseStake(uint256 currentStake, uint256 amountToAdd) public {
// restrict access
require(isStaker(msg.sender) || Operated.isActiveOperator(msg.sender), "only staker or active operator");
// require agreement is not ended
require(!Countdown.isOver(), "agreement ended");
// add stake
Staking._addStake(_data.staker, msg.sender, currentStake, amountToAdd);
}
function reward(uint256 currentStake, uint256 amountToAdd) public {
// restrict access
require(isCounterparty(msg.sender) || Operated.isActiveOperator(msg.sender), "only counterparty or active operator");
// require agreement is not ended
require(!Countdown.isOver(), "agreement ended");
// add stake
Staking._addStake(_data.staker, msg.sender, currentStake, amountToAdd);
}
function punish(uint256 currentStake, uint256 punishment, bytes memory message) public returns (uint256 cost) {
// restrict access
require(isCounterparty(msg.sender) || Operated.isActiveOperator(msg.sender), "only counterparty or active operator");
// require agreement is not ended
require(!Countdown.isOver(), "agreement ended");
// execute griefing
cost = Griefing._grief(msg.sender, _data.staker, currentStake, punishment, message);
}
function releaseStake(uint256 currentStake, uint256 amountToRelease) public {
// restrict access
require(isCounterparty(msg.sender) || Operated.isActiveOperator(msg.sender), "only counterparty or active operator");
// release stake back to the staker
Staking._takeStake(_data.staker, _data.staker, currentStake, amountToRelease);
}
function startCountdown() public returns (uint256 deadline) {
// restrict access
require(isStaker(msg.sender) || Operated.isActiveOperator(msg.sender), "only staker or active operator");
// require countdown is not started
require(Deadline.getDeadline() == 0, "deadline already set");
// start countdown
deadline = Countdown._start();
}
function retrieveStake(address recipient) public returns (uint256 amount) {
// restrict access
require(isStaker(msg.sender) || Operated.isActiveOperator(msg.sender), "only staker or active operator");
// require deadline is passed
require(Deadline.isAfterDeadline(),"deadline not passed");
// retrieve stake
amount = Staking._takeFullStake(_data.staker, recipient);
}
function transferOperator(address operator) public {
// restrict access
require(Operated.isActiveOperator(msg.sender), "only active operator");
// transfer operator
Operated._transferOperator(operator);
}
function renounceOperator() public {
// restrict access
require(Operated.isActiveOperator(msg.sender), "only active operator");
// transfer operator
Operated._renounceOperator();
}
// view functions
function isStaker(address caller) public view returns (bool validity) {
validity = (caller == _data.staker);
}
function isCounterparty(address caller) public view returns (bool validity) {
validity = (caller == _data.counterparty);
}
}