xTRIBE contest - IllIllI's results

A TRIBE tokenomic upgrade with multi-delegation, autocompounding rewards, and reward delegation

General Information

Platform: Code4rena

Start Date: 21/04/2022

Pot Size: $75,000 USDC

Total HM: 7

Participants: 45

Period: 7 days

Judge: 0xean

Total Solo HM: 5

Id: 111

League: ETH

Tribe

Findings Distribution

Researcher Performance

Rank: 1/45

Findings: 3

Award: $11,075.00

🌟 Selected for report: 2

🚀 Solo Findings: 1

Findings Information

🌟 Selected for report: IllIllI

Labels

bug
help wanted
2 (Med Risk)

Awards

9375 USDC - $9,375.00

External Links

Lines of code

https://github.com/fei-protocol/flywheel-v2/blob/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L258-L266

Vulnerability details

Impact

A malicious authorized user can steal all unclaimed rewards and break the reward accounting

Even if the authorized user is benevolent the fact that there is a rug vector available may negatively impact the protocol's reputation. Furthermore since this contract is meant to be used by other projects, the trustworthiness of every project cannot be vouched for.

Proof of Concept

By setting a booster that returns zero for all calls to boostedBalanceOf() where the user address is not under the attacker's control, and returning arbitrary values for those under his/her control, an attacker can choose specific amounts of rewardToken to assign to himself/herself. The attacker can then call claimRewards() to withdraw the funds. Any amounts that the attacker assigns to himself/herself over the amount that normally would have been assigned, upon claiming, is taken from other users' unclaimed balances, since tokens are custodied by the flywheelRewards address rather than per-user accounts.

File: flywheel-v2/src/FlywheelCore.sol

182       /// @notice swap out the flywheel booster contract
183       function setBooster(IFlywheelBooster newBooster) external requiresAuth {
184           flywheelBooster = newBooster;
185   
186           emit FlywheelBoosterUpdate(address(newBooster));
187       }

https://github.com/fei-protocol/flywheel-v2/blob/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L182-L187

File: flywheel-v2/src/FlywheelCore.sol

258           uint256 supplierTokens = address(flywheelBooster) != address(0)
259               ? flywheelBooster.boostedBalanceOf(strategy, user)
260               : strategy.balanceOf(user);
261   
262           // accumulate rewards by multiplying user tokens by rewardsPerToken index and adding on unclaimed
263           uint256 supplierDelta = (supplierTokens * deltaIndex) / ONE;
264           uint256 supplierAccrued = rewardsAccrued[user] + supplierDelta;
265   
266           rewardsAccrued[user] = supplierAccrued;

https://github.com/fei-protocol/flywheel-v2/blob/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L258-L266

File: flywheel-v2/src/FlywheelCore.sol

