@reality.eth/contracts 3.0.46 → 3.0.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/.prettierrc +16 -0
  2. package/abi/solc-0.8.20/RealityETH-4.0.abi.json +1 -0
  3. package/abi/solc-0.8.20/RealityETH_ERC20-4.0.abi.json +1 -0
  4. package/bytecode/Arbitrator.bin +1 -1
  5. package/bytecode/RealityETH-3.0.bin +1 -1
  6. package/bytecode/RealityETH-4.0.bin +1 -0
  7. package/bytecode/RealityETH_ERC20-3.0.bin +1 -1
  8. package/bytecode/RealityETH_ERC20-4.0.bin +1 -0
  9. package/chains/chainid.network.json +5033 -431
  10. package/chains/deployments/300/ETH/RealityETH-3.0.json +7 -0
  11. package/chains/supported.json +3 -0
  12. package/development/contracts/.solhint.json +9 -0
  13. package/development/contracts/Arbitrator.sol +32 -56
  14. package/development/contracts/BalanceHolder.sol +4 -10
  15. package/development/contracts/BalanceHolder_ERC20.sol +5 -11
  16. package/development/contracts/CallbackClient.sol +3 -10
  17. package/development/contracts/ERC20Token.sol +29 -30
  18. package/development/contracts/ExplodingCallbackClient.sol +1 -4
  19. package/development/contracts/IArbitrator.sol +10 -7
  20. package/development/contracts/IArbitratorCore.sol +7 -14
  21. package/development/contracts/IArbitratorCrowdFundable.sol +3 -2
  22. package/development/contracts/IArbitratorErrors.sol +10 -0
  23. package/development/contracts/IArbitratorForeignProxy.sol +1 -1
  24. package/development/contracts/IArbitratorLegacy.sol +3 -3
  25. package/development/contracts/IArbitratorManagement.sol +15 -27
  26. package/development/contracts/IBalanceHolder.sol +3 -3
  27. package/development/contracts/IBalanceHolder_ERC20.sol +5 -5
  28. package/development/contracts/IERC20.sol +4 -5
  29. package/development/contracts/IOwned.sol +3 -3
  30. package/development/contracts/IRealityETH.sol +5 -58
  31. package/development/contracts/IRealityETHCommitReveal.sol +17 -0
  32. package/development/contracts/IRealityETHCommitReveal_ERC20.sol +16 -0
  33. package/development/contracts/IRealityETHCore.sol +135 -0
  34. package/development/contracts/IRealityETHCore_ERC20.sol +149 -0
  35. package/development/contracts/IRealityETHErrors.sol +86 -0
  36. package/development/contracts/IRealityETHErrors_ERC20.sol +13 -0
  37. package/development/contracts/IRealityETH_ERC20.sol +5 -62
  38. package/development/contracts/Owned.sol +4 -6
  39. package/development/contracts/{RealityETH-3.0.sol → RealityETH-4.0.sol} +221 -383
  40. package/development/contracts/{RealityETH_ERC20-3.0.sol → RealityETH_ERC20-4.0.sol} +238 -474
  41. package/development/contracts/RealityETH_ERC20_Factory.sol +47 -42
  42. package/development/contracts/RegisteredWalletArbitrator.sol +8 -15
  43. package/development/contracts/compile.py +3 -0
  44. package/development/scripts/string_to_error.py +111 -0
  45. package/development/version_checksums/check_matches_flat.sh +20 -0
  46. package/development/version_checksums/check_matches_last.sh +37 -0
  47. package/development/version_checksums/log_bytecode_history.sh +41 -0
  48. package/generated/chains.json +33 -5
  49. package/generated/tokens.json +1 -0
  50. package/non_standard_deployments/zksync/LICENSE +21 -0
  51. package/non_standard_deployments/zksync/README.md +51 -0
  52. package/non_standard_deployments/zksync/deploy/deploy.ts +11 -0
  53. package/non_standard_deployments/zksync/deploy/utils.ts +168 -0
  54. package/non_standard_deployments/zksync/hardhat.config.ts +55 -0
  55. package/non_standard_deployments/zksync/package-lock.json +6295 -0
  56. package/non_standard_deployments/zksync/package.json +34 -0
  57. package/package.json +7 -3
  58. package/scripts/transfer_arbitrator.js +60 -0
  59. package/tests/python/requirements.txt +55 -54
  60. package/tests/python/test.py +150 -50
  61. package/tests/python/test_erc20.py +15 -14
  62. package/tokens/ETH.json +3 -2
  63. package/non_standard_deployments/zksync2/README +0 -21
  64. package/non_standard_deployments/zksync2/contracts/RealityETH_ERC20-3.0.sol +0 -1096
  65. package/non_standard_deployments/zksync2/deploy/deploy.ts +0 -62
  66. package/non_standard_deployments/zksync2/deploy/deploy_erc20.ts +0 -56
  67. package/non_standard_deployments/zksync2/deploy/deploy_mainnet.ts +0 -46
  68. package/non_standard_deployments/zksync2/hardhat.config.ts +0 -27
  69. package/non_standard_deployments/zksync2/package.json +0 -15
  70. package/non_standard_deployments/zksync2/yarn.lock +0 -2898
  71. /package/non_standard_deployments/{zksync2 → zksync}/contracts/RealityETH-3.0.sol +0 -0
@@ -1,154 +1,39 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
 
3
- pragma solidity ^0.8.10;
3
+ pragma solidity ^0.8.20;
4
4
 
5
- import './BalanceHolder_ERC20.sol';
5
+ import {IERC20} from "./IERC20.sol";
6
+ import {IRealityETHCore_ERC20} from "./IRealityETHCore_ERC20.sol";
7
+ import {BalanceHolder_ERC20} from "./BalanceHolder_ERC20.sol";
6
8
 
7
- contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
8
-
9
- address constant NULL_ADDRESS = address(0);
9
+ // solhint-disable-next-line contract-name-camelcase
10
+ contract RealityETH_ERC20_v4_0 is BalanceHolder_ERC20, IRealityETHCore_ERC20 {
11
+ address private constant NULL_ADDRESS = address(0);
10
12
 
11
13
  // History hash when no history is created, or history has been cleared
12
- bytes32 constant NULL_HASH = bytes32(0);
14
+ bytes32 private constant NULL_HASH = bytes32(0);
13
15
 
14
16
  // An unitinalized finalize_ts for a question will indicate an unanswered question.
15
- uint32 constant UNANSWERED = 0;
16
-
17
- // An unanswered reveal_ts for a commitment will indicate that it does not exist.
18
- uint256 constant COMMITMENT_NON_EXISTENT = 0;
19
-
20
- // Commit->reveal timeout is 1/8 of the question timeout (rounded down).
21
- uint32 constant COMMITMENT_TIMEOUT_RATIO = 8;
17
+ uint32 private constant UNANSWERED = 0;
22
18
 
23
19
  // Proportion withheld when you claim an earlier bond.
24
- uint256 constant BOND_CLAIM_FEE_PROPORTION = 40; // One 40th ie 2.5%
20
+ uint256 private constant BOND_CLAIM_FEE_PROPORTION = 40; // One 40th ie 2.5%
25
21
 
26
22
  // Special value representing a question that was answered too soon.
27
23
  // bytes32(-2). By convention we use bytes32(-1) for "invalid", although the contract does not handle this.
28
- bytes32 constant UNRESOLVED_ANSWER = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe;
29
-
30
- event LogSetQuestionFee(
31
- address arbitrator,
32
- uint256 amount
33
- );
34
-
35
- event LogNewTemplate(
36
- uint256 indexed template_id,
37
- address indexed user,
38
- string question_text
39
- );
40
-
41
- event LogNewQuestion(
42
- bytes32 indexed question_id,
43
- address indexed user,
44
- uint256 template_id,
45
- string question,
46
- bytes32 indexed content_hash,
47
- address arbitrator,
48
- uint32 timeout,
49
- uint32 opening_ts,
50
- uint256 nonce,
51
- uint256 created
52
- );
53
-
54
- event LogMinimumBond(
55
- bytes32 indexed question_id,
56
- uint256 min_bond
57
- );
58
-
59
- event LogFundAnswerBounty(
60
- bytes32 indexed question_id,
61
- uint256 bounty_added,
62
- uint256 bounty,
63
- address indexed user
64
- );
65
-
66
- event LogNewAnswer(
67
- bytes32 answer,
68
- bytes32 indexed question_id,
69
- bytes32 history_hash,
70
- address indexed user,
71
- uint256 bond,
72
- uint256 ts,
73
- bool is_commitment
74
- );
75
-
76
- event LogAnswerReveal(
77
- bytes32 indexed question_id,
78
- address indexed user,
79
- bytes32 indexed answer_hash,
80
- bytes32 answer,
81
- uint256 nonce,
82
- uint256 bond
83
- );
84
-
85
- event LogNotifyOfArbitrationRequest(
86
- bytes32 indexed question_id,
87
- address indexed user
88
- );
89
-
90
- event LogCancelArbitration(
91
- bytes32 indexed question_id
92
- );
93
-
94
- event LogFinalize(
95
- bytes32 indexed question_id,
96
- bytes32 indexed answer
97
- );
98
-
99
- event LogClaim(
100
- bytes32 indexed question_id,
101
- address indexed user,
102
- uint256 amount
103
- );
104
-
105
- event LogReopenQuestion(
106
- bytes32 indexed question_id,
107
- bytes32 indexed reopened_question_id
108
- );
109
-
110
- struct Question {
111
- bytes32 content_hash;
112
- address arbitrator;
113
- uint32 opening_ts;
114
- uint32 timeout;
115
- uint32 finalize_ts;
116
- bool is_pending_arbitration;
117
- uint256 bounty;
118
- bytes32 best_answer;
119
- bytes32 history_hash;
120
- uint256 bond;
121
- uint256 min_bond;
122
- }
123
-
124
- // Stored in a mapping indexed by commitment_id, a hash of commitment hash, question, bond.
125
- struct Commitment {
126
- uint32 reveal_ts;
127
- bool is_revealed;
128
- bytes32 revealed_answer;
129
- }
130
-
131
- // Only used when claiming more bonds than fits into a transaction
132
- // Stored in a mapping indexed by question_id.
133
- struct Claim {
134
- address payee;
135
- uint256 last_bond;
136
- uint256 queued_funds;
137
- }
24
+ bytes32 private constant UNRESOLVED_ANSWER = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe;
138
25
 
139
- uint256 nextTemplateID = 0;
26
+ uint256 private nextTemplateID = 0;
140
27
  mapping(uint256 => uint256) public templates;
141
28
  mapping(uint256 => bytes32) public template_hashes;
142
29
  mapping(bytes32 => Question) public questions;
143
30
  mapping(bytes32 => Claim) public question_claims;
144
- mapping(bytes32 => Commitment) public commitments;
145
- mapping(address => uint256) public arbitrator_question_fees;
31
+ mapping(address => uint256) public arbitrator_question_fees;
146
32
  mapping(bytes32 => bytes32) public reopened_questions;
147
33
  mapping(bytes32 => bool) public reopener_questions;
148
34
 
149
-
150
35
  modifier onlyArbitrator(bytes32 question_id) {
151
- require(msg.sender == questions[question_id].arbitrator, "msg.sender must be arbitrator");
36
+ if (msg.sender != questions[question_id].arbitrator) revert MsgSenderMustBeArbitrator();
152
37
  _;
153
38
  }
154
39
 
@@ -157,57 +42,58 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
157
42
  }
158
43
 
159
44
  modifier stateNotCreated(bytes32 question_id) {
160
- require(questions[question_id].timeout == 0, "question must not exist");
45
+ if (questions[question_id].timeout != 0) revert QuestionMustNotExist();
161
46
  _;
162
47
  }
163
48
 
164
49
  modifier stateOpen(bytes32 question_id) {
165
- require(questions[question_id].timeout > 0, "question must exist");
166
- require(!questions[question_id].is_pending_arbitration, "question must not be pending arbitration");
50
+ if (questions[question_id].timeout == 0) revert QuestionMustExist();
51
+ if (questions[question_id].is_pending_arbitration) revert QuestionMustNotBePendingArbitration();
167
52
  uint32 finalize_ts = questions[question_id].finalize_ts;
168
- require(finalize_ts == UNANSWERED || finalize_ts > uint32(block.timestamp), "finalization deadline must not have passed");
53
+ if (finalize_ts != UNANSWERED && finalize_ts <= uint32(block.timestamp)) revert FinalizationDeadlineMustNotHavePassed();
169
54
  uint32 opening_ts = questions[question_id].opening_ts;
170
- require(opening_ts == 0 || opening_ts <= uint32(block.timestamp), "opening date must have passed");
55
+ if (opening_ts != 0 && opening_ts > uint32(block.timestamp)) revert OpeningDateMustHavePassed();
171
56
  _;
172
57
  }
173
58
 
174
59
  modifier statePendingArbitration(bytes32 question_id) {
175
- require(questions[question_id].is_pending_arbitration, "question must be pending arbitration");
60
+ if (!questions[question_id].is_pending_arbitration) revert QuestionMustBePendingArbitration();
176
61
  _;
177
62
  }
178
63
 
179
64
  modifier stateOpenOrPendingArbitration(bytes32 question_id) {
180
- require(questions[question_id].timeout > 0, "question must exist");
65
+ if (questions[question_id].timeout == 0) revert QuestionMustExist();
181
66
  uint32 finalize_ts = questions[question_id].finalize_ts;
182
- require(finalize_ts == UNANSWERED || finalize_ts > uint32(block.timestamp), "finalization dealine must not have passed");
67
+ if (finalize_ts != UNANSWERED && finalize_ts <= uint32(block.timestamp)) revert FinalizationDealineMustNotHavePassed();
183
68
  uint32 opening_ts = questions[question_id].opening_ts;
184
- require(opening_ts == 0 || opening_ts <= uint32(block.timestamp), "opening date must have passed");
69
+ if (opening_ts != 0 && opening_ts > uint32(block.timestamp)) revert OpeningDateMustHavePassed();
185
70
  _;
186
71
  }
187
72
 
188
73
  modifier stateFinalized(bytes32 question_id) {
189
- require(isFinalized(question_id), "question must be finalized");
74
+ if (!isFinalized(question_id)) revert QuestionMustBeFinalized();
190
75
  _;
191
76
  }
192
77
 
193
78
  modifier bondMustDoubleAndMatchMinimum(bytes32 question_id, uint256 tokens) {
194
- require(tokens > 0, "bond must be positive");
79
+ if (tokens == 0) revert BondMustBePositive();
195
80
  uint256 current_bond = questions[question_id].bond;
196
81
  if (current_bond == 0) {
197
- require(tokens >= (questions[question_id].min_bond), "bond must exceed the minimum");
82
+ if (tokens < (questions[question_id].min_bond)) revert BondMustExceedTheMinimum();
198
83
  } else {
199
- require(tokens >= (current_bond * 2), "bond must be double at least previous bond");
84
+ if (tokens < (current_bond * 2)) revert BondMustBeDoubleAtLeastPreviousBond();
200
85
  }
201
86
  _;
202
87
  }
203
88
 
204
89
  modifier previousBondMustNotBeatMaxPrevious(bytes32 question_id, uint256 max_previous) {
205
90
  if (max_previous > 0) {
206
- require(questions[question_id].bond <= max_previous, "bond must exceed max_previous");
91
+ if (questions[question_id].bond > max_previous) revert BondMustExceedMax_Previous();
207
92
  }
208
93
  _;
209
94
  }
210
95
 
96
+ /* solhint-disable quotes */
211
97
  /// @notice Constructor, sets up some initial templates
212
98
  /// @dev Creates some generalized templates for different question types used in the DApp.
213
99
  constructor() {
@@ -217,23 +103,20 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
217
103
  createTemplate('{"title": "%s", "type": "multiple-select", "outcomes": [%s], "category": "%s", "lang": "%s"}');
218
104
  createTemplate('{"title": "%s", "type": "datetime", "category": "%s", "lang": "%s"}');
219
105
  }
106
+ /* solhint-enable quotes */
220
107
 
221
108
  /// @notice Set the address of the ERC20 token that will be used for bonds.
222
109
  /// @dev Should not be used with ERC20-like token contracts that implement callbacks like ERC777 that could cause re-entrancy issues
