@d20dao/vrf-sdk 0.3.4 → 0.5.0
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/AGENTS.md +29 -19
- package/API.md +574 -223
- package/BUILD-MANIFEST.json +40 -26
- package/CHANGELOG.md +97 -0
- package/PROTOCOL-PROVENANCE.json +17 -10
- package/README.md +174 -113
- package/THIRD_PARTY_NOTICES.md +3 -1
- package/abi/D20BeaconVerifier.json +165 -0
- package/abi/EpochEntropy.json +605 -26
- package/dist/abi.d.ts +593 -22
- package/dist/abi.js +2 -1
- package/dist/beacon.d.ts +28 -0
- package/dist/beacon.js +133 -0
- package/dist/epoch.d.ts +50 -78
- package/dist/epoch.js +184 -29
- package/dist/index.d.ts +8 -4
- package/dist/index.js +4 -2
- package/dist/sources.d.ts +11 -0
- package/dist/sources.js +74 -0
- package/dist/templates.d.ts +22 -0
- package/dist/templates.js +220 -0
- package/examples/DiceConsumer.sol +37 -29
- package/examples/LootDropConsumer.sol +60 -0
- package/examples/RaffleConsumer.sol +71 -0
- package/notices/BLS-BN254-LICENSE +21 -0
- package/notices/PROVENANCE.md +12 -0
- package/package.json +31 -4
- package/contracts/examples/MiningRandomnessConsumer.sol +0 -59
package/API.md
CHANGED
|
@@ -2,23 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- Generated by scripts/api-reference.mjs from abi/*.json and scripts/api-descriptions.mjs. Do not edit by hand. -->
|
|
4
4
|
|
|
5
|
-
Every function, event and error of `D20VRFCoordinator` and `
|
|
5
|
+
Every function, event and error of `D20VRFCoordinator`, `EpochEntropy` and `D20BeaconVerifier`, generated from the ABIs of `@d20dao/vrf-sdk` 0.5.0. Regenerate with `npm run build && npm run api-reference`; `npm test` fails when this file is out of date.
|
|
6
6
|
|
|
7
|
-
- Package: `@d20dao/vrf-sdk` 0.
|
|
8
|
-
- Protocol source: commit `
|
|
7
|
+
- Package: `@d20dao/vrf-sdk` 0.5.0
|
|
8
|
+
- Protocol source: commit `98e537fb249dd0d3365b8d78e6040a9323a65a88`, copied to [`protocol/contracts/`](protocol/contracts/) (hashes in `PROTOCOL-PROVENANCE.json`)
|
|
9
9
|
- Compiler: solc 0.8.28+commit.7893614a.Emscripten.clang, EVM version `cancun`
|
|
10
10
|
- `abi/D20VRFCoordinator.json` SHA-256: `4764ba62745e109f3b968b21ed23e88da739a4a26906fc2ed3192fa23b8d79c1`
|
|
11
|
-
- `abi/EpochEntropy.json` SHA-256: `
|
|
11
|
+
- `abi/EpochEntropy.json` SHA-256: `74eff72ea9f7f434b628dd98ac921867e68e55cfac609f33d088f2e06c9cbc6c`
|
|
12
|
+
- `abi/D20BeaconVerifier.json` SHA-256: `06a0d6a046a5b790c49ed21cf545f3dfca36c7bac1ef262e927598c01292d6e5`
|
|
12
13
|
|
|
13
14
|
This reference describes that source. A deployment runs it only while the implementation behind each proxy is the one the deployment manifest records for that commit: check when you integrate and whenever a proxy emits `Upgraded` (README [Security and trust](README.md#security-and-trust)).
|
|
14
15
|
|
|
15
16
|
## Conventions
|
|
16
17
|
|
|
17
|
-
- **Addresses.** Call the proxies listed in README [Deployments](README.md#deployments). The ABIs are those of the implementations; `D20Proxy` adds no functions of its own.
|
|
18
|
+
- **Addresses.** Call the proxies listed in README [Deployments](README.md#deployments). The ABIs are those of the implementations; `D20Proxy` adds no functions of its own. `D20BeaconVerifier` is not behind a proxy: its address is in each beacon registration (`beaconOf`) and in README [Deployments](README.md#deployments).
|
|
18
19
|
- **Units.** Fees and credits are wei of native USDC, which has 18 decimals (`1e18` is 1 USDC). Deadlines and timestamps are Unix seconds. Ratios are basis points (10000 is 100%).
|
|
19
20
|
- **Callers.** "Anyone" means any account or contract; "Any contract" means `msg.sender` must have code. Owner-only functions revert `OwnableUnauthorizedAccount` for other callers.
|
|
20
21
|
- **Selectors.** Functions and errors show their 4-byte selector, events their topic 0, so revert data and logs can be matched by hand.
|
|
21
|
-
- **Decoding errors.** `coordinatorAbi` and `
|
|
22
|
+
- **Decoding errors.** `coordinatorAbi`, `epochEntropyAbi` and `beaconVerifierAbi` (`@d20dao/vrf-sdk/abi`) contain every custom error below. When your consumer calls the coordinator with an ordinary Solidity call, a coordinator revert is passed through unchanged, so a wallet sending a transaction to your consumer sees the coordinator's selector. Decode with `coordinator.interface.parseError(data)` in ethers or `decodeErrorResult({ abi: coordinatorAbi, data })` in viem, or build your consumer's contract object from its ABI plus the coordinator's error entries. Your consumer's own errors, such as `OnlyCoordinator` and `InvalidCoordinator` from `D20VRFConsumer`, are only in your consumer's ABI. Arithmetic overflow reverts with `Panic(uint256)`.
|
|
22
23
|
- **ethers v6 results.** Structs and multiple return values arrive as `Result` objects, which are arrays. A named value is also a property unless its name collides with an `Array` or `Result` member, such as `length`, `values`, `keys`, `map` or `filter`; read such a value with `result.getValue(name)`, by position, or from `result.toObject()`. Unnamed outputs, such as those of `pricing()`, are positional only.
|
|
23
24
|
- **Consumer contracts.** `D20VRFConsumer` implements `rawFulfillRandomness(requestId, randomness)` and `onRefund(requestId)`; both revert `OnlyCoordinator` unless called by the coordinator proxy given to its constructor, which reverts `InvalidCoordinator` for an address without code.
|
|
24
25
|
|
|
@@ -42,10 +43,15 @@ This reference describes that source. A deployment runs it only while the implem
|
|
|
42
43
|
- [Epoch state for consumers and verifiers](#registry-epoch-state-for-consumers-and-verifiers)
|
|
43
44
|
- [Registry reads](#registry-registry-reads)
|
|
44
45
|
- [Source selection and publication](#registry-source-selection-and-publication)
|
|
46
|
+
- [Recipes and catalogs](#registry-recipes-and-catalogs)
|
|
45
47
|
- [Owner administration](#registry-owner-administration)
|
|
46
48
|
- [Constants](#registry-constants)
|
|
47
49
|
- [Events](#registry-events)
|
|
48
50
|
- [Errors](#registry-errors)
|
|
51
|
+
- [D20BeaconVerifier](#verifier)
|
|
52
|
+
- [Verification](#verifier-verification)
|
|
53
|
+
- [Constants](#verifier-constants)
|
|
54
|
+
- [Errors](#verifier-errors)
|
|
49
55
|
|
|
50
56
|
## <a id="coordinator"></a>D20VRFCoordinator
|
|
51
57
|
|
|
@@ -59,7 +65,7 @@ Requests, fulfillment, `storeBlockHash`, retries, `refundRequest` and withdrawal
|
|
|
59
65
|
|
|
60
66
|
Returned by `getRequest`. It does not contain the escrowed fee or the refund ratio; read `requestFeePaid` and `requestRefundBps`.
|
|
61
67
|
|
|
62
|
-
Source: `D20VRFCoordinator.sol` lines
|
|
68
|
+
Source: `D20VRFCoordinator.sol` lines 61–79
|
|
63
69
|
|
|
64
70
|
| Field | Type | Meaning |
|
|
65
71
|
| --- | --- | --- |
|
|
@@ -123,7 +129,7 @@ Requests must come from a contract and pay at least the fee computed in their ow
|
|
|
123
129
|
function quoteFee(uint32 callbackGasLimit) external view returns (uint256)
|
|
124
130
|
```
|
|
125
131
|
|
|
126
|
-
Selector `0xc9caa0c3` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines
|
|
132
|
+
Selector `0xc9caa0c3` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines 232–237
|
|
127
133
|
|
|
128
134
|
Fee for a request with this `callbackGasLimit` priced at `block.basefee`, that is `quoteFeeAt(callbackGasLimit, block.basefee)`. Exact inside the requesting transaction, which is how `D20VRFRequests` helpers pay. Through `eth_call` the base fee is commonly reported as 0 (observed on Arc), so the answer collapses to `minFee` and a transaction sent with it reverts `IncorrectFee`. Off-chain, quote with `quoteFeeAt` and the latest header base fee plus a buffer, as `quoteRequestFee` does. It does not check the gas limit range.
|
|
129
135
|
|
|
@@ -135,7 +141,7 @@ Fee for a request with this `callbackGasLimit` priced at `block.basefee`, that i
|
|
|
135
141
|
function quoteFeeAt(uint32 callbackGasLimit, uint256 baseFee) external view returns (uint256)
|
|
136
142
|
```
|
|
137
143
|
|
|
138
|
-
Selector `0x26fa8481` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines
|
|
144
|
+
Selector `0x26fa8481` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines 224–231
|
|
139
145
|
|
|
140
146
|
`max(minFee, feeMultiplier × baseFee × (fulfillGasOverhead + callbackGasLimit))` over the live pricing for a base fee in wei that you supply; with `feeMultiplier` 0 it returns `minFee`. A quote, not a reservation: pricing can change before your transaction. A `baseFee` large enough to overflow uint256 reverts with `Panic(0x11)` instead of `FeeOverflow`.
|
|
141
147
|
|
|
@@ -147,7 +153,7 @@ Selector `0x26fa8481` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol
|
|
|
147
153
|
function requestRandomness(bytes32 clientSeed, uint32 callbackGasLimit, address _refundAddress) external payable returns (uint256 requestId)
|
|
148
154
|
```
|
|
149
155
|
|
|
150
|
-
Selector `0x9849d1e5` · Caller: Any contract · Source: `D20VRFCoordinator.sol` lines
|
|
156
|
+
Selector `0x9849d1e5` · Caller: Any contract · Source: `D20VRFCoordinator.sol` lines 239–244, 252–291
|
|
151
157
|
|
|
152
158
|
Creates a raw request (spec all zero) with `msg.sender` as consumer and returns its ID. Needs `msg.value` at least the fee computed in this transaction; escrows exactly that fee and credits any excess to `_refundAddress` as refund credit. Fixes the request block, epoch, client seed, refund address, fee, refund ratio (`refundBps`) and a deadline of `block.timestamp + RESPONSE_TIMEOUT`. After acceptance the consumer receives `rawFulfillRandomness(requestId, randomness)` with exactly `callbackGasLimit` gas. Checks run in this order: caller has code, refund address non-zero, gas limit in range, fee, mapping, epoch started.
|
|
153
159
|
|
|
@@ -161,7 +167,7 @@ Creates a raw request (spec all zero) with `msg.sender` as consumer and returns
|
|
|
161
167
|
function requestMappedRandomness(bytes32 clientSeed, uint32 callbackGasLimit, address _refundAddress, RandomnessMapping.Spec spec) external payable returns (uint256 requestId)
|
|
162
168
|
```
|
|
163
169
|
|
|
164
|
-
Selector `0xe6b41a8c` · Caller: Any contract · Source: `D20VRFCoordinator.sol` lines
|
|
170
|
+
Selector `0xe6b41a8c` · Caller: Any contract · Source: `D20VRFCoordinator.sol` lines 246–250, 252–291
|
|
165
171
|
|
|
166
172
|
Same as `requestRandomness`, storing `spec` with the request (`getMapping`, `mappingHash`). The callback still carries the raw word; read the mapped values with `getMappedResult`. `D20VRFRequests` helpers call this function and pay `quoteFee` from the calling contract balance.
|
|
167
173
|
|
|
@@ -175,11 +181,11 @@ Views, callable by anyone. They describe requests created from now on; an existi
|
|
|
175
181
|
|
|
176
182
|
| Function | Selector | Meaning | Source |
|
|
177
183
|
| --- | --- | --- | --- |
|
|
178
|
-
| <a id="coordinator-fn-pricing"></a>`pricing() returns (uint256, uint16, uint32)` | `0x7ce91411` | Live `(minFee, feeMultiplier, fulfillGasOverhead)`. The outputs are unnamed, so read them by position. | lines
|
|
179
|
-
| <a id="coordinator-fn-minfee"></a>`minFee() returns (uint256)` | `0x24ec7590` | Minimum fee in wei, at most `MAX_MIN_FEE` (10 USDC). | line
|
|
180
|
-
| <a id="coordinator-fn-feemultiplier"></a>`feeMultiplier() returns (uint16)` | `0xe5a70ef7` | Base-fee multiplier, 0 to `MAX_FEE_MULTIPLIER` (20); 0 makes every fee `minFee`. | lines
|
|
181
|
-
| <a id="coordinator-fn-fulfillgasoverhead"></a>`fulfillGasOverhead() returns (uint32)` | `0x19d40839` | Gas added to `callbackGasLimit` in the fee formula, `MIN_FULFILL_GAS_OVERHEAD` to `MAX_FULFILL_GAS_OVERHEAD`. | line
|
|
182
|
-
| <a id="coordinator-fn-refundbps"></a>`refundBps() returns (uint16)` | `0xec8c9a0b` | Current refund ratio in basis points (5000 to 10000), copied into each new request. Not the ratio of an existing request: use `requestRefundBps(requestId)`. | lines
|
|
184
|
+
| <a id="coordinator-fn-pricing"></a>`pricing() returns (uint256, uint16, uint32)` | `0x7ce91411` | Live `(minFee, feeMultiplier, fulfillGasOverhead)`. The outputs are unnamed, so read them by position. | lines 215–217 |
|
|
185
|
+
| <a id="coordinator-fn-minfee"></a>`minFee() returns (uint256)` | `0x24ec7590` | Minimum fee in wei, at most `MAX_MIN_FEE` (10 USDC). | line 46 |
|
|
186
|
+
| <a id="coordinator-fn-feemultiplier"></a>`feeMultiplier() returns (uint16)` | `0xe5a70ef7` | Base-fee multiplier, 0 to `MAX_FEE_MULTIPLIER` (20); 0 makes every fee `minFee`. | lines 48–49 |
|
|
187
|
+
| <a id="coordinator-fn-fulfillgasoverhead"></a>`fulfillGasOverhead() returns (uint32)` | `0x19d40839` | Gas added to `callbackGasLimit` in the fee formula, `MIN_FULFILL_GAS_OVERHEAD` to `MAX_FULFILL_GAS_OVERHEAD`. | line 50 |
|
|
188
|
+
| <a id="coordinator-fn-refundbps"></a>`refundBps() returns (uint16)` | `0xec8c9a0b` | Current refund ratio in basis points (5000 to 10000), copied into each new request. Not the ratio of an existing request: use `requestRefundBps(requestId)`. | lines 51–52 |
|
|
183
189
|
|
|
184
190
|
### <a id="coordinator-reading-request-state-and-results"></a>Reading request state and results
|
|
185
191
|
|
|
@@ -191,7 +197,7 @@ Views, callable by anyone, including from a callback. Request IDs start at 1 and
|
|
|
191
197
|
function getRequest(uint256 requestId) external view returns (D20VRFCoordinator.Request result)
|
|
192
198
|
```
|
|
193
199
|
|
|
194
|
-
Selector `0xc58343ef` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines
|
|
200
|
+
Selector `0xc58343ef` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines 293–312, 575–580
|
|
195
201
|
|
|
196
202
|
Full state of a request, see [`D20VRFCoordinator.Request`](#coordinator-type-d20vrfcoordinator-request). `targetBlock` and `epochHash` are resolved from the registry, so they become non-zero as soon as the epoch packet is published. `fulfilled` means the word is final; `delivered` only reports that a callback succeeded. A request that is not `fulfilled` in a block whose timestamp is after `deadline` has expired and can only be refunded. When polling, read the latest block before `getRequest`, so that a proof included up to that block is visible.
|
|
197
203
|
|
|
@@ -203,7 +209,7 @@ Full state of a request, see [`D20VRFCoordinator.Request`](#coordinator-type-d20
|
|
|
203
209
|
function getMapping(uint256 requestId) external view returns (RandomnessMapping.Spec)
|
|
204
210
|
```
|
|
205
211
|
|
|
206
|
-
Selector `0xede9ba8b` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines
|
|
212
|
+
Selector `0xede9ba8b` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines 344–347
|
|
207
213
|
|
|
208
214
|
The stored [`RandomnessMapping.Spec`](#coordinator-type-randomnessmapping-spec); all fields zero (Raw) for `requestRandomness`.
|
|
209
215
|
|
|
@@ -215,7 +221,7 @@ The stored [`RandomnessMapping.Spec`](#coordinator-type-randomnessmapping-spec);
|
|
|
215
221
|
function getMappedResult(uint256 requestId) external view returns (uint256[])
|
|
216
222
|
```
|
|
217
223
|
|
|
218
|
-
Selector `0x8f09a3e6` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines
|
|
224
|
+
Selector `0x8f09a3e6` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines 349–353
|
|
219
225
|
|
|
220
226
|
The accepted word mapped with the stored spec: `[uint256(word)]` for a raw request, otherwise the values in README [Randomness options](README.md#randomness-options). Part of `ID20VRF`. Reverts `NotFulfilled` until a proof is accepted, so an expired or refunded request never has a result. Gas grows with the mapping; a 256-item shuffle is expensive onchain.
|
|
221
227
|
|
|
@@ -227,7 +233,7 @@ The accepted word mapped with the stored spec: `[uint256(word)]` for a raw reque
|
|
|
227
233
|
function mapRandomness(bytes32 randomness, RandomnessMapping.Spec spec) external pure returns (uint256[])
|
|
228
234
|
```
|
|
229
235
|
|
|
230
|
-
Selector `0x41c2a199` · Caller: Anyone (pure) · Source: `D20VRFCoordinator.sol` lines
|
|
236
|
+
Selector `0x41c2a199` · Caller: Anyone (pure) · Source: `D20VRFCoordinator.sol` lines 355–360
|
|
231
237
|
|
|
232
238
|
Maps any word with any valid spec, like the SDK `mapRandomness(word, spec)` off-chain. It does not show that a request was fulfilled.
|
|
233
239
|
|
|
@@ -239,7 +245,7 @@ Maps any word with any valid spec, like the SDK `mapRandomness(word, spec)` off-
|
|
|
239
245
|
function requestFeePaid(uint256 requestId) external view returns (uint256)
|
|
240
246
|
```
|
|
241
247
|
|
|
242
|
-
Selector `0xef7cc992` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines
|
|
248
|
+
Selector `0xef7cc992` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines 335–338
|
|
243
249
|
|
|
244
250
|
Fee escrowed by the request (`feePaid` in `RandomnessRequested`), excluding any overpayment. The keeper share, the protocol share and the refund are computed from it.
|
|
245
251
|
|
|
@@ -251,7 +257,7 @@ Fee escrowed by the request (`feePaid` in `RandomnessRequested`), excluding any
|
|
|
251
257
|
function requestRefundBps(uint256 requestId) external view returns (uint16)
|
|
252
258
|
```
|
|
253
259
|
|
|
254
|
-
Selector `0x5d170fd7` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines
|
|
260
|
+
Selector `0x5d170fd7` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines 339–342
|
|
255
261
|
|
|
256
262
|
Refund ratio the request copied from `refundBps` at creation. An expiry refund pays `requestFeePaid × requestRefundBps / 10000`; a later `setRefundBps` does not change it.
|
|
257
263
|
|
|
@@ -263,7 +269,7 @@ Refund ratio the request copied from `refundBps` at creation. An expiry refund p
|
|
|
263
269
|
function refundCallbackDelivered(uint256) external view returns (bool)
|
|
264
270
|
```
|
|
265
271
|
|
|
266
|
-
Selector `0x281d3157` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines
|
|
272
|
+
Selector `0x281d3157` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines 105, 528
|
|
267
273
|
|
|
268
274
|
True once an `onRefund` notification for the request succeeded, at `refundRequest` or `retryRefundCallback`. Returns false for unknown IDs instead of reverting.
|
|
269
275
|
|
|
@@ -273,7 +279,7 @@ True once an `onRefund` notification for the request succeeded, at `refundReques
|
|
|
273
279
|
function nextRequestId() external view returns (uint256)
|
|
274
280
|
```
|
|
275
281
|
|
|
276
|
-
Selector `0x6a84a985` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines
|
|
282
|
+
Selector `0x6a84a985` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines 53, 175, 265
|
|
277
283
|
|
|
278
284
|
ID the next request will receive. Issued IDs are 1 to `nextRequestId() - 1`.
|
|
279
285
|
|
|
@@ -287,7 +293,7 @@ Recovery calls need no value or role. They forward gas to the consumer and rever
|
|
|
287
293
|
function refundRequest(uint256 requestId) external
|
|
288
294
|
```
|
|
289
295
|
|
|
290
|
-
Selector `0x7411484e` · Caller: Anyone · Source: `D20VRFCoordinator.sol` lines
|
|
296
|
+
Selector `0x7411484e` · Caller: Anyone · Source: `D20VRFCoordinator.sol` lines 483–507, 519–530
|
|
291
297
|
|
|
292
298
|
Refunds an unfulfilled request once a block timestamp is after its deadline. Marks it refunded, sends `feePaid × requestRefundBps / 10000` to the fixed refund address with a 30,000-gas transfer, or adds it to that address's refund credit if the transfer fails, and adds the rest of the fee to `earnedFees`. Then calls `onRefund(requestId)` on the consumer with 100,000 gas; a failed notification does not undo the refund. The caller receives nothing. Measured minimum transaction gas limit 302,558 to 357,517; use 400,000.
|
|
293
299
|
|
|
@@ -301,7 +307,7 @@ Refunds an unfulfilled request once a block timestamp is after its deadline. Mar
|
|
|
301
307
|
function retryCallback(uint256 requestId, uint32 gasLimit) external
|
|
302
308
|
```
|
|
303
309
|
|
|
304
|
-
Selector `0xdd11c275` · Caller: Anyone · Source: `D20VRFCoordinator.sol` lines
|
|
310
|
+
Selector `0xdd11c275` · Caller: Anyone · Source: `D20VRFCoordinator.sol` lines 473–481, 630–647
|
|
305
311
|
|
|
306
312
|
Calls `rawFulfillRandomness` again with the same accepted word after a failed callback, forwarding `gasLimit` (30,000 to 1,000,000 and not below the request's `callbackGasLimit`). Sets `delivered` on success. Pays nobody and never changes the word. Transaction gas limit: about `gasLimit + 250,000`.
|
|
307
313
|
|
|
@@ -315,7 +321,7 @@ Calls `rawFulfillRandomness` again with the same accepted word after a failed ca
|
|
|
315
321
|
function retryRefundCallback(uint256 requestId, uint32 gasLimit) external
|
|
316
322
|
```
|
|
317
323
|
|
|
318
|
-
Selector `0x054f6962` · Caller: Anyone · Source: `D20VRFCoordinator.sol` lines
|
|
324
|
+
Selector `0x054f6962` · Caller: Anyone · Source: `D20VRFCoordinator.sol` lines 509–517, 519–530
|
|
319
325
|
|
|
320
326
|
Repeats a failed `onRefund` notification for a refunded request with `gasLimit` (100,000 to 1,000,000). Never transfers funds again. Transaction gas limit: about `gasLimit + 150,000`.
|
|
321
327
|
|
|
@@ -329,7 +335,7 @@ Repeats a failed `onRefund` notification for a refunded request with `gasLimit`
|
|
|
329
335
|
function withdrawRefundCredit(address recipient) external
|
|
330
336
|
```
|
|
331
337
|
|
|
332
|
-
Selector `0x445071f2` · Caller: Refund-credit holder · Source: `D20VRFCoordinator.sol` lines
|
|
338
|
+
Selector `0x445071f2` · Caller: Refund-credit holder · Source: `D20VRFCoordinator.sol` lines 532–542
|
|
333
339
|
|
|
334
340
|
Sends all of the caller's refund credit, `refundCredits(msg.sender)`, to `recipient` with all remaining gas. Credit comes from overpayment and from refund transfers that failed, and belongs to the request's refund address, so that address must make the call. If `recipient` rejects the transfer the call reverts and the credit stays.
|
|
335
341
|
|
|
@@ -343,7 +349,7 @@ Sends all of the caller's refund credit, `refundCredits(msg.sender)`, to `recipi
|
|
|
343
349
|
function withdrawFees(address recipient) external
|
|
344
350
|
```
|
|
345
351
|
|
|
346
|
-
Selector `0x164e68de` · Caller: Fee recipient · Source: `D20VRFCoordinator.sol` lines
|
|
352
|
+
Selector `0x164e68de` · Caller: Fee recipient · Source: `D20VRFCoordinator.sol` lines 544–553
|
|
347
353
|
|
|
348
354
|
Sends all `earnedFees` to `recipient`. Fees accrue at acceptance (fee minus keeper share) and from the part of a refunded fee that is not returned; open escrow is never included. With nothing earned it sends zero without reverting.
|
|
349
355
|
|
|
@@ -357,7 +363,7 @@ Sends all `earnedFees` to `recipient`. Fees accrue at acceptance (fee minus keep
|
|
|
357
363
|
function withdrawKeeperCredit(address recipient) external
|
|
358
364
|
```
|
|
359
365
|
|
|
360
|
-
Selector `0xf62c546b` · Caller: Keeper-credit holder · Source: `D20VRFCoordinator.sol` lines
|
|
366
|
+
Selector `0xf62c546b` · Caller: Keeper-credit holder · Source: `D20VRFCoordinator.sol` lines 555–564
|
|
361
367
|
|
|
362
368
|
Sends all of the caller's keeper credit (keeper-share transfers that failed) to `recipient`.
|
|
363
369
|
|
|
@@ -371,17 +377,17 @@ Views, callable by anyone. Amounts are in wei of native USDC.
|
|
|
371
377
|
|
|
372
378
|
| Function | Selector | Meaning | Source |
|
|
373
379
|
| --- | --- | --- | --- |
|
|
374
|
-
| <a id="coordinator-fn-refundcredits"></a>`refundCredits(address) returns (uint256)` | `0x61137e40` | Refund credit that an address can withdraw with `withdrawRefundCredit`. | line
|
|
375
|
-
| <a id="coordinator-fn-totalrefundcredits"></a>`totalRefundCredits() returns (uint256)` | `0x6e0842e1` | Sum of all refund credit held by the coordinator. | line
|
|
376
|
-
| <a id="coordinator-fn-earnedfees"></a>`earnedFees() returns (uint256)` | `0xb1b3ffd9` | Protocol fees that the fee recipient can withdraw. | line
|
|
377
|
-
| <a id="coordinator-fn-feerecipient"></a>`feeRecipient() returns (address)` | `0x46904840` | Address allowed to call `withdrawFees`; changed with `setFeeRecipient`. | line
|
|
378
|
-
| <a id="coordinator-fn-keeperfeebps"></a>`keeperFeeBps() returns (uint16)` | `0x0eab7d63` | Keeper share of each accepted fee in basis points (0 to 10000). Read at acceptance, not snapshotted: a change applies to open requests accepted afterwards. It only splits the escrowed fee; what the consumer paid and can be refunded does not change. | lines
|
|
379
|
-
| <a id="coordinator-fn-keepercredits"></a>`keeperCredits(address) returns (uint256)` | `0xf5c764f6` | Keeper credit that an address can withdraw with `withdrawKeeperCredit`. | line
|
|
380
|
-
| <a id="coordinator-fn-totalkeepercredits"></a>`totalKeeperCredits() returns (uint256)` | `0xc7281b7a` | Sum of all keeper credit held by the coordinator. | line
|
|
380
|
+
| <a id="coordinator-fn-refundcredits"></a>`refundCredits(address) returns (uint256)` | `0x61137e40` | Refund credit that an address can withdraw with `withdrawRefundCredit`. | line 59 |
|
|
381
|
+
| <a id="coordinator-fn-totalrefundcredits"></a>`totalRefundCredits() returns (uint256)` | `0x6e0842e1` | Sum of all refund credit held by the coordinator. | line 58 |
|
|
382
|
+
| <a id="coordinator-fn-earnedfees"></a>`earnedFees() returns (uint256)` | `0xb1b3ffd9` | Protocol fees that the fee recipient can withdraw. | line 54 |
|
|
383
|
+
| <a id="coordinator-fn-feerecipient"></a>`feeRecipient() returns (address)` | `0x46904840` | Address allowed to call `withdrawFees`; changed with `setFeeRecipient`. | line 42 |
|
|
384
|
+
| <a id="coordinator-fn-keeperfeebps"></a>`keeperFeeBps() returns (uint16)` | `0x0eab7d63` | Keeper share of each accepted fee in basis points (0 to 10000). Read at acceptance, not snapshotted: a change applies to open requests accepted afterwards. It only splits the escrowed fee; what the consumer paid and can be refunded does not change. | lines 43, 450 |
|
|
385
|
+
| <a id="coordinator-fn-keepercredits"></a>`keeperCredits(address) returns (uint256)` | `0xf5c764f6` | Keeper credit that an address can withdraw with `withdrawKeeperCredit`. | line 44 |
|
|
386
|
+
| <a id="coordinator-fn-totalkeepercredits"></a>`totalKeeperCredits() returns (uint256)` | `0xc7281b7a` | Sum of all keeper credit held by the coordinator. | line 45 |
|
|
381
387
|
|
|
382
388
|
### <a id="coordinator-keeper-and-proof-functions"></a>Keeper and proof functions
|
|
383
389
|
|
|
384
|
-
Proof submission is permissionless: anyone holding a valid proof may submit it, and the keeper share
|
|
390
|
+
Proof submission is permissionless: anyone holding a valid proof may submit it, and the keeper share goes to the submitting wallet when the registry authorizes it as its committer or a backup committer, and to `committer()` otherwise. Consumers normally only read `getRequest`. Besides the custom errors listed, proof functions can revert with `Error(string)` messages from the vendored VRF verifier, such as `invalid proof`, which are not in the ABI.
|
|
385
391
|
|
|
386
392
|
#### <a id="coordinator-fn-fulfillrandomness"></a>`fulfillRandomness`
|
|
387
393
|
|
|
@@ -389,9 +395,9 @@ Proof submission is permissionless: anyone holding a valid proof may submit it,
|
|
|
389
395
|
function fulfillRandomness(uint256 requestId, VRF.Proof proof) external
|
|
390
396
|
```
|
|
391
397
|
|
|
392
|
-
Selector `0xef7c2b19` · Caller: Anyone · Source: `D20VRFCoordinator.sol` lines
|
|
398
|
+
Selector `0xef7c2b19` · Caller: Anyone · Source: `D20VRFCoordinator.sol` lines 393–401, 430–465
|
|
393
399
|
|
|
394
|
-
Accepts a proof for a request that is not fulfilled, not refunded and not past its deadline; acceptance in a block with timestamp equal to `deadline` is timely. Stores the target block hash if needed, verifies the proof against `requestSeed(requestId)`, stores the word, proof hash and transcript hash, sets `fulfilled`, adds `feePaid` minus the keeper share to `earnedFees` and calls the consumer with `callbackGasLimit` gas. It then sends the keeper share (`keeperFeeBps` of `feePaid`) to `committer()`
|
|
400
|
+
Accepts a proof for a request that is not fulfilled, not refunded and not past its deadline; acceptance in a block with timestamp equal to `deadline` is timely. Stores the target block hash if needed, verifies the proof against `requestSeed(requestId)`, stores the word, proof hash and transcript hash, sets `fulfilled`, adds `feePaid` minus the keeper share to `earnedFees` and calls the consumer with `callbackGasLimit` gas. It then sends the keeper share (`keeperFeeBps` of `feePaid`) with 30,000 gas to the submitting wallet when the registry answers `isAuthorizedCommitter` true for it (the committer or an allowed backup committer) and to `committer()` otherwise, or records it as that wallet's keeper credit; a registry call that reverts also pays `committer()`. A failing callback does not revert the fulfillment.
|
|
395
401
|
|
|
396
402
|
**Emits:** [`BlockHashStored`](#coordinator-event-blockhashstored), [`RequestServed`](#coordinator-event-requestserved), [`ProofVerified`](#coordinator-event-proofverified), [`RandomnessFulfilled`](#coordinator-event-randomnessfulfilled), [`FulfillmentEvidence`](#coordinator-event-fulfillmentevidence), [`CallbackAttempted`](#coordinator-event-callbackattempted), [`KeeperFeePaid`](#coordinator-event-keeperfeepaid).
|
|
397
403
|
|
|
@@ -403,9 +409,9 @@ Accepts a proof for a request that is not fulfilled, not refunded and not past i
|
|
|
403
409
|
function fulfillRandomnessBatch(uint256[] ids, VRF.Proof[] proofs) external
|
|
404
410
|
```
|
|
405
411
|
|
|
406
|
-
Selector `0x9497b180` · Caller: Anyone · Source: `D20VRFCoordinator.sol` lines
|
|
412
|
+
Selector `0x9497b180` · Caller: Anyone · Source: `D20VRFCoordinator.sol` lines 403–428
|
|
407
413
|
|
|
408
|
-
Fulfills up to `MAX_FULFILL_BATCH` (16) requests, one proof each. Members already fulfilled, refunded or past their deadline, including an ID repeated in the batch, are skipped with `FulfillmentSkipped`; every other member runs exactly like `fulfillRandomness` and emits the same events, so an unknown ID, an unready member or an invalid proof reverts the whole batch.
|
|
414
|
+
Fulfills up to `MAX_FULFILL_BATCH` (16) requests, one proof each. Members already fulfilled, refunded or past their deadline, including an ID repeated in the batch, are skipped with `FulfillmentSkipped`; every other member runs exactly like `fulfillRandomness` and emits the same events, so an unknown ID, an unready member or an invalid proof reverts the whole batch. Before any result is revealed it checks that the gas left covers every member that will be served, `140,000 + Σ(callbackGasLimit + callbackGasLimit / 63 + 400,000)`, and reverts `InsufficientCallbackGas` otherwise, so no callback can starve a later member and revert results already revealed.
|
|
409
415
|
|
|
410
416
|
**Emits:** [`FulfillmentSkipped`](#coordinator-event-fulfillmentskipped), [`BlockHashStored`](#coordinator-event-blockhashstored), [`RequestServed`](#coordinator-event-requestserved), [`ProofVerified`](#coordinator-event-proofverified), [`RandomnessFulfilled`](#coordinator-event-randomnessfulfilled), [`FulfillmentEvidence`](#coordinator-event-fulfillmentevidence), [`CallbackAttempted`](#coordinator-event-callbackattempted), [`KeeperFeePaid`](#coordinator-event-keeperfeepaid).
|
|
411
417
|
|
|
@@ -417,7 +423,7 @@ Fulfills up to `MAX_FULFILL_BATCH` (16) requests, one proof each. Members alread
|
|
|
417
423
|
function storeBlockHash(uint256 requestId) external returns (bytes32)
|
|
418
424
|
```
|
|
419
425
|
|
|
420
|
-
Selector `0x262fd733` · Caller: Anyone · Source: `D20VRFCoordinator.sol` lines
|
|
426
|
+
Selector `0x262fd733` · Caller: Anyone · Source: `D20VRFCoordinator.sol` lines 372–376, 581–596
|
|
421
427
|
|
|
422
428
|
Resolves the target block from the published epoch, stores its hash if not stored yet and returns it. Fulfillment does this automatically; calling it earlier keeps a request provable after its target leaves the 256-block `BLOCKHASH` window. Needs `block.number` at least `targetBlock + confirmationBlocks`. Works on any request, whatever its status.
|
|
423
429
|
|
|
@@ -431,7 +437,7 @@ Resolves the target block from the published epoch, stores its hash if not store
|
|
|
431
437
|
function verifyRequestProof(uint256 requestId, VRF.Proof proof) external view returns (bytes32)
|
|
432
438
|
```
|
|
433
439
|
|
|
434
|
-
Selector `0x0846de99` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines
|
|
440
|
+
Selector `0x0846de99` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines 362–370
|
|
435
441
|
|
|
436
442
|
Returns the word a proof yields for the request's seed, without changing state. A valid proof is not acceptance: check `getRequest(requestId).fulfilled`.
|
|
437
443
|
|
|
@@ -443,7 +449,7 @@ Returns the word a proof yields for the request's seed, without changing state.
|
|
|
443
449
|
function requestSeed(uint256 requestId) external view returns (uint256)
|
|
444
450
|
```
|
|
445
451
|
|
|
446
|
-
Selector `0xa9df851a` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines
|
|
452
|
+
Selector `0xa9df851a` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines 378–383, 598–606
|
|
447
453
|
|
|
448
454
|
Seed the proof must use: `keccak256(abi.encode(SEED_DOMAIN, chainId, coordinator, keyHash, requestId, consumer, clientSeed, mappingHash, requestBlock, targetBlock, blockHash, epochId, epochHash))` as uint256. Available only after publication and `confirmationBlocks` confirmations of the target block.
|
|
449
455
|
|
|
@@ -455,7 +461,7 @@ Seed the proof must use: `keccak256(abi.encode(SEED_DOMAIN, chainId, coordinator
|
|
|
455
461
|
function getProofContext(uint256 requestId) external view returns (uint256 seed, uint64 deadline, bool fulfilled, bool refunded)
|
|
456
462
|
```
|
|
457
463
|
|
|
458
|
-
Selector `0xcf14de9d` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines
|
|
464
|
+
Selector `0xcf14de9d` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines 385–391
|
|
459
465
|
|
|
460
466
|
`requestSeed` together with `deadline`, `fulfilled` and `refunded`. It reverts `NotReady` like `requestSeed`, so it is not a status read for waiting requests; use `getRequest`.
|
|
461
467
|
|
|
@@ -467,7 +473,7 @@ Selector `0xcf14de9d` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol
|
|
|
467
473
|
function getPendingRequestIds(uint256 fromId, uint256 limit) external view returns (uint256[] ids, uint256 nextCursor)
|
|
468
474
|
```
|
|
469
475
|
|
|
470
|
-
Selector `0xfdfe72e6` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines
|
|
476
|
+
Selector `0xfdfe72e6` · Caller: Anyone (view) · Source: `D20VRFCoordinator.sol` lines 314–333
|
|
471
477
|
|
|
472
478
|
Scans `limit` (1 to 256) request IDs from `fromId` (at least 1) and returns those not fulfilled, not refunded and not past their deadline, with the ID to continue from. Continue with `nextCursor` until it equals `nextRequestId()`. The answer can be stale by the time a transaction lands.
|
|
473
479
|
|
|
@@ -479,17 +485,17 @@ Views, callable by anyone. Nothing here has a setter except through an upgrade.
|
|
|
479
485
|
|
|
480
486
|
| Function | Selector | Meaning | Source |
|
|
481
487
|
| --- | --- | --- | --- |
|
|
482
|
-
| <a id="coordinator-fn-lastservedrequestid"></a>`lastServedRequestId() returns (uint256)` | `0xef54e226` | ID of the most recently accepted request; 0 before the first. | lines
|
|
483
|
-
| <a id="coordinator-fn-lastservedindex"></a>`lastServedIndex() returns (uint256)` | `0x7e176eed` | Number of accepted requests so far: the `serveIndex` of the latest `RequestServed`. | lines
|
|
484
|
-
| <a id="coordinator-fn-servedrequestat"></a>`servedRequestAt(uint256) returns (uint256)` | `0xf9a4acc6` | Request ID accepted at a serve index (from 1); 0 for an index not used yet. | lines
|
|
485
|
-
| <a id="coordinator-fn-keyhash"></a>`keyHash() returns (bytes32)` | `0x61728f39` | `keccak256(abi.encode(publicKey))` of the VRF key; indexed in `RandomnessRequested` and `ProofVerified`. | lines
|
|
486
|
-
| <a id="coordinator-fn-publickeyx"></a>`publicKeyX() returns (uint256)` | `0xfa6df55d` | x coordinate of the VRF public key. | line
|
|
487
|
-
| <a id="coordinator-fn-publickeyy"></a>`publicKeyY() returns (uint256)` | `0xd7a6f6e8` | y coordinate of the VRF public key. | line
|
|
488
|
-
| <a id="coordinator-fn-confirmationblocks"></a>`confirmationBlocks() returns (uint16)` | `0x460a58aa` | Blocks after the target block before the seed and proofs become available (1 to 64, set at initialization). | lines
|
|
489
|
-
| <a id="coordinator-fn-epochregistry"></a>`epochRegistry() returns (address)` | `0x2b12cb69` | The `EpochEntropy` proxy that supplies epochs and the keeper-share recipient. | line
|
|
490
|
-
| <a id="coordinator-fn-protocolconfigurationhash"></a>`protocolConfigurationHash() returns (bytes32)` | `0x155cf49b` | Hash of the initialized configuration (public key, initial fee recipient, initial minimum fee, confirmations, registry, initial catalog hash, first epoch start, epoch length 200) under `CONFIG_DOMAIN`. Bound into every transcript hash. | lines
|
|
491
|
-
| <a id="coordinator-fn-initialfeerecipient"></a>`initialFeeRecipient() returns (address)` | `0x308c2d6b` | Fee recipient given to `initialize`, used by replay. The live payout address is `feeRecipient()`. | lines
|
|
492
|
-
| <a id="coordinator-fn-initialminfee"></a>`initialMinFee() returns (uint256)` | `0xb3839295` | Minimum fee given to `initialize`, used by replay. The live minimum is `minFee()`. | lines
|
|
488
|
+
| <a id="coordinator-fn-lastservedrequestid"></a>`lastServedRequestId() returns (uint256)` | `0xef54e226` | ID of the most recently accepted request; 0 before the first. | lines 55, 452 |
|
|
489
|
+
| <a id="coordinator-fn-lastservedindex"></a>`lastServedIndex() returns (uint256)` | `0x7e176eed` | Number of accepted requests so far: the `serveIndex` of the latest `RequestServed`. | lines 56, 453 |
|
|
490
|
+
| <a id="coordinator-fn-servedrequestat"></a>`servedRequestAt(uint256) returns (uint256)` | `0xf9a4acc6` | Request ID accepted at a serve index (from 1); 0 for an index not used yet. | lines 57, 453 |
|
|
491
|
+
| <a id="coordinator-fn-keyhash"></a>`keyHash() returns (bytes32)` | `0x61728f39` | `keccak256(abi.encode(publicKey))` of the VRF key; indexed in `RandomnessRequested` and `ProofVerified`. | lines 39, 182 |
|
|
492
|
+
| <a id="coordinator-fn-publickeyx"></a>`publicKeyX() returns (uint256)` | `0xfa6df55d` | x coordinate of the VRF public key. | line 37 |
|
|
493
|
+
| <a id="coordinator-fn-publickeyy"></a>`publicKeyY() returns (uint256)` | `0xd7a6f6e8` | y coordinate of the VRF public key. | line 38 |
|
|
494
|
+
| <a id="coordinator-fn-confirmationblocks"></a>`confirmationBlocks() returns (uint16)` | `0x460a58aa` | Blocks after the target block before the seed and proofs become available (1 to 64, set at initialization). | lines 47, 583 |
|
|
495
|
+
| <a id="coordinator-fn-epochregistry"></a>`epochRegistry() returns (address)` | `0x2b12cb69` | The `EpochEntropy` proxy that supplies epochs and the keeper-share recipient. | line 35 |
|
|
496
|
+
| <a id="coordinator-fn-protocolconfigurationhash"></a>`protocolConfigurationHash() returns (bytes32)` | `0x155cf49b` | Hash of the initialized configuration (public key, initial fee recipient, initial minimum fee, confirmations, registry, initial catalog hash, first epoch start, epoch length 200) under `CONFIG_DOMAIN`. Bound into every transcript hash. | lines 34, 192 |
|
|
497
|
+
| <a id="coordinator-fn-initialfeerecipient"></a>`initialFeeRecipient() returns (address)` | `0x308c2d6b` | Fee recipient given to `initialize`, used by replay. The live payout address is `feeRecipient()`. | lines 41, 184 |
|
|
498
|
+
| <a id="coordinator-fn-initialminfee"></a>`initialMinFee() returns (uint256)` | `0xb3839295` | Minimum fee given to `initialize`, used by replay. The live minimum is `minFee()`. | lines 107, 187 |
|
|
493
499
|
|
|
494
500
|
### <a id="coordinator-owner-administration"></a>Owner administration
|
|
495
501
|
|
|
@@ -501,9 +507,9 @@ Owner-only functions revert `OwnableUnauthorizedAccount` for anyone else. No set
|
|
|
501
507
|
function setPricing(uint256 nextMinFee, uint16 multiplier, uint32 overhead) external
|
|
502
508
|
```
|
|
503
509
|
|
|
504
|
-
Selector `0x4c729ce6` · Caller: Owner · Source: `D20VRFCoordinator.sol` lines
|
|
510
|
+
Selector `0x4c729ce6` · Caller: Owner · Source: `D20VRFCoordinator.sol` lines 207–214
|
|
505
511
|
|
|
506
|
-
Sets `minFee` (at most `MAX_MIN_FEE`, 10 USDC), `feeMultiplier` (at most `MAX_FEE_MULTIPLIER`, 20) and `fulfillGasOverhead` (`MIN_FULFILL_GAS_OVERHEAD` to `MAX_FULFILL_GAS_OVERHEAD`, 100,000 to 2,000,000 gas). Affects requests created afterwards; open requests keep their escrowed fee.
|
|
512
|
+
Sets `minFee` (at most `MAX_MIN_FEE`, 10 USDC), `feeMultiplier` (at most `MAX_FEE_MULTIPLIER`, 20) and `fulfillGasOverhead` (`MIN_FULFILL_GAS_OVERHEAD` to `MAX_FULFILL_GAS_OVERHEAD`, 100,000 to 2,000,000 gas). `minFee` and `feeMultiplier` cannot both be zero, so a request is never free. Affects requests created afterwards; open requests keep their escrowed fee.
|
|
507
513
|
|
|
508
514
|
**Emits:** [`PricingChanged`](#coordinator-event-pricingchanged).
|
|
509
515
|
|
|
@@ -515,7 +521,7 @@ Sets `minFee` (at most `MAX_MIN_FEE`, 10 USDC), `feeMultiplier` (at most `MAX_FE
|
|
|
515
521
|
function setRefundBps(uint16 next) external
|
|
516
522
|
```
|
|
517
523
|
|
|
518
|
-
Selector `0x55a94d1b` · Caller: Owner · Source: `D20VRFCoordinator.sol` lines
|
|
524
|
+
Selector `0x55a94d1b` · Caller: Owner · Source: `D20VRFCoordinator.sol` lines 218–222
|
|
519
525
|
|
|
520
526
|
Sets the refund ratio for requests created afterwards, `MIN_REFUND_BPS` (5000) to 10000.
|
|
521
527
|
|
|
@@ -529,7 +535,7 @@ Sets the refund ratio for requests created afterwards, `MIN_REFUND_BPS` (5000) t
|
|
|
529
535
|
function setKeeperFeeBps(uint16 next) external
|
|
530
536
|
```
|
|
531
537
|
|
|
532
|
-
Selector `0xe140f0ca` · Caller: Owner · Source: `D20VRFCoordinator.sol` lines
|
|
538
|
+
Selector `0xe140f0ca` · Caller: Owner · Source: `D20VRFCoordinator.sol` lines 203–206
|
|
533
539
|
|
|
534
540
|
Sets the keeper share, 0 to 10000 basis points. Read at each acceptance, so it also applies to open requests accepted later.
|
|
535
541
|
|
|
@@ -543,7 +549,7 @@ Sets the keeper share, 0 to 10000 basis points. Read at each acceptance, so it a
|
|
|
543
549
|
function setFeeRecipient(address next) external
|
|
544
550
|
```
|
|
545
551
|
|
|
546
|
-
Selector `0xe74b981b` · Caller: Owner · Source: `D20VRFCoordinator.sol` lines
|
|
552
|
+
Selector `0xe74b981b` · Caller: Owner · Source: `D20VRFCoordinator.sol` lines 199–202
|
|
547
553
|
|
|
548
554
|
Sets the address allowed to withdraw `earnedFees`, including fees earned before the change. The zero address is rejected.
|
|
549
555
|
|
|
@@ -605,7 +611,7 @@ Completes the transfer to the caller and clears the nomination.
|
|
|
605
611
|
function renounceOwnership() external view
|
|
606
612
|
```
|
|
607
613
|
|
|
608
|
-
Selector `0x715018a6` · Caller: Owner · Source: `D20VRFCoordinator.sol` lines
|
|
614
|
+
Selector `0x715018a6` · Caller: Owner · Source: `D20VRFCoordinator.sol` lines 196–197
|
|
609
615
|
|
|
610
616
|
Disabled and declared `view`: the owner gets `RenounceDisabled` and anyone else `OwnableUnauthorizedAccount`, so the contract always has an owner and upgrade authority can only move through an accepted transfer.
|
|
611
617
|
|
|
@@ -643,7 +649,7 @@ ERC-1822 check used by `upgradeToAndCall`. Returns the ERC-1967 implementation s
|
|
|
643
649
|
function initialize(uint256[2] publicKey, address initialOwner, address recipient, uint256 fee, uint16 confirmations, address registry, uint16 keeperBps) external
|
|
644
650
|
```
|
|
645
651
|
|
|
646
|
-
Selector `0x56b95b47` · Caller: Once, by `D20Proxy` at deployment · Source: `D20VRFCoordinator.sol` lines
|
|
652
|
+
Selector `0x56b95b47` · Caller: Once, by `D20Proxy` at deployment · Source: `D20VRFCoordinator.sol` lines 172–193
|
|
647
653
|
|
|
648
654
|
Sets owner, VRF public key, fee recipient, minimum fee, confirmations, registry and keeper share, with `feeMultiplier` 5, `fulfillGasOverhead` 300,000 and `refundBps` 10000. A public key that is not on the curve can also revert with an `Error(string)` from the verifier.
|
|
649
655
|
|
|
@@ -683,7 +689,7 @@ Views returning values fixed in the implementation code.
|
|
|
683
689
|
event RandomnessRequested(uint256 indexed requestId, address indexed consumer, bytes32 indexed keyHash, bytes32 clientSeed, uint64 requestBlock, uint32 callbackGasLimit, uint256 feePaid, address refundAddress, uint64 deadline)
|
|
684
690
|
```
|
|
685
691
|
|
|
686
|
-
Topic 0 `0xaf91b17376114a36689aa115062983bda7b43263a891fb8de0cc69d30d4240ad` · Emitted by: [`requestRandomness`](#coordinator-fn-requestrandomness), [`requestMappedRandomness`](#coordinator-fn-requestmappedrandomness) · Source: `D20VRFCoordinator.sol` lines
|
|
692
|
+
Topic 0 `0xaf91b17376114a36689aa115062983bda7b43263a891fb8de0cc69d30d4240ad` · Emitted by: [`requestRandomness`](#coordinator-fn-requestrandomness), [`requestMappedRandomness`](#coordinator-fn-requestmappedrandomness) · Source: `D20VRFCoordinator.sol` lines 141–145, 288–289
|
|
687
693
|
|
|
688
694
|
A request was created. `feePaid` is the escrowed fee, not `msg.value`; `deadline` is the block timestamp plus 60 seconds. Read `requestId` from this log in the request receipt, filtering by the coordinator address and event name: with an overpayment, `FeeOverpaymentCredited` comes first.
|
|
689
695
|
|
|
@@ -693,7 +699,7 @@ A request was created. `feePaid` is the escrowed fee, not `msg.value`; `deadline
|
|
|
693
699
|
event MappingRequested(uint256 indexed requestId, bytes32 indexed mappingHash, RandomnessMapping.Spec spec)
|
|
694
700
|
```
|
|
695
701
|
|
|
696
|
-
Topic 0 `0xbe1c93f40bd74ff9acd22dc40818e36d04e0b8a49b8238d0537c63219c2336dd` · Emitted by: [`requestRandomness`](#coordinator-fn-requestrandomness), [`requestMappedRandomness`](#coordinator-fn-requestmappedrandomness) · Source: `D20VRFCoordinator.sol` lines
|
|
702
|
+
Topic 0 `0xbe1c93f40bd74ff9acd22dc40818e36d04e0b8a49b8238d0537c63219c2336dd` · Emitted by: [`requestRandomness`](#coordinator-fn-requestrandomness), [`requestMappedRandomness`](#coordinator-fn-requestmappedrandomness) · Source: `D20VRFCoordinator.sol` lines 160, 290
|
|
697
703
|
|
|
698
704
|
Emitted right after `RandomnessRequested` with the stored spec (all zero for a raw request) and its hash.
|
|
699
705
|
|
|
@@ -703,7 +709,7 @@ Emitted right after `RandomnessRequested` with the stored spec (all zero for a r
|
|
|
703
709
|
event FeeOverpaymentCredited(uint256 indexed requestId, address indexed refundAddress, uint256 amount)
|
|
704
710
|
```
|
|
705
711
|
|
|
706
|
-
Topic 0 `0x8ae693db98f043f48e8f427375449ed5576aba97575e4f7f93ff2c1f6c75dcb5` · Emitted by: [`requestRandomness`](#coordinator-fn-requestrandomness), [`requestMappedRandomness`](#coordinator-fn-requestmappedrandomness) · Source: `D20VRFCoordinator.sol` lines
|
|
712
|
+
Topic 0 `0x8ae693db98f043f48e8f427375449ed5576aba97575e4f7f93ff2c1f6c75dcb5` · Emitted by: [`requestRandomness`](#coordinator-fn-requestrandomness), [`requestMappedRandomness`](#coordinator-fn-requestmappedrandomness) · Source: `D20VRFCoordinator.sol` lines 154, 282–287
|
|
707
713
|
|
|
708
714
|
`msg.value` exceeded the fee and `amount` was added to `refundCredits(refundAddress)`, independently of what happens to the request. Emitted before `RandomnessRequested`.
|
|
709
715
|
|
|
@@ -713,7 +719,7 @@ Topic 0 `0x8ae693db98f043f48e8f427375449ed5576aba97575e4f7f93ff2c1f6c75dcb5` ·
|
|
|
713
719
|
event BlockHashStored(uint256 indexed requestId, uint64 targetBlock, bytes32 blockHash)
|
|
714
720
|
```
|
|
715
721
|
|
|
716
|
-
Topic 0 `0x81bc3b4ec75af0fb9ed3521d7c766d8f995d04b0735c17d61ff9d468b0f04911` · Emitted by: [`fulfillRandomness`](#coordinator-fn-fulfillrandomness), [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch), [`storeBlockHash`](#coordinator-fn-storeblockhash) · Source: `D20VRFCoordinator.sol` lines
|
|
722
|
+
Topic 0 `0x81bc3b4ec75af0fb9ed3521d7c766d8f995d04b0735c17d61ff9d468b0f04911` · Emitted by: [`fulfillRandomness`](#coordinator-fn-fulfillrandomness), [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch), [`storeBlockHash`](#coordinator-fn-storeblockhash) · Source: `D20VRFCoordinator.sol` lines 146, 589–596
|
|
717
723
|
|
|
718
724
|
The target block hash of the request was stored. Emitted once per request: by `storeBlockHash`, or by fulfillment if the hash was not stored before.
|
|
719
725
|
|
|
@@ -723,7 +729,7 @@ The target block hash of the request was stored. Emitted once per request: by `s
|
|
|
723
729
|
event RequestServed(uint256 indexed requestId, uint256 indexed serveIndex)
|
|
724
730
|
```
|
|
725
731
|
|
|
726
|
-
Topic 0 `0x2012511e6cebd578bcabff1ef3346edb032cbab8622e9f23d9f15d7d1037267f` · Emitted by: [`fulfillRandomness`](#coordinator-fn-fulfillrandomness), [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch) · Source: `D20VRFCoordinator.sol` lines
|
|
732
|
+
Topic 0 `0x2012511e6cebd578bcabff1ef3346edb032cbab8622e9f23d9f15d7d1037267f` · Emitted by: [`fulfillRandomness`](#coordinator-fn-fulfillrandomness), [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch) · Source: `D20VRFCoordinator.sol` lines 162, 452–454
|
|
727
733
|
|
|
728
734
|
A proof was accepted. `serveIndex` counts accepted requests from 1 (`lastServedIndex`, `servedRequestAt`).
|
|
729
735
|
|
|
@@ -733,7 +739,7 @@ A proof was accepted. `serveIndex` counts accepted requests from 1 (`lastServedI
|
|
|
733
739
|
event ProofVerified(uint256 indexed requestId, bytes32 indexed keyHash, uint256 seed, bytes32 proofHash)
|
|
734
740
|
```
|
|
735
741
|
|
|
736
|
-
Topic 0 `0x55bb25be3ecd9f68ceae7cdabf4eabe2e0940bd8fc1c26c0d68ad5f7c5d08d22` · Emitted by: [`fulfillRandomness`](#coordinator-fn-fulfillrandomness), [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch) · Source: `D20VRFCoordinator.sol` lines
|
|
742
|
+
Topic 0 `0x55bb25be3ecd9f68ceae7cdabf4eabe2e0940bd8fc1c26c0d68ad5f7c5d08d22` · Emitted by: [`fulfillRandomness`](#coordinator-fn-fulfillrandomness), [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch) · Source: `D20VRFCoordinator.sol` lines 161, 455
|
|
737
743
|
|
|
738
744
|
Seed and hash of the accepted proof.
|
|
739
745
|
|
|
@@ -743,9 +749,9 @@ Seed and hash of the accepted proof.
|
|
|
743
749
|
event RandomnessFulfilled(uint256 indexed requestId, bytes32 randomness, address indexed submitter)
|
|
744
750
|
```
|
|
745
751
|
|
|
746
|
-
Topic 0 `0x9c82683ee7932041c254d206bcce4241d66a811d53ee7191799cc120777b2b87` · Emitted by: [`fulfillRandomness`](#coordinator-fn-fulfillrandomness), [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch) · Source: `D20VRFCoordinator.sol` lines
|
|
752
|
+
Topic 0 `0x9c82683ee7932041c254d206bcce4241d66a811d53ee7191799cc120777b2b87` · Emitted by: [`fulfillRandomness`](#coordinator-fn-fulfillrandomness), [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch) · Source: `D20VRFCoordinator.sol` lines 147, 456
|
|
747
753
|
|
|
748
|
-
A proof was accepted and `randomness` is final. `submitter` sent the transaction
|
|
754
|
+
A proof was accepted and `randomness` is final. `submitter` sent the transaction; `KeeperFeePaid` names the wallet that received the keeper share, which is `submitter` only when the registry authorizes it.
|
|
749
755
|
|
|
750
756
|
#### <a id="coordinator-event-fulfillmentevidence"></a>`FulfillmentEvidence`
|
|
751
757
|
|
|
@@ -753,7 +759,7 @@ A proof was accepted and `randomness` is final. `submitter` sent the transaction
|
|
|
753
759
|
event FulfillmentEvidence(uint256 indexed requestId, bytes32 indexed transcriptHash, bytes packet)
|
|
754
760
|
```
|
|
755
761
|
|
|
756
|
-
Topic 0 `0xa121bbea897439460dfb08c3e6d6af064bc1f31e9477471828a87c5596b92e77` · Emitted by: [`fulfillRandomness`](#coordinator-fn-fulfillrandomness), [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch) · Source: `D20VRFCoordinator.sol` lines
|
|
762
|
+
Topic 0 `0xa121bbea897439460dfb08c3e6d6af064bc1f31e9477471828a87c5596b92e77` · Emitted by: [`fulfillRandomness`](#coordinator-fn-fulfillrandomness), [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch) · Source: `D20VRFCoordinator.sol` lines 165–166, 467–471
|
|
757
763
|
|
|
758
764
|
The accepted proof as a 416-byte ABI-encoded packet, indexed by `transcriptHash`. Decode it with `decodeEvidencePacket`; take evidence from this log, not from calldata, since a batch carries several proofs.
|
|
759
765
|
|
|
@@ -763,7 +769,7 @@ The accepted proof as a 416-byte ABI-encoded packet, indexed by `transcriptHash`
|
|
|
763
769
|
event CallbackAttempted(uint256 indexed requestId, bool success, uint32 gasLimit)
|
|
764
770
|
```
|
|
765
771
|
|
|
766
|
-
Topic 0 `0x70f64c0739e827900ae6f2e1317601653f4080bc857f423671fc58d5822f1f4a` · Emitted by: [`retryCallback`](#coordinator-fn-retrycallback), [`fulfillRandomness`](#coordinator-fn-fulfillrandomness), [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch) · Source: `D20VRFCoordinator.sol` lines
|
|
772
|
+
Topic 0 `0x70f64c0739e827900ae6f2e1317601653f4080bc857f423671fc58d5822f1f4a` · Emitted by: [`retryCallback`](#coordinator-fn-retrycallback), [`fulfillRandomness`](#coordinator-fn-fulfillrandomness), [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch) · Source: `D20VRFCoordinator.sol` lines 148, 630–647
|
|
767
773
|
|
|
768
774
|
Result of calling `rawFulfillRandomness` with `gasLimit` gas, at fulfillment and at each `retryCallback`. `success` false means the consumer reverted, ran out of gas or has no code; the word is accepted either way.
|
|
769
775
|
|
|
@@ -773,9 +779,9 @@ Result of calling `rawFulfillRandomness` with `gasLimit` gas, at fulfillment and
|
|
|
773
779
|
event KeeperFeePaid(uint256 indexed requestId, address indexed keeper, uint256 amount, bool paid)
|
|
774
780
|
```
|
|
775
781
|
|
|
776
|
-
Topic 0 `0x7605929b04963e0365f647d9ab12e7ac4aeba5474bb80f1e1554fccad0584683` · Emitted by: [`fulfillRandomness`](#coordinator-fn-fulfillrandomness), [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch) · Source: `D20VRFCoordinator.sol` lines
|
|
782
|
+
Topic 0 `0x7605929b04963e0365f647d9ab12e7ac4aeba5474bb80f1e1554fccad0584683` · Emitted by: [`fulfillRandomness`](#coordinator-fn-fulfillrandomness), [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch) · Source: `D20VRFCoordinator.sol` lines 155, 459–464
|
|
777
783
|
|
|
778
|
-
At acceptance, when the keeper share is non-zero: `amount` went to `keeper`, the registry committer, by a 30,000-gas transfer (`paid` true) or was added to `keeperCredits(keeper)` (`paid` false). Emitted after `CallbackAttempted`.
|
|
784
|
+
At acceptance, when the keeper share is non-zero: `amount` went to `keeper`, the submitter when the registry authorizes it and `committer()` otherwise, by a 30,000-gas transfer (`paid` true) or was added to `keeperCredits(keeper)` (`paid` false). Emitted after `CallbackAttempted`.
|
|
779
785
|
|
|
780
786
|
#### <a id="coordinator-event-fulfillmentskipped"></a>`FulfillmentSkipped`
|
|
781
787
|
|
|
@@ -783,7 +789,7 @@ At acceptance, when the keeper share is non-zero: `amount` went to `keeper`, the
|
|
|
783
789
|
event FulfillmentSkipped(uint256 indexed requestId, uint8 reason)
|
|
784
790
|
```
|
|
785
791
|
|
|
786
|
-
Topic 0 `0x45d96bda73a91db41bdeab56114e5d7b9f42c9f38add9e2d2c6d6f5761203ca3` · Emitted by: [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch) · Source: `D20VRFCoordinator.sol` lines
|
|
792
|
+
Topic 0 `0x45d96bda73a91db41bdeab56114e5d7b9f42c9f38add9e2d2c6d6f5761203ca3` · Emitted by: [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch) · Source: `D20VRFCoordinator.sol` lines 163–164, 424–425
|
|
787
793
|
|
|
788
794
|
A batch member was left untouched: `reason` 1 already fulfilled, 2 refunded, 3 past its deadline.
|
|
789
795
|
|
|
@@ -793,7 +799,7 @@ A batch member was left untouched: `reason` 1 already fulfilled, 2 refunded, 3 p
|
|
|
793
799
|
event RequestRefundedTo(uint256 indexed requestId, address indexed refundAddress, uint256 amount, bool paid)
|
|
794
800
|
```
|
|
795
801
|
|
|
796
|
-
Topic 0 `0x0f6107d218fea62a20553f3700dba7c94dcf653bd2027c0bf1ebe0832f42a506` · Emitted by: [`refundRequest`](#coordinator-fn-refundrequest) · Source: `D20VRFCoordinator.sol` lines
|
|
802
|
+
Topic 0 `0x0f6107d218fea62a20553f3700dba7c94dcf653bd2027c0bf1ebe0832f42a506` · Emitted by: [`refundRequest`](#coordinator-fn-refundrequest) · Source: `D20VRFCoordinator.sol` lines 157, 505
|
|
797
803
|
|
|
798
804
|
An expired request was refunded: `amount` (`feePaid × requestRefundBps / 10000`) was sent to `refundAddress` (`paid` true) or added to its refund credit (`paid` false).
|
|
799
805
|
|
|
@@ -803,7 +809,7 @@ An expired request was refunded: `amount` (`feePaid × requestRefundBps / 10000`
|
|
|
803
809
|
event RefundCallbackAttempted(uint256 indexed requestId, address indexed consumer, bool success, uint32 gasLimit)
|
|
804
810
|
```
|
|
805
811
|
|
|
806
|
-
Topic 0 `0x88448c9fbcfc67f28f0266e82766e402ccd28115fbb84edb6e5b2597effe83d8` · Emitted by: [`refundRequest`](#coordinator-fn-refundrequest), [`retryRefundCallback`](#coordinator-fn-retryrefundcallback) · Source: `D20VRFCoordinator.sol` lines
|
|
812
|
+
Topic 0 `0x88448c9fbcfc67f28f0266e82766e402ccd28115fbb84edb6e5b2597effe83d8` · Emitted by: [`refundRequest`](#coordinator-fn-refundrequest), [`retryRefundCallback`](#coordinator-fn-retryrefundcallback) · Source: `D20VRFCoordinator.sol` lines 159, 519–530
|
|
807
813
|
|
|
808
814
|
Result of calling `onRefund(requestId)` on `consumer` with `gasLimit` gas: 100,000 at `refundRequest`, the caller's limit at `retryRefundCallback`.
|
|
809
815
|
|
|
@@ -815,7 +821,7 @@ Result of calling `onRefund(requestId)` on `consumer` with `gasLimit` gas: 100,0
|
|
|
815
821
|
event RefundCreditWithdrawn(address indexed owner, address indexed recipient, uint256 amount)
|
|
816
822
|
```
|
|
817
823
|
|
|
818
|
-
Topic 0 `0x9d520065b24fda0469128acd3f3078de7e43d70ab762aeea8c741bde25070192` · Emitted by: [`withdrawRefundCredit`](#coordinator-fn-withdrawrefundcredit) · Source: `D20VRFCoordinator.sol` lines
|
|
824
|
+
Topic 0 `0x9d520065b24fda0469128acd3f3078de7e43d70ab762aeea8c741bde25070192` · Emitted by: [`withdrawRefundCredit`](#coordinator-fn-withdrawrefundcredit) · Source: `D20VRFCoordinator.sol` lines 158, 541
|
|
819
825
|
|
|
820
826
|
`owner`, the credit holder (not the contract owner), withdrew `amount` of refund credit to `recipient`.
|
|
821
827
|
|
|
@@ -825,7 +831,7 @@ Topic 0 `0x9d520065b24fda0469128acd3f3078de7e43d70ab762aeea8c741bde25070192` ·
|
|
|
825
831
|
event KeeperCreditWithdrawn(address indexed keeper, address indexed recipient, uint256 amount)
|
|
826
832
|
```
|
|
827
833
|
|
|
828
|
-
Topic 0 `0x22f05c41968705c032a86a65f8fda7e64483ea5e6b6b27a920d1fbfab94267ba` · Emitted by: [`withdrawKeeperCredit`](#coordinator-fn-withdrawkeepercredit) · Source: `D20VRFCoordinator.sol` lines
|
|
834
|
+
Topic 0 `0x22f05c41968705c032a86a65f8fda7e64483ea5e6b6b27a920d1fbfab94267ba` · Emitted by: [`withdrawKeeperCredit`](#coordinator-fn-withdrawkeepercredit) · Source: `D20VRFCoordinator.sol` lines 156, 563
|
|
829
835
|
|
|
830
836
|
`keeper` withdrew `amount` of keeper credit to `recipient`.
|
|
831
837
|
|
|
@@ -835,7 +841,7 @@ Topic 0 `0x22f05c41968705c032a86a65f8fda7e64483ea5e6b6b27a920d1fbfab94267ba` ·
|
|
|
835
841
|
event FeesWithdrawn(address indexed recipient, uint256 amount)
|
|
836
842
|
```
|
|
837
843
|
|
|
838
|
-
Topic 0 `0xc0819c13be868895eb93e40eaceb96de976442fa1d404e5c55f14bb65a8c489a` · Emitted by: [`withdrawFees`](#coordinator-fn-withdrawfees) · Source: `D20VRFCoordinator.sol` lines
|
|
844
|
+
Topic 0 `0xc0819c13be868895eb93e40eaceb96de976442fa1d404e5c55f14bb65a8c489a` · Emitted by: [`withdrawFees`](#coordinator-fn-withdrawfees) · Source: `D20VRFCoordinator.sol` lines 149, 552
|
|
839
845
|
|
|
840
846
|
The fee recipient withdrew `amount` of earned fees to `recipient`.
|
|
841
847
|
|
|
@@ -847,7 +853,7 @@ The fee recipient withdrew `amount` of earned fees to `recipient`.
|
|
|
847
853
|
event PricingChanged(uint256 minFee, uint16 feeMultiplier, uint32 fulfillGasOverhead)
|
|
848
854
|
```
|
|
849
855
|
|
|
850
|
-
Topic 0 `0x32806eb5e21ac2f5fb7d11f898c2995e19fdf203c8a5aeed8b824506cd0d44ff` · Emitted by: [`setPricing`](#coordinator-fn-setpricing) · Source: `D20VRFCoordinator.sol` lines
|
|
856
|
+
Topic 0 `0x32806eb5e21ac2f5fb7d11f898c2995e19fdf203c8a5aeed8b824506cd0d44ff` · Emitted by: [`setPricing`](#coordinator-fn-setpricing) · Source: `D20VRFCoordinator.sol` lines 152, 213
|
|
851
857
|
|
|
852
858
|
New `minFee`, `feeMultiplier` and `fulfillGasOverhead` for requests created afterwards.
|
|
853
859
|
|
|
@@ -857,7 +863,7 @@ New `minFee`, `feeMultiplier` and `fulfillGasOverhead` for requests created afte
|
|
|
857
863
|
event RefundBpsChanged(uint16 previousBps, uint16 newBps)
|
|
858
864
|
```
|
|
859
865
|
|
|
860
|
-
Topic 0 `0x21e3c4cf3007c4ee385a3936593ff4cfa23fc17bca1175b6350c546f9810e0d8` · Emitted by: [`setRefundBps`](#coordinator-fn-setrefundbps) · Source: `D20VRFCoordinator.sol` lines
|
|
866
|
+
Topic 0 `0x21e3c4cf3007c4ee385a3936593ff4cfa23fc17bca1175b6350c546f9810e0d8` · Emitted by: [`setRefundBps`](#coordinator-fn-setrefundbps) · Source: `D20VRFCoordinator.sol` lines 153, 221
|
|
861
867
|
|
|
862
868
|
New refund ratio for requests created afterwards.
|
|
863
869
|
|
|
@@ -867,7 +873,7 @@ New refund ratio for requests created afterwards.
|
|
|
867
873
|
event KeeperFeeBpsChanged(uint16 previousBps, uint16 newBps)
|
|
868
874
|
```
|
|
869
875
|
|
|
870
|
-
Topic 0 `0xa648a60f1d22511c1cc898ca69b633d1a1114079e83734b9ab9a13e0e28c68b7` · Emitted by: [`setKeeperFeeBps`](#coordinator-fn-setkeeperfeebps) · Source: `D20VRFCoordinator.sol` lines
|
|
876
|
+
Topic 0 `0xa648a60f1d22511c1cc898ca69b633d1a1114079e83734b9ab9a13e0e28c68b7` · Emitted by: [`setKeeperFeeBps`](#coordinator-fn-setkeeperfeebps) · Source: `D20VRFCoordinator.sol` lines 151, 205
|
|
871
877
|
|
|
872
878
|
New keeper share, applied at later acceptances, including of requests already open.
|
|
873
879
|
|
|
@@ -877,7 +883,7 @@ New keeper share, applied at later acceptances, including of requests already op
|
|
|
877
883
|
event FeeRecipientChanged(address indexed previousRecipient, address indexed newRecipient)
|
|
878
884
|
```
|
|
879
885
|
|
|
880
|
-
Topic 0 `0x0bc21fe5c3ab742ff1d15b5c4477ffbacf1167e618228078fa625edebe7f331d` · Emitted by: [`setFeeRecipient`](#coordinator-fn-setfeerecipient) · Source: `D20VRFCoordinator.sol` lines
|
|
886
|
+
Topic 0 `0x0bc21fe5c3ab742ff1d15b5c4477ffbacf1167e618228078fa625edebe7f331d` · Emitted by: [`setFeeRecipient`](#coordinator-fn-setfeerecipient) · Source: `D20VRFCoordinator.sol` lines 150, 201
|
|
881
887
|
|
|
882
888
|
New address allowed to withdraw earned fees.
|
|
883
889
|
|
|
@@ -927,7 +933,7 @@ Topic 0 `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` ·
|
|
|
927
933
|
|
|
928
934
|
#### <a id="coordinator-error-contractconsumerrequired"></a>`ContractConsumerRequired`
|
|
929
935
|
|
|
930
|
-
`error ContractConsumerRequired()` · Selector `0x2b99db1e` · Source: `D20VRFCoordinator.sol` lines
|
|
936
|
+
`error ContractConsumerRequired()` · Selector `0x2b99db1e` · Source: `D20VRFCoordinator.sol` lines 113, 255
|
|
931
937
|
|
|
932
938
|
**Raised by:** [`requestRandomness`](#coordinator-fn-requestrandomness), [`requestMappedRandomness`](#coordinator-fn-requestmappedrandomness).
|
|
933
939
|
|
|
@@ -937,7 +943,7 @@ The caller of a request function has no code: an externally owned account, or a
|
|
|
937
943
|
|
|
938
944
|
#### <a id="coordinator-error-invalidrefundaddress"></a>`InvalidRefundAddress`
|
|
939
945
|
|
|
940
|
-
`error InvalidRefundAddress()` · Selector `0xe2fe2726` · Source: `D20VRFCoordinator.sol` lines
|
|
946
|
+
`error InvalidRefundAddress()` · Selector `0xe2fe2726` · Source: `D20VRFCoordinator.sol` lines 127, 256, 534
|
|
941
947
|
|
|
942
948
|
**Raised by:** [`requestRandomness`](#coordinator-fn-requestrandomness), [`requestMappedRandomness`](#coordinator-fn-requestmappedrandomness), [`withdrawRefundCredit`](#coordinator-fn-withdrawrefundcredit).
|
|
943
949
|
|
|
@@ -947,7 +953,7 @@ A request named the zero address as refund address, or `withdrawRefundCredit` na
|
|
|
947
953
|
|
|
948
954
|
#### <a id="coordinator-error-invalidcallbackgas"></a>`InvalidCallbackGas`
|
|
949
955
|
|
|
950
|
-
`error InvalidCallbackGas()` · Selector `0x35883c54` · Source: `D20VRFCoordinator.sol` lines
|
|
956
|
+
`error InvalidCallbackGas()` · Selector `0x35883c54` · Source: `D20VRFCoordinator.sol` lines 115, 479, 515, 626–628
|
|
951
957
|
|
|
952
958
|
**Raised by:** [`requestRandomness`](#coordinator-fn-requestrandomness), [`requestMappedRandomness`](#coordinator-fn-requestmappedrandomness), [`retryCallback`](#coordinator-fn-retrycallback), [`retryRefundCallback`](#coordinator-fn-retryrefundcallback).
|
|
953
959
|
|
|
@@ -957,7 +963,7 @@ A gas limit is out of range: a request `callbackGasLimit` outside 30,000 to 1,00
|
|
|
957
963
|
|
|
958
964
|
#### <a id="coordinator-error-incorrectfee"></a>`IncorrectFee`
|
|
959
965
|
|
|
960
|
-
`error IncorrectFee(uint256 expected, uint256 actual)` · Selector `0xdcf6afcb` · Source: `D20VRFCoordinator.sol` lines
|
|
966
|
+
`error IncorrectFee(uint256 expected, uint256 actual)` · Selector `0xdcf6afcb` · Source: `D20VRFCoordinator.sol` lines 114, 259
|
|
961
967
|
|
|
962
968
|
**Raised by:** [`requestRandomness`](#coordinator-fn-requestrandomness), [`requestMappedRandomness`](#coordinator-fn-requestmappedrandomness).
|
|
963
969
|
|
|
@@ -967,7 +973,7 @@ A gas limit is out of range: a request `callbackGasLimit` outside 30,000 to 1,00
|
|
|
967
973
|
|
|
968
974
|
#### <a id="coordinator-error-feeoverflow"></a>`FeeOverflow`
|
|
969
975
|
|
|
970
|
-
`error FeeOverflow()` · Selector `0x8181adca` · Source: `D20VRFCoordinator.sol` lines
|
|
976
|
+
`error FeeOverflow()` · Selector `0x8181adca` · Source: `D20VRFCoordinator.sol` lines 138, 229
|
|
971
977
|
|
|
972
978
|
**Raised by:** [`quoteFee`](#coordinator-fn-quotefee), [`quoteFeeAt`](#coordinator-fn-quotefeeat), [`requestRandomness`](#coordinator-fn-requestrandomness), [`requestMappedRandomness`](#coordinator-fn-requestmappedrandomness).
|
|
973
979
|
|
|
@@ -987,7 +993,7 @@ The spec breaks the rules for its operation (README [Randomness options](README.
|
|
|
987
993
|
|
|
988
994
|
#### <a id="coordinator-error-epochunavailable"></a>`EpochUnavailable`
|
|
989
995
|
|
|
990
|
-
`error EpochUnavailable()` · Selector `0x0b3487b8` · Source: `D20VRFCoordinator.sol` lines
|
|
996
|
+
`error EpochUnavailable()` · Selector `0x0b3487b8` · Source: `D20VRFCoordinator.sol` lines 111, 263
|
|
991
997
|
|
|
992
998
|
**Raised by:** [`requestRandomness`](#coordinator-fn-requestrandomness), [`requestMappedRandomness`](#coordinator-fn-requestmappedrandomness).
|
|
993
999
|
|
|
@@ -999,7 +1005,7 @@ The request block is before the registry's first epoch: `epochForBlock(block.num
|
|
|
999
1005
|
|
|
1000
1006
|
#### <a id="coordinator-error-unknownrequest"></a>`UnknownRequest`
|
|
1001
1007
|
|
|
1002
|
-
`error UnknownRequest()` · Selector `0x6d080297` · Source: `D20VRFCoordinator.sol` lines
|
|
1008
|
+
`error UnknownRequest()` · Selector `0x6d080297` · Source: `D20VRFCoordinator.sol` lines 116, 566–569
|
|
1003
1009
|
|
|
1004
1010
|
**Raised by:** [`getRequest`](#coordinator-fn-getrequest), [`getMapping`](#coordinator-fn-getmapping), [`getMappedResult`](#coordinator-fn-getmappedresult), [`requestFeePaid`](#coordinator-fn-requestfeepaid), [`requestRefundBps`](#coordinator-fn-requestrefundbps), [`refundRequest`](#coordinator-fn-refundrequest), [`retryCallback`](#coordinator-fn-retrycallback), [`retryRefundCallback`](#coordinator-fn-retryrefundcallback), [`fulfillRandomness`](#coordinator-fn-fulfillrandomness), [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch), [`storeBlockHash`](#coordinator-fn-storeblockhash), [`verifyRequestProof`](#coordinator-fn-verifyrequestproof), [`requestSeed`](#coordinator-fn-requestseed), [`getProofContext`](#coordinator-fn-getproofcontext).
|
|
1005
1011
|
|
|
@@ -1009,7 +1015,7 @@ No request has this ID: 0, or not below `nextRequestId()`. An unknown ID also re
|
|
|
1009
1015
|
|
|
1010
1016
|
#### <a id="coordinator-error-notfulfilled"></a>`NotFulfilled`
|
|
1011
1017
|
|
|
1012
|
-
`error NotFulfilled()` · Selector `0x07bc6c3e` · Source: `D20VRFCoordinator.sol` lines
|
|
1018
|
+
`error NotFulfilled()` · Selector `0x07bc6c3e` · Source: `D20VRFCoordinator.sol` lines 120, 351, 476
|
|
1013
1019
|
|
|
1014
1020
|
**Raised by:** [`getMappedResult`](#coordinator-fn-getmappedresult), [`retryCallback`](#coordinator-fn-retrycallback).
|
|
1015
1021
|
|
|
@@ -1019,7 +1025,7 @@ No request has this ID: 0, or not below `nextRequestId()`. An unknown ID also re
|
|
|
1019
1025
|
|
|
1020
1026
|
#### <a id="coordinator-error-alreadydelivered"></a>`AlreadyDelivered`
|
|
1021
1027
|
|
|
1022
|
-
`error AlreadyDelivered()` · Selector `0xb9f79653` · Source: `D20VRFCoordinator.sol` lines
|
|
1028
|
+
`error AlreadyDelivered()` · Selector `0xb9f79653` · Source: `D20VRFCoordinator.sol` lines 121, 477
|
|
1023
1029
|
|
|
1024
1030
|
**Raised by:** [`retryCallback`](#coordinator-fn-retrycallback).
|
|
1025
1031
|
|
|
@@ -1029,7 +1035,7 @@ No request has this ID: 0, or not below `nextRequestId()`. An unknown ID also re
|
|
|
1029
1035
|
|
|
1030
1036
|
#### <a id="coordinator-error-refundnotavailable"></a>`RefundNotAvailable`
|
|
1031
1037
|
|
|
1032
|
-
`error RefundNotAvailable()` · Selector `0x0b4d6981` · Source: `D20VRFCoordinator.sol` lines
|
|
1038
|
+
`error RefundNotAvailable()` · Selector `0x0b4d6981` · Source: `D20VRFCoordinator.sol` lines 130, 488
|
|
1033
1039
|
|
|
1034
1040
|
**Raised by:** [`refundRequest`](#coordinator-fn-refundrequest).
|
|
1035
1041
|
|
|
@@ -1039,7 +1045,7 @@ No request has this ID: 0, or not below `nextRequestId()`. An unknown ID also re
|
|
|
1039
1045
|
|
|
1040
1046
|
#### <a id="coordinator-error-notrefunded"></a>`NotRefunded`
|
|
1041
1047
|
|
|
1042
|
-
`error NotRefunded()` · Selector `0xfae7079c` · Source: `D20VRFCoordinator.sol` lines
|
|
1048
|
+
`error NotRefunded()` · Selector `0xfae7079c` · Source: `D20VRFCoordinator.sol` lines 133, 512
|
|
1043
1049
|
|
|
1044
1050
|
**Raised by:** [`retryRefundCallback`](#coordinator-fn-retryrefundcallback).
|
|
1045
1051
|
|
|
@@ -1049,7 +1055,7 @@ No request has this ID: 0, or not below `nextRequestId()`. An unknown ID also re
|
|
|
1049
1055
|
|
|
1050
1056
|
#### <a id="coordinator-error-refundcallbackalreadydelivered"></a>`RefundCallbackAlreadyDelivered`
|
|
1051
1057
|
|
|
1052
|
-
`error RefundCallbackAlreadyDelivered()` · Selector `0x6502f8ae` · Source: `D20VRFCoordinator.sol` lines
|
|
1058
|
+
`error RefundCallbackAlreadyDelivered()` · Selector `0x6502f8ae` · Source: `D20VRFCoordinator.sol` lines 134, 513
|
|
1053
1059
|
|
|
1054
1060
|
**Raised by:** [`retryRefundCallback`](#coordinator-fn-retryrefundcallback).
|
|
1055
1061
|
|
|
@@ -1059,19 +1065,19 @@ No request has this ID: 0, or not below `nextRequestId()`. An unknown ID also re
|
|
|
1059
1065
|
|
|
1060
1066
|
#### <a id="coordinator-error-insufficientcallbackgas"></a>`InsufficientCallbackGas`
|
|
1061
1067
|
|
|
1062
|
-
`error InsufficientCallbackGas()` · Selector `0xa2c23f0d` · Source: `D20VRFCoordinator.sol` lines
|
|
1068
|
+
`error InsufficientCallbackGas()` · Selector `0xa2c23f0d` · Source: `D20VRFCoordinator.sol` lines 124, 421, 497, 522, 638–639
|
|
1063
1069
|
|
|
1064
1070
|
**Raised by:** [`refundRequest`](#coordinator-fn-refundrequest), [`retryCallback`](#coordinator-fn-retrycallback), [`retryRefundCallback`](#coordinator-fn-retryrefundcallback), [`fulfillRandomness`](#coordinator-fn-fulfillrandomness), [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch).
|
|
1065
1071
|
|
|
1066
|
-
Too little gas remained to forward the full callback budget and keep the coordinator's reserve: `gasLimit + gasLimit/63 + 140,000` before a fulfillment callback, `100,000 + 100,000/63 + 140,000` after refund settlement, `gasLimit + gasLimit/63 + 50,000` before a refund notification. The coordinator reverts instead of forwarding less.
|
|
1072
|
+
Too little gas remained to forward the full callback budget and keep the coordinator's reserve: `gasLimit + gasLimit/63 + 140,000` before a fulfillment callback, `100,000 + 100,000/63 + 140,000` after refund settlement, `gasLimit + gasLimit/63 + 50,000` before a refund notification, and `140,000 + Σ(callbackGasLimit + callbackGasLimit / 63 + 400,000)` over the served members before `fulfillRandomnessBatch` reveals any result. The coordinator reverts instead of forwarding less.
|
|
1067
1073
|
|
|
1068
|
-
**What to do:** Raise the transaction gas limit: 400,000 for `refundRequest`, `gasLimit + 250,000` for `retryCallback`, `gasLimit + 150,000` for `retryRefundCallback` (README [Gas for refund and retry calls](README.md#gas-for-refund-and-retry-calls)). `eth_estimateGas` finds the minimum.
|
|
1074
|
+
**What to do:** Raise the transaction gas limit: 400,000 for `refundRequest`, `gasLimit + 250,000` for `retryCallback`, `gasLimit + 150,000` for `retryRefundCallback` (README [Gas for refund and retry calls](README.md#gas-for-refund-and-retry-calls)); a keeper sizes a batch to the sum above. `eth_estimateGas` finds the minimum.
|
|
1069
1075
|
|
|
1070
1076
|
**Credits and withdrawals**
|
|
1071
1077
|
|
|
1072
1078
|
#### <a id="coordinator-error-norefundcredit"></a>`NoRefundCredit`
|
|
1073
1079
|
|
|
1074
|
-
`error NoRefundCredit()` · Selector `0x1d59da8e` · Source: `D20VRFCoordinator.sol` lines
|
|
1080
|
+
`error NoRefundCredit()` · Selector `0x1d59da8e` · Source: `D20VRFCoordinator.sol` lines 131, 536
|
|
1075
1081
|
|
|
1076
1082
|
**Raised by:** [`withdrawRefundCredit`](#coordinator-fn-withdrawrefundcredit).
|
|
1077
1083
|
|
|
@@ -1081,7 +1087,7 @@ Too little gas remained to forward the full callback budget and keep the coordin
|
|
|
1081
1087
|
|
|
1082
1088
|
#### <a id="coordinator-error-transferfailed"></a>`TransferFailed`
|
|
1083
1089
|
|
|
1084
|
-
`error TransferFailed()` · Selector `0x90b8ec18` · Source: `D20VRFCoordinator.sol` lines
|
|
1090
|
+
`error TransferFailed()` · Selector `0x90b8ec18` · Source: `D20VRFCoordinator.sol` lines 126, 540, 551, 562
|
|
1085
1091
|
|
|
1086
1092
|
**Raised by:** [`withdrawRefundCredit`](#coordinator-fn-withdrawrefundcredit), [`withdrawFees`](#coordinator-fn-withdrawfees), [`withdrawKeeperCredit`](#coordinator-fn-withdrawkeepercredit).
|
|
1087
1093
|
|
|
@@ -1091,7 +1097,7 @@ The `recipient` of `withdrawRefundCredit`, `withdrawFees` or `withdrawKeeperCred
|
|
|
1091
1097
|
|
|
1092
1098
|
#### <a id="coordinator-error-onlyfeerecipient"></a>`OnlyFeeRecipient`
|
|
1093
1099
|
|
|
1094
|
-
`error OnlyFeeRecipient()` · Selector `0x07d8ed3d` · Source: `D20VRFCoordinator.sol` lines
|
|
1100
|
+
`error OnlyFeeRecipient()` · Selector `0x07d8ed3d` · Source: `D20VRFCoordinator.sol` lines 125, 546
|
|
1095
1101
|
|
|
1096
1102
|
**Raised by:** [`withdrawFees`](#coordinator-fn-withdrawfees).
|
|
1097
1103
|
|
|
@@ -1101,7 +1107,7 @@ The `recipient` of `withdrawRefundCredit`, `withdrawFees` or `withdrawKeeperCred
|
|
|
1101
1107
|
|
|
1102
1108
|
#### <a id="coordinator-error-nokeepercredit"></a>`NoKeeperCredit`
|
|
1103
1109
|
|
|
1104
|
-
`error NoKeeperCredit()` · Selector `0x0d106640` · Source: `D20VRFCoordinator.sol` lines
|
|
1110
|
+
`error NoKeeperCredit()` · Selector `0x0d106640` · Source: `D20VRFCoordinator.sol` lines 132, 558
|
|
1105
1111
|
|
|
1106
1112
|
**Raised by:** [`withdrawKeeperCredit`](#coordinator-fn-withdrawkeepercredit).
|
|
1107
1113
|
|
|
@@ -1113,7 +1119,7 @@ The `recipient` of `withdrawRefundCredit`, `withdrawFees` or `withdrawKeeperCred
|
|
|
1113
1119
|
|
|
1114
1120
|
#### <a id="coordinator-error-notready"></a>`NotReady`
|
|
1115
1121
|
|
|
1116
|
-
`error NotReady()` · Selector `0x9488aaa6` · Source: `D20VRFCoordinator.sol` lines
|
|
1122
|
+
`error NotReady()` · Selector `0x9488aaa6` · Source: `D20VRFCoordinator.sol` lines 117, 583
|
|
1117
1123
|
|
|
1118
1124
|
**Raised by:** [`fulfillRandomness`](#coordinator-fn-fulfillrandomness), [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch), [`storeBlockHash`](#coordinator-fn-storeblockhash), [`verifyRequestProof`](#coordinator-fn-verifyrequestproof), [`requestSeed`](#coordinator-fn-requestseed), [`getProofContext`](#coordinator-fn-getproofcontext).
|
|
1119
1125
|
|
|
@@ -1123,7 +1129,7 @@ The request cannot be proven yet: its epoch packet is not published, or `block.n
|
|
|
1123
1129
|
|
|
1124
1130
|
#### <a id="coordinator-error-blockhashunavailable"></a>`BlockHashUnavailable`
|
|
1125
1131
|
|
|
1126
|
-
`error BlockHashUnavailable()` · Selector `0xbfc9f0d3` · Source: `D20VRFCoordinator.sol` lines
|
|
1132
|
+
`error BlockHashUnavailable()` · Selector `0xbfc9f0d3` · Source: `D20VRFCoordinator.sol` lines 118, 586
|
|
1127
1133
|
|
|
1128
1134
|
**Raised by:** [`fulfillRandomness`](#coordinator-fn-fulfillrandomness), [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch), [`storeBlockHash`](#coordinator-fn-storeblockhash), [`verifyRequestProof`](#coordinator-fn-verifyrequestproof), [`requestSeed`](#coordinator-fn-requestseed), [`getProofContext`](#coordinator-fn-getproofcontext).
|
|
1129
1135
|
|
|
@@ -1133,7 +1139,7 @@ The target block hash was never stored and is outside the 256-block `BLOCKHASH`
|
|
|
1133
1139
|
|
|
1134
1140
|
#### <a id="coordinator-error-alreadyfulfilled"></a>`AlreadyFulfilled`
|
|
1135
1141
|
|
|
1136
|
-
`error AlreadyFulfilled()` · Selector `0x4a4117f9` · Source: `D20VRFCoordinator.sol` lines
|
|
1142
|
+
`error AlreadyFulfilled()` · Selector `0x4a4117f9` · Source: `D20VRFCoordinator.sol` lines 119, 397
|
|
1137
1143
|
|
|
1138
1144
|
**Raised by:** [`fulfillRandomness`](#coordinator-fn-fulfillrandomness).
|
|
1139
1145
|
|
|
@@ -1143,7 +1149,7 @@ The target block hash was never stored and is outside the 256-block `BLOCKHASH`
|
|
|
1143
1149
|
|
|
1144
1150
|
#### <a id="coordinator-error-requestrefunded"></a>`RequestRefunded`
|
|
1145
1151
|
|
|
1146
|
-
`error RequestRefunded()` · Selector `0xe0dec416` · Source: `D20VRFCoordinator.sol` lines
|
|
1152
|
+
`error RequestRefunded()` · Selector `0xe0dec416` · Source: `D20VRFCoordinator.sol` lines 129, 398
|
|
1147
1153
|
|
|
1148
1154
|
**Raised by:** [`fulfillRandomness`](#coordinator-fn-fulfillrandomness).
|
|
1149
1155
|
|
|
@@ -1153,7 +1159,7 @@ The target block hash was never stored and is outside the 256-block `BLOCKHASH`
|
|
|
1153
1159
|
|
|
1154
1160
|
#### <a id="coordinator-error-requestexpired"></a>`RequestExpired`
|
|
1155
1161
|
|
|
1156
|
-
`error RequestExpired()` · Selector `0xfef01cd2` · Source: `D20VRFCoordinator.sol` lines
|
|
1162
|
+
`error RequestExpired()` · Selector `0xfef01cd2` · Source: `D20VRFCoordinator.sol` lines 128, 399
|
|
1157
1163
|
|
|
1158
1164
|
**Raised by:** [`fulfillRandomness`](#coordinator-fn-fulfillrandomness).
|
|
1159
1165
|
|
|
@@ -1163,7 +1169,7 @@ The target block hash was never stored and is outside the 256-block `BLOCKHASH`
|
|
|
1163
1169
|
|
|
1164
1170
|
#### <a id="coordinator-error-wrongpublickey"></a>`WrongPublicKey`
|
|
1165
1171
|
|
|
1166
|
-
`error WrongPublicKey()` · Selector `0x2b0bb68e` · Source: `D20VRFCoordinator.sol` lines
|
|
1172
|
+
`error WrongPublicKey()` · Selector `0x2b0bb68e` · Source: `D20VRFCoordinator.sol` lines 122, 611
|
|
1167
1173
|
|
|
1168
1174
|
**Raised by:** [`fulfillRandomness`](#coordinator-fn-fulfillrandomness), [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch), [`verifyRequestProof`](#coordinator-fn-verifyrequestproof).
|
|
1169
1175
|
|
|
@@ -1173,7 +1179,7 @@ The proof's `pk` is not the coordinator's VRF key.
|
|
|
1173
1179
|
|
|
1174
1180
|
#### <a id="coordinator-error-wrongseed"></a>`WrongSeed`
|
|
1175
1181
|
|
|
1176
|
-
`error WrongSeed()` · Selector `0xf36cbea4` · Source: `D20VRFCoordinator.sol` lines
|
|
1182
|
+
`error WrongSeed()` · Selector `0xf36cbea4` · Source: `D20VRFCoordinator.sol` lines 123, 613
|
|
1177
1183
|
|
|
1178
1184
|
**Raised by:** [`fulfillRandomness`](#coordinator-fn-fulfillrandomness), [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch), [`verifyRequestProof`](#coordinator-fn-verifyrequestproof).
|
|
1179
1185
|
|
|
@@ -1183,7 +1189,7 @@ The proof's `seed` differs from `requestSeed(requestId)`.
|
|
|
1183
1189
|
|
|
1184
1190
|
#### <a id="coordinator-error-evidencepackettoolarge"></a>`EvidencePacketTooLarge`
|
|
1185
1191
|
|
|
1186
|
-
`error EvidencePacketTooLarge()` · Selector `0xcfbc3ebf` · Source: `D20VRFCoordinator.sol` lines
|
|
1192
|
+
`error EvidencePacketTooLarge()` · Selector `0xcfbc3ebf` · Source: `D20VRFCoordinator.sol` lines 136, 469
|
|
1187
1193
|
|
|
1188
1194
|
**Raised by:** [`fulfillRandomness`](#coordinator-fn-fulfillrandomness), [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch).
|
|
1189
1195
|
|
|
@@ -1193,7 +1199,7 @@ The encoded proof exceeds `MAX_EVIDENCE_PACKET_BYTES`. A proof always encodes to
|
|
|
1193
1199
|
|
|
1194
1200
|
#### <a id="coordinator-error-invalidbatch"></a>`InvalidBatch`
|
|
1195
1201
|
|
|
1196
|
-
`error InvalidBatch()` · Selector `0x33b094a1` · Source: `D20VRFCoordinator.sol` lines
|
|
1202
|
+
`error InvalidBatch()` · Selector `0x33b094a1` · Source: `D20VRFCoordinator.sol` lines 139, 410
|
|
1197
1203
|
|
|
1198
1204
|
**Raised by:** [`fulfillRandomnessBatch`](#coordinator-fn-fulfillrandomnessbatch).
|
|
1199
1205
|
|
|
@@ -1203,7 +1209,7 @@ The encoded proof exceeds `MAX_EVIDENCE_PACKET_BYTES`. A proof always encodes to
|
|
|
1203
1209
|
|
|
1204
1210
|
#### <a id="coordinator-error-invalidscan"></a>`InvalidScan`
|
|
1205
1211
|
|
|
1206
|
-
`error InvalidScan()` · Selector `0x3e6249a2` · Source: `D20VRFCoordinator.sol` lines
|
|
1212
|
+
`error InvalidScan()` · Selector `0x3e6249a2` · Source: `D20VRFCoordinator.sol` lines 135, 320
|
|
1207
1213
|
|
|
1208
1214
|
**Raised by:** [`getPendingRequestIds`](#coordinator-fn-getpendingrequestids).
|
|
1209
1215
|
|
|
@@ -1215,17 +1221,17 @@ The encoded proof exceeds `MAX_EVIDENCE_PACKET_BYTES`. A proof always encodes to
|
|
|
1215
1221
|
|
|
1216
1222
|
#### <a id="coordinator-error-invalidconfig"></a>`InvalidConfig`
|
|
1217
1223
|
|
|
1218
|
-
`error InvalidConfig()` · Selector `0x35be3ac8` · Source: `D20VRFCoordinator.sol` lines
|
|
1224
|
+
`error InvalidConfig()` · Selector `0x35be3ac8` · Source: `D20VRFCoordinator.sol` lines 110, 176–177, 200, 204, 209, 211, 220, 547, 556
|
|
1219
1225
|
|
|
1220
1226
|
**Raised by:** [`withdrawFees`](#coordinator-fn-withdrawfees), [`withdrawKeeperCredit`](#coordinator-fn-withdrawkeepercredit), [`setPricing`](#coordinator-fn-setpricing), [`setRefundBps`](#coordinator-fn-setrefundbps), [`setKeeperFeeBps`](#coordinator-fn-setkeeperfeebps), [`setFeeRecipient`](#coordinator-fn-setfeerecipient), [`initialize`](#coordinator-fn-initialize).
|
|
1221
1227
|
|
|
1222
|
-
A value is out of bounds: in `initialize` (zero fee recipient, confirmations 0 or above 64, keeper share above 10000, minimum fee above 10 USDC, registry without code), `setFeeRecipient` with zero, `setKeeperFeeBps` above 10000, `setPricing` outside its bounds, `setRefundBps` outside 5000 to 10000, or a zero `recipient` for `withdrawFees` or `withdrawKeeperCredit`.
|
|
1228
|
+
A value is out of bounds: in `initialize` (zero fee recipient, confirmations 0 or above 64, keeper share above 10000, minimum fee above 10 USDC, registry without code), `setFeeRecipient` with zero, `setKeeperFeeBps` above 10000, `setPricing` outside its bounds or with `minFee` and `feeMultiplier` both zero, `setRefundBps` outside 5000 to 10000, or a zero `recipient` for `withdrawFees` or `withdrawKeeperCredit`.
|
|
1223
1229
|
|
|
1224
1230
|
**What to do:** Use values within the bounds given for each function.
|
|
1225
1231
|
|
|
1226
1232
|
#### <a id="coordinator-error-invalidpublickey"></a>`InvalidPublicKey`
|
|
1227
1233
|
|
|
1228
|
-
`error InvalidPublicKey()` · Selector `0xa2d0fee8` · Source: `D20VRFCoordinator.sol` lines
|
|
1234
|
+
`error InvalidPublicKey()` · Selector `0xa2d0fee8` · Source: `D20VRFCoordinator.sol` lines 112, 179
|
|
1229
1235
|
|
|
1230
1236
|
**Raised by:** [`initialize`](#coordinator-fn-initialize).
|
|
1231
1237
|
|
|
@@ -1265,7 +1271,7 @@ A `nonReentrant` coordinator function (a request, `storeBlockHash`, a fulfillmen
|
|
|
1265
1271
|
|
|
1266
1272
|
#### <a id="coordinator-error-renouncedisabled"></a>`RenounceDisabled`
|
|
1267
1273
|
|
|
1268
|
-
`error RenounceDisabled()` · Selector `0x89051165` · Source: `D20VRFCoordinator.sol` lines
|
|
1274
|
+
`error RenounceDisabled()` · Selector `0x89051165` · Source: `D20VRFCoordinator.sol` lines 137, 197
|
|
1269
1275
|
|
|
1270
1276
|
**Raised by:** [`renounceOwnership`](#coordinator-fn-renounceownership).
|
|
1271
1277
|
|
|
@@ -1357,21 +1363,25 @@ The initialization call made by `upgradeToAndCall` reverted without revert data.
|
|
|
1357
1363
|
|
|
1358
1364
|
The epoch registry. A consumer never needs to call it: a request fixes its epoch automatically, and the coordinator reads the registry for targets and for the keeper-share recipient. The first group and the events matter to consumers and verifiers (README [Replay and verification](README.md#replay-and-verification)); publication and administration are listed for completeness.
|
|
1359
1365
|
|
|
1366
|
+
Epoch sources are recipes in an owner-managed, append-only registry: each has an id, a canonical request whose `keccak256` is the query hash its signer signs, a data template that fixes the exact signed bytes the registry accepts (README [Data templates](README.md#data-templates)) and the body keepers send: the JSON they post to the provider gateway, or a beacon's canonical request. A catalog lists 1 to `MAX_SOURCES` registered recipes with one signer each; each epoch selects from the catalog in force for it (`catalogAt`).
|
|
1367
|
+
|
|
1368
|
+
A recipe is one of two kinds. A signed API recipe (`registerRecipe`) commits a provider's signed record: the signature is an EIP-191 signature of the recipe's signer over the query hash, timestamp and data. A beacon recipe (`registerBeacon`) commits one round of a public randomness beacon such as drand: the data is the round number, the timestamp the round's scheduled time and the signature the beacon's, which the verifier recorded in its registration (`beaconOf`) checks. Its catalog signer is `slotSigner(recipe)`, an identity derived from the registration. Replay needs the registration of every beacon recipe an epoch used (README [Beacon epochs](README.md#beacon-epochs)).
|
|
1369
|
+
|
|
1360
1370
|
### <a id="registry-types"></a>Types
|
|
1361
1371
|
|
|
1362
1372
|
#### <a id="registry-type-epochentropy-epoch"></a>`EpochEntropy.Epoch`
|
|
1363
1373
|
|
|
1364
1374
|
Returned by `getEpoch`; all zero until the epoch is published.
|
|
1365
1375
|
|
|
1366
|
-
Source: `EpochEntropy.sol` lines
|
|
1376
|
+
Source: `EpochEntropy.sol` lines 57–60
|
|
1367
1377
|
|
|
1368
1378
|
| Field | Type | Meaning |
|
|
1369
1379
|
| --- | --- | --- |
|
|
1370
1380
|
| `epochHash` | `bytes32` | Epoch commitment: `keccak256(abi.encode(EPOCH_DOMAIN, chainId, registry, catalogHash, epochId, epochStart, anchorHash, source, queryHash, dataHash, attestationHash))`. |
|
|
1371
|
-
| `catalogHash` | `bytes32` |
|
|
1381
|
+
| `catalogHash` | `bytes32` | Hash of the catalog in force for the epoch (`catalogAt`) at publication. |
|
|
1372
1382
|
| `anchorHash` | `bytes32` | Hash of block `epochStart - 1`, which selects the source. |
|
|
1373
|
-
| `source` | `uint8` | Committed
|
|
1374
|
-
| `queryHash` | `bytes32` | `keccak256` of the canonical request
|
|
1383
|
+
| `source` | `uint8` | Committed slot in the epoch's catalog, 0 to `sourceCountAt(epochId) - 1`: the selected slot or a fallback. The recipe is the catalog's recipe at that slot. |
|
|
1384
|
+
| `queryHash` | `bytes32` | `keccak256` of the canonical request of the slot's recipe. |
|
|
1375
1385
|
| `dataHash` | `bytes32` | `keccak256` of the signed response data. |
|
|
1376
1386
|
| `attestationHash` | `bytes32` | `keccak256(abi.encode(queryHash, timestamp, dataHash, keccak256(signature)))`. |
|
|
1377
1387
|
| `signedAt` | `uint256` | Attestation timestamp in Unix seconds. |
|
|
@@ -1381,27 +1391,42 @@ Source: `EpochEntropy.sol` lines 30–33
|
|
|
1381
1391
|
|
|
1382
1392
|
Returned by `getEpochSelection` and `getEpochFallbackSelection`.
|
|
1383
1393
|
|
|
1384
|
-
Source: `EpochEntropy.sol` lines
|
|
1394
|
+
Source: `EpochEntropy.sol` lines 55–56, 345–356
|
|
1385
1395
|
|
|
1386
1396
|
| Field | Type | Meaning |
|
|
1387
1397
|
| --- | --- | --- |
|
|
1388
|
-
| `source` | `uint8` |
|
|
1389
|
-
| `
|
|
1390
|
-
| `
|
|
1398
|
+
| `source` | `uint8` | Slot in the epoch's catalog. |
|
|
1399
|
+
| `recipe` | `uint8` | Registered recipe id at that slot. |
|
|
1400
|
+
| `airnode` | `address` | Signer of that slot in the catalog in force for the epoch; for a beacon recipe its `slotSigner`. |
|
|
1401
|
+
| `selector` | `bytes32` | `keccak256(abi.encode(SELECT_DOMAIN, catalogHash, epochId, anchor))`; the slot is `(selector mod count + attempt) mod count` with `count = sourceCountAt(epochId)`. |
|
|
1391
1402
|
| `queryHash` | `bytes32` | `keccak256` of `canonicalRequest`. |
|
|
1392
|
-
| `canonicalRequest` | `string` |
|
|
1403
|
+
| `canonicalRequest` | `string` | Canonical request of the recipe, as `getRecipe` returns it. |
|
|
1393
1404
|
|
|
1394
1405
|
#### <a id="registry-type-epochentropy-attestation"></a>`EpochEntropy.Attestation`
|
|
1395
1406
|
|
|
1396
|
-
|
|
1407
|
+
Source response passed to `commitEpoch` and `commitEpochFallback`: a signed API record or a beacon round.
|
|
1397
1408
|
|
|
1398
|
-
Source: `EpochEntropy.sol` lines
|
|
1409
|
+
Source: `EpochEntropy.sol` lines 54, 363–391
|
|
1399
1410
|
|
|
1400
1411
|
| Field | Type | Meaning |
|
|
1401
1412
|
| --- | --- | --- |
|
|
1402
|
-
| `timestamp` | `uint256` | Signing time in Unix seconds
|
|
1403
|
-
| `data` | `bytes` | Signed response bytes,
|
|
1404
|
-
| `signature` | `bytes` |
|
|
1413
|
+
| `timestamp` | `uint256` | Signing time in Unix seconds, or for a beacon round its scheduled time `genesis + (round - 1) × period`; not in the future and at most `MAX_ATTESTATION_AGE` old at publication. |
|
|
1414
|
+
| `data` | `bytes` | Signed response bytes, or for a beacon the round number in decimal, at most `MAX_DATA_BYTES` (128), matching the data template of the slot's recipe exactly. |
|
|
1415
|
+
| `signature` | `bytes` | For a signed API recipe, the 65-byte signature over `toEthSignedMessageHash(keccak256(abi.encodePacked(queryHash, timestamp, data)))`. For a beacon recipe, the beacon's 64-byte signature of the round, which the registered verifier checks. |
|
|
1416
|
+
|
|
1417
|
+
#### <a id="registry-type-epochentropy-beacon"></a>`EpochEntropy.Beacon`
|
|
1418
|
+
|
|
1419
|
+
Returned by `beaconOf`: the registration of a beacon recipe. Fixed when `registerBeacon` appends the recipe. All zero for a signed API recipe.
|
|
1420
|
+
|
|
1421
|
+
Source: `EpochEntropy.sol` lines 64–66
|
|
1422
|
+
|
|
1423
|
+
| Field | Type | Meaning |
|
|
1424
|
+
| --- | --- | --- |
|
|
1425
|
+
| `verifier` | `address` | Contract that checks a round's signature under `publicKey` (`IBeaconVerifier`, for drand's evmnet `D20BeaconVerifier`). Zero marks a signed API recipe. |
|
|
1426
|
+
| `genesis` | `uint64` | Scheduled time of round 1, Unix seconds. Round `r` is scheduled at `genesis + (r - 1) × period`. |
|
|
1427
|
+
| `period` | `uint64` | Seconds between rounds. |
|
|
1428
|
+
| `chainHash` | `bytes32` | Identifier of the beacon network (for drand, the chain hash), 32 bytes. The recipe's canonical request is `["drand","<chainHash>"]`. |
|
|
1429
|
+
| `publicKey` | `bytes` | The beacon's group public key as the verifier reads it; for `D20BeaconVerifier` 128 bytes, `x_im ‖ x_re ‖ y_im ‖ y_re` of a BN254 G2 point. |
|
|
1405
1430
|
|
|
1406
1431
|
### <a id="registry-epoch-state-for-consumers-and-verifiers"></a>Epoch state for consumers and verifiers
|
|
1407
1432
|
|
|
@@ -1413,7 +1438,7 @@ Views, callable by anyone. Epoch IDs start at 1; each epoch lasts `EPOCH_LENGTH`
|
|
|
1413
1438
|
function epochForBlock(uint256 number) external view returns (uint64)
|
|
1414
1439
|
```
|
|
1415
1440
|
|
|
1416
|
-
Selector `0x7018ebb1` · Caller: Anyone (view) · Source: `EpochEntropy.sol` lines
|
|
1441
|
+
Selector `0x7018ebb1` · Caller: Anyone (view) · Source: `EpochEntropy.sol` lines 318–320
|
|
1417
1442
|
|
|
1418
1443
|
Epoch containing a block: 0 before `firstEpochStart`, otherwise `1 + (number - firstEpochStart) / 200`. A request belongs to `epochForBlock(requestBlock)`.
|
|
1419
1444
|
|
|
@@ -1423,7 +1448,7 @@ Epoch containing a block: 0 before `firstEpochStart`, otherwise `1 + (number - f
|
|
|
1423
1448
|
function epochStart(uint64 epochId) external view returns (uint64)
|
|
1424
1449
|
```
|
|
1425
1450
|
|
|
1426
|
-
Selector `0xa1587509` · Caller: Anyone (view) · Source: `EpochEntropy.sol` lines
|
|
1451
|
+
Selector `0xa1587509` · Caller: Anyone (view) · Source: `EpochEntropy.sol` lines 314–317
|
|
1427
1452
|
|
|
1428
1453
|
First block of an epoch: `firstEpochStart + (epochId - 1) × 200`.
|
|
1429
1454
|
|
|
@@ -1435,29 +1460,97 @@ First block of an epoch: `firstEpochStart + (epochId - 1) × 200`.
|
|
|
1435
1460
|
function getEpoch(uint64 epochId) external view returns (EpochEntropy.Epoch)
|
|
1436
1461
|
```
|
|
1437
1462
|
|
|
1438
|
-
Selector `0x12a02c82` · Caller: Anyone (view) · Source: `EpochEntropy.sol` line
|
|
1463
|
+
Selector `0x12a02c82` · Caller: Anyone (view) · Source: `EpochEntropy.sol` line 335
|
|
1439
1464
|
|
|
1440
1465
|
The published [`EpochEntropy.Epoch`](#registry-type-epochentropy-epoch) record, or all zero while unpublished; it never reverts. A non-zero `epochHash` means published.
|
|
1441
1466
|
|
|
1442
|
-
#### <a id="registry-fn-
|
|
1467
|
+
#### <a id="registry-fn-catalogat"></a>`catalogAt`
|
|
1468
|
+
|
|
1469
|
+
```solidity
|
|
1470
|
+
function catalogAt(uint64 epochId) external view returns (bytes32 hash, uint8[] recipes, address[] signers)
|
|
1471
|
+
```
|
|
1472
|
+
|
|
1473
|
+
Selector `0xec993599` · Caller: Anyone (view) · Source: `EpochEntropy.sol` lines 295–303, 309–313
|
|
1474
|
+
|
|
1475
|
+
The catalog in force for an epoch: its hash and the recipe id and signer of each slot, in slot order. That is the latest scheduled version whose `fromEpoch` is at or below `epochId`, otherwise the initial catalog: recipes 0 to 3 with the initial signers and hash `catalogHash()`. Replay needs this catalog, not the initial signer getters.
|
|
1476
|
+
|
|
1477
|
+
#### <a id="registry-fn-sourcecountat"></a>`sourceCountAt`
|
|
1478
|
+
|
|
1479
|
+
```solidity
|
|
1480
|
+
function sourceCountAt(uint64 epochId) external view returns (uint256)
|
|
1481
|
+
```
|
|
1482
|
+
|
|
1483
|
+
Selector `0x3edc6b12` · Caller: Anyone (view) · Source: `EpochEntropy.sol` lines 304–308, 309–313
|
|
1484
|
+
|
|
1485
|
+
Number of slots in the catalog in force for an epoch, and so the number of selection attempts, 0 to count - 1.
|
|
1486
|
+
|
|
1487
|
+
#### <a id="registry-fn-getrecipe"></a>`getRecipe`
|
|
1488
|
+
|
|
1489
|
+
```solidity
|
|
1490
|
+
function getRecipe(uint8 recipe) external view returns (bytes32 queryHash, string canonicalRequest, bytes template, string body)
|
|
1491
|
+
```
|
|
1492
|
+
|
|
1493
|
+
Selector `0xba01b103` · Caller: Anyone (view) · Source: `EpochEntropy.sol` lines 150–154, 157–160
|
|
1494
|
+
|
|
1495
|
+
A registered recipe: `queryHash` (`keccak256` of `canonicalRequest`), the canonical request its signer signs, the data template its signed data must match and the body keepers send: the JSON they post to the provider gateway, or for a beacon recipe its canonical request. Registered recipes never change. `readEpochRecipes` in `@d20dao/vrf-sdk/epoch` reads recipes with this view, checks each query hash and adds the registration of a beacon recipe from `beaconOf`.
|
|
1496
|
+
|
|
1497
|
+
**Errors:** [`InvalidConfig`](#registry-error-invalidconfig).
|
|
1498
|
+
|
|
1499
|
+
#### <a id="registry-fn-beaconof"></a>`beaconOf`
|
|
1443
1500
|
|
|
1444
1501
|
```solidity
|
|
1445
|
-
function
|
|
1502
|
+
function beaconOf(uint8 recipe) external view returns (EpochEntropy.Beacon)
|
|
1446
1503
|
```
|
|
1447
1504
|
|
|
1448
|
-
Selector `
|
|
1505
|
+
Selector `0x87533a48` · Caller: Anyone (view) · Source: `EpochEntropy.sol` lines 188–192
|
|
1449
1506
|
|
|
1450
|
-
|
|
1507
|
+
The registration of a recipe as an [`EpochEntropy.Beacon`](#registry-type-epochentropy-beacon): verifier, genesis, period, chain hash and public key. A signed API recipe returns all zero. Replay of a beacon epoch needs this registration, and `readEpochRecipes` reads it for every recipe whose canonical request names drand.
|
|
1451
1508
|
|
|
1452
|
-
|
|
1509
|
+
**Errors:** [`InvalidConfig`](#registry-error-invalidconfig).
|
|
1510
|
+
|
|
1511
|
+
#### <a id="registry-fn-slotsigner"></a>`slotSigner`
|
|
1453
1512
|
|
|
1454
1513
|
```solidity
|
|
1455
|
-
function
|
|
1514
|
+
function slotSigner(uint8 recipe) external view returns (address)
|
|
1456
1515
|
```
|
|
1457
1516
|
|
|
1458
|
-
Selector `
|
|
1517
|
+
Selector `0xb42be3c1` · Caller: Anyone (view) · Source: `EpochEntropy.sol` lines 193–199
|
|
1518
|
+
|
|
1519
|
+
The signer a catalog lists for a beacon recipe: the low 160 bits of `keccak256(abi.encode(BEACON_DOMAIN, verifier, chainHash, keccak256(publicKey), genesis, period))`, an identity derived from the registration and not a key. Zero for a signed API recipe and for an id that is not registered. `scheduleCatalog` requires it as the signer of a beacon slot; `beaconSlotSigner` in `@d20dao/vrf-sdk` computes it off-chain.
|
|
1459
1520
|
|
|
1460
|
-
|
|
1521
|
+
#### <a id="registry-fn-verifybeacon"></a>`verifyBeacon`
|
|
1522
|
+
|
|
1523
|
+
```solidity
|
|
1524
|
+
function verifyBeacon(uint8 recipe, uint64 round, bytes signature) external view returns (bool)
|
|
1525
|
+
```
|
|
1526
|
+
|
|
1527
|
+
Selector `0x0ccd9ab2` · Caller: Anyone (view) · Source: `EpochEntropy.sol` lines 200–209
|
|
1528
|
+
|
|
1529
|
+
Whether `signature` is the valid signature of `round` for a beacon recipe, checked the way a publication checks it: the recipe's verifier is called with a fixed allowance of `BEACON_VERIFY_GAS` and only an exact `true` counts. False for a signed API recipe and for an id that is not registered. For a beacon recipe it reverts `BeaconGasTooLow`, and never answers false, when the gas of the call cannot give the verifier its whole allowance; an `eth_call` needs about 461,000 gas.
|
|
1530
|
+
|
|
1531
|
+
**Errors:** [`BeaconGasTooLow`](#registry-error-beacongastoolow).
|
|
1532
|
+
|
|
1533
|
+
#### <a id="registry-fn-reciperequest"></a>`recipeRequest`
|
|
1534
|
+
|
|
1535
|
+
```solidity
|
|
1536
|
+
function recipeRequest(uint8 recipe) external view returns (string)
|
|
1537
|
+
```
|
|
1538
|
+
|
|
1539
|
+
Selector `0x7ce4b6e0` · Caller: Anyone (view) · Source: `EpochEntropy.sol` lines 155–160
|
|
1540
|
+
|
|
1541
|
+
Canonical request of a registered recipe, the same string `getRecipe` returns.
|
|
1542
|
+
|
|
1543
|
+
**Errors:** [`InvalidConfig`](#registry-error-invalidconfig).
|
|
1544
|
+
|
|
1545
|
+
#### <a id="registry-fn-recipecount"></a>`recipeCount`
|
|
1546
|
+
|
|
1547
|
+
```solidity
|
|
1548
|
+
function recipeCount() external view returns (uint256)
|
|
1549
|
+
```
|
|
1550
|
+
|
|
1551
|
+
Selector `0x69cfdf74` · Caller: Anyone (view) · Source: `EpochEntropy.sol` line 149
|
|
1552
|
+
|
|
1553
|
+
Number of registered recipes; ids run from 0 to `recipeCount() - 1`.
|
|
1461
1554
|
|
|
1462
1555
|
### <a id="registry-registry-reads"></a>Registry reads
|
|
1463
1556
|
|
|
@@ -1465,18 +1558,21 @@ Views, callable by anyone.
|
|
|
1465
1558
|
|
|
1466
1559
|
| Function | Selector | Meaning | Source |
|
|
1467
1560
|
| --- | --- | --- | --- |
|
|
1468
|
-
| <a id="registry-fn-firstepochstart"></a>`firstEpochStart() returns (uint64)` | `0x219f2428` | First block of epoch 1: the initialization block plus 200. | lines
|
|
1469
|
-
| <a id="registry-fn-committer"></a>`committer() returns (address)` | `0x5bc8e8f9` |
|
|
1470
|
-
| <a id="registry-fn-
|
|
1471
|
-
| <a id="registry-fn-
|
|
1472
|
-
| <a id="registry-fn-
|
|
1473
|
-
| <a id="registry-fn-
|
|
1474
|
-
| <a id="registry-fn-
|
|
1475
|
-
| <a id="registry-fn-
|
|
1561
|
+
| <a id="registry-fn-firstepochstart"></a>`firstEpochStart() returns (uint64)` | `0x219f2428` | First block of epoch 1: the initialization block plus 200. | lines 52, 101 |
|
|
1562
|
+
| <a id="registry-fn-committer"></a>`committer() returns (address)` | `0x5bc8e8f9` | Primary publishing address. The coordinator pays it the keeper share of the requests it serves itself and of every request whose proof came from a wallet this registry does not authorize. | lines 51, 364 |
|
|
1563
|
+
| <a id="registry-fn-isbackupcommitter"></a>`isBackupCommitter(address account) returns (bool)` | `0x1d97e417` | Whether an address may publish epochs besides `committer()`. | line 136 |
|
|
1564
|
+
| <a id="registry-fn-isauthorizedcommitter"></a>`isAuthorizedCommitter(address account) returns (bool)` | `0x1579ab83` | Whether an address may publish epochs at all: `committer()` or an allowed backup committer. The coordinator reads it to decide whether a proof submitter earns the keeper share. | lines 137–139 |
|
|
1565
|
+
| <a id="registry-fn-backupcommittercount"></a>`backupCommitterCount() returns (uint256)` | `0xa815c5bf` | Number of allowed backup committers, at most `MAX_BACKUP_COMMITTERS`. | lines 78, 125–135 |
|
|
1566
|
+
| <a id="registry-fn-cataloghash"></a>`catalogHash() returns (bytes32)` | `0x830c083a` | Initial catalog hash, bound into `protocolConfigurationHash`. Never changes; `catalogAt` gives the catalog of an epoch. | lines 53, 102 |
|
|
1567
|
+
| <a id="registry-fn-epochanchors"></a>`epochAnchors(uint64) returns (bytes32)` | `0x48a030fb` | Checkpointed anchor of an epoch (hash of block `epochStart - 1`); zero until a request, `checkpointEpoch` or publication stores it. | lines 68, 324–327 |
|
|
1568
|
+
| <a id="registry-fn-hyperliquidsigner"></a>`hyperliquidSigner() returns (address)` | `0xf2a12563` | Initial-catalog signer of slot 0 (recipe 0, Hyperliquid BTC volume). Never changes; see `catalogAt`. | line 46 |
|
|
1569
|
+
| <a id="registry-fn-ethereumblocksigner"></a>`ethereumBlockSigner() returns (address)` | `0xd25eacfc` | Initial-catalog signer of slot 1 (recipe 1, Ethereum block hash). Never changes; see `catalogAt`. | lines 47–48 |
|
|
1570
|
+
| <a id="registry-fn-btctradesigner"></a>`btcTradeSigner() returns (address)` | `0xb3b9cbb0` | Initial-catalog signer of slot 2 (recipe 2, TickerLayer BTCUSD). Never changes; see `catalogAt`. | line 49 |
|
|
1571
|
+
| <a id="registry-fn-ethtradesigner"></a>`ethTradeSigner() returns (address)` | `0x3a700168` | Initial-catalog signer of slot 3 (recipe 3, TickerLayer ETHUSD). Never changes; see `catalogAt`. | line 50 |
|
|
1476
1572
|
|
|
1477
1573
|
### <a id="registry-source-selection-and-publication"></a>Source selection and publication
|
|
1478
1574
|
|
|
1479
|
-
Used by
|
|
1575
|
+
Used by keepers. Publication is restricted to the committer and backup committers; the selection views and `checkpointEpoch` are open to anyone.
|
|
1480
1576
|
|
|
1481
1577
|
#### <a id="registry-fn-getepochselection"></a>`getEpochSelection`
|
|
1482
1578
|
|
|
@@ -1484,11 +1580,11 @@ Used by the keeper. Publication is restricted to the committer; the selection vi
|
|
|
1484
1580
|
function getEpochSelection(uint64 epochId) external view returns (EpochEntropy.Selection s)
|
|
1485
1581
|
```
|
|
1486
1582
|
|
|
1487
|
-
Selector `0xec4960ad` · Caller: Anyone (view) · Source: `EpochEntropy.sol` lines
|
|
1583
|
+
Selector `0xec4960ad` · Caller: Anyone (view) · Source: `EpochEntropy.sol` lines 336, 345–356
|
|
1488
1584
|
|
|
1489
1585
|
The selected source of an epoch, attempt 0, as an [`EpochEntropy.Selection`](#registry-type-epochentropy-selection).
|
|
1490
1586
|
|
|
1491
|
-
**Errors:** [`InvalidEpoch`](#registry-error-invalidepoch), [`PreparationClosed`](#registry-error-preparationclosed), [`AnchorUnavailable`](#registry-error-anchorunavailable).
|
|
1587
|
+
**Errors:** [`InvalidEpoch`](#registry-error-invalidepoch), [`PreparationClosed`](#registry-error-preparationclosed), [`AnchorUnavailable`](#registry-error-anchorunavailable), [`InvalidConfig`](#registry-error-invalidconfig).
|
|
1492
1588
|
|
|
1493
1589
|
#### <a id="registry-fn-getepochfallbackselection"></a>`getEpochFallbackSelection`
|
|
1494
1590
|
|
|
@@ -1496,11 +1592,11 @@ The selected source of an epoch, attempt 0, as an [`EpochEntropy.Selection`](#re
|
|
|
1496
1592
|
function getEpochFallbackSelection(uint64 epochId, uint8 attempt) external view returns (EpochEntropy.Selection s)
|
|
1497
1593
|
```
|
|
1498
1594
|
|
|
1499
|
-
Selector `0x0e5a0e02` · Caller: Anyone (view) · Source: `EpochEntropy.sol` lines
|
|
1595
|
+
Selector `0x0e5a0e02` · Caller: Anyone (view) · Source: `EpochEntropy.sol` lines 337–338, 345–356
|
|
1500
1596
|
|
|
1501
|
-
The source for attempt 0 to `
|
|
1597
|
+
The source for attempt 0 to `sourceCountAt(epochId) - 1`; attempt n uses the slot n positions after the selected one.
|
|
1502
1598
|
|
|
1503
|
-
**Errors:** [`InvalidFallback`](#registry-error-invalidfallback), [`InvalidEpoch`](#registry-error-invalidepoch), [`PreparationClosed`](#registry-error-preparationclosed), [`AnchorUnavailable`](#registry-error-anchorunavailable).
|
|
1599
|
+
**Errors:** [`InvalidFallback`](#registry-error-invalidfallback), [`InvalidEpoch`](#registry-error-invalidepoch), [`PreparationClosed`](#registry-error-preparationclosed), [`AnchorUnavailable`](#registry-error-anchorunavailable), [`InvalidConfig`](#registry-error-invalidconfig).
|
|
1504
1600
|
|
|
1505
1601
|
#### <a id="registry-fn-fallbackopensat"></a>`fallbackOpensAt`
|
|
1506
1602
|
|
|
@@ -1508,9 +1604,9 @@ The source for attempt 0 to `MAX_FALLBACK_ATTEMPT` (3); attempt n uses the slot
|
|
|
1508
1604
|
function fallbackOpensAt(uint64 epochId, uint8 attempt) external view returns (uint64)
|
|
1509
1605
|
```
|
|
1510
1606
|
|
|
1511
|
-
Selector `0x98208050` · Caller: Anyone (view) · Source: `EpochEntropy.sol` lines
|
|
1607
|
+
Selector `0x98208050` · Caller: Anyone (view) · Source: `EpochEntropy.sol` lines 339–343
|
|
1512
1608
|
|
|
1513
|
-
First block at which an attempt may be published: `epochStart + attempt × FALLBACK_DELAY_BLOCKS` (20).
|
|
1609
|
+
First block at which an attempt may be published: `epochStart + attempt × FALLBACK_DELAY_BLOCKS` (20). With at most `MAX_SOURCES` (10) slots the last window opens 180 blocks into the epoch.
|
|
1514
1610
|
|
|
1515
1611
|
**Errors:** [`InvalidFallback`](#registry-error-invalidfallback), [`InvalidEpoch`](#registry-error-invalidepoch).
|
|
1516
1612
|
|
|
@@ -1520,7 +1616,7 @@ First block at which an attempt may be published: `epochStart + attempt × FALLB
|
|
|
1520
1616
|
function nextEpochToPrepare(uint256 number) external view returns (uint64)
|
|
1521
1617
|
```
|
|
1522
1618
|
|
|
1523
|
-
Selector `0xc78fafe2` · Caller: Anyone (view) · Source: `EpochEntropy.sol` line
|
|
1619
|
+
Selector `0xc78fafe2` · Caller: Anyone (view) · Source: `EpochEntropy.sol` line 321
|
|
1524
1620
|
|
|
1525
1621
|
Same value as `epochForBlock(number)`.
|
|
1526
1622
|
|
|
@@ -1530,7 +1626,7 @@ Same value as `epochForBlock(number)`.
|
|
|
1530
1626
|
function checkpointEpoch(uint64 epochId) external returns (bytes32 anchor)
|
|
1531
1627
|
```
|
|
1532
1628
|
|
|
1533
|
-
Selector `0x16de78cb` · Caller: Anyone · Source: `EpochEntropy.sol` lines
|
|
1629
|
+
Selector `0x16de78cb` · Caller: Anyone · Source: `EpochEntropy.sol` lines 322–327, 328–334
|
|
1534
1630
|
|
|
1535
1631
|
Stores the anchor of a started epoch (hash of block `epochStart - 1`) if not stored yet, and returns it. The coordinator calls it on every request, so the anchor of an epoch with requests survives the 256-block `BLOCKHASH` window.
|
|
1536
1632
|
|
|
@@ -1542,13 +1638,13 @@ Stores the anchor of a started epoch (hash of block `epochStart - 1`) if not sto
|
|
|
1542
1638
|
function commitEpoch(uint64 epochId, EpochEntropy.Attestation a) external
|
|
1543
1639
|
```
|
|
1544
1640
|
|
|
1545
|
-
Selector `0xb1580277` · Caller: Committer · Source: `EpochEntropy.sol` lines
|
|
1641
|
+
Selector `0xb1580277` · Caller: Committer or backup committer · Source: `EpochEntropy.sol` lines 357, 363–391
|
|
1546
1642
|
|
|
1547
|
-
Publishes the packet of the selected source once per epoch, from the epoch start: checks that the attestation is not future-dated and at most 240 seconds old
|
|
1643
|
+
Publishes the packet of the selected source once per epoch, from the epoch start: checks that the attestation is not future-dated and at most 240 seconds old and that its data matches the data template of the slot's recipe exactly, then checks its signature. For a signed API recipe the slot's signer in the epoch's catalog must have signed it. For a beacon recipe the timestamp must be the scheduled time of the round in the data, and the verifier of its registration must accept the signature of that round within `BEACON_VERIFY_GAS`; the call reverts `BeaconGasTooLow` when the gas left cannot give the verifier that allowance. Stores the record and emits the packet. Publishing earns nothing by itself: the keeper share of each request goes to the authorized wallet that submits its accepted proof, or to `committer()` when the submitter is not authorized.
|
|
1548
1644
|
|
|
1549
1645
|
**Emits:** [`EpochCommitted`](#registry-event-epochcommitted).
|
|
1550
1646
|
|
|
1551
|
-
**Errors:** [`OnlyCommitter`](#registry-error-onlycommitter), [`AlreadyCommitted`](#registry-error-alreadycommitted), [`InvalidEpoch`](#registry-error-invalidepoch), [`FallbackNotOpen`](#registry-error-fallbacknotopen), [`AnchorUnavailable`](#registry-error-anchorunavailable), [`InvalidTime`](#registry-error-invalidtime), [`InvalidData`](#registry-error-invaliddata), [`ECDSAInvalidSignatureLength`](#registry-error-ecdsainvalidsignaturelength), [`ECDSAInvalidSignatureS`](#registry-error-ecdsainvalidsignatures), [`ECDSAInvalidSignature`](#registry-error-ecdsainvalidsignature), [`InvalidSigner`](#registry-error-invalidsigner), [`PacketTooLarge`](#registry-error-packettoolarge).
|
|
1647
|
+
**Errors:** [`OnlyCommitter`](#registry-error-onlycommitter), [`AlreadyCommitted`](#registry-error-alreadycommitted), [`InvalidEpoch`](#registry-error-invalidepoch), [`FallbackNotOpen`](#registry-error-fallbacknotopen), [`AnchorUnavailable`](#registry-error-anchorunavailable), [`InvalidConfig`](#registry-error-invalidconfig), [`InvalidTime`](#registry-error-invalidtime), [`InvalidData`](#registry-error-invaliddata), [`ECDSAInvalidSignatureLength`](#registry-error-ecdsainvalidsignaturelength), [`ECDSAInvalidSignatureS`](#registry-error-ecdsainvalidsignatures), [`ECDSAInvalidSignature`](#registry-error-ecdsainvalidsignature), [`InvalidSigner`](#registry-error-invalidsigner), [`BeaconGasTooLow`](#registry-error-beacongastoolow), [`PacketTooLarge`](#registry-error-packettoolarge).
|
|
1552
1648
|
|
|
1553
1649
|
#### <a id="registry-fn-commitepochfallback"></a>`commitEpochFallback`
|
|
1554
1650
|
|
|
@@ -1556,13 +1652,73 @@ Publishes the packet of the selected source once per epoch, from the epoch start
|
|
|
1556
1652
|
function commitEpochFallback(uint64 epochId, uint8 attempt, EpochEntropy.Attestation a) external
|
|
1557
1653
|
```
|
|
1558
1654
|
|
|
1559
|
-
Selector `0x5768d9a1` · Caller: Committer · Source: `EpochEntropy.sol` lines
|
|
1655
|
+
Selector `0x5768d9a1` · Caller: Committer or backup committer · Source: `EpochEntropy.sol` lines 358–362, 363–391
|
|
1560
1656
|
|
|
1561
|
-
Publishes fallback attempt 1 to
|
|
1657
|
+
Publishes fallback attempt 1 to `sourceCountAt(epochId) - 1`, using the slot `attempt` positions after the selected source, once `fallbackOpensAt(epochId, attempt)` is reached. Same checks as `commitEpoch`.
|
|
1562
1658
|
|
|
1563
1659
|
**Emits:** [`EpochCommitted`](#registry-event-epochcommitted).
|
|
1564
1660
|
|
|
1565
|
-
**Errors:** [`InvalidFallback`](#registry-error-invalidfallback), [`OnlyCommitter`](#registry-error-onlycommitter), [`AlreadyCommitted`](#registry-error-alreadycommitted), [`InvalidEpoch`](#registry-error-invalidepoch), [`FallbackNotOpen`](#registry-error-fallbacknotopen), [`AnchorUnavailable`](#registry-error-anchorunavailable), [`InvalidTime`](#registry-error-invalidtime), [`InvalidData`](#registry-error-invaliddata), [`ECDSAInvalidSignatureLength`](#registry-error-ecdsainvalidsignaturelength), [`ECDSAInvalidSignatureS`](#registry-error-ecdsainvalidsignatures), [`ECDSAInvalidSignature`](#registry-error-ecdsainvalidsignature), [`InvalidSigner`](#registry-error-invalidsigner), [`PacketTooLarge`](#registry-error-packettoolarge).
|
|
1661
|
+
**Errors:** [`InvalidFallback`](#registry-error-invalidfallback), [`OnlyCommitter`](#registry-error-onlycommitter), [`AlreadyCommitted`](#registry-error-alreadycommitted), [`InvalidEpoch`](#registry-error-invalidepoch), [`FallbackNotOpen`](#registry-error-fallbacknotopen), [`AnchorUnavailable`](#registry-error-anchorunavailable), [`InvalidConfig`](#registry-error-invalidconfig), [`InvalidTime`](#registry-error-invalidtime), [`InvalidData`](#registry-error-invaliddata), [`ECDSAInvalidSignatureLength`](#registry-error-ecdsainvalidsignaturelength), [`ECDSAInvalidSignatureS`](#registry-error-ecdsainvalidsignatures), [`ECDSAInvalidSignature`](#registry-error-ecdsainvalidsignature), [`InvalidSigner`](#registry-error-invalidsigner), [`BeaconGasTooLow`](#registry-error-beacongastoolow), [`PacketTooLarge`](#registry-error-packettoolarge).
|
|
1662
|
+
|
|
1663
|
+
### <a id="registry-recipes-and-catalogs"></a>Recipes and catalogs
|
|
1664
|
+
|
|
1665
|
+
Owner-only; on Arc Mainnet the owner is the DAO treasury Safe. A recipe or catalog never changes a published epoch.
|
|
1666
|
+
|
|
1667
|
+
#### <a id="registry-fn-registerrecipe"></a>`registerRecipe`
|
|
1668
|
+
|
|
1669
|
+
```solidity
|
|
1670
|
+
function registerRecipe(string canonicalRequest, bytes template, string body) external returns (uint8 recipe)
|
|
1671
|
+
```
|
|
1672
|
+
|
|
1673
|
+
Selector `0x5add5c50` · Caller: Owner · Source: `EpochEntropy.sol` lines 141–148, 161–170
|
|
1674
|
+
|
|
1675
|
+
Appends an immutable recipe and returns its id, the next index. The canonical request is 1 to `MAX_REQUEST_BYTES` (1024) bytes, the body 1 to `MAX_BODY_BYTES` (2048) bytes, and the template must be a well-formed data template of at most `MAX_TEMPLATE_BYTES` (256) bytes; at most `MAX_RECIPES` (256) recipes exist. The contract does not check that the body canonicalizes to the request; keepers refuse a recipe whose body does not. A changed listing is registered as a new id.
|
|
1676
|
+
|
|
1677
|
+
**Emits:** [`RecipeRegistered`](#registry-event-reciperegistered).
|
|
1678
|
+
|
|
1679
|
+
**Errors:** [`OwnableUnauthorizedAccount`](#registry-error-ownableunauthorizedaccount), [`InvalidRecipe`](#registry-error-invalidrecipe), [`InvalidTemplate`](#registry-error-invalidtemplate).
|
|
1680
|
+
|
|
1681
|
+
#### <a id="registry-fn-registerbeacon"></a>`registerBeacon`
|
|
1682
|
+
|
|
1683
|
+
```solidity
|
|
1684
|
+
function registerBeacon(address verifier, bytes32 chainHash, bytes publicKey, uint64 genesis, uint64 period, uint64 sampleRound, bytes sampleSignature) external returns (uint8 recipe)
|
|
1685
|
+
```
|
|
1686
|
+
|
|
1687
|
+
Selector `0x65afb221` · Caller: Owner · Source: `EpochEntropy.sol` lines 171–187
|
|
1688
|
+
|
|
1689
|
+
Appends a public randomness beacon as an immutable recipe and returns its id. Its canonical request, which is also its body, is `["drand","<chainHash>"]` with the hash in lowercase hex, and its template accepts one round number: 1 to 19 decimal digits without a leading zero. An epoch it serves commits round `r` as the data, the round's scheduled time `genesis + (r - 1) × period` as the timestamp and the beacon's signature of the round, which `verifier` checks under `publicKey`. Reverts `InvalidConfig` for a verifier without code, a zero `chainHash`, `genesis`, `period` or `sampleRound`, a `sampleRound` not yet scheduled, a key the verifier does not accept, or a `sampleSignature` of `sampleRound` it rejects, so that a malformed key or a verifier that misbehaves or needs more gas cannot register. The registration, like the recipe, never changes.
|
|
1690
|
+
|
|
1691
|
+
**Emits:** [`RecipeRegistered`](#registry-event-reciperegistered), [`BeaconRegistered`](#registry-event-beaconregistered).
|
|
1692
|
+
|
|
1693
|
+
**Errors:** [`OwnableUnauthorizedAccount`](#registry-error-ownableunauthorizedaccount), [`InvalidConfig`](#registry-error-invalidconfig), [`BeaconGasTooLow`](#registry-error-beacongastoolow), [`InvalidRecipe`](#registry-error-invalidrecipe).
|
|
1694
|
+
|
|
1695
|
+
#### <a id="registry-fn-schedulecatalog"></a>`scheduleCatalog`
|
|
1696
|
+
|
|
1697
|
+
```solidity
|
|
1698
|
+
function scheduleCatalog(uint8[] recipes, address[] signers, uint64 fromEpoch) external
|
|
1699
|
+
```
|
|
1700
|
+
|
|
1701
|
+
Selector `0x42984450` · Caller: Owner · Source: `EpochEntropy.sol` lines 268–294
|
|
1702
|
+
|
|
1703
|
+
Schedules a catalog for epochs from `fromEpoch`, which must be at least two epochs after the current one: 1 to `MAX_SOURCES` (10) distinct registered recipe ids with one non-zero signer each, in slot order; the signer of a beacon recipe must be its `slotSigner`. Its hash is `keccak256(abi.encode(RECIPE_DOMAIN, recipes, signers))`. A pending version, one whose `fromEpoch` is two or more epochs after the current one, is replaced, so that version never applies. The version that takes effect at the next epoch is kept, as is every active one, because the next epoch's catalog is already fixed: its snapshot may be prepared and its requests open. The current epoch keeps its catalog.
|
|
1704
|
+
|
|
1705
|
+
**Emits:** [`CatalogScheduled`](#registry-event-catalogscheduled).
|
|
1706
|
+
|
|
1707
|
+
**Errors:** [`OwnableUnauthorizedAccount`](#registry-error-ownableunauthorizedaccount), [`InvalidConfig`](#registry-error-invalidconfig), [`InvalidEpoch`](#registry-error-invalidepoch).
|
|
1708
|
+
|
|
1709
|
+
#### <a id="registry-fn-initializereciperegistry"></a>`initializeRecipeRegistry`
|
|
1710
|
+
|
|
1711
|
+
```solidity
|
|
1712
|
+
function initializeRecipeRegistry() external
|
|
1713
|
+
```
|
|
1714
|
+
|
|
1715
|
+
Selector `0x8700b456` · Caller: Owner, once per proxy, as the `upgradeToAndCall` data of the recipe-registry upgrade · Source: `EpochEntropy.sol` lines 105–113
|
|
1716
|
+
|
|
1717
|
+
Registers built-in recipes 0 to 5 on a registry initialized before the recipe registry, whose initial catalog selects recipes 0 to 3. It runs once per proxy (reinitializer version 2) and refuses a registry that already has recipes, which includes every registry initialized by this implementation, or a catalog scheduled under the earlier hardcoded recipe ids.
|
|
1718
|
+
|
|
1719
|
+
**Emits:** [`RecipeRegistered`](#registry-event-reciperegistered), [`Initialized`](#registry-event-initialized).
|
|
1720
|
+
|
|
1721
|
+
**Errors:** [`InvalidInitialization`](#registry-error-invalidinitialization), [`OwnableUnauthorizedAccount`](#registry-error-ownableunauthorizedaccount), [`InvalidConfig`](#registry-error-invalidconfig).
|
|
1566
1722
|
|
|
1567
1723
|
### <a id="registry-owner-administration"></a>Owner administration
|
|
1568
1724
|
|
|
@@ -1574,27 +1730,27 @@ Owner-only functions revert `OwnableUnauthorizedAccount` for anyone else. No set
|
|
|
1574
1730
|
function setCommitter(address next) external
|
|
1575
1731
|
```
|
|
1576
1732
|
|
|
1577
|
-
Selector `0xdd51ce22` · Caller: Owner · Source: `EpochEntropy.sol` lines
|
|
1733
|
+
Selector `0xdd51ce22` · Caller: Owner · Source: `EpochEntropy.sol` lines 118–121
|
|
1578
1734
|
|
|
1579
|
-
Changes the publishing address, which is also the keeper-share recipient the coordinator reads at each acceptance.
|
|
1735
|
+
Changes the primary publishing address, which is also the keeper-share recipient the coordinator reads at each acceptance.
|
|
1580
1736
|
|
|
1581
1737
|
**Emits:** [`CommitterChanged`](#registry-event-committerchanged).
|
|
1582
1738
|
|
|
1583
1739
|
**Errors:** [`OwnableUnauthorizedAccount`](#registry-error-ownableunauthorizedaccount), [`InvalidConfig`](#registry-error-invalidconfig).
|
|
1584
1740
|
|
|
1585
|
-
#### <a id="registry-fn-
|
|
1741
|
+
#### <a id="registry-fn-setbackupcommitter"></a>`setBackupCommitter`
|
|
1586
1742
|
|
|
1587
1743
|
```solidity
|
|
1588
|
-
function
|
|
1744
|
+
function setBackupCommitter(address account, bool allowed) external
|
|
1589
1745
|
```
|
|
1590
1746
|
|
|
1591
|
-
Selector `
|
|
1747
|
+
Selector `0xd870d0c6` · Caller: Owner · Source: `EpochEntropy.sol` lines 122–135
|
|
1592
1748
|
|
|
1593
|
-
|
|
1749
|
+
Allows or removes a backup committer: a separate wallet that may call `commitEpoch` and `commitEpochFallback` under exactly the committer's rules, for example a follower keeper that takes over while the primary keeper is down. It has no other role, and the coordinator pays it the keeper share of the requests whose accepted proofs it submits itself. Reverts for the zero address, for allowing the current committer, for a call that does not change the address's status, and for more than `MAX_BACKUP_COMMITTERS` (4).
|
|
1594
1750
|
|
|
1595
|
-
**Emits:** [`
|
|
1751
|
+
**Emits:** [`BackupCommitterSet`](#registry-event-backupcommitterset).
|
|
1596
1752
|
|
|
1597
|
-
**Errors:** [`OwnableUnauthorizedAccount`](#registry-error-ownableunauthorizedaccount), [`InvalidConfig`](#registry-error-invalidconfig)
|
|
1753
|
+
**Errors:** [`OwnableUnauthorizedAccount`](#registry-error-ownableunauthorizedaccount), [`InvalidConfig`](#registry-error-invalidconfig).
|
|
1598
1754
|
|
|
1599
1755
|
#### <a id="registry-fn-owner"></a>`owner`
|
|
1600
1756
|
|
|
@@ -1650,7 +1806,7 @@ Completes the transfer to the caller and clears the nomination.
|
|
|
1650
1806
|
function renounceOwnership() external view
|
|
1651
1807
|
```
|
|
1652
1808
|
|
|
1653
|
-
Selector `0x715018a6` · Caller: Owner · Source: `EpochEntropy.sol` lines
|
|
1809
|
+
Selector `0x715018a6` · Caller: Owner · Source: `EpochEntropy.sol` lines 115–116
|
|
1654
1810
|
|
|
1655
1811
|
Disabled and declared `view`: the owner gets `RenounceDisabled` and anyone else `OwnableUnauthorizedAccount`, so the contract always has an owner and upgrade authority can only move through an accepted transfer.
|
|
1656
1812
|
|
|
@@ -1688,11 +1844,11 @@ ERC-1822 check used by `upgradeToAndCall`. Returns the ERC-1967 implementation s
|
|
|
1688
1844
|
function initialize(address[4] signers, address initialOwner, address initialCommitter) external
|
|
1689
1845
|
```
|
|
1690
1846
|
|
|
1691
|
-
Selector `0xfda9f5ca` · Caller: Once, by `D20Proxy` at deployment · Source: `EpochEntropy.sol` lines
|
|
1847
|
+
Selector `0xfda9f5ca` · Caller: Once, by `D20Proxy` at deployment · Source: `EpochEntropy.sol` lines 96–104
|
|
1692
1848
|
|
|
1693
|
-
Sets the four initial signers, owner and committer. Epoch 1 starts 200 blocks after the initialization block.
|
|
1849
|
+
Sets the four initial-catalog signers of recipes 0 to 3, the owner and the committer, and registers built-in recipes 0 to 5. Epoch 1 starts 200 blocks after the initialization block.
|
|
1694
1850
|
|
|
1695
|
-
**Emits:** [`OwnershipTransferred`](#registry-event-ownershiptransferred), [`Initialized`](#registry-event-initialized).
|
|
1851
|
+
**Emits:** [`OwnershipTransferred`](#registry-event-ownershiptransferred), [`RecipeRegistered`](#registry-event-reciperegistered), [`Initialized`](#registry-event-initialized).
|
|
1696
1852
|
|
|
1697
1853
|
**Errors:** [`InvalidInitialization`](#registry-error-invalidinitialization), [`OwnableInvalidOwner`](#registry-error-ownableinvalidowner), [`InvalidConfig`](#registry-error-invalidconfig).
|
|
1698
1854
|
|
|
@@ -1706,15 +1862,23 @@ Views returning values fixed in the implementation code.
|
|
|
1706
1862
|
| <a id="registry-fn-max_attestation_age"></a>`MAX_ATTESTATION_AGE` | `uint256` | `240 seconds` | `0xb9f7bb8d` | Oldest attestation accepted at publication, in seconds; also exported by `@d20dao/vrf-sdk/epoch`. |
|
|
1707
1863
|
| <a id="registry-fn-max_packet_bytes"></a>`MAX_PACKET_BYTES` | `uint256` | `2048` | `0x48cad11b` | Upper bound on the `EpochCommitted` packet. |
|
|
1708
1864
|
| <a id="registry-fn-fallback_delay_blocks"></a>`FALLBACK_DELAY_BLOCKS` | `uint64` | `20` | `0x0a48a95d` | Blocks between fallback windows. |
|
|
1709
|
-
| <a id="registry-fn-
|
|
1865
|
+
| <a id="registry-fn-max_sources"></a>`MAX_SOURCES` | `uint256` | `10` | `0x64aefc06` | Most slots in a catalog. |
|
|
1866
|
+
| <a id="registry-fn-max_recipes"></a>`MAX_RECIPES` | `uint256` | `256` | `0x0c148333` | Most registered recipes; ids are `uint8`. |
|
|
1867
|
+
| <a id="registry-fn-max_request_bytes"></a>`MAX_REQUEST_BYTES` | `uint256` | `1024` | `0x4b62e5b4` | Longest canonical request of a recipe. |
|
|
1868
|
+
| <a id="registry-fn-max_body_bytes"></a>`MAX_BODY_BYTES` | `uint256` | `2048` | `0x2ade18c2` | Longest gateway request body of a recipe. |
|
|
1869
|
+
| <a id="registry-fn-max_data_bytes"></a>`MAX_DATA_BYTES` | `uint256` | `128` | `0xf1d11a6c` | Longest signed data a template accepts. |
|
|
1870
|
+
| <a id="registry-fn-max_template_bytes"></a>`MAX_TEMPLATE_BYTES` | `uint256` | `256` | `0x30a3bee5` | Longest data template. |
|
|
1871
|
+
| <a id="registry-fn-max_backup_committers"></a>`MAX_BACKUP_COMMITTERS` | `uint256` | `4` | `0xc195af66` | Most backup committers allowed at once. |
|
|
1710
1872
|
| <a id="registry-fn-recipe_domain"></a>`RECIPE_DOMAIN` | `bytes32` | `keccak256("D20_EPOCH_RECIPES")` | `0xacea73c8` | Domain tag of catalog hashes. |
|
|
1711
1873
|
| <a id="registry-fn-select_domain"></a>`SELECT_DOMAIN` | `bytes32` | `keccak256("D20_EPOCH_SELECT")` | `0x10181587` | Domain tag of the source selector. |
|
|
1712
1874
|
| <a id="registry-fn-epoch_domain"></a>`EPOCH_DOMAIN` | `bytes32` | `keccak256("D20_EPOCH")` | `0xbece738c` | Domain tag of the epoch commitment. |
|
|
1875
|
+
| <a id="registry-fn-beacon_domain"></a>`BEACON_DOMAIN` | `bytes32` | `keccak256("D20_EPOCH_BEACON")` | `0x11083512` | Domain tag of `slotSigner`. |
|
|
1876
|
+
| <a id="registry-fn-beacon_verify_gas"></a>`BEACON_VERIFY_GAS` | `uint256` | `400_000` | `0x92c32ece` | Gas a beacon verifier gets for one round; `D20BeaconVerifier` uses about 175,000 of it. A call that cannot leave the verifier this much reverts `BeaconGasTooLow`. |
|
|
1713
1877
|
| <a id="registry-fn-upgrade_interface_version"></a>`UPGRADE_INTERFACE_VERSION` | `string` | `"5.0.0"` | `0xad3cb1cc` | OpenZeppelin UUPS interface version: upgrades go through `upgradeToAndCall` only. |
|
|
1714
1878
|
|
|
1715
1879
|
### <a id="registry-events"></a>Events
|
|
1716
1880
|
|
|
1717
|
-
**Epochs**
|
|
1881
|
+
**Epochs, recipes and catalogs**
|
|
1718
1882
|
|
|
1719
1883
|
#### <a id="registry-event-epochcommitted"></a>`EpochCommitted`
|
|
1720
1884
|
|
|
@@ -1722,19 +1886,39 @@ Views returning values fixed in the implementation code.
|
|
|
1722
1886
|
event EpochCommitted(uint64 indexed epochId, bytes32 indexed epochHash, bytes packet)
|
|
1723
1887
|
```
|
|
1724
1888
|
|
|
1725
|
-
Topic 0 `0xc9db8d1389570196eda0f2c6c4e2f78429c2f812db30b6b1022b5e0b5162ef72` · Emitted by: [`commitEpoch`](#registry-fn-commitepoch), [`commitEpochFallback`](#registry-fn-commitepochfallback) · Source: `EpochEntropy.sol` lines
|
|
1889
|
+
Topic 0 `0xc9db8d1389570196eda0f2c6c4e2f78429c2f812db30b6b1022b5e0b5162ef72` · Emitted by: [`commitEpoch`](#registry-fn-commitepoch), [`commitEpochFallback`](#registry-fn-commitepochfallback) · Source: `EpochEntropy.sol` lines 88, 388–390
|
|
1890
|
+
|
|
1891
|
+
An epoch was published. `packet` is `abi.encode(canonicalRequest, attestation)`: decode it with `decodeEpochEvidencePacket` and verify with `replayEpochCommitment`, which needs the registration of a beacon recipe as well. Requests of the epoch now have a target block.
|
|
1892
|
+
|
|
1893
|
+
#### <a id="registry-event-reciperegistered"></a>`RecipeRegistered`
|
|
1894
|
+
|
|
1895
|
+
```solidity
|
|
1896
|
+
event RecipeRegistered(uint8 indexed recipe, bytes32 indexed queryHash, string canonicalRequest, bytes template, string body)
|
|
1897
|
+
```
|
|
1898
|
+
|
|
1899
|
+
Topic 0 `0xbc5c1e3f4647d7f37dc8b4fe5e26e7c58ae35b8c9fb1db0233ddedba0d7f5fd8` · Emitted by: [`registerRecipe`](#registry-fn-registerrecipe), [`registerBeacon`](#registry-fn-registerbeacon), [`initializeRecipeRegistry`](#registry-fn-initializereciperegistry), [`initialize`](#registry-fn-initialize) · Source: `EpochEntropy.sol` lines 91, 169
|
|
1900
|
+
|
|
1901
|
+
Recipe `recipe` was registered, by `registerRecipe` or by `registerBeacon`. The event carries the complete definition, so every recipe can be rebuilt from logs; `getRecipe` returns the same values.
|
|
1902
|
+
|
|
1903
|
+
#### <a id="registry-event-beaconregistered"></a>`BeaconRegistered`
|
|
1904
|
+
|
|
1905
|
+
```solidity
|
|
1906
|
+
event BeaconRegistered(uint8 indexed recipe, address indexed verifier, bytes32 indexed chainHash, bytes publicKey, uint64 genesis, uint64 period)
|
|
1907
|
+
```
|
|
1908
|
+
|
|
1909
|
+
Topic 0 `0x293a9d9da76ea51abf287fd8574e03634d02d6156cf7df7e901320c2de39bf96` · Emitted by: [`registerBeacon`](#registry-fn-registerbeacon) · Source: `EpochEntropy.sol` lines 93, 186
|
|
1726
1910
|
|
|
1727
|
-
|
|
1911
|
+
Recipe `recipe` is a beacon recipe: emitted right after its `RecipeRegistered` with the registration `beaconOf` returns (`verifier`, `chainHash`, `publicKey`, `genesis`, `period`).
|
|
1728
1912
|
|
|
1729
1913
|
#### <a id="registry-event-catalogscheduled"></a>`CatalogScheduled`
|
|
1730
1914
|
|
|
1731
1915
|
```solidity
|
|
1732
|
-
event CatalogScheduled(uint64 indexed fromEpoch, bytes32 indexed catalogHash, address[
|
|
1916
|
+
event CatalogScheduled(uint64 indexed fromEpoch, bytes32 indexed catalogHash, uint8[] recipes, address[] signers)
|
|
1733
1917
|
```
|
|
1734
1918
|
|
|
1735
|
-
Topic 0 `
|
|
1919
|
+
Topic 0 `0xc91bcd562b1edaabdb2772ada76957511610c715ef892b9c9af1f35be93c3c4f` · Emitted by: [`scheduleCatalog`](#registry-fn-schedulecatalog) · Source: `EpochEntropy.sol` lines 90, 293
|
|
1736
1920
|
|
|
1737
|
-
|
|
1921
|
+
A catalog was scheduled for epochs from `fromEpoch`: recipe ids and signers in slot order. A later `CatalogScheduled` emitted while this version is still pending, two or more epochs ahead, replaces it, so when rebuilding catalogs from history drop replaced versions, or read `catalogAt(epochId)`.
|
|
1738
1922
|
|
|
1739
1923
|
**Administration and upgrades**
|
|
1740
1924
|
|
|
@@ -1744,9 +1928,19 @@ Signers scheduled for epochs from `fromEpoch`. A later `CatalogScheduled` emitte
|
|
|
1744
1928
|
event CommitterChanged(address indexed previousCommitter, address indexed newCommitter)
|
|
1745
1929
|
```
|
|
1746
1930
|
|
|
1747
|
-
Topic 0 `0x3f67cc70f736070aaac75db90cef1ab4047521b73e8a38d02852e8bf1a91e7e0` · Emitted by: [`setCommitter`](#registry-fn-setcommitter) · Source: `EpochEntropy.sol` lines
|
|
1931
|
+
Topic 0 `0x3f67cc70f736070aaac75db90cef1ab4047521b73e8a38d02852e8bf1a91e7e0` · Emitted by: [`setCommitter`](#registry-fn-setcommitter) · Source: `EpochEntropy.sol` lines 89, 120
|
|
1932
|
+
|
|
1933
|
+
New primary publishing address; it also receives the keeper share of proofs submitted by wallets the registry does not authorize.
|
|
1934
|
+
|
|
1935
|
+
#### <a id="registry-event-backupcommitterset"></a>`BackupCommitterSet`
|
|
1936
|
+
|
|
1937
|
+
```solidity
|
|
1938
|
+
event BackupCommitterSet(address indexed account, bool allowed)
|
|
1939
|
+
```
|
|
1748
1940
|
|
|
1749
|
-
|
|
1941
|
+
Topic 0 `0x20380b8c17d904db7d905a51f1538057d280a6cecca38882832ba0261b39fa66` · Emitted by: [`setBackupCommitter`](#registry-fn-setbackupcommitter) · Source: `EpochEntropy.sol` lines 92, 134
|
|
1942
|
+
|
|
1943
|
+
`account` may now publish epochs (`allowed` true) or no longer may (`allowed` false).
|
|
1750
1944
|
|
|
1751
1945
|
#### <a id="registry-event-ownershiptransferstarted"></a>`OwnershipTransferStarted`
|
|
1752
1946
|
|
|
@@ -1784,9 +1978,9 @@ The proxy now runs `implementation`. Emitted by the proxy at deployment and at e
|
|
|
1784
1978
|
event Initialized(uint64 version)
|
|
1785
1979
|
```
|
|
1786
1980
|
|
|
1787
|
-
Topic 0 `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` · Emitted by: [`initialize`](#registry-fn-initialize)
|
|
1981
|
+
Topic 0 `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` · Emitted by: [`initializeRecipeRegistry`](#registry-fn-initializereciperegistry), [`initialize`](#registry-fn-initialize)
|
|
1788
1982
|
|
|
1789
|
-
`initialize` ran on the proxy (`version` 1). Each implementation contract also emitted it once at construction with `version` 2^64 − 1, which locks the implementation against initialization.
|
|
1983
|
+
`initialize` ran on the proxy (`version` 1) or `initializeRecipeRegistry` did (`version` 2). Each implementation contract also emitted it once at construction with `version` 2^64 − 1, which locks the implementation against initialization.
|
|
1790
1984
|
|
|
1791
1985
|
### <a id="registry-errors"></a>Errors
|
|
1792
1986
|
|
|
@@ -1794,7 +1988,7 @@ Topic 0 `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` ·
|
|
|
1794
1988
|
|
|
1795
1989
|
#### <a id="registry-error-invalidepoch"></a>`InvalidEpoch`
|
|
1796
1990
|
|
|
1797
|
-
`error InvalidEpoch()` · Selector `0xd5b25b63` · Source: `EpochEntropy.sol` lines
|
|
1991
|
+
`error InvalidEpoch()` · Selector `0xd5b25b63` · Source: `EpochEntropy.sol` lines 83, 284, 315
|
|
1798
1992
|
|
|
1799
1993
|
**Raised by:** [`epochStart`](#registry-fn-epochstart), [`getEpochSelection`](#registry-fn-getepochselection), [`getEpochFallbackSelection`](#registry-fn-getepochfallbackselection), [`fallbackOpensAt`](#registry-fn-fallbackopensat), [`checkpointEpoch`](#registry-fn-checkpointepoch), [`commitEpoch`](#registry-fn-commitepoch), [`commitEpochFallback`](#registry-fn-commitepochfallback), [`scheduleCatalog`](#registry-fn-schedulecatalog).
|
|
1800
1994
|
|
|
@@ -1804,7 +1998,7 @@ Epoch 0 was passed to `epochStart`, `fallbackOpensAt`, a selection view, `checkp
|
|
|
1804
1998
|
|
|
1805
1999
|
#### <a id="registry-error-preparationclosed"></a>`PreparationClosed`
|
|
1806
2000
|
|
|
1807
|
-
`error PreparationClosed()` · Selector `0x8e2a3c7d` · Source: `EpochEntropy.sol` lines
|
|
2001
|
+
`error PreparationClosed()` · Selector `0x8e2a3c7d` · Source: `EpochEntropy.sol` lines 83, 330
|
|
1808
2002
|
|
|
1809
2003
|
**Raised by:** [`getEpochSelection`](#registry-fn-getepochselection), [`getEpochFallbackSelection`](#registry-fn-getepochfallbackselection), [`checkpointEpoch`](#registry-fn-checkpointepoch).
|
|
1810
2004
|
|
|
@@ -1814,7 +2008,7 @@ The epoch has not started (`block.number` is below `epochStart(epochId)`), so it
|
|
|
1814
2008
|
|
|
1815
2009
|
#### <a id="registry-error-anchorunavailable"></a>`AnchorUnavailable`
|
|
1816
2010
|
|
|
1817
|
-
`error AnchorUnavailable()` · Selector `0x60776ed3` · Source: `EpochEntropy.sol` lines
|
|
2011
|
+
`error AnchorUnavailable()` · Selector `0x60776ed3` · Source: `EpochEntropy.sol` lines 83, 333
|
|
1818
2012
|
|
|
1819
2013
|
**Raised by:** [`getEpochSelection`](#registry-fn-getepochselection), [`getEpochFallbackSelection`](#registry-fn-getepochfallbackselection), [`checkpointEpoch`](#registry-fn-checkpointepoch), [`commitEpoch`](#registry-fn-commitepoch), [`commitEpochFallback`](#registry-fn-commitepochfallback).
|
|
1820
2014
|
|
|
@@ -1826,17 +2020,17 @@ The anchor (hash of block `epochStart - 1`) was never checkpointed and is outsid
|
|
|
1826
2020
|
|
|
1827
2021
|
#### <a id="registry-error-onlycommitter"></a>`OnlyCommitter`
|
|
1828
2022
|
|
|
1829
|
-
`error OnlyCommitter()` · Selector `0xfffe5af3` · Source: `EpochEntropy.sol` lines
|
|
2023
|
+
`error OnlyCommitter()` · Selector `0xfffe5af3` · Source: `EpochEntropy.sol` lines 84, 364
|
|
1830
2024
|
|
|
1831
2025
|
**Raised by:** [`commitEpoch`](#registry-fn-commitepoch), [`commitEpochFallback`](#registry-fn-commitepochfallback).
|
|
1832
2026
|
|
|
1833
|
-
A commit from an address
|
|
2027
|
+
A commit from an address that is neither `committer()` nor an allowed backup committer.
|
|
1834
2028
|
|
|
1835
|
-
**What to do:** Only the committer
|
|
2029
|
+
**What to do:** Only the committer and backup committers publish; check `isBackupCommitter`.
|
|
1836
2030
|
|
|
1837
2031
|
#### <a id="registry-error-alreadycommitted"></a>`AlreadyCommitted`
|
|
1838
2032
|
|
|
1839
|
-
`error AlreadyCommitted()` · Selector `0xbfec5558` · Source: `EpochEntropy.sol` lines
|
|
2033
|
+
`error AlreadyCommitted()` · Selector `0xbfec5558` · Source: `EpochEntropy.sol` lines 84, 365
|
|
1840
2034
|
|
|
1841
2035
|
**Raised by:** [`commitEpoch`](#registry-fn-commitepoch), [`commitEpochFallback`](#registry-fn-commitepochfallback).
|
|
1842
2036
|
|
|
@@ -1846,7 +2040,7 @@ The epoch already has a published packet.
|
|
|
1846
2040
|
|
|
1847
2041
|
#### <a id="registry-error-fallbacknotopen"></a>`FallbackNotOpen`
|
|
1848
2042
|
|
|
1849
|
-
`error FallbackNotOpen()` · Selector `0xf8635228` · Source: `EpochEntropy.sol` lines
|
|
2043
|
+
`error FallbackNotOpen()` · Selector `0xf8635228` · Source: `EpochEntropy.sol` lines 86, 366
|
|
1850
2044
|
|
|
1851
2045
|
**Raised by:** [`commitEpoch`](#registry-fn-commitepoch), [`commitEpochFallback`](#registry-fn-commitepochfallback).
|
|
1852
2046
|
|
|
@@ -1856,43 +2050,53 @@ The epoch already has a published packet.
|
|
|
1856
2050
|
|
|
1857
2051
|
#### <a id="registry-error-invalidfallback"></a>`InvalidFallback`
|
|
1858
2052
|
|
|
1859
|
-
`error InvalidFallback()` · Selector `0x5a93724d` · Source: `EpochEntropy.sol` lines
|
|
2053
|
+
`error InvalidFallback()` · Selector `0x5a93724d` · Source: `EpochEntropy.sol` lines 86, 341, 349, 360
|
|
1860
2054
|
|
|
1861
2055
|
**Raised by:** [`getEpochFallbackSelection`](#registry-fn-getepochfallbackselection), [`fallbackOpensAt`](#registry-fn-fallbackopensat), [`commitEpochFallback`](#registry-fn-commitepochfallback).
|
|
1862
2056
|
|
|
1863
|
-
An attempt above `
|
|
2057
|
+
An attempt at or above `sourceCountAt(epochId)`, or attempt 0 passed to `commitEpochFallback`.
|
|
1864
2058
|
|
|
1865
|
-
**What to do:** Use attempts 1 to
|
|
2059
|
+
**What to do:** Use attempts 1 to `sourceCountAt(epochId) - 1` for fallbacks.
|
|
1866
2060
|
|
|
1867
2061
|
#### <a id="registry-error-invalidtime"></a>`InvalidTime`
|
|
1868
2062
|
|
|
1869
|
-
`error InvalidTime()` · Selector `0x6f7eac26` · Source: `EpochEntropy.sol` lines
|
|
2063
|
+
`error InvalidTime()` · Selector `0x6f7eac26` · Source: `EpochEntropy.sol` lines 84, 368, 378
|
|
1870
2064
|
|
|
1871
2065
|
**Raised by:** [`commitEpoch`](#registry-fn-commitepoch), [`commitEpochFallback`](#registry-fn-commitepochfallback).
|
|
1872
2066
|
|
|
1873
|
-
The attestation timestamp is in the future or more than `MAX_ATTESTATION_AGE` (240 seconds) before the publication block.
|
|
2067
|
+
The attestation timestamp is in the future or more than `MAX_ATTESTATION_AGE` (240 seconds) before the publication block, or, for a beacon recipe, is not the scheduled time of the round in the data.
|
|
1874
2068
|
|
|
1875
2069
|
**What to do:** A saved packet is never refreshed; its requests expire and are refunded.
|
|
1876
2070
|
|
|
1877
2071
|
#### <a id="registry-error-invaliddata"></a>`InvalidData`
|
|
1878
2072
|
|
|
1879
|
-
`error InvalidData()` · Selector `0x5cb045db` · Source: `EpochEntropy.sol` lines
|
|
2073
|
+
`error InvalidData()` · Selector `0x5cb045db` · Source: `EpochEntropy.sol` lines 84, 369–370
|
|
1880
2074
|
|
|
1881
2075
|
**Raised by:** [`commitEpoch`](#registry-fn-commitepoch), [`commitEpochFallback`](#registry-fn-commitepochfallback).
|
|
1882
2076
|
|
|
1883
|
-
The signed data
|
|
2077
|
+
The signed data does not match the data template of the slot's recipe exactly, which includes data longer than `MAX_DATA_BYTES` (128).
|
|
1884
2078
|
|
|
1885
|
-
**What to do:** Publish only a
|
|
2079
|
+
**What to do:** Publish only a response that matches the selected recipe's template, unmodified.
|
|
1886
2080
|
|
|
1887
2081
|
#### <a id="registry-error-invalidsigner"></a>`InvalidSigner`
|
|
1888
2082
|
|
|
1889
|
-
`error InvalidSigner()` · Selector `0x815e1d64` · Source: `EpochEntropy.sol` lines
|
|
2083
|
+
`error InvalidSigner()` · Selector `0x815e1d64` · Source: `EpochEntropy.sol` lines 84, 374, 379
|
|
1890
2084
|
|
|
1891
2085
|
**Raised by:** [`commitEpoch`](#registry-fn-commitepoch), [`commitEpochFallback`](#registry-fn-commitepochfallback).
|
|
1892
2086
|
|
|
1893
|
-
The signature does not recover to the slot's signer in the epoch's catalog.
|
|
2087
|
+
The signature does not recover to the slot's signer in the epoch's catalog, or, for a beacon recipe, the verifier of its registration did not accept it as the beacon's signature of the round in the data.
|
|
2088
|
+
|
|
2089
|
+
**What to do:** Use `catalogAt(epochId)` for the expected signer; for a beacon recipe check the round with `verifyBeacon`.
|
|
2090
|
+
|
|
2091
|
+
#### <a id="registry-error-beacongastoolow"></a>`BeaconGasTooLow`
|
|
2092
|
+
|
|
2093
|
+
`error BeaconGasTooLow()` · Selector `0x919ddbf6` · Source: `EpochEntropy.sol` lines 87, 220
|
|
2094
|
+
|
|
2095
|
+
**Raised by:** [`verifyBeacon`](#registry-fn-verifybeacon), [`commitEpoch`](#registry-fn-commitepoch), [`commitEpochFallback`](#registry-fn-commitepochfallback), [`registerBeacon`](#registry-fn-registerbeacon).
|
|
1894
2096
|
|
|
1895
|
-
|
|
2097
|
+
Too little gas was left to give the beacon verifier its whole `BEACON_VERIFY_GAS` allowance, in `registerBeacon`, `verifyBeacon` or a publication of a beacon epoch. It is raised instead of answering false, so a valid round is never read as invalid because the sender's gas limit was low.
|
|
2098
|
+
|
|
2099
|
+
**What to do:** Send the transaction with a higher gas limit; an `eth_call` of `verifyBeacon` needs about 461,000 gas.
|
|
1896
2100
|
|
|
1897
2101
|
#### <a id="registry-error-ecdsainvalidsignature"></a>`ECDSAInvalidSignature`
|
|
1898
2102
|
|
|
@@ -1926,31 +2130,61 @@ The signature has a high `s` value (OpenZeppelin `ECDSA`).
|
|
|
1926
2130
|
|
|
1927
2131
|
#### <a id="registry-error-packettoolarge"></a>`PacketTooLarge`
|
|
1928
2132
|
|
|
1929
|
-
`error PacketTooLarge()` · Selector `0xda85e8a5` · Source: `EpochEntropy.sol` lines
|
|
2133
|
+
`error PacketTooLarge()` · Selector `0xda85e8a5` · Source: `EpochEntropy.sol` lines 85, 389
|
|
1930
2134
|
|
|
1931
2135
|
**Raised by:** [`commitEpoch`](#registry-fn-commitepoch), [`commitEpochFallback`](#registry-fn-commitepochfallback).
|
|
1932
2136
|
|
|
1933
2137
|
The encoded packet exceeds `MAX_PACKET_BYTES` (2048).
|
|
1934
2138
|
|
|
1935
|
-
**What to do:** Not reachable
|
|
2139
|
+
**What to do:** Not reachable: the recipe and data bounds keep every packet within `MAX_PACKET_BYTES`.
|
|
1936
2140
|
|
|
1937
|
-
**
|
|
2141
|
+
**Recipes, administration, initialization and upgrades**
|
|
2142
|
+
|
|
2143
|
+
#### <a id="registry-error-invalidrecipe"></a>`InvalidRecipe`
|
|
2144
|
+
|
|
2145
|
+
`error InvalidRecipe()` · Selector `0x7b776f4c` · Source: `EpochEntropy.sol` lines 87, 165
|
|
2146
|
+
|
|
2147
|
+
**Raised by:** [`registerRecipe`](#registry-fn-registerrecipe), [`registerBeacon`](#registry-fn-registerbeacon).
|
|
2148
|
+
|
|
2149
|
+
`registerRecipe` got an empty canonical request or body, a canonical request over `MAX_REQUEST_BYTES` or a body over `MAX_BODY_BYTES`, or `MAX_RECIPES` recipes are already registered.
|
|
2150
|
+
|
|
2151
|
+
**What to do:** Shorten the request or body. Recipe ids are never freed.
|
|
2152
|
+
|
|
2153
|
+
#### <a id="registry-error-invalidtemplate"></a>`InvalidTemplate`
|
|
2154
|
+
|
|
2155
|
+
`error InvalidTemplate()` · Selector `0xec55b8cd` · Source: `EpochEntropy.sol` lines 87, 166
|
|
2156
|
+
|
|
2157
|
+
**Raised by:** [`registerRecipe`](#registry-fn-registerrecipe).
|
|
2158
|
+
|
|
2159
|
+
`registerRecipe` got a data template that is not well formed (README [Data templates](README.md#data-templates)).
|
|
2160
|
+
|
|
2161
|
+
**What to do:** Build the template with `encodeDataTemplate`, which names the broken rule, before registering.
|
|
2162
|
+
|
|
2163
|
+
#### <a id="registry-error-stringsinsufficienthexlength"></a>`StringsInsufficientHexLength`
|
|
2164
|
+
|
|
2165
|
+
`error StringsInsufficientHexLength(uint256 value, uint256 length)` · Selector `0xe22e27eb`
|
|
2166
|
+
|
|
2167
|
+
**Raised by:** no public function (declared by OpenZeppelin `Strings`).
|
|
2168
|
+
|
|
2169
|
+
Declared by OpenZeppelin `Strings`, which `registerBeacon` uses to write the chain hash as 32 bytes of hex. A 32-byte value always fits, so it cannot be raised.
|
|
2170
|
+
|
|
2171
|
+
**What to do:** None.
|
|
1938
2172
|
|
|
1939
2173
|
#### <a id="registry-error-invalidconfig"></a>`InvalidConfig`
|
|
1940
2174
|
|
|
1941
|
-
`error InvalidConfig()` · Selector `0x35be3ac8` · Source: `EpochEntropy.sol` lines
|
|
2175
|
+
`error InvalidConfig()` · Selector `0x35be3ac8` · Source: `EpochEntropy.sol` lines 83, 99, 111, 119, 126, 128, 158, 180–182, 275, 279, 280
|
|
1942
2176
|
|
|
1943
|
-
**Raised by:** [`
|
|
2177
|
+
**Raised by:** [`getRecipe`](#registry-fn-getrecipe), [`beaconOf`](#registry-fn-beaconof), [`recipeRequest`](#registry-fn-reciperequest), [`getEpochSelection`](#registry-fn-getepochselection), [`getEpochFallbackSelection`](#registry-fn-getepochfallbackselection), [`commitEpoch`](#registry-fn-commitepoch), [`commitEpochFallback`](#registry-fn-commitepochfallback), [`registerBeacon`](#registry-fn-registerbeacon), [`scheduleCatalog`](#registry-fn-schedulecatalog), [`initializeRecipeRegistry`](#registry-fn-initializereciperegistry), [`setCommitter`](#registry-fn-setcommitter), [`setBackupCommitter`](#registry-fn-setbackupcommitter), [`initialize`](#registry-fn-initialize).
|
|
1944
2178
|
|
|
1945
|
-
A zero signer or committer in `initialize
|
|
2179
|
+
A zero signer or committer in `initialize`; a zero address in `setCommitter`; in `setBackupCommitter` the zero address, allowing the committer, an unchanged status or a fifth backup committer; in `registerBeacon` a verifier without code, a zero chain hash, genesis, period or sample round, a sample round not yet scheduled, or a key or sample signature the verifier rejects; in `scheduleCatalog` an empty or oversized catalog, mismatched lengths, a repeated or unregistered recipe, a zero signer or a beacon recipe listed with a signer other than its `slotSigner`; `initializeRecipeRegistry` on a registry that already has recipes or a scheduled catalog; or a recipe id that is not registered, in `getRecipe`, `recipeRequest` and `beaconOf` or, on a registry upgraded without `initializeRecipeRegistry`, in selection and publication.
|
|
1946
2180
|
|
|
1947
|
-
**What to do:**
|
|
2181
|
+
**What to do:** Correct the arguments; recipe ids run from 0 to `recipeCount() - 1`. A registry upgraded without the recipe step needs `initializeRecipeRegistry` from its owner.
|
|
1948
2182
|
|
|
1949
2183
|
#### <a id="registry-error-ownableunauthorizedaccount"></a>`OwnableUnauthorizedAccount`
|
|
1950
2184
|
|
|
1951
2185
|
`error OwnableUnauthorizedAccount(address account)` · Selector `0x118cdaa7`
|
|
1952
2186
|
|
|
1953
|
-
**Raised by:** [`
|
|
2187
|
+
**Raised by:** [`registerRecipe`](#registry-fn-registerrecipe), [`registerBeacon`](#registry-fn-registerbeacon), [`scheduleCatalog`](#registry-fn-schedulecatalog), [`initializeRecipeRegistry`](#registry-fn-initializereciperegistry), [`setCommitter`](#registry-fn-setcommitter), [`setBackupCommitter`](#registry-fn-setbackupcommitter), [`transferOwnership`](#registry-fn-transferownership), [`acceptOwnership`](#registry-fn-acceptownership), [`renounceOwnership`](#registry-fn-renounceownership), [`upgradeToAndCall`](#registry-fn-upgradetoandcall).
|
|
1954
2188
|
|
|
1955
2189
|
`account` is not the owner (owner-only functions) or not the pending owner (`acceptOwnership`).
|
|
1956
2190
|
|
|
@@ -1968,7 +2202,7 @@ A zero signer or committer in `initialize`, a zero address in `setCommitter`, or
|
|
|
1968
2202
|
|
|
1969
2203
|
#### <a id="registry-error-renouncedisabled"></a>`RenounceDisabled`
|
|
1970
2204
|
|
|
1971
|
-
`error RenounceDisabled()` · Selector `0x89051165` · Source: `EpochEntropy.sol` lines
|
|
2205
|
+
`error RenounceDisabled()` · Selector `0x89051165` · Source: `EpochEntropy.sol` lines 85, 116
|
|
1972
2206
|
|
|
1973
2207
|
**Raised by:** [`renounceOwnership`](#registry-fn-renounceownership).
|
|
1974
2208
|
|
|
@@ -1980,11 +2214,11 @@ The owner called `renounceOwnership`, which is disabled.
|
|
|
1980
2214
|
|
|
1981
2215
|
`error InvalidInitialization()` · Selector `0xf92ee8a9`
|
|
1982
2216
|
|
|
1983
|
-
**Raised by:** [`initialize`](#registry-fn-initialize).
|
|
2217
|
+
**Raised by:** [`initializeRecipeRegistry`](#registry-fn-initializereciperegistry), [`initialize`](#registry-fn-initialize).
|
|
1984
2218
|
|
|
1985
|
-
`initialize` on a proxy that is already initialized
|
|
2219
|
+
`initialize` on a proxy that is already initialized or on an implementation contract, whose initializers are disabled at construction, or `initializeRecipeRegistry` on a proxy that has already reached initializer version 2.
|
|
1986
2220
|
|
|
1987
|
-
**What to do:** None:
|
|
2221
|
+
**What to do:** None: `initialize` happens once when `D20Proxy` is deployed, and `initializeRecipeRegistry` once in the recipe-registry upgrade.
|
|
1988
2222
|
|
|
1989
2223
|
#### <a id="registry-error-notinitializing"></a>`NotInitializing`
|
|
1990
2224
|
|
|
@@ -2055,3 +2289,120 @@ Declared by OpenZeppelin `Address` for the delegatecall in `upgradeToAndCall`. N
|
|
|
2055
2289
|
The initialization call made by `upgradeToAndCall` reverted without revert data.
|
|
2056
2290
|
|
|
2057
2291
|
**What to do:** Owner upgrade procedure only.
|
|
2292
|
+
|
|
2293
|
+
## <a id="verifier"></a>D20BeaconVerifier
|
|
2294
|
+
|
|
2295
|
+
The verifier of the registry's drand beacon recipe: stateless and deployed directly, not behind a proxy. `EpochEntropy` records its address in a recipe's registration (`beaconOf`) and calls `isValidPublicKey` and `verifyRound` under a fixed gas allowance. It checks the bls-bn254-unchained-on-g1 scheme of drand's evmnet: the group public key is a BN254 G2 point, round `r`'s signature is a G1 point on the RFC 9380 hash-to-curve of `keccak256` of `r` as 8 big-endian bytes, and keys and signatures use drand's serialization of 32-byte big-endian words (`x ‖ y` for G1, `x_im ‖ x_re ‖ y_im ‖ y_re` for G2). It is built on the unmodified kevincharm/bls-bn254 library recorded in `notices/PROVENANCE.md`.
|
|
2296
|
+
|
|
2297
|
+
Anyone can call it, for example to check a drand round inside another contract. `beaconVerifierAbi` from `@d20dao/vrf-sdk/abi` carries its ABI, and `verifyBeaconRound` in `@d20dao/vrf-sdk` computes the same check off-chain.
|
|
2298
|
+
|
|
2299
|
+
### <a id="verifier-verification"></a>Verification
|
|
2300
|
+
|
|
2301
|
+
Views, callable by anyone.
|
|
2302
|
+
|
|
2303
|
+
#### <a id="verifier-fn-isvalidpublickey"></a>`isValidPublicKey`
|
|
2304
|
+
|
|
2305
|
+
```solidity
|
|
2306
|
+
function isValidPublicKey(bytes publicKey) external pure returns (bool)
|
|
2307
|
+
```
|
|
2308
|
+
|
|
2309
|
+
Selector `0xc4c1cf54` · Caller: Anyone (view) · Source: `D20BeaconVerifier.sol` lines 28–34
|
|
2310
|
+
|
|
2311
|
+
Whether `publicKey` is 128 bytes, `x_im ‖ x_re ‖ y_im ‖ y_re`, encoding a point on the BN254 G2 curve with every coordinate below the field order. Subgroup membership is not checked here: the pairing precompile refuses a key outside the subgroup, so a verified signature under the key establishes it. `EpochEntropy` calls it when a beacon is registered.
|
|
2312
|
+
|
|
2313
|
+
#### <a id="verifier-fn-roundmessage"></a>`roundMessage`
|
|
2314
|
+
|
|
2315
|
+
```solidity
|
|
2316
|
+
function roundMessage(uint64 round) external view returns (uint256[2])
|
|
2317
|
+
```
|
|
2318
|
+
|
|
2319
|
+
Selector `0xfd5a7458` · Caller: Anyone (view) · Source: `D20BeaconVerifier.sol` lines 36–39
|
|
2320
|
+
|
|
2321
|
+
The G1 point that the signature of `round` signs: the RFC 9380 hash-to-curve of `keccak256` of the round as 8 big-endian bytes under `DST` (`expand_message_xmd` with `keccak256`, the Shallue-van de Woestijne map and the sum of two mapped field elements). `beaconRoundMessage` in `@d20dao/vrf-sdk` computes the same point off-chain.
|
|
2322
|
+
|
|
2323
|
+
**Errors:** [`BNAddFailed`](#verifier-error-bnaddfailed), [`ModExpFailed`](#verifier-error-modexpfailed).
|
|
2324
|
+
|
|
2325
|
+
#### <a id="verifier-fn-verifyround"></a>`verifyRound`
|
|
2326
|
+
|
|
2327
|
+
```solidity
|
|
2328
|
+
function verifyRound(bytes publicKey, uint64 round, bytes signature) external view returns (bool)
|
|
2329
|
+
```
|
|
2330
|
+
|
|
2331
|
+
Selector `0x3a1bc7c9` · Caller: Anyone (view) · Source: `D20BeaconVerifier.sol` lines 41–60
|
|
2332
|
+
|
|
2333
|
+
Whether `signature` (64 bytes, `x ‖ y`) is the beacon's signature of `round` under `publicKey`: the pairing of `signature` with the G2 generator equals the pairing of `roundMessage(round)` with `publicKey`. It returns false, without reverting, for a signature that is not 64 bytes, a key that fails `isValidPublicKey` and a signature whose coordinates are not below the field order or not on the curve. Otherwise it runs the pairing precompile with a fixed allowance of `PAIRING_GAS`, and a direct call needs about 285,000 gas. It reverts `InsufficientGas`, and never answers false, when too little gas is left to give the precompile that allowance, so a valid signature is not read as invalid for want of gas.
|
|
2334
|
+
|
|
2335
|
+
**Errors:** [`InsufficientGas`](#verifier-error-insufficientgas), [`BNAddFailed`](#verifier-error-bnaddfailed), [`ModExpFailed`](#verifier-error-modexpfailed).
|
|
2336
|
+
|
|
2337
|
+
### <a id="verifier-constants"></a>Constants
|
|
2338
|
+
|
|
2339
|
+
Views returning values fixed in the code.
|
|
2340
|
+
|
|
2341
|
+
| Constant | Returns | Value | Selector | Meaning |
|
|
2342
|
+
| --- | --- | --- | --- | --- |
|
|
2343
|
+
| <a id="verifier-fn-dst"></a>`DST` | `bytes` | `"BLS_SIG_BN254G1_XMD:KECCAK-256_SVDW_RO_NUL_"` | `0x5f7c7522` | RFC 9380 domain separation tag of the scheme's hash-to-curve. |
|
|
2344
|
+
| <a id="verifier-fn-pairing_gas"></a>`PAIRING_GAS` | `uint256` | `200_000` | `0x1848e02a` | Gas given to the pairing precompile (address 8). A two-pair check costs 113,000 under EIP-1108. |
|
|
2345
|
+
|
|
2346
|
+
### <a id="verifier-errors"></a>Errors
|
|
2347
|
+
|
|
2348
|
+
**Verification**
|
|
2349
|
+
|
|
2350
|
+
#### <a id="verifier-error-insufficientgas"></a>`InsufficientGas`
|
|
2351
|
+
|
|
2352
|
+
`error InsufficientGas()` · Selector `0x1c26714c` · Source: `D20BeaconVerifier.sol` lines 17, 57
|
|
2353
|
+
|
|
2354
|
+
**Raised by:** [`verifyRound`](#verifier-fn-verifyround).
|
|
2355
|
+
|
|
2356
|
+
Too little gas was left in `verifyRound` for the pairing precompile to get its whole `PAIRING_GAS` allowance.
|
|
2357
|
+
|
|
2358
|
+
**What to do:** Send the call with a higher gas limit; a direct call needs about 285,000 gas.
|
|
2359
|
+
|
|
2360
|
+
#### <a id="verifier-error-modexpfailed"></a>`ModExpFailed`
|
|
2361
|
+
|
|
2362
|
+
`error ModExpFailed(uint256 base, uint256 exponent, uint256 modulus)` · Selector `0xc6daf7ab` · Source: `vendor/bls-bn254/BLS.sol` lines 56, 399
|
|
2363
|
+
|
|
2364
|
+
**Raised by:** [`roundMessage`](#verifier-fn-roundmessage), [`verifyRound`](#verifier-fn-verifyround).
|
|
2365
|
+
|
|
2366
|
+
The modexp precompile (address 5), which the hash-to-curve calls with all remaining gas, failed: in practice the call ran out of gas.
|
|
2367
|
+
|
|
2368
|
+
**What to do:** Send the call with a higher gas limit.
|
|
2369
|
+
|
|
2370
|
+
#### <a id="verifier-error-bnaddfailed"></a>`BNAddFailed`
|
|
2371
|
+
|
|
2372
|
+
`error BNAddFailed(uint256[4] input)` · Selector `0x128e3f08` · Source: `vendor/bls-bn254/BLS.sol` lines 52, 113
|
|
2373
|
+
|
|
2374
|
+
**Raised by:** [`roundMessage`](#verifier-fn-roundmessage), [`verifyRound`](#verifier-fn-verifyround).
|
|
2375
|
+
|
|
2376
|
+
The bn256 addition precompile (address 6), which adds the two mapped points of the hash-to-curve, failed: in practice the call ran out of gas.
|
|
2377
|
+
|
|
2378
|
+
**What to do:** Send the call with a higher gas limit.
|
|
2379
|
+
|
|
2380
|
+
#### <a id="verifier-error-maptopointfailed"></a>`MapToPointFailed`
|
|
2381
|
+
|
|
2382
|
+
`error MapToPointFailed(uint256 noSqrt)` · Selector `0x396ec771` · Source: `vendor/bls-bn254/BLS.sol` lines 54, 329, 334, 339, 365
|
|
2383
|
+
|
|
2384
|
+
**Raised by:** no input known (check inside the vendored library).
|
|
2385
|
+
|
|
2386
|
+
Raised by the vendored library when its map of a field element to the curve finds no square root or a Legendre exponentiation returns an unexpected value. The Shallue-van de Woestijne map always yields a point, so no input should reach it.
|
|
2387
|
+
|
|
2388
|
+
**What to do:** None.
|
|
2389
|
+
|
|
2390
|
+
#### <a id="verifier-error-invalidfieldelement"></a>`InvalidFieldElement`
|
|
2391
|
+
|
|
2392
|
+
`error InvalidFieldElement(uint256 x)` · Selector `0xd53e9415` · Source: `vendor/bls-bn254/BLS.sol` lines 53, 310
|
|
2393
|
+
|
|
2394
|
+
**Raised by:** no input of this contract (check inside the vendored library).
|
|
2395
|
+
|
|
2396
|
+
The vendored library was asked to map a value at or above the field order. The hash-to-curve reduces its field elements below it first, so this contract cannot reach it.
|
|
2397
|
+
|
|
2398
|
+
**What to do:** None.
|
|
2399
|
+
|
|
2400
|
+
#### <a id="verifier-error-invaliddstlength"></a>`InvalidDSTLength`
|
|
2401
|
+
|
|
2402
|
+
`error InvalidDSTLength(bytes dst)` · Selector `0x26e4f9ba` · Source: `vendor/bls-bn254/BLS.sol` lines 55, 260
|
|
2403
|
+
|
|
2404
|
+
**Raised by:** no input of this contract (check inside the vendored library).
|
|
2405
|
+
|
|
2406
|
+
The domain separation tag is longer than 255 bytes. `DST` is 43 bytes, so this contract cannot reach it.
|
|
2407
|
+
|
|
2408
|
+
**What to do:** None.
|