-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathanalyze_results.json
More file actions
4626 lines (4626 loc) · 723 KB
/
analyze_results.json
File metadata and controls
4626 lines (4626 loc) · 723 KB
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
{
"WBERA.name": {
"type": "public pure override",
"function_name": "name() returns (string memory)",
"analysis_result": "This function overrides the `name()` function from the inherited `WETH` contract. It is a `public` and `pure` function, meaning it does not read from or write to the contract's state. Its purpose is to return the official name of the token. It simply returns the constant string \"Wrapped Bera\". It does not use any variables or interact with storage. It does not call any other functions."
},
"WBERA.symbol": {
"type": "public pure override",
"function_name": "symbol() returns (string memory)",
"analysis_result": "This function overrides the `symbol()` function from the inherited `WETH` contract. It is a `public` and `pure` function, meaning it does not read from or write to the contract's state. Its purpose is to return the ticker symbol of the token. It simply returns the constant string \"WBERA\". It does not use any variables or interact with storage. It does not call any other functions."
},
"POLDeployer.constructor": {
"type": "constructor",
"function_name": "constructor(address bgt, address governance, uint256 beraChefSalt, uint256 blockRewardControllerSalt, uint256 distributorSalt, uint256 rewardVaultFactorySalt)",
"analysis_result": "This is the constructor function of the POLDeployer contract. Its purpose is to deploy and initialize the core Proof of Liquidity (PoL) related contracts using the CREATE2 opcode for predictable addresses. It takes several arguments:\n- `bgt`: The address of the BGT token contract.\n- `governance`: The address of the governance contract, likely the owner or controller of the deployed contracts.\n- `beraChefSalt`: A salt value used for deploying the BeraChef proxy.\n- `blockRewardControllerSalt`: A salt value used for deploying the BlockRewardController proxy.\n- `distributorSalt`: A salt value used for deploying the Distributor proxy.\n- `rewardVaultFactorySalt`: A salt value used for deploying the RewardVaultFactory proxy.\nThe function performs the following steps:\n1. Deploys the implementation contract for `BeraChef` using `deployWithCreate2` with a salt of 0 (effectively standard CREATE).\n2. Deploys the proxy contract for `BeraChef` using `deployProxyWithCreate2`, passing the deployed implementation address and the provided `beraChefSalt`. The resulting proxy address is stored in the immutable state variable `beraChef`.\n3. Deploys the implementation contract for `BlockRewardController` using `deployWithCreate2` (salt 0).\n4. Deploys the proxy contract for `BlockRewardController` using `deployProxyWithCreate2` with the implementation address and `blockRewardControllerSalt`. The address is stored in the immutable `blockRewardController` variable.\n5. Deploys the implementation contract for `Distributor` using `deployWithCreate2` (salt 0).\n6. Deploys the proxy contract for `Distributor` using `deployProxyWithCreate2` with the implementation address and `distributorSalt`. The address is stored in the immutable `distributor` variable.\n7. Deploys the implementation contract for `RewardVault` using `deployWithCreate2` (salt 0). This is needed by the factory but not stored directly in a state variable of this contract.\n8. Deploys the implementation contract for `RewardVaultFactory` using `deployWithCreate2` (salt 0).\n9. Deploys the proxy contract for `RewardVaultFactory` using `deployProxyWithCreate2` with the implementation address and `rewardVaultFactorySalt`. The address is stored in the immutable `rewardVaultFactory` variable.\n10. Initializes the deployed `beraChef` proxy by calling its `initialize` function with the address of the deployed `distributor`, the address of the deployed `rewardVaultFactory`, the `governance` address, the `BEACON_DEPOSIT` constant, and the `maxNumWeightsPerRewardAllocation` constant.\n11. Initializes the deployed `blockRewardController` proxy by calling its `initialize` function with the `bgt` address, the address of the deployed `distributor`, the `BEACON_DEPOSIT` constant, and the `governance` address.\n12. Initializes the deployed `distributor` proxy by calling its `initialize` function with the address of the deployed `beraChef`, the `bgt` address, the address of the deployed `blockRewardController`, the `governance` address, the `ZERO_VALIDATOR_PUBKEY_G_INDEX` constant, and the `PROPOSER_INDEX_G_INDEX` constant.\n13. Initializes the deployed `rewardVaultFactory` proxy by calling its `initialize` function with the `bgt` address, the address of the deployed `distributor`, the `BEACON_DEPOSIT` constant, the `governance` address, and the address of the deployed `RewardVault` implementation.\n\nVariables Used:\n- Reads from arguments: `bgt`, `governance`, `beraChefSalt`, `blockRewardControllerSalt`, `distributorSalt`, `rewardVaultFactorySalt`.\n- Reads constants: `maxNumWeightsPerRewardAllocation`, `ZERO_VALIDATOR_PUBKEY_G_INDEX`, `PROPOSER_INDEX_G_INDEX`, `BEACON_DEPOSIT`.\n- Writes to storage (immutable): `beraChef`, `blockRewardController`, `distributor`, `rewardVaultFactory`.\n\nFunctions Called:\n- `deployWithCreate2(0, ...)`: Inherited, used multiple times to deploy implementation contracts.\n- `deployProxyWithCreate2(..., salt)`: Inherited, used multiple times to deploy proxy contracts.\n- `beraChef.initialize(...)`: Called on the deployed BeraChef proxy.\n- `blockRewardController.initialize(...)`: Called on the deployed BlockRewardController proxy.\n- `distributor.initialize(...)`: Called on the deployed Distributor proxy.\n- `rewardVaultFactory.initialize(...)`: Called on the deployed RewardVaultFactory proxy."
},
"BeaconRootsHelper.setZeroValidatorPubkeyGIndex": {
"type": "public virtual",
"function_name": "setZeroValidatorPubkeyGIndex(uint64 _zeroValidatorPubkeyGIndex)",
"analysis_result": "This function allows setting the `zeroValidatorPubkeyGIndex` storage variable, which represents the Generalized Index of the pubkey for the first validator (validator index 0) in the beacon state's validator registry. The input parameter `_zeroValidatorPubkeyGIndex` is assigned directly to the storage variable. It emits the `ZeroValidatorPubkeyGIndexChanged` event with the new value. This function is marked as `virtual`, allowing derived contracts to override its behavior. The `@dev` comment indicates that this function should be permissioned to restrict who can call it, although the abstract contract itself does not implement access control."
},
"BeaconRootsHelper.setProposerIndexGIndex": {
"type": "public virtual",
"function_name": "setProposerIndexGIndex(uint64 _proposerIndexGIndex)",
"analysis_result": "This function allows setting the `proposerIndexGIndex` storage variable, which represents the Generalized Index of the proposer index field within the beacon block. The input parameter `_proposerIndexGIndex` is assigned directly to the storage variable. It emits the `ProposerIndexGIndexChanged` event with the new value. This function is marked as `virtual`, allowing derived contracts to override its behavior. The `@dev` comment indicates that this function should be permissioned to restrict who can call it, although the abstract contract itself does not implement access control."
},
"BeaconRootsHelper.isTimestampActionable": {
"type": "external view",
"function_name": "isTimestampActionable(uint64 timestamp)",
"analysis_result": "This function checks if a given `timestamp` is currently present in the EIP-4788 Beacon Roots history buffer AND has not yet been marked as processed within this contract's local buffer (`_processedTimestampsBuffer`). It first calls the `isParentBlockRootAt()` function via the `BeaconRoots` library extension on the input `timestamp`. If this returns false, the timestamp is not in the EIP-4788 buffer, and the function returns `false`. If the timestamp is in the EIP-4788 buffer, it calculates the index in `_processedTimestampsBuffer` using `timestamp % HISTORY_BUFFER_LENGTH`. It then checks if the timestamp stored at this index in `_processedTimestampsBuffer` is *not* equal to the input `timestamp`. If they are different, it means the timestamp hasn't been processed locally, and the function returns `true` (actionable). If they are equal, it means it has been processed locally, and the function returns `false`."
},
"BeaconRootsHelper._processTimestampInBuffer": {
"type": "internal",
"function_name": "_processTimestampInBuffer(uint64 timestamp)",
"analysis_result": "This internal function attempts to process a given `timestamp`, marking it as processed in the contract's local buffer (`_processedTimestampsBuffer`) and returning the corresponding parent beacon block root from the EIP-4788 buffer. It first calls `getParentBlockRootAt()` using the `BeaconRoots` library extension on the input `timestamp`. This call will revert if the timestamp is not found in the EIP-4788 buffer. It then calculates the index in `_processedTimestampsBuffer` using `timestamp % HISTORY_BUFFER_LENGTH`. It checks if the timestamp currently stored at this index is equal to the input `timestamp`. If they are equal, it means the timestamp has already been processed locally, and the function reverts with `TimestampAlreadyProcessed`. If the timestamp is found in the EIP-4788 buffer and not yet processed locally, the function updates `_processedTimestampsBuffer[timestampIndex]` to the input `timestamp`, effectively marking it as processed. Finally, it emits the `TimestampProcessed` event and returns the `parentBeaconBlockRoot` obtained from the EIP-4788 buffer."
},
"BeaconRootsHelper._verifyProposerIndexInBeaconBlock": {
"type": "internal view",
"function_name": "_verifyProposerIndexInBeaconBlock(bytes32 beaconBlockRoot, bytes32[] calldata proposerIndexProof, uint64 proposerIndex)",
"analysis_result": "This internal view function verifies an SSZ proof that a specific `proposerIndex` is correctly included within the beacon block identified by `beaconBlockRoot`. It first calculates the SSZ Hash Tree Root of the `proposerIndex` using the `SSZ.uint64HashTreeRoot` library function. It then calls the `SSZ.verifyProof` library function, passing the provided `proposerIndexProof`, the `beaconBlockRoot`, the calculated `proposerIndexRoot`, and the stored `proposerIndexGIndex`. If the `SSZ.verifyProof` call returns `false`, indicating the proof is invalid, the function reverts with `InvalidProof`."
},
"BeaconRootsHelper._verifyValidatorPubkeyInBeaconBlock": {
"type": "internal view",
"function_name": "_verifyValidatorPubkeyInBeaconBlock(bytes32 beaconBlockRoot, bytes32[] calldata validatorPubkeyProof, bytes calldata validatorPubkey, uint64 validatorIndex)",
"analysis_result": "This internal view function verifies an SSZ proof that a specific `validatorPubkey` is present at the correct position (`validatorIndex`) within the validator registry of the beacon state, rooted by `beaconBlockRoot`. It first checks if the provided `validatorIndex` is greater than or equal to the constant `VALIDATOR_REGISTRY_LIMIT` (1 << 40). If it is, the index is out of a valid range, and the function reverts with `IndexOutOfRange`. Otherwise, it calculates the SSZ Hash Tree Root of the `validatorPubkey` using the `SSZ.validatorPubkeyHashTreeRoot` library function. It then calculates the expected Generalized Index for this specific validator's pubkey by adding `VALIDATOR_PUBKEY_OFFSET` multiplied by the `validatorIndex` to the stored `zeroValidatorPubkeyGIndex`. Finally, it calls the `SSZ.verifyProof` library function with the provided `validatorPubkeyProof`, the `beaconBlockRoot`, the calculated `validatorPubkeyRoot`, and the derived Generalized Index. If `SSZ.verifyProof` returns `false`, the proof is invalid, and the function reverts with `InvalidProof`."
},
"FeeCollector.constructor": {
"type": "constructor",
"function_name": "constructor()",
"analysis_result": "This is the constructor for the `FeeCollector` contract. It is marked with `/// @custom:oz-upgrades-unsafe-allow constructor` and calls `_disableInitializers()`. In upgradeable contracts using the UUPS pattern via OpenZeppelin, the constructor is typically used to disable the initializers for the base contract (the implementation contract) to prevent them from being called directly, which could lead to state inconsistencies when used via a proxy. The actual initialization logic is moved to an `initialize` function."
},
"FeeCollector.initialize": {
"type": "external",
"function_name": "initialize(address governance, address _payoutToken, address _rewardReceiver, uint256 _payoutAmount)",
"analysis_result": "This is the initializer function for the upgradeable contract, replacing a standard constructor for setting initial state. It is marked `external` and uses the `initializer` modifier from OpenZeppelin's upgradeable contracts, which ensures it can only be called once. It requires four parameters: `governance` (the address granted the `DEFAULT_ADMIN_ROLE`), `_payoutToken` (the address of the token used for payouts), `_rewardReceiver` (the address, expected to be the `BGTStaker`, that receives payout tokens), and `_payoutAmount` (the fixed amount of `_payoutToken` to transfer upon each successful `claimFees` call).\n\n**Logic:**\n1. It calls `__AccessControl_init()`, `__Pausable_init()`, and `__UUPSUpgradeable_init()` to initialize the base OpenZeppelin upgradeable contracts.\n2. It checks if `governance`, `_payoutToken`, or `_rewardReceiver` are the zero address. If any are zero, it reverts with the `ZeroAddress.selector` error.\n3. It checks if `_payoutAmount` is zero. If it is, it reverts with the `PayoutAmountIsZero.selector` error.\n4. It grants the `DEFAULT_ADMIN_ROLE` to the `governance` address using `_grantRole`.\n5. It sets the admin role for the `PAUSER_ROLE` to the `MANAGER_ROLE` using `_setRoleAdmin`. This means only addresses with the `MANAGER_ROLE` can grant or revoke the `PAUSER_ROLE`.\n6. It sets the storage variable `payoutToken` to `_payoutToken`.\n7. It sets the storage variable `payoutAmount` to `_payoutAmount`.\n8. It sets the storage variable `rewardReceiver` to `_rewardReceiver`.\n9. It emits the `PayoutAmountSet` event with the initial old amount (0) and the new amount (`_payoutAmount`).\n\n**Storage Variables Modified:** `payoutToken`, `payoutAmount`, `rewardReceiver`, and internal state variables managed by `__AccessControl_init`, `__Pausable_init`, and `__UUPSUpgradeable_init`.\n\n**Events Emitted:** `PayoutAmountSet`."
},
"FeeCollector._authorizeUpgrade": {
"type": "internal",
"function_name": "_authorizeUpgrade(address newImplementation)",
"analysis_result": "This internal function is an override required by `UUPSUpgradeable`. It is called internally by the `_upgradeTo` function (or similar functions provided by the proxy pattern) before an upgrade is performed. Its purpose is to implement access control or other checks to determine if the calling context is authorized to initiate an upgrade.\n\n**Logic:**\n1. It applies the `onlyRole(DEFAULT_ADMIN_ROLE)` modifier.\n\n**Storage Variables Modified:** None directly.\n\n**Modifiers Used:** `onlyRole(DEFAULT_ADMIN_ROLE)` (ensures only the address with the default admin role, typically the governance address set during initialization, can trigger an upgrade)."
},
"FeeCollector.queuePayoutAmountChange": {
"type": "external",
"function_name": "queuePayoutAmountChange(uint256 _newPayoutAmount)",
"analysis_result": "This function allows an authorized role to queue a change to the `payoutAmount`. The change is not applied immediately but stored in `queuedPayoutAmount`. The actual change happens later when `claimFees` is called and `queuedPayoutAmount` is non-zero.\n\n**Logic:**\n1. It applies the `onlyRole(DEFAULT_ADMIN_ROLE)` modifier, restricting access to the default admin.\n2. It checks if the `_newPayoutAmount` is zero. If it is, it reverts with the `PayoutAmountIsZero.selector` error.\n3. It emits the `QueuedPayoutAmount` event, indicating the old `payoutAmount` and the new `_newPayoutAmount` being queued.\n4. It updates the storage variable `queuedPayoutAmount` with the provided `_newPayoutAmount`.\n\n**Storage Variables Modified:** `queuedPayoutAmount`.\n\n**Events Emitted:** `QueuedPayoutAmount`.\n\n**Errors Reverted:** `PayoutAmountIsZero.selector`."
},
"FeeCollector.claimFees": {
"type": "external",
"function_name": "claimFees(address _recipient, address[] calldata _feeTokens)",
"analysis_result": "This function is the primary mechanism for claiming collected fees and initiating a payout to the reward receiver. It is marked `external` and uses the `whenNotPaused` modifier, meaning it cannot be called when the contract is paused. It requires two parameters: `_recipient` (the address to which the collected fee tokens will be sent) and `_feeTokens` (an array of addresses of the fee tokens to collect).\n\n**Logic:**\n1. It applies the `whenNotPaused` modifier.\n2. It transfers a fixed amount (`payoutAmount`) of the `payoutToken` from the caller (`msg.sender`) to the `rewardReceiver` (expected to be the `BGTStaker` contract) using `IERC20(payoutToken).safeTransferFrom`. This requires `msg.sender` to have approved this contract to spend at least `payoutAmount` of the `payoutToken` on their behalf.\n3. It calls `notifyRewardAmount(payoutAmount)` on the `rewardReceiver` contract (casting it as a `BGTStaker`). This notifies the reward receiver (staker) that a payout has occurred and updates their reward calculation.\n4. It iterates through the `_feeTokens` array:\n a. For each `feeToken`, it gets the current balance of that token held by the `FeeCollector` contract using `IERC20(feeToken).balanceOf(address(this))`. This represents the collected fees of that token.\n b. It transfers the entire balance of that `feeToken` from the `FeeCollector` contract to the `_recipient` using `IERC20(feeToken).safeTransfer`.\n c. It emits the `FeesClaimed` event for each individual fee token transferred, including the caller, recipient, token address, and amount.\n5. After the loop, it emits a general `FeesClaimed` event indicating the caller and recipient for the overall fee claim operation.\n6. Finally, it checks if `queuedPayoutAmount` is non-zero. If it is, it calls the internal function `_setPayoutAmount()` to apply the queued change.\n\n**Storage Variables Read:** `payoutToken`, `payoutAmount`, `rewardReceiver`, `queuedPayoutAmount`.\n\n**Storage Variables Modified:** `payoutAmount`, `queuedPayoutAmount` (if `queuedPayoutAmount` was non-zero).\n\n**External Calls:**\n* `IERC20(payoutToken).safeTransferFrom(msg.sender, rewardReceiver, payoutAmount)`\n* `BGTStaker(rewardReceiver).notifyRewardAmount(payoutAmount)`\n* `IERC20(feeToken).balanceOf(address(this))` (within the loop)\n* `IERC20(feeToken).safeTransfer(_recipient, feeTokenAmountToTransfer)` (within the loop)\n\n**Events Emitted:** `FeesClaimed` (multiple times), potentially `PayoutAmountSet` if `_setPayoutAmount` is called.\n\n**Modifiers Used:** `whenNotPaused`."
},
"FeeCollector.donate": {
"type": "external",
"function_name": "donate(uint256 amount)",
"analysis_result": "This function allows anyone (when not paused) to donate `payoutToken` directly to the `rewardReceiver`. It is marked `external` and uses the `whenNotPaused` modifier. It takes one parameter: `amount`, the amount of `payoutToken` to donate.\n\n**Logic:**\n1. It applies the `whenNotPaused` modifier.\n2. It checks if the `amount` is less than the current `payoutAmount`. The comment suggests it should be at least `payoutAmount` to notify the receiver, but the check only ensures it's not less. If `amount` is less than `payoutAmount`, it reverts with the `DonateAmountLessThanPayoutAmount.selector` error.\n3. It transfers the specified `amount` of the `payoutToken` from the caller (`msg.sender`) directly to the `rewardReceiver` using `IERC20(payoutToken).safeTransferFrom`. This requires `msg.sender` to have approved this contract to spend at least `amount` of the `payoutToken`.\n4. It calls `notifyRewardAmount(amount)` on the `rewardReceiver` contract (casting it as a `BGTStaker`), notifying the receiver of the donation and updating their reward calculation.\n5. It emits the `PayoutDonated` event, indicating the caller and the donated `amount`.\n\n**Storage Variables Read:** `payoutToken`, `payoutAmount`, `rewardReceiver`.\n\n**Storage Variables Modified:** None directly.\n\n**External Calls:**\n* `IERC20(payoutToken).safeTransferFrom(msg.sender, rewardReceiver, amount)`\n* `BGTStaker(rewardReceiver).notifyRewardAmount(amount)`\n\n**Events Emitted:** `PayoutDonated`.\n\n**Modifiers Used:** `whenNotPaused`.\n\n**Errors Reverted:** `DonateAmountLessThanPayoutAmount.selector`."
},
"FeeCollector.pause": {
"type": "external",
"function_name": "pause()",
"analysis_result": "This function allows an authorized role to pause the contract, preventing calls to functions marked with `whenNotPaused`. It is marked `external`.\n\n**Logic:**\n1. It applies the `onlyRole(PAUSER_ROLE)` modifier, restricting access to addresses holding the `PAUSER_ROLE`.\n2. It calls the internal `_pause()` function, which is inherited from `PausableUpgradeable` and handles setting the paused state and emitting the `Paused` event.\n\n**Storage Variables Modified:** Internal state variable managed by `_pause()`.\n\n**Events Emitted:** `Paused` (by `_pause()`)."
},
"FeeCollector.unpause": {
"type": "external",
"function_name": "unpause()",
"analysis_result": "This function allows an authorized role to unpause the contract, re-enabling calls to functions marked with `whenNotPaused`. It is marked `external`.\n\n**Logic:**\n1. It applies the `onlyRole(MANAGER_ROLE)` modifier, restricting access to addresses holding the `MANAGER_ROLE`. Recall that the `MANAGER_ROLE` is set as the admin for the `PAUSER_ROLE` in `initialize`, allowing managers to manage pausers, but here the manager itself is given the ability to unpause.\n2. It calls the internal `_unpause()` function, which is inherited from `PausableUpgradeable` and handles unsetting the paused state and emitting the `Unpaused` event.\n\n**Storage Variables Modified:** Internal state variable managed by `_unpause()`.\n\n**Events Emitted:** `Unpaused` (by `_unpause()`)."
},
"FeeCollector._setPayoutAmount": {
"type": "internal",
"function_name": "_setPayoutAmount()",
"analysis_result": "This internal helper function is called to apply a previously queued payout amount change. It is only called from within the `claimFees` function when `queuedPayoutAmount` is non-zero.\n\n**Logic:**\n1. It emits the `PayoutAmountSet` event, indicating the old `payoutAmount` and the new amount from `queuedPayoutAmount`.\n2. It updates the storage variable `payoutAmount` with the value stored in `queuedPayoutAmount`.\n3. It resets `queuedPayoutAmount` to 0.\n\n**Storage Variables Read:** `payoutAmount`, `queuedPayoutAmount`.\n\n**Storage Variables Modified:** `payoutAmount`, `queuedPayoutAmount`.\n\n**Events Emitted:** `PayoutAmountSet`."
},
"FeeCollector.onlyRole": {
"type": "modifier",
"function_name": "onlyRole(bytes32 role)",
"analysis_result": "This modifier, inherited from `AccessControlUpgradeable`, restricts the decorated function's execution to only addresses that possess the specified `role`. It checks the caller's role using the internal `_checkRole` function. If the caller does not have the required role, it reverts with an `AccessControlUnauthorizedAccount` error."
},
"FeeCollector.whenNotPaused": {
"type": "modifier",
"function_name": "whenNotPaused",
"analysis_result": "This modifier, inherited from `PausableUpgradeable`, restricts the decorated function's execution to only when the contract is *not* in a paused state. It checks the internal pause state. If the contract is paused, it reverts with a `PausablePaused` error."
},
"FeeCollector.initializer": {
"type": "modifier",
"function_name": "initializer",
"analysis_result": "This modifier, from OpenZeppelin's upgradeable contracts (`Initializable.sol`), ensures that the function it decorates can only be called once. This is crucial for initializing state in upgradeable contracts after deployment via a proxy, preventing re-initialization attacks."
},
"BGTStaker.constructor": {
"type": "public",
"function_name": "constructor()",
"analysis_result": "This is the constructor for the proxy pattern implementation. It calls `_disableInitializers()` to prevent the `initialize` function from being called during the initial contract deployment (as it will be called via the proxy's `initialize`). It sets up the contract for being used as an upgradeable contract implementation. No storage variables are modified directly in this function, but it prepares the contract state for the initializer."
},
"BGTStaker.initialize": {
"type": "external",
"function_name": "initialize(address _bgt, address _feeCollector, address _governance, address _rewardToken)",
"analysis_result": "This is the initializer function, meant to be called once through the proxy to set up the contract's initial state. It is marked with the `initializer` modifier. It initializes three inherited base contracts: `OwnableUpgradeable` with `_governance` as the initial owner, `StakingRewards` with `_bgt` as the staking token, `_rewardToken` as the reward token, and a default `rewardsDuration` of 7 days. It also initializes `UUPSUpgradeable`. Finally, it sets the contract's `FEE_COLLECTOR` storage variable to `_feeCollector`. Storage variables modified include `owner`, `stakeToken`, `rewardToken`, `rewardsDuration`, and `FEE_COLLECTOR`. It calls `__Ownable_init`, `__StakingRewards_init`, and `__UUPSUpgradeable_init`. Its purpose is to configure the core settings of the contract after deployment."
},
"BGTStaker.onlyBGT": {
"type": "modifier",
"function_name": "onlyBGT()",
"analysis_result": "This custom modifier restricts the execution of a function to only the address specified as the staking token (`stakeToken`). It checks if `msg.sender` is equal to `address(stakeToken)`. If not, it reverts the transaction using a custom error `NotBGT` by checking its selector. This is used for `stake` and `withdraw` functions, implying they are designed to be called by the BGT token contract itself."
},
"BGTStaker.onlyFeeCollector": {
"type": "modifier",
"function_name": "onlyFeeCollector()",
"analysis_result": "This custom modifier restricts the execution of a function to only the address stored in the `FEE_COLLECTOR` storage variable. It checks if `msg.sender` is equal to `FEE_COLLECTOR`. If not, it reverts the transaction using a custom error `NotFeeCollector` by checking its selector. This is used for the `notifyRewardAmount` function."
},
"BGTStaker._authorizeUpgrade": {
"type": "internal",
"function_name": "_authorizeUpgrade(address newImplementation)",
"analysis_result": "This function is an override of the internal `_authorizeUpgrade` function from `UUPSUpgradeable`. It implements the authorization logic for contract upgrades, simply calling the `onlyOwner` modifier. This ensures that only the contract owner (set during initialization) can trigger a contract upgrade. It is protected by the `onlyOwner` modifier."
},
"BGTStaker.notifyRewardAmount": {
"type": "external",
"function_name": "notifyRewardAmount(uint256 reward)",
"analysis_result": "This function allows the designated `FEE_COLLECTOR` to inform the staking contract about a new amount of reward tokens available for distribution. It is protected by the `onlyFeeCollector` modifier. It calls the internal `_notifyRewardAmount` function inherited from the `StakingRewards` base contract, passing the `reward` amount. `_notifyRewardAmount` handles the logic for calculating the new reward rate and updating the reward period, potentially modifying variables like `lastUpdateTime`, `rewardRate`, `periodFinish`, and `totalRewardPerTokenStored` in `StakingRewards`. Its purpose is to initiate the distribution of reward tokens to stakers."
},
"BGTStaker.recoverERC20": {
"type": "external",
"function_name": "recoverERC20(address tokenAddress, uint256 tokenAmount)",
"analysis_result": "This function allows the contract `owner` to recover accidentally sent ERC20 tokens from the contract address. It is protected by the `onlyOwner` modifier. It checks if the `tokenAddress` is the same as the `rewardToken` address (from `StakingRewards`), reverting with `CannotRecoverRewardToken` if they match to protect reward funds. If not the reward token, it uses `SafeERC20.safeTransfer` to transfer the specified `tokenAmount` of the token at `tokenAddress` to the `owner`'s address. An event `Recovered` is emitted upon success. It reads `rewardToken` and `owner` storage variables."
},
"BGTStaker.setRewardsDuration": {
"type": "external",
"function_name": "setRewardsDuration(uint256 _rewardsDuration)",
"analysis_result": "This function allows the contract `owner` to change the duration over which the notified rewards are distributed. It is protected by the `onlyOwner` modifier. It calls the internal `_setRewardsDuration` function inherited from the `StakingRewards` base contract, passing the new `_rewardsDuration`. `_setRewardsDuration` updates the `rewardsDuration` storage variable in `StakingRewards`. Its purpose is to adjust the reward distribution period."
},
"BGTStaker.stake": {
"type": "external",
"function_name": "stake(address account, uint256 amount)",
"analysis_result": "This function is intended to be called by the staking token contract (BGT) itself, not directly by a user, as indicated by the `onlyBGT` modifier. It takes the `account` that is staking and the `amount` of BGT being staked. It calls the internal `_stake` function inherited from the `StakingRewards` base contract. `_stake` handles updating the total supply of staked tokens and the individual user's balance, potentially modifying `totalSupply` and `balances` in `StakingRewards`. Importantly, this function *does not* involve transferring BGT tokens into this contract due to the overrides of `_safeTransferFromStakeToken`. Staking here represents delegation or notification of staked balance elsewhere."
},
"BGTStaker.withdraw": {
"type": "external",
"function_name": "withdraw(address account, uint256 amount)",
"analysis_result": "Similar to `stake`, this function is intended to be called by the staking token contract (BGT) itself, not directly by a user, as indicated by the `onlyBGT` modifier. It takes the `account` that is withdrawing and the `amount` of BGT being unstaked/undelegated. It calls the internal `_withdraw` function inherited from the `StakingRewards` base contract. `_withdraw` handles updating the total supply of staked tokens and the individual user's balance, potentially modifying `totalSupply` and `balances` in `StakingRewards`. As with `stake`, this function *does not* involve transferring BGT tokens out of this contract due to the overrides of `_safeTransferStakeToken`. Withdrawal here represents undelegation or notification of reduced staked balance elsewhere."
},
"BGTStaker.getReward": {
"type": "external",
"function_name": "getReward()",
"analysis_result": "This function allows any caller (`msg.sender`) to claim their accumulated reward tokens. It calls the internal `_getReward` function inherited from the `StakingRewards` base contract. It passes `msg.sender` for both the account whose rewards are being claimed and the address to which the rewards should be sent. `_getReward` calculates the pending rewards for the user based on their stake and the reward rate, transfers the reward tokens using `safeTransfer` (which *is* active for the reward token), and updates the user's state to reflect that rewards have been claimed. It modifies variables related to user's claimed rewards and potentially reward calculations in `StakingRewards`. Its purpose is to enable users to claim earned reward tokens."
},
"BGTStaker._safeTransferFromStakeToken": {
"type": "internal",
"function_name": "_safeTransferFromStakeToken(address from, uint256 amount)",
"analysis_result": "This function is an override of an internal function in the `StakingRewards` base contract. In `StakingRewards`, this function would typically perform an ERC20 transfer of the stake token from a user's address to the staking contract. However, in `BGTStaker`, this function is intentionally overridden to be empty (`{}`). This prevents actual BGT tokens from being transferred into this contract, facilitating a delegation/notification model rather than a deposit model. No storage variables are modified, and no other functions are called within this override."
},
"BGTStaker._safeTransferStakeToken": {
"type": "internal",
"function_name": "_safeTransferStakeToken(address to, uint256 amount)",
"analysis_result": "This function is an override of an internal function in the `StakingRewards` base contract. In `StakingRewards`, this function would typically perform an ERC20 transfer of the stake token from the staking contract back to a user's address. However, in `BGTStaker`, this function is intentionally overridden to be empty (`{}`). This prevents actual BGT tokens from being transferred out of this contract during withdrawal, facilitating a delegation/notification model rather than a deposit model. No storage variables are modified, and no other functions are called within this override."
},
"BeaconDeposit.supportsInterface": {
"type": "external",
"function_name": "supportsInterface(bytes4 interfaceId) external pure override returns (bool)",
"analysis_result": "This function implements the ERC165 interface. It checks if the contract supports the given interface ID. It returns `true` if the interface ID is either `type(ERC165).interfaceId` or `type(IBeaconDeposit).interfaceId`, indicating that the contract supports the ERC165 standard and the IBeaconDeposit custom interface. It does not read or modify any state variables as it is a pure function."
},
"BeaconDeposit.getOperator": {
"type": "external",
"function_name": "getOperator(bytes calldata pubkey) external view returns (address)",
"analysis_result": "This function allows external callers to retrieve the current operator address associated with a specific validator public key. It takes a `bytes calldata pubkey` as input. It looks up the public key in the private mapping `_operatorByPubKey` and returns the corresponding address. If the public key is not found, it returns the zero address (address(0)). This function is a `view` function, meaning it does not modify the contract's state."
},
"BeaconDeposit.deposit": {
"type": "external",
"function_name": "deposit(bytes calldata pubkey, bytes calldata credentials, bytes calldata signature, address operator) external payable",
"analysis_result": "This function handles the deposit of BERA (native token) to register a validator and link it to an operator address. It is a `payable` function, requiring native tokens to be sent with the transaction. It takes the validator's `pubkey` (48 bytes), `credentials` (32 bytes), `signature` (96 bytes), and an `operator` address as inputs. It performs length checks on `pubkey`, `credentials`, and `signature` against defined constants (`PUBLIC_KEY_LENGTH`, `CREDENTIALS_LENGTH`, `SIGNATURE_LENGTH`), reverting with specific error selectors if invalid lengths are provided.\n\nIt checks the `_operatorByPubKey` mapping to see if the `pubkey` has been registered before. If it's the first deposit for this `pubkey` (`_operatorByPubKey[pubkey]` is address(0)), it requires a non-zero `operator` address to be provided and sets `_operatorByPubKey[pubkey]` to this address, emitting an `OperatorUpdated` event. If it's not the first deposit for this `pubkey`, it requires the `operator` parameter to be the zero address (address(0)), reverting with `OperatorAlreadySet` otherwise, to prevent front-running of the operator assignment.\n\nIt calls the internal `_deposit()` function to process the attached `msg.value`, validate it is a multiple of Gwei and within `uint64` range, and transfer it to the zero address (simulating burning/sending to the consensus layer). It checks the returned `amountInGwei` from `_deposit()` against `MIN_DEPOSIT_AMOUNT_IN_GWEI` (10,000 Gwei), reverting with `InsufficientDeposit` if the amount is too low.\n\nFinally, it emits a `Deposit` event containing the `pubkey`, `credentials`, `amountInGwei`, `signature`, and the current `depositCount`. It then increments the public state variable `depositCount` by 1, which serves as a unique index for the deposit."
},
"BeaconDeposit.requestOperatorChange": {
"type": "external",
"function_name": "requestOperatorChange(bytes calldata pubkey, address newOperator) external",
"analysis_result": "This function allows the current operator associated with a public key to initiate a request to change the operator to a `newOperator`. It takes the validator's `pubkey` and the desired `newOperator` address as inputs. It first retrieves the current operator address from the `_operatorByPubKey` mapping. It requires `msg.sender` to be equal to this current operator address, reverting with `NotOperator` if not (this check also implicitly verifies that the `pubkey` is registered and has a non-zero operator). It also requires the `newOperator` address not to be the zero address, reverting with `ZeroAddress` if it is.\n\nIt accesses the `QueuedOperator` struct associated with the `pubkey` in the `queuedOperator` mapping. It updates this struct's `newOperator` field to the provided `newOperator` and sets the `queuedTimestamp` to the current `block.timestamp`. This queues the operator change request. It then emits an `OperatorChangeQueued` event with the `pubkey`, `newOperator`, `currentOperator` (before the change), and the `block.timestamp` when the request was made.\n\nState variables modified: `queuedOperator`. State variables read: `_operatorByPubKey`, `queuedOperator`."
},
"BeaconDeposit.cancelOperatorChange": {
"type": "external",
"function_name": "cancelOperatorChange(bytes calldata pubkey) external",
"analysis_result": "This function allows the current operator associated with a public key to cancel a pending operator change request for that public key. It takes the validator's `pubkey` as input. It verifies that `msg.sender` is the current operator for the `pubkey` by checking `_operatorByPubKey[pubkey]`, reverting with `NotOperator` if not. If the caller is the current operator, it deletes the entry for the `pubkey` in the `queuedOperator` mapping. This effectively removes the queued request.\n\nAfter successful cancellation, it emits an `OperatorChangeCancelled` event with the `pubkey`. State variables modified: `queuedOperator`. State variables read: `_operatorByPubKey`, `queuedOperator`."
},
"BeaconDeposit.acceptOperatorChange": {
"type": "external",
"function_name": "acceptOperatorChange(bytes calldata pubkey) external",
"analysis_result": "This function allows the *proposed* new operator to accept a previously queued operator change request for a given `pubkey`. It takes the validator's `pubkey` as input. It retrieves the queued request data (`newOperator` and `queuedTimestamp`) from the `queuedOperator` mapping. It performs several checks:\n\n1. Requires `msg.sender` to be equal to the `newOperator` stored in the queued request. Reverts with `NotNewOperator` if not (this also covers cases where no request is queued, as `newOperator` would be address(0)).\n2. Checks if sufficient time (at least `ONE_DAY` seconds) has passed since the request was queued (`queuedTimestamp + ONE_DAY <= block.timestamp`). Reverts with `NotEnoughTime` if the delay has not passed.\n\nIf these checks pass, it proceeds to update the operator. It reads the current operator from `_operatorByPubKey` (the 'old' operator). It then updates `_operatorByPubKey[pubkey]` to the `newOperator` from the queued request. Finally, it deletes the entry for the `pubkey` in the `queuedOperator` mapping, clearing the request. An `OperatorUpdated` event is emitted with the `pubkey`, the new operator, and the old operator.\n\nState variables modified: `_operatorByPubKey`, `queuedOperator`. State variables read: `queuedOperator`, `_operatorByPubKey`."
},
"BeaconDeposit._deposit": {
"type": "internal",
"function_name": "_deposit() internal virtual returns (uint64)",
"analysis_result": "This internal helper function is called by the `deposit` function to handle the processing of the native token value sent with the deposit. It first checks if `msg.value` (the amount of native token sent) is a multiple of 1 Gwei, reverting with `DepositNotMultipleOfGwei` if it's not precise to the Gwei unit. It calculates the amount in Gwei by dividing `msg.value` by 1 Gwei. It checks if this amount exceeds the maximum value representable by a `uint64`, reverting with `DepositValueTooHigh` if it does.\n\nIt then calls the internal `_safeTransferETH` function to transfer the original `msg.value` to the zero address (`address(0)`). This is a standard pattern in consensus layer deposit contracts to effectively remove the tokens from the execution layer and signal them for use on the consensus layer. Finally, it returns the validated deposit amount converted to `uint64` in Gwei. It reads no state variables and modifies none directly, but calls `_safeTransferETH` which handles the ETH transfer."
},
"BeaconDeposit._safeTransferETH": {
"type": "internal",
"function_name": "_safeTransferETH(address to, uint256 amount) internal",
"analysis_result": "This internal helper function is used to safely transfer a specified `amount` of native token to a target address `to` using a low-level `call`. It's designed to handle potential failures of the transfer call. It uses an assembly block to perform the `call`. If the `call` returns a zero success indicator, the function reverts with a specific error selector (`ETHTransferFailed()`). In this contract, it is specifically used by `_deposit` to send the deposited amount to `address(0)`. It does not read or modify any state variables."
},
"BGT.onlyBlockRewardController": {
"type": "modifier",
"function_name": "onlyBlockRewardController()",
"analysis_result": "This modifier restricts access to a function, allowing it to be called only by the address stored in the `_blockRewardController` state variable. It checks if `msg.sender` is equal to `_blockRewardController`. If not, it reverts with the custom error `NotBlockRewardController` using its selector."
},
"BGT.onlyApprovedSender": {
"type": "modifier",
"function_name": "onlyApprovedSender(address sender)",
"analysis_result": "This modifier restricts access to a function, allowing it to be called only if the provided `sender` address is whitelisted in the `isWhitelistedSender` mapping. It checks `isWhitelistedSender[sender]`. If the sender is not whitelisted (the value is false), it reverts with the custom error `NotApprovedSender` using its selector. It uses the state variable `isWhitelistedSender`."
},
"BGT.checkUnboostedBalance": {
"type": "modifier",
"function_name": "checkUnboostedBalance(address sender, uint256 amount)",
"analysis_result": "This modifier checks if the unboosted balance of the `sender` address is greater than or equal to the specified `amount`. It calls the internal helper function `_checkUnboostedBalance` with the `sender` and `amount`. If the check fails (unboosted balance is insufficient), the helper function will revert with `NotEnoughBalance`. It uses the state variable `userBoosts` indirectly via `unboostedBalanceOf`."
},
"BGT.invariantCheck": {
"type": "modifier",
"function_name": "invariantCheck()",
"analysis_result": "This modifier is intended to check contract invariants after a state-changing operation. It executes the function body first (`_;`). After the function body successfully completes, it calls the private helper function `_invariantCheck`. This helper function checks if the contract's ETH balance (`address(this).balance`) is less than the total BGT supply (`totalSupply()`). If this invariant is violated, it reverts with the custom error `InvariantCheckFailed`. It uses the state variable `totalSupply` indirectly via `_invariantCheck` and checks the contract's own balance."
},
"BGT.initialize": {
"type": "external",
"function_name": "initialize(address _owner)",
"analysis_result": "This function is an initializer, designed to be called only once by the deployer (via OpenZeppelin's `initializer` modifier, although the code comment says it's not upgradable, it uses upgradeable base contracts and the `initializer` pattern). It sets up the contract's initial state. It calls the initializer for `OwnableUpgradeable` (`__Ownable_init(_owner)`) to set the contract owner to `_owner`. It calls the initializer for `ERC20Upgradeable` (`__ERC20_init(NAME, SYMBOL)`) to set the token name and symbol using the private constants `NAME` and `SYMBOL`. It sets the `activateBoostDelay` and `dropBoostDelay` state variables to the value of the private constant `BOOST_MAX_BLOCK_DELAY`. It modifies the state variables `owner`, `_name`, `_symbol`, `activateBoostDelay`, and `dropBoostDelay`."
},
"BGT.whitelistSender": {
"type": "external",
"function_name": "whitelistSender(address sender, bool approved)",
"analysis_result": "This function allows the contract owner to add or remove an address from the list of approved senders. It is restricted to the owner by the `onlyOwner` modifier (inherited from `OwnableUpgradeable`). It takes an address `sender` and a boolean `approved`. It updates the `isWhitelistedSender` mapping for the given `sender` with the value of `approved`. It emits the `SenderWhitelisted` event with the `sender` and `approved` status. It uses and modifies the state variable `isWhitelistedSender`."
},
"BGT.setMinter": {
"type": "external",
"function_name": "setMinter(address _minter)",
"analysis_result": "This function allows the contract owner to set the address of the BlockRewardController, which is the only contract authorized to mint BGT. It is restricted to the owner by the `onlyOwner` modifier. It takes an address `_minter`. It checks if `_minter` is the zero address; if so, it reverts with the custom error `ZeroAddress`. It emits the `MinterChanged` event with the old and new minter addresses (`_blockRewardController` and `_minter`). It updates the `_blockRewardController` state variable. It uses and modifies the state variable `_blockRewardController`."
},
"BGT.mint": {
"type": "external",
"function_name": "mint(address distributor, uint256 amount)",
"analysis_result": "This function allows the minting of BGT tokens. It is restricted to the BlockRewardController address by the `onlyBlockRewardController` modifier. It is also subject to the `invariantCheck` modifier, which runs after the minting operation to ensure the contract's ETH balance invariant is maintained. It takes a `distributor` address (the recipient of the minted tokens) and the `amount` to mint. It calls the inherited internal function `super._mint(distributor, amount)` from `ERC20Upgradeable` to perform the minting. It modifies the total supply and the recipient's balance state variables within `_mint`. It uses and modifies internal state variables related to ERC20 balances and total supply via the `_mint` call."
},
"BGT.setStaker": {
"type": "external",
"function_name": "setStaker(address _staker)",
"analysis_result": "This function allows the contract owner to set the address of the BGTStaker contract, which is used for staking and withdrawing BGT related to validator boosts. It is restricted to the owner by the `onlyOwner` modifier. It takes an address `_staker`. It checks if `_staker` is the zero address; if so, it reverts with the custom error `ZeroAddress`. It emits the `StakerChanged` event with the old and new staker addresses (`staker` and `_staker`). It updates the `staker` state variable. It uses and modifies the state variable `staker`."
},
"BGT.setActivateBoostDelay": {
"type": "external",
"function_name": "setActivateBoostDelay(uint32 _activateBoostDelay)",
"analysis_result": "This function allows the contract owner to set the minimum block delay required before a queued boost can be activated. It is restricted to the owner by the `onlyOwner` modifier. It takes a `uint32 _activateBoostDelay`. It checks if `_activateBoostDelay` is 0 or greater than `BOOST_MAX_BLOCK_DELAY`; if so, it reverts with the custom error `InvalidActivateBoostDelay`. Otherwise, it updates the `activateBoostDelay` state variable. It emits the `ActivateBoostDelayChanged` event with the new delay value. It uses and modifies the state variable `activateBoostDelay` and uses the constant `BOOST_MAX_BLOCK_DELAY`."
},
"BGT.setDropBoostDelay": {
"type": "external",
"function_name": "setDropBoostDelay(uint32 _dropBoostDelay)",
"analysis_result": "This function allows the contract owner to set the minimum block delay required before a queued drop boost can be finalized. It is restricted to the owner by the `onlyOwner` modifier. It takes a `uint32 _dropBoostDelay`. It checks if `_dropBoostDelay` is 0 or greater than `BOOST_MAX_BLOCK_DELAY`; if so, it reverts with the custom error `InvalidDropBoostDelay`. Otherwise, it updates the `dropBoostDelay` state variable. It emits the `DropBoostDelayChanged` event with the new delay value. It uses and modifies the state variable `dropBoostDelay` and uses the constant `BOOST_MAX_BLOCK_DELAY`."
},
"BGT.setBgtTermsAndConditions": {
"type": "external",
"function_name": "setBgtTermsAndConditions(string calldata _bgtTermsAndConditions)",
"analysis_result": "This function allows the contract owner to set or update the BGT terms and conditions string. It is restricted to the owner by the `onlyOwner` modifier. It takes a `string calldata _bgtTermsAndConditions`. It updates the `bgtTermsAndConditions` state variable with the provided string. It emits the `BgtTermsAndConditionsChanged` event with the new terms string. It uses and modifies the state variable `bgtTermsAndConditions`."
},
"BGT.queueBoost": {
"type": "external",
"function_name": "queueBoost(bytes calldata pubkey, uint128 amount)",
"analysis_result": "This function allows a user to queue a certain `amount` of their BGT balance to be used for boosting a specific validator identified by `pubkey`. It is restricted by the `checkUnboostedBalance` modifier, ensuring the sender has enough unboosted BGT. It adds the `amount` to the sender's total queued boost balance in `userBoosts[msg.sender].queuedBoost`. It then updates the `boostedQueue` mapping for the sender and pubkey, adding the `amount` to the `balance` and updating the `blockNumberLast` to the current block number (`uint32(block.number)`). It emits the `QueueBoost` event with the sender, pubkey, and amount. It uses and modifies the state variables `userBoosts` and `boostedQueue`."
},
"BGT.cancelBoost": {
"type": "external",
"function_name": "cancelBoost(bytes calldata pubkey, uint128 amount)",
"analysis_result": "This function allows a user to cancel a previously queued boost of a specific `amount` for a validator identified by `pubkey`. It subtracts the `amount` from the queued boost balance in the `boostedQueue` mapping for the sender and pubkey (`boostedQueue[msg.sender][pubkey].balance`). It also subtracts the `amount` from the sender's total queued boost balance in `userBoosts[msg.sender].queuedBoost`. It uses unchecked arithmetic for subtraction, assuming the amount being cancelled does not exceed the queued amount (which should be guaranteed by the logic that adds to these variables). It emits the `CancelBoost` event with the sender, pubkey, and amount. It uses and modifies the state variables `boostedQueue` and `userBoosts`."
},
"BGT.activateBoost": {
"type": "external",
"function_name": "activateBoost(address user, bytes calldata pubkey)",
"analysis_result": "This function allows activation of a queued boost for a specific `user` and validator `pubkey` after the required block delay has passed. It is typically called by a third party (potentially an approved sender, though not enforced by modifier here, Multicallable context might imply this) to help users finalize boosts. It retrieves the queued boost information (`blockNumberLast` and `amount`) from `boostedQueue[user][pubkey]`. It checks if the `amount` is greater than 0 and if enough blocks have passed since `blockNumberLast` by calling the internal helper function `_checkEnoughTimePassed` with `blockNumberLast` and `activateBoostDelay`. If either condition is false, it returns `false`. If conditions are met, it adds the `amount` to the `totalBoosts`, `boostees[pubkey]`, and `boosted[user][pubkey]` state variables. It also updates the sender's `userBoosts[user]` by adding `amount` to `boost` and subtracting `amount` from `queuedBoost`. It uses unchecked arithmetic for these updates, assuming the queued amount is available in the queued balance. It deletes the entry in `boostedQueue[user][pubkey]`. It then calls the `stake` function on the contract address stored in `staker` (expected to be the `IBGTStaker` contract), passing the `user` and `amount`. Finally, it emits the `ActivateBoost` event with the caller (`msg.sender`), the user, pubkey, and amount, and returns `true`. It uses and modifies `totalBoosts`, `boostees`, `boosted`, `userBoosts`, `boostedQueue`, `activateBoostDelay`, and calls an external contract via the `staker` address."
},
"BGT.queueDropBoost": {
"type": "external",
"function_name": "queueDropBoost(bytes calldata pubkey, uint128 amount)",
"analysis_result": "This function allows a user to queue a certain `amount` of their currently boosted BGT balance to be dropped for a specific validator identified by `pubkey`. It calculates the new drop balance (`dropBalance`) by adding the `amount` to the current queued drop balance for the sender and pubkey (`dropBoostQueue[msg.sender][pubkey].balance`). It checks if the sender has enough currently boosted balance for that validator (`boosted[msg.sender][pubkey]`) to cover the `dropBalance`. If not, it reverts with the custom error `NotEnoughBoostedBalance`. If the check passes, it updates the `dropBoostQueue` mapping for the sender and pubkey, setting the `balance` to `dropBalance` and updating the `blockNumberLast` to the current block number (`uint32(block.number)`). It emits the `QueueDropBoost` event with the sender, pubkey, and amount. It uses and modifies the state variable `dropBoostQueue` and reads from `boosted`."
},
"BGT.cancelDropBoost": {
"type": "external",
"function_name": "cancelDropBoost(bytes calldata pubkey, uint128 amount)",
"analysis_result": "This function allows a user to cancel a previously queued drop boost of a specific `amount` for a validator identified by `pubkey`. It subtracts the `amount` from the queued drop boost balance in the `dropBoostQueue` mapping for the sender and pubkey (`dropBoostQueue[msg.sender][pubkey].balance`). It uses unchecked arithmetic for the subtraction, assuming the amount being cancelled does not exceed the queued amount. It emits the `CancelDropBoost` event with the sender, pubkey, and amount. It uses and modifies the state variable `dropBoostQueue`."
},
"BGT.dropBoost": {
"type": "external",
"function_name": "dropBoost(address user, bytes calldata pubkey)",
"analysis_result": "This function allows finalizing a queued drop boost for a specific `user` and validator `pubkey` after the required block delay has passed. It is typically called by a third party (potentially an approved sender). It retrieves the queued drop boost information (`blockNumberLast` and `amount`) from `dropBoostQueue[user][pubkey]`. It checks if the `amount` is greater than 0 and if enough blocks have passed since `blockNumberLast` by calling the internal helper function `_checkEnoughTimePassed` with `blockNumberLast` and `dropBoostDelay`. If either condition is false, it returns `false`. If conditions are met, it subtracts the `amount` from `boosted[user][pubkey]`, `totalBoosts`, and `userBoosts[user].boost`. It also subtracts the amount from `boostees[pubkey]`. It uses unchecked arithmetic for these updates, assuming the amount being dropped is available in the boosted and queued drop balances (checked in `queueDropBoost`). It deletes the entry in `dropBoostQueue[user][pubkey]`. It then calls the `withdraw` function on the contract address stored in `staker` (expected to be the `IBGTStaker` contract), passing the `user` and `amount`. Finally, it emits the `DropBoost` event with the caller (`msg.sender`), the user, pubkey, and amount, and returns `true`. It uses and modifies `boosted`, `totalBoosts`, `userBoosts`, `boostees`, `dropBoostQueue`, `dropBoostDelay`, and calls an external contract via the `staker` address."
},
"BGT.approve": {
"type": "public",
"function_name": "approve(address spender, uint256 amount)",
"analysis_result": "This function allows a user to approve a `spender` address to withdraw a specific `amount` of tokens on their behalf. It overrides the standard ERC20 `approve` function. It is restricted by the `onlyApprovedSender` modifier, meaning only addresses whitelisted as senders can call this function. It calls the inherited `super.approve(spender, amount)` from `ERC20Upgradeable` to perform the standard ERC20 approval logic, which updates the allowance mapping. It returns a boolean indicating success. It uses the state variable `isWhitelistedSender` via the modifier and internal state variables related to ERC20 allowances via the `super.approve` call."
},
"BGT.transfer": {
"type": "public",
"function_name": "transfer(address to, uint256 amount)",
"analysis_result": "This function allows a user to transfer a specific `amount` of tokens from their balance to a `to` address. It overrides the standard ERC20 `transfer` function. It is restricted by the `onlyApprovedSender` modifier, meaning only whitelisted senders can call this function. It is further restricted by the `checkUnboostedBalance` modifier, ensuring the sender has enough *unboosted* BGT balance to cover the `amount`. It calls the inherited `super.transfer(to, amount)` from `ERC20Upgradeable` to perform the standard ERC20 transfer logic, which updates balances. It returns a boolean indicating success. It uses the state variable `isWhitelistedSender` via `onlyApprovedSender`, `userBoosts` via `checkUnboostedBalance`, and internal state variables related to ERC20 balances via the `super.transfer` call."
},
"BGT.transferFrom": {
"type": "public",
"function_name": "transferFrom(address from, address to, uint256 amount)",
"analysis_result": "This function allows a `spender` (caller) to transfer a specific `amount` of tokens from the `from` address to the `to` address, provided the `spender` has sufficient allowance from `from`. It overrides the standard ERC20 `transferFrom` function. It is restricted by the `onlyApprovedSender` modifier, meaning the `from` address (not the caller) must be whitelisted as a sender. It is further restricted by the `checkUnboostedBalance` modifier, ensuring the `from` address has enough *unboosted* BGT balance. It calls the inherited `super.transferFrom(from, to, amount)` from `ERC20Upgradeable` to perform the standard ERC20 transferFrom logic, which checks allowance, updates balances, and reduces allowance. It returns a boolean indicating success. It uses the state variable `isWhitelistedSender` via `onlyApprovedSender`, `userBoosts` via `checkUnboostedBalance`, and internal state variables related to ERC20 balances and allowances via the `super.transferFrom` call."
},
"BGT.redeem": {
"type": "external",
"function_name": "redeem(address receiver, uint256 amount)",
"analysis_result": "This function allows a user (`msg.sender`) to redeem a specific `amount` of their BGT tokens for the contract's native token (ETH). It is restricted by the `checkUnboostedBalance` modifier, ensuring the sender has enough unboosted BGT to redeem. It is also subject to the `invariantCheck` modifier, ensuring the contract's ETH balance invariant is maintained after the operation. It calls the inherited internal function `super._burn(msg.sender, amount)` from `ERC20Upgradeable` to burn the BGT from the sender's account, reducing supply and balance. It then calls `SafeTransferLib.safeTransferETH(receiver, amount)` to transfer the corresponding `amount` of native token from the contract's balance to the `receiver` address. It emits the `Redeem` event with the sender, receiver, and amount. It uses the state variable `userBoosts` via `checkUnboostedBalance`, and internal state variables related to ERC20 balances and total supply via `_burn`. It also relies on the contract's native token balance."
},
"BGT.burnExceedingReserves": {
"type": "external",
"function_name": "burnExceedingReserves()",
"analysis_result": "This function allows anyone to trigger a burn of excess native token (ETH) held by the contract. The contract is intended to hold enough native token to back the total supply of BGT plus a buffer for potential future mints (based on `HISTORY_BUFFER_LENGTH` and the max BGT per block). It calculates the `potentialMintableBGT` based on `HISTORY_BUFFER_LENGTH` and the max BGT per block obtained by calling `getMaxBGTPerBlock` on the `_blockRewardController` contract. It calculates the `outstandingRequiredAmount` as the sum of the current total supply and the `potentialMintableBGT`. It then gets the contract's current native token balance (`currentReservesAmount`). If `currentReservesAmount` is not greater than `outstandingRequiredAmount`, the function returns without doing anything. If there is an excess (`currentReservesAmount > outstandingRequiredAmount`), it calculates the `excessAmountToBurn` and transfers this amount to the zero address (`address(0)`) using `SafeTransferLib.safeTransferETH(address(0), excessAmountToBurn)`, effectively burning it. It emits the `ExceedingReservesBurnt` event with the caller and the amount burned. It uses the state variables `_blockRewardController` and the internal state variable for total supply (`totalSupply()`) and relies on the contract's native token balance. It calls an external contract via the `_blockRewardController` address."
},
"BGT.minter": {
"type": "external",
"function_name": "minter()",
"analysis_result": "This getter function returns the address currently set as the BlockRewardController, which is authorized to mint BGT. It is a `view` function and returns the value of the `_blockRewardController` state variable."
},
"BGT.normalizedBoost": {
"type": "external",
"function_name": "normalizedBoost(bytes calldata pubkey)",
"analysis_result": "This getter function calculates and returns the normalized boost value for a specific validator identified by `pubkey`. The normalized boost represents the proportion of the total active boosts that is attributed to this specific validator. It checks if `totalBoosts` is 0; if so, it returns 0 to avoid division by zero. Otherwise, it calculates the normalized boost by dividing the validator's total boost (`boostees[pubkey]`) by the total active boosts (`totalBoosts`) using the `FixedPointMathLib.divWad` function, which handles fixed-point division. It uses the state variables `totalBoosts` and `boostees` and the `FixedPointMathLib` library."
},
"BGT.boosts": {
"type": "external",
"function_name": "boosts(address account)",
"analysis_result": "This getter function returns the total active boosted BGT balance for a specific `account`. It is a `view` function and returns the `boost` value from the `UserBoost` struct stored in `userBoosts[account].boost`. It uses the state variable `userBoosts`."
},
"BGT.queuedBoost": {
"type": "external",
"function_name": "queuedBoost(address account)",
"analysis_result": "This getter function returns the total queued boost balance (waiting to be activated) for a specific `account`. It is a `view` function and returns the `queuedBoost` value from the `UserBoost` struct stored in `userBoosts[account].queuedBoost`. It uses the state variable `userBoosts`."
},
"BGT.name": {
"type": "public",
"function_name": "name()",
"analysis_result": "This function returns the name of the ERC20 token. It is a `pure` function, overriding inherited `name()` functions from `IERC20Metadata` and `ERC20Upgradeable`. It simply returns the private constant string `NAME`."
},
"BGT.symbol": {
"type": "public",
"function_name": "symbol()",
"analysis_result": "This function returns the symbol of the ERC20 token. It is a `pure` function, overriding inherited `symbol()` functions from `IERC20Metadata` and `ERC20Upgradeable`. It simply returns the private constant string `SYMBOL`."
},
"BGT.unboostedBalanceOf": {
"type": "public",
"function_name": "unboostedBalanceOf(address account)",
"analysis_result": "This getter function calculates and returns the 'unboosted' balance of a specific `account`. The unboosted balance is defined as the account's total BGT balance minus their total active boosted balance and their total queued boost balance. It retrieves the account's total balance by calling the inherited `balanceOf(account)`. It retrieves the active boost (`boost`) and queued boost (`_queuedBoost`) from the `userBoosts[account]` struct. It subtracts the boost and queued boost from the total balance. It uses the state variable `userBoosts` and the inherited `balanceOf` function."
},
"BGT.clock": {
"type": "public",
"function_name": "clock()",
"analysis_result": "This function implements the `clock()` function required by the `IERC6372` interface. It returns a `uint48` representing the current timestamp. It calls `Time.timestamp()` from the imported OpenZeppelin `Time` library to get the current block timestamp."
},
"BGT.CLOCK_MODE": {
"type": "public",
"function_name": "CLOCK_MODE()",
"analysis_result": "This function implements the `CLOCK_MODE()` function required by the `IERC6372` interface. It returns a string describing the clock mode used. It is a `pure` function and returns the string \"mode=timestamp\"."
},
"BGT._checkUnboostedBalance": {
"type": "private",
"function_name": "_checkUnboostedBalance(address sender, uint256 amount)",
"analysis_result": "This internal helper function checks if the unboosted balance of a `sender` is sufficient for a given `amount`. It calls the public getter function `unboostedBalanceOf(sender)` to get the sender's unboosted balance. If the unboosted balance is less than the `amount`, it reverts with the custom error `NotEnoughBalance` using its selector. It uses the state variable `userBoosts` indirectly via `unboostedBalanceOf`."
},
"BGT._checkEnoughTimePassed": {
"type": "private",
"function_name": "_checkEnoughTimePassed(uint32 blockNumberLast, uint32 blockBufferDelay)",
"analysis_result": "This internal helper function checks if enough blocks have passed since a specific block number (`blockNumberLast`) compared to a required delay (`blockBufferDelay`). It calculates the block difference (`delta`) using `uint32(block.number) - blockNumberLast` within an unchecked block to prevent overflow/underflow reverts for typical use cases (block numbers increase sequentially). If the `delta` is less than or equal to `blockBufferDelay`, it means not enough time has passed, and it returns `false`. Otherwise, it returns `true`. It uses the block.number global variable."
},
"BGT._invariantCheck": {
"type": "private",
"function_name": "_invariantCheck()",
"analysis_result": "This internal helper function checks a critical contract invariant: that the contract's native token (ETH) balance is not less than the total supply of BGT. It compares `address(this).balance` with the result of `totalSupply()`. If `address(this).balance` is less than `totalSupply()`, it means the contract does not hold enough native token to back the BGT supply, and it reverts with the custom error `InvariantCheckFailed` using its selector. It uses the internal state variable for total supply (`totalSupply()`) and relies on the contract's native token balance."
},
"BGTFeeDeployer.constructor": {
"type": "constructor",
"function_name": "constructor(address bgt, address governance, address rewardToken, uint256 bgtStakerSalt, uint256 feeCollectorSalt, uint256 payoutAmount)",
"analysis_result": "This is the constructor for the BGTFeeDeployer contract. Its purpose is to deploy and initialize the BGTStaker and FeeCollector contracts using the CREATE2 opcode. It takes six parameters: `bgt` (address of the BGT token), `governance` (address of the governance contract), `rewardToken` (address of the reward token), `bgtStakerSalt` (salt for the BGTStaker proxy deployment), `feeCollectorSalt` (salt for the FeeCollector proxy deployment), and `payoutAmount` (initial payout amount for the FeeCollector). The constructor first uses the inherited `deployWithCreate2` function (presumably from `Create2Deployer`) to deploy the *implementation* contract of `BGTStaker` using its creation code and a salt of 0. It then uses the inherited `deployProxyWithCreate2` function to deploy the *proxy* contract for `BGTStaker`, using the previously deployed implementation address and the provided `bgtStakerSalt`. The address of the deployed BGTStaker proxy is cast to the `BGTStaker` type and assigned to the `bgtStaker` immutable state variable. The same process is repeated for the `FeeCollector` contract: its implementation is deployed with salt 0 using `deployWithCreate2`, and its proxy is deployed using the implementation address and the provided `feeCollectorSalt` via `deployProxyWithCreate2`. The address of the deployed FeeCollector proxy is cast to the `FeeCollector` type and assigned to the `feeCollector` immutable state variable. Finally, the constructor calls the `initialize` function on both the newly deployed `bgtStaker` and `feeCollector` proxy contracts to set up their initial state. The `bgtStaker.initialize` call receives the `bgt` token address, the address of the `feeCollector` contract, the `governance` address, and the `rewardToken` address. The `feeCollector.initialize` call receives the `governance` address, the `rewardToken` address, the address of the `bgtStaker` contract, and the `payoutAmount`. This function modifies the immutable state variables `bgtStaker` and `feeCollector` by assigning them the addresses of the deployed proxy contracts."
},
"RewardVault.constructor": {
"type": "constructor",
"function_name": "constructor()",
"analysis_result": "The constructor for the `RewardVault` contract. It is marked with `/// @custom:oz-upgrades-unsafe-allow constructor` and calls `_disableInitializers()`. This is a standard pattern for upgradeable contracts using the OpenZeppelin Upgrades plugin, ensuring that the `initialize` function must be called instead of the constructor for initial setup after deployment."
},
"RewardVault.initialize": {
"type": "external",
"function_name": "initialize(address _beaconDepositContract, address _bgt, address _distributor, address _stakingToken)",
"analysis_result": "This is the initializer function for the upgradeable contract, called once after deployment. It takes the addresses of the `beaconDepositContract`, `bgt` (reward token), `distributor`, and `stakingToken` as parameters. It calls initializers for inherited contracts: `__FactoryOwnable_init(msg.sender)`, `__Pausable_init()`, `__ReentrancyGuard_init()`, and `__StakingRewards_init(_stakingToken, _bgt, 3 days)`. It sets the `maxIncentiveTokensCount` to 3, `distributor` to `_distributor` (includes a `slither-disable-next-line missing-zero-check`), and `beaconDepositContract` to the provided address. It emits the `DistributorSet` and `MaxIncentiveTokensCountUpdated` events. Storage variables modified: `owner` (via `__FactoryOwnable_init`), `_paused` (via `__Pausable_init`), `_notEntered` (via `__ReentrancyGuard_init`), `stakeToken`, `rewardToken`, `rewardsDuration` (via `__StakingRewards_init`), `maxIncentiveTokensCount`, `distributor`, `beaconDepositContract`. Requires the `initializer` modifier."
},
"RewardVault.onlyDistributor": {
"type": "modifier",
"function_name": "onlyDistributor()",
"analysis_result": "This modifier checks if the `msg.sender` is equal to the stored `distributor` address. If not, it reverts with the `NotDistributor` error selector. It is used to restrict access to functions that should only be callable by the designated distributor contract."
},
"RewardVault.onlyOperatorOrUser": {
"type": "modifier",
"function_name": "onlyOperatorOrUser(address account)",
"analysis_result": "This modifier checks if the `msg.sender` is either the `account` itself or the operator address stored for that `account` in the `_operators` mapping. If neither condition is met, it reverts with the `NotOperator` error selector. It is used to control access to functions that can be called by an account or its designated operator."
},
"RewardVault.checkSelfStakedBalance": {
"type": "modifier",
"function_name": "checkSelfStakedBalance(address account, uint256 amount)",
"analysis_result": "This modifier calls the internal function `_checkSelfStakedBalance(account, amount)` to verify that the specified `account` has a sufficient self-staked balance (total stake minus stake delegated by others) to cover the requested `amount`. It is used to ensure that withdrawal amounts do not exceed the portion of stake that was directly staked by the user."
},
"RewardVault.onlyWhitelistedToken": {
"type": "modifier",
"function_name": "onlyWhitelistedToken(address token)",
"analysis_result": "This modifier checks if the provided `token` address is whitelisted as an incentive token. It does this by looking up the token in the `incentives` mapping and checking if its `minIncentiveRate` is non-zero. If the token is not whitelisted, it reverts with the `TokenNotWhitelisted` error selector. It is used to restrict operations related to incentive tokens to only those that have been explicitly whitelisted."
},
"RewardVault.setDistributor": {
"type": "external",
"function_name": "setDistributor(address _rewardDistribution)",
"analysis_result": "Allows the factory owner to set a new address for the `distributor` contract. It requires the `_rewardDistribution` address to be non-zero. Updates the `distributor` storage variable and emits the `DistributorSet` event. Storage variables modified: `distributor`. Requires the `onlyFactoryOwner` modifier (inherited)."
},
"RewardVault.notifyRewardAmount": {
"type": "external",
"function_name": "notifyRewardAmount(bytes calldata pubkey, uint256 reward)",
"analysis_result": "This function is called by the `distributor` to notify the contract about a new reward amount (`reward`) for a specific validator identified by their `pubkey`. It first calls the inherited `_notifyRewardAmount(reward)` from `StakingRewards` to update the BGT reward state. Then, it calls the internal `_processIncentives(pubkey, reward)` function to handle the distribution of whitelisted incentive tokens based on this BGT emission. Storage variables modified: `rewardRate`, `lastUpdateTime`, `rewardPerTokenStored`, `undistributedRewards` (via `_notifyRewardAmount`), `incentives[token].amountRemaining` (via `_processIncentives`). Requires the `onlyDistributor` modifier."
},
"RewardVault.recoverERC20": {
"type": "external",
"function_name": "recoverERC20(address tokenAddress, uint256 tokenAmount)",
"analysis_result": "Allows the factory owner to recover accidental ERC20 token transfers to the contract. It takes the `tokenAddress` and `tokenAmount` to recover. It explicitly prevents recovering the `stakeToken` or any token that is currently whitelisted as an incentive token by checking `incentives[tokenAddress].minIncentiveRate != 0`. It uses `SafeERC20.safeTransfer` to send the `tokenAmount` of `tokenAddress` to `msg.sender`. Emits the `Recovered` event. Storage variables read: `stakeToken`, `incentives`. Requires the `onlyFactoryOwner` modifier (inherited)."
},
"RewardVault.setRewardsDuration": {
"type": "external",
"function_name": "setRewardsDuration(uint256 _rewardsDuration)",
"analysis_result": "Allows the factory owner to set a new duration for the reward distribution period. It calls the inherited `_setRewardsDuration(_rewardsDuration)` from `StakingRewards`. This function might affect the calculated reward rate. Storage variables modified: `rewardsDuration` (via `_setRewardsDuration`). Requires the `onlyFactoryOwner` modifier (inherited)."
},
"RewardVault.whitelistIncentiveToken": {
"type": "external",
"function_name": "whitelistIncentiveToken(address token, uint256 minIncentiveRate, address manager)",
"analysis_result": "Allows the factory owner to add a new token to the list of whitelisted incentive tokens. It takes the `token` address, a `minIncentiveRate` (minimum amount per BGT emission), and the `manager` address responsible for adding this token. It validates that `minIncentiveRate` is non-zero and within `MAX_INCENTIVE_RATE`, and that `token` and `manager` addresses are non-zero. It checks if the `maxIncentiveTokensCount` limit has been reached or if the token is already whitelisted. It pushes the `token` to the `whitelistedTokens` array, sets the initial `incentiveRate` and `minIncentiveRate` for the token in the `incentives` mapping, and sets the `manager`. Emits the `IncentiveTokenWhitelisted` event. Storage variables modified: `incentives`, `whitelistedTokens`. Storage variables read: `maxIncentiveTokensCount`. Requires the `onlyFactoryOwner` modifier (inherited)."
},
"RewardVault.removeIncentiveToken": {
"type": "external",
"function_name": "removeIncentiveToken(address token)",
"analysis_result": "Allows the factory vault manager to remove a token from the whitelisted incentive tokens list. It requires the `token` to be currently whitelisted using the `onlyWhitelistedToken` modifier. It deletes the token's data from the `incentives` mapping and calls the internal helper `_deleteWhitelistedTokenFromList(token)` to remove it from the `whitelistedTokens` array. Emits the `IncentiveTokenRemoved` event. Storage variables modified: `incentives`, `whitelistedTokens` (via `_deleteWhitelistedTokenFromList`). Requires the `onlyFactoryVaultManager` (inherited) and `onlyWhitelistedToken` modifiers."
},
"RewardVault.updateIncentiveManager": {
"type": "external",
"function_name": "updateIncentiveManager(address token, address newManager)",
"analysis_result": "Allows the factory owner to update the `manager` address for an existing whitelisted incentive token. It takes the `token` address and the `newManager` address. It requires the `token` to be whitelisted and the `newManager` address to be non-zero. It updates the `manager` field in the `incentives` mapping for the given token. Emits the `IncentiveManagerChanged` event, including the old and new manager addresses. Storage variables modified: `incentives[token].manager`. Requires the `onlyFactoryOwner` (inherited) and `onlyWhitelistedToken` modifiers."
},
"RewardVault.setMaxIncentiveTokensCount": {
"type": "external",
"function_name": "setMaxIncentiveTokensCount(uint8 _maxIncentiveTokensCount)",
"analysis_result": "Allows the factory owner to set the maximum number of incentive tokens that can be whitelisted. It takes the `_maxIncentiveTokensCount` as a parameter. It requires the new maximum count to be greater than or equal to the current number of whitelisted tokens (`whitelistedTokens.length`). Updates the `maxIncentiveTokensCount` storage variable. Emits the `MaxIncentiveTokensCountUpdated` event. Storage variables modified: `maxIncentiveTokensCount`. Storage variables read: `whitelistedTokens`. Requires the `onlyFactoryOwner` modifier (inherited)."
},
"RewardVault.pause": {
"type": "external",
"function_name": "pause()",
"analysis_result": "Pauses the contract, preventing execution of functions protected by the `whenNotPaused` modifier. It calls the inherited `_pause()` function from `PausableUpgradeable`. Requires the `onlyFactoryVaultPauser` modifier (inherited)."
},
"RewardVault.unpause": {
"type": "external",
"function_name": "unpause()",
"analysis_result": "Unpauses the contract, allowing execution of functions protected by the `whenNotPaused` modifier. It calls the inherited `_unpause()` function from `PausableUpgradeable`. Requires the `onlyFactoryVaultManager` modifier (inherited)."
},
"RewardVault.operator": {
"type": "external",
"function_name": "operator(address account)",
"analysis_result": "A public view function that returns the operator address for a given `account` by querying the `_operators` mapping. Storage variables read: `_operators`. Returns: `address`."
},
"RewardVault.getWhitelistedTokensCount": {
"type": "external",
"function_name": "getWhitelistedTokensCount()",
"analysis_result": "A public view function that returns the current number of whitelisted incentive tokens. It returns the length of the `whitelistedTokens` array. Storage variables read: `whitelistedTokens`. Returns: `uint256`."
},
"RewardVault.getWhitelistedTokens": {
"type": "public",
"function_name": "getWhitelistedTokens() view returns (address[] memory)",
"analysis_result": "A public view function that returns the array of all whitelisted incentive token addresses (`whitelistedTokens`). Storage variables read: `whitelistedTokens`. Returns: `address[] memory`."
},
"RewardVault.getTotalDelegateStaked": {
"type": "external",
"function_name": "getTotalDelegateStaked(address account)",
"analysis_result": "A public view function that returns the total amount of stake delegated by others to a specific `account`. It queries the `_delegateStake` mapping for the `account` and returns the `delegateTotalStaked` field. Storage variables read: `_delegateStake`. Returns: `uint256`."
},
"RewardVault.getDelegateStake": {
"type": "external",
"function_name": "getDelegateStake(address account, address delegate)",
"analysis_result": "A public view function that returns the amount of stake delegated by a specific `delegate` to a specific `account`. It queries the `_delegateStake` mapping for the `account` and then looks up the `delegate` in the nested `stakedByDelegate` mapping. Storage variables read: `_delegateStake`. Returns: `uint256`."
},
"RewardVault.stake": {
"type": "external",
"function_name": "stake(uint256 amount)",
"analysis_result": "Allows `msg.sender` to stake `amount` of the `stakeToken`. It uses the `nonReentrant` and `whenNotPaused` modifiers to prevent reentrancy and ensure the contract is not paused. It calls the inherited `_stake(msg.sender, amount)` function from `StakingRewards` to handle the staking logic (transferring tokens to the contract, updating total supply, and updating user's account balance). Storage variables modified: `_accountInfo[msg.sender].balance`, `totalSupply` (via `_stake`). Requires the `nonReentrant` and `whenNotPaused` modifiers."
},
"RewardVault.delegateStake": {
"type": "external",
"function_name": "delegateStake(address account, uint256 amount)",
"analysis_result": "Allows `msg.sender` (a delegate) to stake `amount` on behalf of another `account`. It requires `msg.sender` not to be the same as `account`. It uses the `nonReentrant` and `whenNotPaused` modifiers. It first calls the inherited `_stake(account, amount)` function to perform the actual staking of tokens for the specified `account`. Then, in an unchecked block, it updates the `_delegateStake` mapping for the `account`: incrementing `delegateTotalStaked` and the amount staked by the specific `msg.sender` delegate (`stakedByDelegate[msg.sender]`). Emits the `DelegateStaked` event. Storage variables modified: `_accountInfo[account].balance`, `totalSupply` (via `_stake`), `_delegateStake[account].delegateTotalStaked`, `_delegateStake[account].stakedByDelegate[msg.sender]`. Requires the `nonReentrant` and `whenNotPaused` modifiers."
},
"RewardVault.withdraw": {
"type": "external",
"function_name": "withdraw(uint256 amount)",
"analysis_result": "Allows `msg.sender` to withdraw `amount` of their self-staked tokens. It uses the `nonReentrant` and `checkSelfStakedBalance(msg.sender, amount)` modifiers. The `checkSelfStakedBalance` modifier ensures that the withdrawn `amount` does not exceed the portion of the user's total stake that was not delegated by others. It calls the inherited `_withdraw(msg.sender, amount)` function from `StakingRewards` to handle the withdrawal logic (transferring tokens from the contract, updating total supply, and updating user's account balance). Storage variables modified: `_accountInfo[msg.sender].balance`, `totalSupply` (via `_withdraw`). Storage variables read: `_accountInfo[msg.sender].balance`, `_delegateStake[msg.sender].delegateTotalStaked` (via `checkSelfStakedBalance`). Requires the `nonReentrant` and `checkSelfStakedBalance` modifiers."
},
"RewardVault.delegateWithdraw": {
"type": "external",
"function_name": "delegateWithdraw(address account, uint256 amount)",
"analysis_result": "Allows `msg.sender` (a delegate) to withdraw `amount` from the stake they previously delegated to an `account`. It requires `msg.sender` not to be the same as `account`. It uses the `nonReentrant` modifier. It retrieves the amount staked by the delegate (`stakedByDelegate[msg.sender]`) from the `_delegateStake` mapping for the `account`. It checks if this amount is sufficient for the withdrawal, reverting with `InsufficientDelegateStake` if not. In an unchecked block, it decreases `_delegateStake[account].stakedByDelegate[msg.sender]` and `_delegateStake[account].delegateTotalStaked` by the `amount`. Finally, it calls the inherited `_withdraw(account, amount)` function to perform the actual token transfer and update the `account`'s total stake. Emits the `DelegateWithdrawn` event. Storage variables modified: `_delegateStake[account].stakedByDelegate[msg.sender]`, `_delegateStake[account].delegateTotalStaked`, `_accountInfo[account].balance`, `totalSupply` (via `_withdraw`). Requires the `nonReentrant` modifier."
},
"RewardVault.getReward": {
"type": "external",
"function_name": "getReward(address account, address recipient) returns (uint256)",
"analysis_result": "Allows an `account` or their designated operator (`msg.sender`) to claim pending BGT rewards. It takes the `account` whose rewards are being claimed and the `recipient` address where the rewards should be sent. It uses the `nonReentrant` and `onlyOperatorOrUser(account)` modifiers. It calls the inherited `_getReward(account, recipient)` function from `StakingRewards` to calculate and transfer the earned rewards to the `recipient`. Returns the amount of reward transferred. Storage variables modified: `userRewardPerTokenPaid[account]`, `rewards[account]` (via `_getReward`). Requires the `nonReentrant` and `onlyOperatorOrUser` modifiers."
},
"RewardVault.exit": {
"type": "external",
"function_name": "exit(address recipient)",
"analysis_result": "Allows `msg.sender` to withdraw all their self-staked tokens and claim all pending BGT rewards in a single transaction. It uses the `nonReentrant` modifier. It calculates the user's self-staked amount by subtracting the total delegated stake (`_delegateStake[msg.sender].delegateTotalStaked`) from their total stake (`_accountInfo[msg.sender].balance`). It then calls the inherited `_withdraw(msg.sender, amount)` to withdraw the self-staked amount and the inherited `_getReward(msg.sender, recipient)` to claim rewards and send them to the `recipient`. Storage variables read: `_accountInfo[msg.sender].balance`, `_delegateStake[msg.sender].delegateTotalStaked`. Storage variables modified: `_accountInfo[msg.sender].balance`, `totalSupply`, `userRewardPerTokenPaid[msg.sender]`, `rewards[msg.sender]` (via `_withdraw` and `_getReward`). Requires the `nonReentrant` modifier."
},
"RewardVault.setOperator": {
"type": "external",
"function_name": "setOperator(address _operator)",
"analysis_result": "Allows `msg.sender` to set or update their designated operator address. It takes the `_operator` address as a parameter. It updates the `_operators` mapping for `msg.sender`. Emits the `OperatorSet` event, showing the user and their new operator. Storage variables modified: `_operators[msg.sender]`."
},
"RewardVault.addIncentive": {
"type": "external",
"function_name": "addIncentive(address token, uint256 amount, uint256 incentiveRate)",
"analysis_result": "Allows the manager of a whitelisted incentive token to add more incentive tokens to the contract and optionally update the `incentiveRate`. It requires the `token` to be whitelisted via the `onlyWhitelistedToken` modifier. It uses the `nonReentrant` modifier. It checks if `msg.sender` is the designated `manager` for the token. It validates that the `amount` is at least the `minIncentiveRate` and that the new `incentiveRate` is at least the `minIncentiveRate` and within `MAX_INCENTIVE_RATE`. It uses `SafeERC20.safeTransferFrom` to pull the `amount` of tokens from the manager's address to the contract. It adds the `amount` to the `incentives[token].amountRemaining`. It updates the `incentiveRate` if the `amountRemaining` *before* adding the new amount was 0, or if the new `incentiveRate` is greater than or equal to the stored rate. If `amountRemainingBefore` is non-zero and the new rate is less than the stored rate, it reverts with `InvalidIncentiveRate`. Emits the `IncentiveAdded` event. Storage variables modified: `incentives[token].amountRemaining`, `incentives[token].incentiveRate`. Storage variables read: `incentives[token]`. Requires the `nonReentrant` and `onlyWhitelistedToken` modifiers."
},
"RewardVault.accountIncentives": {
"type": "external",
"function_name": "accountIncentives(address token, uint256 amount)",
"analysis_result": "Allows the manager of a whitelisted incentive token to increase the `amountRemaining` for a token without transferring new tokens into the contract. This might be used if tokens are deposited via a different method. It requires the `token` to be whitelisted via `onlyWhitelistedToken` and uses the `nonReentrant` modifier. It checks if `msg.sender` is the designated `manager`. It validates that the `amount` is at least the `minIncentiveRate`. It checks if the contract's balance of the `token` minus the current `amountRemaining` is sufficient to 'account for' the `amount`, preventing adding more to `amountRemaining` than exists in the contract beyond the previously accounted-for amount. It adds the `amount` to `incentives[token].amountRemaining`. Emits the `IncentiveAdded` event (note: same event as `addIncentive`). Storage variables modified: `incentives[token].amountRemaining`. Storage variables read: `incentives[token]`. External calls: `IERC20(token).balanceOf(address(this))`. Requires the `nonReentrant` and `onlyWhitelistedToken` modifiers."
},
"RewardVault._checkSelfStakedBalance": {
"type": "internal",
"function_name": "_checkSelfStakedBalance(address account, uint256 amount) view",
"analysis_result": "An internal helper function used by the `checkSelfStakedBalance` modifier. It calculates the `selfStaked` balance for an `account` by subtracting the total amount delegated *to* that account (`_delegateStake[account].delegateTotalStaked`) from the account's total balance (`_accountInfo[account].balance`) in the `StakingRewards` system. It then checks if the calculated `selfStaked` amount is less than the requested `amount` to be withdrawn. If it is, it reverts with `InsufficientSelfStake`. This ensures users can only withdraw the stake they deposited themselves, not stake delegated to them. Storage variables read: `_accountInfo`, `_delegateStake`."
},
"RewardVault._safeTransferRewardToken": {
"type": "internal",
"function_name": "_safeTransferRewardToken(address to, uint256 amount) override",
"analysis_result": "Overrides the internal function from the `StakingRewards` base contract. This function is called by `_getReward` in the base contract when distributing rewards. It performs the actual transfer of the `rewardToken` from the `distributor` address to the `to` address. It uses `rewardToken.safeTransferFrom(distributor, to, amount)`. This requires that the `distributor` contract has previously approved the `RewardVault` contract to spend its `rewardToken` balance. Storage variables read: `distributor`, `rewardToken`. External calls: `rewardToken.safeTransferFrom`."
},
"RewardVault._checkRewardSolvency": {
"type": "internal",
"function_name": "_checkRewardSolvency() view override",
"analysis_result": "Overrides the internal function from the `StakingRewards` base contract. This function is called by `_notifyRewardAmount` in the base contract to ensure that the reward amount being added does not exceed the contract's ability to pay it out based on the allowance granted by the `distributor`. It checks if the `undistributedRewards` (which includes the new reward) divided by `PRECISION` (to adjust for decimals) is greater than the `allowance` granted by the `distributor` to this contract for the `rewardToken`. If it is greater, it means the distributor hasn't provided sufficient allowance for the reward announced, and the function reverts with `InsolventReward`. Storage variables read: `undistributedRewards`, `distributor`, `rewardToken`. External calls: `rewardToken.allowance(distributor, address(this))`."
},
"RewardVault._processIncentives": {
"type": "internal",
"function_name": "_processIncentives(bytes calldata pubkey, uint256 bgtEmitted)",
"analysis_result": "This internal function is called by `notifyRewardAmount` to process the distribution of whitelisted incentive tokens when BGT is emitted (`bgtEmitted`) for a specific validator (`pubkey`). It determines the validator's operator address using `beaconDepositContract.getOperator(pubkey)`. It gets addresses for `beraChef` and `bgtIncentiveDistributor` from the `distributor` contract. It iterates through the `whitelistedTokens` array. For each token, it calculates the `amount` of incentive to distribute based on `bgtEmitted` and `incentive.incentiveRate` using `FixedPointMathLib.mulDiv`, capped by the `incentive.amountRemaining`. If `amount > 0`, it calculates the `validatorShare` using `beraChef.getValidatorIncentiveTokenShare`. It attempts to transfer the `validatorShare` to the validator's operator using a low-level `token.trySafeTransfer(_operator, validatorShare)`. If successful, it updates `amountRemaining` and emits `IncentivesProcessed`. If unsuccessful, it emits `IncentivesProcessFailed`. If any `amount` remains after the validator share, it attempts to transfer it to the `bgtIncentiveDistributor` for BGT boosters. This involves two low-level calls with a `SAFE_GAS_LIMIT`: first, approving the `bgtIncentiveDistributor` to spend the amount via `IERC20.approve`; second, calling `IBGTIncentiveDistributor.receiveIncentive` on the distributor contract. If the receive call succeeds, it updates `amountRemaining` and emits `BGTBoosterIncentivesProcessed`. If either the approve or receive call fails, it emits `BGTBoosterIncentivesProcessFailed` and attempts to reset the allowance to 0 for USDT compatibility. Finally, it updates `incentive.amountRemaining` in storage for the current token. Storage variables read: `beaconDepositContract`, `distributor`, `whitelistedTokens`, `incentives`. Storage variables modified: `incentives[token].amountRemaining`. External calls: `beaconDepositContract.getOperator`, `IDistributor(distributor).beraChef`, `getBGTIncentiveDistributor`, `beraChef.getValidatorIncentiveTokenShare`, `token.trySafeTransfer` (low-level), `token.call` (low-level for approve), `bgtIncentiveDistributor.call` (low-level for receiveIncentive), `token.call` (low-level for resetting allowance). Events emitted: `IncentivesProcessed`, `IncentivesProcessFailed`, `BGTBoosterIncentivesProcessed`, `BGTBoosterIncentivesProcessFailed`."
},
"RewardVault._deleteWhitelistedTokenFromList": {
"type": "internal",
"function_name": "_deleteWhitelistedTokenFromList(address token)",
"analysis_result": "An internal helper function called by `removeIncentiveToken` to remove a specific `token` address from the `whitelistedTokens` dynamic array. It iterates through the array to find the index of the `token`. Once found, it swaps the found element with the last element in the array and then uses `whitelistedTokens.pop()` to remove the last element effectively. This maintains the order of other elements but is an efficient way to remove an element from an array by index. Storage variables modified: `whitelistedTokens`. Storage variables read: `whitelistedTokens`."
},
"BlockRewardController.constructor": {
"type": "constructor",
"function_name": "constructor()",
"analysis_result": "This is the constructor for the `BlockRewardController` contract. It is marked with `/// @custom:oz-upgrades-unsafe-allow constructor` and calls `_disableInitializers()`. This pattern is used in OpenZeppelin UUPS upgradeable contracts to prevent the `initialize` function from being called twice on the implementation contract itself, ensuring it can only be called on the proxy."
},
"BlockRewardController.initialize": {
"type": "external",
"function_name": "initialize(address _bgt, address _distributor, address _beaconDepositContract, address _governance)",
"analysis_result": "This is the initializer function for the upgradeable contract, called once via the proxy upon deployment. It requires the `initializer` modifier. It initializes the `OwnableUpgradeable` aspect by setting the contract owner to `_governance` using `__Ownable_init(_governance)`. It also initializes the `UUPSUpgradeable` aspect using `__UUPSUpgradeable_init()`. It sets the storage variable `bgt` to the address of the BGT token contract (`_bgt`) and `beaconDepositContract` to the address of the `IBeaconDeposit` contract (`_beaconDepositContract`). It sets the `distributor` address to `_distributor` and emits a `SetDistributor` event. It uses `slither-disable-next-line missing-zero-check` comments for the distributor and beacon deposit addresses, indicating a potential consideration about zero address checks, although the code explicitly checks for `_distributor == address(0)` in `setDistributor`. It relies on the caller providing valid, non-zero addresses for BGT, distributor, and beacon deposit contracts."
},
"BlockRewardController._authorizeUpgrade": {
"type": "internal",
"function_name": "_authorizeUpgrade(address newImplementation)",
"analysis_result": "This is an internal function required by the `UUPSUpgradeable` pattern. It defines who is authorized to perform upgrades. The current implementation simply applies the `onlyOwner` modifier. This means only the contract's owner (set during initialization) can call this function and thus authorize an upgrade to `newImplementation`. It does not access or modify any storage variables directly, but relies on the `owner()` state variable implicitly through the `onlyOwner` modifier."
},
"BlockRewardController.onlyDistributor": {
"type": "modifier",
"function_name": "onlyDistributor()",
"analysis_result": "This modifier is used to restrict function access. It checks if the `msg.sender` is equal to the address stored in the `distributor` state variable. If the sender is not the distributor, it reverts the transaction with the custom error `NotDistributor`. It is used to protect functions that should only be callable by the designated distributor contract."
},
"BlockRewardController.setBaseRate": {
"type": "external",
"function_name": "setBaseRate(uint256 _baseRate)",
"analysis_result": "This function allows the contract owner to set the `baseRate` storage variable. It takes a `uint256 _baseRate` as input. It first checks if `_baseRate` is greater than the constant `MAX_BASE_RATE`. If it is, the transaction is reverted with the custom error `InvalidBaseRate`. Otherwise, it emits a `BaseRateChanged` event with the old and new values and updates the `baseRate` storage variable to `_baseRate`. This function is restricted to the contract `onlyOwner`."
},
"BlockRewardController.setRewardRate": {
"type": "external",
"function_name": "setRewardRate(uint256 _rewardRate)",
"analysis_result": "This function allows the contract owner to set the `rewardRate` storage variable. It takes a `uint256 _rewardRate` as input. It first checks if `_rewardRate` is greater than the constant `MAX_REWARD_RATE`. If it is, the transaction is reverted with the custom error `InvalidRewardRate`. Otherwise, it emits a `RewardRateChanged` event with the old and new values and updates the `rewardRate` storage variable to `_rewardRate`. This function is restricted to the contract `onlyOwner`."
},
"BlockRewardController.setMinBoostedRewardRate": {
"type": "external",
"function_name": "setMinBoostedRewardRate(uint256 _minBoostedRewardRate)",
"analysis_result": "This function allows the contract owner to set the `minBoostedRewardRate` storage variable. It takes a `uint256 _minBoostedRewardRate` as input. It first checks if `_minBoostedRewardRate` is greater than the constant `MAX_MIN_BOOSTED_REWARD_RATE`. If it is, the transaction is reverted with the custom error `InvalidMinBoostedRewardRate`. Otherwise, it emits a `MinBoostedRewardRateChanged` event with the old and new values and updates the `minBoostedRewardRate` storage variable to `_minBoostedRewardRate`. This function is restricted to the contract `onlyOwner`."
},
"BlockRewardController.setBoostMultiplier": {
"type": "external",
"function_name": "setBoostMultiplier(uint256 _boostMultiplier)",
"analysis_result": "This function allows the contract owner to set the `boostMultiplier` storage variable. It takes a `uint256 _boostMultiplier` as input. It first checks if `_boostMultiplier` is greater than the constant `MAX_BOOST_MULTIPLIER`. If it is, the transaction is reverted with the custom error `InvalidBoostMultiplier`. Otherwise, it emits a `BoostMultiplierChanged` event with the old and new values and updates the `boostMultiplier` storage variable to `_boostMultiplier`. This function is restricted to the contract `onlyOwner`."
},
"BlockRewardController.setRewardConvexity": {
"type": "external",
"function_name": "setRewardConvexity(uint256 _rewardConvexity)",
"analysis_result": "This function allows the contract owner to set the `rewardConvexity` storage variable. It takes a `uint256 _rewardConvexity` as input. It first checks if `_rewardConvexity` is zero or greater than the constant `MAX_REWARD_CONVEXITY`. If it is, the transaction is reverted with the custom error `InvalidRewardConvexity`. Otherwise, it emits a `RewardConvexityChanged` event with the old (casted from int256 to uint256 for the event) and new values. It then updates the `rewardConvexity` storage variable, storing the provided `uint256` value as an `int256` to avoid casting during future calculations. This function is restricted to the contract `onlyOwner`."
},
"BlockRewardController.setDistributor": {
"type": "external",
"function_name": "setDistributor(address _distributor)",
"analysis_result": "This function allows the contract owner to set the address of the distributor contract. It takes an `address _distributor` as input. It first checks if `_distributor` is the zero address. If it is, the transaction is reverted with the custom error `ZeroAddress`. Otherwise, it emits a `SetDistributor` event with the new address and updates the `distributor` storage variable to `_distributor`. This function is restricted to the contract `onlyOwner`."
},
"BlockRewardController.computeReward": {
"type": "public",
"function_name": "computeReward(uint256 boostPower, uint256 _rewardRate, uint256 _boostMultiplier, int256 _rewardConvexity)",
"analysis_result": "This function computes the reward amount based on validator boost power and global reward parameters. It is a `pure` function, meaning it does not read from or write to storage. It takes `boostPower`, `_rewardRate`, `_boostMultiplier`, and `_rewardConvexity` as input parameters. It uses the `FixedPointMathLib` for fixed-point arithmetic operations (specifically `WAD`, `powWad`, `mulWad`, `divWad`). The function implements a specific mathematical formula to calculate the `reward`. It handles the edge case `boostPower == 0` by returning 0 reward. It includes a specific check `if (boostPower == one)` (where `one` is `FixedPointMathLib.WAD`) to avoid approximation errors for the specific case where boost power is exactly 1 WAD. The core logic calculates a coefficient based on the formula involving `_boostMultiplier`, `boostPower` raised to the power of `_rewardConvexity`, and then multiplies this coefficient by `_rewardRate`. It includes a check `if (coeff > _boostMultiplier) coeff = _boostMultiplier;` which is noted in the code comments as potentially necessary due to precision errors in splitting the fixed-point operations. It returns the calculated `reward` (uint256)."
},
"BlockRewardController.getMaxBGTPerBlock": {
"type": "public",
"function_name": "getMaxBGTPerBlock()",
"analysis_result": "This function calculates and returns the maximum possible BGT reward that could be processed in a block. It is a `view` function, reading from storage but not modifying it. It calls the internal `computeReward` function with `FixedPointMathLib.WAD` as the `boostPower`, and the contract's current storage variables `rewardRate`, `boostMultiplier`, and `rewardConvexity`. This calculates the maximum possible boosted reward. It then checks if this computed reward is less than the `minBoostedRewardRate` storage variable; if so, it sets the reward to `minBoostedRewardRate`. Finally, it adds the `baseRate` storage variable to this value to get the total maximum potential reward (`amount`) per block and returns it. It uses `rewardRate`, `boostMultiplier`, `rewardConvexity`, `minBoostedRewardRate`, and `baseRate` storage variables."
},
"BlockRewardController.processRewards": {
"type": "external",
"function_name": "processRewards(bytes calldata pubkey, uint64 nextTimestamp, bool isReady)",
"analysis_result": "This is the main function for processing block rewards for a specific validator identified by `pubkey`. It is restricted to the contract `onlyDistributor`. It takes `pubkey` (validator's public key), `nextTimestamp`, and `isReady` (boolean indicating if berachef/validator is ready) as input. It reads the `baseRate` storage variable. It initializes a local `reward` variable to 0. If `isReady` is true, it calculates the boosted reward: it calls `bgt.normalizedBoost(pubkey)` to get the validator's boost power, then calls the internal `computeReward` function with this boost power and the contract's stored `rewardRate`, `boostMultiplier`, and `rewardConvexity`. It checks if the calculated `reward` is less than the `minBoostedRewardRate` storage variable and sets `reward` to `minBoostedRewardRate` if necessary. After calculating the reward (either boosted or 0 if not ready), it emits a `BlockRewardProcessed` event with `pubkey`, `nextTimestamp`, `baseRate`, and the calculated `reward`. It then interacts with external contracts: it calls `beaconDepositContract.getOperator(pubkey)` to get the operator address associated with the validator's `pubkey`. The comment states this is guaranteed to return a valid address. If `baseRate` is greater than 0, it calls `bgt.mint(operator, base)` to mint the base reward portion to the validator's operator. If the calculated `reward` (boosted reward) is greater than 0, it calls `bgt.mint(distributor, reward)` to mint the boosted reward portion to the `distributor` contract. It returns the calculated `reward` (uint256). It uses `baseRate`, `rewardRate`, `boostMultiplier`, `rewardConvexity`, `minBoostedRewardRate`, `bgt`, `beaconDepositContract`, and `distributor` storage variables. It calls `bgt.normalizedBoost`, `computeReward`, `beaconDepositContract.getOperator`, and `bgt.mint`."
},
"BeraChef.constructor": {
"type": "constructor",
"function_name": "constructor()",
"analysis_result": "This is the constructor for the BeraChef contract. It is marked with `custom:oz-upgrades-unsafe-allow constructor` and calls `_disableInitializers()`. This pattern is specific to OpenZeppelin UUPS upgradeable contracts, preventing the `initialize` function from being called more than once via the constructor itself, ensuring initialization is handled through the `initialize` function called by the proxy."
},
"BeraChef.initialize": {
"type": "external",
"function_name": "initialize(address _distributor, address _factory, address _governance, address _beaconDepositContract, uint8 _maxNumWeightsPerRewardAllocation)",
"analysis_result": "This is the initializer function for the upgradeable contract, meant to be called once after deployment via a proxy. It takes addresses for the distributor, factory, governance (owner), beacon deposit contract, and the maximum number of weights allowed per reward allocation. It calls `__Ownable_init(_governance)` to initialize ownership, setting the provided governance address as the contract owner. It also calls `__UUPSUpgradeable_init()`. It sets the storage variables `distributor`, `factory`, and `beaconDepositContract` to the provided addresses, with `slither-disable-next-line missing-zero-check` indicating these are expected to be non-zero. It checks if `_maxNumWeightsPerRewardAllocation` is zero and reverts if it is. Finally, it sets the `maxNumWeightsPerRewardAllocation` storage variable and emits the `MaxNumWeightsPerRewardAllocationSet` event."
},
"BeraChef._authorizeUpgrade": {
"type": "internal override",
"function_name": "_authorizeUpgrade(address newImplementation)",
"analysis_result": "This is an internal function required by the `UUPSUpgradeable` standard. It is called before an upgrade happens to determine if the caller is authorized. In this implementation, it simply calls the `onlyOwner` modifier, which checks if `msg.sender` is the current owner of the contract (set during initialization). This restricts the ability to upgrade the contract to only the owner."
},
"BeraChef.onlyDistributor": {
"type": "modifier",
"function_name": "onlyDistributor()",
"analysis_result": "This modifier checks if the caller (`msg.sender`) is equal to the address stored in the `distributor` storage variable. If they are not equal, it reverts the transaction with `NotDistributor.selector.revertWith()`. This modifier is used to restrict access to certain functions to only the designated distributor contract."
},
"BeraChef.onlyOperator": {
"type": "modifier",
"function_name": "onlyOperator(bytes calldata valPubkey)",
"analysis_result": "This modifier checks if the caller (`msg.sender`) is the operator address associated with a given validator public key (`valPubkey`). It calls the `beaconDepositContract`'s `getOperator(valPubkey)` function to retrieve the operator address for the validator. If `msg.sender` is not equal to the retrieved operator address, it reverts the transaction with `NotOperator.selector.revertWith()`. This modifier is used to restrict access to certain functions to only the designated operator of a specific validator."
},
"BeraChef.setMaxNumWeightsPerRewardAllocation": {
"type": "external",
"function_name": "setMaxNumWeightsPerRewardAllocation(uint8 _maxNumWeightsPerRewardAllocation)",
"analysis_result": "This function allows the contract owner to set the maximum number of weight entries allowed in a single reward allocation. It uses the `onlyOwner` modifier. It checks if the provided `_maxNumWeightsPerRewardAllocation` is zero and reverts if it is. It then checks if the new maximum is less than the current number of weights in the `defaultRewardAllocation`. If it is, it means the current default allocation would become invalid, so it reverts with `InvalidateDefaultRewardAllocation.selector.revertWith()`. If the checks pass, it updates the `maxNumWeightsPerRewardAllocation` storage variable and emits the `MaxNumWeightsPerRewardAllocationSet` event."
},
"BeraChef.setMaxWeightPerVault": {
"type": "external",
"function_name": "setMaxWeightPerVault(uint96 _maxWeightPerVault)",
"analysis_result": "This function allows the contract owner to set the maximum weight a single vault can have within a reward allocation. It uses the `onlyOwner` modifier. It checks if the provided `_maxWeightPerVault` is zero or greater than `ONE_HUNDRED_PERCENT`. If either condition is true, it reverts with `InvalidMaxWeightPerVault.selector.revertWith()`. It updates the `maxWeightPerVault` storage variable. It then calls the internal function `_checkIfStillValid(defaultRewardAllocation.weights)` to verify if the current `defaultRewardAllocation` remains valid under the new `maxWeightPerVault`. If it does not, it reverts with `InvalidateDefaultRewardAllocation.selector.revertWith()`. Finally, it emits the `MaxWeightPerVaultSet` event."
},
"BeraChef.setRewardAllocationBlockDelay": {
"type": "external",
"function_name": "setRewardAllocationBlockDelay(uint64 _rewardAllocationBlockDelay)",
"analysis_result": "This function allows the contract owner to set the required block delay before a queued reward allocation can become active. It uses the `onlyOwner` modifier. It checks if the provided `_rewardAllocationBlockDelay` is greater than `MAX_REWARD_ALLOCATION_BLOCK_DELAY`. If it is, it reverts with `RewardAllocationBlockDelayTooLarge.selector.revertWith()`. If the check passes, it updates the `rewardAllocationBlockDelay` storage variable and emits the `RewardAllocationBlockDelaySet` event."
},
"BeraChef.setVaultWhitelistedStatus": {
"type": "external",
"function_name": "setVaultWhitelistedStatus(address receiver, bool isWhitelisted, string memory metadata)",
"analysis_result": "This function allows the contract owner to whitelist or unwhitelist a specific vault address. It uses the `onlyOwner` modifier. It first checks if the provided `receiver` address is a valid vault registered with the factory. It does this by calling `RewardVault(receiver).stakeToken()` to get the associated stake token and then calling `IRewardVaultFactory(factory).getVault(stakeToken)` to see if the factory returns the same `receiver` address for that token. If not, it reverts with `NotFactoryVault.selector.revertWith()`. If the receiver is a valid factory vault, it updates the `isWhitelistedVault` mapping for the `receiver` address with the provided `isWhitelisted` status. If `isWhitelisted` is set to `false` (unwhitelisting), it calls `_checkIfStillValid(defaultRewardAllocation.weights)` to ensure the default allocation remains valid. If it becomes invalid, it reverts with `InvalidateDefaultRewardAllocation.selector.revertWith()`. Finally, it emits the `VaultWhitelistedStatusUpdated` event including the metadata."
},
"BeraChef.updateWhitelistedVaultMetadata": {
"type": "external",
"function_name": "updateWhitelistedVaultMetadata(address vault, string memory metadata)",
"analysis_result": "This function allows the contract owner to update the metadata associated with a whitelisted vault. It uses the `onlyOwner` modifier. It first checks if the provided `vault` address is currently whitelisted by looking up `isWhitelistedVault[vault]`. If it is not whitelisted, it reverts with `NotWhitelistedVault.selector.revertWith()`. If it is whitelisted, it emits the `WhitelistedVaultMetadataUpdated` event with the vault address and the new metadata."
},
"BeraChef.setDefaultRewardAllocation": {
"type": "external",
"function_name": "setDefaultRewardAllocation(RewardAllocation calldata ra)",
"analysis_result": "This function allows the contract owner to set the default reward allocation that is used when a validator does not have a valid active custom allocation. It uses the `onlyOwner` modifier. It takes a `RewardAllocation` struct (`ra`) as input and calls the internal function `_validateWeights(ra.weights)` to ensure the provided weights are valid (total 100%, receivers are whitelisted, within max weights and max weight per vault). If validation passes, it updates the `defaultRewardAllocation` storage variable and emits the `SetDefaultRewardAllocation` event."
},
"BeraChef.setCommissionChangeDelay": {
"type": "external",
"function_name": "setCommissionChangeDelay(uint64 _commissionChangeDelay)",
"analysis_result": "This function allows the contract owner to set the required block delay before a queued commission rate change can become active. It uses the `onlyOwner` modifier. It checks if the provided `_commissionChangeDelay` is zero or greater than `MAX_COMMISSION_CHANGE_DELAY`. If either is true, it reverts with `InvalidCommissionChangeDelay.selector.revertWith()`. If the check passes, it updates the `commissionChangeDelay` storage variable and emits the `CommissionChangeDelaySet` event."
},
"BeraChef.queueNewRewardAllocation": {
"type": "external",
"function_name": "queueNewRewardAllocation(bytes calldata valPubkey, uint64 startBlock, Weight[] calldata weights)",
"analysis_result": "This function allows a validator's operator to queue a new custom reward allocation for their validator. It uses the `onlyOperator(valPubkey)` modifier to ensure the caller is the registered operator for the given validator public key. It checks if the provided `startBlock` is in the future and adheres to the minimum `rewardAllocationBlockDelay`. If `startBlock` is not greater than `block.number + rewardAllocationBlockDelay`, it reverts with `InvalidStartBlock.selector.revertWith()`. It then checks if there is already a queued reward allocation for this validator by checking `queuedRewardAllocations[valPubkey].startBlock`. If `startBlock` is greater than 0, it means one is already queued, and it reverts with `RewardAllocationAlreadyQueued.selector.revertWith()`. It calls the internal function `_validateWeights(weights)` to validate the provided weights. If validation passes, it stores the `startBlock` and copies the provided `weights` into the `queuedRewardAllocations` mapping for the given `valPubkey`. Finally, it emits the `QueueRewardAllocation` event."
},
"BeraChef.queueValCommission": {
"type": "external",
"function_name": "queueValCommission(bytes calldata valPubkey, uint96 commissionRate)",
"analysis_result": "This function allows a validator's operator to queue a change to their validator's commission rate on incentive tokens. It uses the `onlyOperator(valPubkey)` modifier. It checks if the provided `commissionRate` is greater than `ONE_HUNDRED_PERCENT`. If it is, it reverts with `InvalidCommissionValue.selector.revertWith()`. It then checks if there is already a queued commission change for this validator by checking `valQueuedCommission[valPubkey].blockNumberLast`. If `blockNumberLast` is greater than 0, it means one is already queued, and it reverts with `CommissionChangeAlreadyQueued.selector.revertWith()`. If checks pass, it stores the current `block.number` and the new `commissionRate` in the `valQueuedCommission` mapping for the given `valPubkey`. Finally, it emits the `QueuedValCommission` event."
},
"BeraChef.activateQueuedValCommission": {
"type": "external",
"function_name": "activateQueuedValCommission(bytes calldata valPubkey)",
"analysis_result": "This function allows anyone to activate a queued commission rate change for a validator, provided the required block delay has passed. It retrieves the queued commission change information (`blockNumberLast`, `commissionRate`) from the `valQueuedCommission` mapping for the given `valPubkey`. It calculates the activation block number by adding `commissionChangeDelay` to `blockNumberLast`. It checks if there was a queued change (`blockNumberLast == 0`) or if the current `block.number` is less than the activation block. If either is true, it reverts with `CommissionNotQueuedOrDelayNotPassed.selector.revertWith()`. If the delay has passed, it retrieves the old commission rate by calling the internal function `_getOperatorCommission(valPubkey)`. It then updates the `valCommission` mapping for the `valPubkey` with a new `CommissionRate` struct containing the calculated `activationBlock` and the queued `commissionRate`. Finally, it emits the `ValCommissionSet` event with the validator pubkey, old commission, and new commission, and deletes the entry from the `valQueuedCommission` mapping."
},
"BeraChef.activateReadyQueuedRewardAllocation": {
"type": "external",
"function_name": "activateReadyQueuedRewardAllocation(bytes calldata valPubkey)",
"analysis_result": "This function is intended to be called by the distributor to activate a queued reward allocation for a validator once its start block has been reached. It uses the `onlyDistributor` modifier. It first calls the public view function `isQueuedRewardAllocationReady(valPubkey, block.number)` to check if a queued allocation exists and is ready for activation. If it's not ready, the function simply returns without doing anything. If it is ready, it retrieves the queued reward allocation (`qra`) from the `queuedRewardAllocations` mapping. It then copies `qra` into the `activeRewardAllocations` mapping for the same `valPubkey`. Finally, it emits the `ActivateRewardAllocation` event and deletes the entry from the `queuedRewardAllocations` mapping."
},
"BeraChef.getActiveRewardAllocation": {
"type": "external view",
"function_name": "getActiveRewardAllocation(bytes calldata valPubkey)",
"analysis_result": "This view function returns the currently active reward allocation for a given validator public key. It first attempts to retrieve the reward allocation (`ara`) from the `activeRewardAllocations` mapping for the `valPubkey`. It then checks if this retrieved allocation is valid by verifying if its `startBlock` is greater than 0 (meaning it was explicitly set) and if it passes the internal `_checkIfStillValid(ara.weights)` check (ensuring weights are within limits and vaults are still whitelisted). If both conditions are true, it returns the `ara`. Otherwise (if no active allocation is set or the active one is no longer valid), it returns the `defaultRewardAllocation`."
},
"BeraChef.getQueuedRewardAllocation": {
"type": "external view",
"function_name": "getQueuedRewardAllocation(bytes calldata valPubkey)",
"analysis_result": "This view function returns the queued reward allocation for a given validator public key. It simply retrieves and returns the `RewardAllocation` struct stored in the `queuedRewardAllocations` mapping for the specified `valPubkey`. If no allocation is queued, it will return a struct with default values (startBlock 0, empty weights array)."
},
"BeraChef.getSetActiveRewardAllocation": {
"type": "external view",
"function_name": "getSetActiveRewardAllocation(bytes calldata valPubkey)",
"analysis_result": "This view function returns the reward allocation explicitly *set* as active for a given validator public key, without checking its validity against current contract state (like whitelisted vaults or max weights). It directly retrieves and returns the `RewardAllocation` struct stored in the `activeRewardAllocations` mapping for the specified `valPubkey`. This differs from `getActiveRewardAllocation` which checks validity and falls back to the default."
},
"BeraChef.getDefaultRewardAllocation": {
"type": "external view",
"function_name": "getDefaultRewardAllocation()",
"analysis_result": "This view function returns the current default reward allocation set by the contract owner. It directly retrieves and returns the `defaultRewardAllocation` storage variable."
},
"BeraChef.isQueuedRewardAllocationReady": {
"type": "public view",
"function_name": "isQueuedRewardAllocationReady(bytes calldata valPubkey, uint256 blockNumber)",
"analysis_result": "This view function checks if a queued reward allocation for a given validator is ready to be activated at a specific block number. It takes the validator public key (`valPubkey`) and a target `blockNumber` as input. It retrieves the `startBlock` of the queued allocation from the `queuedRewardAllocations` mapping. It returns `true` if a queued allocation exists (`startBlock != 0`) and the target `blockNumber` is greater than or equal to the `startBlock`. Otherwise, it returns `false`."
},
"BeraChef.isReady": {
"type": "external view",
"function_name": "isReady()",
"analysis_result": "This view function indicates whether the BeraChef contract is considered 'ready' for operation. It returns `true` if the `defaultRewardAllocation` has been set (checked by verifying if its `weights` array has a length greater than 0). Otherwise, it returns `false`. This serves as a simple status check."
},
"BeraChef.getValCommissionOnIncentiveTokens": {
"type": "external view",
"function_name": "getValCommissionOnIncentiveTokens(bytes calldata valPubkey)",
"analysis_result": "This view function returns the currently active commission rate for a validator on incentive tokens. It takes the validator public key (`valPubkey`) as input and calls the internal view function `_getOperatorCommission(valPubkey)` which handles retrieving the commission rate or returning the default rate if none is explicitly set."
},
"BeraChef.getValQueuedCommissionOnIncentiveTokens": {
"type": "external view",
"function_name": "getValQueuedCommissionOnIncentiveTokens(bytes calldata valPubkey)",
"analysis_result": "This view function returns the queued commission rate change information for a validator, if any. It takes the validator public key (`valPubkey`) as input. It retrieves and returns the `QueuedCommissionRateChange` struct stored in the `valQueuedCommission` mapping for the specified `valPubkey`. If no change is queued, it will return a struct with default values (blockNumberLast 0, commissionRate 0)."
},
"BeraChef.getValidatorIncentiveTokenShare": {
"type": "external view",
"function_name": "getValidatorIncentiveTokenShare(bytes calldata valPubkey, uint256 incentiveTokenAmount)",
"analysis_result": "This view function calculates the portion of a given incentive token amount that corresponds to a validator's commission. It takes the validator public key (`valPubkey`) and the total `incentiveTokenAmount` as input. It first calls the internal view function `_getOperatorCommission(valPubkey)` to get the validator's active commission rate. It then calculates the operator's share by multiplying the `incentiveTokenAmount` by the commission rate and dividing by `ONE_HUNDRED_PERCENT`. It returns the calculated operator's share as a `uint256`."
},
"BeraChef._validateWeights": {
"type": "internal view",
"function_name": "_validateWeights(Weight[] calldata weights)",
"analysis_result": "This internal view function validates an array of `Weight` structs intended for a reward allocation. It takes the `weights` array as input. It first checks if the number of weights (`weights.length`) exceeds `maxNumWeightsPerRewardAllocation`. If it does, it reverts with `TooManyWeights.selector.revertWith()`. It then iterates through the weights. For each weight, it checks if `percentageNumerator` is zero or greater than `maxWeightPerVault`. If either is true, it reverts with `InvalidWeight.selector.revertWith()`. It also checks if the `receiver` address for the weight is whitelisted using the `isWhitelistedVault` mapping. If any receiver is not whitelisted, it reverts with `NotWhitelistedVault.selector.revertWith()`. During the iteration, it sums up the `percentageNumerator` values into a `totalWeight`. After iterating through all weights, it checks if `totalWeight` equals `ONE_HUNDRED_PERCENT`. If not, it reverts with `InvalidRewardAllocationWeights.selector.revertWith()`. This function is used by `setDefaultRewardAllocation` and `queueNewRewardAllocation` before setting or queuing an allocation."
},
"BeraChef._checkIfStillValid": {
"type": "internal view",
"function_name": "_checkIfStillValid(Weight[] memory weights)",
"analysis_result": "This internal view function checks if the weights of a reward allocation are still valid based on the current contract state (`maxNumWeightsPerRewardAllocation`, `maxWeightPerVault`, `isWhitelistedVault`). It is used to validate existing reward allocations (like the active or default ones). It takes a `weights` array (memory) as input. It first checks if the length of the `weights` array is greater than the current `maxNumWeightsPerRewardAllocation`. If so, it returns `false`. It then iterates through the weights. For each weight, it checks if its `percentageNumerator` is greater than the current `maxWeightPerVault` or if its `receiver` address is not whitelisted. If either condition is met for any weight, it immediately returns `false`. If the loop completes without finding any invalid weights, it returns `true`. This function is used by `getActiveRewardAllocation`, `setMaxWeightPerVault`, and `setVaultWhitelistedStatus`."
},
"BeraChef._getOperatorCommission": {
"type": "internal view",
"function_name": "_getOperatorCommission(bytes calldata valPubkey)",
"analysis_result": "This internal view function retrieves the active commission rate for a validator. It takes the validator public key (`valPubkey`) as input. It looks up the `CommissionRate` struct in the `valCommission` mapping for the `valPubkey`. If the `activationBlock` in the retrieved struct is 0, it indicates that no custom commission rate has ever been set or activated for this validator, so it returns the constant `DEFAULT_COMMISSION_RATE`. Otherwise, it returns the `commissionRate` stored in the struct. This function is used by `activateQueuedValCommission`, `getValCommissionOnIncentiveTokens`, and `getValidatorIncentiveTokenShare`."
},
"BGTIncentiveDistributor.constructor": {
"type": "constructor",
"function_name": "constructor()",
"analysis_result": "Purpose: To disable initializers for upgradeability. Variables Used: None directly. Calls: _disableInitializers(). Logic: Standard practice for OpenZeppelin UUPS upgradeable contracts to prevent 'initialize' from being called during deployment."
},
"BGTIncentiveDistributor.initialize": {
"type": "external",
"function_name": "initialize(address _governance)",
"analysis_result": "Purpose: Initializes the contract after deployment. Sets up AccessControl, Pausable, ReentrancyGuard, and UUPS. Grants the DEFAULT_ADMIN_ROLE to _governance and sets the initial rewardClaimDelay. Variables Used: rewardClaimDelay. Storage Modified: AccessControl roles, Pausable state, ReentrancyGuard state, UUPS state, rewardClaimDelay. Calls: __AccessControl_init(), __Pausable_init(), __ReentrancyGuard_init(), __UUPSUpgradeable_init(), _grantRole(DEFAULT_ADMIN_ROLE, _governance), _setRewardClaimDelay(MAX_REWARD_CLAIM_DELAY). Logic: Basic setup and access control configuration for the upgradeable contract. Requires _governance not to be the zero address. Modifiers: initializer."
},
"BGTIncentiveDistributor._authorizeUpgrade": {
"type": "internal",
"function_name": "_authorizeUpgrade(address newImplementation)",
"analysis_result": "Purpose: Internal hook for OpenZeppelin UUPS upgradeability. Controls who can authorize contract upgrades. Variables Used: None directly. Calls: None directly, part of UUPS framework. Logic: Allows upgrade only if the caller has the DEFAULT_ADMIN_ROLE. Modifiers: override, onlyRole(DEFAULT_ADMIN_ROLE)."
},
"BGTIncentiveDistributor.setRewardClaimDelay": {
"type": "external",
"function_name": "setRewardClaimDelay(uint64 _delay)",
"analysis_result": "Purpose: Allows the admin to set the delay period after reward metadata update before rewards are claimable. Variables Used: rewardClaimDelay. Storage Modified: rewardClaimDelay (via _setRewardClaimDelay). Calls: _setRewardClaimDelay(_delay). Logic: Forwards the call to the internal helper function _setRewardClaimDelay. Modifiers: onlyRole(DEFAULT_ADMIN_ROLE)."
},
"BGTIncentiveDistributor.updateRewardsMetadata": {
"type": "external",
"function_name": "updateRewardsMetadata(Distribution[] calldata _distributions)",
"analysis_result": "Purpose: Allows a manager to update the Merkle roots and metadata for reward distributions. Variables Used: rewards, rewardClaimDelay. Storage Modified: rewards. Calls: InvalidDistribution.selector.revertWith(), InvalidToken.selector.revertWith(). Emits: RewardMetadataUpdated. Logic: Iterates through distributions, updates merkleRoot, proof, activeAt (based on current time + rewardClaimDelay), and pubkey in the 'rewards' mapping. Sets the 'token' on the first update for an identifier and checks for consistency on subsequent updates. Reverts if input array is empty or token changes for an identifier. Modifiers: onlyRole(MANAGER_ROLE)."
},
"BGTIncentiveDistributor.setPauseState": {
"type": "external",
"function_name": "setPauseState(bool state)",
"analysis_result": "Purpose: Allows a pauser to pause or unpause the contract, affecting functions with the 'whenNotPaused' modifier. Variables Used: Pausing state (managed by PausableUpgradeable). Storage Modified: Pausing state. Calls: _pause() or _unpause(). Logic: Calls the appropriate OpenZeppelin internal function based on the desired 'state'. Modifiers: onlyRole(PAUSER_ROLE)."
},
"BGTIncentiveDistributor.receiveIncentive": {
"type": "external",
"function_name": "receiveIncentive(bytes calldata pubkey, address token, uint256 _amount)",
"analysis_result": "Purpose: Allows an external caller (e.g., a reward vault) to send incentive tokens to this contract and register them against a specific validator pubkey and token address. Variables Used: incentiveTokensPerValidator. Storage Modified: incentiveTokensPerValidator. Calls: IERC20(token).safeTransferFrom(msg.sender, address(this), _amount). Emits: IncentiveReceived. Logic: Transfers tokens from the caller to the contract and updates the internal tracking of tokens available per validator pubkey and token type. Note: Based on code, anyone can call this."
},
"BGTIncentiveDistributor.claim": {
"type": "external",
"function_name": "claim(Claim[] calldata _claims)",
"analysis_result": "Purpose: Allows a user to claim rewards for one or more distributions using Merkle proofs. Variables Used: None directly, but calls _claim. Calls: _claim(...) for each item, InvalidArray.selector.revertWith(). Logic: Iterates through the provided claims array and calls the internal _claim function for each individual claim. Reverts if input array is empty. Modifiers: nonReentrant, whenNotPaused."
},
"BGTIncentiveDistributor._claim": {
"type": "private",
"function_name": "_claim(bytes32 _identifier, address _account, uint256 _amount, bytes32[] calldata _merkleProof)",
"analysis_result": "Purpose: Internal function to process a single reward claim. Verifies Merkle proof, updates claimed amount, checks token balance, and transfers tokens. Variables Used: rewards, claimed, incentiveTokensPerValidator. Storage Modified: claimed, incentiveTokensPerValidator. Calls: MerkleProof.verifyCalldata(...), IERC20(token).safeTransfer(...), InvalidMerkleRoot.selector.revertWith(), RewardInactive.selector.revertWith(), InvalidProof.selector.revertWith(), InsufficientIncentiveTokens.selector.revertWith(). Emits: RewardClaimed. Logic: Retrieves reward metadata, checks if active. Calculates the *total* claimed amount (_claimed + _amount) and verifies the Merkle proof against this total. Updates the 'claimed' mapping to this total. Checks if sufficient tokens are available for the associated validator and token type. Decrements validator's token balance and transfers tokens to the user. Reverts if metadata doesn't exist, reward is inactive, proof is invalid, or insufficient tokens are held for the validator. Modifiers: None (private helper)."
},
"BGTIncentiveDistributor._setRewardClaimDelay": {
"type": "internal",
"function_name": "_setRewardClaimDelay(uint64 _delay)",
"analysis_result": "Purpose: Internal function to set the reward claim delay. Variables Used: rewardClaimDelay, MAX_REWARD_CLAIM_DELAY. Storage Modified: rewardClaimDelay. Calls: InvalidRewardClaimDelay.selector.revertWith(). Emits: RewardClaimDelaySet. Logic: Sets the 'rewardClaimDelay' state variable after checking it does not exceed 'MAX_REWARD_CLAIM_DELAY'. Modifiers: None (internal helper)."
},
"Distributor.constructor": {
"type": "constructor",
"function_name": "constructor()",
"analysis_result": "This is the constructor for the upgradeable contract. It calls _disableInitializers() to prevent the `initialize` function from being called outside of the proxy deployment process. It uses no storage variables directly and does not call other functions within this contract, only the inherited _disableInitializers()."
},
"Distributor.initialize": {
"type": "external",
"function_name": "initialize(address _berachef, address _bgt, address _blockRewardController, address _governance, uint64 _zeroValidatorPubkeyGIndex, uint64 _proposerIndexGIndex)",
"analysis_result": "This function serves as the initializer for the upgradeable contract, intended to be called once immediately after deployment via a proxy. It initializes core components: `AccessControl`, `ReentrancyGuard`, and `UUPSUpgradeable` using their respective `__init` functions. It sets critical storage variables: `beraChef`, `bgt`, and `blockRewardController` based on provided addresses. It grants the `DEFAULT_ADMIN_ROLE` to the specified `_governance` address using `_grantRole`. Finally, it sets the `zeroValidatorPubkeyGIndex` and `proposerIndexGIndex` required for beacon chain verification by calling the inherited `setZeroValidatorPubkeyGIndex` and `setProposerIndexGIndex` functions from `BeaconRootsHelper`. It depends on `AccessControlUpgradeable`, `ReentrancyGuardUpgradeable`, `UUPSUpgradeable`, and `BeaconRootsHelper` for initialization and setting parameters."
},
"Distributor._authorizeUpgrade": {
"type": "internal",
"function_name": "_authorizeUpgrade(address newImplementation)",
"analysis_result": "This internal function is required by the `UUPSUpgradeable` pattern. It defines the authorization logic for contract upgrades. It uses the `onlyRole(DEFAULT_ADMIN_ROLE)` modifier to restrict upgrade calls to addresses holding the `DEFAULT_ADMIN_ROLE`. It checks the caller's role using the AccessControl's internal state (_roles mapping) and does not directly modify any storage variables within this contract, only performing a permission check."
},
"Distributor.setZeroValidatorPubkeyGIndex": {
"type": "public",
"function_name": "setZeroValidatorPubkeyGIndex(uint64 _zeroValidatorPubkeyGIndex)",
"analysis_result": "This function allows updating the GIndex used by `BeaconRootsHelper` to locate a validator's public key in the beacon state tree. This might be necessary after beacon chain hard forks that change the state structure. It uses the `onlyRole(MANAGER_ROLE)` modifier to restrict access to addresses holding the `MANAGER_ROLE`. It calls the inherited `setZeroValidatorPubkeyGIndex` function from `BeaconRootsHelper`, which modifies the `zeroValidatorPubkeyGIndex` storage variable within the inherited contract state."
},
"Distributor.setProposerIndexGIndex": {
"type": "public",
"function_name": "setProposerIndexGIndex(uint64 _proposerIndexGIndex)",
"analysis_result": "This function allows updating the GIndex used by `BeaconRootsHelper` to locate the proposer index in the beacon state tree. This might be necessary after beacon chain hard forks. It uses the `onlyRole(MANAGER_ROLE)` modifier to restrict access to addresses holding the `MANAGER_ROLE`. It calls the inherited `setProposerIndexGIndex` function from `BeaconRootsHelper`, which modifies the `proposerIndexGIndex` storage variable within the inherited contract state."
},
"Distributor.distributeFor": {
"type": "external",
"function_name": "distributeFor(uint64 nextTimestamp, uint64 proposerIndex, bytes calldata pubkey, bytes32[] calldata proposerIndexProof, bytes32[] calldata pubkeyProof)",
"analysis_result": "This is the main entry point for initiating reward distribution for a block's proposer. It uses the `nonReentrant` modifier to prevent reentrancy attacks. It first calls `_processTimestampInBuffer(nextTimestamp)` (inherited from BeaconRootsHelper) to ensure the timestamp is processed sequentially and isn't a duplicate, potentially modifying BeaconRootsHelper's internal timestamp buffer storage. It then performs two critical verification steps using methods from BeaconRootsHelper: `_verifyProposerIndexInBeaconBlock` to check if the provided `proposerIndex` is correct for the block root derived from `nextTimestamp`, and `_verifyValidatorPubkeyInBeaconBlock` to verify the `pubkey` at the specified `proposerIndex`. If all verifications pass, it calls the internal `_distributeFor(pubkey, nextTimestamp)` function to handle the actual reward calculation and distribution logic. It relies heavily on the verification logic provided by `BeaconRootsHelper`."
},
"Distributor._distributeFor": {
"type": "internal",
"function_name": "_distributeFor(bytes calldata pubkey, uint64 nextTimestamp)",
"analysis_result": "This internal function handles the core logic of calculating and distributing rewards for a specific validator (identified by `pubkey`) for a block associated with `nextTimestamp`. It first calls `blockRewardController.processRewards(pubkey, nextTimestamp, beraChef.isReady())` using the stored `blockRewardController` and `beraChef` interfaces to get the reward amount for this block. If `rewardRate` is 0, distribution is skipped. It then calls `beraChef.activateReadyQueuedRewardAllocation(pubkey)` on the stored `beraChef` to potentially activate a pending reward allocation. It retrieves the active reward allocation structure for the validator via `beraChef.getActiveRewardAllocation(pubkey)`, which may return a default allocation. It iterates through the `weights` array within the retrieved `RewardAllocation`. For each weight (receiver and percentage): it calculates the `rewardAmount` using `FixedPointMathLib.fullMulDiv` based on the `rewardRate` and the receiver's percentage weight (adjusted for the last receiver to use the remainder). It then calls `bgt.safeIncreaseAllowance(receiver, rewardAmount)` on the stored `bgt` token contract to approve the receiver (expected to be a RewardVault) to pull the tokens. Finally, it notifies the receiver's contract (cast to `IRewardVault`) by calling `notifyRewardAmount(pubkey, rewardAmount)`. It tracks `totalRewardDistributed` to correctly calculate the last receiver's share. It emits the `Distributed` event for each distribution. This function reads `beraChef`, `blockRewardController`, and `bgt` storage variables but does not modify storage within the Distributor contract itself (except indirectly via external calls like allowance modification). It depends on the `IBeraChef`, `IBlockRewardController`, `IRewardVault` interfaces, `FixedPointMathLib`, and the token contract's allowance mechanism."
},
"RewardVaultFactory.VAULT_MANAGER_ROLE": {
"type": "public",
"function_name": "VAULT_MANAGER_ROLE()",
"analysis_result": "This is a public view function automatically generated for the public state variable `VAULT_MANAGER_ROLE`. It returns the bytes32 value representing the vault manager role. It does not modify any storage variables and serves as a constant getter."
},
"RewardVaultFactory.VAULT_PAUSER_ROLE": {
"type": "public",
"function_name": "VAULT_PAUSER_ROLE()",
"analysis_result": "This is a public view function automatically generated for the public state variable `VAULT_PAUSER_ROLE`. It returns the bytes32 value representing the vault pauser role. It does not modify any storage variables and serves as a constant getter."
},
"RewardVaultFactory.beacon": {
"type": "public",
"function_name": "beacon()",
"analysis_result": "This is a public view function automatically generated for the public state variable `beacon`. It returns the address of the UpgradeableBeacon contract used for cloning RewardVault implementations. It does not modify any storage variables and serves as a state variable getter."
},
"RewardVaultFactory.bgt": {
"type": "public",
"function_name": "bgt()",
"analysis_result": "This is a public view function automatically generated for the public state variable `bgt`. It returns the address of the BGT token. It does not modify any storage variables and serves as a state variable getter."
},
"RewardVaultFactory.distributor": {
"type": "public",
"function_name": "distributor()",
"analysis_result": "This is a public view function automatically generated for the public state variable `distributor`. It returns the address of the main distributor contract. It does not modify any storage variables and serves as a state variable getter."
},
"RewardVaultFactory.beaconDepositContract": {
"type": "public",
"function_name": "beaconDepositContract()",
"analysis_result": "This is a public view function automatically generated for the public state variable `beaconDepositContract`. It returns the address of the BeaconDeposit contract. It does not modify any storage variables and serves as a state variable getter."
},
"RewardVaultFactory.getVault": {
"type": "public",
"function_name": "getVault(address stakingToken)",
"analysis_result": "This is a public view function automatically generated for the public mapping state variable `getVault`. It takes a `stakingToken` address as input and returns the address of the associated RewardVault contract if one has been created, otherwise returns address(0). It reads from the `getVault` mapping. It does not modify any storage variables."
},
"RewardVaultFactory.allVaults": {
"type": "public",
"function_name": "allVaults(uint256)",
"analysis_result": "This is a public view function automatically generated for the public array state variable `allVaults`. It takes an index as input and returns the address of the RewardVault contract stored at that index in the array. It reads from the `allVaults` array. It does not modify any storage variables."
},
"RewardVaultFactory.bgtIncentiveDistributor": {
"type": "public",
"function_name": "bgtIncentiveDistributor()",
"analysis_result": "This is a public view function automatically generated for the public state variable `bgtIncentiveDistributor`. It returns the address of the BGTIncentiveDistributor contract. It does not modify any storage variables and serves as a state variable getter."
},
"RewardVaultFactory.constructor": {
"type": "constructor",
"function_name": "constructor()",
"analysis_result": "This is the contract constructor. It is called only once upon deployment. Its purpose is to disable the initializer function for upgradeable contracts using the `_disableInitializers()` function from OpenZeppelin's UUPSUpgradeable. This prevents the `initialize` function from being called again after the initial setup, ensuring proper upgradeability patterns are followed. It does not take any arguments and does not interact with other contract functions or state variables other than calling `_disableInitializers()`."
},
"RewardVaultFactory.initialize": {
"type": "external",
"function_name": "initialize(address _bgt, address _distributor, address _beaconDepositContract, address _governance, address _vaultImpl)",
"analysis_result": "This is the initializer function for the upgradeable proxy contract. It can only be called once. It initializes the AccessControl and UUPSUpgradeable components using `__AccessControl_init()` and `__UUPSUpgradeable_init()`. It grants the `DEFAULT_ADMIN_ROLE` to the provided `_governance` address. It sets the admin role for the `VAULT_PAUSER_ROLE` to `VAULT_MANAGER_ROLE`, allowing Vault Managers to manage Pausers. It assigns the provided addresses for `_bgt`, `_distributor`, and `_beaconDepositContract` to the respective state variables (`bgt`, `distributor`, `beaconDepositContract`). It uses Solady's `UpgradeableBeacon` to deploy a new Beacon contract, setting the provided `_governance` as its owner and `_vaultImpl` as the implementation address, and stores the beacon's address in the `beacon` state variable. It requires non-zero addresses for the input parameters implicitly by checking against `address(0)` later in `setBGTIncentiveDistributor`, but the `initialize` function itself does not explicitly check for zero addresses (though the `slither-disable-next-line missing-zero-check` comment is present, this check should ideally be included in the function body). It modifies the `_roles`, `_roleAdmins`, `beacon`, `bgt`, `distributor`, and `beaconDepositContract` storage variables."
},
"RewardVaultFactory._authorizeUpgrade": {
"type": "internal",
"function_name": "_authorizeUpgrade(address newImplementation)",
"analysis_result": "This is an internal override function required by the UUPSUpgradeable pattern. Its purpose is to define the access control mechanism for authorizing contract upgrades. This implementation restricts upgrades to only addresses holding the `DEFAULT_ADMIN_ROLE` using the `onlyRole(DEFAULT_ADMIN_ROLE)` modifier. It does not modify any storage variables itself but enforces a check based on the caller's role in the AccessControl storage (`_roles`). The `newImplementation` parameter is not used within the function body but is required by the UUPS standard."
},
"RewardVaultFactory.setBGTIncentiveDistributor": {
"type": "external",
"function_name": "setBGTIncentiveDistributor(address _bgtIncentiveDistributor)",
"analysis_result": "This external function allows the `DEFAULT_ADMIN_ROLE` to set the address of the BGTIncentiveDistributor contract. It first checks if the provided `_bgtIncentiveDistributor` address is not `address(0)` using `ZeroAddress.selector.revertWith()`, reverting if it is. It then emits a `BGTIncentiveDistributorSet` event, logging the new and old addresses of the distributor. Finally, it updates the `bgtIncentiveDistributor` state variable with the new address. Access is restricted to the `DEFAULT_ADMIN_ROLE` by the `onlyRole` modifier. It reads the current value of `bgtIncentiveDistributor` and modifies it."
},
"RewardVaultFactory.createRewardVault": {
"type": "external",
"function_name": "createRewardVault(address stakingToken)",
"analysis_result": "This external function is used to create a new RewardVault contract for a specific `stakingToken`. It first checks if a vault already exists for the given `stakingToken` by reading the `getVault` mapping. If `getVault[stakingToken]` is not `address(0)`, it returns the existing vault address without creating a new one. If no vault exists, it checks if the `stakingToken` address corresponds to a deployed contract by checking `stakingToken.code.length`. If the code length is 0 (indicating it's not a contract), it reverts with `NotAContract.selector.revertWith()`. It then calculates a unique `salt` for deterministic deployment using a keccak256 hash of the `stakingToken` address. It uses Solady's `LibClone.deployDeterministicERC1967BeaconProxy` to deploy a new RewardVault contract clone via the stored `beacon` address using the calculated `salt`. The address of the newly deployed vault is stored in the `getVault` mapping with the `stakingToken` as the key, and the vault address is also pushed to the `allVaults` array. A `VaultCreated` event is emitted with the `stakingToken` and the new `vault` address. Finally, it calls the `initialize` function on the newly deployed vault contract, passing the stored `beaconDepositContract`, `bgt`, `distributor`, and `stakingToken` addresses. It reads `getVault`, `beacon`, and `allVaults` and writes to `getVault` and `allVaults`. It calls an external function `initialize` on the newly created `RewardVault` contract."
},
"RewardVaultFactory.predictRewardVaultAddress": {
"type": "external",
"function_name": "predictRewardVaultAddress(address stakingToken)",
"analysis_result": "This external view function allows predicting the address of a RewardVault that *would be* created for a given `stakingToken` using deterministic deployment. It calculates the same `salt` as the `createRewardVault` function using the keccak256 hash of the `stakingToken` address. It then calls Solady's `LibClone.predictDeterministicAddressERC1967BeaconProxy`, providing the `beacon` address, the calculated `salt`, and the address of the factory contract (`address(this)`) which acts as the deployer. This function does not deploy a contract or modify any state variables. It reads the `beacon` state variable and uses the `address(this)` implicit variable."
},
"RewardVaultFactory.allVaultsLength": {
"type": "external",
"function_name": "allVaultsLength()",
"analysis_result": "This external view function returns the total number of RewardVaults created by this factory. It simply returns the `.length` property of the `allVaults` array. It reads the `allVaults` array's length. It does not modify any state variables."
},
"IBGT.staker": {
"type": "external",
"function_name": "staker() external view returns (address)",
"analysis_result": "This function is a view function that returns the address of the BGT staker contract. It reads a storage variable intended to store the staker's address. It takes no parameters and returns an address."
},
"IBGT.activateBoostDelay": {
"type": "external",
"function_name": "activateBoostDelay() external view returns (uint32)",
"analysis_result": "This function is a view function that returns the required delay (likely in blocks or time) before a queued boost can be activated. It reads a storage variable holding the activate boost delay duration. It takes no parameters and returns a uint32 value."
},
"IBGT.dropBoostDelay": {
"type": "external",
"function_name": "dropBoostDelay() external view returns (uint32)",
"analysis_result": "This function is a view function that returns the required delay (likely in blocks or time) before a queued drop boost can be executed. It reads a storage variable holding the drop boost delay duration. It takes no parameters and returns a uint32 value."
},
"IBGT.whitelistSender": {
"type": "external",
"function_name": "whitelistSender(address sender, bool approved) external",
"analysis_result": "This function is intended to control which addresses are allowed to transfer BGT tokens. According to the NatSpec, BGT is intended to be soul-bound to EOAs and only transferable by approved senders. This function allows a 'governance module' to approve or revoke the ability of a specific 'sender' address to transfer BGT. It takes the 'sender' address and a boolean 'approved' indicating whether to grant or revoke permission. This function likely modifies an internal mapping or list of approved senders. It emits the 'SenderWhitelisted' event."
},
"IBGT.mint": {
"type": "external",
"function_name": "mint(address distributor, uint256 amount) external",
"analysis_result": "This function is used to create new BGT tokens and assign them to a 'distributor' address. The NatSpec indicates this function can only be called by a designated 'minter' address, which itself is set by governance. It takes the 'distributor' address and the 'amount' of BGT to mint. This function increases the total supply of BGT and the balance of the 'distributor'. It likely interacts with internal token balance storage and the total supply variable, similar to standard ERC20 minting, potentially calling an internal '_mint' function."
},
"IBGT.queueBoost": {
"type": "external",
"function_name": "queueBoost(bytes calldata pubkey, uint128 amount) external",
"analysis_result": "This function allows `msg.sender` to enqueue an amount of their unboosted BGT balance for boosting a specific validator identified by 'pubkey'. The NatSpec specifies that it reverts if the caller doesn't have sufficient unboosted balance. It takes the validator's 'pubkey' (bytes) and the 'amount' of BGT to queue. This function likely decreases the user's unboosted balance and increases a 'queuedBoost' balance associated with the user and validator, updating an internal state related to boosting queues. It should emit the 'QueueBoost' event."
},
"IBGT.cancelBoost": {
"type": "external",
"function_name": "cancelBoost(bytes calldata pubkey, uint128 amount) external",
"analysis_result": "This function allows `msg.sender` to cancel a previously queued boost for a validator identified by 'pubkey'. The NatSpec states it reverts if the caller doesn't have enough balance in the queued state for that validator. It takes the validator's 'pubkey' (bytes) and the 'amount' of BGT to remove from the queue. This function likely decreases the 'queuedBoost' balance for the user and validator and increases the user's unboosted balance. It should emit the 'CancelBoost' event."
},
"IBGT.activateBoost": {
"type": "external",
"function_name": "activateBoost(address user, bytes calldata pubkey) external returns (bool)",
"analysis_result": "This function is used to transition queued boost balance for a specific 'user' and validator ('pubkey') into an active boost. The NatSpec indicates it's called by a 'sender' (likely the staker contract) on behalf of a 'user'. It takes the 'user' address and the validator's 'pubkey'. It returns false if the amount to activate is zero or if the 'activateBoostDelay' has not passed since the boost was queued. Otherwise, it activates the queued amount. This function likely moves BGT balance from a 'queuedBoost' state to a 'boosted' state for the user/validator pair, potentially updating total boosted amounts and the validator's 'boostees' balance. It should emit the 'ActivateBoost' event."
},
"IBGT.queueDropBoost": {
"type": "external",
"function_name": "queueDropBoost(bytes calldata pubkey, uint128 amount) external",
"analysis_result": "This function allows `msg.sender` (the user) to enqueue an amount of their active boost balance for a specific validator ('pubkey') to be dropped. The NatSpec states it reverts if the user doesn't have enough currently boosted balance with that validator. It takes the validator's 'pubkey' and the 'amount' of BGT boost to queue for dropping. This function likely moves balance from the 'boosted' state to a 'dropBoostQueue' state for the user/validator. It should emit the 'QueueDropBoost' event."
},
"IBGT.cancelDropBoost": {
"type": "external",
"function_name": "cancelDropBoost(bytes calldata pubkey, uint128 amount) external",
"analysis_result": "This function allows `msg.sender` (the user) to cancel a previously queued drop boost for a validator ('pubkey'). It takes the validator's 'pubkey' and the 'amount' of BGT boost to remove from the queued drop state. This function likely moves balance from the 'dropBoostQueue' state back to the 'boosted' state for the user/validator. It should emit the 'CancelDropBoost' event."
},
"IBGT.dropBoost": {
"type": "external",
"function_name": "dropBoost(address user, bytes calldata pubkey) external returns (bool)",
"analysis_result": "This function is used to execute a queued drop boost, reducing the active boost balance for a specific 'user' and validator ('pubkey'). The NatSpec indicates it's called by a 'sender' (likely the staker contract) on behalf of a 'user'. It takes the 'user' address and the validator's 'pubkey'. It returns false if the amount to drop is zero or if the 'dropBoostDelay' has not passed since the drop was queued. Otherwise, it executes the drop. This function likely moves balance from the 'dropBoostQueue' state back to the user's unboosted balance, reducing the 'boosted' amount for the user/validator and potentially the validator's 'boostees' balance. It should emit the 'DropBoost' event."
},
"IBGT.boostedQueue": {
"type": "external",
"function_name": "boostedQueue(address account, bytes calldata pubkey) external view returns (uint32 blockNumberLast, uint128 balance)",
"analysis_result": "This is a view function that returns the details of the queued boost for a specific 'account' targeting a particular validator 'pubkey'. It returns two values: `blockNumberLast` which likely indicates when the queue action last occurred (useful for delay checks), and `balance` which is the amount of BGT currently queued for boosting this validator by this account. It reads internal state related to queued boosts."
},
"IBGT.dropBoostQueue": {
"type": "external",
"function_name": "dropBoostQueue(address account, bytes calldata pubkey) external view returns (uint32 blockNumberLast, uint128 balance)",
"analysis_result": "This is a view function that returns the details of the queued drop boost for a specific 'account' targeting a particular validator 'pubkey'. It returns two values: `blockNumberLast` which likely indicates when the queue drop action last occurred (useful for delay checks), and `balance` which is the amount of BGT currently queued for dropping from this validator's boost by this account. It reads internal state related to queued drop boosts."