@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.
- package/.prettierrc +16 -0
- package/abi/solc-0.8.20/RealityETH-4.0.abi.json +1 -0
- package/abi/solc-0.8.20/RealityETH_ERC20-4.0.abi.json +1 -0
- package/bytecode/Arbitrator.bin +1 -1
- package/bytecode/RealityETH-3.0.bin +1 -1
- package/bytecode/RealityETH-4.0.bin +1 -0
- package/bytecode/RealityETH_ERC20-3.0.bin +1 -1
- package/bytecode/RealityETH_ERC20-4.0.bin +1 -0
- package/chains/chainid.network.json +5033 -431
- package/chains/deployments/300/ETH/RealityETH-3.0.json +7 -0
- package/chains/supported.json +3 -0
- package/development/contracts/.solhint.json +9 -0
- package/development/contracts/Arbitrator.sol +32 -56
- package/development/contracts/BalanceHolder.sol +4 -10
- package/development/contracts/BalanceHolder_ERC20.sol +5 -11
- package/development/contracts/CallbackClient.sol +3 -10
- package/development/contracts/ERC20Token.sol +29 -30
- package/development/contracts/ExplodingCallbackClient.sol +1 -4
- package/development/contracts/IArbitrator.sol +10 -7
- package/development/contracts/IArbitratorCore.sol +7 -14
- package/development/contracts/IArbitratorCrowdFundable.sol +3 -2
- package/development/contracts/IArbitratorErrors.sol +10 -0
- package/development/contracts/IArbitratorForeignProxy.sol +1 -1
- package/development/contracts/IArbitratorLegacy.sol +3 -3
- package/development/contracts/IArbitratorManagement.sol +15 -27
- package/development/contracts/IBalanceHolder.sol +3 -3
- package/development/contracts/IBalanceHolder_ERC20.sol +5 -5
- package/development/contracts/IERC20.sol +4 -5
- package/development/contracts/IOwned.sol +3 -3
- package/development/contracts/IRealityETH.sol +5 -58
- package/development/contracts/IRealityETHCommitReveal.sol +17 -0
- package/development/contracts/IRealityETHCommitReveal_ERC20.sol +16 -0
- package/development/contracts/IRealityETHCore.sol +135 -0
- package/development/contracts/IRealityETHCore_ERC20.sol +149 -0
- package/development/contracts/IRealityETHErrors.sol +86 -0
- package/development/contracts/IRealityETHErrors_ERC20.sol +13 -0
- package/development/contracts/IRealityETH_ERC20.sol +5 -62
- package/development/contracts/Owned.sol +4 -6
- package/development/contracts/{RealityETH-3.0.sol → RealityETH-4.0.sol} +221 -383
- package/development/contracts/{RealityETH_ERC20-3.0.sol → RealityETH_ERC20-4.0.sol} +238 -474
- package/development/contracts/RealityETH_ERC20_Factory.sol +47 -42
- package/development/contracts/RegisteredWalletArbitrator.sol +8 -15
- package/development/contracts/compile.py +3 -0
- package/development/scripts/string_to_error.py +111 -0
- package/development/version_checksums/check_matches_flat.sh +20 -0
- package/development/version_checksums/check_matches_last.sh +37 -0
- package/development/version_checksums/log_bytecode_history.sh +41 -0
- package/generated/chains.json +33 -5
- package/generated/tokens.json +1 -0
- package/non_standard_deployments/zksync/LICENSE +21 -0
- package/non_standard_deployments/zksync/README.md +51 -0
- package/non_standard_deployments/zksync/deploy/deploy.ts +11 -0
- package/non_standard_deployments/zksync/deploy/utils.ts +168 -0
- package/non_standard_deployments/zksync/hardhat.config.ts +55 -0
- package/non_standard_deployments/zksync/package-lock.json +6295 -0
- package/non_standard_deployments/zksync/package.json +34 -0
- package/package.json +7 -3
- package/scripts/transfer_arbitrator.js +60 -0
- package/tests/python/requirements.txt +55 -54
- package/tests/python/test.py +150 -50
- package/tests/python/test_erc20.py +15 -14
- package/tokens/ETH.json +3 -2
- package/non_standard_deployments/zksync2/README +0 -21
- package/non_standard_deployments/zksync2/contracts/RealityETH_ERC20-3.0.sol +0 -1096
- package/non_standard_deployments/zksync2/deploy/deploy.ts +0 -62
- package/non_standard_deployments/zksync2/deploy/deploy_erc20.ts +0 -56
- package/non_standard_deployments/zksync2/deploy/deploy_mainnet.ts +0 -46
- package/non_standard_deployments/zksync2/hardhat.config.ts +0 -27
- package/non_standard_deployments/zksync2/package.json +0 -15
- package/non_standard_deployments/zksync2/yarn.lock +0 -2898
- /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.
|
|
3
|
+
pragma solidity ^0.8.20;
|
|
4
4
|
|
|
5
|
-
import
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
45
|
+
if (questions[question_id].timeout != 0) revert QuestionMustNotExist();
|
|
161
46
|
_;
|
|
162
47
|
}
|
|
163
48
|
|
|
164
49
|
modifier stateOpen(bytes32 question_id) {
|
|
165
|
-
|
|
166
|
-
|
|
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
|
-
|
|
53
|
+
if (finalize_ts != UNANSWERED && finalize_ts <= uint32(block.timestamp)) revert FinalizationDeadlineMustNotHavePassed();
|
|
169
54
|
uint32 opening_ts = questions[question_id].opening_ts;
|
|
170
|
-
|
|
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
|
-
|
|
60
|
+
if (!questions[question_id].is_pending_arbitration) revert QuestionMustBePendingArbitration();
|
|
176
61
|
_;
|
|
177
62
|
}
|
|
178
63
|
|
|
179
64
|
modifier stateOpenOrPendingArbitration(bytes32 question_id) {
|
|
180
|
-
|
|
65
|
+
if (questions[question_id].timeout == 0) revert QuestionMustExist();
|
|
181
66
|
uint32 finalize_ts = questions[question_id].finalize_ts;
|
|
182
|
-
|
|
67
|
+
if (finalize_ts != UNANSWERED && finalize_ts <= uint32(block.timestamp)) revert FinalizationDealineMustNotHavePassed();
|
|
183
68
|
uint32 opening_ts = questions[question_id].opening_ts;
|
|
184
|
-
|
|
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
|
-
|
|
74
|
+
if (!isFinalized(question_id)) revert QuestionMustBeFinalized();
|
|
190
75
|
_;
|
|
191
76
|
}
|
|
192
77
|
|
|
193
78
|
modifier bondMustDoubleAndMatchMinimum(bytes32 question_id, uint256 tokens) {
|
|
194
|
-
|
|
79
|
+
if (tokens == 0) revert BondMustBePositive();
|
|
195
80
|
uint256 current_bond = questions[question_id].bond;
|
|
196
81
|
if (current_bond == 0) {
|
|
197
|
-
|
|
82
|
+
if (tokens < (questions[question_id].min_bond)) revert BondMustExceedTheMinimum();
|
|
198
83
|
} else {
|
|
199
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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(
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
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(
|
|
314
|
-
|
|
315
|
-
|
|
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
|
-
|
|
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(
|
|
343
|
-
|
|
344
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
392
|
-
|
|
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
|
-
|
|
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(
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
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
|
|
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(
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
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
|
-
|
|
469
|
-
_addAnswerToHistory(question_id, answer, answerer, tokens
|
|
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
|
-
|
|
474
|
-
|
|
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(
|
|
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(
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
external {
|
|
579
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
626
|
-
|
|
627
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
705
|
-
|
|
706
|
-
|
|
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
|
-
|
|
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
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
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
|
|
785
|
-
/// @param bonds Last-to-first, the bond supplied with each answer
|
|
786
|
-
/// @param answers Last-to-first, each answer supplied
|
|
787
|
-
function claimWinnings(
|
|
788
|
-
|
|
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 =
|
|
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
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
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
|
-
//
|
|
836
|
-
|
|
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
|
-
|
|
863
|
-
|
|
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
|
|
942
|
-
/// @param bonds In a single list for all supplied questions, the bond supplied with each answer
|
|
943
|
-
/// @param answers In a single list for all supplied questions, each answer supplied
|
|
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,
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
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
|
}
|