You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- Yarn ([v1](https://classic.yarnpkg.com/en/docs/install/) or [v2+](https://yarnpkg.com/getting-started/install))
@@ -98,19 +98,19 @@ yarn start
98
98
99
99
## Checkpoint 1: 🏛️ Whitelist Oracle Overview
100
100
101
-
🔍 Let's start the simplest of the three oracle designs we'll cover: the Whitelist Oracle. This design uses a centralized authority to control which data sources can provide information, making it simple and fast but requiring trust.
101
+
🔍 Let's start with the simplest of the three oracle designs we'll cover: the Whitelist Oracle. This design uses a centralized authority to control which data sources can provide information, making it simple and fast but requiring trust.
102
102
103
103
💰 The implementation we'll be looking at is a **price** oracle. Price oracles are one of the most common and critical types of oracles in DeFi, as they enable smart contracts to make decisions based on real-world asset prices. Our whitelist price oracle collects price reports from multiple trusted sources (instances of `SimpleOracle`) and returns their median value.
104
104
105
-
🗂️ The whitelist oracle contracts are located in `packages/hardhat/contracts`. Go check them out and reference the following descriptions.
105
+
🗂️ The whitelist oracle contracts are located in `packages/hardhat/contracts/00_Whitelist/`. Go check them out and reference the following descriptions.
106
106
107
107
### Core Components
108
108
109
109
1. 🔗 **SimpleOracle (`SimpleOracle.sol`)**
110
110
111
111
- Basic oracle contract that allows price updates from the contract owner (We have commented out the onlyOwner modifier to allow you to impersonate the owner)
112
112
113
-
- Each SimpleOracle represents one trusted data source
113
+
- Each SimpleOracle instance represents one trusted data source
114
114
115
115
2. 🏛️ **WhitelistOracle (`WhitelistOracle.sol`)**
116
116
@@ -140,15 +140,15 @@ yarn start
140
140
141
141
1.**`setPrice(uint256 _newPrice)`** - This function allows the contract owner to update the current price
142
142
143
-
* 🔄 Updates the `price` state variable with the new value
143
+
* 🔄 Updates the `price` state variable with the new value
144
144
145
-
* ⏱️ Updates the `timestamp` to the current block timestamp
145
+
* ⏱️ Updates the `timestamp` to the current block timestamp
146
146
147
-
* 📣 Emits the `PriceUpdated` event with the new price
147
+
* 📣 Emits the `PriceUpdated` event with the new price
148
148
149
149
2.**`getPrice()`** - This function returns both the current price and timestamp
150
150
151
-
* ↩️ Returns them as a tuple: `(price, timestamp)`
151
+
* ↩️ Returns them as a tuple: `(price, timestamp)`
152
152
153
153
#### 🤔 Key Insights:
154
154
@@ -166,7 +166,7 @@ The `WhitelistOracle` contract **aggregates data from multiple SimpleOracle cont
166
166
167
167
```solidity
168
168
169
-
SimpleOracle[] public oracles; *// Array of SimpleOracle contracts*
169
+
SimpleOracle[] public oracles; // Array of SimpleOracle contract instances
170
170
171
171
```
172
172
@@ -179,33 +179,33 @@ SimpleOracle[] public oracles; *// Array of SimpleOracle contracts*
179
179
180
180
1.**`addOracle(address oracle)`** - Adds a SimpleOracle contract to the whitelist
181
181
182
-
* ✔️ Validates the oracle address is not zero
182
+
* ✔️ Validates the oracle address is not zero
183
183
184
-
* 🧪 Checks for duplicates in the existing list
184
+
* 🧪 Checks for duplicates in the existing list
185
185
186
-
* ➕ Adds the SimpleOracle to the `oracles` array
186
+
* ➕ Adds the SimpleOracle to the `oracles` array
187
187
188
-
* 📣 Emits the `OracleAdded` event
188
+
* 📣 Emits the `OracleAdded` event
189
189
190
190
2.**`removeOracle(uint256 index)`** - Removes a SimpleOracle from the whitelist
191
191
192
-
* ✔️ Validates the index is within bounds
192
+
* ✔️ Validates the index is within bounds
193
193
194
-
* ➖ Efficiently removes the oracle (swaps with last element)
194
+
* ➖ Efficiently removes the oracle (swaps with last element)
195
195
196
-
* 📣 Emits the `OracleRemoved` event
196
+
* 📣 Emits the `OracleRemoved` event
197
197
198
198
3.**`getPrice()`** - Aggregates prices from all whitelisted SimpleOracle contracts
199
199
200
-
* 🔁 Loops through each SimpleOracle in the whitelist
200
+
* 🔁 Loops through each SimpleOracle in the whitelist
201
201
202
-
* 📡 Calls `getPrice()` on each SimpleOracle to get `(price, timestamp)`
202
+
* 📡 Calls `getPrice()` on each SimpleOracle to get `(price, timestamp)`
203
203
204
-
* 🧹 Filters out stale prices (older than 10 seconds)
204
+
* 🧹 Filters out stale prices (older than 10 seconds)
-*Real-World Impact**: These vulnerabilities explain why protocols like [MakerDAO/Sky](https://github.com/sky-ecosystem/medianizer) eventually moved to more decentralized oracle systems as the stakes grew higher!
277
+
💡 *Real-World Impact*: These vulnerabilities explain why protocols like [MakerDAO/Sky](https://github.com/sky-ecosystem/medianizer) eventually moved to more decentralized oracle systems as the stakes grew higher!
280
278
281
279
</details>
282
280
@@ -312,53 +310,79 @@ yarn simulate:whitelist
312
310
313
311
🔍 Open the `packages/hardhat/contracts/01_Staking/StakingOracle.sol` file to examine the staking oracle implementation.
314
312
315
-
### 📖 Understanding the Code:
313
+
####📖 Understanding the Code:
316
314
317
315
🧩 The `StakingOracle` contract implements a decentralized economic incentive model:
318
316
319
317
1.**`registerNode(uint256 initialPrice)`** - Allows users to register as oracle nodes
320
318
321
-
* ⚠️ Requires a minimum stake of 1 ETH
319
+
* ⚠️ Requires a minimum stake of 1 ETH
322
320
323
-
* 🧪 Checks that the node is not already registered
321
+
* 🧪 Checks that the node is not already registered
324
322
325
-
* 🏗️ Creates a new `OracleNode` struct with the provided data
323
+
* 🏗️ Creates a new `OracleNode` struct with the provided data
326
324
327
-
* ➕ Adds the node to the `nodeAddresses` array
325
+
* ➕ Adds the node to the `nodeAddresses` array
328
326
329
-
* 📣 Emits the `NodeRegistered` and `PriceReported` events
327
+
* 📣 Emits the `NodeRegistered` and `PriceReported` events
330
328
331
329
2.**`reportPrice(uint256 price)`** - Allows registered nodes to report new prices
332
330
333
-
* 🧪 Checks that the caller is a registered node
331
+
* 🧪 Checks that the caller is a registered node
332
+
333
+
* 🔍 Verifies the node has sufficient stake
334
+
335
+
* 🔄 Updates the node's last reported price and timestamp
336
+
337
+
* 📣 Emits the `PriceReported` event
338
+
339
+
3.**`separateStaleNodes(address[] memory nodesToSeparate)`** - Categorizes nodes into fresh and stale based on data recency
340
+
341
+
* 📦 Takes an array of node addresses to categorize
342
+
343
+
* ⏱️ Checks each node's last reported timestamp against `STALE_DATA_WINDOW` (5 seconds)
344
+
345
+
* 📊 Separates nodes into two arrays: fresh (recent data) and stale (old data)
346
+
347
+
* 🧹 Returns trimmed arrays containing only the relevant addresses
348
+
349
+
* 🔍 Used internally by other functions to filter active vs inactive nodes
350
+
351
+
4.**`claimReward()`** - Allows registered nodes to claim their ORA token rewards
334
352
335
-
* 🔍 Verifies the node has sufficient stake
353
+
* 🧪 Checks that the caller is a registered node
336
354
337
-
* 🔄 Updates the node's last reported price and timestamp
355
+
* 🔍 Calculates reward amount based on time elapsed since last claim
338
356
339
-
* 📣 Emits the `PriceReported` event
357
+
* 💰 For active nodes (sufficient stake): rewards based on time since last claim
340
358
341
-
3.**`slashNodes()`** - Allows anyone to slash nodes that haven't reported recently
359
+
* ⚠️ For slashed nodes (insufficient stake): limited rewards only up to when they were slashed
342
360
343
-
* 🔎 Identifies nodes with stale data (older than 5 seconds)
361
+
* 🎁 Mints ORA tokens as rewards (time-based, scaled by 10^18)
344
362
345
-
* ✂️ Slashes each stale node by 1 ETH
363
+
* 📣 Emits the `NodeRewarded` event
346
364
347
-
* 🏅 Rewards the slasher with 10% of the slashed amount so we can guarantee bad nodes are always slashed
365
+
5.**`slashNodes()`** - Allows anyone to slash nodes that haven't reported recently
348
366
349
-
* 📣 Emits the `NodeSlashed` event for each slashed node
367
+
* 🔎 Identifies nodes with stale data (older than 5 seconds)
350
368
351
-
4.**`getPrice()`** - Aggregates prices from all active nodes
369
+
* ✂️ Slashes each stale node by 1 ETH
352
370
353
-
* 📦 Collects prices from all active nodes
371
+
* 🏅 Rewards the slasher with 10% of the slashed amount so we can guarantee bad nodes are always slashed
354
372
355
-
* 🧹 Filters out nodes with stale data
373
+
* 📣 Emits the `NodeSlashed` event for each slashed node
356
374
357
-
* 🧮 Calculates the median of all valid prices
375
+
6.**`getPrice()`** - Aggregates prices from all active nodes
358
376
359
-
* ⛔️ Reverts if no valid prices are available
377
+
* 📦 Collects prices from all active nodes
360
378
361
-
### 🤔 Key Insights:
379
+
* 🧹 Filters out nodes with stale data
380
+
381
+
* 🧮 Calculates the median of all valid prices
382
+
383
+
* ⛔️ Reverts if no valid prices are available
384
+
385
+
**### 🤔 Key Insights:**
362
386
363
387
-**Economic Incentives**: Nodes stake ETH and can be slashed for bad behavior, where in contrast, good behavior rewards the nodes with ORA token
364
388
-**Decentralized**: Anyone can participate by staking, no central authority needed
@@ -378,7 +402,7 @@ yarn simulate:staking
378
402
379
403
🤖 This will start automated bots that simulate honest and malicious node behavior, frequent and stale reports, and demonstrate how slashing and median aggregation impact the reported price. You can update the price variance and skip probability from the front-end as well.
380
404
381
-
### 🥅 Goals:
405
+
**### 🥅 Goals:**
382
406
383
407
- Understand how economic incentives drive honest behavior
384
408
- See how slashing mechanisms enforce data freshness
@@ -447,7 +471,7 @@ sequenceDiagram
447
471
448
472
🔍 Open the `packages/hardhat/contracts/02_Optimistic/OptimisticOracle.sol` file to implement the optimistic oracle functionality.
@@ -478,7 +502,7 @@ Here are more granular instructions on setting up the EventAssertion struct:
478
502
- reward should be `msg.value`
479
503
- bond should be `FIXED_BOND`
480
504
- startTime = `startTime`
481
-
- endTime = `endTime`
505
+
- endTime = `endTIme`
482
506
- description = `description`
483
507
- any remaining properties can be initialized with the default values (`false`, `address(0)`, etc.)
484
508
@@ -791,7 +815,7 @@ This function enables the asserter to get a refund of their posted reward when n
791
815
792
816
This is the method that the decider will call to settle whether the proposer or disputer are correct.
793
817
794
-
It should be:
818
+
It should be;
795
819
796
820
* 🧑⚖️ Only callable by the `decider` contract
797
821
@@ -949,7 +973,7 @@ yarn simulate:optimistic
949
973
950
974
🤖 This will start automated bots that create assertions, propose outcomes, dispute proposals, and settle via the decider, so you can observe rewards, bonds, fees, and timing windows in a realistic flow.
951
975
952
-
### 🥅 Goals:
976
+
**### 🥅 Goals:**
953
977
954
978
- Users can assert events with descriptions and time windows
955
979
- Users can propose outcomes for asserted events
@@ -963,16 +987,23 @@ yarn simulate:optimistic
963
987
964
988
🧠 Now let's analyze the strengths and weaknesses of each oracle design.
|**Security**| Low (trusted authority) | Medium (economic incentives) | High (dispute resolution) |
999
+
971
1000
|**Decentralization**| Low | High | Medium |
1001
+
972
1002
|**Cost**| Low | Medium | High |
1003
+
973
1004
|**Complexity**| Simple | Medium | Complex |
974
1005
975
-
### 🤔 Key Trade-offs:
1006
+
**### 🤔 Key Trade-offs:**
976
1007
977
1008
1.**Whitelist Oracle:**
978
1009
@@ -1006,7 +1037,7 @@ yarn simulate:optimistic
1006
1037
1007
1038
- ❌ More complex
1008
1039
1009
-
### 🎯 Understanding the "Why":
1040
+
**### 🎯 Understanding the "Why":**
1010
1041
1011
1042
Each oracle design solves different problems:
1012
1043
@@ -1052,7 +1083,7 @@ Each oracle design solves different problems:
1052
1083
1053
1084
> 🦊 Since we have deployed to a public testnet, you will now need to connect using a wallet you own or use a burner wallet. By default 🔥 `burner wallets` are only available on `hardhat` . You can enable them on every chain by setting `onlyLocalBurnerWallet: false` in your frontend config (`scaffold.config.ts` in `packages/nextjs/`)
1054
1085
1055
-
#### Configuration of Third-Party Services for Production-Grade Apps.
1086
+
**#### Configuration of Third-Party Services for Production-Grade Apps.**
1056
1087
1057
1088
By default, 🏗 Scaffold-ETH 2 provides predefined API keys for popular services such as Alchemy and Etherscan. This allows you to begin developing and testing your applications more easily, avoiding the need to register for these services.
0 commit comments