Skip to content

Commit b93e8ad

Browse files
mcoetzeeSiegrift
andauthored
Update docs to make auction lengths chain specific (#221)
* Update auctioneer docs to reflect chain-specific auction lengths * Add vitest and test that all supported chains are listed in the Auction length section * Update lockfile * Add renovate group for @api3/* packages * Add type checking to the CI * Use only Arbitrum for 15s auctions --------- Co-authored-by: Emanuel Tesař <e.tesarr@gmail.com>
1 parent a41d48f commit b93e8ad

File tree

9 files changed

+8130
-527
lines changed

9 files changed

+8130
-527
lines changed

.github/workflows/main.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,13 @@ jobs:
2727
- run: pnpm install
2828

2929
- name: Lint
30-
run: |
31-
pnpm format:check
30+
run: pnpm lint
31+
32+
- name: Test
33+
run: pnpm test
3234

3335
- name: Build documentation
34-
run: |
35-
pnpm docs:build
36+
run: pnpm docs:build
3637

3738
- name: Serve docs and check links
3839
run: |

docs/dapps/integration/security-considerations.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ Similarly, our OEV implementation uses this mechanism, ensuring OEV updates cont
9595
OEV updates provide identical guarantees to regular updates—they are on-chain aggregations of API provider-signed data—so they introduce no additional [data correctness](#data-correctness) risk.
9696
The OEV auction mechanism allows winners to frontrun updates of an artificially delayed base feed, a tradeoff designed to benefit the dApp.
9797

98-
Here's how the process works.
98+
Here's how the process works for auctions with a length of 30 seconds.
9999
The lifecycle of a data point consists of three phases:
100100

101101
1. From 0-30 seconds: OEV searchers examine the data point and place bids on potential OEV opportunities.

docs/oev-searchers/in-depth/oev-auctioneer.md

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,27 +42,85 @@ understand and comply with in order to successfully participate in auctions.
4242

4343
| Name | Value | Description |
4444
| ------------------------------------- | ----- | -------------------------------------------------------------------------------------------------- |
45-
| AUCTION_LENGTH_SECONDS | 30 | How long an auction lasts. |
4645
| OEV_AUCTIONS_MAJOR_VERSION | 1 | Increased when we release any breaking change relevant to OEV auctions. |
4746
| COLLATERAL_REQUIREMENT_BUFFER_PERCENT | 5 | The additional percentage of the bidder's collateral to mitigate against price changes. |
48-
| BID_PHASE_LENGTH_SECONDS | 25 | The length of the bid phase during which searchers can place their bids. |
47+
| AWARD_PHASE_LENGTH_SECONDS | 5 | The length of the award phase during which Auctioneer attempts to resolve the auction. |
4948
| REPORT_FULFILLMENT_PERIOD_SECONDS | 86400 | The fulfillment period, during which the auction winner is able to report payment for the OEV bid. |
5049
| MINIMUM_BID_EXPIRING_SECONDS | 15 | The minimum expiring time for a bid to be considered eligible for award. |
5150
| PLACED_BIDS_BLOCK_RANGE | 300 | The number of blocks queried for placed bids during award phase. |
5251

52+
### Auction length
53+
54+
The auction length is chain dependent.
55+
56+
<!-- BEGIN:chain-auction-length-table -->
57+
58+
| Chain | Length (seconds) |
59+
| --------------- | ---------------- |
60+
| ApeChain | 30 |
61+
| Arbitrum One | 15 |
62+
| Avalanche | 30 |
63+
| Base | 30 |
64+
| Berachain | 30 |
65+
| Bitlayer | 30 |
66+
| Blast | 30 |
67+
| BNB Smart Chain | 30 |
68+
| BOB | 30 |
69+
| Core | 30 |
70+
| Ethereum | 30 |
71+
| Fraxtal | 30 |
72+
| Gnosis Chain | 30 |
73+
| Ink | 30 |
74+
| Katana | 30 |
75+
| Kava | 30 |
76+
| Linea | 30 |
77+
| Lumia | 30 |
78+
| Manta | 30 |
79+
| Mantle | 30 |
80+
| Merlin | 30 |
81+
| Metal L2 | 30 |
82+
| Metis | 30 |
83+
| Mode | 30 |
84+
| Moonbeam | 30 |
85+
| Moonriver | 30 |
86+
| opBNB | 30 |
87+
| Optimism | 30 |
88+
| Polygon | 30 |
89+
| Polygon zkEVM | 30 |
90+
| Ronin | 30 |
91+
| Scroll | 30 |
92+
| Sei | 30 |
93+
| Soneium | 30 |
94+
| Sonic | 30 |
95+
| Taiko | 30 |
96+
| Unichain | 30 |
97+
| World Chain | 30 |
98+
| X Layer | 30 |
99+
| Zircuit | 30 |
100+
101+
<!-- END:chain-auction-length-table -->
102+
103+
### Bid phase length
104+
105+
The length of the bid phase during which searchers can place their bids. The bid phase length is auction length dependent.
106+
107+
```js
108+
const bidPhaseLength = auctionLength - AWARD_PHASE_LENGTH_SECONDS;
109+
```
110+
53111
### Auction offset
54112

55113
Auctions repeat indefinitely and take a fixed amount of time. The first auction
56114
starts at the UNIX timestamp 0 (midnight UTC on 1st of January 1970) plus an
57115
offset based on the dApp ID.
58116

59117
```solidity
60-
uint256(keccak256(abi.encodePacked(uint256(dAppId)))) % AUCTION_LENGTH_SECONDS;
118+
uint256(keccak256(abi.encodePacked(uint256(dappId)))) % auctionLength;
61119
```
62120

63121
::: info ℹ️ Example
64122

65-
Say there is a dApp with ID `13` and `AUCTION_LENGTH_SECONDS=30`
123+
Say there is a dApp with ID `13` and `auctionLength=30`
66124

67125
- When we encode and hash the dApp ID, we get
68126
`0xd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5`.
@@ -97,9 +155,7 @@ Let's break down the components of the bid topic:
97155
protocol specs, is denoted by this major version being incremented. Refer to
98156
the current value of `OEV_AUCTIONS_MAJOR_VERSION` constant.
99157
2. `dappId` - The dApp ID for which the auction is being held.
100-
3. `auctionLength` - The length of the auction. This parameter must be set to
101-
`AUCTION_LENGTH_SECONDS`. It is one of the most important parameters, so
102-
we're explicitly including it in the bid topic to highlight its importance.
158+
3. `auctionLength` - The length of the auction in seconds. It is one of the most important parameters, so we're explicitly including it in the bid topic to highlight its importance.
103159
4. `signedDataTimestampCutoff` - The cutoff timestamp of the signed data. The auction winner is permitted to only use signed data with timestamps smaller than or equal to this. It is equal to the end of the bid phase of the
104160
auction.
105161

@@ -108,10 +164,10 @@ Let's break down the components of the bid topic:
108164
Auctions repeat continuously and indefinitely. To calculate the
109165
`signedDataTimestampCutoff` that is to be specified in the bid topic, one needs
110166
to calculate the `startTimestamp` of the next auction. This depends on the auction
111-
offset, `BID_PHASE_LENGTH_SECONDS` and the current time.
167+
offset, `bidPhaseLength` and the current time.
112168

113169
For example, dApp with ID `13` has an auction offset of `17`. With
114-
`AUCTION_LENGTH_SECONDS=30` and `BID_PHASE_LENGTH_SECONDS=25` this gives the
170+
`auctionLength=30` and `bidPhaseLength=25` this gives the
115171
following sequence of auctions:
116172

117173
| `startTimestamp` | `signedDataTimestampCutoff` | End of award phase |
@@ -205,7 +261,7 @@ transaction.
205261
Each auction is split into two phases:
206262

207263
1. Bid phase - During this phase, searchers are free to submit their bids.
208-
This phase takes `BID_PHASE_LENGTH_SECONDS`.
264+
This phase takes `bidPhaseLength`.
209265
2. Award phase - During this phase, Auctioneer determines and awards the winner.
210266
Bids placed during this period are ignored.
211267

@@ -221,6 +277,7 @@ as soon as possible. The following happens under the hood:
221277
selected
222278
6. Prepare and submit the award for the auction winner on the OEV Network
223279

280+
Auctioneer may take longer than the allotted `AWARD_PHASE_LENGTH_SECONDS` to award the winner.
224281
Under rare circumstances, when Auctioneer is unable to fetch the block or the
225282
logs from the OEV Network, the auction will be aborted and no winner is chosen.
226283
Similarly, if the auction award transaction fails, there will be no retry,
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import path from 'node:path';
2+
import fs from 'node:fs';
3+
import { test, expect } from 'vitest';
4+
import { CHAINS } from '@api3/contracts';
5+
import { getChains } from '@api3/dapi-management';
6+
7+
const supportedMainnets = getChains()
8+
.filter((chain) => chain.stage === 'active')
9+
.map((chain) => CHAINS.find((api3Chain) => api3Chain.id === chain.id)!)
10+
.filter((chain) => !chain.testnet)
11+
.filter((chain) => chain.alias !== 'oev-network')
12+
.map((chain) => chain.name)
13+
.sort((a, b) => a.localeCompare(b));
14+
15+
test('the auction length section lists all the supported chains', () => {
16+
const docPath = path.join(
17+
process.cwd(),
18+
'docs',
19+
'oev-searchers',
20+
'in-depth',
21+
'oev-auctioneer.md'
22+
);
23+
const content = fs.readFileSync(docPath, 'utf8');
24+
25+
const chains = extractContentBetweenMarkers(content, 'chain-auction-length-table')
26+
.split('\n')
27+
.filter(Boolean) // Get rid of blank lines
28+
.slice(2) // Get rid of the header rows
29+
.map((row) => row.split('|')[1].trim());
30+
31+
expect(chains).toStrictEqual(supportedMainnets);
32+
});
33+
34+
function extractContentBetweenMarkers(content: string, key: string) {
35+
const beginMarker = `<!-- BEGIN:${key} -->`;
36+
const endMarker = `<!-- END:${key} -->`;
37+
const beginIndex = content.indexOf(beginMarker);
38+
const endIndex = content.indexOf(endMarker);
39+
if (beginIndex === -1 || endIndex === -1) {
40+
throw new Error(`Could not find markers "${beginMarker}" and "${endMarker}"`);
41+
}
42+
return content.slice(beginIndex + beginMarker.length, endIndex).trim();
43+
}

package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,17 @@
1111
"docs:serve": "vitepress serve docs --port 8082",
1212
"format": "prettier --write --cache \"./**/*.{js,vue,md,json,yaml}\" --log-level silent",
1313
"format:check": "prettier --check --cache \"./**/*.{js,vue,md,json,yaml}\"",
14+
"lint": "pnpm format:check && pnpm lint:tsc",
15+
"lint:tsc": "pnpm tsc",
16+
"test": "vitest run",
1417
"generate-llms-files": "node scripts/generate-llms-files.js",
1518
"prepare": "husky",
1619
"firebase:emulator": "pnpm docs:build; firebase emulators:start"
1720
},
1821
"devDependencies": {
22+
"@api3/contracts": "^27.0.0",
23+
"@api3/dapi-management": "^3.48.0",
24+
"@types/node": "^22.18.0",
1925
"axios": "^1.11.0",
2026
"colors": "^1.4.0",
2127
"file": "^0.2.2",
@@ -24,7 +30,9 @@
2430
"medium-zoom": "^1.1.0",
2531
"oust": "^2.0.4",
2632
"prettier": "^3.6.2",
33+
"typescript": "^5.9.2",
2734
"vitepress": "1.6.4",
35+
"vitest": "^3.2.4",
2836
"walk-sync": "^3.0.0"
2937
}
3038
}

0 commit comments

Comments
 (0)