This repository has been archived by the owner on Oct 8, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 32
/
Copy pathIDEAS.txt
94 lines (72 loc) · 2.8 KB
/
IDEAS.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
bytes32
uint128 val
uint64 age
bytes sig
uint128[] val, uint64[] age, bytes[] sig (== length)
med
uint128 val
uint64 age <-- timestamp now
Mapping of authorized oracles
Each oracle signs price data (ETH_USD) every minute (second?) and broadcasts it via scuttlebot or whatever, maybe posts it somewhere or exposes it as an API. We can have as many as we want, and this part is all off-chain.
Oracles sign messages as such: (maybe with EIP712 eth_signTypedData)
`uint128 val, uint64 age` (there's room for a uint64 here for something else)
So in the end, every oracle submits:
```
{
uint128 val,
uint64 age,
bytes sig
}
```
Feedbots grab these messages, get enough valid ones (at least the minimum required by Medianizer) and do these steps:
1. Order every feed by value, lowest to highest
2. Calculate the median off-chain
3. Send transaction to the blockchain Medianizer (anyone can do this)
4. Medianizer on-chain does the following (code not tested)
```
// Medianizer values
uint128 val;
uint64 age;
uint64 ???; // room for something here maybe
uint8 min; // minimum valid feeds
// Authorized oracles, set by an auth
mapping (address => bool) oracles;
function poke(uint128 med_, uint128[] val_, uint64[] age_, bytes[] sig) {
// One val, age and sig per feed
require(val_.length == age_.length);
require(age_.length == sig_.length);
// At least min feeds
require(val_.length >= min);
var length = val_.length;
for (uint i = 0; i < length; i++) {
// Validate the values were signed by an authorized oracle
// ecverify does some ecrecover magic
address signer = ecverify(keccak256(val_[i], age_[i], sig_[i]));
require(oracles[signer]);
// Price feed age greater than last medianizer age
require(age_[i] > age);
// Check for ordered values (TODO: add array out of bounds check!)
require(val_[i] <= val_[i + 1]);
}
// Calculate median (we required values were already ordered)
if (length % 2 == 0) {
// Even number of feeds, grab middle ones and average
uint128 one = val_[(length / 2) - 1];
uint128 two = val_[length / 2];
// Check the median value provided is accurate
require(med_ == wdiv(add(one, two)));
} else {
// Grab middle value, check if it's accurate
require(med_ == val_((length - 1) / 2));
}
// Write the value and timestamp to storage
val = med_;
age = uint64(block.timestamp);
LogPrice(val, age); // some event
}
```
This accomplishes the following:
- Oracles can sign as many messages as they want
- Anyone can update the medianizer (we can incentivize people)
- Validity of medianizer price can be handled elsewhere maybe? It just tells you price and last update time
- One transaction per update, instead of one per oracle