223
110
  /// @param _token The ERC20 token that will be used for bonds.
224
- function setToken(IERC20 _token)
225
- public
226
- {
227
- require(token == IERC20(address(0x0)), "Token can only be initialized once");
111
+ function setToken(IERC20 _token) public {
112
+ if (token != IERC20(address(0x0))) revert TokenCanOnlyBeInitializedOnce();
228
113
  token = _token;
229
114
  }
230
115
 
231
- /// @notice Function for arbitrator to set an optional per-question fee.
116
+ /// @notice Function for arbitrator to set an optional per-question fee.
232
117
  /// @dev The per-question fee, charged when a question is asked, is intended as an anti-spam measure.
233
118
  /// @param fee The fee to be charged by the arbitrator when a question is asked
234
- function setQuestionFee(uint256 fee)
235
- stateAny()
236
- external {
119
+ function setQuestionFee(uint256 fee) external stateAny {
237
120
  arbitrator_question_fees[msg.sender] = fee;
238
121
  emit LogSetQuestionFee(msg.sender, fee);
239
122
  }
@@ -243,9 +126,7 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
243
126
  /// @dev Template data is only stored in the event logs, but its block number is kept in contract storage.
244
127
  /// @param content The template content
245
128
  /// @return The ID of the newly-created template, which is created sequentially.
246
- function createTemplate(string memory content)
247
- stateAny()
248
- public returns (uint256) {
129
+ function createTemplate(string memory content) public stateAny returns (uint256) {
249
130
  uint256 id = nextTemplateID;
250
131
  templates[id] = block.number;
251
132
  template_hashes[id] = keccak256(abi.encodePacked(content));
@@ -264,11 +145,19 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
264
145
  /// @param nonce A user-specified nonce used in the question ID. Change it to repeat a question.
265
146
  /// @return The ID of the newly-created template, which is created sequentially.
266
147
  function createTemplateAndAskQuestion(
267
- string memory content,
268
- string memory question, address arbitrator, uint32 timeout, uint32 opening_ts, uint256 nonce
269
- )
270
- // stateNotCreated is enforced by the internal _askQuestion
271
- public returns (bytes32) {
148
+ string memory content,
149
+ string memory question,
150
+ address arbitrator,
151
+ uint32 timeout,
152
+ uint32 opening_ts,
153
+ uint256 nonce
154
+ )
155
+ public
156
+ returns (
157
+ // stateNotCreated is enforced by the internal _askQuestion
158
+ bytes32
159
+ )
160
+ {
272
161
  uint256 template_id = createTemplate(content);
273
162
  return askQuestion(template_id, question, arbitrator, timeout, opening_ts, nonce);
274
163
  }
@@ -284,11 +173,21 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
284
173
  /// @param opening_ts If set, the earliest time it should be possible to answer the question.
285
174
  /// @param nonce A user-specified nonce used in the question ID. Change it to repeat a question.
286
175
  /// @return The ID of the newly-created question, created deterministically.
287
- function askQuestion(uint256 template_id, string memory question, address arbitrator, uint32 timeout, uint32 opening_ts, uint256 nonce)
288
- // stateNotCreated is enforced by the internal _askQuestion
289
- public returns (bytes32) {
290
-
291
- require(templates[template_id] > 0, "template must exist");
176
+ function askQuestion(
177
+ uint256 template_id,
178
+ string memory question,
179
+ address arbitrator,
180
+ uint32 timeout,
181
+ uint32 opening_ts,
182
+ uint256 nonce
183
+ )
184
+ public
185
+ returns (
186
+ // stateNotCreated is enforced by the internal _askQuestion
187
+ bytes32
188
+ )
189
+ {
190
+ if (templates[template_id] == 0) revert TemplateMustExist();
292
191
 
293
192
  bytes32 content_hash = keccak256(abi.encodePacked(template_id, opening_ts, question));
294
193
  bytes32 question_id = keccak256(abi.encodePacked(content_hash, arbitrator, timeout, uint256(0), address(this), msg.sender, nonce));
@@ -310,13 +209,24 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
310
209
  /// @param nonce A user-specified nonce used in the question ID. Change it to repeat a question.
311
210
  /// @param tokens The combined initial question bounty and question fee
312
211
  /// @return The ID of the newly-created question, created deterministically.
313
- function askQuestionERC20(uint256 template_id, string memory question, address arbitrator, uint32 timeout, uint32 opening_ts, uint256 nonce, uint256 tokens)
314
- // stateNotCreated is enforced by the internal _askQuestion
315
- public returns (bytes32) {
316
-
212
+ function askQuestionERC20(
213
+ uint256 template_id,
214
+ string memory question,
215
+ address arbitrator,
216
+ uint32 timeout,
217
+ uint32 opening_ts,
218
+ uint256 nonce,
219
+ uint256 tokens
220
+ )
221
+ public
222
+ returns (
223
+ // stateNotCreated is enforced by the internal _askQuestion
224
+ bytes32
225
+ )
226
+ {
317
227
  _deductTokensOrRevert(tokens);
318
228
 
319
- require(templates[template_id] > 0, "template must exist");
229
+ if (templates[template_id] == 0) revert TemplateMustExist();
320
230
 
321
231
  bytes32 content_hash = keccak256(abi.encodePacked(template_id, opening_ts, question));
322
232
  bytes32 question_id = keccak256(abi.encodePacked(content_hash, arbitrator, timeout, uint256(0), address(this), msg.sender, nonce));
@@ -339,13 +249,25 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
339
249
  /// @param min_bond The minimum bond that may be used for an answer.
340
250
  /// @param tokens Number of tokens sent
341
251
  /// @return The ID of the newly-created question, created deterministically.
342
- function askQuestionWithMinBondERC20(uint256 template_id, string memory question, address arbitrator, uint32 timeout, uint32 opening_ts, uint256 nonce, uint256 min_bond, uint256 tokens)
343
- // stateNotCreated is enforced by the internal _askQuestion
344
- public returns (bytes32) {
345
-
252
+ function askQuestionWithMinBondERC20(
253
+ uint256 template_id,
254
+ string memory question,
255
+ address arbitrator,
256
+ uint32 timeout,
257
+ uint32 opening_ts,
258
+ uint256 nonce,
259
+ uint256 min_bond,
260
+ uint256 tokens
261
+ )
262
+ public
263
+ returns (
264
+ // stateNotCreated is enforced by the internal _askQuestion
265
+ bytes32
266
+ )
267
+ {
346
268
  _deductTokensOrRevert(tokens);
347
269
 
348
- require(templates[template_id] > 0, "template must exist");
270
+ if (templates[template_id] == 0) revert TemplateMustExist();
349
271
 
350
272
  bytes32 content_hash = keccak256(abi.encodePacked(template_id, opening_ts, question));
351
273
  bytes32 question_id = keccak256(abi.encodePacked(content_hash, arbitrator, timeout, min_bond, address(this), msg.sender, nonce));
@@ -358,9 +280,7 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
358
280
  return question_id;
359
281
  }
360
282
 
361
- function _deductTokensOrRevert(uint256 tokens)
362
- internal {
363
-
283
+ function _deductTokensOrRevert(uint256 tokens) internal {
364
284
  if (tokens == 0) {
365
285
  return;
366
286
  }
@@ -377,30 +297,26 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
377
297
  balanceOf[msg.sender] = 0;
378
298
  }
379
299
  }
380
- // Now we need to charge the rest from
381
- require(token.transferFrom(msg.sender, address(this), tokens), "Transfer of tokens failed, insufficient approved balance?");
300
+ // Now we need to charge the rest from
301
+ if (!token.transferFrom(msg.sender, address(this), tokens)) revert TransferOfTokensFailedInsufficientApprovedBalance();
382
302
  return;
383
-
384
303
  }
385
304
 
386
- function _askQuestion(bytes32 question_id, bytes32 content_hash, address arbitrator, uint32 timeout, uint32 opening_ts, uint256 min_bond, uint256 tokens)
387
- stateNotCreated(question_id)
388
- internal {
389
-
305
+ function _askQuestion(bytes32 question_id, bytes32 content_hash, address arbitrator, uint32 timeout, uint32 opening_ts, uint256 min_bond, uint256 tokens) internal stateNotCreated(question_id) {
390
306
  // A timeout of 0 makes no sense, and we will use this to check existence
391
- require(timeout > 0, "timeout must be positive");
392
- require(timeout < 365 days, "timeout must be less than 365 days");
307
+ if (timeout == 0) revert TimeoutMustBePositive();
308
+ if (timeout >= 365 days) revert TimeoutMustBeLessThan365Days();
393
309
 
394
310
  uint256 bounty = tokens;
395
311
 
396
- // The arbitrator can set a fee for asking a question.
312
+ // The arbitrator can set a fee for asking a question.
397
313
  // This is intended as an anti-spam defence.
398
314
  // The fee is waived if the arbitrator is asking the question.
399
315
  // This allows them to set an impossibly high fee and make users proxy the question through them.
400
316
  // This would allow more sophisticated pricing, question whitelisting etc.
401
317
  if (arbitrator != NULL_ADDRESS && msg.sender != arbitrator) {
402
318
  uint256 question_fee = arbitrator_question_fees[arbitrator];
403
- require(bounty >= question_fee, "Tokens provided must cover question fee");
319
+ if (bounty < question_fee) revert TokensProvidedMustCoverQuestionFee();
404
320
  bounty = bounty - question_fee;
405
321
  balanceOf[arbitrator] = balanceOf[arbitrator] + question_fee;
406
322
  }
@@ -419,16 +335,13 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
419
335
  questions[question_id].min_bond = min_bond;
420
336
  emit LogMinimumBond(question_id, min_bond);
421
337
  }
422
-
423
338
  }
424
339
 
425
340
  /// @notice Add funds to the bounty for a question
426
341
  /// @dev Add bounty funds after the initial question creation. Can be done any time until the question is finalized.
427
342
  /// @param question_id The ID of the question you wish to fund
428
343
  /// @param tokens The number of tokens to fund
429
- function fundAnswerBountyERC20(bytes32 question_id, uint256 tokens)
430
- stateOpen(question_id)
431
- external {
344
+ function fundAnswerBountyERC20(bytes32 question_id, uint256 tokens) external stateOpen(question_id) {
432
345
  _deductTokensOrRevert(tokens);
433
346
  questions[question_id].bounty = questions[question_id].bounty + tokens;
434
347
  emit LogFundAnswerBounty(question_id, tokens, questions[question_id].bounty, msg.sender);
@@ -436,113 +349,43 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
436
349
 
437
350
  /// @notice Submit an answer for a question.
438
351
  /// @dev Adds the answer to the history and updates the current "best" answer.
439
- /// May be subject to front-running attacks; Substitute submitAnswerCommitment()->submitAnswerReveal() to prevent them.
440
352
  /// @param question_id The ID of the question
441
353
  /// @param answer The answer, encoded into bytes32
442
354
  /// @param max_previous If specified, reverts if a bond higher than this was submitted after you sent your transaction.
443
355
  /// @param tokens The amount of tokens to submit
444
- function submitAnswerERC20(bytes32 question_id, bytes32 answer, uint256 max_previous, uint256 tokens)
445
- stateOpen(question_id)
446
- bondMustDoubleAndMatchMinimum(question_id, tokens)
447
- previousBondMustNotBeatMaxPrevious(question_id, max_previous)
448
- external {
356
+ function submitAnswerERC20(
357
+ bytes32 question_id,
358
+ bytes32 answer,
359
+ uint256 max_previous,
360
+ uint256 tokens
361
+ ) external stateOpen(question_id) bondMustDoubleAndMatchMinimum(question_id, tokens) previousBondMustNotBeatMaxPrevious(question_id, max_previous) {
449
362
  _deductTokensOrRevert(tokens);
450
- _addAnswerToHistory(question_id, answer, msg.sender, tokens, false);
363
+ _addAnswerToHistory(question_id, answer, msg.sender, tokens);
451
364
  _updateCurrentAnswer(question_id, answer);
452
365
  }
453
366
 
454
367
  /// @notice Submit an answer for a question, crediting it to the specified account.
455
368
  /// @dev Adds the answer to the history and updates the current "best" answer.
456
- /// May be subject to front-running attacks; Substitute submitAnswerCommitment()->submitAnswerReveal() to prevent them.
457
369
  /// @param question_id The ID of the question
458
370
  /// @param answer The answer, encoded into bytes32
459
371
  /// @param max_previous If specified, reverts if a bond higher than this was submitted after you sent your transaction.
460
372
  /// @param answerer The account to which the answer should be credited
461
373
  /// @param tokens Number of tokens sent
462
- function submitAnswerForERC20(bytes32 question_id, bytes32 answer, uint256 max_previous, address answerer, uint256 tokens)
463
- stateOpen(question_id)
464
- bondMustDoubleAndMatchMinimum(question_id, tokens)
465
- previousBondMustNotBeatMaxPrevious(question_id, max_previous)
466
- external {
374
+ function submitAnswerForERC20(
375
+ bytes32 question_id,
376
+ bytes32 answer,
377
+ uint256 max_previous,
378
+ address answerer,
379
+ uint256 tokens
380
+ ) external stateOpen(question_id) bondMustDoubleAndMatchMinimum(question_id, tokens) previousBondMustNotBeatMaxPrevious(question_id, max_previous) {
467
381
  _deductTokensOrRevert(tokens);
468
- require(answerer != NULL_ADDRESS, "answerer must be non-zero");
469
- _addAnswerToHistory(question_id, answer, answerer, tokens, false);
382
+ if (answerer == NULL_ADDRESS) revert AnswererMustBeNonZero();
383
+ _addAnswerToHistory(question_id, answer, answerer, tokens);
470
384
  _updateCurrentAnswer(question_id, answer);
471
385
  }
472
386
 
473
- // @notice Verify and store a commitment, including an appropriate timeout
474
- // @param question_id The ID of the question to store
475
- // @param commitment The ID of the commitment
476
- function _storeCommitment(bytes32 question_id, bytes32 commitment_id)
477
- internal
478
- {
479
- require(commitments[commitment_id].reveal_ts == COMMITMENT_NON_EXISTENT, "commitment must not already exist");
480
-
481
- uint32 commitment_timeout = questions[question_id].timeout / COMMITMENT_TIMEOUT_RATIO;
482
- commitments[commitment_id].reveal_ts = uint32(block.timestamp) + commitment_timeout;
483
- }
484
-
485
- /// @notice Submit the hash of an answer, laying your claim to that answer if you reveal it in a subsequent transaction.
486
- /// @dev Creates a hash, commitment_id, uniquely identifying this answer, to this question, with this bond.
487
- /// The commitment_id is stored in the answer history where the answer would normally go.
488
- /// Does not update the current best answer - this is left to the later submitAnswerReveal() transaction.
489
- /// @param question_id The ID of the question
490
- /// @param answer_hash The hash of your answer, plus a nonce that you will later reveal
491
- /// @param max_previous If specified, reverts if a bond higher than this was submitted after you sent your transaction.
492
- /// @param _answerer If specified, the address to be given as the question answerer. Defaults to the sender.
493
- /// @param tokens Number of tokens sent
494
- /// @dev Specifying the answerer is useful if you want to delegate the commit-and-reveal to a third-party.
495
- function submitAnswerCommitmentERC20(bytes32 question_id, bytes32 answer_hash, uint256 max_previous, address _answerer, uint256 tokens)
496
- stateOpen(question_id)
497
- bondMustDoubleAndMatchMinimum(question_id, tokens)
498
- previousBondMustNotBeatMaxPrevious(question_id, max_previous)
499
- external {
500
-
501
- _deductTokensOrRevert(tokens);
502
-
503
- bytes32 commitment_id = keccak256(abi.encodePacked(question_id, answer_hash, tokens));
504
- address answerer = (_answerer == NULL_ADDRESS) ? msg.sender : _answerer;
505
-
506
- _storeCommitment(question_id, commitment_id);
507
- _addAnswerToHistory(question_id, commitment_id, answerer, tokens, true);
508
-
509
- }
510
-
511
- /// @notice Submit the answer whose hash you sent in a previous submitAnswerCommitment() transaction
512
- /// @dev Checks the parameters supplied recreate an existing commitment, and stores the revealed answer
513
- /// Updates the current answer unless someone has since supplied a new answer with a higher bond
514
- /// msg.sender is intentionally not restricted to the user who originally sent the commitment;
515
- /// For example, the user may want to provide the answer+nonce to a third-party service and let them send the tx
516
- /// NB If we are pending arbitration, it will be up to the arbitrator to wait and see any outstanding reveal is sent
517
- /// @param question_id The ID of the question
518
- /// @param answer The answer, encoded as bytes32
519
- /// @param nonce The nonce that, combined with the answer, recreates the answer_hash you gave in submitAnswerCommitment()
520
- /// @param bond The bond that you paid in your submitAnswerCommitment() transaction
521
- function submitAnswerReveal(bytes32 question_id, bytes32 answer, uint256 nonce, uint256 bond)
522
- stateOpenOrPendingArbitration(question_id)
523
- external {
524
-
525
- bytes32 answer_hash = keccak256(abi.encodePacked(answer, nonce));
526
- bytes32 commitment_id = keccak256(abi.encodePacked(question_id, answer_hash, bond));
527
-
528
- require(!commitments[commitment_id].is_revealed, "commitment must not have been revealed yet");
529
- require(commitments[commitment_id].reveal_ts > uint32(block.timestamp), "reveal deadline must not have passed");
530
-
531
- commitments[commitment_id].revealed_answer = answer;
532
- commitments[commitment_id].is_revealed = true;
533
-
534
- if (bond == questions[question_id].bond) {
535
- _updateCurrentAnswer(question_id, answer);
536
- }
537
-
538
- emit LogAnswerReveal(question_id, msg.sender, answer_hash, answer, nonce, bond);
539
-
540
- }
541
-
542
- function _addAnswerToHistory(bytes32 question_id, bytes32 answer_or_commitment_id, address answerer, uint256 bond, bool is_commitment)
543
- internal
544
- {
545
- bytes32 new_history_hash = keccak256(abi.encodePacked(questions[question_id].history_hash, answer_or_commitment_id, bond, answerer, is_commitment));
387
+ function _addAnswerToHistory(bytes32 question_id, bytes32 answer, address answerer, uint256 bond) internal {
388
+ bytes32 new_history_hash = keccak256(abi.encodePacked(questions[question_id].history_hash, answer, bond, answerer, false));
546
389
 
547
390
  // Update the current bond level, if there's a bond (ie anything except arbitration)
548
391
  if (bond > 0) {
@@ -550,18 +393,16 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
550
393
  }
551
394
  questions[question_id].history_hash = new_history_hash;
552
395
 
553
- emit LogNewAnswer(answer_or_commitment_id, question_id, new_history_hash, answerer, bond, block.timestamp, is_commitment);
396
+ emit LogNewAnswer(answer, question_id, new_history_hash, answerer, bond, block.timestamp, false);
554
397
  }
555
398
 
556
- function _updateCurrentAnswer(bytes32 question_id, bytes32 answer)
557
- internal {
399
+ function _updateCurrentAnswer(bytes32 question_id, bytes32 answer) internal {
558
400
  questions[question_id].best_answer = answer;
559
401
  questions[question_id].finalize_ts = uint32(block.timestamp) + questions[question_id].timeout;
560
402
  }
561
403
 
562
404
  // Like _updateCurrentAnswer but without advancing the timeout
563
- function _updateCurrentAnswerByArbitrator(bytes32 question_id, bytes32 answer)
564
- internal {
405
+ function _updateCurrentAnswerByArbitrator(bytes32 question_id, bytes32 answer) internal {
565
406
  questions[question_id].best_answer = answer;
566
407
  questions[question_id].finalize_ts = uint32(block.timestamp);
567
408
  }
@@ -571,12 +412,12 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
571
412
  /// @param question_id The ID of the question
572
413
  /// @param requester The account that requested arbitration
573
414
  /// @param max_previous If specified, reverts if a bond higher than this was submitted after you sent your transaction.
574
- function notifyOfArbitrationRequest(bytes32 question_id, address requester, uint256 max_previous)
575
- onlyArbitrator(question_id)
576
- stateOpen(question_id)
577
- previousBondMustNotBeatMaxPrevious(question_id, max_previous)
578
- external {
579
- require(questions[question_id].finalize_ts > UNANSWERED, "Question must already have an answer when arbitration is requested");
415
+ function notifyOfArbitrationRequest(
416
+ bytes32 question_id,
417
+ address requester,
418
+ uint256 max_previous
419
+ ) external onlyArbitrator(question_id) stateOpen(question_id) previousBondMustNotBeatMaxPrevious(question_id, max_previous) {
420
+ if (questions[question_id].finalize_ts <= UNANSWERED) revert QuestionMustAlreadyHaveAnAnswerWhenArbitrationIsRequested();
580
421
  questions[question_id].is_pending_arbitration = true;
581
422
  emit LogNotifyOfArbitrationRequest(question_id, requester);
582
423
  }
@@ -584,10 +425,7 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
584
425
  /// @notice Cancel a previously-requested arbitration and extend the timeout
585
426
  /// @dev Useful when doing arbitration across chains that can't be requested atomically
586
427
  /// @param question_id The ID of the question
587
- function cancelArbitration(bytes32 question_id)
588
- onlyArbitrator(question_id)
589
- statePendingArbitration(question_id)
590
- external {
428
+ function cancelArbitration(bytes32 question_id) external onlyArbitrator(question_id) statePendingArbitration(question_id) {
591
429
  questions[question_id].is_pending_arbitration = false;
592
430
  questions[question_id].finalize_ts = uint32(block.timestamp) + questions[question_id].timeout;
593
431
  emit LogCancelArbitration(question_id);
@@ -601,16 +439,12 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
601
439
  /// @param question_id The ID of the question
602
440
  /// @param answer The answer, encoded into bytes32
603
441
  /// @param answerer The account credited with this answer for the purpose of bond claims
604
- function submitAnswerByArbitrator(bytes32 question_id, bytes32 answer, address answerer)
605
- onlyArbitrator(question_id)
606
- statePendingArbitration(question_id)
607
- public {
608
-
609
- require(answerer != NULL_ADDRESS, "answerer must be provided");
442
+ function submitAnswerByArbitrator(bytes32 question_id, bytes32 answer, address answerer) public onlyArbitrator(question_id) statePendingArbitration(question_id) {
443
+ if (answerer == NULL_ADDRESS) revert AnswererMustBeProvided();
610
444
  emit LogFinalize(question_id, answer);
611
445
 
612
446
  questions[question_id].is_pending_arbitration = false;
613
- _addAnswerToHistory(question_id, answer, answerer, 0, false);
447
+ _addAnswerToHistory(question_id, answer, answerer, 0);
614
448
  _updateCurrentAnswerByArbitrator(question_id, answer);
615
449
  }
616
450
 
@@ -620,71 +454,54 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
620
454
  /// @param answer The answer, encoded into bytes32
621
455
  /// @param payee_if_wrong The account to by credited as winner if the last answer given is wrong, usually the account that paid the arbitrator
622
456
  /// @param last_history_hash The history hash before the final one
623
- /// @param last_answer_or_commitment_id The last answer given, or the commitment ID if it was a commitment.
457
+ /// @param last_answer The last answer given
624
458
  /// @param last_answerer The address that supplied the last answer
625
- function assignWinnerAndSubmitAnswerByArbitrator(bytes32 question_id, bytes32 answer, address payee_if_wrong, bytes32 last_history_hash, bytes32 last_answer_or_commitment_id, address last_answerer)
626
- external {
627
- bool is_commitment = _verifyHistoryInputOrRevert(questions[question_id].history_hash, last_history_hash, last_answer_or_commitment_id, questions[question_id].bond, last_answerer);
628
-
629
- address payee;
630
- // If the last answer is an unrevealed commit, it's always wrong.
631
- // For anything else, the last answer was set as the "best answer" in submitAnswer or submitAnswerReveal.
632
- if (is_commitment && !commitments[last_answer_or_commitment_id].is_revealed) {
633
- require(commitments[last_answer_or_commitment_id].reveal_ts < uint32(block.timestamp), "You must wait for the reveal deadline before finalizing");
634
- payee = payee_if_wrong;
635
- } else {
636
- payee = (questions[question_id].best_answer == answer) ? last_answerer : payee_if_wrong;
637
- }
459
+ function assignWinnerAndSubmitAnswerByArbitrator(bytes32 question_id, bytes32 answer, address payee_if_wrong, bytes32 last_history_hash, bytes32 last_answer, address last_answerer) external {
460
+ _verifyHistoryInputOrRevert(questions[question_id].history_hash, last_history_hash, last_answer, questions[question_id].bond, last_answerer);
461
+
462
+ address payee = (questions[question_id].best_answer == answer) ? last_answerer : payee_if_wrong;
638
463
  submitAnswerByArbitrator(question_id, answer, payee);
639
464
  }
640
465
 
641
-
642
466
  /// @notice Report whether the answer to the specified question is finalized
643
467
  /// @param question_id The ID of the question
644
468
  /// @return Return true if finalized
645
- function isFinalized(bytes32 question_id)
646
- view public returns (bool) {
469
+ function isFinalized(bytes32 question_id) public view returns (bool) {
647
470
  uint32 finalize_ts = questions[question_id].finalize_ts;
648
- return ( !questions[question_id].is_pending_arbitration && (finalize_ts > UNANSWERED) && (finalize_ts <= uint32(block.timestamp)) );
471
+ return (!questions[question_id].is_pending_arbitration && (finalize_ts > UNANSWERED) && (finalize_ts <= uint32(block.timestamp)));
649
472
  }
650
473
 
651
474
  /// @notice (Deprecated) Return the final answer to the specified question, or revert if there isn't one
652
475
  /// @param question_id The ID of the question
653
476
  /// @return The answer formatted as a bytes32
654
- function getFinalAnswer(bytes32 question_id)
655
- stateFinalized(question_id)
656
- external view returns (bytes32) {
477
+ function getFinalAnswer(bytes32 question_id) external view stateFinalized(question_id) returns (bytes32) {
657
478
  return questions[question_id].best_answer;
658
479
  }
659
480
 
660
481
  /// @notice Return the final answer to the specified question, or revert if there isn't one
661
482
  /// @param question_id The ID of the question
662
483
  /// @return The answer formatted as a bytes32
663
- function resultFor(bytes32 question_id)
664
- stateFinalized(question_id)
665
- public view returns (bytes32) {
484
+ function resultFor(bytes32 question_id) public view stateFinalized(question_id) returns (bytes32) {
666
485
  return questions[question_id].best_answer;
667
486
  }
668
487
 
669
488
  /// @notice Returns whether the question was answered before it had an answer, ie resolved to UNRESOLVED_ANSWER
670
- /// @param question_id The ID of the question
671
- function isSettledTooSoon(bytes32 question_id)
672
- public view returns(bool) {
489
+ /// @param question_id The ID of the question
490
+ function isSettledTooSoon(bytes32 question_id) public view returns (bool) {
673
491
  return (resultFor(question_id) == UNRESOLVED_ANSWER);
674
492
  }
675
493
 
676
494
  /// @notice Like resultFor(), but errors out if settled too soon, or returns the result of a replacement if it was reopened at the right time and settled
677
- /// @param question_id The ID of the question
678
- function resultForOnceSettled(bytes32 question_id)
679
- external view returns(bytes32) {
495
+ /// @param question_id The ID of the question
496
+ function resultForOnceSettled(bytes32 question_id) external view returns (bytes32) {
680
497
  bytes32 result = resultFor(question_id);
681
498
  if (result == UNRESOLVED_ANSWER) {
682
499
  // Try the replacement
683
500
  bytes32 replacement_id = reopened_questions[question_id];
684
- require(replacement_id != bytes32(0x0), "Question was settled too soon and has not been reopened");
501
+ if (replacement_id == bytes32(0x0)) revert QuestionWasSettledTooSoonAndHasNotBeenReopened();
685
502
  // We only try one layer down rather than recursing to keep the gas costs predictable
686
503
  result = resultFor(replacement_id);
687
- require(result != UNRESOLVED_ANSWER, "Question replacement was settled too soon and has not been reopened");
504
+ if (result == UNRESOLVED_ANSWER) revert QuestionReplacementWasSettledTooSoonAndHasNotBeenReopened();
688
505
  }
689
506
  return result;
690
507
  }
@@ -701,26 +518,39 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
701
518
  /// @param reopens_question_id The ID of the question this reopens
702
519
  /// @param tokens The number of tokens you want to use as an additional question reward for the reopened question.
703
520
  /// @return The ID of the newly-created question, created deterministically.
704
- function reopenQuestionERC20(uint256 template_id, string memory question, address arbitrator, uint32 timeout, uint32 opening_ts, uint256 nonce, uint256 min_bond, bytes32 reopens_question_id, uint256 tokens)
705
- // stateNotCreated is enforced by the internal _askQuestion
706
- public returns (bytes32) {
707
-
521
+ function reopenQuestionERC20(
522
+ uint256 template_id,
523
+ string memory question,
524
+ address arbitrator,
525
+ uint32 timeout,
526
+ uint32 opening_ts,
527
+ uint256 nonce,
528
+ uint256 min_bond,
529
+ bytes32 reopens_question_id,
530
+ uint256 tokens
531
+ )
532
+ public
533
+ returns (
534
+ // stateNotCreated is enforced by the internal _askQuestion
535
+ bytes32
536
+ )
537
+ {
708
538
  // _deductTokensOrRevert will be called when we call askQuestionWithMinBondERC20
709
539
 
710
- require(isSettledTooSoon(reopens_question_id), "You can only reopen questions that resolved as settled too soon");
540
+ if (!isSettledTooSoon(reopens_question_id)) revert YouCanOnlyReopenQuestionsThatResolvedAsSettledTooSoon();
711
541
 
712
542
  bytes32 content_hash = keccak256(abi.encodePacked(template_id, opening_ts, question));
713
543
 
714
544
  // A reopening must exactly match the original question, except for the nonce and the creator
715
- require(content_hash == questions[reopens_question_id].content_hash, "content hash mismatch");
716
- require(arbitrator == questions[reopens_question_id].arbitrator, "arbitrator mismatch");
717
- require(timeout == questions[reopens_question_id].timeout, "timeout mismatch");
718
- require(opening_ts == questions[reopens_question_id].opening_ts , "opening_ts mismatch");
719
- require(min_bond == questions[reopens_question_id].min_bond, "min_bond mismatch");
545
+ if (content_hash != questions[reopens_question_id].content_hash) revert ContentHashMismatch();
546
+ if (arbitrator != questions[reopens_question_id].arbitrator) revert ArbitratorMismatch();
547
+ if (timeout != questions[reopens_question_id].timeout) revert TimeoutMismatch();
548
+ if (opening_ts != questions[reopens_question_id].opening_ts) revert Opening_TsMismatch();
549
+ if (min_bond != questions[reopens_question_id].min_bond) revert Min_BondMismatch();
720
550
 
721
551
  // If the the question was itself reopening some previous question, you'll have to re-reopen the previous question first.
722
552
  // This ensures the bounty can be passed on to the next attempt of the original question.
723
- require(!reopener_questions[reopens_question_id], "Question is already reopening a previous question");
553
+ if (reopener_questions[reopens_question_id]) revert QuestionIsAlreadyReopeningAPreviousQuestion();
724
554
 
725
555
  // A question can only be reopened once, unless the reopening was also settled too soon in which case it can be replaced
726
556
  bytes32 existing_reopen_question_id = reopened_questions[reopens_question_id];
@@ -729,7 +559,7 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
729
559
  bytes32 take_bounty_from_question_id = reopens_question_id;
730
560
  // If the question has already been reopened but was again settled too soon, we can transfer its bounty to the next attempt.
731
561
  if (existing_reopen_question_id != bytes32(0)) {
732
- require(isSettledTooSoon(existing_reopen_question_id), "Question has already been reopened");
562
+ if (!isSettledTooSoon(existing_reopen_question_id)) revert QuestionHasAlreadyBeenReopened();
733
563
  // We'll overwrite the reopening with our new question and move the bounty.
734
564
  // Once that's done we'll detach the failed reopener and you'll be able to reopen that too if you really want, but without the bounty.
735
565
  reopener_questions[existing_reopen_question_id] = false;
@@ -757,16 +587,11 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
757
587
  /// @param min_timeout The timeout set in the initial question settings must be this high or higher
758
588
  /// @param min_bond The bond sent with the final answer must be this high or higher
759
589
  /// @return The answer formatted as a bytes32
760
- function getFinalAnswerIfMatches(
761
- bytes32 question_id,
762
- bytes32 content_hash, address arbitrator, uint32 min_timeout, uint256 min_bond
763
- )
764
- stateFinalized(question_id)
765
- external view returns (bytes32) {
766
- require(content_hash == questions[question_id].content_hash, "content hash must match");
767
- require(arbitrator == questions[question_id].arbitrator, "arbitrator must match");
768
- require(min_timeout <= questions[question_id].timeout, "timeout must be long enough");
769
- require(min_bond <= questions[question_id].bond, "bond must be high enough");
590
+ function getFinalAnswerIfMatches(bytes32 question_id, bytes32 content_hash, address arbitrator, uint32 min_timeout, uint256 min_bond) external view stateFinalized(question_id) returns (bytes32) {
591
+ if (content_hash != questions[question_id].content_hash) revert ContentHashMustMatch();
592
+ if (arbitrator != questions[question_id].arbitrator) revert ArbitratorMustMatch();
593
+ if (min_timeout > questions[question_id].timeout) revert TimeoutMustBeLongEnough();
594
+ if (min_bond > questions[question_id].bond) revert BondMustBeHighEnough();
770
595
  return questions[question_id].best_answer;
771
596
  }
772
597
 
@@ -781,22 +606,16 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
781
606
  /// Usually you would call the whole thing in a single transaction, but if not then the data is persisted to pick up later.
782
607
  /// @param question_id The ID of the question
783
608
  /// @param history_hashes Second-last-to-first, the hash of each history entry. (Final one should be empty).
784
- /// @param addrs Last-to-first, the address of each answerer or commitment sender
785
- /// @param bonds Last-to-first, the bond supplied with each answer or commitment
786
- /// @param answers Last-to-first, each answer supplied, or commitment ID if the answer was supplied with commit->reveal
787
- function claimWinnings(
788
- bytes32 question_id,
789
- bytes32[] memory history_hashes, address[] memory addrs, uint256[] memory bonds, bytes32[] memory answers
790
- )
791
- stateFinalized(question_id)
792
- public {
793
-
794
- require(history_hashes.length > 0, "at least one history hash entry must be provided");
609
+ /// @param addrs Last-to-first, the address of each answerer
610
+ /// @param bonds Last-to-first, the bond supplied with each answer
611
+ /// @param answers Last-to-first, each answer supplied
612
+ function claimWinnings(bytes32 question_id, bytes32[] memory history_hashes, address[] memory addrs, uint256[] memory bonds, bytes32[] memory answers) public stateFinalized(question_id) {
613
+ if (history_hashes.length == 0) revert AtLeastOneHistoryHashEntryMustBeProvided();
795
614
 
796
615
  // These are only set if we split our claim over multiple transactions.
797
- address payee = question_claims[question_id].payee;
798
- uint256 last_bond = question_claims[question_id].last_bond;
799
- uint256 queued_funds = question_claims[question_id].queued_funds;
616
+ address payee = question_claims[question_id].payee;
617
+ uint256 last_bond = question_claims[question_id].last_bond;
618
+ uint256 queued_funds = 0;
800
619
 
801
620
  // Starts as the hash of the final answer submitted. It'll be cleared when we're done.
802
621
  // If we're splitting the claim over multiple transactions, it'll be the hash where we left off last time
@@ -806,15 +625,11 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
806
625
 
807
626
  uint256 i;
808
627
  for (i = 0; i < history_hashes.length; i++) {
809
-
810
- // Check input against the history hash, and see which of 2 possible values of is_commitment fits.
811
- bool is_commitment = _verifyHistoryInputOrRevert(last_history_hash, history_hashes[i], answers[i], bonds[i], addrs[i]);
812
-
813
- queued_funds = queued_funds + last_bond;
814
- (queued_funds, payee) = _processHistoryItem(
815
- question_id, best_answer, queued_funds, payee,
816
- addrs[i], bonds[i], answers[i], is_commitment);
817
-
628
+ _verifyHistoryInputOrRevert(last_history_hash, history_hashes[i], answers[i], bonds[i], addrs[i]);
629
+
630
+ queued_funds = queued_funds + last_bond;
631
+ (queued_funds, payee) = _processHistoryItem(question_id, best_answer, queued_funds, payee, addrs[i], bonds[i], answers[i]);
632
+
818
633
  // Line the bond up for next time, when it will be added to somebody's queued_funds
819
634
  last_bond = bonds[i];
820
635
 
@@ -825,23 +640,17 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
825
640
  }
826
641
 
827
642
  last_history_hash = history_hashes[i];
828
-
829
643
  }
830
-
644
+
831
645
  if (last_history_hash != NULL_HASH) {
832
646
  // We haven't yet got to the null hash (1st answer), ie the caller didn't supply the full answer chain.
833
647
  // Persist the details so we can pick up later where we left off later.
834
648
 
835
- // If we know who to pay we can go ahead and pay them out, only keeping back last_bond
836
- // (We always know who to pay unless all we saw were unrevealed commits)
837
- if (payee != NULL_ADDRESS) {
838
- _payPayee(question_id, payee, queued_funds);
839
- queued_funds = 0;
840
- }
649
+ // Pay out the latest payee, only keeping back last_bond which the next may have a claim on
650
+ _payPayee(question_id, payee, queued_funds);
841
651
 
842
652
  question_claims[question_id].payee = payee;
843
653
  question_claims[question_id].last_bond = last_bond;
844
- question_claims[question_id].queued_funds = queued_funds;
845
654
  } else {
846
655
  // There is nothing left below us so the payee can keep what remains
847
656
  _payPayee(question_id, payee, queued_funds + last_bond);
@@ -849,54 +658,22 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
849
658
  }
850
659
 
851
660
  questions[question_id].history_hash = last_history_hash;
852
-
853
661
  }
854
662
 
855
- function _payPayee(bytes32 question_id, address payee, uint256 value)
856
- internal {
663
+ function _payPayee(bytes32 question_id, address payee, uint256 value) internal {
857
664
  balanceOf[payee] = balanceOf[payee] + value;
858
665
  emit LogClaim(question_id, payee, value);
859
666
  }
860
667
 
861
- function _verifyHistoryInputOrRevert(
862
- bytes32 last_history_hash,
863
- bytes32 history_hash, bytes32 answer, uint256 bond, address addr
864
- )
865
- internal pure returns (bool) {
866
- if (last_history_hash == keccak256(abi.encodePacked(history_hash, answer, bond, addr, true)) ) {
867
- return true;
668
+ function _verifyHistoryInputOrRevert(bytes32 last_history_hash, bytes32 history_hash, bytes32 answer, uint256 bond, address addr) internal pure {
669
+ if (last_history_hash != keccak256(abi.encodePacked(history_hash, answer, bond, addr, false))) {
670
+ revert HistoryInputProvidedDidNotMatchTheExpectedHash();
868
671
  }
869
- if (last_history_hash == keccak256(abi.encodePacked(history_hash, answer, bond, addr, false)) ) {
870
- return false;
871
- }
872
- revert("History input provided did not match the expected hash");
873
672
  }
874
673
 
875
- function _processHistoryItem(
876
- bytes32 question_id, bytes32 best_answer,
877
- uint256 queued_funds, address payee,
878
- address addr, uint256 bond, bytes32 answer, bool is_commitment
879
- )
880
- internal returns (uint256, address) {
881
-
882
- // For commit-and-reveal, the answer history holds the commitment ID instead of the answer.
883
- // We look at the referenced commitment ID and switch in the actual answer.
884
- if (is_commitment) {
885
- bytes32 commitment_id = answer;
886
- // If it's a commit but it hasn't been revealed, it will always be considered wrong.
887
- if (!commitments[commitment_id].is_revealed) {
888
- delete commitments[commitment_id];
889
- return (queued_funds, payee);
890
- } else {
891
- answer = commitments[commitment_id].revealed_answer;
892
- delete commitments[commitment_id];
893
- }
894
- }
895
-
674
+ function _processHistoryItem(bytes32 question_id, bytes32 best_answer, uint256 queued_funds, address payee, address addr, uint256 bond, bytes32 answer) internal returns (uint256, address) {
896
675
  if (answer == best_answer) {
897
-
898
676
  if (payee == NULL_ADDRESS) {
899
-
900
677
  // The entry is for the first payee we come to, ie the winner.
901
678
  // They get the question bounty.
902
679
  payee = addr;
@@ -905,13 +682,11 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
905
682
  _payPayee(question_id, payee, questions[question_id].bounty);
906
683
  questions[question_id].bounty = 0;
907
684
  }
908
-
909
685
  } else if (addr != payee) {
910
-
911
686
  // Answerer has changed, ie we found someone lower down who needs to be paid
912
687
 
913
688
  // The lower answerer will take over receiving bonds from higher answerer.
914
- // They should also be paid the takeover fee, which is set at a rate equivalent to their bond.
689
+ // They should also be paid the takeover fee, which is set at a rate equivalent to their bond.
915
690
  // (This is our arbitrary rule, to give consistent right-answerers a defence against high-rollers.)
916
691
 
917
692
  // There should be enough for the fee, but if not, take what we have.
@@ -923,13 +698,10 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
923
698
  // Now start queued_funds again for the new (lower-bonded) payee
924
699
  payee = addr;
925
700
  queued_funds = answer_takeover_fee;
926
-
927
701
  }
928
-
929
702
  }
930
703
 
931
704
  return (queued_funds, payee);
932
-
933
705
  }
934
706
 
935
707
  /// @notice Convenience function to assign bounties/bonds for multiple questions in one go, then withdraw all your funds.
@@ -938,16 +710,20 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
938
710
  /// @param question_ids The IDs of the questions you want to claim for
939
711
  /// @param lengths The number of history entries you will supply for each question ID
940
712
  /// @param hist_hashes In a single list for all supplied questions, the hash of each history entry.
941
- /// @param addrs In a single list for all supplied questions, the address of each answerer or commitment sender
942
- /// @param bonds In a single list for all supplied questions, the bond supplied with each answer or commitment
943
- /// @param answers In a single list for all supplied questions, each answer supplied, or commitment ID
713
+ /// @param addrs In a single list for all supplied questions, the address of each answerer
714
+ /// @param bonds In a single list for all supplied questions, the bond supplied with each answer
715
+ /// @param answers In a single list for all supplied questions, each answer supplied
944
716
  function claimMultipleAndWithdrawBalance(
945
- bytes32[] memory question_ids, uint256[] memory lengths,
946
- bytes32[] memory hist_hashes, address[] memory addrs, uint256[] memory bonds, bytes32[] memory answers
947
- )
948
- stateAny() // The finalization checks are done in the claimWinnings function
949
- public {
950
-
717
+ bytes32[] memory question_ids,
718
+ uint256[] memory lengths,
719
+ bytes32[] memory hist_hashes,
720
+ address[] memory addrs,
721
+ uint256[] memory bonds,
722
+ bytes32[] memory answers
723
+ )
724
+ public
725
+ stateAny // The finalization checks are done in the claimWinnings function
726
+ {
951
727
  uint256 qi;
952
728
  uint256 i;
953
729
  for (qi = 0; qi < question_ids.length; qi++) {
@@ -971,82 +747,70 @@ contract RealityETH_ERC20_v3_0 is BalanceHolder_ERC20 {
971
747
  }
972
748
 
973
749
  /// @notice Returns the questions's content hash, identifying the question content
974
- /// @param question_id The ID of the question
975
- function getContentHash(bytes32 question_id)
976
- public view returns(bytes32) {
750
+ /// @param question_id The ID of the question
751
+ function getContentHash(bytes32 question_id) public view returns (bytes32) {
977
752
  return questions[question_id].content_hash;
978
753
  }
979
754
 
980
755
  /// @notice Returns the arbitrator address for the question
981
- /// @param question_id The ID of the question
982
- function getArbitrator(bytes32 question_id)
983
- public view returns(address) {
756
+ /// @param question_id The ID of the question
757
+ function getArbitrator(bytes32 question_id) public view returns (address) {
984
758
  return questions[question_id].arbitrator;
985
759
  }
986
760
 
987
761
  /// @notice Returns the timestamp when the question can first be answered
988
- /// @param question_id The ID of the question
989
- function getOpeningTS(bytes32 question_id)
990
- public view returns(uint32) {
762
+ /// @param question_id The ID of the question
763
+ function getOpeningTS(bytes32 question_id) public view returns (uint32) {
991
764
  return questions[question_id].opening_ts;
992
765
  }
993
766
 
994
767
  /// @notice Returns the timeout in seconds used after each answer
995
- /// @param question_id The ID of the question
996
- function getTimeout(bytes32 question_id)
997
- public view returns(uint32) {
768
+ /// @param question_id The ID of the question
769
+ function getTimeout(bytes32 question_id) public view returns (uint32) {
998
770
  return questions[question_id].timeout;
999
771
  }
1000
772
 
1001
773
  /// @notice Returns the timestamp at which the question will be/was finalized
1002
- /// @param question_id The ID of the question
1003
- function getFinalizeTS(bytes32 question_id)
1004
- public view returns(uint32) {
774
+ /// @param question_id The ID of the question
775
+ function getFinalizeTS(bytes32 question_id) public view returns (uint32) {
1005
776
  return questions[question_id].finalize_ts;
1006
777
  }
1007
778
 
1008
779
  /// @notice Returns whether the question is pending arbitration
1009
- /// @param question_id The ID of the question
1010
- function isPendingArbitration(bytes32 question_id)
1011
- public view returns(bool) {
780
+ /// @param question_id The ID of the question
781
+ function isPendingArbitration(bytes32 question_id) public view returns (bool) {
1012
782
  return questions[question_id].is_pending_arbitration;
1013
783
  }
1014
784
 
1015
785
  /// @notice Returns the current total unclaimed bounty
1016
786
  /// @dev Set back to zero once the bounty has been claimed
1017
- /// @param question_id The ID of the question
1018
- function getBounty(bytes32 question_id)
1019
- public view returns(uint256) {
787
+ /// @param question_id The ID of the question
788
+ function getBounty(bytes32 question_id) public view returns (uint256) {
1020
789
  return questions[question_id].bounty;
1021
790
  }
1022
791
 
1023
792
  /// @notice Returns the current best answer
1024
- /// @param question_id The ID of the question
1025
- function getBestAnswer(bytes32 question_id)
1026
- public view returns(bytes32) {
793
+ /// @param question_id The ID of the question
794
+ function getBestAnswer(bytes32 question_id) public view returns (bytes32) {
1027
795
  return questions[question_id].best_answer;
1028
796
  }
1029
797
 
1030
- /// @notice Returns the history hash of the question
1031
- /// @param question_id The ID of the question
798
+ /// @notice Returns the history hash of the question
799
+ /// @param question_id The ID of the question
1032
800
  /// @dev Updated on each answer, then rewound as each is claimed
1033
- function getHistoryHash(bytes32 question_id)
1034
- public view returns(bytes32) {
801
+ function getHistoryHash(bytes32 question_id) public view returns (bytes32) {
1035
802
  return questions[question_id].history_hash;
1036
803
  }
1037
804
 
1038
805
  /// @notice Returns the highest bond posted so far for a question
1039
- /// @param question_id The ID of the question
1040
- function getBond(bytes32 question_id)
1041
- public view returns(uint256) {
806
+ /// @param question_id The ID of the question
807
+ function getBond(bytes32 question_id) public view returns (uint256) {
1042
808
  return questions[question_id].bond;
1043
809
  }
1044
810
 
1045
811
  /// @notice Returns the minimum bond that can answer the question
1046
812
  /// @param question_id The ID of the question
1047
- function getMinBond(bytes32 question_id)
1048
- public view returns(uint256) {
813
+ function getMinBond(bytes32 question_id) public view returns (uint256) {
1049
814
  return questions[question_id].min_bond;
1050
815
  }
1051
-
1052
816
  }