-
Notifications
You must be signed in to change notification settings - Fork 1
KingNFT - Keepers will suffer significant losses due to miss compensation for L1 rollup fees #91
Comments
1 comment(s) were left on this issue during the judging contest. 141345 commented:
|
The |
Escalate Using CurrentL1GasPrice = 20 Gwei // it refers to smoothed recent Ethereum gas price provided by L2 system contract
CurretnL2GasPrice = 2 Gwei // it refers to block.basefee
L1RollupGas = 40,000
L1RollupFee = L1RollupGas * CurrentL1GasPrice = 40,000 * 20 = 800,000 Gwei To compensate L1 rollup fee, we should set buffer = L1RollupFee / CurrentL2GasPrice = 800,000 / 2 = 400,000 to make L1Compensation = buffer * CurrentL2GasPrice = 400,000 * 2 = 800,000 = L1RollupFee some time later, i.e. 1 hour, gas prices change to NewL1GasPrice = 40 Gwei
NewL2GasPrice = 0.01 Gwei we can see the L1RollupFee = L1RollupGas * CurrentL1GasPrice = 40, 000 * 40 = 1,600,000 Gwei
L1Compensation = buffer * CurretnL2GasPrice = 400, 000 * 0.01 = 4,000 Gwei In contrast, if gas prices change to NewL1GasPrice = 10 Gwei
NewL2GasPrice = 2 Gwei then, the L1RollupFee = L1RollupGas * CurrentL1GasPrice = 40,000 * 10 = 400,000 Gwei
L1Compensation= buffer * CurretnL2GasPrice = 400,000 * 2 = 800,000 Gwei Therefore, regardless of how we set During periods that keepers suffer losses, they are likely to stop working and the system is blocked. About the severity: File: perennial-v2\packages\perennial\contracts\types\Order.sol
50: function registerFee(
51: Order memory self,
52: OracleVersion memory latestVersion,
53: MarketParameter memory marketParameter,
54: RiskParameter memory riskParameter
55: ) internal pure {
...
64: self.fee = self.maker.abs().mul(latestVersion.price.abs()).mul(UFixed6Lib.from(makerFee))
65: .add(self.long.abs().add(self.short.abs()).mul(latestVersion.price.abs()).mul(UFixed6Lib.from(takerFee)));
66:
67: self.keeper = isEmpty(self) ? UFixed6Lib.ZERO : marketParameter.settlementFee;
68: }
To sum up, I think it's high, not medium |
You've created a valid escalation! To remove the escalation from consideration: Delete your comment. You may delete or edit your escalation comment anytime before the 48-hour escalation window closes. After that, the escalation becomes final. |
Thanks for the thorough explanation on why a buffer won't work. We agree that we should modify the Kept function to estimate L1 gas costs, thanks for the report! |
The severity of medium seems more appropriate. Because according to sherlock's HM criteria:
Here the imbalanced L1/L2 gas fee would not be too frequent. Most of the time, the buffer will be good to compensate for the keeper. The described loss will incur when all the special conditions are met, and the fixed buffer is not enough to cover the keeper's cost. |
Fixed |
@ydspa tend to agree with this comment: |
I think the conclusion of
It will cause users' orders been held up to some hours in 2 ways: File: packages\perennial-oracle\contracts\OracleFactory.sol
93: function claim(UFixed6 amount) external {
94: if (amount.gt(maxClaim)) revert OracleFactoryClaimTooLargeError();
...
97: }
To be emphasized:
Hence, the issue is with both |
Yes the fee ratio could vary across a wide span. Extreme high L1 gas fee is intermittent, and will repeat. Still seems medium due to conditional loss. |
(1)I'm convinced that you can't find a (2) conditional loss of |
Even the distribution is Pareto distribution (power law), percentile still works. 50%, 90% can be found. |
Give your specific parameters please |
percentile always can be found, such as medium number(50%). On the opposite, mean value could be hard to find, those extreme high gas fee can make mean not converge. |
More proof: if we set buffer according The instances are all from the past one month, and sample interval is 1 hour, that's mean, averagely speaking, the system will be blocked for about 127 hours (5+ days) in one month if we set buffer according index blockHeight
0 108995426
1 108952226
2 108865826
3 108864026
4 108862226
5 108860426
6 108822626
7 108820826
8 108819026
9 108817226
10 108815426
11 108813626
12 108811826
13 108810026
14 108808226
15 108806426
16 108804626
17 108802826
18 108801026
19 108799226
20 108604826
21 108570626
22 108504026
23 108471626
24 108376226
25 108360026
26 108358226
27 108356426
28 108345626
29 108318626
30 108311426
31 108309626
32 108298826
33 108297026
34 108295226
35 108293426
36 108291626
37 108289826
38 108288026
39 108286226
40 108284426
41 108268226
42 108266426
43 108264626
44 108262826
45 108261026
46 108259226
47 108257426
48 108255626
49 108253826
50 108252026
51 108250226
52 108248426
53 108246626
54 108244826
55 108243026
56 108241226
57 108239426
58 108237626
59 108235826
60 108234026
61 108232226
62 108230426
63 108223226
64 108221426
65 108219626
66 108217826
67 108216026
68 108214226
69 108212426
70 108210626
71 108208826
72 108207026
73 108205226
74 108203426
75 108201626
76 108079226
77 107958626
78 107953226
79 107951426
80 107949626
81 107947826
82 107946026
83 107944226
84 107942426
85 107940626
86 107938826
87 107937026
88 107935226
89 107933426
90 107931626
91 107929826
92 107928026
93 107926226
94 107924426
95 107922626
96 107920826
97 107919026
98 107917226
99 107915426
100 107913626
101 107911826
102 107910026
103 107908226
104 107906426
105 107904626
106 107902826
107 107901026
108 107870426
109 107780426
110 107778626
111 107776826
112 107775026
113 107773226
114 107771426
115 107769626
116 107767826
117 107742626
118 107740826
119 107739026
120 107737226
121 107735426
122 107733626
123 107731826
124 107730026
125 107728226
126 107726426 |
The main point is, there is some parameter, considering the trade off, can balance the loss and overpayment. e8 is just an example. |
What my meaning is the parameter doesn't exist at all, mathematically speaking, Optimism Transaction Fee = [ Fee Scalar * L1 Gas Price * (Calldata + Fixed Overhead) ] + [ L2 Gas Price * L2 Gas Used ] reference: https://dune.com/haddis3/optimism-fee-calculator This is why no matter we set |
Here is a mistake in thoughts, set |
0.001, 0.02, 0.3, 4, 5, 6, 7, 8, 9, 10000. For this skewed distribution, 90% percentile is 9. |
|
My understanding, something like, it could be triggered 10-20% of the time in a certain time span, such as 1 month, 1 week. It still falls into the category with condition:
|
My understanding about the probability of issue occurrence, which i learned when i work for other audit firms, are like this: If the issue will occur even It's far away from the thought that only if a issue will keep occurring in most the time, let's say, in 2 of the 3 months, then it's high probability. So, in my opinion, if a issue might occur hundred times a month, it's obviously a Actually, we can think the situation much more simple:
I will choose critical though Sherlock doesn't have this level. |
Result: |
Escalations have been resolved successfully! Escalation status:
|
From WatchPug: The dynamicCalldata passed to the keep modifier is not the entire calldata. This will result in a wrong result of _calculateDynamicFee(). Recommendation |
Passing in the whole msg.data is vulnerable to data expansion attacks, we chose to instead let the user of the library choose which portion of the data to incentivize. This is similar to how only the function with the incentivize modifier is counted with respect to the gas usage instead of the entire transaction. The difference in real cost to the keeper can be accounted for via the premium and buffer parameters. |
KingNFT
high
Keepers will suffer significant losses due to miss compensation for L1 rollup fees
Summary
While keepers submits transactions to L2 EVM chains, they need to pay both L2 execution fee and L1 rollup fee. Actually, L1 fees are much higher than L2 fees. In many case, L2 fees can be practically negligible. The current implementation only compensate and incentive keepers based on L2 gas consumption, keepers will suffer significant losses.
Vulnerability Detail
As shown of
keep()
modifier (L40-57), only L2 execution fee are compensated.Takes a random selected transaction at the writing time
https://optimistic.etherscan.io/tx/0xbb8e68e21c92acf4171fb6041b758b55acc3c559ec4595ed1129d534d90de995
We can find the L1 fee is much expensive than L2 fee.
Typically, L1 fees are dynamic and determined by the calldata length and smoothed Ethereum gas prices. To submit Pyth oracle price, the
VAA
calldata will be 1700+ bytes, keepers need to pay much L1 rollup fee.https://github.com/sherlock-audit/2023-07-perennial/blob/main/perennial-v2/packages/perennial-oracle/test/integration/pyth/PythOracle.test.ts#L34
Impact
No enough incentive for keeper to submit oracle price and execute orders, the system will not work.
Code Snippet
https://github.com/sherlock-audit/2023-07-perennial/blob/main/root/contracts/attribute/Kept.sol#L40
Tool used
Manual Review
Recommendation
Compensating L1 rollup fee, here are some reference:
https://docs.arbitrum.io/arbos/l1-pricing
https://community.optimism.io/docs/developers/build/transaction-fees/#the-l1-data-fee
The text was updated successfully, but these errors were encountered: