Skip to content

Commit deef735

Browse files
authored
Upgrade StaderOracle implementation (#258)
* forge install: openzeppelin-foundry-upgrades v0.3.6 * feat: change min ONO requirement * chore: update equality check to more broader * feat: update consensus of sd price match
1 parent c2b620a commit deef735

File tree

4 files changed

+39
-39
lines changed

4 files changed

+39
-39
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
[submodule "lib/forge-std"]
22
path = lib/forge-std
33
url = https://github.com/foundry-rs/forge-std
4+
[submodule "lib/openzeppelin-foundry-upgrades"]
5+
path = lib/openzeppelin-foundry-upgrades
6+
url = https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades

contracts/StaderOracle.sol

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ contract StaderOracle is IStaderOracle, AccessControlUpgradeable, PausableUpgrad
2929
uint256 public constant MAX_ER_UPDATE_FREQUENCY = 7200 * 7; // 7 days
3030
uint256 public constant ER_CHANGE_MAX_BPS = 10_000;
3131
uint256 public override erChangeLimit;
32-
uint256 public constant MIN_TRUSTED_NODES = 5;
32+
uint256 public constant MIN_TRUSTED_NODES = 3;
3333
uint256 public override trustedNodeChangeCoolingPeriod;
3434

3535
/// @inheritdoc IStaderOracle
@@ -119,6 +119,9 @@ contract StaderOracle is IStaderOracle, AccessControlUpgradeable, PausableUpgrad
119119
if (block.number < lastTrustedNodeCountChangeBlock + trustedNodeChangeCoolingPeriod) {
120120
revert CooldownNotComplete();
121121
}
122+
if (trustedNodesCount <= MIN_TRUSTED_NODES) {
123+
revert InsufficientTrustedNodes();
124+
}
122125
lastTrustedNodeCountChangeBlock = block.number;
123126

124127
isTrustedNode[_nodeAddress] = false;
@@ -304,8 +307,7 @@ contract StaderOracle is IStaderOracle, AccessControlUpgradeable, PausableUpgrad
304307
// Emit SD Price submitted event
305308
emit SDPriceSubmitted(msg.sender, _sdPriceData.sdPriceInETH, _sdPriceData.reportingBlockNumber, block.number);
306309

307-
// price can be derived once more than 66% percent oracles have submitted price
308-
if ((submissionCount >= (2 * trustedNodesCount) / 3 + 1)) {
310+
if ((submissionCount >= trustedNodesCount / 2 + 1)) {
309311
lastReportedSDPriceData = _sdPriceData;
310312
lastReportedSDPriceData.sdPriceInETH = getMedianValue(sdPrices);
311313

test/foundry_tests/StaderOracle.t.sol

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ contract StaderOracleTest is Test {
125125
}
126126

127127
function test_add_remove_trustedNode() public {
128+
// Tests for adding nodes
128129
address trustedNode = vm.addr(123);
129130
assertEq(staderOracle.trustedNodesCount(), 0);
130131
assertFalse(staderOracle.isTrustedNode(trustedNode));
@@ -139,16 +140,6 @@ contract StaderOracleTest is Test {
139140
assertEq(staderOracle.trustedNodesCount(), 1);
140141
assertTrue(staderOracle.isTrustedNode(trustedNode));
141142

142-
vm.expectRevert(IStaderOracle.NodeNotTrusted.selector);
143-
vm.prank(staderManager);
144-
staderOracle.removeTrustedNode(vm.addr(567));
145-
146-
vm.prank(staderManager);
147-
staderOracle.removeTrustedNode(trustedNode);
148-
149-
assertEq(staderOracle.trustedNodesCount(), 0);
150-
assertFalse(staderOracle.isTrustedNode(trustedNode));
151-
152143
// lets update trustedNode cooling period
153144
vm.expectRevert(UtilLib.CallerNotManager.selector);
154145
staderOracle.updateTrustedNodeChangeCoolingPeriod(100);
@@ -157,22 +148,36 @@ contract StaderOracleTest is Test {
157148
staderOracle.updateTrustedNodeChangeCoolingPeriod(100);
158149

159150
vm.expectRevert(IStaderOracle.CooldownNotComplete.selector);
160-
staderOracle.addTrustedNode(vm.addr(78));
151+
staderOracle.addTrustedNode(vm.addr(77));
161152

162-
// wait for 100 blocks
153+
// wait for 100 blocks each time to add node
154+
vm.roll(block.number + 100);
155+
staderOracle.addTrustedNode(vm.addr(77));
163156
vm.roll(block.number + 100);
164157
staderOracle.addTrustedNode(vm.addr(78));
165-
assertEq(staderOracle.trustedNodesCount(), 1);
158+
vm.roll(block.number + 100);
159+
staderOracle.addTrustedNode(vm.addr(79));
160+
assertEq(staderOracle.trustedNodesCount(), 4);
161+
assertTrue(staderOracle.isTrustedNode(vm.addr(77)));
166162
assertTrue(staderOracle.isTrustedNode(vm.addr(78)));
163+
assertTrue(staderOracle.isTrustedNode(vm.addr(79)));
164+
165+
// Tests for removing nodes
166+
vm.expectRevert(IStaderOracle.NodeNotTrusted.selector);
167+
staderOracle.removeTrustedNode(vm.addr(567));
167168

168169
vm.expectRevert(IStaderOracle.CooldownNotComplete.selector);
169-
staderOracle.removeTrustedNode(vm.addr(78));
170+
staderOracle.removeTrustedNode(vm.addr(77));
170171

171172
// wait for 100 blocks
172173
vm.roll(block.number + 100);
174+
staderOracle.removeTrustedNode(vm.addr(77));
175+
assertEq(staderOracle.trustedNodesCount(), 3);
176+
assertFalse(staderOracle.isTrustedNode(vm.addr(77)));
177+
178+
vm.roll(block.number + 100);
179+
vm.expectRevert(IStaderOracle.InsufficientTrustedNodes.selector);
173180
staderOracle.removeTrustedNode(vm.addr(78));
174-
assertEq(staderOracle.trustedNodesCount(), 0);
175-
assertFalse(staderOracle.isTrustedNode(vm.addr(78)));
176181
vm.stopPrank();
177182
}
178183

@@ -189,7 +194,7 @@ contract StaderOracleTest is Test {
189194
vm.expectRevert(IStaderOracle.InsufficientTrustedNodes.selector);
190195
staderOracle.submitSDPrice(sdPriceData);
191196

192-
assertEq(staderOracle.MIN_TRUSTED_NODES(), 5);
197+
assertEq(staderOracle.MIN_TRUSTED_NODES(), 3);
193198
address trustedNode2 = vm.addr(702);
194199
address trustedNode3 = vm.addr(703);
195200
address trustedNode4 = vm.addr(704);
@@ -307,17 +312,12 @@ contract StaderOracleTest is Test {
307312
vm.prank(trustedNode3);
308313
staderOracle.submitSDPrice(sdPriceData);
309314

310-
sdPriceData.reportingBlockNumber = 5 * 7200;
311-
sdPriceData.sdPriceInETH = 4;
312-
vm.prank(trustedNode4);
313-
staderOracle.submitSDPrice(sdPriceData);
314-
315315
// now consensus is met for reporting block num 5 * 7200
316316
// trustedNode1 manipulated the sd price if other oracles are not wrking properly
317-
// sdPrice submited were [1,6,2,4] => hence median = (2+4)/2 = 3
317+
// sdPrice submited were [1,6,2] => hence median = 2
318318
(lastSDReportingBlockNumber, lastSDPrice) = staderOracle.lastReportedSDPriceData();
319319
assertEq(lastSDReportingBlockNumber, 5 * 7200);
320-
assertEq(lastSDPrice, 3);
320+
assertEq(lastSDPrice, 2);
321321

322322
// trusted node 5 tries to submit at reportable block 5 * 7200
323323
sdPriceData.reportingBlockNumber = 5 * 7200;
@@ -330,7 +330,7 @@ contract StaderOracleTest is Test {
330330
function test_submitSDPrice_manipulation_not_possible_by_minority_malicious_oracles() public {
331331
SDPriceData memory sdPriceData = SDPriceData({ reportingBlockNumber: 1212, sdPriceInETH: 1 });
332332

333-
assertEq(staderOracle.MIN_TRUSTED_NODES(), 5);
333+
assertEq(staderOracle.MIN_TRUSTED_NODES(), 3);
334334
address trustedNode1 = vm.addr(701);
335335
address trustedNode2 = vm.addr(702);
336336
address trustedNode3 = vm.addr(703);
@@ -355,9 +355,6 @@ contract StaderOracleTest is Test {
355355
vm.prank(trustedNode2);
356356
staderOracle.submitSDPrice(sdPriceData);
357357

358-
vm.prank(trustedNode3);
359-
staderOracle.submitSDPrice(sdPriceData);
360-
361358
// cycle 2
362359
vm.roll(2 * 7200 + 1);
363360
sdPriceData.reportingBlockNumber = 2 * 7200;
@@ -369,9 +366,6 @@ contract StaderOracleTest is Test {
369366
vm.prank(trustedNode2);
370367
staderOracle.submitSDPrice(sdPriceData);
371368

372-
vm.prank(trustedNode3);
373-
staderOracle.submitSDPrice(sdPriceData);
374-
375369
// trustedNode4 submits for cycle 1
376370
sdPriceData.reportingBlockNumber = 1 * 7200;
377371
sdPriceData.sdPriceInETH = 1;
@@ -800,7 +794,7 @@ contract StaderOracleTest is Test {
800794
totalETHXSupply: 100
801795
});
802796

803-
assertEq(staderOracle.MIN_TRUSTED_NODES(), 5);
797+
assertEq(staderOracle.MIN_TRUSTED_NODES(), 3);
804798
address trustedNode1 = vm.addr(701);
805799
address trustedNode2 = vm.addr(702);
806800
address trustedNode3 = vm.addr(703);
@@ -1007,7 +1001,7 @@ contract StaderOracleTest is Test {
10071001
sortedInvalidSignaturePubkeys: invalidSignaturePubkeys
10081002
});
10091003

1010-
assertEq(staderOracle.MIN_TRUSTED_NODES(), 5);
1004+
assertEq(staderOracle.MIN_TRUSTED_NODES(), 3);
10111005
address trustedNode1 = vm.addr(701);
10121006
address trustedNode2 = vm.addr(702);
10131007
address trustedNode3 = vm.addr(703);
@@ -1082,7 +1076,7 @@ contract StaderOracleTest is Test {
10821076
sortedPubkeys: sortedPubkeys
10831077
});
10841078

1085-
assertEq(staderOracle.MIN_TRUSTED_NODES(), 5);
1079+
assertEq(staderOracle.MIN_TRUSTED_NODES(), 3);
10861080
address trustedNode1 = vm.addr(701);
10871081
address trustedNode2 = vm.addr(702);
10881082
address trustedNode3 = vm.addr(703);
@@ -1162,7 +1156,7 @@ contract StaderOracleTest is Test {
11621156
sortedPubkeys: sortedPubkeys
11631157
});
11641158

1165-
assertEq(staderOracle.MIN_TRUSTED_NODES(), 5);
1159+
assertEq(staderOracle.MIN_TRUSTED_NODES(), 3);
11661160
address trustedNode1 = vm.addr(701);
11671161
address trustedNode2 = vm.addr(702);
11681162
address trustedNode3 = vm.addr(703);
@@ -1232,7 +1226,7 @@ contract StaderOracleTest is Test {
12321226
slashedValidatorsCount: 4
12331227
});
12341228

1235-
assertEq(staderOracle.MIN_TRUSTED_NODES(), 5);
1229+
assertEq(staderOracle.MIN_TRUSTED_NODES(), 3);
12361230
address trustedNode1 = vm.addr(701);
12371231
address trustedNode2 = vm.addr(702);
12381232
address trustedNode3 = vm.addr(703);

0 commit comments

Comments
 (0)