119       function claimRewards(address user) external {
120           uint256 accrued = rewardsAccrued[user];
121   
122           if (accrued != 0) {
123               rewardsAccrued[user] = 0;
124   
125               rewardToken.safeTransferFrom(address(flywheelRewards), user, accrued);

https://github.com/fei-protocol/flywheel-v2/blob/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L119-L125

Projects also using BaseFlywheelRewards or its child contrats, are implicitly approving infinite transfers by the core

File: flywheel-v2/src/rewards/BaseFlywheelRewards.sol

25        constructor(FlywheelCore _flywheel) {
26            flywheel = _flywheel;
27            ERC20 _rewardToken = _flywheel.rewardToken();
28            rewardToken = _rewardToken;
29    
30            _rewardToken.safeApprove(address(_flywheel), type(uint256).max);
31        }

https://github.com/fei-protocol/flywheel-v2/blob/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/BaseFlywheelRewards.sol#L25-L31

The attacker need not keep the booster set this way - he/she can set it, call accrue() for his/her specific user, and unset it, all in the same block

Tools Used

Code inspection

Make flywheelRewards immutable, or only allow it to change if there are no current users

#0 - Joeysantoro

2022-04-27T03:20:02Z

This is a similar issue to one which already affects the SushiSwap masterchef. If rewards are decreased without first calling the accrue-equivalent on the masterchef, then previous rewards are lost.

If trust minimization is a desired property (in my opinion it is), then these functions should be behind timelocks.

If a user can call accrue before the booster is updated, they can lock in past rewards as they are added onto the rewardsAccrued global state var 266 rewardsAccrued[user] = supplierAccrued;

#1 - Joeysantoro

2022-04-27T03:20:30Z

I don't really see this as a vulnerability, but will leave it to the c4 judge

#2 - 0xean

2022-05-19T00:02:36Z

I do see this as a vulnerability. Essentially, there is a backdoor by which a privileged address can extract value from users. A timelock would be a potential solution to mitigate some of the risk, as well as the mitigation options presented by the warden.

2 — Med: Assets not at direct risk, but the function of the protocol or its availability could be impacted, or leak value with a hypothetical attack path with stated assumptions, but external requirements.

This is a hypothetical attack path with external requirements and deserves the medium severity rating.

Awards

1437.6398 USDC - $1,437.64

Labels

bug
QA (Quality Assurance)
sponsor todo

External Links

Low Risk Issues

1. Nonce used for multiple purposes

The nonce mapping used for permit() calls is the same as the one used for delegateBySig(). This should at the very least be documented so signers know that the order of operations between the two functions matters, and so that multicall()s can be organized appropriately

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #1

392        require(nonce == nonces[signer]++, "ERC20MultiVotes: invalid nonce");

https://github.com/fei-protocol/flywheel-v2/blob/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L392

2. multicall()s involving permit() and delegateBySig() can be DOSed

Attackers monitoring the blockchain for multicalls can front-run by calling permit() and delegateBySig() before the multicall(), causing it to revert. Have separate flavors of the functions where the multicall() data is included in the hash

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #1

392        require(nonce == nonces[signer]++, "ERC20MultiVotes: invalid nonce");

https://github.com/fei-protocol/flywheel-v2/blob/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L392

3. Misleading comments

File: lib/flywheel-v2/src/FlywheelCore.sol   #1

82      @return the cumulative amount of rewards accrued to user (including prior)

the cumulative amount of rewards accrued to the user since the last claim https://github.com/fei-protocol/flywheel-v2/blob/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L82

4. require() should be used instead of assert()

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #1

196             assert(queuedRewards.storedCycle == 0 || queuedRewards.storedCycle >= lastCycle);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L196

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #2

235         assert(queuedRewards.storedCycle >= cycle);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L235

Non-critical Issues

1. require()/revert() statements should have descriptive reason strings

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #1

114         require(rewardToken.balanceOf(address(this)) - balanceBefore >= totalQueuedForCycle);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L114

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #2

153             require(rewardToken.balanceOf(address(this)) - balanceBefore >= newRewards);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L153

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #3

154             require(newRewards <= type(uint112).max); // safe cast

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L154

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #4

195             require(queuedRewards.storedCycle < currentCycle);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L195

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #5

200             require(nextRewards <= type(uint112).max); // safe cast

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L200

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #6

345             require(_userGauges[user].remove(gauge));

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L345

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #7

266             require(_delegates[delegator].remove(delegatee));

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L266

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #8

352                 require(_delegates[user].remove(delegatee)); // Remove from set. Should never fail.

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L352

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #9

393         require(signer != address(0));

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L393

2. public functions not called by the contract should be declared external instead

Contracts are allowed to override their parents' functions and change the visibility from external to public.

File: lib/flywheel-v2/src/FlywheelCore.sol   #1

84     function accrue(ERC20 strategy, address user) public returns (uint256) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L84

File: lib/flywheel-v2/src/FlywheelCore.sol   #2

101     function accrue(
102         ERC20 strategy,
103         address user,
104         address secondUser
105     ) public returns (uint256, uint256) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L101-L105

3. Use a more recent version of solidity

Use a solidity version of at least 0.8.4 to get bytes.concat() instead of abi.encodePacked(<bytes>,<bytes>) Use a solidity version of at least 0.8.12 to get string.concat() instead of abi.encodePacked(<str>,<str>)

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #1

4 pragma solidity ^0.8.0;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L4

4. Constant redefined elsewhere

Consider defining in only one contract so that values cannot become out of sync when only one location is updated. If the variable is a local cache of another contract's value, consider making the cache variable internal or private, which will require external users to query the contract with the source of truth, so that callers don't get out of sync

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #1

47     uint32 public immutable gaugeCycleLength;

seen in lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L47

5. Non-library/interface files should use fixed compiler versions, not floating ones

File: lib/xTRIBE/src/xTRIBE.sol   #1

4 pragma solidity ^0.8.0;

https://github.com/fei-protocol/xTRIBE/tree/989e47d176facbb0c38bc1e1ca58672f179159e1/src/xTRIBE.sol#L4

6. Typos

File: lib/flywheel-v2/src/FlywheelCore.sol   #1

17          The Core contract maintaings three important pieces of state:

maintaings https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L17

File: lib/flywheel-v2/src/FlywheelCore.sol   #2

262         // accumulate rewards by multiplying user tokens by rewardsPerToken index and adding on unclaimed

rewardsPerToken https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L262

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #3

230     /// @notice thrown when incremending during the freeze window.

incremending https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L230

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #4

143     /// @notice An event thats emitted when an account changes its delegate

thats https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L143

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #5

189      * @param delegatee the receivier of votes.

receivier https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L189

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #6

364    /*///////////////////////////////////////////////////////////////
365                             EIP-712 LOGIC
366    //////////////////////////////////////////////////////////////*/

did you mean EIP-2612? https://github.com/fei-protocol/flywheel-v2/blob/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L364-L366

7. NatSpec is incomplete

File: lib/flywheel-v2/src/FlywheelCore.sol   #1

93     /** 
94       @notice accrue rewards for a two users on a strategy
95       @param strategy the strategy to accrue a user's rewards on
96       @param user the first user to be accrued
97       @param user the second user to be accrued
98       @return the cumulative amount of rewards accrued to the first user (including prior)
99       @return the cumulative amount of rewards accrued to the second user (including prior)
100     */
101     function accrue(
102         ERC20 strategy,
103         address user,
104         address secondUser
105     ) public returns (uint256, uint256) {

Missing: @param secondUser https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L93-L105

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #2

130       @param num the number of gauges to return
131     */
132     function gauges(uint256 offset, uint256 num) external view returns (address[] memory values) {

Missing: @return https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L130-L132

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #3

176       @param num the number of gauges to return.
177     */
178     function userGauges(
179         address user,
180         uint256 offset,
181         uint256 num
182     ) external view returns (address[] memory values) {

Missing: @return https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L176-L182

8. Event is missing indexed fields

Each event should use three indexed fields if there are three or more fields

File: lib/flywheel-v2/src/FlywheelCore.sol   #1

66     event AccrueRewards(ERC20 indexed strategy, address indexed user, uint256 rewardsDelta, uint256 rewardsIndex);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L66

File: lib/flywheel-v2/src/FlywheelCore.sol   #2

73     event ClaimRewards(address indexed user, uint256 amount);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L73

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #3

44     event CycleStart(uint32 indexed cycleStart, uint256 rewardAmount);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L44

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #4

47     event QueueRewards(address indexed gauge, uint32 indexed cycleStart, uint256 rewardAmount);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L47

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #5

234     event IncrementGaugeWeight(address indexed user, address indexed gauge, uint256 weight, uint32 cycleEnd);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L234

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #6

237     event DecrementGaugeWeight(address indexed user, address indexed gauge, uint256 weight, uint32 cycleEnd);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L237

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #7

440     event MaxGaugesUpdate(uint256 oldMaxGauges, uint256 newMaxGauges);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L440

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #8

443     event CanContractExceedMaxGaugesUpdate(address indexed account, bool canContractExceedMaxGauges);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L443

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #9

102     event MaxDelegatesUpdate(uint256 oldMaxDelegates, uint256 newMaxDelegates);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L102

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #10

105     event CanContractExceedMaxDelegatesUpdate(address indexed account, bool canContractExceedMaxDelegates);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L105

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #11

135     event Delegation(address indexed delegator, address indexed delegate, uint256 amount);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L135

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #12

138     event Undelegation(address indexed delegator, address indexed delegate, uint256 amount);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L138

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #13

141     event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L141

9. Consider addings checks for signature malleability

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #1

380        address signer = ecrecover(
381            keccak256(
382                abi.encodePacked(
383                    "\x19\x01",
384                    DOMAIN_SEPARATOR(),
385                    keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry))
386                )
387            ),
388            v,
389            r,
390            s
391        );
392        require(nonce == nonces[signer]++, "ERC20MultiVotes: invalid nonce");
393        require(signer != address(0));
394        _delegate(signer, delegatee);

https://github.com/fei-protocol/flywheel-v2/blob/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L380-L394

#0 - 0xean

2022-05-20T18:41:37Z

The severities listed in this QA report are correct as-is

Awards

262.36 USDC - $262.36

Labels

bug
G (Gas Optimization)

External Links

1. Cheaper checks should be moved up

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #1

241        // Require freeVotes exceed the delegation size
242        uint256 free = freeVotes(delegator);
243        if (delegatee == address(0) || free < amount) revert DelegationError();

The address check should be split out and moved to before the call to freeVotes() https://github.com/fei-protocol/flywheel-v2/blob/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L241-L243

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #2

393        require(signer != address(0));

https://github.com/fei-protocol/flywheel-v2/blob/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L393

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #3

259            if (cycle - block.timestamp <= incrementFreezeWindow) revert IncrementFreezeError();

https://github.com/fei-protocol/flywheel-v2/blob/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L259

2. Multiple address mappings can be combined into a single mapping of an address to a struct, where appropriate

Saves a storage slot for the mapping. Depending on the circumstances and sizes of types, can avoid a Gsset (20000 gas). Reads and subsequent writes can also be cheaper

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #1

59     mapping(address => mapping(address => uint112)) public getUserGaugeWeight;
60 
61     /// @notice a mapping from a user to their total allocated weight across all gauges
62     /// @dev NOTE this may contain weights for deprecated gauges
63     mapping(address => uint112) public getUserWeight;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L59-L63

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #2

151     mapping(address => mapping(address => uint256)) private _delegatesVotesCount;
152 
153     /// @notice mapping from a delegator to the total number of delegated votes.
154     mapping(address => uint256) public userDelegatedVotes;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L151-L154

3. State variables should be cached in stack variables rather than re-reading them from storage

The instances below point to the second access of a state variable within a function. Caching will replace each Gwarmaccess (100 gas) with a much cheaper stack read. Less obvious fixes/optimizations include having local storage variables of mappings within state variable mappings or mappings within state variable structs, having local storage variables of structs within mappings, or having local caches of state variable contracts/addresses.

File: lib/ERC4626/src/xERC4626.sol   #1

40         rewardsCycleEnd = (block.timestamp.safeCastTo32() / rewardsCycleLength) * rewardsCycleLength;

https://github.com/fei-protocol/ERC4626/blob/643cd044fac34bcbf64e1c3790a5126fec0dbec1/src/xERC4626.sol#L40

File: lib/ERC4626/src/xERC4626.sol   #2

89         uint32 end = ((timestamp + rewardsCycleLength) / rewardsCycleLength) * rewardsCycleLength;

https://github.com/fei-protocol/ERC4626/blob/643cd044fac34bcbf64e1c3790a5126fec0dbec1/src/xERC4626.sol#L89

File: lib/flywheel-v2/src/FlywheelCore.sol   #3

168             rewardToken.safeTransferFrom(address(flywheelRewards), address(newFlywheelRewards), oldRewardBalance);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L168

File: lib/flywheel-v2/src/FlywheelCore.sol   #4

168             rewardToken.safeTransferFrom(address(flywheelRewards), address(newFlywheelRewards), oldRewardBalance);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L168

File: lib/flywheel-v2/src/FlywheelCore.sol   #5

221                 ? flywheelBooster.boostedTotalSupply(strategy)

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L221

File: lib/flywheel-v2/src/FlywheelCore.sol   #6

259             ? flywheelBooster.boostedBalanceOf(strategy, user)

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L259

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #7

90         gaugeCycle = (block.timestamp.safeCastTo32() / gaugeCycleLength) * gaugeCycleLength;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L90

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #8

103         uint32 currentCycle = (block.timestamp.safeCastTo32() / gaugeCycleLength) * gaugeCycleLength;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L103

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #9

135         uint32 currentCycle = (block.timestamp.safeCastTo32() / gaugeCycleLength) * gaugeCycleLength;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L135

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #10

158         uint112 queued = nextCycleQueuedRewards;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L158

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #11

146         uint32 offset = paginationOffset;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L146

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #12

174         address[] memory gauges = gaugeToken.gauges(offset, numRewards);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L174

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #13

92             return (nowPlusOneCycle / gaugeCycleLength) * gaugeCycleLength; // cannot divide by zero and always <= nowPlusOneCycle so no overflow

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L92

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #14

263         if (added && _userGauges[user].length() > maxGauges && !canContractExceedMaxGauges[user])

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L263

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #15

61         return pos == 0 ? 0 : _checkpoints[account][pos - 1].votes;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L61

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #16

269         _delegatesVotesCount[delegator][delegatee] = newDelegates;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L269

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #17

354                 _delegatesVotesCount[user][delegatee] = 0;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L354

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #18

352                 require(_delegates[user].remove(delegatee)); // Remove from set. Should never fail.

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L352

4. <x> += <y> costs more gas than <x> = <x> + <y> for state variables

File: lib/ERC4626/src/xERC4626.sol   #1

67         storedTotalAssets -= amount;

https://github.com/fei-protocol/ERC4626/blob/643cd044fac34bcbf64e1c3790a5126fec0dbec1/src/xERC4626.sol#L67

File: lib/ERC4626/src/xERC4626.sol   #2

72         storedTotalAssets += amount;

https://github.com/fei-protocol/ERC4626/blob/643cd044fac34bcbf64e1c3790a5126fec0dbec1/src/xERC4626.sol#L72

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #3

155             nextCycleQueuedRewards += uint112(newRewards); // in case a previous incomplete cycle had rewards, add on

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L155

5. ++i/i++ should be unchecked{++i}/unchecked{++i} when it is not possible for them to overflow, as is the case when used in for- and while-loops

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #1

189         for (uint256 i = 0; i < size; i++) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L189

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #2

346         for (uint256 i = 0; i < size && (userFreeVotes + totalFreed) < votes; i++) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L346

6. require()/revert() strings longer than 32 bytes cost extra gas

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #1

379         require(block.timestamp <= expiry, "ERC20MultiVotes: signature expired");

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L379

7. Not using the named return variables when a function returns, wastes deployment gas

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #1

231             return 0;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L231

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #2

248         return _incrementUserAndGlobalWeights(msg.sender, weight, currentCycle);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L248

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #3

317         return _incrementUserAndGlobalWeights(msg.sender, weightsSum, currentCycle);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L317

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #4

331         return _decrementUserAndGlobalWeights(msg.sender, weight, currentCycle);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L331

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #5

394         return _decrementUserAndGlobalWeights(msg.sender, weightsSum, currentCycle);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L394

8. Using bools for storage incurs overhead

    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

https://github.com/OpenZeppelin/openzeppelin-contracts/blob/58f635312aa21f947cae5f8578638a85aa2519f5/contracts/security/ReentrancyGuard.sol#L23-L27 Use uint256(1) and uint256(2) for true/false

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #1

450     mapping(address => bool) public canContractExceedMaxGauges;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L450

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #2

111     mapping(address => bool) public canContractExceedMaxDelegates;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L111

9. Use a more recent version of solidity

Use a solidity version of at least 0.8.2 to get compiler automatic inlining Use a solidity version of at least 0.8.3 to get better struct packing and cheaper multiple storage reads Use a solidity version of at least 0.8.4 to get custom errors, which are cheaper at deployment than revert()/require() strings Use a solidity version of at least 0.8.10 to have external calls skip contract existence checks if the external call has a return value

File: lib/ERC4626/src/xERC4626.sol   #1

4 pragma solidity ^0.8.0;

https://github.com/fei-protocol/ERC4626/blob/643cd044fac34bcbf64e1c3790a5126fec0dbec1/src/xERC4626.sol#L4

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #2

3 pragma solidity ^0.8.0;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L3

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #3

4 pragma solidity ^0.8.0;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L4

File: lib/xTRIBE/src/xTRIBE.sol   #4

4 pragma solidity ^0.8.0;

https://github.com/fei-protocol/xTRIBE/tree/989e47d176facbb0c38bc1e1ca58672f179159e1/src/xTRIBE.sol#L4

10. It costs more gas to initialize variables to zero than to let the default of zero be applied

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #1

189         for (uint256 i = 0; i < size; i++) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L189

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #2

134         for (uint256 i = 0; i < num; ) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L134

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #3

184         for (uint256 i = 0; i < num; ) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L184

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #4

307         for (uint256 i = 0; i < size; ) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L307

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #5

384         for (uint256 i = 0; i < size; ) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L384

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #6

564         for (uint256 i = 0; i < size && (userFreeWeight + totalFreed) < weight; ) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L564

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #7

79         uint256 low = 0;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L79

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #8

346         for (uint256 i = 0; i < size && (userFreeVotes + totalFreed) < votes; i++) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L346

File: lib/xTRIBE/src/xTRIBE.sol   #9

95         for (uint256 i = 0; i < size; ) {

https://github.com/fei-protocol/xTRIBE/tree/989e47d176facbb0c38bc1e1ca58672f179159e1/src/xTRIBE.sol#L95

11. internal functions only called once can be inlined to save gas

File: lib/flywheel-v2/src/FlywheelCore.sol   #1

146     function _addStrategyForRewards(ERC20 strategy) internal {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L146

12. ++i costs less gas than ++i, especially when it's used in for-loops (--i/i-- too)

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #1

189         for (uint256 i = 0; i < size; i++) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L189

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #2

346         for (uint256 i = 0; i < size && (userFreeVotes + totalFreed) < votes; i++) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L346

13. Usage of uints/ints smaller than 32 bytes (256 bits) incurs overhead

When using elements that are smaller than 32 bytes, your contract’s gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size.

https://docs.soliditylang.org/en/v0.8.11/internals/layout_in_storage.html Use a larger size then downcast where needed

File: lib/ERC4626/src/xERC4626.sol   #1

24     uint32 public immutable rewardsCycleLength;

https://github.com/fei-protocol/ERC4626/blob/643cd044fac34bcbf64e1c3790a5126fec0dbec1/src/xERC4626.sol#L24

File: lib/ERC4626/src/xERC4626.sol   #2

27     uint32 public lastSync;

https://github.com/fei-protocol/ERC4626/blob/643cd044fac34bcbf64e1c3790a5126fec0dbec1/src/xERC4626.sol#L27

File: lib/ERC4626/src/xERC4626.sol   #3

30     uint32 public rewardsCycleEnd;

https://github.com/fei-protocol/ERC4626/blob/643cd044fac34bcbf64e1c3790a5126fec0dbec1/src/xERC4626.sol#L30

File: lib/ERC4626/src/xERC4626.sol   #4

33     uint192 public lastRewardAmount;

https://github.com/fei-protocol/ERC4626/blob/643cd044fac34bcbf64e1c3790a5126fec0dbec1/src/xERC4626.sol#L33

File: lib/ERC4626/src/xERC4626.sol   #5

37     constructor(uint32 _rewardsCycleLength) {

https://github.com/fei-protocol/ERC4626/blob/643cd044fac34bcbf64e1c3790a5126fec0dbec1/src/xERC4626.sol#L37

File: lib/ERC4626/src/xERC4626.sol   #6

48         uint192 lastRewardAmount_ = lastRewardAmount;

https://github.com/fei-protocol/ERC4626/blob/643cd044fac34bcbf64e1c3790a5126fec0dbec1/src/xERC4626.sol#L48

File: lib/ERC4626/src/xERC4626.sol   #7

49         uint32 rewardsCycleEnd_ = rewardsCycleEnd;

https://github.com/fei-protocol/ERC4626/blob/643cd044fac34bcbf64e1c3790a5126fec0dbec1/src/xERC4626.sol#L49

File: lib/ERC4626/src/xERC4626.sol   #8

50         uint32 lastSync_ = lastSync;

https://github.com/fei-protocol/ERC4626/blob/643cd044fac34bcbf64e1c3790a5126fec0dbec1/src/xERC4626.sol#L50

File: lib/ERC4626/src/xERC4626.sol   #9

79         uint192 lastRewardAmount_ = lastRewardAmount;

https://github.com/fei-protocol/ERC4626/blob/643cd044fac34bcbf64e1c3790a5126fec0dbec1/src/xERC4626.sol#L79

File: lib/ERC4626/src/xERC4626.sol   #10

80         uint32 timestamp = block.timestamp.safeCastTo32();

https://github.com/fei-protocol/ERC4626/blob/643cd044fac34bcbf64e1c3790a5126fec0dbec1/src/xERC4626.sol#L80

File: lib/ERC4626/src/xERC4626.sol   #11

89         uint32 end = ((timestamp + rewardsCycleLength) / rewardsCycleLength) * rewardsCycleLength;

https://github.com/fei-protocol/ERC4626/blob/643cd044fac34bcbf64e1c3790a5126fec0dbec1/src/xERC4626.sol#L89

File: lib/flywheel-v2/src/FlywheelCore.sol   #12

195         uint224 index;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L195

File: lib/flywheel-v2/src/FlywheelCore.sol   #13

197         uint32 lastUpdatedTimestamp;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L197

File: lib/flywheel-v2/src/FlywheelCore.sol   #14

201     uint224 public constant ONE = 1e18;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L201

File: lib/flywheel-v2/src/FlywheelCore.sol   #15

224             uint224 deltaIndex;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L224

File: lib/flywheel-v2/src/FlywheelCore.sol   #16

244         uint224 strategyIndex = state.index;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L244

File: lib/flywheel-v2/src/FlywheelCore.sol   #17

245         uint224 supplierIndex = userIndex[strategy][user];

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L245

File: lib/flywheel-v2/src/FlywheelCore.sol   #18

256         uint224 deltaIndex = strategyIndex - supplierIndex;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L256

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #19

44     event CycleStart(uint32 indexed cycleStart, uint256 rewardAmount);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L44

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #20

47     event QueueRewards(address indexed gauge, uint32 indexed cycleStart, uint256 rewardAmount);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L47

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #21

50     uint32 public gaugeCycle;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L50

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #22

53     uint32 public immutable gaugeCycleLength;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L53

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #23

56     uint32 internal nextCycle;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L56

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #24

59     uint112 internal nextCycleQueuedRewards;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L59

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #25

62     uint32 internal paginationOffset;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L62

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #26

66         uint112 priorCycleRewards;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L66

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #27

67         uint112 cycleRewards;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L67

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #28

68         uint32 storedCycle;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L68

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #29

103         uint32 currentCycle = (block.timestamp.safeCastTo32() / gaugeCycleLength) * gaugeCycleLength;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L103

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #30

104         uint32 lastCycle = gaugeCycle;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L104

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #31

135         uint32 currentCycle = (block.timestamp.safeCastTo32() / gaugeCycleLength) * gaugeCycleLength;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L135

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #32

136         uint32 lastCycle = gaugeCycle;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L136

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #33

146         uint32 offset = paginationOffset;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L146

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #34

158         uint112 queued = nextCycleQueuedRewards;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L158

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #35

181         uint32 currentCycle,

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L181

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #36

182         uint32 lastCycle,

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L182

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #37

198             uint112 completedRewards = queuedRewards.storedCycle == lastCycle ? queuedRewards.cycleRewards : 0;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L198

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #38

218     function getAccruedRewards(ERC20 gauge, uint32 lastUpdatedTimestamp)

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L218

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #39

226         uint32 cycle = gaugeCycle;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L226

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #40

237         uint32 cycleEnd = cycle + gaugeCycleLength;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L237

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #41

241         uint112 cycleRewardsNext = queuedRewards.cycleRewards;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L241

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #42

250             uint32 beginning = lastUpdatedTimestamp > cycle ? lastUpdatedTimestamp : cycle;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L250

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #43

253             uint32 elapsed = block.timestamp.safeCastTo32() - beginning;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L253

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #44

254             uint32 remaining = cycleEnd - beginning;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L254

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #45

36     constructor(uint32 _gaugeCycleLength, uint32 _incrementFreezeWindow) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L36

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #46

36     constructor(uint32 _gaugeCycleLength, uint32 _incrementFreezeWindow) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L36

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #47

47     uint32 public immutable gaugeCycleLength;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L47

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #48

50     uint32 public immutable incrementFreezeWindow;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L50

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #49

53         uint112 storedWeight;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L53

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #50

54         uint112 currentWeight;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L54

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #51

55         uint32 currentCycle;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L55

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #52

84     function getGaugeCycleEnd() public view returns (uint32) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L84

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #53

89     function _getGaugeCycleEnd() internal view returns (uint32) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L89

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #54

90         uint32 nowPlusOneCycle = block.timestamp.safeCastTo32() + gaugeCycleLength;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L90

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #55

97     function getGaugeWeight(address gauge) public view returns (uint112) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L97

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #56

102     function getStoredGaugeWeight(address gauge) public view returns (uint112) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L102

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #57

108     function _getStoredWeight(Weight storage gaugeWeight, uint32 currentCycle) internal view returns (uint112) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L108

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #58

108     function _getStoredWeight(Weight storage gaugeWeight, uint32 currentCycle) internal view returns (uint112) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L108

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #59

113     function totalWeight() external view returns (uint112) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L113

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #60

118     function storedTotalWeight() external view returns (uint112) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L118

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #61

210         uint32 currentCycle = _getGaugeCycleEnd();

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L210

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #62

212         uint112 total = _getStoredWeight(_totalWeight, currentCycle);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L212

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #63

213         uint112 weight = _getStoredWeight(_getGaugeWeight[gauge], currentCycle);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L213

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #64

234     event IncrementGaugeWeight(address indexed user, address indexed gauge, uint256 weight, uint32 cycleEnd);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L234

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #65

237     event DecrementGaugeWeight(address indexed user, address indexed gauge, uint256 weight, uint32 cycleEnd);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L237

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #66

245     function incrementGauge(address gauge, uint112 weight) external returns (uint112 newUserWeight) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L245

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #67

245     function incrementGauge(address gauge, uint112 weight) external returns (uint112 newUserWeight) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L245

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #68

246         uint32 currentCycle = _getGaugeCycleEnd();

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L246

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #69

254         uint112 weight,

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L254

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #70

255         uint32 cycle

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L255

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #71

275         uint112 weight,

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L275

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #72

276         uint32 cycle

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L276

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #73

277     ) internal returns (uint112 newUserWeight) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L277

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #74

302         uint112 weightsSum;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L302

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #75

304         uint32 currentCycle = _getGaugeCycleEnd();

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L304

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #76

309             uint112 weight = weights[i];

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L309

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #77

326     function decrementGauge(address gauge, uint112 weight) external returns (uint112 newUserWeight) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L326

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #78

326     function decrementGauge(address gauge, uint112 weight) external returns (uint112 newUserWeight) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L326

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #79

327         uint32 currentCycle = _getGaugeCycleEnd();

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L327

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #80

337         uint112 weight,

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L337

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #81

338         uint32 cycle

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L338

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #82

340         uint112 oldWeight = getUserGaugeWeight[user][gauge];

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L340

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #83

355         uint112 weight,

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L355

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #84

356         uint32 cycle

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L356

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #85

357     ) internal returns (uint112 newUserWeight) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L357

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #86

372         returns (uint112 newUserWeight)

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L372

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #87

378         uint112 weightsSum;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L378

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #88

380         uint32 currentCycle = _getGaugeCycleEnd();

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L380

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #89

386             uint112 weight = weights[i];

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L386

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #90

404         function(uint112, uint112) view returns (uint112) op,

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L404

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #91

404         function(uint112, uint112) view returns (uint112) op,

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L404

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #92

404         function(uint112, uint112) view returns (uint112) op,

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L404

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #93

405         uint112 delta,

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L405

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #94

406         uint32 cycle

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L406

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #95

408         uint112 currentWeight = weight.currentWeight;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L408

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #96

410         uint112 stored = weight.currentCycle < cycle ? currentWeight : weight.storedWeight;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L410

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #97

411         uint112 newWeight = op(currentWeight, delta);

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L411

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #98

418     function _add(uint112 a, uint112 b) private pure returns (uint112) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L418

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #99

418     function _add(uint112 a, uint112 b) private pure returns (uint112) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L418

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #100

418     function _add(uint112 a, uint112 b) private pure returns (uint112) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L418

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #101

422     function _subtract(uint112 a, uint112 b) private pure returns (uint112) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L422

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #102

422     function _subtract(uint112 a, uint112 b) private pure returns (uint112) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L422

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #103

422     function _subtract(uint112 a, uint112 b) private pure returns (uint112) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L422

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #104

453     function addGauge(address gauge) external requiresAuth returns (uint112) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L453

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #105

457     function _addGauge(address gauge) internal returns (uint112 weight) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L457

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #106

463         uint32 currentCycle = _getGaugeCycleEnd();

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L463

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #107

483         uint32 currentCycle = _getGaugeCycleEnd();

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L483

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #108

486         uint112 weight = _getGaugeWeight[gauge].currentWeight;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L486

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #109

553         uint32 currentCycle = _getGaugeCycleEnd();

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L553

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #110

556         uint112 userFreed;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L556

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #111

557         uint112 totalFreed;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L557

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #112

566             uint112 userGaugeWeight = getUserGaugeWeight[user][gauge];

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L566

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #113

28         uint32 fromBlock;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L28

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #114

29         uint224 votes;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L29

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #115

36     function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoint memory) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L36

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #116

41     function numCheckpoints(address account) public view virtual returns (uint32) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L41

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #117

375         uint8 v,

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L375

File: lib/xTRIBE/src/xTRIBE.sol   #118

18         returns (uint96);

https://github.com/fei-protocol/xTRIBE/tree/989e47d176facbb0c38bc1e1ca58672f179159e1/src/xTRIBE.sol#L18

File: lib/xTRIBE/src/xTRIBE.sol   #119

20     function getCurrentVotes(address account) external view returns (uint96);

https://github.com/fei-protocol/xTRIBE/tree/989e47d176facbb0c38bc1e1ca58672f179159e1/src/xTRIBE.sol#L20

File: lib/xTRIBE/src/xTRIBE.sol   #120

37         uint32 _rewardsCycleLength,

https://github.com/fei-protocol/xTRIBE/tree/989e47d176facbb0c38bc1e1ca58672f179159e1/src/xTRIBE.sol#L37

File: lib/xTRIBE/src/xTRIBE.sol   #121

38         uint32 _incrementFreezeWindow

https://github.com/fei-protocol/xTRIBE/tree/989e47d176facbb0c38bc1e1ca58672f179159e1/src/xTRIBE.sol#L38

14. Expressions for constant values such as a call to keccak256(), should use immutable rather than constant

See this issue for a detail description of the issue

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #1

368     bytes32 public constant DELEGATION_TYPEHASH =
369         keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L368-L369

15. Using private rather than public for constants, saves gas

If needed, the value can be read from the verified contract source code

File: lib/ERC4626/src/xERC4626.sol   #1

24     uint32 public immutable rewardsCycleLength;

https://github.com/fei-protocol/ERC4626/blob/643cd044fac34bcbf64e1c3790a5126fec0dbec1/src/xERC4626.sol#L24

File: lib/flywheel-v2/src/FlywheelCore.sol   #2

201     uint224 public constant ONE = 1e18;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L201

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #3

53     uint32 public immutable gaugeCycleLength;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L53

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #4

47     uint32 public immutable gaugeCycleLength;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L47

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #5

50     uint32 public immutable incrementFreezeWindow;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L50

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #6

368     bytes32 public constant DELEGATION_TYPEHASH =
369         keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L368-L369

16. Multiplication/division by two should use bit shifting

<x> * 2 is equivalent to <x> << 1 and <x> / 2 is the same as <x> >> 1

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #1

94         return (a & b) + (a ^ b) / 2;

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L94

17. require() or revert() statements that check input arguments should be at the top of the function

Checks that involve constants should come before checks that involve state variables

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #1

392         require(nonce == nonces[signer]++, "ERC20MultiVotes: invalid nonce");

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L392

18. Empty blocks should be removed

The code should be refactored such that they no longer exist, or the block should do something useful, such as emitting an event or reverting. If the block is an empty if-statement block to avoid doing subsequent checks in the else-if/else conditions, the else-if/else conditions should be nested under the negation of the if-statement, because they involve different classes of checks, which may lead to the introduction of errors when the code is later modified (if(x){}else if(y){...}else{...} => if(!x){if(y){...}else{...}})

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #1

243         if (incompleteCycle) {
244             // If current cycle queue incomplete, do nothing to current cycle rewards or accrued
245         } else if (block.timestamp >= cycleEnd) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L243-L245

19. Use custom errors rather than revert()/require() strings to save deployment gas

File: lib/flywheel-v2/src/FlywheelCore.sol (various lines)   #1

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol (various lines)   #2

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol

20. Functions guaranteed to revert when called by normal users can be marked payable

If a function modifier such as onlyOwner is used, the function will revert if a normal user tries to pay the function. Marking the function as payable will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided.

File: lib/flywheel-v2/src/FlywheelCore.sol   #1

142     function addStrategyForRewards(ERC20 strategy) external requiresAuth {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L142

File: lib/flywheel-v2/src/FlywheelCore.sol   #2

165     function setFlywheelRewards(IFlywheelRewards newFlywheelRewards) external requiresAuth {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L165

File: lib/flywheel-v2/src/FlywheelCore.sol   #3

183     function setBooster(IFlywheelBooster newBooster) external requiresAuth {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/FlywheelCore.sol#L183

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #4

101     function queueRewardsForCycle() external requiresAuth returns (uint256 totalQueuedForCycle) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L101

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #5

133     function queueRewardsForCyclePaginated(uint256 numRewards) external requiresAuth {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L133

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #6

218     function getAccruedRewards(ERC20 gauge, uint32 lastUpdatedTimestamp)
219         external
220         override
221         onlyFlywheel
222         returns (uint256 accruedRewards)

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L218-L222

File: lib/flywheel-v2/src/rewards/FlywheelGaugeRewards.sol   #7

273     function setRewardsStream(IRewardsStream newRewardsStream) external requiresAuth {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/rewards/FlywheelGaugeRewards.sol#L273

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #8

453     function addGauge(address gauge) external requiresAuth returns (uint112) {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L453

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #9

475     function removeGauge(address gauge) external requiresAuth {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L475

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #10

495     function replaceGauge(address oldGauge, address newGauge) external requiresAuth {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L495

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #11

502     function setMaxGauges(uint256 newMax) external requiresAuth {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L502

File: lib/flywheel-v2/src/token/ERC20Gauges.sol   #12

510     function setContractExceedMaxGauges(address account, bool canExceedMax) external requiresAuth {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20Gauges.sol#L510

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #13

114     function setMaxDelegates(uint256 newMax) external requiresAuth {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L114

File: lib/flywheel-v2/src/token/ERC20MultiVotes.sol   #14

122     function setContractExceedMaxDelegates(address account, bool canExceedMax) external requiresAuth {

https://github.com/fei-protocol/flywheel-v2/tree/77bfadf388db25cf5917d39cd9c0ad920f404aad/src/token/ERC20MultiVotes.sol#L122

File: lib/xTRIBE/src/xTRIBE.sol   #15

89     function emitVotingBalances(address[] calldata accounts)
90         external
91         requiresAuth

https://github.com/fei-protocol/xTRIBE/tree/989e47d176facbb0c38bc1e1ca58672f179159e1/src/xTRIBE.sol#L89-L91

File: lib/xTRIBE/src/xTRIBE.sol   #16

108     function syncRewards() public override requiresAuth {

https://github.com/fei-protocol/xTRIBE/tree/989e47d176facbb0c38bc1e1ca58672f179159e1/src/xTRIBE.sol#L108

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter