Skip to content

Commit fba0df1

Browse files
swellanderescottalexander
authored andcommitted
minor text and formatting changes
1 parent 269dc6f commit fba0df1

File tree

1 file changed

+95
-64
lines changed

1 file changed

+95
-64
lines changed

README.md

Lines changed: 95 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ Oracles are bridges between blockchains and the external world. They solve a fun
4646

4747
## Checkpoint 0: 📦 Environment 📚
4848

49-
🛠️ Before you begin, you need to install the following tools:
49+
🛠️ Before you begin, make sure you have the following tools installed:
5050

5151
- [Node (>=20.18.3)](https://nodejs.org/en/download/)
5252
- Yarn ([v1](https://classic.yarnpkg.com/en/docs/install/) or [v2+](https://yarnpkg.com/getting-started/install))
@@ -98,19 +98,19 @@ yarn start
9898

9999
## Checkpoint 1: 🏛️ Whitelist Oracle Overview
100100

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.
102102

103103
💰 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.
104104

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.
106106

107107
### Core Components
108108

109109
1. 🔗 **SimpleOracle (`SimpleOracle.sol`)**
110110

111111
- 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)
112112

113-
- Each SimpleOracle represents one trusted data source
113+
- Each SimpleOracle instance represents one trusted data source
114114

115115
2. 🏛️ **WhitelistOracle (`WhitelistOracle.sol`)**
116116

@@ -140,15 +140,15 @@ yarn start
140140

141141
1. **`setPrice(uint256 _newPrice)`** - This function allows the contract owner to update the current price
142142

143-
* 🔄 Updates the `price` state variable with the new value
143+
* 🔄 Updates the `price` state variable with the new value
144144

145-
* ⏱️ Updates the `timestamp` to the current block timestamp
145+
* ⏱️ Updates the `timestamp` to the current block timestamp
146146

147-
* 📣 Emits the `PriceUpdated` event with the new price
147+
* 📣 Emits the `PriceUpdated` event with the new price
148148

149149
2. **`getPrice()`** - This function returns both the current price and timestamp
150150

151-
* ↩️ Returns them as a tuple: `(price, timestamp)`
151+
* ↩️ Returns them as a tuple: `(price, timestamp)`
152152

153153
#### 🤔 Key Insights:
154154

@@ -166,7 +166,7 @@ The `WhitelistOracle` contract **aggregates data from multiple SimpleOracle cont
166166

167167
```solidity
168168
169-
SimpleOracle[] public oracles; *// Array of SimpleOracle contracts*
169+
SimpleOracle[] public oracles; // Array of SimpleOracle contract instances
170170
171171
```
172172

@@ -179,33 +179,33 @@ SimpleOracle[] public oracles; *// Array of SimpleOracle contracts*
179179

180180
1. **`addOracle(address oracle)`** - Adds a SimpleOracle contract to the whitelist
181181

182-
* ✔️ Validates the oracle address is not zero
182+
* ✔️ Validates the oracle address is not zero
183183

184-
* 🧪 Checks for duplicates in the existing list
184+
* 🧪 Checks for duplicates in the existing list
185185

186-
* ➕ Adds the SimpleOracle to the `oracles` array
186+
* ➕ Adds the SimpleOracle to the `oracles` array
187187

188-
* 📣 Emits the `OracleAdded` event
188+
* 📣 Emits the `OracleAdded` event
189189

190190
2. **`removeOracle(uint256 index)`** - Removes a SimpleOracle from the whitelist
191191

192-
* ✔️ Validates the index is within bounds
192+
* ✔️ Validates the index is within bounds
193193

194-
* ➖ Efficiently removes the oracle (swaps with last element)
194+
* ➖ Efficiently removes the oracle (swaps with last element)
195195

196-
* 📣 Emits the `OracleRemoved` event
196+
* 📣 Emits the `OracleRemoved` event
197197

198198
3. **`getPrice()`** - Aggregates prices from all whitelisted SimpleOracle contracts
199199

200-
* 🔁 Loops through each SimpleOracle in the whitelist
200+
* 🔁 Loops through each SimpleOracle in the whitelist
201201

202-
* 📡 Calls `getPrice()` on each SimpleOracle to get `(price, timestamp)`
202+
* 📡 Calls `getPrice()` on each SimpleOracle to get `(price, timestamp)`
203203

204-
* 🧹 Filters out stale prices (older than 10 seconds)
204+
* 🧹 Filters out stale prices (older than 10 seconds)
205205

206-
* 🧮 Calculates the median of valid prices
206+
* ⛔️ Reverts if all prices are stale
207207

208-
* ⛔️ Reverts if no valid prices are available
208+
* 🧮 Calculates the median of valid prices
209209

210210
#### 🤔 Key Insights:
211211

@@ -254,29 +254,27 @@ WhitelistOracle → getPrice() → [100, 102, 98] → median(100) → 100
254254

255255
<summary>💡 Click to see potential vulnerabilities</summary>
256256

257-
- *Main Attack Vectors:**
257+
1. 🔓 **Whitelist Authority Compromise**: If the owner's private key is compromised, an attacker could:
258258

259-
1. **Whitelist Authority Compromise**: If the owner's private key is compromised, an attacker could:
259+
- Remove all legitimate oracles and add malicious ones
260260

261-
- Remove all legitimate oracles and add malicious ones
261+
- Manipulate which data sources are trusted
262262

263-
- Manipulate which data sources are trusted
263+
- Add multiple oracles they control to skew the median
264264

265-
- Add multiple oracles they control to skew the median
265+
2. 👥 **Collusion Among Whitelisted Providers**: If enough whitelisted oracle providers collude, they could:
266266

267-
2. **Collusion Among Whitelisted Providers**: If enough whitelisted oracle providers collude, they could:
267+
- Report coordinated false prices to manipulate the median
268268

269-
- Report coordinated false prices to manipulate the median
269+
- Extract value from protocols relying on the oracle
270270

271-
- Extract value from protocols relying on the oracle
271+
3. 🔓 **Data Provider Compromise**: Individual SimpleOracle operators could:
272272

273-
3. **Data Provider Compromise**: Individual SimpleOracle operators could:
273+
- Be hacked or coerced to report false prices
274274

275-
- Be hacked or coerced to report false prices
275+
- Sell their influence to manipulators
276276

277-
- Sell their influence to manipulators
278-
279-
- *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!
280278

281279
</details>
282280

@@ -312,53 +310,79 @@ yarn simulate:whitelist
312310

313311
🔍 Open the `packages/hardhat/contracts/01_Staking/StakingOracle.sol` file to examine the staking oracle implementation.
314312

315-
### 📖 Understanding the Code:
313+
#### 📖 Understanding the Code:
316314

317315
🧩 The `StakingOracle` contract implements a decentralized economic incentive model:
318316

319317
1. **`registerNode(uint256 initialPrice)`** - Allows users to register as oracle nodes
320318

321-
* ⚠️ Requires a minimum stake of 1 ETH
319+
* ⚠️ Requires a minimum stake of 1 ETH
322320

323-
* 🧪 Checks that the node is not already registered
321+
* 🧪 Checks that the node is not already registered
324322

325-
* 🏗️ Creates a new `OracleNode` struct with the provided data
323+
* 🏗️ Creates a new `OracleNode` struct with the provided data
326324

327-
* ➕ Adds the node to the `nodeAddresses` array
325+
* ➕ Adds the node to the `nodeAddresses` array
328326

329-
* 📣 Emits the `NodeRegistered` and `PriceReported` events
327+
* 📣 Emits the `NodeRegistered` and `PriceReported` events
330328

331329
2. **`reportPrice(uint256 price)`** - Allows registered nodes to report new prices
332330

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
334352

335-
* 🔍 Verifies the node has sufficient stake
353+
* 🧪 Checks that the caller is a registered node
336354

337-
* 🔄 Updates the node's last reported price and timestamp
355+
* 🔍 Calculates reward amount based on time elapsed since last claim
338356

339-
* 📣 Emits the `PriceReported` event
357+
* 💰 For active nodes (sufficient stake): rewards based on time since last claim
340358

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
342360

343-
* 🔎 Identifies nodes with stale data (older than 5 seconds)
361+
* 🎁 Mints ORA tokens as rewards (time-based, scaled by 10^18)
344362

345-
* ✂️ Slashes each stale node by 1 ETH
363+
* 📣 Emits the `NodeRewarded` event
346364

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
348366

349-
* 📣 Emits the `NodeSlashed` event for each slashed node
367+
* 🔎 Identifies nodes with stale data (older than 5 seconds)
350368

351-
4. **`getPrice()`** - Aggregates prices from all active nodes
369+
* ✂️ Slashes each stale node by 1 ETH
352370

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
354372

355-
* 🧹 Filters out nodes with stale data
373+
* 📣 Emits the `NodeSlashed` event for each slashed node
356374

357-
* 🧮 Calculates the median of all valid prices
375+
6. **`getPrice()`** - Aggregates prices from all active nodes
358376

359-
* ⛔️ Reverts if no valid prices are available
377+
* 📦 Collects prices from all active nodes
360378

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:**
362386

363387
- **Economic Incentives**: Nodes stake ETH and can be slashed for bad behavior, where in contrast, good behavior rewards the nodes with ORA token
364388
- **Decentralized**: Anyone can participate by staking, no central authority needed
@@ -378,7 +402,7 @@ yarn simulate:staking
378402

379403
🤖 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.
380404

381-
### 🥅 Goals:
405+
**### 🥅 Goals:**
382406

383407
- Understand how economic incentives drive honest behavior
384408
- See how slashing mechanisms enforce data freshness
@@ -447,7 +471,7 @@ sequenceDiagram
447471

448472
🔍 Open the `packages/hardhat/contracts/02_Optimistic/OptimisticOracle.sol` file to implement the optimistic oracle functionality.
449473

450-
### ✏️ Tasks:
474+
**### ✏️ Tasks:**
451475

452476
1. **Implement `assertEvent(string memory description, uint256 startTime, uint256 endTime)`**
453477

@@ -478,7 +502,7 @@ Here are more granular instructions on setting up the EventAssertion struct:
478502
- reward should be `msg.value`
479503
- bond should be `FIXED_BOND`
480504
- startTime = `startTime`
481-
- endTime = `endTime`
505+
- endTime = `endTIme`
482506
- description = `description`
483507
- any remaining properties can be initialized with the default values (`false`, `address(0)`, etc.)
484508

@@ -791,7 +815,7 @@ This function enables the asserter to get a refund of their posted reward when n
791815

792816
This is the method that the decider will call to settle whether the proposer or disputer are correct.
793817

794-
It should be:
818+
It should be;
795819

796820
* 🧑‍⚖️ Only callable by the `decider` contract
797821

@@ -949,7 +973,7 @@ yarn simulate:optimistic
949973

950974
🤖 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.
951975

952-
### 🥅 Goals:
976+
**### 🥅 Goals:**
953977

954978
- Users can assert events with descriptions and time windows
955979
- Users can propose outcomes for asserted events
@@ -963,16 +987,23 @@ yarn simulate:optimistic
963987

964988
🧠 Now let's analyze the strengths and weaknesses of each oracle design.
965989

966-
### 📊 Comparison Table:
990+
**### 📊 Comparison Table:**
991+
967992
| Aspect | Whitelist Oracle | Staking Oracle | Optimistic Oracle |
993+
968994
|--------|------------------|----------------|-------------------|
995+
969996
| **Speed** | Fast | Medium | Slow |
997+
970998
| **Security** | Low (trusted authority) | Medium (economic incentives) | High (dispute resolution) |
999+
9711000
| **Decentralization** | Low | High | Medium |
1001+
9721002
| **Cost** | Low | Medium | High |
1003+
9731004
| **Complexity** | Simple | Medium | Complex |
9741005

975-
### 🤔 Key Trade-offs:
1006+
**### 🤔 Key Trade-offs:**
9761007

9771008
1. **Whitelist Oracle:**
9781009

@@ -1006,7 +1037,7 @@ yarn simulate:optimistic
10061037

10071038
- ❌ More complex
10081039

1009-
### 🎯 Understanding the "Why":
1040+
**### 🎯 Understanding the "Why":**
10101041

10111042
Each oracle design solves different problems:
10121043

@@ -1052,7 +1083,7 @@ Each oracle design solves different problems:
10521083
10531084
> 🦊 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/`)
10541085
1055-
#### Configuration of Third-Party Services for Production-Grade Apps.
1086+
**#### Configuration of Third-Party Services for Production-Grade Apps.**
10561087

10571088
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.
10581089

0 commit comments

Comments
 (0)