Number | Details | Instances |
---|---|---|
[Medium-1] | Privileged functions can create points of failure | 5 |
[Medium-2] | Insufficient oracle validation | 1 |
[Medium-3] | Using block.timestamp as the deadline/expiry invites MEV | 1 |
[Medium-4] | Price should round up | 24 |
Number | Details | Instances |
---|---|---|
[Low-1] | Potential division by zero should have zero checks in place | 7 |
[Low-2] | Division operations should always be performed after multiplication operations | 3 |
[Low-3] | Function with two array parameter missing a length check | 4 |
[Low-4] | Missing checks for address(0x0) when updating address state variables | 1 |
[Low-5] | Missing empty bytes check when assigning bytes/string state variable | 1 |
[Low-6] | Unchecked blocks with subtractions may underflow | 2 |
[Low-7] | Incorrect comparison against a max value | 2 |
[Low-8] | Getting a bool return value does not confirm the existence of a function in an external call | 2 |
[Low-9] | Low level calls in solidity versions preceding 0.8.14 can result in an optimiser bug | 13 |
[Low-10] | Mint function with no access control | 3 |
[Low-11] | Important function with no access control | 2 |
[Low-12] | Chainlink price feeds are not validated | 1 |
[Low-13] | Return values not checked for approve() | 2 |
[Low-14] | Empty receive functions can cause gas issues | 4 |
[Low-15] | The call abi.encodeWithSignature is not safe from typographical errors | 1 |
[Low-16] | The call abi.encodeWithSelector is not type safe | 2 |
[Low-17] | Token supply should not be centralised at deployment | 2 |
[Low-18] | Use SafeCast to safely downcast variables | 32 |
[Low-19] | The nonReentrant modifier should be first in a function declaration | 4 |
[Low-20] | Function calls within for loops | 19 |
[Low-21] | For loops in public or external functions should be avoided due to high gas costs and possible DOS | 45 |
[Low-22] | The function decimals() is not part of the ERC20 standard | 23 |
[Low-23] | Minting to the zero address should be avoided | 6 |
[Low-24] | No limits when setting fees | 1 |
[Low-25] | Loss of precision | 40 |
[Low-26] | Missing zero address check in constructor | 22 |
[Low-27] | Using zero as a parameter | 16 |
[Low-28] | Constant decimal values | 32 |
[Low-29] | Calculation will revert when totalSupply() returns zero | 2 |
[Low-30] | Bridge function must check for native token | 1 |
[Low-31] | A year is not always 365/364 days | 1 |
[Low-32] | Chainlink answer is not compared against min/max values | 1 |
[Low-33] | Unsafe uint to int conversion | 2 |
[Low-34] | Calling internal _grantRole bypasses role access checks | 1 |
[Low-35] | Direct supportsInterface() calls may cause caller to revert | 4 |
[Low-36] | SafeTransferLib does not ensure that the token contract exists | 6 |
[Low-37] | External calls in modifiers should be avoided | 1 |
[Low-38] | Using a immutable/constant state variable value as a gas limit can be dangerous | 1 |
[Low-39] | Prefer skip over revert model in iteration | 1 |
[Low-40] | Constructors missing validation | 35 |
[Low-41] | Division in comparison | 9 |
[Low-42] | Contract contains payable functions but no withdraw/sweep function | 14 |
Number | Details | Instances |
---|---|---|
[NonCritical-1] | Some if-statement can be converted to a ternary | 71 |
[NonCritical-2] | Addresses shouldn't be hard-coded | 8 |
[NonCritical-3] | Code does not follow the best practice of check-effects-interaction | 49 |
[NonCritical-4] | Events may be emitted out of order due to code not follow the best practice of check-effects-interaction | 18 |
[NonCritical-5] | It is standard for all external and public functions to be override from an interface | 397 |
[NonCritical-6] | Using abi.encodePacked can result in hash collision when used in hashing functions | 1 |
[NonCritical-7] | Overly complicated arithmetic | 14 |
[NonCritical-8] | It's not standard to end and begin a code object on the same line | 2 |
[NonCritical-9] | Using constants directly, rather than caching the value, saves gas | 1 |
[NonCritical-10] | State variables which are not modified within functions should be set as constants or immutable for values set at deployment | 18 |
[NonCritical-11] | External call recipient may consume all transaction gas | 1 |
[NonCritical-12] | ERC4626 maxWithdraw/maxRedeem function not to spec | 2 |
[NonCritical-13] | Function call in event emit | 133 |
[NonCritical-14] | int/uint passed into abi.encodePacked without casting to a string. | 2 |
[NonCritical-15] | NatSpec: @notice tags missing from contract/abstract/library/interface/function/modifier/constructor/receive/fallback | 273 |
[NonCritical-16] | Natspec @author is missing from contract/interface/library | 99 |
[NonCritical-17] | Natspec @title is missing from contract/interface/library | 90 |
[NonCritical-18] | NatSpec: @dev tags missing from contract/abstract/library/interface/function/modifier/constructor/receive/fallback | 527 |
[NonCritical-19] | NatSpec: @param tags missing from function/modifier/constructor | 139 |
[NonCritical-20] | NatSpec: @return tags missing from function/modifier/constructor | 121 |
[NonCritical-21] | Inconsistent comment spacing | 9 |
[NonCritical-22] | Incorrect NatSpec Syntax | 13 |
[NonCritical-23] | Use @inheritdoc rather than using a non-standard annotation | 1 |
[NonCritical-24] | Solidity version 0.8.20 won't work on all chains due to PUSH0 | 2 |
[NonCritical-25] | Floating pragma should be avoided | 2 |
[NonCritical-26] | Empty function blocks | 13 |
[NonCritical-27] | Events regarding state variable changes should emit the previous state variable value | 18 |
[NonCritical-28] | In functions which accept an address as a parameter, there should be a zero address check to prevent bugs | 386 |
[NonCritical-29] | Enum values should be used in place of constant array indexes | 48 |
[NonCritical-30] | Revert statements within external and public functions can be used to perform DOS attacks | 130 |
[NonCritical-31] | Functions which are either public or external should not have a preceding _ in their name | 1 |
[NonCritical-32] | Functions which are either private or internal should have a preceding _ in their name | 21 |
[NonCritical-33] | Private and internal state variables should have a preceding _ in their name unless they are constants | 10 |
[NonCritical-34] | Public state variables shouldn't have a preceding _ in their name | 1 |
[NonCritical-35] | Contract lines should not be longer than 120 characters for readability | 1 |
[NonCritical-36] | Specific imports should be used where possible so only used code is imported | 1 |
[NonCritical-37] | Use newer solidity versions | 3 |
[NonCritical-38] | Not all event definitions are utilizing indexed variables. | 82 |
[NonCritical-39] | Dependence on external protocols | 3 |
[NonCritical-40] | Call calls must have their return checked | 1 |
[NonCritical-41] | Function names should differ to make the code more readable | 478 |
[NonCritical-42] | Functions should not be longer than 50 lines | 28 |
[NonCritical-43] | Functions within contracts are not ordered according to the solidity style guide | 13 |
[NonCritical-44] | Double type casts create complexity within the code | 9 |
[NonCritical-45] | Emits without msg.sender parameter | 11 |
[NonCritical-46] | Functions with array parameters should have length checks in place | 13 |
[NonCritical-47] | Interface imports should be declared first | 72 |
[NonCritical-48] | All interfaces used within a project should be imported | 5 |
[NonCritical-49] | A function which defines named returns in it's declaration doesn't need to use return | 9 |
[NonCritical-50] | SPDX identifier should be the in the first line of a solidity file | 121 |
[NonCritical-51] | Multiple mappings can be replaced with a single struct mapping | 13 |
[NonCritical-52] | Having chainId as a parameter can introduce cross chain replay attacks | 7 |
[NonCritical-53] | Unused state variables present | 1 |
[NonCritical-54] | Constants should be on the left side of the | 254 |
[NonCritical-55] | Interface names should have an I as the first character | 1 |
[NonCritical-56] | Defined named returns not used within function | 18 |
[NonCritical-57] | Both immutable and constant state variables should be CONSTANT_CASE | 33 |
[NonCritical-58] | Consider using named mappings | 50 |
[NonCritical-59] | Use a single contract or library for system wide constants | 37 |
[NonCritical-60] | Consider using modifiers for address control | 4 |
[NonCritical-61] | Off-by-one timestamp error | 7 |
[NonCritical-62] | Address from parameter can cause issues | 1 |
[NonCritical-63] | Variables should be used in place of magic numbers to improve readability | 158 |
[NonCritical-64] | Long powers of ten should use scientific notation 1eX | 7 |
[NonCritical-65] | Redundant else statement | 9 |
[NonCritical-66] | increase/decrease allowance should be used instead of approve/safeApprove | 16 |
[NonCritical-67] | Unused errors present | 37 |
[NonCritical-68] | Consider adding emergency-stop functionality | 66 |
[NonCritical-69] | Employ Explicit Casting to Bytes or Bytes32 for Enhanced Code Clarity and Meaning | 8 |
[NonCritical-70] | Custom error has no error variables | 259 |
[NonCritical-71] | Large or complicated code bases should implement invariant tests | 28 |
[NonCritical-72] | Overridden function has no body | 1 |
[NonCritical-73] | Unused structs present | 1 |
[NonCritical-74] | Empty bytes check is missing | 39 |
[NonCritical-75] | Use max instead of 0xfff... | 1 |
[NonCritical-76] | Chainlink price feed decimals not checked | 2 |
[NonCritical-77] | Use scopes sparingly | 16 |
[NonCritical-78] | No equate comparison checks between to and from address parameters | 3 |
[NonCritical-79] | Return bool not explicit | 14 |
[NonCritical-80] | Remove unnecessary solhint-disable | 1 |
[NonCritical-81] | Do not use underscore at the end of variable name | 17 |
[NonCritical-82] | Consider using SMTChecker | 121 |
[NonCritical-83] | The function symbol() is not part of the ERC20 standard | 3 |
[NonCritical-84] | Contracts should have full test coverage | 67 |
[NonCritical-85] | Chainlink oracle roundId and answeredIn variables no longer contain useful information | |
1 | ||
[NonCritical-86] | Use OpenZeppelin's ReentrancyGuard/ReentrancyGuardUpgradeable rather than writing your own | 1 |
[NonCritical-87] | Consider using SafeTransferLib.safeTransferETH() or Address.sendValue() for clearer semantic meaning | 1 |
[NonCritical-88] | Assembly block creates dirty bits | 8 |
[NonCritical-89] | Whitespace in expressions | 16 |
[NonCritical-90] | Consider using named function calls | 339 |
[NonCritical-91] | Using XOR (^) and AND (&) bitwise equivalents | 2 |
[NonCritical-92] | Public state variables should include natspec comments | 5 |
[NonCritical-93] | Lack Of Brace Spacing | 2 |
[NonCritical-94] | .call bypasses function existence check, type checking and argument packing | 2 |
[NonCritical-95] | Using while for unbounded loops isn’t recommended | 3 |
[NonCritical-96] | Revert should be used on some functions instead of return | 3 |
[NonCritical-97] | Common functions should be refactored to a common base contract | 94 |
[NonCritical-98] | Use of override is unnecessary | 10 |
[NonCritical-99] | No access control on receive/payable fallback | 4 |
[NonCritical-100] | If statement control structures do not comply with best practices | 9 |
[NonCritical-101] | Cyclomatic complexity in functions | 32 |
[NonCritical-102] | Incorrect withdraw declaration | 1 |
[NonCritical-103] | Consider adding formal verification proofs | 67 |
[NonCritical-104] | Unused events present | 1 |
[NonCritical-105] | Unused import | 1 |
[NonCritical-106] | function names should be lowerCamelCase | 2 |
[NonCritical-107] | safeApprove()/approve() may revert if the current approval is not zero | 14 |
[NonCritical-108] | Missing events in sensitive functions | 50 |
[NonCritical-109] | Consider disallowing transfers to "address(this)" | 2 |
[NonCritical-110] | Add inline comments for unnamed variables in function declarations | 16 |
[NonCritical-111] | The function name() is not part of the ERC20 standard | 2 |
[NonCritical-112] | Public state arrays should have a getter to return all elements | 5 |
[NonCritical-113] | Ensure block.timestamp is only used in long time intervals | 5 |
[NonCritical-114] | Don't assume specific ETH balance | 3 |
[NonCritical-115] | Avoid mutating function parameters | 24 |
[NonCritical-116] | Don't only depend on Solidity's arithmetic ordering. | 2 |
[NonCritical-117] | View function is not defined as such in interface | 2 |
[NonCritical-118] | Pure function is not defined as such in interface | 5 |
[NonCritical-119] | It is best practice to use linear inheritance | 21 |
[NonCritical-120] | A event should be emitted if a non immutable state variable is set in a constructor | 23 |
[NonCritical-121] | Funds can be trapped due to unreverting local payable call | 21 |
[NonCritical-122] | Payable functions which do not interact with the native token should not be payable | 2 |
[NonCritical-123] | Uint casted addresses used in conditional checks can be bypassed | 4 |
[NonCritical-124] | gasLimit should be uint64 | 5 |
[NonCritical-125] | Inconstant use of 0x0 and 0x00 for 0 bytes | 2 |
[NonCritical-126] | Mint functions should be accompanied by a burn function and vice versa | 1 |
[NonCritical-127] | Tautology when checking address value | 2 |
[NonCritical-128] | Avoid hard coding gasLimit values | 2 |
[NonCritical-129] | Immutable and constant integer state variables should not be casted | 2 |
[NonCritical-130] | Numbers downcast to addresses may result in collisions | 5 |
[NonCritical-131] | Public variable declarations should have NatSpec descriptions | 3 |
[NonCritical-132] | Use -= for mappings | 7 |
[NonCritical-133] | Use the Modern Upgradeable Contract Paradigm | 67 |
[NonCritical-134] | Upgrade openzeppelin to the Latest Version - 5.0.0 | 1 |
[NonCritical-135] | Use a struct to encapsulate multiple function parameters | 65 |
[NonCritical-136] | Returning a struct instead of returning many variables is better | 1 |
[NonCritical-137] | Using delete instead of setting mapping to 0 saves gas | 1 |
[NonCritical-138] | Empty function body without natspec comments | 1 |
[NonCritical-139] | Long numbers should include underscores to improve readability and prevent typos | 21 |
[NonCritical-140] | Consider using ERC20Capped | 7 |
[NonCritical-141] | Consider using a format prettier or forge fmt | 10 |
[NonCritical-142] | Avoid defining a function in a single line including it's contents | 192 |
[NonCritical-143] | Use 'using' keyword when using specific imports rather than calling the specific import directly | 290 |
[NonCritical-144] | Try catch statement without human readable error | 4 |
[NonCritical-145] | Avoid revertible function calls in a constructor | 11 |
[NonCritical-146] | Use the same Solidity version in non library/interface files throughout the project | 3 |
[NonCritical-147] | Inconsistent checks of address params against address(0) | 4 |
[NonCritical-148] | Avoid declaring variables with the names of defined functions within the project | 1743 |
[NonCritical-149] | Reserved keyword 'error' used as a variable/object name | 16 |
[NonCritical-150] | Avoid caching global vars used once within the function | 1 |
[NonCritical-151] | Upgradeable contract uses non-upgradeable version of the OpenZeppelin libraries/contracts | 1 |
[NonCritical-152] | All verbatim blocks are considered identical by deduplicator and can incorrectly be unified | 2 |
[NonCritical-153] | Constructors should emit an event | 74 |
[NonCritical-154] | Avoid single line non empty object declarations | 151 |
[NonCritical-155] | Contract and Abstract files should have a fixed compiler version | 83 |
[NonCritical-156] | Variables should be mixedCase | 1 |
[NonCritical-157] | Consider using 'using-for' syntax when using libraries | 156 |
[NonCritical-158] | Consider validating all user inputs | 257 |
[NonCritical-159] | Consider providing a ranged getter for array state variables | 8 |
[NonCritical-160] | Consider using named returns | 293 |
[NonCritical-161] | Avoid external calls in modifiers | 3 |
[NonCritical-162] | Errors should have parameters | 276 |
[NonCritical-163] | Avoid using 'owner' or '_owner' as a parameter name | 22 |
[NonCritical-164] | Catch return of decimals as uint8 | 20 |
[NonCritical-165] | While true/false loops can result in infinite loops | 2 |
[NonCritical-166] | ERC777 tokens can introduce reentrancy risks | 14 |
Number | Details | Instances | Gas |
---|---|---|---|
[Gas-1] | Multiple accesses of the same mapping/array key/index should be cached | 24 | 24192 |
[Gas-2] | The result of a function call should be cached rather than re-calling the function | 7 | 10500 |
[Gas-3] | State variables used within a function more than once should be cached to save gas | 5 | 11000 |
[Gas-4] | Low level call can be optimized with assembly | 5 | 6200 |
[Gas-5] | Consider Using Solady's Gas Optimized Lib for Math | 100 | 0.0 |
[Gas-6] | It is a waste of GAS to emit variable literals | 38 | 11552 |
[Gas-7] | x + y is more efficient than using += for state variables (likewise for -=) | 4 | 80 |
[Gas-8] | Public functions not used internally can be marked as external to save gas | 10 | 0.0 |
[Gas-9] | Calldata should be used in place of memory function parameters when not mutated | 4 | 208 |
[Gas-10] | Usage of smaller uint/int types causes overhead | 29 | 46255 |
[Gas-11] | Mappings are cheaper than arrays for state variable iteration | 8 | 152000 |
[Gas-12] | Use != 0 instead of > 0 | 59 | 10443 |
[Gas-13] | Integer increments by one can be unchecked to save on gas fees | 43 | 221880 |
[Gas-14] | Use byte32 in place of string | 7 | 0.0 |
[Gas-15] | Default bool values are manually reset | 3 | 0.0 |
[Gas-16] | Default int values are manually reset | 13 | 0.0 |
[Gas-17] | Mappings used within a function more than once should be cached to save gas | 11 | 12100 |
[Gas-18] | Use assembly to check for the zero address | 31 | 0.0 |
[Gas-19] | Divisions which do not divide by -X cannot overflow or overflow so such operations can be unchecked to save gas | 55 | 0.0 |
[Gas-20] | Can transfer 0 | 1 | 0.0 |
[Gas-21] | Redundant state variable getters | 4 | 0.0 |
[Gas-22] | Divisions of powers of 2 can be replaced by a right shift operation to save gas | 1 | 0.0 |
[Gas-23] | multiplications of powers of 2 can be replaced by a left shift operation to save gas | 4 | 0.0 |
[Gas-24] | Struct variables can be packed into fewer storage slots | 22 | 1210000 |
[Gas-25] | Consider activating via-ir for deploying | 121 | 3660250 |
[Gas-26] | Superfluous event fields | 2 | 136 |
[Gas-27] | Use bitmap to save gas | 47 | 154630 |
[Gas-28] | Use assembly hashing | 2 | 0.0 |
[Gas-29] | Consider using OZ EnumerateSet in place of nested mappings | 10 | 100000 |
[Gas-30] | Use selfBalance() in place of address(this).balance | 5 | 20000 |
[Gas-31] | Use assembly to emit events | 127 | 612902 |
[Gas-32] | Shorten the array rather than copying to a new one | 24 | 0.0 |
[Gas-33] | Use unchecked for operations on immutable variables | 1 | 0.0 |
[Gas-34] | Use assembly in place of abi.decode to extract calldata values more efficiently | 18 | 0.0 |
[Gas-35] | Counting down in for statements is more gas efficient | 25 | 0.0 |
[Gas-36] | State variables can be packed into fewer storage slots by truncating timestamp bytes | 1 | 2500 |
[Gas-37] | Using private rather than public for constants and immutables, saves gas | 39 | 0.0 |
[Gas-38] | Mark Functions That Revert For Normal Users As payable | 5 | 625 |
[Gas-39] | Function names can be optimized | 67 | 574592 |
[Gas-40] | Lack of unchecked in loops | 18 | 65880 |
[Gas-41] | Consider migrating require statements to custom errors | 3 | 126 |
[Gas-42] | Consider not using libraries when implementing simple functionality. | 7 | 49000 |
[Gas-43] | Avoid indexing dynamic types | 5 | 0.0 |
[Gas-44] | Using bools for storage incurs overhead | 29 | 58870 |
[Gas-45] | Where a value is casted more than once, consider caching the result to save gas | 4 | 0.0 |
[Gas-46] | The following mappings can be replaced with a bit mask | 1 | 0.0 |
[Gas-47] | State variable can be updated more than once in a function | 1 | 800 |
[Gas-48] | Assembly let var only used on once | 2 | 0.0 |
[Gas-49] | Unnecessary casting as variable is already of the same type | 4 | 352 |
[Gas-50] | Use += for mappings | 8 | 0.0 |
[Gas-51] | Simple checks for zero uint can be done using assembly to save gas | 18 | 1944 |
[Gas-52] | Use Unchecked for Divisions on Constant or Immutable Values | 9 | 0.0 |
[Gas-53] | Using nested if to save gas | 43 | 11094 |
[Gas-54] | Optimize Deployment Size by Fine-tuning IPFS Hash | 67 | 47583400 |
[Gas-55] | Avoid Unnecessary Public Variables | 162 | 577368000 |
[Gas-56] | Optimize Storage with Byte Truncation for Time Related State Variables | 11 | 242000 |
[Gas-57] | Stack variable cost less than state variables while used in emiting event | 2 | 36 |
[Gas-58] | Caching global variables is more expensive than using the actual variable | 1 | 12 |
[Gas-59] | Avoid emitting event on every iteration | 1 | 2250 |
[Gas-60] | Using constants directly, rather than caching the value, saves gas | 1 | 0.0 |
[Gas-61] | Use s.x = s.x + y instead of s.x += y for memory structs (same for -= etc) | 17 | 28900 |
[Gas-62] | Time state variables can be truncated to uint32 | 3 | 180000 |
[Gas-63] | Constants are cheaper than Enums | 2 | 80000 |
[Gas-64] | ++X costs slightly less gas than X++ (same with --) | 28 | 3920 |
[Gas-65] | Solidity versions 0.8.19 and above are more gas efficient | 3 | 9000 |
[Gas-66] | Variables that can be set to immutable | 5 | 0.0 |
[Gas-67] | Variable declared within iteration | 6 | 0.0 |
[Gas-68] | Internal functions only used once can be inlined so save gas | 34 | 34680 |
[Gas-69] | Constructors can be marked as payable to save deployment gas | 76 | 0.0 |
[Gas-70] | Use assembly scratch space to build calldata for external calls | 376 | 31102720 |
[Gas-71] | Use assembly scratch space to build calldata for event emits | 89 | 1742620 |
[Gas-72] | Consider using solady's "FixedPointMathLib" | 152 | 0.0 |
[Gas-73] | Same cast is done multiple times | 15 | 0.0 |
[Gas-74] | Assigning to structs can be more efficient | 7 | 6370 |
[Gas-75] | Cache address(this) when used more than once | 51 | 0.0 |
[Gas-76] | Internal functions never used once can be removed | 2 | 0.0 |
[Gas-77] | Only emit event in setter function if the state variable was changed | 26 | 0.0 |
[Gas-78] | Short circuit before external calls | 33 | 0.0 |
[Gas-79] | Use OZ Array.unsafeAccess() to avoid repeated array length checks | 54 | 6123600 |
[Gas-80] | State variable written in a loop | 3 | 173820 |
[Gas-81] | State variable read in a loop | 15 | 2954940 |
[Gas-82] | Use uint256(1)/uint256(2) instead of true/false to save gas for changes | 155 | 205413750 |
[Gas-83] | Avoid emitting events in loops | 1 | 2250 |
[Gas-84] | Enable IR-based code generation | 67 | 0.0 |
[Gas-85] | Call msg.sender directly rather than caching the value to save gas | 5 | 0.0 |
[Gas-86] | Write direct outcome, instead of performing mathematical operations for constant state variables | 5 | 0.0 |
Ensure such accounts are protected and consider implementing multi sig to prevent a single point of failure
Num of instances: 5
Click to show findings
['378']
357: function _withdraw(
358: uint256 assets,
359: address receiver,
360: address owner,
361: bool forceRedeemCollateral
362: ) internal override returns (uint256 shares) {
363:
364: uint256 pending = _calculatePendingRewards();
365: uint256 ta = _totalAssets + pending;
366:
367:
368: if (assets > _convertToAssets(balanceOf(owner), ta)) {
369:
370: _revert(0x05203273);
371: }
372:
373:
374: shares = _previewWithdraw(assets, ta);
375:
376:
377:
378: if (msg.sender != owner) { // <= FOUND
379: uint256 allowed = allowance(owner, msg.sender);
380:
381: if (allowed != type(uint256).max) {
382: _spendAllowance(owner, msg.sender, allowed - shares);
383: }
384: }
385:
386:
387: marketManager.canRedeemWithCollateralRemoval( // <= FOUND
388: address(this),
389: owner,
390: balanceOf(owner),
391: shares,
392: forceRedeemCollateral
393: );
394:
395:
396: _gaugePool().withdraw(address(this), owner, shares);
397:
398: _processWithdraw(
399: msg.sender,
400: receiver,
401: owner,
402: assets,
403: shares,
404: ta,
405: pending
406: );
407: }
['438']
424: function _redeem(
425: uint256 shares,
426: address receiver,
427: address owner,
428: bool delegatedAction,
429: bool forceRedeemCollateral
430: ) internal override returns (uint256 assets) {
431:
432:
433: if (delegatedAction) {
434: if (!_checkIsDelegate(owner, msg.sender)) {
435: _revert(_UNAUTHORIZED_SELECTOR);
436: }
437: } else {
438: if (msg.sender != owner) { // <= FOUND
439: uint256 allowed = allowance(owner, msg.sender);
440:
441: if (allowed != type(uint256).max) {
442: _spendAllowance(owner, msg.sender, allowed - shares);
443: }
444: }
445: }
446:
447:
448: if (shares > maxRedeem(owner)) {
449:
450: _revert(0xcc3c42c0);
451: }
452:
453:
454: marketManager.canRedeemWithCollateralRemoval( // <= FOUND
455: address(this),
456: owner,
457: balanceOf(owner),
458: shares,
459: forceRedeemCollateral
460: );
461:
462:
463: uint256 pending = _calculatePendingRewards();
464: uint256 ta = _totalAssets + pending;
465:
466:
467: if ((assets = _previewRedeem(shares, ta)) == 0) {
468: revert CTokenCompounding__ZeroAssets();
469: }
470:
471:
472: _gaugePool().withdraw(address(this), owner, shares);
473:
474: _processWithdraw(
475: msg.sender,
476: receiver,
477: owner,
478: assets,
479: shares,
480: ta,
481: pending
482: );
483: }
['197']
176: function _withdraw(
177: uint256 assets,
178: address receiver,
179: address owner,
180: bool forceRedeemCollateral
181: ) internal override returns (uint256 shares) {
182:
183: uint256 ta = _totalAssets;
184:
185:
186:
187: if (assets > _convertToAssets(balanceOf(owner), ta)) {
188:
189: _revert(0xc6e63cc0);
190: }
191:
192:
193: shares = _previewWithdraw(assets, ta);
194:
195:
196:
197: if (msg.sender != owner) { // <= FOUND
198: uint256 allowed = allowance(owner, msg.sender);
199:
200: if (allowed != type(uint256).max) {
201: _spendAllowance(owner, msg.sender, allowed - shares);
202: }
203: }
204:
205:
206: marketManager.canRedeemWithCollateralRemoval( // <= FOUND
207: address(this),
208: owner,
209: balanceOf(owner),
210: shares,
211: forceRedeemCollateral
212: );
213:
214:
215: _gaugePool().withdraw(address(this), owner, shares);
216:
217: _processWithdraw(msg.sender, receiver, owner, assets, shares, ta);
218: }
['246']
232: function _redeem(
233: uint256 shares,
234: address receiver,
235: address owner,
236: bool delegatedAction,
237: bool forceRedeemCollateral
238: ) internal override returns (uint256 assets) {
239:
240:
241: if (delegatedAction) {
242: if (!_checkIsDelegate(owner, msg.sender)) {
243: _revert(_UNAUTHORIZED_SELECTOR);
244: }
245: } else {
246: if (msg.sender != owner) { // <= FOUND
247: uint256 allowed = allowance(owner, msg.sender);
248:
249: if (allowed != type(uint256).max) {
250: _spendAllowance(owner, msg.sender, allowed - shares);
251: }
252: }
253: }
254:
255:
256: if (shares > maxRedeem(owner)) {
257:
258: _revert(0xb1652d68);
259: }
260:
261:
262: marketManager.canRedeemWithCollateralRemoval( // <= FOUND
263: address(this),
264: owner,
265: balanceOf(owner),
266: shares,
267: forceRedeemCollateral
268: );
269:
270:
271: uint256 ta = _totalAssets;
272:
273:
274: if ((assets = _previewRedeem(shares, ta)) == 0) {
275: revert CTokenPrimitive__ZeroAssets();
276: }
277:
278:
279: _gaugePool().withdraw(address(this), owner, shares);
280:
281: _processWithdraw(msg.sender, receiver, owner, assets, shares, ta);
282: }
['476']
472: function _withdraw(address by, address to, address owner, uint256 assets, uint256 shares)
473: internal
474: virtual
475: {
476: if (by != owner) _spendAllowance(owner, by, shares); // <= FOUND
477: _beforeWithdraw(assets, shares);
478: _burn(owner, shares);
479: SafeTransferLib.safeTransfer(asset(), to, assets);
480:
481: assembly {
482:
483: mstore(0x00, assets)
484: mstore(0x20, shares)
485: let m := shr(96, not(0))
486: log4(0x00, 0x40, _WITHDRAW_EVENT_SIGNATURE, and(m, by), and(m, to), and(m, owner))
487: }
488: }
The contract currently lacks a mechanism to ensure that prices fetched from the Chainlink oracle are up-to-date. In scenarios where the Off-Chain Reporting (OCR) protocol fails to update prices in a timely manner, stale price data could be used inadvertently. This could potentially lead to incorrect contract operations, including mispriced transactions. To mitigate this, consider incorporating a staleness threshold (defined in seconds) into the contract configuration. This would enforce that any price data used is within this specified freshness timeframe, thereby ensuring the contract only operates with relevant and recent price information.
Num of instances: 1
Click to show findings
['249']
249: function _parseData(
250: AdaptorData memory data,
251: bool inUSD
252: ) internal view returns (PriceReturnData memory pData) {
253: pData.inUSD = inUSD;
254: if (!IOracleRouter(centralRegistry.oracleRouter()).isSequencerValid()) {
255: pData.hadError = true;
256: return pData;
257: }
258:
259: (, int256 price, , uint256 updatedAt, ) = IChainlink(data.aggregator)
260: .latestRoundData(); // <= FOUND
261:
262:
263: if (price <= 0) {
264: pData.hadError = true;
265: return pData;
266: }
267:
268: uint256 newPrice = (uint256(price) * WAD) / (10 ** data.decimals);
269:
270: pData.price = uint240(newPrice);
271: pData.hadError = _verifyData(
272: uint256(price),
273: updatedAt,
274: data.max,
275: data.min,
276: data.heartbeat
277: );
278: }
Using block.timestamp
for operation deadlines can be exploited by malicious entities in the Miner Extractable Value (MEV) landscape. Instead of ensuring immediacy, this approach lets miners choose when to execute the transaction within the block, potentially manipulating outcomes for their gain. For instance, they might delay the transaction until market conditions shift, triggering maximum allowable slippage or even causing other significant events like liquidations. To mitigate this risk, deadlines should be determined off-chain and explicitly set by the transaction initiator, ensuring a more predictable and secure execution environment and reducing potential MEV opportunities.
Num of instances: 1
Click to show findings
['292']
273: function _swapExactTokensForTokens(
274: address router,
275: address lpToken,
276: address tokenIn,
277: address tokenOut,
278: uint256 amount,
279: bool stable
280: ) internal returns (uint256) {
281:
282: SwapperLib._approveTokenIfNeeded(tokenIn, router, amount);
283:
284: IVeloRouter.Route[] memory routes = new IVeloRouter.Route[](1);
285: routes[0].from = tokenIn;
286: routes[0].to = tokenOut;
287: routes[0].stable = stable;
288: routes[0].factory = IVeloPool(lpToken).factory();
289:
290:
291: uint256[] memory amountsOut = IVeloRouter(router)
292: .swapExactTokensForTokens( // <= FOUND
293: amount,
294: 0,
295: routes,
296: address(this),
297: block.timestamp // <= FOUND
298: );
299:
300:
301: SwapperLib._removeApprovalIfNeeded(tokenIn, router);
302:
303: return amountsOut[amountsOut.length - 1];
304: }
24
When calculating price involves division, ensure there is a check of loss of precision in place, if this check is triggered the price should be rounded up by adding 1
Findings are labeled with ' <= FOUND'
Click to show findings
212: function _parseData(
213: AdaptorData memory data,
214: bool inUSD
215: ) internal view returns (PriceReturnData memory pData) {
216: uint256 price = _extractPrice(data.symbolHash); // <= FOUND
217:
218:
219: uint256 quoteDecimals = data.decimals;
220: if (quoteDecimals != 18) {
221:
222:
223: if (quoteDecimals < 18) {
224: price = price * (10 ** (18 - quoteDecimals)); // <= FOUND
225: } else {
226:
227:
228: price = price / (10 ** (quoteDecimals - 18)); // <= FOUND
229: }
230: }
231:
232: pData.hadError = _verifyData(price, data.max);
233:
234: if (!pData.hadError) {
235: pData.inUSD = inUSD;
236: pData.price = uint240(price); // <= FOUND
237: }
238: }
111: function getPrice(
112: address asset,
113: bool inUSD,
114: bool getLower
115: ) external view override returns (PriceReturnData memory pData) {
116: AdaptorData memory data = adaptorData[asset];
117:
118:
119:
120: if (isLocked(data.pool, 2)) {
121: revert Curve2PoolAssetAdaptor__Reentrant();
122: }
123:
124:
125: ICurvePool pool = ICurvePool(data.pool);
126:
127:
128: uint256 virtualPrice = pool.get_virtual_price();
129: _enforceBounds(virtualPrice, data.lowerBound, data.upperBound);
130:
131:
132: IOracleRouter oracleRouter = IOracleRouter(
133: centralRegistry.oracleRouter()
134: );
135: (uint256 basePrice, uint256 errorCode) = oracleRouter.getPrice(
136: data.baseToken,
137: inUSD,
138: getLower
139: );
140: if (errorCode > 0) {
141: pData.hadError = true;
142: return pData;
143: }
144:
145:
146: uint256 sample = pool.balances(
147: uint256(uint128(data.quoteTokenIndex))
148: ) / 100;
149:
150: uint256 out = pool.get_dy(
151: data.quoteTokenIndex,
152: data.baseTokenIndex,
153: sample
154: );
155:
156: uint256 price = (out * WAD * (10 ** data.quoteTokenDecimals)) / // <= FOUND
157: sample /
158: (10 ** data.baseTokenDecimals);
159:
160: price = (price * basePrice) / WAD; // <= FOUND
106: function getPrice(
107: address asset,
108: bool inUSD,
109: bool getLower
110: ) external view override returns (PriceReturnData memory pData) {
111: AdaptorData memory data = adaptorData[asset];
112:
113:
114:
115: if (isLocked(data.pool, 2)) {
116: revert Curve2PoolLPAdaptor__Reentrant();
117: }
118:
119:
120: ICurvePool pool = ICurvePool(data.pool);
121:
122:
123: uint256 virtualPrice = pool.get_virtual_price();
124: _enforceBounds(virtualPrice, data.lowerBound, data.upperBound);
125:
126:
127: IOracleRouter oracleRouter = IOracleRouter(
128: centralRegistry.oracleRouter()
129: );
130: uint256 price0;
131: uint256 price1;
132: uint256 errorCode;
133: (price0, errorCode) = oracleRouter.getPrice(
134: data.underlying0,
135: inUSD,
136: getLower
137: );
138: if (errorCode > 0) {
139: pData.hadError = true;
140: return pData;
141: }
142: (price1, errorCode) = oracleRouter.getPrice(
143: data.underlying1,
144: inUSD,
145: getLower
146: );
147: if (errorCode > 0) {
148: pData.hadError = true;
149: return pData;
150: }
151:
152:
153: uint256 price;
154: if (data.isCorrelated) {
155:
156: if (data.divideRate0 || data.divideRate1) {
157: uint256[2] memory rates = pool.stored_rates();
158: if (data.divideRate0) {
159: price0 = (price0 * WAD) / rates[0];
160: }
161: if (data.divideRate1) {
162: price1 = (price1 * WAD) / rates[1];
163: }
164: }
165:
166: if (getLower) {
167:
168: uint256 minPrice = price0 < price1 ? price0 : price1;
169: price = (minPrice * virtualPrice) / WAD; // <= FOUND
170: } else {
171:
172: uint256 maxPrice = price0 < price1 ? price1 : price0;
173: price = (maxPrice * virtualPrice) / WAD; // <= FOUND
174: }
175: } else {
176: price = // <= FOUND
177: (2 * virtualPrice * FixedPointMathLib.sqrt(price0)) /
178: FixedPointMathLib.sqrt(price1);
179: price = (price * price0) / WAD; // <= FOUND
180: }
181:
182: if (_checkOracleOverflow(price)) {
183: pData.hadError = true;
184: return pData;
185: }
186:
187: pData.inUSD = inUSD;
188: pData.price = uint240(price); // <= FOUND
189: }
350: function getPricesForAsset(
351: address asset,
352: bool inUSD
353: ) external view returns (FeedData[] memory) {
354: bool isMToken = mTokenAssets[asset].isMToken;
355: if (isMToken) {
356: asset = mTokenAssets[asset].underlying;
357: }
358:
359: uint256 numFeeds = assetPriceFeeds[asset].length;
360: if (numFeeds == 0) {
361: _revert(_NOT_SUPPORTED_SELECTOR);
362: }
363:
364: FeedData[] memory data = new FeedData[](numFeeds * 2);
365:
366:
367:
368: if (numFeeds < 2) {
369: data[0] = _getPriceFromFeed(asset, 0, inUSD, true);
370: data[1] = _getPriceFromFeed(asset, 0, inUSD, false);
371: if (isMToken) {
372: uint256 exchangeRate = IMToken(asset).exchangeRateCached();
373: data[0].price = uint240((data[0].price * exchangeRate) / WAD); // <= FOUND
374: data[1].price = uint240((data[1].price * exchangeRate) / WAD); // <= FOUND
375: }
376:
377: return data;
378: }
379:
380:
381:
382: data[0] = _getPriceFromFeed(asset, 0, inUSD, true);
383: data[1] = _getPriceFromFeed(asset, 0, inUSD, false);
384: data[2] = _getPriceFromFeed(asset, 1, inUSD, true);
385: data[3] = _getPriceFromFeed(asset, 1, inUSD, false);
386:
387: if (isMToken) {
388: uint256 exchangeRate = IMToken(asset).exchangeRateCached();
389: data[0].price = uint240((data[0].price * exchangeRate) / WAD); // <= FOUND
390: data[1].price = uint240((data[1].price * exchangeRate) / WAD); // <= FOUND
391: data[2].price = uint240((data[2].price * exchangeRate) / WAD); // <= FOUND
392: data[3].price = uint240((data[3].price * exchangeRate) / WAD); // <= FOUND
393: }
394:
395: return data;
396: }
435: function getPrice(
436: address asset,
437: bool inUSD,
438: bool getLower
439: ) public view returns (uint256 price, uint256 errorCode) {
440: address mAsset;
441:
442: if (mTokenAssets[asset].isMToken) {
443: mAsset = asset;
444: asset = mTokenAssets[asset].underlying;
445: }
446:
447: uint256 numFeeds = assetPriceFeeds[asset].length;
448:
449: if (numFeeds == 0) {
450: _revert(_NOT_SUPPORTED_SELECTOR);
451: }
452:
453:
454: if (numFeeds < 2) {
455: (price, errorCode) = _getPriceSingleFeed(asset, inUSD, getLower);
456: } else {
457: (price, errorCode) = _getPriceDualFeed(asset, inUSD, getLower);
458: }
459:
460:
461:
462: if (price == 0 && errorCode < BAD_SOURCE) { // <= FOUND
463: errorCode = BAD_SOURCE;
464: }
465:
466:
467: if (mAsset != address(0)) {
468: uint256 exchangeRate = IMToken(mAsset).exchangeRateCached();
469: price = (price * exchangeRate) / WAD; // <= FOUND
470: }
471: }
86: function getPrice(
87: address asset,
88: bool inUSD,
89: bool getLower
90: ) external view override returns (PriceReturnData memory pData) {
91:
92: if (!isSupportedAsset[asset]) {
93: revert PendleLPTokenAdaptor__AssetIsNotSupported();
94: }
95:
96: AdaptorData memory data = adaptorData[asset];
97:
98: uint256 lpRate = IPMarket(asset).getLpToAssetRate(data.twapDuration);
99:
100: (uint256 price, uint256 errorCode) = IOracleRouter(
101: centralRegistry.oracleRouter()
102: ).getPrice(data.quoteAsset, inUSD, getLower);
103:
104:
105: if (errorCode > 0) {
106: pData.hadError = true;
107: return pData;
108: }
109:
110:
111:
112: price = (price * lpRate) / WAD; // <= FOUND
113:
114:
115: if (_checkOracleOverflow(price)) {
116: pData.hadError = true;
117: return pData;
118: }
119:
120: pData.inUSD = inUSD;
121: pData.price = uint240(price); // <= FOUND
122: }
87: function getPrice(
88: address asset,
89: bool inUSD,
90: bool getLower
91: ) external view override returns (PriceReturnData memory pData) {
92:
93: if (!isSupportedAsset[asset]) {
94: revert PendlePrincipalTokenAdaptor__AssetIsNotSupported();
95: }
96:
97: AdaptorData memory data = adaptorData[asset];
98:
99: uint256 ptRate = data.market.getPtToAssetRate(data.twapDuration);
100:
101: (uint256 price, uint256 errorCode) = IOracleRouter(
102: centralRegistry.oracleRouter()
103: ).getPrice(data.quoteAsset, inUSD, getLower);
104:
105:
106: if (errorCode > 0) {
107: pData.hadError = true;
108: return pData;
109: }
110:
111:
112:
113: price = (price * ptRate) / WAD; // <= FOUND
114:
115:
116: if (_checkOracleOverflow(price)) {
117: pData.hadError = true;
118: return pData;
119: }
120:
121: pData.inUSD = inUSD;
122: pData.price = uint240(price); // <= FOUND
123: }
Implement a zero address check for found instances
Num of instances: 7
Click to show findings
['217']
217: function _getFairPrice(
218: uint256 reserve0,
219: uint256 reserve1,
220: uint256 price0,
221: uint256 price1,
222: uint256 totalSupply
223: ) internal pure returns (uint256) {
224:
225: uint256 sqrtReserve = FixedPointMathLib.sqrt(
226: FixedPointMathLib.sqrt(reserve0 * reserve1) *
227: FixedPointMathLib.sqrt(
228: reserve0 * reserve0 + reserve1 * reserve1
229: )
230: );
231: uint256 ratio = ((1e18) * price0) / price1; // <= FOUND
232: uint256 sqrtPrice = FixedPointMathLib.sqrt(
233: FixedPointMathLib.sqrt((1e18) * ratio) *
234: FixedPointMathLib.sqrt(1e36 + ratio * ratio)
235: );
236: return
237: ((((1e18) * sqrtReserve) / sqrtPrice) * price0 * 2) / totalSupply;
238: }
['178']
178: function claim() external returns (uint256 amount) { // <= FOUND
179: SaleStatus saleStatus = currentStatus();
180: if (saleStatus == SaleStatus.NotStarted) {
181: revert CurvanceDAOLBP__NotStarted();
182: }
183: if (saleStatus == SaleStatus.InSale) {
184: revert CurvanceDAOLBP__InSale();
185: }
186:
187: uint256 payAmount = userCommitted[msg.sender];
188: userCommitted[msg.sender] = 0;
189:
190: uint256 price = currentPrice();
191: uint256 adjustedPayAmount = _adjustDecimals(
192: payAmount,
193: paymentTokenDecimals,
194: 18
195: );
196: amount = (adjustedPayAmount * WAD) / price; // <= FOUND
197:
198: SafeTransferLib.safeTransfer(cve, msg.sender, amount);
199:
200: emit Claimed(msg.sender, amount);
201: }
['821']
821: function _getPositiveCFactorResult(
822: uint256 multiplier,
823: uint256 adjustmentVelocity,
824: uint256 decay,
825: uint256 current,
826: uint256 start,
827: uint256 end
828: ) internal pure returns (uint256) {
829:
830:
831:
832:
833: uint256 cFactor = ((current - start) * WAD) / (end - start);
834:
835:
836:
837: cFactor = WAD_SQUARED + (cFactor * adjustmentVelocity);
838:
839:
840:
841: return ((multiplier * cFactor) / WAD_SQUARED) - decay;
842: }
['867']
867: function _getNegativeCFactorResult(
868: uint256 multiplier,
869: uint256 adjustmentVelocity,
870: uint256 decay,
871: uint256 current,
872: uint256 start,
873: uint256 end
874: ) internal pure returns (uint256) {
875:
876:
877:
878: uint256 cFactor = ((start - current) * WAD) / (start - end);
879:
880:
881:
882: cFactor = WAD_SQUARED + (cFactor * adjustmentVelocity);
883:
884:
885:
886: return ((multiplier * WAD_SQUARED) / cFactor) - decay;
887: }
['748']
748: function _executeEpochFeeRouter(
749: ChainData memory chainData,
750: uint256 numChains,
751: uint256 epoch
752: ) internal returns (uint256) {
753: IProtocolMessagingHub messagingHub = IProtocolMessagingHub(
754: centralRegistry.protocolMessagingHub()
755: );
756:
757: IVeCVE veCVE = IVeCVE(centralRegistry.veCVE());
758: uint256 lockedTokens = (veCVE.chainPoints() -
759: veCVE.chainUnlocksByEpoch(epoch));
760:
761: uint256 totalLockedTokens = lockedTokens;
762:
763:
764:
765: for (uint256 i; i < numChains; ) {
766: totalLockedTokens += crossChainLockData[i].lockAmount;
767:
768: unchecked {
769: ++i;
770: }
771: }
772:
773: uint256 feeTokenBalance = IERC20(feeToken).balanceOf(address(this));
774:
775:
776:
777: SafeTransferLib.safeTransfer(
778: feeToken,
779: oneBalanceFeeManager,
780: (feeTokenBalance * vaultCompoundFee()) /
781: centralRegistry.protocolHarvestFee()
782: );
783:
784: feeTokenBalance = IERC20(feeToken).balanceOf(address(this));
785:
786: uint256 chainId;
787: uint256 feeTokenBalanceForChain;
788:
789:
790:
791: for (uint256 i; i < numChains; ) {
792: chainId = crossChainLockData[i].chainId;
793: chainData = centralRegistry.supportedChainData(chainId);
794:
795:
796:
797:
798:
799:
800:
801: feeTokenBalanceForChain =
802: (((feeTokenBalance * WAD) / totalLockedTokens) *
803: crossChainLockData[i].lockAmount) /
804: WAD;
805:
806: messagingHub.sendFees(
807: chainId,
808: chainData.messagingHub,
809: feeTokenBalanceForChain
810: );
811:
812: unchecked {
813: ++i;
814: }
815: }
816:
817:
818:
819:
820:
821:
822:
823:
824: feeTokenBalanceForChain =
825: (((feeTokenBalance * WAD) / totalLockedTokens) * lockedTokens) /
826: WAD;
827: uint256 epochRewardsPerCVE = (feeTokenBalance * WAD) /
828: totalLockedTokens;
829:
830: ICVELocker locker = ICVELocker(centralRegistry.cveLocker());
831:
832:
833:
834: if (locker.isShutdown() == 2) {
835: SafeTransferLib.safeTransfer(
836: feeToken,
837: centralRegistry.daoAddress(),
838: feeTokenBalanceForChain
839: );
840: return epochRewardsPerCVE;
841: }
842:
843:
844: SafeTransferLib.safeTransfer(
845: feeToken,
846: address(locker),
847: feeTokenBalanceForChain
848: );
849: ICVELocker(locker).recordEpochRewards(epochRewardsPerCVE);
850:
851: return epochRewardsPerCVE;
852: }
['856']
856: function _convertETHUSD(
857: uint240 currentPrice,
858: uint256 conversionRate,
859: bool currentlyInUSD
860: ) internal pure returns (uint256) {
861: if (!currentlyInUSD) {
862:
863: return (currentPrice * conversionRate) / WAD;
864: }
865:
866: return (currentPrice * WAD) / conversionRate;
867: }
['224']
224: function _optimalDeposit(
225: address factory,
226: address lpToken,
227: uint256 amount0,
228: uint256 reserve0,
229: uint256 reserve1,
230: uint256 decimals0,
231: uint256 decimals1,
232: bool stable
233: ) internal view returns (uint256) {
234:
235: uint256 swapFee = IVeloPairFactory(factory).getFee(lpToken, stable);
236: uint256 a;
237:
238:
239: if (stable) {
240: a = (((amount0 * 10000) / (10000 - swapFee)) * 1e18) / decimals0; // <= FOUND
241:
242: uint256 x = (reserve0 * 1e18) / decimals0;
243: uint256 y = (reserve1 * 1e18) / decimals1; // <= FOUND
244: uint256 x2 = (x * x) / 1e18;
245: uint256 y2 = (y * y) / 1e18;
246: uint256 p = (y * (((x2 * 3 + y2) * 1e18) / (y2 * 3 + x2))) / x; // <= FOUND
247:
248: uint256 num = a * y;
249: uint256 den = ((a + x) * p) / 1e18 + y;
250:
251: return ((num / den) * decimals0) / 1e18;
252: }
253:
254:
255: uint256 swapFeeFactor = 10000 - swapFee;
256:
257: a = (10000 + swapFeeFactor) * reserve0;
258: uint256 b = amount0 * 10000 * reserve0 * 4 * swapFeeFactor;
259: uint256 c = FixedPointMathLib.sqrt(a * a + b);
260: uint256 d = swapFeeFactor * 2;
261: return (c - a) / d; // <= FOUND
262:
263: }
Perform multiplication operations first
Num of instances: 3
Click to show findings
['72']
72: function getPrice(
73: address asset,
74: bool inUSD,
75: bool getLower
76: ) external view override returns (PriceReturnData memory pData) {
77:
78: if (!isSupportedAsset[asset]) {
79: revert BalancerStablePoolAdaptor__AssetIsNotSupported();
80: }
81:
82:
83: _ensureNotInVaultContext(balancerVault);
84:
85:
86: AdaptorData memory data = adaptorData[asset];
87: IBalancerPool pool = IBalancerPool(asset);
88:
89: pData.inUSD = inUSD;
90: IOracleRouter oracleRouter = IOracleRouter(centralRegistry.oracleRouter());
91:
92:
93: uint256 numUnderlyingOrConstituent = data
94: .underlyingOrConstituent
95: .length;
96: uint256 averagePrice;
97: uint256 numPrices;
98:
99: uint256 price;
100: uint256 errorCode;
101: for (uint256 i; i < numUnderlyingOrConstituent; ++i) {
102:
103: if (address(data.underlyingOrConstituent[i]) == address(0)) {
104: break;
105: }
106:
107: (price, errorCode) = oracleRouter.getPrice(
108: data.underlyingOrConstituent[i],
109: inUSD,
110: getLower
111: );
112:
113:
114: if (errorCode > 0) {
115: pData.hadError = true;
116: return pData;
117: }
118:
119:
120:
121: averagePrice += price;
122: ++numPrices;
123:
124: }
125:
126:
127: if (averagePrice == 0) {
128: pData.hadError = true;
129: return pData;
130: }
131:
132: averagePrice = ((averagePrice / numPrices) * pool.getRate()) / WAD;
133:
134:
135: if (_checkOracleOverflow(averagePrice)) {
136: pData.hadError = true;
137: return pData;
138: }
139:
140: pData.price = uint240(averagePrice);
141: }
['217']
217: function _getFairPrice(
218: uint256 reserve0,
219: uint256 reserve1,
220: uint256 price0,
221: uint256 price1,
222: uint256 totalSupply
223: ) internal pure returns (uint256) {
224:
225: uint256 sqrtReserve = FixedPointMathLib.sqrt(
226: FixedPointMathLib.sqrt(reserve0 * reserve1) *
227: FixedPointMathLib.sqrt(
228: reserve0 * reserve0 + reserve1 * reserve1
229: )
230: );
231: uint256 ratio = ((1e18) * price0) / price1;
232: uint256 sqrtPrice = FixedPointMathLib.sqrt(
233: FixedPointMathLib.sqrt((1e18) * ratio) *
234: FixedPointMathLib.sqrt(1e36 + ratio * ratio)
235: );
236: return
237: ((((1e18) * sqrtReserve) / sqrtPrice) * price0 * 2) / totalSupply;
238: }
['748']
748: function _executeEpochFeeRouter(
749: ChainData memory chainData,
750: uint256 numChains,
751: uint256 epoch
752: ) internal returns (uint256) {
753: IProtocolMessagingHub messagingHub = IProtocolMessagingHub(
754: centralRegistry.protocolMessagingHub()
755: );
756:
757: IVeCVE veCVE = IVeCVE(centralRegistry.veCVE());
758: uint256 lockedTokens = (veCVE.chainPoints() -
759: veCVE.chainUnlocksByEpoch(epoch));
760:
761: uint256 totalLockedTokens = lockedTokens;
762:
763:
764:
765: for (uint256 i; i < numChains; ) {
766: totalLockedTokens += crossChainLockData[i].lockAmount;
767:
768: unchecked {
769: ++i;
770: }
771: }
772:
773: uint256 feeTokenBalance = IERC20(feeToken).balanceOf(address(this));
774:
775:
776:
777: SafeTransferLib.safeTransfer(
778: feeToken,
779: oneBalanceFeeManager,
780: (feeTokenBalance * vaultCompoundFee()) /
781: centralRegistry.protocolHarvestFee()
782: );
783:
784: feeTokenBalance = IERC20(feeToken).balanceOf(address(this));
785:
786: uint256 chainId;
787: uint256 feeTokenBalanceForChain;
788:
789:
790:
791: for (uint256 i; i < numChains; ) {
792: chainId = crossChainLockData[i].chainId;
793: chainData = centralRegistry.supportedChainData(chainId);
794:
795:
796:
797:
798:
799:
800:
801: feeTokenBalanceForChain =
802: (((feeTokenBalance * WAD) / totalLockedTokens) *
803: crossChainLockData[i].lockAmount) /
804: WAD;
805:
806: messagingHub.sendFees(
807: chainId,
808: chainData.messagingHub,
809: feeTokenBalanceForChain
810: );
811:
812: unchecked {
813: ++i;
814: }
815: }
816:
817:
818:
819:
820:
821:
822:
823:
824: feeTokenBalanceForChain =
825: (((feeTokenBalance * WAD) / totalLockedTokens) * lockedTokens) /
826: WAD;
827: uint256 epochRewardsPerCVE = (feeTokenBalance * WAD) /
828: totalLockedTokens;
829:
830: ICVELocker locker = ICVELocker(centralRegistry.cveLocker());
831:
832:
833:
834: if (locker.isShutdown() == 2) {
835: SafeTransferLib.safeTransfer(
836: feeToken,
837: centralRegistry.daoAddress(),
838: feeTokenBalanceForChain
839: );
840: return epochRewardsPerCVE;
841: }
842:
843:
844: SafeTransferLib.safeTransfer(
845: feeToken,
846: address(locker),
847: feeTokenBalanceForChain
848: );
849: ICVELocker(locker).recordEpochRewards(epochRewardsPerCVE);
850:
851: return epochRewardsPerCVE;
852: }
In Solidity, if two array parameters are used within a function and one of their lengths is used as the for-loop range, it's essential to have a length check. If the arrays are not the same length, you could experience out-of-bounds errors or unintended behavior. This could happen if the function tries to access an index that doesn't exist in the shorter array.
Resolution: Always validate that the lengths of both arrays are the same before entering the loop. Add a require statement at the start of the function to check that both arrays are of equal length. This helps maintain the integrity of the function and prevents potential errors due to differing array lengths. This requirement ensures the function fails early if the arrays don't match, rather than failing unpredictably or silently during execution.
Num of instances: 4
Click to show findings
['454']
454: function registerWormholeChainIDs(
455: uint256[] calldata chainIds,
456: uint16[] calldata wormholeChainIds
457: ) external {
458: _checkElevatedPermissions();
459:
460: uint256 numChainIds = chainIds.length;
461: for (uint256 i; i < numChainIds; ++i) { // <= FOUND
462: wormholeChainId[chainIds[i]] = wormholeChainIds[i];
463: }
464: emit WormholeChainIDsSet(chainIds, wormholeChainIds);
465: }
['472']
472: function registerCCTPDomains(
473: uint256[] calldata chainIds,
474: uint32[] calldata cctpDomains
475: ) external {
476: _checkElevatedPermissions();
477:
478: uint256 numChainIds = chainIds.length;
479:
480: for (uint256 i; i < numChainIds; ++i) { // <= FOUND
481: cctpDomain[chainIds[i]] = cctpDomains[i];
482: }
483: emit CCTPDomainsSet(chainIds, cctpDomains);
484: }
['78']
78: function setEmissionRates(
79: uint256 epoch,
80: address[] calldata tokens,
81: uint256[] calldata poolWeights
82: ) external override {
83: if (msg.sender != centralRegistry.protocolMessagingHub()) {
84: revert GaugeErrors.Unauthorized();
85: }
86:
87:
88:
89: if (
90: !(epoch == 0 && (startTime == 0 || block.timestamp < startTime)) &&
91: epoch != currentEpoch() + 1
92: ) {
93: revert GaugeErrors.InvalidEpoch();
94: }
95:
96: uint256 numTokens = tokens.length;
97:
98:
99: if (numTokens != poolWeights.length) {
100: revert GaugeErrors.InvalidLength();
101: }
102:
103: Epoch storage info = _epochInfo[epoch];
104: address priorAddress;
105: for (uint256 i; i < numTokens; ) { // <= FOUND
106:
107:
108: if (priorAddress > tokens[i]) {
109: revert GaugeErrors.InvalidToken();
110: }
111:
112: info.totalWeights =
113: info.totalWeights +
114: poolWeights[i] -
115: info.poolWeights[tokens[i]];
116: info.poolWeights[tokens[i]] = poolWeights[i];
117: unchecked {
118:
119: priorAddress = tokens[i++];
120: }
121: }
122: }
['1086']
1086: function setCTokenCollateralCaps(
1087: address[] calldata mTokens,
1088: uint256[] calldata newCollateralCaps
1089: ) external {
1090: if (!centralRegistry.hasDaoPermissions(msg.sender)) {
1091: _revert(_UNAUTHORIZED_SELECTOR);
1092: }
1093:
1094: uint256 numTokens = mTokens.length;
1095:
1096: assembly {
1097: if iszero(numTokens) {
1098:
1099: mstore(0x0, _INVALID_PARAMETER_SELECTOR)
1100:
1101: revert(0x1c, 0x04)
1102: }
1103: }
1104:
1105: if (numTokens != newCollateralCaps.length) {
1106: _revert(_INVALID_PARAMETER_SELECTOR);
1107: }
1108:
1109: for (uint256 i; i < numTokens; ++i) { // <= FOUND
1110:
1111: if (!IMToken(mTokens[i]).isCToken()) {
1112: _revert(_INVALID_PARAMETER_SELECTOR);
1113: }
1114:
1115:
1116:
1117: if (tokenData[mTokens[i]].collRatio == 0) {
1118: _revert(_INVALID_PARAMETER_SELECTOR);
1119: }
1120:
1121: collateralCaps[mTokens[i]] = newCollateralCaps[i];
1122: emit NewCollateralCap(mTokens[i], newCollateralCaps[i]);
1123: }
1124: }
Num of instances: 1
Click to show findings
['97']
97: function start(
98: uint256 startTimestamp,
99: uint256 softPriceInUSD,
100: uint256 cveAmountInLBP,
101: address paymentTokenAddress
102: ) external {
103: if (!centralRegistry.hasDaoPermissions(msg.sender)) {
104: revert CurvanceDAOLBP__Unauthorized();
105: }
106:
107: if (startTime != 0) {
108: revert CurvanceDAOLBP__AlreadyStarted();
109: }
110:
111: if (startTimestamp < block.timestamp) {
112: revert CurvanceDAOLBP__InvalidStartTime();
113: }
114:
115: uint256 errorCode;
116: (paymentTokenPrice, errorCode) = IOracleRouter(centralRegistry.oracleRouter())
117: .getPrice(paymentTokenAddress, true, true);
118:
119:
120:
121: if (errorCode == 2) {
122: revert CurvanceDAOLBP__InvalidPriceSource();
123: }
124:
125: startTime = startTimestamp;
126: softPriceInpaymentToken = (softPriceInUSD * WAD) / paymentTokenPrice;
127: cveAmountForSale = cveAmountInLBP;
128: paymentToken = paymentTokenAddress; // <= FOUND
129: paymentTokenDecimals = IERC20(paymentTokenAddress).decimals();
130:
131: emit LBPStarted(startTimestamp);
132: }
In programming, especially when dealing with dynamically sized types like bytes and strings in Solidity, omitting a check for empty values when assigning to a state variable can lead to unexpected behavior or vulnerabilities. This oversight may allow zero-length or null values to be stored, which could be problematic in contexts where valid data is expected. Implementing explicit checks for empty bytes or strings before assignment ensures data integrity and can prevent potential logic errors or exploits in smart contracts. It's a crucial practice in robust smart contract development to validate data thoroughly before state modifications.
Num of instances: 1
Click to show findings
['247']
234: function setMerkleRoot(bytes32 newRoot) external {
235: _checkDaoPermissions();
236:
237: if (newRoot == bytes32(0)) {
238: revert CVEInitialDistribution__ParametersAreInvalid();
239: }
240:
241: if (merkleRoot == bytes32(0)) {
242: if (!centralRegistry.hasElevatedPermissions(msg.sender)) {
243: revert CVEInitialDistribution__Unauthorized();
244: }
245: }
246:
247: merkleRoot = newRoot; // <= FOUND
248: }
Within unchecked blocks in Solidity, arithmetic operations bypass overflow and underflow checks. When subtractions occur without proper bounds validation, they may underflow. An underflow in an unsigned integer subtraction can wrap the value around to its maximum, leading to unintended contract behavior or potential vulnerabilities. To prevent such scenarios, developers should either avoid unchecked blocks for subtraction operations or manually implement checks to ensure operands' validity before subtraction.
Num of instances: 2
Click to show findings
['86']
86: unchecked {
87: gasSpent = gasStart - gasleft(); // <= FOUND
88: }
['1212']
1212: unchecked {
1213: totalSupply = totalSupply - tokens; // <= FOUND
1214: }
Comparing a value using >= MAX_VALUE
is conceptually incorrect when MAX_VALUE
is defined as the upper limit that a variable can take. According to the definition of a maximum value, the condition should only revert if the variable is greater than MAX_VALUE
, not equal to it. Using >=
can introduce unintended behavior, as the condition will trigger a revert even when the variable reaches its legitimate upper bound. This can lead to bugs and vulnerabilities, as well as hamper the contract's intended functionality. The resolution is to strictly use >
when making comparisons against a defined MAX_VALUE
to align with its conceptual definition and to prevent unintended reverts or vulnerabilities.
Num of instances: 2
Click to show findings
['308']
308:
309:
310:
311:
312: if (maxCautionDivergence >= maxBadSourceDivergence) { // <= FOUND
['308']
308: if (maxCautionDivergence >= maxBadSourceDivergence) { // <= FOUND
309: _revert(_INVALID_PARAMETER_SELECTOR); // <= FOUND
310: }
[Low-8] Getting a bool return value does not confirm the existence of a function in an external call
External calls to contracts using address.call()
might return a boolean indicating success or failure. However, this boolean doesn't guarantee the existence of a called function. If a function isn't present, the call won't revert but will simply return false
. This behavior might lead developers into mistakenly believing they're interacting with a legitimate or expected function, whereas it might not exist at all—a scenario sometimes termed as "phantom functions". Resolution: Instead of solely relying on the boolean, further validate the contract you're interacting with, or use interfaces or abstract contracts to enforce the existence of expected functions.
Num of instances: 2
Click to show findings
['50']
50: function swap(
51: ICentralRegistry centralRegistry,
52: Swap memory swapData
53: ) internal returns (uint256) {
54: address callDataChecker = centralRegistry.externalCallDataChecker(
55: swapData.target
56: );
57:
58:
59: if (callDataChecker == address(0)) {
60: revert SwapperLib__UnknownCalldata();
61: }
62:
63:
64: IExternalCallDataChecker(callDataChecker).checkCallData(
65: swapData,
66: address(this)
67: );
68:
69:
70: _approveTokenIfNeeded(
71: swapData.inputToken,
72: swapData.target,
73: swapData.inputAmount
74: );
75:
76:
77: address outputToken = swapData.outputToken;
78: uint256 balance = CommonLib.getTokenBalance(outputToken);
79:
80: uint256 value = CommonLib.isETH(swapData.inputToken)
81: ? swapData.inputAmount
82: : 0;
83:
84:
85: (bool success, bytes memory auxData) = swapData.target.call{
86: value: value
87: }(swapData.call);
88:
89: propagateError(success, auxData, "SwapperLib: swap");
90:
91:
92: if (!success) {
93: revert SwapperLib__SwapError();
94: }
95:
96:
97: _removeApprovalIfNeeded(swapData.inputToken, swapData.target);
98:
99: return CommonLib.getTokenBalance(outputToken) - balance;
100: }
['111']
111: function zap(ZapperCall memory zapperCall) internal { // <= FOUND
112:
113: _approveTokenIfNeeded(
114: zapperCall.inputToken,
115: zapperCall.target,
116: zapperCall.inputAmount
117: );
118:
119:
120: uint256 value = 0;
121: if (CommonLib.isETH(zapperCall.inputToken)) {
122: value = zapperCall.inputAmount;
123: }
124:
125:
126: (bool success, bytes memory auxData) = zapperCall.target.call{
127: value: value
128: }(zapperCall.call);
129:
130:
131: _removeApprovalIfNeeded(zapperCall.inputToken, zapperCall.target);
132:
133: SwapperLib.propagateError(success, auxData, "SwapperLib: zapper");
134: }
In Solidity versions 0.8.13 and 0.8.14, a known optimizer bug presents potential risks when a variable is used in a separate assembly block from the one in which it was stored. Specifically, the 'mstore' operation could be optimized out due to this bug, leading to the use of uninitialized memory. Although the current code does not exhibit this risky pattern of execution, it does utilize 'mstore' within assembly blocks, which introduces a vulnerability risk for future code modifications. As a preventative measure, it is advisable to avoid the usage of the afflicted Solidity versions, 0.8.13 and 0.8.14. Instead, consider utilizing a version that is not impacted by this optimizer bug to prevent potential memory initialization issues in your smart contract.
Num of instances: 13
Click to show findings
['312']
312: assembly { // <= FOUND
313:
314: mstore(0x00, assets)
315: mstore(0x20, shares)
316: let m := shr(96, not(0))
317: log3(0x00, 0x40, _DEPOSIT_EVENT_SIGNATURE, and(m, by), and(m, to))
318: }
['128']
128: assembly { // <= FOUND
129:
130: mstore(0x00, 0x313ce567)
131:
132: success :=
133: and(
134:
135: and(lt(mload(0x00), 0x100), gt(returndatasize(), 0x1f)),
136:
137: staticcall(gas(), underlying, 0x1c, 0x04, 0x00, 0x20)
138: )
139: result := mul(mload(0x00), success)
140: }
['301']
301: assembly { // <= FOUND
302: result := or(iszero(a), iszero(b))
303: }
['312']
312: assembly { // <= FOUND
313:
314: mstore(0x00, assets)
315: mstore(0x20, shares)
316: let m := shr(96, not(0))
317: log3(0x00, 0x40, _DEPOSIT_EVENT_SIGNATURE, and(m, by), and(m, to))
318: }
['481']
481: assembly { // <= FOUND
482:
483: mstore(0x00, assets)
484: mstore(0x20, shares)
485: let m := shr(96, not(0))
486: log4(0x00, 0x40, _WITHDRAW_EVENT_SIGNATURE, and(m, by), and(m, to), and(m, owner))
487: }
['29']
29: assembly { // <= FOUND
30: for {} 1 {} {
31:
32:
33:
34:
35:
36:
37:
38: result := mul(x, y)
39: let mm := mulmod(x, y, not(0))
40:
41: let p1 := sub(mm, add(result, lt(mm, result)))
42:
43:
44: if iszero(p1) {
45: if iszero(d) {
46: mstore(0x00, 0xae47f702)
47: revert(0x1c, 0x04)
48: }
49: result := div(result, d)
50: break
51: }
52:
53:
54: if iszero(gt(d, p1)) {
55: mstore(0x00, 0xae47f702)
56: revert(0x1c, 0x04)
57: }
58:
59:
60:
61:
62:
63: let r := mulmod(x, y, d)
64:
65:
66: let t := and(d, sub(0, d))
67:
68: d := div(d, t)
69:
70:
71:
72:
73:
74: let inv := xor(2, mul(3, d))
75:
76:
77:
78: inv := mul(inv, sub(2, mul(d, inv)))
['107']
107: assembly { // <= FOUND
108: if mulmod(x, y, d) {
109: result := add(result, 1)
110: if iszero(result) {
111: mstore(0x00, 0xae47f702)
112: revert(0x1c, 0x04)
113: }
114: }
115: }
['122']
122: assembly { // <= FOUND
123:
124: if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
125: mstore(0x00, 0xad251c27)
126: revert(0x1c, 0x04)
127: }
128: z := div(mul(x, y), d)
129: }
['136']
136: assembly { // <= FOUND
137:
138: if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
139: mstore(0x00, 0xad251c27)
140: revert(0x1c, 0x04)
141: }
142: z := add(iszero(iszero(mod(mul(x, y), d))), div(mul(x, y), d))
143: }
['149']
149: assembly { // <= FOUND
150:
151: z := 181
152:
153:
154:
155:
156:
157:
158: let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x))
159: r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x))))
160: r := or(r, shl(5, lt(0xffffffffff, shr(r, x))))
161: r := or(r, shl(4, lt(0xffffff, shr(r, x))))
162: z := shl(shr(1, r), z)
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182: z := shr(18, mul(z, add(shr(r, x), 65536)))
183:
184:
185: z := shr(1, add(z, div(x, z)))
186: z := shr(1, add(z, div(x, z)))
187: z := shr(1, add(z, div(x, z)))
188: z := shr(1, add(z, div(x, z)))
189: z := shr(1, add(z, div(x, z)))
190: z := shr(1, add(z, div(x, z)))
191: z := shr(1, add(z, div(x, z)))
192:
193:
194:
195:
196: z := sub(z, lt(div(x, z), z))
197: }
['30']
30: assembly { // <= FOUND
31: if eq(sload(_REENTRANCY_GUARD_SLOT), 2) {
32: mstore(0x00, 0xab143c06)
33: revert(0x1c, 0x04)
34: }
35: sstore(_REENTRANCY_GUARD_SLOT, 2)
36: }
['39']
39: assembly { // <= FOUND
40: sstore(_REENTRANCY_GUARD_SLOT, 1)
41: }
['30']
30: assembly { // <= FOUND
31: if eq(sload(_REENTRANCY_GUARD_SLOT), 2) {
32: mstore(0x00, 0xab143c06)
33: revert(0x1c, 0x04)
34: }
35: }
Having a mint function without proper access control in a smart contract is a critical vulnerability. It allows anyone to issue new tokens at will, potentially leading to unlimited inflation, devaluation of the token, and erosion of trust in the project. Proper access control mechanisms, such as specifying roles with the OpenZeppelin Ownable
or AccessControl
contracts, ensure that only authorized addresses can execute sensitive functions like minting. Implementing rigorous access control is fundamental to maintaining the integrity, security, and economic stability of token ecosystems, preventing unauthorized token creation and protecting against malicious actors.
Num of instances: 3
Click to show findings
['371']
371: function mint( // <= FOUND
372: uint256 shares,
373: address receiver
374: ) public override nonReentrant returns (uint256 assets) {
375: assets = _mint(shares, receiver); // <= FOUND
376: }
['569']
569: function mint(uint256 amount) external nonReentrant returns (bool) { // <= FOUND
570: _mint(msg.sender, msg.sender, amount); // <= FOUND
571: return true;
572: }
['393']
393: function mint(uint256 shares, address to) public virtual returns (uint256 assets) { // <= FOUND
394: if (shares > maxMint(to)) _revert(0x6a695959);
395: assets = previewMint(shares);
396: _deposit(msg.sender, to, assets, shares);
397: }
Num of instances: 2
Click to show findings
['385']
385: function withdraw( // <= FOUND
386: uint256 assets,
387: address receiver,
388: address owner
389: ) public override nonReentrant returns (uint256 shares)
['401']
401: function withdraw( // <= FOUND
402: address token,
403: address user,
404: uint256 amount
405: ) external nonReentrant
Chainlink's latestRoundData
function returns the latest price information from a specific oracle feed. However, not validating these prices could be dangerous, particularly if they're used in further arithmetic operations. If the price is 0 or negative, and it's involved in calculations with unsigned integers (uint), it can cause underflows. Underflows with uint can cause the value to wrap around to a very large number (due to uint's inability to represent negative numbers), resulting in unexpected and potentially catastrophic outcomes in the contract logic. To avoid this, always validate oracle prices to ensure they are positive, non-zero, and within expected bounds before using them in any arithmetic operations.
Num of instances: 1
Click to show findings
['823']
823: function _isSequencerValid() internal view returns (bool) {
824: address sequencer = centralRegistry.sequencer();
825:
826: if (sequencer != address(0)) {
827: (, int256 answer, uint256 startedAt, , ) = IChainlink(sequencer)
828: .latestRoundData();
829:
830:
831:
832:
833: if (
834: answer != 0 || block.timestamp < startedAt + GRACE_PERIOD_TIME
835: ) {
836: return false;
837: }
838: }
839:
840: return true;
841: }
The ERC-20 token standard does not dictate that the approve function must return a value. The function signature in the ERC-20 standard is function approve(address spender, uint tokens) public returns (bool success);. However, a well-implemented ERC-20 token contract will typically have approve return a boolean value indicating whether or not the operation was successful.
It's crucial to note that not all token contracts follow this practice. Some might not return a value, or they might return a value in a non-standard way. This inconsistency among token contracts is one reason why it's important to handle token interactions carefully in your smart contracts and to check the return value of approve when possible.
Num of instances: 2
Click to show findings
['592']
592:
593: IERC20(cve).approve(address(veCVE), lockAmount); // <= FOUND
['267']
267: cve.approve(veCVE, amount); // <= FOUND
In Solidity, functions that receive Ether without corresponding functionality to utilize or withdraw these funds can inadvertently lead to a permanent loss of value. This is because if someone sends Ether to the contract, they may be unable to retrieve it. To avoid this, functions receiving Ether should be accompanied by additional methods that process or allow the withdrawal of these funds. If the intent is to use the received Ether, it should trigger a separate function; if not, it should revert the transaction (for instance, via require(msg.sender == address(weth))
). Access control checks can also prevent unintended Ether transfers, despite the slight gas cost they entail. If concerns over gas costs persist, at minimum, include a rescue function to recover unused Ether. Missteps in handling Ether in smart contracts can lead to irreversible financial losses, hence these precautions are crucial.
Num of instances: 4
Click to show findings
['71']
71: receive() external payable {}
['71']
71: receive() external payable {}
['71']
71: receive() external payable {}
['71']
71: receive() external payable {}
When you use abi.encodeWithSignature
in Solidity, you're creating an ABI-encoded string representing a function call. This method relies on you, the programmer, correctly typing the function signature (i.e., the function name and types of arguments) as a string.
For instance, if you want to call a function foo(uint256, address)
, you'd write abi.encodeWithSignature("foo(uint256,address)", arg1, arg2)
. If there's a typographical error like abi.encodeWithSignature("foo(uinnt256,address)", arg1, arg2)
, the Solidity compiler will not raise an error because the string is syntactically correct. However, this will fail at runtime because there's no function with that incorrect signature.
This makes abi.encodeWithSignature
less safe than directly calling the function or using interfaces to call functions on other contracts. An effective resolution would be using a Solidity interface. An interface provides compile-time type checking, ensuring that you're calling existing functions with the correct parameters.
Num of instances: 1
Click to show findings
['81']
71:
72:
73:
74:
75:
76:
77:
78:
79:
80: bytes32 REENTRANCY_ERROR_HASH = keccak256(
81: abi.encodeWithSignature("Error(string)", "BAL#400") // <= FOUND
82: );
In Solidity, abi.encodeWithSelector
is a function used for encoding data along with a function selector, but it is not type-safe. This means it does not enforce type checking at compile time, potentially leading to errors if arguments do not match the expected types. Starting from version 0.8.13, Solidity introduced abi.encodeCall
, which offers a safer alternative. abi.encodeCall
ensures type safety by performing a full type check, aligning the types of the arguments with the function signature. This reduces the risk of bugs caused by typographical errors or mismatched types. Using abi.encodeCall
enhances the reliability and security of the code by ensuring that the encoded data strictly conforms to the specified types, making it a preferable choice in Solidity versions 0.8.13 and above.
Num of instances: 2
Click to show findings
['80']
61: function _ensureNotInVaultContext(IVault vault) internal view {
62:
63:
64:
65:
66:
67:
68:
69:
70:
71: bytes32 REENTRANCY_ERROR_HASH = keccak256(
72: abi.encodeWithSignature("Error(string)", "BAL#400")
73: );
74:
75:
76:
77:
78:
79: (, bytes memory revertData) = address(vault).staticcall{ gas: GAS_LIMIT }(
80: abi.encodeWithSelector( // <= FOUND
81: vault.manageUserBalance.selector,
82: new address[](0)
83: )
84: );
85:
86: if (keccak256(revertData) == REENTRANCY_ERROR_HASH) {
87: revert BalancerBaseAdaptor__Reentrancy();
88: }
89: }
['154']
110: function harvest(
111: bytes calldata
112: ) external override returns (uint256 yield) {
113:
114: _canCompound();
115:
116:
117: _vestIfNeeded();
118:
119:
120: if (_checkVestStatus(_vaultData)) {
121: _updateVestingPeriodIfNeeded();
122:
123:
124: uint256[] memory rewardAmounts = _claimReward();
125:
126:
127:
128: address feeAccumulator = centralRegistry.feeAccumulator();
129: uint256 harvestFee = centralRegistry.protocolHarvestFee();
130:
131: for (uint256 i; i < 2; ++i) {
132:
133:
134: if (rewardAmounts[i] > 0) {
135:
136:
137: uint256 protocolFee = FixedPointMathLib.mulDiv(
138: rewardAmounts[i],
139: harvestFee,
140: 1e18
141: );
142: rewardAmounts[i] -= protocolFee;
143: SafeTransferLib.safeTransfer(
144: underlyingTokens[i],
145: feeAccumulator,
146: protocolFee
147: );
148: }
149: }
150:
151:
152: bytes[] memory data = new bytes[](4);
153:
154: data[0] = abi.encodeWithSelector( // <= FOUND
155: IGMXExchangeRouter.sendWnt.selector,
156: gmxDepositVault,
157: 0.01e18
158: );
159:
160: uint256 rewardAmount;
161: for (uint256 i = 0; i < 2; ) {
162: rewardAmount = rewardAmounts[i];
163: SafeTransferLib.safeApprove(
164: underlyingTokens[i],
165: gmxRouter,
166: rewardAmount
167: );
168: data[++i] = abi.encodeWithSelector( // <= FOUND
169: IGMXExchangeRouter.sendTokens.selector,
170: underlyingTokens[i],
171: gmxDepositVault,
172: rewardAmount
173: );
174: }
175: data[3] = abi.encodeWithSelector( // <= FOUND
176: IGMXExchangeRouter.createDeposit.selector,
177: IGMXExchangeRouter.CreateDepositParams(
178: address(this),
179: address(this),
180: address(0),
181: asset(),
182: underlyingTokens[0],
183: underlyingTokens[1],
184: new address[](0),
185: new address[](0),
186: 0,
187: false,
188: 0.01e18,
189: 500000
190: )
191: );
192:
193: bytes[] memory results = IGMXExchangeRouter(gmxExchangeRouter)
194: .multicall{ value: 0.01e18 }(data);
195: _isDepositKey[bytes32(results[3])] = true;
196:
197: yield = 1;
198: }
199: }
Avoid minting tokens to a single address on deployment, rather have them distributed as intended within the constructor (i.e liquidity pools)
Num of instances: 2
Click to show findings
['92']
57: constructor(ICentralRegistry centralRegistry_, address builder_) {
58: if (
59: !ERC165Checker.supportsInterface(
60: address(centralRegistry_),
61: type(ICentralRegistry).interfaceId
62: )
63: ) {
64: revert CVE__ParametersAreInvalid();
65: }
66:
67: if (builder_ == address(0)) {
68: builder_ = msg.sender;
69: }
70:
71: centralRegistry = centralRegistry_;
72: tokenGenerationEventTimestamp = block.timestamp;
73: builderAddress = builder_;
74:
75:
76:
77:
78: daoTreasuryAllocation = 60900010e18;
79:
80: initialCommunityAllocation = 1575000259e16;
81:
82: builderAllocation = 44100007245e15;
83:
84: builderAllocationPerMonth = builderAllocation / 48;
85:
86:
87:
88:
89:
90: uint256 initialTokenMint = 50400008285e15;
91:
92: _mint(msg.sender, initialTokenMint); // <= FOUND
93: }
['83']
56: constructor(ICentralRegistry centralRegistry_, address paymentToken_) {
57: _name = "CVE Options";
58: _symbol = "oCVE";
59:
60: if (
61: !ERC165Checker.supportsInterface(
62: address(centralRegistry_),
63: type(ICentralRegistry).interfaceId
64: )
65: ) {
66: revert OCVE__ParametersAreInvalid();
67: }
68:
69: if (paymentToken_ == address(0)) {
70: revert OCVE__ParametersAreInvalid();
71: }
72:
73: centralRegistry = centralRegistry_;
74: paymentToken = paymentToken_;
75: if (paymentToken_ == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {
76: paymentTokenDecimals = 18;
77: } else {
78: paymentTokenDecimals = ERC20(paymentToken_).decimals();
79: }
80: cve = centralRegistry.cve();
81:
82:
83: _mint(msg.sender, 15750002.59 ether); // <= FOUND
84: }
Downcasting int/uints in Solidity can be unsafe due to the potential for data loss and unintended behavior. When downcasting a larger integer type to a smaller one (e.g., uint256 to uint128), the value may exceed the range of the target type, leading to truncation and loss of significant digits. This data loss can result in unexpected state changes, incorrect calculations, or other contract vulnerabilities, ultimately compromising the contracts functionality and reliability. To prevent these risks, developers should carefully consider the range of values their variables may hold and ensure that proper checks are in place to prevent out-of-range values before performing downcasting. Also consider using OZ SafeCast functionality.
Num of instances: 32
Click to show findings
['142']
123: function _transferFeeTokenViaCCTP(
124: ITokenMessenger circleTokenMessenger,
125: uint256 dstChainId,
126: address to,
127: uint256 amount,
128: uint256 wormholeFee
129: ) internal {
130: IWormholeRelayer wormholeRelayer = centralRegistry.wormholeRelayer();
131: uint16 wormholeChainId = centralRegistry.wormholeChainId(dstChainId);
132:
133: SwapperLib._approveTokenIfNeeded(
134: feeToken,
135: address(circleTokenMessenger),
136: amount
137: );
138:
139: uint64 nonce = circleTokenMessenger.depositForBurnWithCaller(
140: amount,
141: centralRegistry.cctpDomain(dstChainId),
142: bytes32(uint256(uint160(to))), // <= FOUND
143: feeToken,
144: bytes32(uint256(uint160(to))) // <= FOUND
145: );
146:
147: IWormholeRelayer.MessageKey[]
148: memory messageKeys = new IWormholeRelayer.MessageKey[](1);
149: messageKeys[0] = IWormholeRelayer.MessageKey(
150: 2,
151: abi.encodePacked(centralRegistry.cctpDomain(block.chainid), nonce)
152: );
153:
154: address defaultDeliveryProvider = wormholeRelayer
155: .getDefaultDeliveryProvider();
156:
157: wormholeRelayer.sendToEvm{ value: wormholeFee }(
158: wormholeChainId,
159: to,
160: abi.encode(uint8(1), feeToken, amount), // <= FOUND
161: 0,
162: 0,
163: _GAS_LIMIT,
164: wormholeChainId,
165: address(0),
166: defaultDeliveryProvider,
167: messageKeys,
168: 15
169: );
170: }
['193']
179: function _transferTokenViaWormhole(
180: address token,
181: uint256 dstChainId,
182: address to,
183: uint256 amount,
184: uint256 wormholeFee
185: ) internal returns (uint64) {
186: ITokenBridge tokenBridge = centralRegistry.tokenBridge();
187: uint16 wormholeChainId = centralRegistry.wormholeChainId(dstChainId);
188: IWormhole wormholeCore = centralRegistry.wormholeCore();
189: uint256 messageFee = wormholeCore.messageFee();
190:
191: SwapperLib._approveTokenIfNeeded(token, address(tokenBridge), amount);
192:
193: bytes memory payload = abi.encode(uint8(1), feeToken, amount); // <= FOUND
194:
195: uint64 sequence = tokenBridge.transferTokensWithPayload{
196: value: messageFee
197: }(
198: token,
199: amount,
200: wormholeChainId,
201: bytes32(uint256(uint160(to))), // <= FOUND
202: 0,
203: payload
204: );
205:
206: IWormholeRelayer.VaaKey[]
207: memory vaaKeys = new IWormholeRelayer.VaaKey[](1);
208: vaaKeys[0] = IWormholeRelayer.VaaKey({
209: emitterAddress: bytes32(uint256(uint160(address(tokenBridge)))), // <= FOUND
210: chainId: wormholeCore.chainId(),
211: sequence: sequence
212: });
213:
214: return
215: centralRegistry.wormholeRelayer().sendVaasToEvm{
216: value: wormholeFee - messageFee
217: }(wormholeChainId, to, payload, 0, _GAS_LIMIT, vaaKeys);
218: }
['733']
707: function _validateAndRecordChainData(
708: uint256 value,
709: uint256 chainId,
710: uint256 numChainData,
711: uint256 epoch
712: ) internal {
713: if (numChainData > 0) {
714: for (uint256 i; i < numChainData; ) {
715:
716:
717: if (
718: crossChainLockData[i].epoch < epoch ||
719: crossChainLockData[i].chainId == chainId
720: ) {
721: delete crossChainLockData;
722: break;
723: }
724:
725: unchecked {
726: ++i;
727: }
728: }
729: }
730:
731:
732: crossChainLockData.push() = LockData({
733: lockAmount: uint224(value), // <= FOUND
734: epoch: uint16(epoch), // <= FOUND
735: chainId: uint16(chainId) // <= FOUND
736: });
737: }
['1015']
977: function accrueInterest() public {
978:
979: MarketData memory cachedData = marketData;
980:
981:
982: if (
983: cachedData.lastTimestampUpdated + cachedData.compoundRate >
984: block.timestamp
985: ) {
986: return;
987: }
988:
989:
990: uint256 borrowsPrior = totalBorrows;
991: uint256 reservesPrior = totalReserves;
992: uint256 exchangeRatePrior = cachedData.exchangeRate;
993:
994:
995: uint256 borrowRate = interestRateModel.getBorrowRateWithUpdate(
996: marketUnderlyingHeld(),
997: borrowsPrior,
998: reservesPrior
999: );
1000:
1001:
1002:
1003: uint256 interestCompounds = (block.timestamp -
1004: cachedData.lastTimestampUpdated) / cachedData.compoundRate;
1005:
1006: uint256 interestAccumulated = borrowRate * interestCompounds;
1007: uint256 debtAccumulated = (interestAccumulated * borrowsPrior) / WAD;
1008:
1009:
1010: uint256 totalBorrowsNew = debtAccumulated + borrowsPrior;
1011: uint256 exchangeRateNew = ((interestAccumulated * exchangeRatePrior) /
1012: WAD) + exchangeRatePrior;
1013:
1014:
1015: marketData.lastTimestampUpdated = uint40( // <= FOUND
1016: cachedData.lastTimestampUpdated +
1017: (interestCompounds * cachedData.compoundRate)
1018: );
1019: marketData.exchangeRate = uint216(exchangeRateNew); // <= FOUND
1020: totalBorrows = totalBorrowsNew;
1021:
1022:
1023:
1024: uint256 newReserves = ((interestFactor * debtAccumulated) / WAD);
1025: if (newReserves > 0) {
1026: totalReserves = newReserves + reservesPrior;
1027:
1028:
1029: _gaugePool().deposit(
1030: address(this),
1031: centralRegistry.daoAddress(),
1032: newReserves
1033: );
1034: }
1035:
1036: emit InterestAccrued(
1037: debtAccumulated,
1038: exchangeRateNew,
1039: totalBorrowsNew
1040: );
1041: }
['649']
646: function _unpackedVaultData(
647: uint256 packedVaultData
648: ) internal pure returns (VaultData memory vault) {
649: vault.rewardRate = uint128(packedVaultData); // <= FOUND
650: vault.vestingPeriodEnd = uint64(packedVaultData >> _BITPOS_VEST_END); // <= FOUND
651: vault.lastVestClaim = uint64(packedVaultData >> _BITPOS_LAST_VEST); // <= FOUND
652: }
['404']
401: function currentRatesData() external view returns (uint256, uint256) {
402: uint256 currentRates = _currentRates;
403: return (
404: uint192(currentRates), // <= FOUND
405: uint64(currentRates >> _BITPOS_UPDATE_TIMESTAMP) // <= FOUND
406: );
407: }
['147']
111: function getPrice(
112: address asset,
113: bool inUSD,
114: bool getLower
115: ) external view override returns (PriceReturnData memory pData) {
116: AdaptorData memory data = adaptorData[asset];
117:
118:
119:
120: if (isLocked(data.pool, 2)) {
121: revert Curve2PoolAssetAdaptor__Reentrant();
122: }
123:
124:
125: ICurvePool pool = ICurvePool(data.pool);
126:
127:
128: uint256 virtualPrice = pool.get_virtual_price();
129: _enforceBounds(virtualPrice, data.lowerBound, data.upperBound);
130:
131:
132: IOracleRouter oracleRouter = IOracleRouter(
133: centralRegistry.oracleRouter()
134: );
135: (uint256 basePrice, uint256 errorCode) = oracleRouter.getPrice(
136: data.baseToken,
137: inUSD,
138: getLower
139: );
140: if (errorCode > 0) {
141: pData.hadError = true;
142: return pData;
143: }
144:
145:
146: uint256 sample = pool.balances(
147: uint256(uint128(data.quoteTokenIndex)) // <= FOUND
148: ) / 100;
149:
150: uint256 out = pool.get_dy(
151: data.quoteTokenIndex,
152: data.baseTokenIndex,
153: sample
154: );
155:
156: uint256 price = (out * WAD * (10 ** data.quoteTokenDecimals)) /
157: sample /
158: (10 ** data.baseTokenDecimals);
159:
160: price = (price * basePrice) / WAD;
161:
162: if (_checkOracleOverflow(price)) {
163: pData.hadError = true;
164: return pData;
165: }
166:
167: pData.inUSD = inUSD;
168: pData.price = uint240(price); // <= FOUND
169: }
['206']
177: function addAsset(address asset, AdaptorData memory data) external {
178: _checkElevatedPermissions();
179:
180:
181:
182: if (isLocked(data.pool, 2)) {
183: revert Curve2PoolAssetAdaptor__UnsupportedPool();
184: }
185:
186:
187: if (asset == data.baseToken) {
188: revert Curve2PoolAssetAdaptor__InvalidAsset();
189: }
190:
191: address oracleRouter = centralRegistry.oracleRouter();
192:
193:
194:
195: if (!IOracleRouter(oracleRouter).isSupportedAsset(data.baseToken)) {
196: revert Curve2PoolAssetAdaptor__BaseAssetIsNotSupported();
197: }
198:
199:
200: if (data.lowerBound >= data.upperBound) {
201: revert Curve2PoolAssetAdaptor__InvalidBounds();
202: }
203:
204: ICurvePool pool = ICurvePool(data.pool);
205:
206: if (pool.coins(uint256(uint128(data.quoteTokenIndex))) != asset) { // <= FOUND
207: revert Curve2PoolAssetAdaptor__InvalidAssetIndex();
208: }
209: if (
210: pool.coins(uint256(uint128(data.baseTokenIndex))) != data.baseToken // <= FOUND
211: ) {
212: revert Curve2PoolAssetAdaptor__InvalidAssetIndex();
213: }
214:
215: data.quoteTokenDecimals = ERC20(asset).decimals();
216:
217: if (CommonLib.isETH(data.baseToken)) {
218: data.baseTokenDecimals = 18;
219: } else {
220: data.baseTokenDecimals = ERC20(data.baseToken).decimals();
221: }
222:
223:
224:
225:
226:
227: data.lowerBound = _bpToWad(data.lowerBound);
228: data.upperBound = _bpToWad(data.upperBound);
229:
230:
231: if (_MAX_BOUND_RANGE + data.lowerBound < data.upperBound) {
232: revert Curve2PoolAssetAdaptor__InvalidBounds();
233: }
234:
235:
236: uint256 testVirtualPrice = pool.get_virtual_price();
237:
238:
239: _enforceBounds(testVirtualPrice, data.lowerBound, data.upperBound);
240:
241:
242: adaptorData[asset] = data;
243:
244:
245: bool isUpdate;
246: if (isSupportedAsset[asset]) {
247: isUpdate = true;
248: }
249:
250: isSupportedAsset[asset] = true;
251: emit CurvePoolAssetAdded(asset, data, isUpdate);
252: }
['176']
121: function exitCurve(
122: address lpMinter,
123: address lpToken,
124: address[] calldata tokens,
125: uint256 lpAmount,
126: uint256 singleAssetWithdraw,
127: uint256 singleAssetIndex
128: ) internal {
129:
130: SwapperLib._approveTokenIfNeeded(lpToken, lpMinter, lpAmount);
131:
132: uint256 numTokens = tokens.length;
133: if (singleAssetWithdraw == 0) {
134:
135:
136:
137: if (numTokens > 4 || numTokens < 2) {
138: revert CurveLib__InvalidPoolType();
139: }
140:
141: if (numTokens == 4) {
142: uint256[4] memory fourPoolAmounts;
143: return ICurveSwap(lpMinter).remove_liquidity(
144: lpAmount,
145: fourPoolAmounts
146: );
147: }
148:
149: if (numTokens == 3) {
150: uint256[3] memory threePoolAmounts;
151: return ICurveSwap(lpMinter).remove_liquidity(
152: lpAmount,
153: threePoolAmounts
154: );
155: }
156:
157: uint256[2] memory twoPoolAmounts;
158: return ICurveSwap(lpMinter).remove_liquidity(
159: lpAmount,
160: twoPoolAmounts
161: );
162: }
163:
164:
165: if (singleAssetWithdraw == 1) {
166: return ICurveSwap(lpMinter).remove_liquidity_one_coin(
167: lpAmount,
168: singleAssetIndex,
169: 0
170: );
171: }
172:
173:
174: ICurveSwap(lpMinter).remove_liquidity_one_coin(
175: lpAmount,
176: int128(uint128(singleAssetIndex)), // <= FOUND
177: 0
178: );
179: }
['124']
94: function receiveWormholeMessages(
95: bytes memory payload,
96: bytes[] memory ,
97: bytes32 ,
98: uint16 ,
99: bytes32 deliveryHash
100: ) external payable {
101: if (block.chainid != _POLYGON_CHAIN_ID) {
102: return;
103: }
104:
105: if (isDeliveredMessageHash[deliveryHash]) {
106: revert OneBalanceFeeManager__MessageHashIsAlreadyDelivered(
107: deliveryHash
108: );
109: }
110:
111: isDeliveredMessageHash[deliveryHash] = true;
112:
113: address wormholeRelayer = address(centralRegistry.wormholeRelayer());
114:
115: if (msg.sender != wormholeRelayer) {
116: revert OneBalanceFeeManager__Unauthorized();
117: }
118:
119: uint8 payloadId = abi.decode(payload, (uint8));
120:
121: if (payloadId == 1) {
122: (, bytes32 token) = abi.decode(payload, (uint8, bytes32));
123:
124: if (address(uint160(uint256(token))) == feeToken) { // <= FOUND
125: _depositOneBalanceFee();
126: }
127: }
128: }
['124']
97: function receiveWormholeMessages(
98: bytes memory payload,
99: bytes[] memory ,
100: bytes32 srcAddress,
101: uint16 srcChainId,
102: bytes32 deliveryHash
103: ) external payable {
104: _checkMessagingHubStatus();
105:
106:
107: if (isDeliveredMessageHash[deliveryHash]) {
108: revert ProtocolMessagingHub__MessageHashIsAlreadyDelivered(
109: deliveryHash
110: );
111: }
112:
113: isDeliveredMessageHash[deliveryHash] = true;
114: address wormholeRelayer = address(centralRegistry.wormholeRelayer());
115:
116:
117: if (msg.sender != wormholeRelayer) {
118: _revert(_UNAUTHORIZED_SELECTOR);
119: }
120:
121: uint256 gethChainId = centralRegistry.messagingToGETHChainId(
122: srcChainId
123: );
124: address srcAddr = address(uint160(uint256(srcAddress))); // <= FOUND
125:
126: OmnichainData memory operator = centralRegistry.getOmnichainOperators(
127: srcAddr,
128: gethChainId
129: );
130:
131:
132: if (
133: centralRegistry.supportedChainData(gethChainId).messagingHub !=
134: srcAddr
135: ) {
136: return;
137: }
138:
139:
140: if (operator.isAuthorized < 2) {
141: return;
142: }
143:
144: uint8 payloadId = abi.decode(payload, (uint8));
145:
146:
147:
148: if (payloadId == 1) {
149: (, address token, uint256 amount) = abi.decode(
150: payload,
151: (uint8, address, uint256)
152: );
153:
154: address feeToken = centralRegistry.feeToken();
155:
156:
157:
158:
159: if (token == feeToken) {
160: ICVELocker locker = ICVELocker(centralRegistry.cveLocker());
161:
162:
163:
164: if (locker.isShutdown() == 2) {
165: SafeTransferLib.safeTransfer(
166: feeToken,
167: centralRegistry.daoAddress(),
168: amount
169: );
170: return;
171: }
172:
173:
['135']
93: function addAsset(
94: address asset,
95: bool inUSD,
96: uint8 decimals
97: ) external {
98: _checkElevatedPermissions();
99:
100: bytes32 symbolHash;
101: if (inUSD) {
102:
103:
104: symbolHash = Bytes32Helper._toBytes32(asset);
105: } else {
106:
107:
108: symbolHash = Bytes32Helper._toBytes32WithETH(asset);
109: }
110:
111: AdaptorData storage data;
112:
113: if (inUSD) {
114: data = adaptorDataUSD[asset];
115: } else {
116: data = adaptorDataNonUSD[asset];
117: }
118:
119:
120:
121: if (decimals == 0) {
122: data.decimals = 8;
123: } else {
124:
125:
126: data.decimals = uint256(decimals);
127: }
128:
129:
130:
131:
132:
133:
134:
135: data.max = uint192(uint256(type(uint192).max) * 9 / 10); // <= FOUND
136: data.symbolHash = symbolHash;
137: data.isConfigured = true;
138:
139:
140: bool isUpdate;
141: if (isSupportedAsset[asset]) {
142: isUpdate = true;
143: }
144:
145: isSupportedAsset[asset] = true;
146: emit RedstoneCoreAssetAdded(asset, data, isUpdate);
147: }
['24']
22: function maxAnswer() external view returns (int192) {
23: uint256 max = uint256(
24: uint192( // <= FOUND
25: IChainlink(
26: IChainlink(underlyingAssetAggregator()).aggregator()
27: ).maxAnswer()
28: )
29: );
30:
31: max = FixedPointMathLib.fullMulDiv(max, getWrappedAssetWeight(), WAD);
32: int256 intMax = _toInt256(max);
33: if (intMax > type(int192).max) {
34: return type(int192).max;
35: }
36: if (intMax < type(int192).min) {
37: return type(int192).min;
38: }
39:
40: return _toInt192(intMax);
41: }
['46']
44: function minAnswer() external view returns (int192) {
45: uint256 min = uint256(
46: uint192( // <= FOUND
47: IChainlink(
48: IChainlink(underlyingAssetAggregator()).aggregator()
49: ).minAnswer()
50: )
51: );
52:
53: min = FixedPointMathLib.fullMulDiv(min, getWrappedAssetWeight(), WAD);
54: int256 intMin = _toInt256(min);
55:
56: if (intMin > type(int192).max) {
57: return type(int192).max;
58: }
59: if (intMin < type(int192).min) {
60: return type(int192).min;
61: }
62:
63: return _toInt192(intMin);
64: }
['134']
113: function addAsset(
114: address asset,
115: address aggregator,
116: uint256 heartbeat,
117: bool inUSD
118: ) external {
119: _checkElevatedPermissions();
120:
121: if (heartbeat != 0) {
122: if (heartbeat > DEFAULT_HEART_BEAT) {
123: revert ChainlinkAdaptor__InvalidHeartbeat();
124: }
125: }
126:
127:
128: IChainlink feedAggregator = IChainlink(
129: IChainlink(aggregator).aggregator()
130: );
131:
132:
133: uint256 maxFromChainlink = uint256(
134: uint192(feedAggregator.maxAnswer()) // <= FOUND
135: );
136: uint256 minFromChainklink = uint256(
137: uint192(feedAggregator.minAnswer()) // <= FOUND
138: );
139:
140:
141:
142:
143: uint256 bufferedMaxPrice = (maxFromChainlink * 9) / 10;
144: uint256 bufferedMinPrice = (minFromChainklink * 11) / 10;
145:
146:
147:
148:
149:
150: if (bufferedMaxPrice > type(uint240).max) {
151: bufferedMaxPrice = type(uint240).max;
152: }
153:
154: if (bufferedMinPrice >= bufferedMaxPrice) {
155: revert ChainlinkAdaptor__InvalidMinMaxConfig();
156: }
157:
158: AdaptorData storage data;
159:
160: if (inUSD) {
161: data = adaptorDataUSD[asset];
162: } else {
163: data = adaptorDataNonUSD[asset];
164: }
165:
166:
167: data.decimals = feedAggregator.decimals();
168: data.max = bufferedMaxPrice;
169: data.min = bufferedMinPrice;
170: data.heartbeat = heartbeat != 0
171: ? heartbeat
172: : DEFAULT_HEART_BEAT;
173: data.aggregator = IChainlink(aggregator);
174: data.isConfigured = true;
175:
176:
177: bool isUpdate;
178: if (isSupportedAsset[asset]) {
179: isUpdate = true;
180: }
181:
182: isSupportedAsset[asset] = true;
183: emit ChainlinkAssetAdded(asset, data, isUpdate);
184: }
['603']
540: function combineAllLocks(
541: bool continuousLock,
542: RewardsData calldata rewardsData,
543: bytes calldata params,
544: uint256 aux
545: ) external nonReentrant {
546: if (isShutdown == 2) {
547: _revert(_VECVE_SHUTDOWN_SELECTOR);
548: }
549:
550:
551: _claimRewards(msg.sender, rewardsData, params, aux);
552:
553:
554:
555: Lock[] storage locks = userLocks[msg.sender];
556: uint256 numLocks = locks.length;
557:
558:
559: if (numLocks < 2) {
560: _revert(_INVALID_LOCK_SELECTOR);
561: }
562:
563: uint256 lockedAmount;
564: Lock storage lock;
565:
566: for (uint256 i; i < numLocks; ) {
567: lock = locks[i];
568:
569: if (lock.unlockTime != CONTINUOUS_LOCK_VALUE) {
570:
571: _reduceTokenUnlocks(
572: msg.sender,
573: currentEpoch(lock.unlockTime),
574: lock.amount
575: );
576: }
577:
578: unchecked {
579:
580:
581: lockedAmount += locks[i++].amount;
582: }
583: }
584:
585:
586: delete userLocks[msg.sender];
587: uint256 veBalanceOf = balanceOf(msg.sender);
588:
589:
590:
591: if (veBalanceOf != lockedAmount) {
592: revert VeCVE__InvariantError();
593: }
594:
595:
596: uint256 currentPoints = userPoints[msg.sender];
597:
598:
599: if (continuousLock) {
600:
601: userLocks[msg.sender].push(
602: Lock({
603: amount: uint216(lockedAmount), // <= FOUND
604: unlockTime: CONTINUOUS_LOCK_VALUE
605: })
606: );
607:
608:
609:
610:
611:
612:
613: veBalanceOf = veBalanceOf * CL_POINT_MULTIPLIER;
614:
615:
616:
617: if (veBalanceOf != currentPoints) {
618: _incrementPoints(msg.sender, veBalanceOf - currentPoints);
619: }
620:
621:
622:
623: return;
624: }
625:
626:
627:
628:
629: userLocks[msg.sender].push(
630: Lock({
631: amount: uint216(lockedAmount), // <= FOUND
632: unlockTime: freshLockTimestamp()
633: })
634: );
635:
636:
637:
638:
639:
640: if (veBalanceOf != currentPoints) {
641:
642:
643: if (veBalanceOf > currentPoints) {
644: _incrementPoints(msg.sender, veBalanceOf - currentPoints);
645: } else {
646:
647:
648:
649: _reducePoints(msg.sender, currentPoints - veBalanceOf);
650: }
651: }
652:
653:
654: _incrementTokenUnlocks(msg.sender, freshLockEpoch(), lockedAmount);
655: }
['1160']
1145: function _lock(
1146: address recipient,
1147: uint256 amount,
1148: bool continuousLock
1149: ) internal {
1150: if (userLocks[recipient].length == 0) {
1151: cveLocker.updateUserClaimIndex(
1152: recipient,
1153: currentEpoch(block.timestamp)
1154: );
1155: }
1156:
1157: if (continuousLock) {
1158: userLocks[recipient].push(
1159: Lock({
1160: amount: uint216(amount), // <= FOUND
1161: unlockTime: CONTINUOUS_LOCK_VALUE
1162: })
1163: );
1164:
1165: _incrementPoints(recipient, _getCLPoints(amount));
1166: } else {
1167: userLocks[recipient].push(
1168: Lock({
1169: amount: uint216(amount), // <= FOUND
1170: unlockTime: freshLockTimestamp()
1171: })
1172: );
1173:
1174: _incrementPoints(recipient, amount);
1175: _incrementTokenUnlocks(recipient, freshLockEpoch(), amount);
1176: }
1177:
1178: _mint(recipient, amount);
1179: }
['1211']
1187: function _increaseAmountAndExtendLockFor(
1188: address recipient,
1189: uint256 amount,
1190: uint256 lockIndex,
1191: bool continuousLock
1192: ) internal {
1193: Lock[] storage user = userLocks[recipient];
1194:
1195:
1196: if (lockIndex >= user.length) {
1197: _revert(_INVALID_LOCK_SELECTOR);
1198: }
1199:
1200: uint40 unlockTimestamp = user[lockIndex].unlockTime;
1201:
1202: if (unlockTimestamp == CONTINUOUS_LOCK_VALUE) {
1203: if (!continuousLock) {
1204: _revert(_INVALID_LOCK_SELECTOR);
1205: }
1206:
1207:
1208: _incrementPoints(recipient, _getCLPoints(amount));
1209:
1210:
1211: user[lockIndex].amount = uint216(user[lockIndex].amount + amount); // <= FOUND
1212: } else {
1213:
1214:
1215: if (unlockTimestamp < block.timestamp) {
1216: _revert(_INVALID_LOCK_SELECTOR);
1217: }
1218:
1219: uint256 previousAmount = user[lockIndex].amount;
1220: uint256 newAmount = previousAmount + amount;
1221: uint256 priorEpoch = currentEpoch(user[lockIndex].unlockTime);
1222:
1223: if (continuousLock) {
1224: user[lockIndex].unlockTime = CONTINUOUS_LOCK_VALUE;
1225:
1226:
1227:
1228: _updateDataToContinuousOn(
1229: recipient,
1230: priorEpoch,
1231: _getCLPoints(newAmount) - previousAmount,
1232: previousAmount
1233: );
1234: } else {
1235: user[lockIndex].unlockTime = freshLockTimestamp();
1236:
1237:
1238:
1239: _updateUnlockDataToExtendedLock(
1240: recipient,
1241: priorEpoch,
1242: freshLockEpoch(),
1243: previousAmount,
1244: newAmount
1245: );
1246:
1247:
1248: _incrementPoints(recipient, amount);
1249: }
1250:
1251: user[lockIndex].amount = uint216(newAmount); // <= FOUND
1252: }
1253:
1254: _mint(recipient, amount);
1255:
1256: emit Locked(recipient, amount);
1257: }
['240']
228: function _parseData(
229: AdaptorData memory data,
230: bool inUSD
231: ) internal view returns (PriceReturnData memory pData) {
232: (int256 price, uint256 updatedAt) = data.proxyFeed.read();
233:
234:
235: if (price <= 0) {
236: pData.hadError = true;
237: return pData;
238: }
239:
240: pData.price = uint240(uint256(price)); // <= FOUND
241: pData.hadError = _verifyData(
242: uint256(price),
243: updatedAt,
244: data.max,
245: data.heartbeat
246: );
247: pData.inUSD = inUSD;
248: }
['140']
72: function getPrice(
73: address asset,
74: bool inUSD,
75: bool getLower
76: ) external view override returns (PriceReturnData memory pData) {
77:
78: if (!isSupportedAsset[asset]) {
79: revert BalancerStablePoolAdaptor__AssetIsNotSupported();
80: }
81:
82:
83: _ensureNotInVaultContext(balancerVault);
84:
85:
86: AdaptorData memory data = adaptorData[asset];
87: IBalancerPool pool = IBalancerPool(asset);
88:
89: pData.inUSD = inUSD;
90: IOracleRouter oracleRouter = IOracleRouter(centralRegistry.oracleRouter());
91:
92:
93: uint256 numUnderlyingOrConstituent = data
94: .underlyingOrConstituent
95: .length;
96: uint256 averagePrice;
97: uint256 numPrices;
98:
99: uint256 price;
100: uint256 errorCode;
101: for (uint256 i; i < numUnderlyingOrConstituent; ++i) {
102:
103: if (address(data.underlyingOrConstituent[i]) == address(0)) {
104: break;
105: }
106:
107: (price, errorCode) = oracleRouter.getPrice(
108: data.underlyingOrConstituent[i],
109: inUSD,
110: getLower
111: );
112:
113:
114: if (errorCode > 0) {
115: pData.hadError = true;
116: return pData;
117: }
118:
119:
120:
121: averagePrice += price;
122: ++numPrices;
123:
124: }
125:
126:
127: if (averagePrice == 0) {
128: pData.hadError = true;
129: return pData;
130: }
131:
132: averagePrice = ((averagePrice / numPrices) * pool.getRate()) / WAD;
133:
134:
135: if (_checkOracleOverflow(averagePrice)) {
136: pData.hadError = true;
137: return pData;
138: }
139:
140: pData.price = uint240(averagePrice); // <= FOUND
141: }
['236']
212: function _parseData(
213: AdaptorData memory data,
214: bool inUSD
215: ) internal view returns (PriceReturnData memory pData) {
216: uint256 price = _extractPrice(data.symbolHash);
217:
218:
219: uint256 quoteDecimals = data.decimals;
220: if (quoteDecimals != 18) {
221:
222:
223: if (quoteDecimals < 18) {
224: price = price * (10 ** (18 - quoteDecimals));
225: } else {
226:
227:
228: price = price / (10 ** (quoteDecimals - 18));
229: }
230: }
231:
232: pData.hadError = _verifyData(price, data.max);
233:
234: if (!pData.hadError) {
235: pData.inUSD = inUSD;
236: pData.price = uint240(price); // <= FOUND
237: }
238: }
['164']
91: function _getPrice(
92: address asset,
93: bool inUSD,
94: bool getLower
95: ) internal view returns (PriceReturnData memory pData) {
96:
97: if (!isSupportedAsset[asset]) {
98: revert BaseStableLPAdaptor__AssetIsNotSupported();
99: }
100:
101:
102: AdaptorData memory data = adaptorData[asset];
103: IUniswapV2Pair pool = IUniswapV2Pair(asset);
104:
105:
106: uint256 totalSupply = pool.totalSupply();
107:
108: (uint256 reserve0, uint256 reserve1, ) = pool.getReserves();
109:
110: if (data.decimals0 != 18) {
111: reserve0 = (reserve0 * 1e18) / (10 ** data.decimals0);
112: }
113:
114: if (data.decimals1 != 18) {
115: reserve1 = (reserve1 * 1e18) / (10 ** data.decimals1);
116: }
117:
118: uint256 price0;
119: uint256 price1;
120: uint256 errorCode;
121:
122: IOracleRouter oracleRouter = IOracleRouter(
123: centralRegistry.oracleRouter()
124: );
125: (price0, errorCode) = oracleRouter.getPrice(
126: data.token0,
127: inUSD,
128: getLower
129: );
130:
131:
132: if (errorCode > 0) {
133: pData.hadError = true;
134: return pData;
135: }
136:
137: (price1, errorCode) = oracleRouter.getPrice(
138: data.token1,
139: inUSD,
140: getLower
141: );
142:
143:
144: if (errorCode > 0) {
145: pData.hadError = true;
146: return pData;
147: }
148:
149: uint256 finalPrice = _getFairPrice(
150: reserve0,
151: reserve1,
152: price0,
153: price1,
154: totalSupply
155: );
156:
157:
158: if (_checkOracleOverflow(finalPrice)) {
159: pData.hadError = true;
160: return pData;
161: }
162:
163: pData.inUSD = inUSD;
164: pData.price = uint240(finalPrice); // <= FOUND
165: }
['159']
91: function _getPrice(
92: address asset,
93: bool inUSD,
94: bool getLower
95: ) internal view returns (PriceReturnData memory pData) {
96:
97: if (!isSupportedAsset[asset]) {
98: revert BaseVolatileLPAdaptor__AssetIsNotSupported();
99: }
100:
101:
102: AdaptorData memory data = adaptorData[asset];
103: IUniswapV2Pair pool = IUniswapV2Pair(asset);
104:
105:
106: uint256 totalSupply = pool.totalSupply();
107:
108: (uint256 reserve0, uint256 reserve1, ) = pool.getReserves();
109:
110: reserve0 = (reserve0 * 1e18) / (10 ** data.decimals0);
111: reserve1 = (reserve1 * 1e18) / (10 ** data.decimals1);
112:
113:
114: uint256 sqrtReserve = FixedPointMathLib.sqrt(reserve0 * reserve1);
115:
116: uint256 price0;
117: uint256 price1;
118: uint256 errorCode;
119:
120: IOracleRouter oracleRouter = IOracleRouter(
121: centralRegistry.oracleRouter()
122: );
123: (price0, errorCode) = oracleRouter.getPrice(
124: data.token0,
125: inUSD,
126: getLower
127: );
128:
129:
130: if (errorCode > 0) {
131: pData.hadError = true;
132: return pData;
133: }
134:
135: (price1, errorCode) = oracleRouter.getPrice(
136: data.token1,
137: inUSD,
138: getLower
139: );
140:
141:
142: if (errorCode > 0) {
143: pData.hadError = true;
144: return pData;
145: }
146:
147:
148: uint256 finalPrice = (2 *
149: sqrtReserve *
150: FixedPointMathLib.sqrt(price0 * price1)) / totalSupply;
151:
152:
153: if (_checkOracleOverflow(finalPrice)) {
154: pData.hadError = true;
155: return pData;
156: }
157:
158: pData.inUSD = inUSD;
159: pData.price = uint240(finalPrice); // <= FOUND
160: }
['270']
249: function _parseData(
250: AdaptorData memory data,
251: bool inUSD
252: ) internal view returns (PriceReturnData memory pData) {
253: pData.inUSD = inUSD;
254: if (!IOracleRouter(centralRegistry.oracleRouter()).isSequencerValid()) {
255: pData.hadError = true;
256: return pData;
257: }
258:
259: (, int256 price, , uint256 updatedAt, ) = IChainlink(data.aggregator)
260: .latestRoundData();
261:
262:
263: if (price <= 0) {
264: pData.hadError = true;
265: return pData;
266: }
267:
268: uint256 newPrice = (uint256(price) * WAD) / (10 ** data.decimals);
269:
270: pData.price = uint240(newPrice); // <= FOUND
271: pData.hadError = _verifyData(
272: uint256(price),
273: updatedAt,
274: data.max,
275: data.min,
276: data.heartbeat
277: );
278: }
['188']
106: function getPrice(
107: address asset,
108: bool inUSD,
109: bool getLower
110: ) external view override returns (PriceReturnData memory pData) {
111: AdaptorData memory data = adaptorData[asset];
112:
113:
114:
115: if (isLocked(data.pool, 2)) {
116: revert Curve2PoolLPAdaptor__Reentrant();
117: }
118:
119:
120: ICurvePool pool = ICurvePool(data.pool);
121:
122:
123: uint256 virtualPrice = pool.get_virtual_price();
124: _enforceBounds(virtualPrice, data.lowerBound, data.upperBound);
125:
126:
127: IOracleRouter oracleRouter = IOracleRouter(
128: centralRegistry.oracleRouter()
129: );
130: uint256 price0;
131: uint256 price1;
132: uint256 errorCode;
133: (price0, errorCode) = oracleRouter.getPrice(
134: data.underlying0,
135: inUSD,
136: getLower
137: );
138: if (errorCode > 0) {
139: pData.hadError = true;
140: return pData;
141: }
142: (price1, errorCode) = oracleRouter.getPrice(
143: data.underlying1,
144: inUSD,
145: getLower
146: );
147: if (errorCode > 0) {
148: pData.hadError = true;
149: return pData;
150: }
151:
152:
153: uint256 price;
154: if (data.isCorrelated) {
155:
156: if (data.divideRate0 || data.divideRate1) {
157: uint256[2] memory rates = pool.stored_rates();
158: if (data.divideRate0) {
159: price0 = (price0 * WAD) / rates[0];
160: }
161: if (data.divideRate1) {
162: price1 = (price1 * WAD) / rates[1];
163: }
164: }
165:
166: if (getLower) {
167:
168: uint256 minPrice = price0 < price1 ? price0 : price1;
169: price = (minPrice * virtualPrice) / WAD;
170: } else {
171:
172: uint256 maxPrice = price0 < price1 ? price1 : price0;
173: price = (maxPrice * virtualPrice) / WAD;
174: }
175: } else {
176: price =
177: (2 * virtualPrice * FixedPointMathLib.sqrt(price0)) /
178: FixedPointMathLib.sqrt(price1);
179: price = (price * price0) / WAD;
180: }
181:
182: if (_checkOracleOverflow(price)) {
183: pData.hadError = true;
184: return pData;
185: }
186:
187: pData.inUSD = inUSD;
188: pData.price = uint240(price); // <= FOUND
189: }
['121']
86: function getPrice(
87: address asset,
88: bool inUSD,
89: bool getLower
90: ) external view override returns (PriceReturnData memory pData) {
91:
92: if (!isSupportedAsset[asset]) {
93: revert PendleLPTokenAdaptor__AssetIsNotSupported();
94: }
95:
96: AdaptorData memory data = adaptorData[asset];
97:
98: uint256 lpRate = IPMarket(asset).getLpToAssetRate(data.twapDuration);
99:
100: (uint256 price, uint256 errorCode) = IOracleRouter(
101: centralRegistry.oracleRouter()
102: ).getPrice(data.quoteAsset, inUSD, getLower);
103:
104:
105: if (errorCode > 0) {
106: pData.hadError = true;
107: return pData;
108: }
109:
110:
111:
112: price = (price * lpRate) / WAD;
113:
114:
115: if (_checkOracleOverflow(price)) {
116: pData.hadError = true;
117: return pData;
118: }
119:
120: pData.inUSD = inUSD;
121: pData.price = uint240(price); // <= FOUND
122: }
['122']
87: function getPrice(
88: address asset,
89: bool inUSD,
90: bool getLower
91: ) external view override returns (PriceReturnData memory pData) {
92:
93: if (!isSupportedAsset[asset]) {
94: revert PendlePrincipalTokenAdaptor__AssetIsNotSupported();
95: }
96:
97: AdaptorData memory data = adaptorData[asset];
98:
99: uint256 ptRate = data.market.getPtToAssetRate(data.twapDuration);
100:
101: (uint256 price, uint256 errorCode) = IOracleRouter(
102: centralRegistry.oracleRouter()
103: ).getPrice(data.quoteAsset, inUSD, getLower);
104:
105:
106: if (errorCode > 0) {
107: pData.hadError = true;
108: return pData;
109: }
110:
111:
112:
113: price = (price * ptRate) / WAD;
114:
115:
116: if (_checkOracleOverflow(price)) {
117: pData.hadError = true;
118: return pData;
119: }
120:
121: pData.inUSD = inUSD;
122: pData.price = uint240(price); // <= FOUND
123: }
['159']
97: function getPrice(
98: address asset,
99: bool ,
100: bool
101: ) external view override returns (PriceReturnData memory pData) {
102:
103: if (!isSupportedAsset[asset]) {
104: revert GMAdaptor__AssetIsNotSupported();
105: }
106:
107:
108: IOracleRouter oracleRouter = IOracleRouter(
109: centralRegistry.oracleRouter()
110: );
111:
112: uint256[] memory prices = new uint256[](3);
113: address[] memory tokens = marketData[asset];
114: uint256 errorCode;
115: address token;
116:
117:
118:
119: for (uint256 i; i < 3; ++i) {
120: token = tokens[i];
121:
122: (prices[i], errorCode) = oracleRouter.getPrice(token, true, false);
123: if (errorCode > 0) {
124: pData.hadError = true;
125: return pData;
126: }
127:
128: prices[i] = (prices[i] * 1e30) / _priceUnit[token];
129: }
130:
131:
132: (int256 price, ) = gmxReader.getMarketTokenPrice(
133: gmxDataStore,
134: IReader.MarketProps(asset, tokens[3], tokens[1], tokens[2]),
135: IReader.PriceProps(prices[0], prices[0]),
136: IReader.PriceProps(prices[1], prices[1]),
137: IReader.PriceProps(prices[2], prices[2]),
138: PNL_FACTOR_TYPE,
139: true
140: );
141:
142:
143:
144: if (price <= 0) {
145: pData.hadError = true;
146: return pData;
147: }
148:
149:
150: uint256 newPrice = uint256(price) / 1e12;
151:
152:
153: if (_checkOracleOverflow(newPrice)) {
154: pData.hadError = true;
155: return pData;
156: }
157:
158: pData.inUSD = true;
159: pData.price = uint240(newPrice); // <= FOUND
160: }
['373']
350: function getPricesForAsset(
351: address asset,
352: bool inUSD
353: ) external view returns (FeedData[] memory) {
354: bool isMToken = mTokenAssets[asset].isMToken;
355: if (isMToken) {
356: asset = mTokenAssets[asset].underlying;
357: }
358:
359: uint256 numFeeds = assetPriceFeeds[asset].length;
360: if (numFeeds == 0) {
361: _revert(_NOT_SUPPORTED_SELECTOR);
362: }
363:
364: FeedData[] memory data = new FeedData[](numFeeds * 2);
365:
366:
367:
368: if (numFeeds < 2) {
369: data[0] = _getPriceFromFeed(asset, 0, inUSD, true);
370: data[1] = _getPriceFromFeed(asset, 0, inUSD, false);
371: if (isMToken) {
372: uint256 exchangeRate = IMToken(asset).exchangeRateCached();
373: data[0].price = uint240((data[0].price * exchangeRate) / WAD); // <= FOUND
374: data[1].price = uint240((data[1].price * exchangeRate) / WAD); // <= FOUND
375: }
376:
377: return data;
378: }
379:
380:
381:
382: data[0] = _getPriceFromFeed(asset, 0, inUSD, true);
383: data[1] = _getPriceFromFeed(asset, 0, inUSD, false);
384: data[2] = _getPriceFromFeed(asset, 1, inUSD, true);
385: data[3] = _getPriceFromFeed(asset, 1, inUSD, false);
386:
387: if (isMToken) {
388: uint256 exchangeRate = IMToken(asset).exchangeRateCached();
389: data[0].price = uint240((data[0].price * exchangeRate) / WAD); // <= FOUND
390: data[1].price = uint240((data[1].price * exchangeRate) / WAD); // <= FOUND
391: data[2].price = uint240((data[2].price * exchangeRate) / WAD); // <= FOUND
392: data[3].price = uint240((data[3].price * exchangeRate) / WAD); // <= FOUND
393: }
394:
395: return data;
396: }
['722']
694: function _getPriceSingleFeed(
695: address asset,
696: bool inUSD,
697: bool getLower
698: ) internal view returns (uint256, uint256) {
699: address adapter = assetPriceFeeds[asset][0];
700: if (!isApprovedAdaptor[adapter]) {
701: revert OracleRouter__AdaptorIsNotApproved();
702: }
703:
704: PriceReturnData memory data = IOracleAdaptor(adapter).getPrice(
705: asset,
706: inUSD,
707: getLower
708: );
709:
710: if (data.hadError) {
711: return (0, BAD_SOURCE);
712: }
713:
714:
715: if (data.inUSD != inUSD) {
716: uint256 newPrice;
717: (newPrice, data.hadError) = _getETHUSD(getLower);
718: if (data.hadError) {
719: return (0, BAD_SOURCE);
720: }
721:
722: data.price = uint240( // <= FOUND
723: _convertETHUSD(data.price, newPrice, data.inUSD)
724: );
725: }
726:
727: return (data.price, NO_ERROR);
728: }
['773']
744: function _getPriceFromFeed(
745: address asset,
746: uint256 feedNumber,
747: bool inUSD,
748: bool getLower
749: ) internal view returns (FeedData memory) {
750: address adapter = assetPriceFeeds[asset][feedNumber];
751: if (!isApprovedAdaptor[adapter]) {
752: revert OracleRouter__AdaptorIsNotApproved();
753: }
754:
755: PriceReturnData memory data = IOracleAdaptor(adapter).getPrice(
756: asset,
757: inUSD,
758: getLower
759: );
760:
761: if (data.hadError) {
762: return FeedData({ price: 0, hadError: true });
763: }
764:
765:
766: if (data.inUSD != inUSD) {
767: uint256 newPrice;
768: (newPrice, data.hadError) = _getETHUSD(getLower);
769: if (data.hadError) {
770: return FeedData({ price: 0, hadError: true });
771: }
772:
773: data.price = uint240( // <= FOUND
774: _convertETHUSD(data.price, newPrice, data.inUSD)
775: );
776: }
777:
778: return FeedData({ price: data.price, hadError: data.hadError });
779: }
['163']
85: function getPrice(
86: address asset,
87: bool inUSD,
88: bool getLower
89: ) external view override returns (PriceReturnData memory pData) {
90:
91: if (!isSupportedAsset[asset]) {
92: revert UniswapV3Adaptor__AssetIsNotSupported();
93: }
94:
95: AdaptorData memory data = adaptorData[asset];
96:
97: address[] memory pools = new address[](1);
98: pools[0] = data.priceSource;
99: uint256 twapPrice;
100:
101:
102: (bool success, bytes memory returnData) = address(uniswapOracleRouter)
103: .staticcall(
104: abi.encodePacked(
105: uniswapOracleRouter
106: .quoteSpecificPoolsWithTimePeriod
107: .selector,
108: abi.encode(
109: 10 ** data.baseDecimals,
110: asset,
111: data.quoteToken,
112: pools,
113: data.secondsAgo
114: )
115: )
116: );
117:
118: if (success) {
119:
120: twapPrice = abi.decode(returnData, (uint256));
121: } else {
122:
123: pData.hadError = true;
124: return pData;
125: }
126:
127: IOracleRouter OracleRouter = IOracleRouter(
128: centralRegistry.oracleRouter()
129: );
130: pData.inUSD = inUSD;
131:
132:
133:
134:
135: if (inUSD) {
136: if (!OracleRouter.isSupportedAsset(data.quoteToken)) {
137:
138:
139: pData.hadError = true;
140: return pData;
141: }
142:
143: (uint256 quoteTokenDenominator, uint256 errorCode) = OracleRouter
144: .getPrice(data.quoteToken, true, getLower);
145:
146:
147: if (errorCode > 0) {
148: pData.hadError = true;
149: return pData;
150: }
151:
152:
153:
154: uint256 newPrice = (twapPrice * quoteTokenDenominator) /
155: (10 ** data.quoteDecimals);
156:
157:
158: if (_checkOracleOverflow(newPrice)) {
159: pData.hadError = true;
160: return pData;
161: }
162:
163: pData.price = uint240(newPrice); // <= FOUND
164: return pData;
165: }
166:
167: if (data.quoteToken != WETH) {
168: if (!OracleRouter.isSupportedAsset(data.quoteToken)) {
169:
170:
171: pData.hadError = true;
172: return pData;
173: }
174:
175: (uint256 quoteTokenDenominator, uint256 errorCode) = OracleRouter
176: .getPrice(data.quoteToken, false, getLower);
177:
178:
179: if (errorCode > 0) {
180: pData.hadError = true;
181: return pData;
182: }
183:
184:
185: uint256 newPrice = (twapPrice * quoteTokenDenominator) /
186: (10 ** data.quoteDecimals);
187:
188:
189: if (_checkOracleOverflow(newPrice)) {
190: pData.hadError = true;
191: return pData;
192: }
193:
194:
195:
196: pData.price = uint240(newPrice); // <= FOUND
197: return pData;
198: }
199:
200:
201: if (_checkOracleOverflow(twapPrice)) {
202: pData.hadError = true;
203: return pData;
204: }
205:
206: pData.price = uint240(twapPrice); // <= FOUND
207: }
In Solidity, the nonReentrant
modifier is essential for securing smart contracts against reentrancy attacks. It should be positioned first in a function declaration. This placement is critical because it ensures that the modifier's protection is applied before any other code or modifiers in the function. If placed later, other modifiers could potentially be executed in a reentrant manner before nonReentrant
has a chance to lock the function, leaving the contract vulnerable. Thus, prioritizing nonReentrant
as the first modifier is a best practice for robust smart contract security, effectively guarding against unintended reentries and related exploits.
Num of instances: 4
Click to show findings
['174']
174: function leverage(
175: LeverageStruct calldata leverageData,
176: uint256 slippage
177: ) external checkSlippage(msg.sender, slippage) nonReentrant { // <= FOUND
178: _leverage(leverageData, msg.sender);
179: }
['194']
194: function leverageFor(
195: LeverageStruct calldata leverageData,
196: address account,
197: uint256 slippage
198: ) external checkSlippage(account, slippage) nonReentrant { // <= FOUND
199: if (!_checkIsDelegate(account, msg.sender)) {
200: _revert(_UNAUTHORIZED_SELECTOR);
201: }
202:
203: _leverage(leverageData, account);
204: }
['217']
217: function deleverage(
218: DeleverageStruct calldata deleverageData,
219: uint256 slippage
220: ) external checkSlippage(msg.sender, slippage) nonReentrant { // <= FOUND
221: _deleverage(deleverageData, msg.sender);
222: }
['234']
234: function deleverageFor(
235: DeleverageStruct calldata deleverageData,
236: address account,
237: uint256 slippage
238: ) external checkSlippage(account, slippage) nonReentrant { // <= FOUND
239: if (!_checkIsDelegate(account, msg.sender)) {
240: _revert(_UNAUTHORIZED_SELECTOR);
241: }
242:
243: _deleverage(deleverageData, account);
244: }
Making function calls or external calls within loops in Solidity can lead to inefficient gas usage, potential bottlenecks, and increased vulnerability to attacks. Each function call or external call consumes gas, and when executed within a loop, the gas cost multiplies, potentially causing the transaction to run out of gas or exceed block gas limits. This can result in transaction failure or unpredictable behavior.
Num of instances: 19
Click to show findings
['147']
147: for (uint256 i; i < extraRewardsLength; ) { // <= FOUND
148: unchecked {
149: address rewardToken = IStashWrapper( // <= FOUND
150: IRewards(rewarder.extraRewards(i++)).rewardToken() // <= FOUND
151: ).baseToken(); // <= FOUND
152:
153: if (rewardToken != _AURA && rewardToken != _BAL) { // <= FOUND
154: strategyData.rewardTokens.push() = rewardToken; // <= FOUND
155: }
156: }
157: }
['40']
40: for (uint256 i; i < numTokens; ++i) { // <= FOUND
41: balances[i] = CommonLib.getTokenBalance(tokens[i]); // <= FOUND
42: SwapperLib._approveTokenIfNeeded( // <= FOUND
43: tokens[i],
44: balancerVault,
45: balances[i]
46: );
47:
48: if (CommonLib.isETH(tokens[i])) { // <= FOUND
49:
50:
51: if (containsEth) { // <= FOUND
52: revert BalancerLib__InvalidPoolInvariantError(); // <= FOUND
53: }
54:
55: value = balances[i];
56: containsEth = true;
57: }
58: }
['162']
162: for (uint256 i; i < numUnderlyingOrConstituent; ++i) { // <= FOUND
163:
164: if (address(data.underlyingOrConstituent[i]) == address(0)) { // <= FOUND
165: continue;
166: }
167:
168: if ( // <= FOUND
169: !IOracleRouter(centralRegistry.oracleRouter()).isSupportedAsset( // <= FOUND
170: data.underlyingOrConstituent[i]
171: )
172: ) {
173: revert BalancerStablePoolAdaptor__ConfigurationError(); // <= FOUND
174: }
175:
176: if (data.rateProviders[i] != address(0)) { // <= FOUND
177:
178: if (data.rateProviderDecimals[i] == 0) { // <= FOUND
179: revert BalancerStablePoolAdaptor__ConfigurationError(); // <= FOUND
180: }
181:
182:
183: if (IRateProvider(data.rateProviders[i]).getRate() == 0) { // <= FOUND
184: revert BalancerStablePoolAdaptor__ConfigurationError(); // <= FOUND
185: }
186: }
187: }
['404']
404: for (uint256 i; i < nonMTokensLength; ++i) { // <= FOUND
405: yieldClaimed += CHAIN_YIELD_MANAGER.claimMaxGas( // <= FOUND
406: nonMTokens[i],
407: address(this) // <= FOUND
408: );
409: }
['470']
470: for (uint256 i; i < epochs; ) { // <= FOUND
471: unchecked {
472: rewards += _calculateRewardsForEpoch(user, startEpoch + i++); // <= FOUND
473: }
474: }
['647']
647: for (uint256 i; i < numTokenSwaps; ) { // <= FOUND
648:
649: if (!centralRegistry.isSwapper(tokenSwaps[i].target)) { // <= FOUND
650: revert ComplexZapper__InvalidSwapper(i, tokenSwaps[i].target); // <= FOUND
651: }
652:
653:
654: unchecked {
655: SwapperLib.swap(centralRegistry, tokenSwaps[i++]); // <= FOUND
656: }
657: }
['297']
297: for (uint256 i; i < 2; ++i) { // <= FOUND
298: underlyingToken = strategyData.underlyingTokens[i];
299: amounts[i] = CommonLib.getTokenBalance(underlyingToken); // <= FOUND
300:
301: if (CommonLib.isETH(underlyingToken)) { // <= FOUND
302: value = amounts[i];
303: }
304:
305: SwapperLib._approveTokenIfNeeded( // <= FOUND
306: underlyingToken,
307: address(strategyData.curvePool), // <= FOUND
308: amounts[i]
309: );
310:
311: if (amounts[i] > 0) { // <= FOUND
312: liquidityAvailable = true;
313: }
314: }
['297']
297: for (uint256 i; i < 3; ++i) { // <= FOUND
298: underlyingToken = strategyData.underlyingTokens[i];
299: amounts[i] = CommonLib.getTokenBalance(underlyingToken); // <= FOUND
300:
301: if (CommonLib.isETH(underlyingToken)) { // <= FOUND
302: value = amounts[i];
303: }
304:
305: SwapperLib._approveTokenIfNeeded( // <= FOUND
306: underlyingToken,
307: address(strategyData.curvePool), // <= FOUND
308: amounts[i]
309: );
310:
311: if (amounts[i] > 0) { // <= FOUND
312: liquidityAvailable = true;
313: }
314: }
['458']
458: for (uint256 i; i < numChainData; ) { // <= FOUND
459: lockData = crossChainLockData[i];
460: chainData = centralRegistry.supportedChainData( // <= FOUND
461: lockData.chainId
462: );
463: messagingChainId = centralRegistry.GETHToMessagingChainId( // <= FOUND
464: uint256(lockData.chainId) // <= FOUND
465: );
466:
467: gas = messagingHub.quoteWormholeFee( // <= FOUND
468: uint256(lockData.chainId), // <= FOUND
469: false
470: );
471:
472: messagingHub.sendWormholeMessages{ value: gas }( // <= FOUND
473: uint256(lockData.chainId), // <= FOUND
474: chainData.messagingHub,
475: abi.encode(epochRewardsPerCVE) // <= FOUND
476: );
477:
478: unchecked {
479: ++i;
480: }
481: }
['648']
648: for (uint256 i; i < numTokens; ) { // <= FOUND
649: tokenBalances[i] = IERC20(currentTokens[i]).balanceOf( // <= FOUND
650: address(this) // <= FOUND
651: );
652:
653: unchecked {
654: ++i;
655: }
656: }
['128']
128: for (uint256 i; i < numTokens; ) { // <= FOUND
129: unchecked {
130:
131: updatePool(tokens[i++]); // <= FOUND
132: }
133: }
['325']
325: for (uint256 i; i < rewardTokensLength; ++i) { // <= FOUND
326: results[i] = pendingRewards(token, user, rewardTokens[i]); // <= FOUND
327: }
['692']
692: for (uint256 i; i < rewardTokensLength; ) { // <= FOUND
693:
694: address rewardToken = rewardTokens[i++];
695: UserRewardInfo storage info = userDebtInfo[token][user][
696: rewardToken
697: ];
698: info.rewardPending +=
699: (balanceOf[token][user] * // <= FOUND
700: poolAccRewardPerShare[token][rewardToken]) /
701: (WAD_SQUARED) - // <= FOUND
702: info.rewardDebt;
703: }
['712']
712: for (uint256 i; i < rewardTokensLength; ) { // <= FOUND
713:
714: address rewardToken = rewardTokens[i++];
715: UserRewardInfo storage info = userDebtInfo[token][user][
716: rewardToken
717: ];
718: info.rewardDebt =
719: (balanceOf[token][user] * // <= FOUND
720: poolAccRewardPerShare[token][rewardToken]) /
721: (WAD_SQUARED); // <= FOUND
722: }
['209']
209: for (uint256 i; i < numAssets; ++i) { // <= FOUND
210: snapshot = snapshots[i];
211:
212: if (snapshot.isCToken) { // <= FOUND
213:
214:
215: if (tokenData[snapshot.asset].collRatio != 0) { // <= FOUND
216: uint256 collateralValue = _assetValue( // <= FOUND
217: ((tokenData[snapshot.asset] // <= FOUND
218: .accountPositions[account]
219: .collateralPosted * snapshot.exchangeRate) / WAD),
220: underlyingPrices[i],
221: snapshot.decimals
222: );
223: accountCollateral += collateralValue;
224: maxDebt =
225: (collateralValue * // <= FOUND
226: tokenData[snapshot.asset].collRatio) /
227: WAD;
228: }
229: } else {
230:
231: if (snapshot.debtBalance > 0) { // <= FOUND
232: accountDebt += _assetValue( // <= FOUND
233: snapshot.debtBalance,
234: underlyingPrices[i],
235: snapshot.decimals
236: );
237: }
238: }
239: }
['425']
425: for (uint256 i; i < numAssets; ++i) { // <= FOUND
426: snapshot = snapshots[i];
427:
428: if (snapshot.isCToken) { // <= FOUND
429:
430:
431: if (tokenData[snapshot.asset].collRatio != 0) { // <= FOUND
432: accountCollateral += _assetValue( // <= FOUND
433: ((tokenData[snapshot.asset] // <= FOUND
434: .accountPositions[account]
435: .collateralPosted * snapshot.exchangeRate) / WAD),
436: underlyingPrices[i],
437: snapshot.decimals
438: );
439: }
440: } else {
441:
442: if (snapshot.debtBalance > 0) { // <= FOUND
443: accountDebt += _assetValue( // <= FOUND
444: snapshot.debtBalance,
445: underlyingPrices[i],
446: snapshot.decimals
447: );
448: }
449: }
450: }
['506']
506: for (uint256 i; i < numAssets; ++i) { // <= FOUND
507: snapshot = snapshots[i];
508:
509: if (snapshot.isCToken) { // <= FOUND
510: if (snapshot.asset == collateralToken) { // <= FOUND
511: result.collateralTokenPrice = underlyingPrices[i];
512: }
513:
514:
515: if (tokenData[snapshot.asset].collRatio != 0) { // <= FOUND
516: ( // <= FOUND
517: accountCollateralSoft,
518: accountCollateralHard
519: ) = _addLiquidationValues( // <= FOUND
520: snapshot,
521: account,
522: underlyingPrices[i],
523: accountCollateralSoft,
524: accountCollateralHard
525: );
526: }
527: } else {
528: if (snapshot.asset == debtToken) { // <= FOUND
529: result.debtTokenPrice = underlyingPrices[i];
530: }
531:
532:
533:
534: if (snapshot.debtBalance > 0) { // <= FOUND
535: accountDebt += _assetValue( // <= FOUND
536: snapshot.debtBalance,
537: underlyingPrices[i],
538: snapshot.decimals
539: );
540: }
541: }
542: }
['1319']
1319: for (uint256 i; i < numUserAssets; ++i) { // <= FOUND
1320: if (userAssetList[i] == mToken) { // <= FOUND
1321: assetIndex = i;
1322: break;
1323: }
1324: }
['1372']
1372: for (uint256 i = numAssets; i > 0; ) { // <= FOUND
1373:
1374:
1375: if (positionsToClose[--i]) { // <= FOUND
1376:
1377:
1378: if (i != lastAssetIndex) { // <= FOUND
1379:
1380:
1381: storedAssets[i] = storedAssets[lastAssetIndex--];
1382:
1383:
1384: storedAssets.pop(); // <= FOUND
1385: } else {
1386:
1387:
1388: if (lastAssetIndex != 0) { // <= FOUND
1389: --lastAssetIndex;
1390: }
1391:
1392: storedAssets.pop(); // <= FOUND
1393: }
1394:
1395: cachedToken = address(userAssets[i]); // <= FOUND
1396:
1397:
1398: tokenData[cachedToken].accountPositions[account].activePosition = 1;
1399: emit TokenPositionClosed(cachedToken, account); // <= FOUND
1400: }
1401: }
[Low-21] For loops in public or external functions should be avoided due to high gas costs and possible DOS
In Solidity, for loops can potentially cause Denial of Service (DoS) attacks if not handled carefully. DoS attacks can occur when an attacker intentionally exploits the gas cost of a function, causing it to run out of gas or making it too expensive for other users to call. Below are some scenarios where for loops can lead to DoS attacks: Nested for loops can become exceptionally gas expensive and should be used sparingly
Num of instances: 45
Click to show findings
['147']
134: function reQueryRewardTokens() external {
135: delete strategyData.rewardTokens;
136:
137:
138:
139: strategyData.rewardTokens.push() = _BAL;
140:
141:
142: strategyData.rewardTokens.push() = _AURA;
143:
144: IBaseRewardPool rewarder = strategyData.rewarder;
145: uint256 extraRewardsLength = rewarder.extraRewardsLength();
146:
147: for (uint256 i; i < extraRewardsLength; ) { // <= FOUND
148: unchecked {
149: address rewardToken = IStashWrapper(
150: IRewards(rewarder.extraRewards(i++)).rewardToken()
151: ).baseToken();
152:
153: if (rewardToken != _AURA && rewardToken != _BAL) {
154: strategyData.rewardTokens.push() = rewardToken;
155: }
156: }
157: }
158: }
['169']
163: function reQueryUnderlyingTokens() external {
164: address[] memory currentTokens = strategyData.underlyingTokens;
165: uint256 numCurrentTokens = currentTokens.length;
166:
167:
168:
169: for (uint256 i; i < numCurrentTokens; ) { // <= FOUND
170: unchecked {
171: isUnderlyingToken[currentTokens[i++]] = false;
172: }
173: }
174:
175:
176: (currentTokens, , ) = strategyData.balancerVault.getPoolTokens(
177: strategyData.balancerPoolId
178: );
179: strategyData.underlyingTokens = currentTokens;
180: numCurrentTokens = currentTokens.length;
181:
182:
183:
184: for (uint256 i = 0; i < numCurrentTokens; ) { // <= FOUND
185: unchecked {
186: isUnderlyingToken[strategyData.underlyingTokens[i++]] = true;
187: }
188: }
189: }
['245']
212: function harvest(
213: bytes calldata data
214: ) external override returns (uint256 yield) {
215:
216: _canCompound();
217:
218:
219: _vestIfNeeded();
220:
221:
222: if (_checkVestStatus(_vaultData)) {
223: _updateVestingPeriodIfNeeded();
224:
225:
226: StrategyData memory sd = strategyData;
227:
228:
229: sd.rewarder.getReward(address(this), true);
230:
231: (SwapperLib.Swap[] memory swapDataArray, uint256 minLPAmount) = abi
232: .decode(data, (SwapperLib.Swap[], uint256));
233:
234: {
235:
236: uint256 numRewardTokens = sd.rewardTokens.length;
237: address rewardToken;
238: uint256 rewardAmount;
239: uint256 protocolFee;
240:
241:
242: address feeAccumulator = centralRegistry.feeAccumulator();
243: uint256 harvestFee = centralRegistry.protocolHarvestFee();
244:
245: for (uint256 i; i < numRewardTokens; ++i) { // <= FOUND
246: rewardToken = sd.rewardTokens[i];
247: rewardAmount = IERC20(rewardToken).balanceOf(
248: address(this)
249: );
250:
251:
252:
253: if (rewardAmount == 0) {
254: continue;
255: }
256:
257:
258:
259: protocolFee = FixedPointMathLib.mulDiv(
260: rewardAmount,
261: harvestFee,
262: 1e18
263: );
264: rewardAmount -= protocolFee;
265: SafeTransferLib.safeTransfer(
266: rewardToken,
267: feeAccumulator,
268: protocolFee
269: );
270:
271:
272: if (!isUnderlyingToken[rewardToken]) {
273: if (
274: !centralRegistry.isSwapper(swapDataArray[i].target)
275: ) {
276: revert AuraCToken__InvalidSwapper(
277: i,
278: swapDataArray[i].target
279: );
280: }
281:
282: SwapperLib.swap(centralRegistry, swapDataArray[i]);
283: }
284: }
285: }
286:
287:
288: {
289:
290: uint256 numUnderlyingTokens = sd.underlyingTokens.length;
291: address[] memory assets = new address[](numUnderlyingTokens);
292: uint256[] memory maxAmountsIn = new uint256[](
293: numUnderlyingTokens
294: );
295: address underlyingToken;
296:
297: for (uint256 i; i < numUnderlyingTokens; ++i) { // <= FOUND
298: underlyingToken = sd.underlyingTokens[i];
299: assets[i] = underlyingToken;
300: maxAmountsIn[i] = IERC20(underlyingToken).balanceOf(
301: address(this)
302: );
303:
304: SwapperLib._approveTokenIfNeeded(
305: underlyingToken,
306: address(sd.balancerVault),
307: maxAmountsIn[i]
308: );
309: }
310:
311:
312: sd.balancerVault.joinPool(
313: sd.balancerPoolId,
314: address(this),
315: address(this),
316: IBalancerVault.JoinPoolRequest(
317: assets,
318: maxAmountsIn,
319: abi.encode(
320: IBalancerVault
321: .JoinKind
322: .EXACT_TOKENS_IN_FOR_BPT_OUT,
323: maxAmountsIn,
324: minLPAmount
325: ),
326: false
327: )
328: );
329: }
330:
331:
332: yield = IERC20(asset()).balanceOf(address(this));
333: _afterDeposit(yield, 0);
334:
335:
336: _setNewVaultData(yield, vestPeriod);
337:
338: emit Harvest(yield);
339: }
340: }
['101']
72: function getPrice(
73: address asset,
74: bool inUSD,
75: bool getLower
76: ) external view override returns (PriceReturnData memory pData) {
77:
78: if (!isSupportedAsset[asset]) {
79: revert BalancerStablePoolAdaptor__AssetIsNotSupported();
80: }
81:
82:
83: _ensureNotInVaultContext(balancerVault);
84:
85:
86: AdaptorData memory data = adaptorData[asset];
87: IBalancerPool pool = IBalancerPool(asset);
88:
89: pData.inUSD = inUSD;
90: IOracleRouter oracleRouter = IOracleRouter(centralRegistry.oracleRouter());
91:
92:
93: uint256 numUnderlyingOrConstituent = data
94: .underlyingOrConstituent
95: .length;
96: uint256 averagePrice;
97: uint256 numPrices;
98:
99: uint256 price;
100: uint256 errorCode;
101: for (uint256 i; i < numUnderlyingOrConstituent; ++i) { // <= FOUND
102:
103: if (address(data.underlyingOrConstituent[i]) == address(0)) {
104: break;
105: }
106:
107: (price, errorCode) = oracleRouter.getPrice(
108: data.underlyingOrConstituent[i],
109: inUSD,
110: getLower
111: );
112:
113:
114: if (errorCode > 0) {
115: pData.hadError = true;
116: return pData;
117: }
118:
119:
120:
121: averagePrice += price;
122: ++numPrices;
123:
124: }
125:
126:
127: if (averagePrice == 0) {
128: pData.hadError = true;
129: return pData;
130: }
131:
132: averagePrice = ((averagePrice / numPrices) * pool.getRate()) / WAD;
133:
134:
135: if (_checkOracleOverflow(averagePrice)) {
136: pData.hadError = true;
137: return pData;
138: }
139:
140: pData.price = uint240(averagePrice);
141: }
['162']
148: function addAsset(address asset, AdaptorData memory data) external {
149: _checkElevatedPermissions();
150:
151: IBalancerPool pool = IBalancerPool(asset);
152:
153:
154: data.poolId = pool.getPoolId();
155: data.poolDecimals = pool.decimals();
156:
157: uint256 numUnderlyingOrConstituent = data
158: .underlyingOrConstituent
159: .length;
160:
161:
162: for (uint256 i; i < numUnderlyingOrConstituent; ++i) { // <= FOUND
163:
164: if (address(data.underlyingOrConstituent[i]) == address(0)) {
165: continue;
166: }
167:
168: if (
169: !IOracleRouter(centralRegistry.oracleRouter()).isSupportedAsset(
170: data.underlyingOrConstituent[i]
171: )
172: ) {
173: revert BalancerStablePoolAdaptor__ConfigurationError();
174: }
175:
176: if (data.rateProviders[i] != address(0)) {
177:
178: if (data.rateProviderDecimals[i] == 0) {
179: revert BalancerStablePoolAdaptor__ConfigurationError();
180: }
181:
182:
183: if (IRateProvider(data.rateProviders[i]).getRate() == 0) {
184: revert BalancerStablePoolAdaptor__ConfigurationError();
185: }
186: }
187: }
188:
189:
190: adaptorData[asset] = data;
191:
192:
193: bool isUpdate;
194: if (isSupportedAsset[asset]) {
195: isUpdate = true;
196: }
197:
198: isSupportedAsset[asset] = true;
199: emit BalancerStablePoolAssetAdded(asset, data, isUpdate);
200: }
['85']
70: function withdrawNativeYield(address[] calldata nonMTokens) external {
71:
72: _checkDaoPermissions();
73:
74: uint256 nonMTokensLength = nonMTokens.length;
75: if (nonMTokensLength == 0) {
76: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
77: }
78:
79:
80: IBlastNativeYieldManager yieldManager =IBlastNativeYieldManager(
81: nativeYieldManager
82: );
83: address nonMToken;
84:
85: for (uint256 i; i < nonMTokensLength; ) { // <= FOUND
86: nonMToken = nonMTokens[i++];
87:
88:
89: (bool success, ) = nonMToken.staticcall(
90: abi.encodePacked(IMToken(nonMToken).isCToken.selector)
91: );
92:
93:
94: if (success) {
95: revert BlastCentralRegistry__Unauthorized();
96: }
97: }
98:
99: yieldManager.claimPendingNativeYield(nonMTokens);
100: }
['404']
398: function claimPendingNativeYield(address[] calldata nonMTokens) external {
399: _checkIsCentralRegistry();
400:
401: uint256 nonMTokensLength = nonMTokens.length;
402: uint256 yieldClaimed;
403:
404: for (uint256 i; i < nonMTokensLength; ++i) { // <= FOUND
405: yieldClaimed += CHAIN_YIELD_MANAGER.claimMaxGas(
406: nonMTokens[i],
407: address(this)
408: );
409: }
410:
411: if (yieldClaimed == 0) {
412: revert BlastNativeYieldManager__NoYieldToClaim();
413: }
414:
415: IWETH(address(WETH_YIELD_MANAGER)).deposit{ value: yieldClaimed }();
416: SafeTransferLib.safeTransfer(address(WETH_YIELD_MANAGER), centralRegistry.daoAddress(), yieldClaimed);
417: }
['249']
236: function hypotheticalRewardsClaim(
237: address user
238: ) external view returns (uint256) {
239: uint256 epochs = epochsToClaim(user);
240: if (epochs == 0) {
241: return 0;
242: }
243:
244: uint256 startEpoch = userNextClaimIndex[user];
245: uint256 startPoints = veCVE.userPoints(user);
246: uint256 rewards;
247: uint256 pointsOffset;
248:
249: for (uint256 i; i < epochs; ++i) { // <= FOUND
250: pointsOffset = veCVE.userUnlocksByEpoch(user, startEpoch + i);
251:
252:
253: if (pointsOffset > 0) {
254:
255: startPoints -= pointsOffset;
256: }
257:
258:
259: if (startPoints == 0) {
260: break;
261: }
262:
263:
264: rewards += startPoints * epochRewardsPerCVE[startEpoch + i];
265: }
266:
267:
268: return rewards / WAD;
269: }
['314']
303: function withdrawReservesMulti(address[] calldata dTokens) external {
304:
305: _checkDaoPermissions();
306:
307: uint256 dTokenLength = dTokens.length;
308: if (dTokenLength == 0) {
309: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
310: }
311:
312: IMToken dToken;
313:
314: for (uint256 i; i < dTokenLength; ) { // <= FOUND
315: dToken = IMToken(dTokens[i++]);
316:
317: if (dToken.isCToken()) {
318: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
319: }
320:
321: dToken.processWithdrawReserves();
322: }
323: }
['461']
454: function registerWormholeChainIDs(
455: uint256[] calldata chainIds,
456: uint16[] calldata wormholeChainIds
457: ) external {
458: _checkElevatedPermissions();
459:
460: uint256 numChainIds = chainIds.length;
461: for (uint256 i; i < numChainIds; ++i) { // <= FOUND
462: wormholeChainId[chainIds[i]] = wormholeChainIds[i];
463: }
464: emit WormholeChainIDsSet(chainIds, wormholeChainIds);
465: }
['480']
472: function registerCCTPDomains(
473: uint256[] calldata chainIds,
474: uint32[] calldata cctpDomains
475: ) external {
476: _checkElevatedPermissions();
477:
478: uint256 numChainIds = chainIds.length;
479:
480: for (uint256 i; i < numChainIds; ++i) { // <= FOUND
481: cctpDomain[chainIds[i]] = cctpDomains[i];
482: }
483: emit CCTPDomainsSet(chainIds, cctpDomains);
484: }
['210']
177: function harvest(
178: bytes calldata data
179: ) external override returns (uint256 yield) {
180:
181: _canCompound();
182:
183:
184: _vestIfNeeded();
185:
186:
187: if (_checkVestStatus(_vaultData)) {
188: _updateVestingPeriodIfNeeded();
189:
190:
191: StrategyData memory sd = strategyData;
192:
193:
194: sd.rewarder.getReward(address(this), true);
195:
196: (SwapperLib.Swap[] memory swapDataArray, uint256 minLPAmount) = abi
197: .decode(data, (SwapperLib.Swap[], uint256));
198:
199: uint256 numRewardTokens = sd.rewardTokens.length;
200: address rewardToken;
201: uint256 rewardAmount;
202: uint256 protocolFee;
203:
204: {
205:
206:
207: address feeAccumulator = centralRegistry.feeAccumulator();
208: uint256 harvestFee = centralRegistry.protocolHarvestFee();
209:
210: for (uint256 i; i < numRewardTokens; ++i) { // <= FOUND
211: rewardToken = sd.rewardTokens[i];
212: rewardAmount = IERC20(rewardToken).balanceOf(
213: address(this)
214: );
215:
216:
217:
218: if (rewardAmount == 0) {
219: continue;
220: }
221:
222:
223:
224: protocolFee = FixedPointMathLib.mulDiv(
225: rewardAmount,
226: harvestFee,
227: 1e18
228: );
229: rewardAmount -= protocolFee;
230: SafeTransferLib.safeTransfer(
231: address(rewardToken),
232: feeAccumulator,
233: protocolFee
234: );
235: }
236: }
237:
238:
239: {
240: uint256 numSwapData = swapDataArray.length;
241: for (uint256 i; i < numSwapData; ++i) { // <= FOUND
242: if (!centralRegistry.isSwapper(swapDataArray[i].target)) {
243: revert Convex2PoolCToken__InvalidSwapper(
244: i,
245: swapDataArray[i].target
246: );
247: }
248: SwapperLib.swap(centralRegistry, swapDataArray[i]);
249: }
250: }
251:
252:
253: _addLiquidityToCurve(minLPAmount);
254:
255:
256: yield = IERC20(asset()).balanceOf(address(this));
257: if (yield == 0) {
258: revert Convex2PoolCToken__NoYield();
259: }
260: _afterDeposit(yield, 0);
261:
262:
263: _setNewVaultData(yield, vestPeriod);
264:
265: emit Harvest(yield);
266: }
267: }
['210']
177: function harvest(
178: bytes calldata data
179: ) external override returns (uint256 yield) {
180:
181: _canCompound();
182:
183:
184: _vestIfNeeded();
185:
186:
187: if (_checkVestStatus(_vaultData)) {
188: _updateVestingPeriodIfNeeded();
189:
190:
191: StrategyData memory sd = strategyData;
192:
193:
194: sd.rewarder.getReward(address(this), true);
195:
196: (SwapperLib.Swap[] memory swapDataArray, uint256 minLPAmount) = abi
197: .decode(data, (SwapperLib.Swap[], uint256));
198:
199: uint256 numRewardTokens = sd.rewardTokens.length;
200: address rewardToken;
201: uint256 rewardAmount;
202: uint256 protocolFee;
203:
204: {
205:
206:
207: address feeAccumulator = centralRegistry.feeAccumulator();
208: uint256 harvestFee = centralRegistry.protocolHarvestFee();
209:
210: for (uint256 i; i < numRewardTokens; ++i) { // <= FOUND
211: rewardToken = sd.rewardTokens[i];
212: rewardAmount = IERC20(rewardToken).balanceOf(
213: address(this)
214: );
215:
216:
217:
218: if (rewardAmount == 0) {
219: continue;
220: }
221:
222:
223:
224: protocolFee = FixedPointMathLib.mulDiv(
225: rewardAmount,
226: harvestFee,
227: 1e18
228: );
229: rewardAmount -= protocolFee;
230: SafeTransferLib.safeTransfer(
231: address(rewardToken),
232: feeAccumulator,
233: protocolFee
234: );
235: }
236: }
237:
238:
239: {
240: uint256 numSwapData = swapDataArray.length;
241: for (uint256 i; i < numSwapData; ++i) { // <= FOUND
242: if (!centralRegistry.isSwapper(swapDataArray[i].target)) {
243: revert Convex3PoolCToken__InvalidSwapper(
244: i,
245: swapDataArray[i].target
246: );
247: }
248: SwapperLib.swap(centralRegistry, swapDataArray[i]);
249: }
250: }
251:
252:
253: _addLiquidityToCurve(minLPAmount);
254:
255:
256: yield = IERC20(asset()).balanceOf(address(this));
257: if (yield == 0) {
258: revert Convex3PoolCToken__NoYield();
259: }
260: _afterDeposit(yield, 0);
261:
262:
263: _setNewVaultData(yield, vestPeriod);
264:
265: emit Harvest(yield);
266: }
267: }
['249']
196: function addAsset(address asset, AdaptorData memory data) external {
197: _checkElevatedPermissions();
198:
199:
200:
201: if (isLocked(asset, 2)) {
202: revert Curve2PoolLPAdaptor__UnsupportedPool();
203: }
204:
205: address oracleRouter = centralRegistry.oracleRouter();
206:
207:
208:
209: if (
210: !IOracleRouter(oracleRouter).isSupportedAsset(
211: data.underlying0
212: )
213: ) {
214: revert Curve2PoolLPAdaptor__QuoteAssetIsNotSupported();
215: }
216:
217:
218:
219: if (
220: !IOracleRouter(oracleRouter).isSupportedAsset(
221: data.underlying1
222: )
223: ) {
224: revert Curve2PoolLPAdaptor__QuoteAssetIsNotSupported();
225: }
226:
227:
228: if (data.lowerBound >= data.upperBound) {
229: revert Curve2PoolLPAdaptor__InvalidBounds();
230: }
231:
232: ICurvePool pool = ICurvePool(data.pool);
233: uint256 coinsLength;
234:
235: while (true) {
236: try pool.coins(coinsLength) {
237: ++coinsLength;
238: } catch {
239: break;
240: }
241: }
242:
243:
244: if (coinsLength != 2) {
245: revert Curve2PoolLPAdaptor__UnsupportedPool();
246: }
247:
248: address underlying;
249: for (uint256 i; i < coinsLength; ) { // <= FOUND
250: underlying = pool.coins(i++);
251:
252:
253:
254: if (
255: underlying != data.underlying0 &&
256: underlying != data.underlying1
257: ) {
258: revert Curve2PoolLPAdaptor__UnsupportedPool();
259: }
260: }
261:
262:
263:
264:
265:
266: data.lowerBound = _bpToWad(data.lowerBound);
267: data.upperBound = _bpToWad(data.upperBound);
268:
269:
270: if (_MAX_BOUND_RANGE + data.lowerBound < data.upperBound) {
271: revert Curve2PoolLPAdaptor__InvalidBounds();
272: }
273:
274:
275: if (data.isCorrelated) {
276:
277:
278: try pool.lp_price() {
279: revert Curve2PoolLPAdaptor__UnsupportedPool();
280: } catch {}
281: } else {
282:
283:
284: try pool.lp_price() {} catch {
285: revert Curve2PoolLPAdaptor__UnsupportedPool();
286: }
287: }
288:
289:
290: uint256 testVirtualPrice = pool.get_virtual_price();
291:
292:
293: _enforceBounds(testVirtualPrice, data.lowerBound, data.upperBound);
294:
295:
296: adaptorData[asset] = data;
297:
298:
['203']
181: function multiSwap(
182: bytes calldata data,
183: address[] calldata tokens
184: ) external nonReentrant {
185: if (!centralRegistry.isHarvester(msg.sender)) {
186: revert FeeAccumulator__Unauthorized();
187: }
188:
189: SwapperLib.Swap[] memory swapDataArray = abi.decode(
190: data,
191: (SwapperLib.Swap[])
192: );
193:
194: uint256 numTokens = swapDataArray.length;
195: if (numTokens != tokens.length) {
196: revert FeeAccumulator__SwapDataAndTokenLengthMismatch(
197: numTokens,
198: tokens.length
199: );
200: }
201: address currentToken;
202:
203: for (uint256 i; i < numTokens; ++i) { // <= FOUND
204: currentToken = tokens[i];
205:
206: if (rewardTokenInfo[currentToken].forOTC == 2) {
207: continue;
208: }
209: if (rewardTokenInfo[currentToken].isRewardToken != 2) {
210: revert FeeAccumulator__SwapDataCurrentTokenIsNotRewardToken(
211: i,
212: currentToken
213: );
214: }
215: if (swapDataArray[i].inputToken != currentToken) {
216: revert FeeAccumulator__SwapDataInputTokenIsNotCurrentToken(
217: i,
218: swapDataArray[i].inputToken,
219: currentToken
220: );
221: }
222: if (swapDataArray[i].outputToken != feeToken) {
223: revert FeeAccumulator__SwapDataOutputTokenIsNotFeeToken(
224: i,
225: swapDataArray[i].outputToken,
226: feeToken
227: );
228: }
229: if (!centralRegistry.isSwapper(swapDataArray[i].target)) {
230: revert FeeAccumulator__SwapDataInvalidSwapper(
231: i,
232: swapDataArray[i].target
233: );
234: }
235:
236:
237:
238:
239:
240:
241:
242: SwapperLib.swap(centralRegistry, swapDataArray[i]);
243: }
244:
245: SafeTransferLib.safeTransfer(
246: feeToken,
247: oneBalanceFeeManager,
248: (IERC20(feeToken).balanceOf(address(this)) * vaultCompoundFee()) /
249: vaultYieldFee()
250: );
251: }
['458']
420: function executeEpochFeeRouter(uint256 chainId) external {
421: ICVELocker locker = ICVELocker(centralRegistry.cveLocker());
422: uint256 epoch = locker.nextEpochToDeliver();
423:
424: if (locker.currentEpoch(block.timestamp) <= epoch) {
425: revert FeeAccumulator__CurrentEpochError(
426: locker.currentEpoch(block.timestamp),
427: epoch
428: );
429: }
430:
431: ChainData memory chainData = centralRegistry.supportedChainData(
432: chainId
433: );
434: if (chainData.isSupported < 2) {
435: return;
436: }
437:
438: uint256 numChainData = crossChainLockData.length;
439:
440:
441:
442: if (numChainData == centralRegistry.supportedChains()) {
443:
444: uint256 epochRewardsPerCVE = _executeEpochFeeRouter(
445: chainData,
446: numChainData,
447: epoch
448: );
449:
450: IProtocolMessagingHub messagingHub = IProtocolMessagingHub(
451: centralRegistry.protocolMessagingHub()
452: );
453: LockData memory lockData;
454: uint256 gas;
455: uint16 messagingChainId;
456:
457:
458: for (uint256 i; i < numChainData; ) { // <= FOUND
459: lockData = crossChainLockData[i];
460: chainData = centralRegistry.supportedChainData(
461: lockData.chainId
462: );
463: messagingChainId = centralRegistry.GETHToMessagingChainId(
464: uint256(lockData.chainId)
465: );
466:
467: gas = messagingHub.quoteWormholeFee(
468: uint256(lockData.chainId),
469: false
470: );
471:
472: messagingHub.sendWormholeMessages{ value: gas }(
473: uint256(lockData.chainId),
474: chainData.messagingHub,
475: abi.encode(epochRewardsPerCVE)
476: );
477:
478: unchecked {
479: ++i;
480: }
481: }
482:
483: delete crossChainLockData;
484: }
485: }
['502']
491: function migrateFeeAccumulator() external {
492: address newFeeAccumulator = centralRegistry.feeAccumulator();
493: if (newFeeAccumulator == address(this)) {
494: revert FeeAccumulator__NewFeeAccumulatorIsNotChanged();
495: }
496:
497: address[] memory currentRewardTokens = rewardTokens;
498: uint256 numTokens = currentRewardTokens.length;
499: uint256 tokenBalance;
500:
501:
502: for (uint256 i; i < numTokens; ) { // <= FOUND
503: tokenBalance = IERC20(currentRewardTokens[i]).balanceOf(
504: address(this)
505: );
506:
507: if (tokenBalance > 0) {
508: SafeTransferLib.safeTransfer(
509: currentRewardTokens[i],
510: newFeeAccumulator,
511: tokenBalance
512: );
513: }
514:
515: unchecked {
516: ++i;
517: }
518: }
519:
520: tokenBalance = IERC20(feeToken).balanceOf(address(this));
521:
522:
523: if (tokenBalance > 0) {
524: SafeTransferLib.safeTransfer(
525: feeToken,
526: newFeeAccumulator,
527: tokenBalance
528: );
529: }
530: }
['576']
568: function addRewardTokens(address[] calldata newTokens) external {
569: _checkDaoPermissions();
570:
571: uint256 numTokens = newTokens.length;
572: if (numTokens == 0) {
573: revert FeeAccumulator__TokenLengthIsZero();
574: }
575:
576: for (uint256 i; i < numTokens; ++i) { // <= FOUND
577:
578: if (rewardTokenInfo[newTokens[i]].isRewardToken == 2) {
579: continue;
580: }
581:
582:
583:
584: _addRewardToken(newTokens[i]);
585: }
586: }
['606']
592: function removeRewardToken(address rewardTokenToRemove) external {
593: _checkDaoPermissions();
594:
595: RewardToken storage tokenToRemove = rewardTokenInfo[
596: rewardTokenToRemove
597: ];
598: if (tokenToRemove.isRewardToken != 2) {
599: revert FeeAccumulator__RemovalTokenIsNotRewardToken();
600: }
601:
602: address[] memory currentTokens = rewardTokens;
603: uint256 numTokens = currentTokens.length;
604: uint256 tokenIndex = numTokens;
605:
606: for (uint256 i; i < numTokens; ) { // <= FOUND
607: if (currentTokens[i] == rewardTokenToRemove) {
608:
609: tokenIndex = i;
610: break;
611: }
612: unchecked {
613: ++i;
614: }
615: }
616:
617:
618: if (tokenIndex == numTokens--) {
619:
620:
621: revert FeeAccumulator__RemovalTokenDoesNotExist();
622: }
623:
624:
625: address[] storage currentList = rewardTokens;
626:
627: currentList[tokenIndex] = currentList[numTokens];
628:
629: currentList.pop();
630:
631:
632: tokenToRemove.isRewardToken = 1;
633: }
['648']
639: function getRewardTokenBalances()
640: external
641: view
642: returns (uint256[] memory)
643: {
644: address[] memory currentTokens = rewardTokens;
645: uint256 numTokens = currentTokens.length;
646: uint256[] memory tokenBalances = new uint256[](numTokens);
647:
648: for (uint256 i; i < numTokens; ) { // <= FOUND
649: tokenBalances[i] = IERC20(currentTokens[i]).balanceOf(
650: address(this)
651: );
652:
653: unchecked {
654: ++i;
655: }
656: }
657:
658: return tokenBalances;
659: }
['119']
97: function getPrice(
98: address asset,
99: bool ,
100: bool
101: ) external view override returns (PriceReturnData memory pData) {
102:
103: if (!isSupportedAsset[asset]) {
104: revert GMAdaptor__AssetIsNotSupported();
105: }
106:
107:
108: IOracleRouter oracleRouter = IOracleRouter(
109: centralRegistry.oracleRouter()
110: );
111:
112: uint256[] memory prices = new uint256[](3);
113: address[] memory tokens = marketData[asset];
114: uint256 errorCode;
115: address token;
116:
117:
118:
119: for (uint256 i; i < 3; ++i) { // <= FOUND
120: token = tokens[i];
121:
122: (prices[i], errorCode) = oracleRouter.getPrice(token, true, false);
123: if (errorCode > 0) {
124: pData.hadError = true;
125: return pData;
126: }
127:
128: prices[i] = (prices[i] * 1e30) / _priceUnit[token];
129: }
130:
131:
132: (int256 price, ) = gmxReader.getMarketTokenPrice(
133: gmxDataStore,
134: IReader.MarketProps(asset, tokens[3], tokens[1], tokens[2]),
135: IReader.PriceProps(prices[0], prices[0]),
136: IReader.PriceProps(prices[1], prices[1]),
137: IReader.PriceProps(prices[2], prices[2]),
138: PNL_FACTOR_TYPE,
139: true
140: );
141:
142:
143:
144: if (price <= 0) {
145: pData.hadError = true;
146: return pData;
147: }
148:
149:
150: uint256 newPrice = uint256(price) / 1e12;
151:
152:
153: if (_checkOracleOverflow(newPrice)) {
154: pData.hadError = true;
155: return pData;
156: }
157:
158: pData.inUSD = true;
159: pData.price = uint240(newPrice);
160: }
['210']
169: function addAsset(address asset, address alteredToken) external {
170: _checkElevatedPermissions();
171:
172: IReader.MarketProps memory market = gmxReader.getMarket(
173: gmxDataStore,
174: asset
175: );
176:
177: bool isSynthetic = market.indexToken.code.length == 0;
178:
179:
180: if (
181: market.indexToken == address(0) ||
182: market.longToken == address(0) ||
183: market.shortToken == address(0)
184: ) {
185: revert GMAdaptor__MarketIsInvalid();
186: }
187:
188:
189:
190: if (
191: (isSynthetic && alteredToken == address(0)) ||
192: (!isSynthetic && alteredToken != address(0))
193: ) {
194: revert GMAdaptor__AlteredTokenIsInvalid();
195: }
196:
197: IOracleRouter oracleRouter = IOracleRouter(
198: centralRegistry.oracleRouter()
199: );
200:
201: address[] memory tokens = new address[](4);
202: tokens[0] = isSynthetic ? alteredToken : market.indexToken;
203: tokens[1] = market.longToken;
204: tokens[2] = market.shortToken;
205: tokens[3] = market.indexToken;
206:
207: address token;
208:
209:
210: for (uint256 i; i < 3; ++i) { // <= FOUND
211: token = tokens[i];
212:
213: if (!oracleRouter.isSupportedAsset(token)) {
214: revert GMAdaptor__MarketTokenIsNotSupported(token);
215: }
216:
217: if (_priceUnit[token] == 0) {
218: _priceUnit[token] = WAD * 10 ** IERC20(token).decimals();
219: }
220: }
221:
222:
223: marketData[asset] = tokens;
224:
225:
226: bool isUpdate;
227: if (isSupportedAsset[asset]) {
228: isUpdate = true;
229: }
230:
231: isSupportedAsset[asset] = true;
232: emit GMXGMAssetAdded(
233: asset,
234: tokens,
235: isSynthetic,
236: alteredToken,
237: isUpdate
238: );
239: }
['131']
110: function harvest(
111: bytes calldata
112: ) external override returns (uint256 yield) {
113:
114: _canCompound();
115:
116:
117: _vestIfNeeded();
118:
119:
120: if (_checkVestStatus(_vaultData)) {
121: _updateVestingPeriodIfNeeded();
122:
123:
124: uint256[] memory rewardAmounts = _claimReward();
125:
126:
127:
128: address feeAccumulator = centralRegistry.feeAccumulator();
129: uint256 harvestFee = centralRegistry.protocolHarvestFee();
130:
131: for (uint256 i; i < 2; ++i) { // <= FOUND
132:
133:
134: if (rewardAmounts[i] > 0) {
135:
136:
137: uint256 protocolFee = FixedPointMathLib.mulDiv(
138: rewardAmounts[i],
139: harvestFee,
140: 1e18
141: );
142: rewardAmounts[i] -= protocolFee;
143: SafeTransferLib.safeTransfer(
144: underlyingTokens[i],
145: feeAccumulator,
146: protocolFee
147: );
148: }
149: }
150:
151:
152: bytes[] memory data = new bytes[](4);
153:
154: data[0] = abi.encodeWithSelector(
155: IGMXExchangeRouter.sendWnt.selector,
156: gmxDepositVault,
157: 0.01e18
158: );
159:
160: uint256 rewardAmount;
161: for (uint256 i = 0; i < 2; ) { // <= FOUND
162: rewardAmount = rewardAmounts[i];
163: SafeTransferLib.safeApprove(
164: underlyingTokens[i],
165: gmxRouter,
166: rewardAmount
167: );
168: data[++i] = abi.encodeWithSelector(
169: IGMXExchangeRouter.sendTokens.selector,
170: underlyingTokens[i],
171: gmxDepositVault,
172: rewardAmount
173: );
174: }
175: data[3] = abi.encodeWithSelector(
176: IGMXExchangeRouter.createDeposit.selector,
177: IGMXExchangeRouter.CreateDepositParams(
178: address(this),
179: address(this),
180: address(0),
181: asset(),
182: underlyingTokens[0],
183: underlyingTokens[1],
184: new address[](0),
185: new address[](0),
186: 0,
187: false,
188: 0.01e18,
189: 500000
190: )
191: );
192:
193: bytes[] memory results = IGMXExchangeRouter(gmxExchangeRouter)
194: .multicall{ value: 0.01e18 }(data);
195: _isDepositKey[bytes32(results[3])] = true;
196:
197: yield = 1;
198: }
199: }
['105']
78: function setEmissionRates(
79: uint256 epoch,
80: address[] calldata tokens,
81: uint256[] calldata poolWeights
82: ) external override {
83: if (msg.sender != centralRegistry.protocolMessagingHub()) {
84: revert GaugeErrors.Unauthorized();
85: }
86:
87:
88:
89: if (
90: !(epoch == 0 && (startTime == 0 || block.timestamp < startTime)) &&
91: epoch != currentEpoch() + 1
92: ) {
93: revert GaugeErrors.InvalidEpoch();
94: }
95:
96: uint256 numTokens = tokens.length;
97:
98:
99: if (numTokens != poolWeights.length) {
100: revert GaugeErrors.InvalidLength();
101: }
102:
103: Epoch storage info = _epochInfo[epoch];
104: address priorAddress;
105: for (uint256 i; i < numTokens; ) { // <= FOUND
106:
107:
108: if (priorAddress > tokens[i]) {
109: revert GaugeErrors.InvalidToken();
110: }
111:
112: info.totalWeights =
113: info.totalWeights +
114: poolWeights[i] -
115: info.poolWeights[tokens[i]];
116: info.poolWeights[tokens[i]] = poolWeights[i];
117: unchecked {
118:
119: priorAddress = tokens[i++];
120: }
121: }
122: }
['128']
126: function massUpdatePools(address[] calldata tokens) external {
127: uint256 numTokens = tokens.length;
128: for (uint256 i; i < numTokens; ) { // <= FOUND
129: unchecked {
130:
131: updatePool(tokens[i++]);
132: }
133: }
134: }
['153']
145: function addExtraReward(address newReward) external {
146: _checkDaoPermissions();
147:
148: if (newReward == address(0)) {
149: revert GaugeErrors.InvalidAddress();
150: }
151:
152: uint256 rewardTokensLength = rewardTokens.length;
153: for (uint256 i; i < rewardTokensLength; ) { // <= FOUND
154:
155: if (rewardTokens[i++] == newReward) {
156: revert GaugeErrors.InvalidAddress();
157: }
158: }
159:
160: rewardTokens.push(newReward);
161:
162: emit AddExtraReward(newReward);
163: }
['325']
318: function pendingRewards(
319: address token,
320: address user
321: ) external view returns (uint256[] memory results) {
322: uint256 rewardTokensLength = rewardTokens.length;
323: results = new uint256[](rewardTokensLength);
324:
325: for (uint256 i; i < rewardTokensLength; ++i) { // <= FOUND
326: results[i] = pendingRewards(token, user, rewardTokens[i]);
327: }
328: }
['371']
334: function deposit(
335: address token,
336: address user,
337: uint256 amount
338: ) external nonReentrant {
339: if (amount == 0) {
340: revert GaugeErrors.InvalidAmount();
341: }
342:
343:
344:
345: if (
346: msg.sender != token ||
347: !IMarketManager(marketManager).isListed(token)
348: ) {
349: revert GaugeErrors.InvalidToken();
350: }
351:
352: updatePool(token);
353:
354: _calcPending(user, token);
355:
356: balanceOf[token][user] += amount;
357: totalSupply[token] += amount;
358:
359:
360:
361: if (block.timestamp > startTime) {
362:
363:
364: if (firstDeposit == 0) {
365:
366:
367: firstDeposit = block.timestamp;
368: updatePool(token);
369:
370: uint256 rewardTokensLength = rewardTokens.length;
371: for (uint256 i; i < rewardTokensLength; ) { // <= FOUND
372:
373: address rewardToken = rewardTokens[i++];
374: uint256 unallocatedRewards = (poolAccRewardPerShare[token][
375: rewardToken
376: ] * totalSupply[token]) / WAD_SQUARED;
377: if (unallocatedRewards > 0) {
378: SafeTransferLib.safeTransfer(
379: rewardToken,
380: centralRegistry.daoAddress(),
381: unallocatedRewards
382: );
383: }
384: }
385: }
386: }
387:
388: _calcDebt(user, token);
389:
390: emit Deposit(user, token, amount);
391: }
['447']
436: function claim(address token) external nonReentrant {
437: if (block.timestamp < startTime) {
438: revert GaugeErrors.NotStarted();
439: }
440:
441: updatePool(token);
442: _calcPending(msg.sender, token);
443:
444: bool hasRewards;
445: uint256 rewardTokensLength = rewardTokens.length;
446:
447: for (uint256 i; i < rewardTokensLength; ) { // <= FOUND
448:
449: address rewardToken = rewardTokens[i++];
450: uint256 rewards = userDebtInfo[token][msg.sender][rewardToken]
451: .rewardPending;
452:
453:
454: if (rewards > 0) {
455: hasRewards = true;
456: SafeTransferLib.safeTransfer(rewardToken, msg.sender, rewards);
457: }
458:
459:
460: userDebtInfo[token][msg.sender][rewardToken].rewardPending = 0;
461: }
462: if (!hasRewards) {
463: revert GaugeErrors.NoReward();
464: }
465:
466: _calcDebt(msg.sender, token);
467:
468: emit Claim(msg.sender, token);
469: }
['759']
743: function liquidateAccount(address account) external {
744:
745: if (msg.sender == account) {
746: _revert(_UNAUTHORIZED_SELECTOR);
747: }
748:
749:
750: if (seizePaused == 2) {
751: _revert(_PAUSED_SELECTOR);
752: }
753:
754: IMToken[] memory accountAssetsPrior = accountAssets[account].assets;
755: uint256 numAssetsPrior = accountAssetsPrior.length;
756: IMToken mToken;
757:
758:
759: for (uint256 i = 0; i < numAssetsPrior; ) { // <= FOUND
760:
761: mToken = accountAssetsPrior[i++];
762: if (!mToken.isCToken()) {
763:
764: mToken.accrueInterest();
765: }
766: }
767:
768: (
769: BadDebtData memory data,
770: uint256[] memory assetBalances
771: ) = _BadDebtTermsOf(account);
772:
773:
774: if (data.collateral >= data.debt) {
775: revert MarketManager__NoLiquidationAvailable();
776: }
777:
778: uint256 repayRatio = (data.debtToPay * WAD) / data.debt;
779: uint256 debt;
780:
781:
782: for (uint256 i = 0; i < numAssetsPrior; ++i) { // <= FOUND
783:
784: mToken = accountAssetsPrior[i];
785: if (!mToken.isCToken()) {
786: debt = mToken.debtBalanceCached(account);
787:
788:
789:
790:
791: if (debt != assetBalances[i]) {
792: _revert(_INVARIANT_ERROR_SELECTOR);
793: }
794:
795:
796: if (debt > 0) {
797:
798:
799:
800:
801:
802:
803:
804:
805: mToken.repayWithBadDebt(msg.sender, account, repayRatio);
806: }
807: }
808: }
809:
810: uint256 collateral;
811:
812:
813: for (uint256 i = 0; i < numAssetsPrior; ++i) { // <= FOUND
814:
815: mToken = accountAssetsPrior[i];
816: if (mToken.isCToken()) {
817: AccountPosition storage collateralData = tokenData[address(mToken)]
818: .accountPositions[account];
819:
820: collateral = collateralData.collateralPosted;
821:
822:
823:
824:
825: if (collateral != assetBalances[i]) {
826: _revert(_INVARIANT_ERROR_SELECTOR);
827: }
828:
829:
830:
831:
832:
833: if (collateral > 0) {
834:
835:
836:
837: delete collateralData.collateralPosted;
838:
839:
840: collateralPosted[address(mToken)] =
841: collateralPosted[address(mToken)] -
842: collateral;
843: emit CollateralRemoved(account, address(mToken), collateral);
844:
845: mToken.seizeAccountLiquidation(
846: msg.sender,
847: account,
848: collateral
849: );
850: }
851: }
852: }
853:
854: IMToken[] memory accountAssetsPost = accountAssets[account].assets;
855: uint256 numAssetsPost = accountAssetsPost.length;
856:
857:
858:
859:
860:
861: if (numAssetsPost != numAssetsPrior) {
862: _revert(_INVARIANT_ERROR_SELECTOR);
863: }
864:
865: for (uint256 i = 0; i < numAssetsPrior; ++i) { // <= FOUND
866: if (accountAssetsPost[i] != accountAssetsPrior[i]) {
867: _revert(_INVARIANT_ERROR_SELECTOR);
868: }
869: }
870: }
['900']
878: function listToken(address mToken) external {
879: _checkElevatedPermissions();
880:
881: if (tokenData[mToken].isListed) {
882: _revert(_INVALID_PARAMETER_SELECTOR);
883: }
884:
885:
886: IMToken(mToken).isCToken();
887:
888:
889:
890: if (!IMToken(mToken).startMarket(msg.sender)) {
891: _revert(_INVARIANT_ERROR_SELECTOR);
892: }
893:
894: MarketToken storage token = tokenData[mToken];
895: token.isListed = true;
896: token.collRatio = 0;
897:
898: uint256 numTokens = tokensListed.length;
899:
900: for (uint256 i; i < numTokens; ) { // <= FOUND
901: unchecked {
902: if (tokensListed[i++] == mToken) {
903: _revert(_INVALID_PARAMETER_SELECTOR);
904: }
905: }
906: }
907:
908: tokensListed.push(mToken);
909: emit TokenListed(mToken);
910: }
['1109']
1086: function setCTokenCollateralCaps(
1087: address[] calldata mTokens,
1088: uint256[] calldata newCollateralCaps
1089: ) external {
1090: if (!centralRegistry.hasDaoPermissions(msg.sender)) {
1091: _revert(_UNAUTHORIZED_SELECTOR);
1092: }
1093:
1094: uint256 numTokens = mTokens.length;
1095:
1096: assembly {
1097: if iszero(numTokens) {
1098:
1099: mstore(0x0, _INVALID_PARAMETER_SELECTOR)
1100:
1101: revert(0x1c, 0x04)
1102: }
1103: }
1104:
1105: if (numTokens != newCollateralCaps.length) {
1106: _revert(_INVALID_PARAMETER_SELECTOR);
1107: }
1108:
1109: for (uint256 i; i < numTokens; ++i) { // <= FOUND
1110:
1111: if (!IMToken(mTokens[i]).isCToken()) {
1112: _revert(_INVALID_PARAMETER_SELECTOR);
1113: }
1114:
1115:
1116:
1117: if (tokenData[mTokens[i]].collRatio == 0) {
1118: _revert(_INVALID_PARAMETER_SELECTOR);
1119: }
1120:
1121: collateralCaps[mTokens[i]] = newCollateralCaps[i];
1122: emit NewCollateralCap(mTokens[i], newCollateralCaps[i]);
1123: }
1124: }
['502']
483: function getPrices(
484: address[] calldata assets,
485: bool[] calldata inUSD,
486: bool[] calldata getLower
487: ) external view returns (uint256[] memory, uint256[] memory) {
488: uint256 numAssets = assets.length;
489:
490: if (numAssets == 0) {
491: _revert(_INVALID_PARAMETER_SELECTOR);
492: }
493:
494:
495: if (numAssets != inUSD.length || numAssets != getLower.length) {
496: _revert(_INVALID_PARAMETER_SELECTOR);
497: }
498:
499: uint256[] memory prices = new uint256[](numAssets);
500: uint256[] memory hadError = new uint256[](numAssets);
501:
502: for (uint256 i; i < numAssets; ) { // <= FOUND
503: (prices[i], hadError[i]) = getPrice(
504: assets[i],
505: inUSD[i],
506: getLower[i]
507: );
508:
509: unchecked {
510: ++i;
511: }
512: }
513:
514: return (prices, hadError);
515: }
['545']
526: function getPricesForMarket(
527: address account,
528: IMToken[] calldata assets,
529: uint256 errorCodeBreakpoint
530: )
531: external
532: view
533: returns (AccountSnapshot[] memory, uint256[] memory, uint256)
534: {
535: uint256 numAssets = assets.length;
536:
537: if (numAssets == 0) {
538: _revert(_INVALID_PARAMETER_SELECTOR);
539: }
540:
541: AccountSnapshot[] memory snapshots = new AccountSnapshot[](numAssets);
542: uint256[] memory underlyingPrices = new uint256[](numAssets);
543: uint256 hadError;
544:
545: for (uint256 i; i < numAssets; ) { // <= FOUND
546: snapshots[i] = assets[i].getSnapshotPacked(account);
547: (underlyingPrices[i], hadError) = getPrice(
548: assets[i].underlying(),
549: true,
550: snapshots[i].isCToken
551: );
552:
553: if (hadError >= errorCodeBreakpoint) {
554: _revert(_ERROR_CODE_FLAGGED_SELECTOR);
555: }
556:
557: unchecked {
558: ++i;
559: }
560: }
561:
562: return (snapshots, underlyingPrices, numAssets);
563: }
['107']
101: function reQueryUnderlyingTokens() external {
102: address[] memory currentTokens = strategyData.underlyingTokens;
103: uint256 numCurrentTokens = currentTokens.length;
104:
105:
106:
107: for (uint256 i; i < numCurrentTokens; ) { // <= FOUND
108: unchecked {
109: isUnderlyingToken[currentTokens[i++]] = false;
110: }
111: }
112:
113:
114: strategyData.underlyingTokens = strategyData.sy.getTokensIn();
115: numCurrentTokens = strategyData.underlyingTokens.length;
116:
117:
118:
119: for (uint256 i = 0; i < numCurrentTokens; ) { // <= FOUND
120: unchecked {
121: isUnderlyingToken[strategyData.underlyingTokens[i++]] = true;
122: }
123: }
124: }
['184']
147: function harvest(
148: bytes calldata data
149: ) external override returns (uint256 yield) {
150:
151: _canCompound();
152:
153:
154: _vestIfNeeded();
155:
156:
157: if (_checkVestStatus(_vaultData)) {
158: _updateVestingPeriodIfNeeded();
159:
160:
161: StrategyData memory sd = strategyData;
162:
163:
164: sd.lp.redeemRewards(address(this));
165:
166: (
167: SwapperLib.Swap[] memory swapDataArray,
168: uint256 minLPAmount,
169: ApproxParams memory approx,
170: LimitOrderData memory limit
171: ) = abi.decode(data, (SwapperLib.Swap[], uint256, ApproxParams, LimitOrderData));
172:
173: {
174:
175: uint256 numRewardTokens = sd.rewardTokens.length;
176: address rewardToken;
177: uint256 rewardAmount;
178: uint256 protocolFee;
179:
180:
181: address feeAccumulator = centralRegistry.feeAccumulator();
182: uint256 harvestFee = centralRegistry.protocolHarvestFee();
183:
184: for (uint256 i; i < numRewardTokens; ++i) { // <= FOUND
185: rewardToken = sd.rewardTokens[i];
186: rewardAmount = IERC20(rewardToken).balanceOf(
187: address(this)
188: );
189:
190:
191:
192: if (rewardAmount == 0) {
193: continue;
194: }
195:
196:
197:
198: protocolFee = FixedPointMathLib.mulDiv(
199: rewardAmount,
200: harvestFee,
201: 1e18
202: );
203: rewardAmount -= protocolFee;
204: SafeTransferLib.safeTransfer(
205: rewardToken,
206: feeAccumulator,
207: protocolFee
208: );
209:
210:
211: if (!isUnderlyingToken[rewardToken]) {
212: if (
213: !centralRegistry.isSwapper(swapDataArray[i].target)
214: ) {
215: revert PendleLPCToken__InvalidSwapper(
216: i,
217: swapDataArray[i].target
218: );
219: }
220:
221: SwapperLib.swap(centralRegistry, swapDataArray[i]);
222: }
223: }
224: }
225:
226:
227: {
228: uint256 numUnderlyingTokens = sd.underlyingTokens.length;
229: address underlyingToken;
230: uint256 balance;
231: for (uint256 i; i < numUnderlyingTokens; ++i) { // <= FOUND
232: underlyingToken = sd.underlyingTokens[i];
233:
234: if (underlyingToken == address(0)) {
235: balance = address(this).balance;
236: if (balance > 0) {
237:
238: sd.sy.deposit{ value: balance }(
239: address(this),
240: underlyingToken,
241: balance,
242: 0
243: );
244: }
245: } else {
246: balance = IERC20(underlyingToken).balanceOf(
247: address(this)
248: );
249: if (balance > 0) {
250: SwapperLib._approveTokenIfNeeded(
251: underlyingToken,
252: address(sd.sy),
253: balance
254: );
255:
256: sd.sy.deposit(
257: address(this),
258: underlyingToken,
259: balance,
260: 0
261: );
262: }
263: }
264: }
265: }
266:
267: {
268: uint256 balance = sd.sy.balanceOf(address(this));
269: SwapperLib._approveTokenIfNeeded(
270: address(sd.sy),
271: address(sd.router),
272: balance
273: );
274:
275:
276: (yield, ) = sd.router.addLiquiditySingleSy(
277: address(this),
278: address(sd.lp),
279: balance,
280: minLPAmount,
['239']
97: function receiveWormholeMessages(
98: bytes memory payload,
99: bytes[] memory ,
100: bytes32 srcAddress,
101: uint16 srcChainId,
102: bytes32 deliveryHash
103: ) external payable {
104: _checkMessagingHubStatus();
105:
106:
107: if (isDeliveredMessageHash[deliveryHash]) {
108: revert ProtocolMessagingHub__MessageHashIsAlreadyDelivered(
109: deliveryHash
110: );
111: }
112:
113: isDeliveredMessageHash[deliveryHash] = true;
114: address wormholeRelayer = address(centralRegistry.wormholeRelayer());
115:
116:
117: if (msg.sender != wormholeRelayer) {
118: _revert(_UNAUTHORIZED_SELECTOR);
119: }
120:
121: uint256 gethChainId = centralRegistry.messagingToGETHChainId(
122: srcChainId
123: );
124: address srcAddr = address(uint160(uint256(srcAddress)));
125:
126: OmnichainData memory operator = centralRegistry.getOmnichainOperators(
127: srcAddr,
128: gethChainId
129: );
130:
131:
132: if (
133: centralRegistry.supportedChainData(gethChainId).messagingHub !=
134: srcAddr
135: ) {
136: return;
137: }
138:
139:
140: if (operator.isAuthorized < 2) {
141: return;
142: }
143:
144: uint8 payloadId = abi.decode(payload, (uint8));
145:
146:
147:
148: if (payloadId == 1) {
149: (, address token, uint256 amount) = abi.decode(
150: payload,
151: (uint8, address, uint256)
152: );
153:
154: address feeToken = centralRegistry.feeToken();
155:
156:
157:
158:
159: if (token == feeToken) {
160: ICVELocker locker = ICVELocker(centralRegistry.cveLocker());
161:
162:
163:
164: if (locker.isShutdown() == 2) {
165: SafeTransferLib.safeTransfer(
166: feeToken,
167: centralRegistry.daoAddress(),
168: amount
169: );
170: return;
171: }
172:
173:
174: SafeTransferLib.safeTransfer(
175: feeToken,
176: address(locker),
177: amount
178: );
179: locker.recordEpochRewards(amount);
180: return;
181: }
182:
183:
184:
185: } else if (payloadId == 4) {
186: (, bytes memory emissionData) = abi.decode(
187: payload,
188: (uint8, bytes)
189: );
190:
191: (
192: address[] memory gaugePools,
193: uint256[] memory emissionTotals,
194: address[][] memory tokens,
195: uint256[][] memory emissions,
196: uint256 chainLockedAmount,
197: uint256 messageType
198: ) = abi.decode(
199: emissionData,
200: (
201: address[],
202: uint256[],
203: address[][],
204: uint256[][],
205: uint256,
206: uint256
207: )
208: );
209:
210:
211:
212: if (messageType == 1) {
213: IFeeAccumulator(centralRegistry.feeAccumulator())
214: .receiveCrossChainLockData(
215: EpochRolloverData({
216: chainId: gethChainId,
217: value: chainLockedAmount,
218: numChainData: 0,
219: epoch: 0
220: })
221: );
222: return;
223: }
224:
225:
226: if (messageType == 2) {
227: IFeeAccumulator(centralRegistry.feeAccumulator())
228: .receiveExecutableLockData(chainLockedAmount);
229: return;
230: }
231:
232:
233:
234: {
235:
236: uint256 numPools = gaugePools.length;
237: GaugeController gaugePool;
238:
239: for (uint256 i; i < numPools; ) { // <= FOUND
240: gaugePool = GaugeController(gaugePools[i]);
241:
242: cve.mintGaugeEmissions(
243: address(gaugePool),
244: emissionTotals[i]
245: );
246:
247: gaugePool.setEmissionRates(
248: gaugePool.currentEpoch() + 1,
249: tokens[i],
250: emissions[i]
251: );
252:
253: unchecked {
254: ++i;
255: }
256: }
257: }
258:
259:
260: } else if (payloadId == 5) {
261: (, bytes memory lockData) = abi.decode(payload, (uint8, bytes));
262:
263: (address recipient, uint256 amount, bool continuousLock) = abi
264: .decode(lockData, (address, uint256, bool));
265:
266: cve.mintVeCVELock(amount);
267: cve.approve(veCVE, amount);
268:
269: RewardsData memory rewardData;
270:
271:
272:
273:
274: IVeCVE(veCVE).createLockFor(
275: recipient,
276: amount,
277: continuousLock,
278: rewardData,
279: "",
280: 0
281: );
282: }
283: }
['229']
220: function queryUserLocks(
221: address user
222: ) external view returns (uint256[] memory, uint256[] memory) {
223: uint256 numLocks = userLocks[user].length;
224: Lock[] memory locks = userLocks[user];
225: Lock memory lock;
226: uint256[] memory lockAmounts = new uint256[](numLocks);
227: uint256[] memory lockTimestamps = new uint256[](numLocks);
228:
229: for (uint256 i; i < numLocks; ++i) { // <= FOUND
230: lock = locks[i];
231: lockAmounts[i] = lock.amount;
232: lockTimestamps[i] = lock.unlockTime;
233: }
234:
235: return (lockAmounts, lockTimestamps);
236: }
['566']
540: function combineAllLocks(
541: bool continuousLock,
542: RewardsData calldata rewardsData,
543: bytes calldata params,
544: uint256 aux
545: ) external nonReentrant {
546: if (isShutdown == 2) {
547: _revert(_VECVE_SHUTDOWN_SELECTOR);
548: }
549:
550:
551: _claimRewards(msg.sender, rewardsData, params, aux);
552:
553:
554:
555: Lock[] storage locks = userLocks[msg.sender];
556: uint256 numLocks = locks.length;
557:
558:
559: if (numLocks < 2) {
560: _revert(_INVALID_LOCK_SELECTOR);
561: }
562:
563: uint256 lockedAmount;
564: Lock storage lock;
565:
566: for (uint256 i; i < numLocks; ) { // <= FOUND
567: lock = locks[i];
568:
569: if (lock.unlockTime != CONTINUOUS_LOCK_VALUE) {
570:
571: _reduceTokenUnlocks(
572: msg.sender,
573: currentEpoch(lock.unlockTime),
574: lock.amount
575: );
576: }
577:
578: unchecked {
579:
580:
581: lockedAmount += locks[i++].amount;
582: }
583: }
584:
585:
586: delete userLocks[msg.sender];
587: uint256 veBalanceOf = balanceOf(msg.sender);
588:
589:
590:
591: if (veBalanceOf != lockedAmount) {
592: revert VeCVE__InvariantError();
593: }
594:
595:
596: uint256 currentPoints = userPoints[msg.sender];
597:
598:
599: if (continuousLock) {
600:
601: userLocks[msg.sender].push(
602: Lock({
603: amount: uint216(lockedAmount),
604: unlockTime: CONTINUOUS_LOCK_VALUE
605: })
606: );
607:
608:
609:
610:
611:
612:
613: veBalanceOf = veBalanceOf * CL_POINT_MULTIPLIER;
614:
615:
['930']
920: function getVotes(address user) external view returns (uint256) {
921: uint256 numLocks = userLocks[user].length;
922:
923: if (numLocks == 0) {
924: return 0;
925: }
926:
927: uint256 currentLockBoost = centralRegistry.voteBoostMultiplier();
928: uint256 votes;
929:
930: for (uint256 i; i < numLocks; ) { // <= FOUND
931:
932: unchecked {
933: votes += getVotesForSingleLockForTime(
934: user,
935: i++,
936: block.timestamp,
937: currentLockBoost
938: );
939: }
940: }
941:
942: return votes;
943: }
['964']
950: function getVotesForEpoch(
951: address user,
952: uint256 epoch
953: ) external view returns (uint256) {
954: uint256 numLocks = userLocks[user].length;
955:
956: if (numLocks == 0) {
957: return 0;
958: }
959:
960: uint256 timestamp = genesisEpoch + (EPOCH_DURATION * epoch);
961: uint256 currentLockBoost = centralRegistry.voteBoostMultiplier();
962: uint256 votes;
963:
964: for (uint256 i; i < numLocks; ) { // <= FOUND
965:
966: unchecked {
967: votes += getVotesForSingleLockForTime(
968: user,
969: i++,
970: timestamp,
971: currentLockBoost
972: );
973: }
974: }
975:
976: return votes;
977: }
['1202']
1186: function removeMarketManager(
1187: address currentMarketManager
1188: ) public virtual {
1189: _checkElevatedPermissions();
1190:
1191:
1192: if (!isMarketManager[currentMarketManager]) {
1193: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
1194: }
1195:
1196: delete isMarketManager[currentMarketManager];
1197:
1198:
1199: uint256 numMarkets = marketManagers.length;
1200: uint256 marketIndex = numMarkets;
1201:
1202: for (uint256 i; i < numMarkets; ++i) { // <= FOUND
1203: if (marketManagers[i] == currentMarketManager) {
1204: marketIndex = i;
1205: break;
1206: }
1207: }
1208:
1209:
1210:
1211:
1212: if (marketIndex >= numMarkets--) {
1213: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
1214: }
1215:
1216:
1217: marketManagers[marketIndex] = marketManagers[numMarkets];
1218:
1219:
1220: marketManagers.pop();
1221:
1222: emit RemovedCurvanceContract("Market Manager", currentMarketManager);
1223: }
['149']
140: function reQueryRewardTokens() public {
141: delete strategyData.rewardTokens;
142:
143:
144:
145: strategyData.rewardTokens.push() = _CRV;
146: IBaseRewardPool rewarder = strategyData.rewarder;
147:
148: uint256 extraRewardsLength = rewarder.extraRewardsLength();
149: for (uint256 i; i < extraRewardsLength; ++i) { // <= FOUND
150: strategyData.rewardTokens.push() = IRewards(
151: rewarder.extraRewards(i)
152: ).rewardToken();
153: }
154: }
['149']
140: function reQueryRewardTokens() public {
141: delete strategyData.rewardTokens;
142:
143:
144:
145: strategyData.rewardTokens.push() = _CRV;
146: IBaseRewardPool rewarder = strategyData.rewarder;
147:
148: uint256 extraRewardsLength = rewarder.extraRewardsLength();
149: for (uint256 i; i < extraRewardsLength; ++i) { // <= FOUND
150: strategyData.rewardTokens.push() = IRewards(
151: rewarder.extraRewards(i)
152: ).rewardToken();
153: }
154: }
['628']
603: function updatePool(address token) public override {
604:
605: if (block.timestamp <= startTime) {
606: return;
607: }
608:
609: uint256 _lastRewardTimestamp = poolLastRewardTimestamp[token];
610:
611: if (_lastRewardTimestamp == 0) {
612: _lastRewardTimestamp = startTime;
613: }
614:
615:
616: if (block.timestamp <= _lastRewardTimestamp) {
617: return;
618: }
619:
620:
621: uint256 totalDeposited = totalSupply[token];
622: if (totalDeposited == 0) {
623: return;
624: }
625:
626:
627: uint256 rewardTokensLength = rewardTokens.length;
628: for (uint256 i; i < rewardTokensLength; ) { // <= FOUND
629: uint256 lastRewardTimestamp = _lastRewardTimestamp;
630:
631:
632: address rewardToken = rewardTokens[i++];
633: uint256 accRewardPerShare = poolAccRewardPerShare[token][
634: rewardToken
635: ];
636: uint256 lastEpoch = epochOfTimestamp(lastRewardTimestamp);
637: uint256 currentEpoch = currentEpoch();
638: uint256 reward;
639:
640:
641: while (lastEpoch < currentEpoch) {
642: uint256 endTimestamp = epochEndTime(lastEpoch);
643:
644:
645: reward =
646: ((endTimestamp - lastRewardTimestamp) *
647: rewardAllocation(token, lastEpoch, rewardToken)) /
648: EPOCH_WINDOW;
649: accRewardPerShare =
650: accRewardPerShare +
651: (reward * (WAD_SQUARED)) /
652: totalDeposited;
653:
654: ++lastEpoch;
655: lastRewardTimestamp = endTimestamp;
656: }
657:
658:
659: reward =
660: ((block.timestamp - lastRewardTimestamp) *
661: rewardAllocation(token, lastEpoch, rewardToken)) /
662: EPOCH_WINDOW;
663: accRewardPerShare =
664: accRewardPerShare +
665: (reward * (WAD_SQUARED)) /
666: totalDeposited;
667:
668: poolAccRewardPerShare[token][rewardToken] = accRewardPerShare;
669: }
670:
671:
672: poolLastRewardTimestamp[token] = block.timestamp;
673: }
The decimals()
function in an ERC20 token contract is used to specify how many decimal places the token can be divided into. However, it should be used with caution because not all ERC20 token contracts implement decimals()
, and the function isn't required by the ERC20 standard. Calling decimals()
on a contract that doesn't implement it will result in a runtime error. Moreover, even when implemented, the returned value can be manipulated or artificially set, which may cause unexpected behavior. Therefore, always verify the decimal count independently if precision is crucial for your contract logic. When interacting with other ERC20 tokens, consider implementing safeguards or checks to handle potential errors from calling decimals()
.
Num of instances: 23
Click to show findings
['104']
104: strategyData.decimalsA = 10 ** IERC20(strategyData.token0).decimals(); // <= FOUND
['105']
105: strategyData.decimalsB = 10 ** IERC20(strategyData.token1).decimals(); // <= FOUND
['173']
173: data.decimals0 = IERC20(data.token0).decimals(); // <= FOUND
['174']
174: data.decimals1 = IERC20(data.token1).decimals(); // <= FOUND
['129']
129: paymentTokenDecimals = IERC20(paymentTokenAddress).decimals(); // <= FOUND
['215']
215:
216: data.quoteTokenDecimals = ERC20(asset).decimals(); // <= FOUND
['220']
220: data.baseTokenDecimals = ERC20(data.baseToken).decimals(); // <= FOUND
['918']
918: return IERC20(underlying).decimals(); // <= FOUND
['103']
103:
107: function decimals() public view virtual override(ERC20) returns (uint8) { // <= FOUND
['160']
160: _feeTokenUnit = 10 ** IERC20(feeToken).decimals(); // <= FOUND
['292']
292:
293:
294: uint256 feeTokenRequiredForOTC = (
295: ((priceSwap * amountToOTC * _feeTokenUnit) / priceFeeToken)
296: ) / 10 ** IERC20(tokenToOTC).decimals(); // <= FOUND
['218']
218: _priceUnit[token] = WAD * 10 ** IERC20(token).decimals(); // <= FOUND
['1596']
1596:
1597:
1598: uint256 amountAdjusted = (debtAmount *
1599: (10 ** IERC20(collateralToken).decimals())) / // <= FOUND
1600: (10 ** IERC20(debtToken).decimals()); // <= FOUND
['78']
78: paymentTokenDecimals = ERC20(paymentToken_).decimals(); // <= FOUND
['228']
228: data.baseDecimals = ERC20(asset).decimals(); // <= FOUND
['229']
229: data.quoteDecimals = ERC20(token1).decimals(); // <= FOUND
['233']
233: data.quoteDecimals = ERC20(token0).decimals(); // <= FOUND
['57']
57:
58: uint256 swapAmount = _optimalDeposit(
59: factory,
60: lpToken,
61: amount0,
62: r0,
63: r1,
64: 10 ** ERC20(token0).decimals(), // <= FOUND
65: 10 ** ERC20(token1).decimals(), // <= FOUND
66: stable
67: );
['99']
99:
100: uint256 swapAmount = _optimalDeposit(
101: factory,
102: lpToken,
103: amount1,
104: r1,
105: r0,
106: 10 ** ERC20(token1).decimals(), // <= FOUND
107: 10 ** ERC20(token0).decimals(), // <= FOUND
108: stable
109: );
['155']
155: data.poolDecimals = pool.decimals(); // <= FOUND
['68']
68: return IChainlink(underlyingAssetAggregator()).decimals(); // <= FOUND
['107']
107: _decimals = asset_.decimals(); // <= FOUND
['167']
167:
168:
169: data.decimals = feedAggregator.decimals(); // <= FOUND
Minting tokens to the zero address in Solidity is a potential pitfall that should be carefully guarded against. The zero address (0x0) is generally used as a default value and represents an uninitialized or null address. Minting tokens to this address effectively burns them, making them inaccessible and permanently removing them from the total supply. This could lead to unintended token loss if performed accidentally. To prevent this, it's important to include a check in the minting function to ensure that the target address is not the zero address. Using a library like OpenZeppelin's Address
can provide utility functions like requireNonZero
, which simplifies this check and enhances the security of the minting function.
Num of instances: 6
Click to show findings
['371']
371: function mint(
372: uint256 shares,
373: address receiver
374: ) public override nonReentrant returns (uint256 assets) {
375: assets = _mint(shares, receiver);
376: }
['142']
142: function _mint(
143: uint256 shares,
144: address receiver
145: ) internal virtual returns (uint256 assets) {}
['320']
320: function _mint(
321: uint256 shares,
322: address receiver
323: ) internal override returns (uint256 assets) {
324: if (shares == 0) {
325: revert CTokenCompounding__ZeroShares();
326: }
327:
328:
329:
330: marketManager.canMint(address(this));
331:
332:
333: uint256 pending = _calculatePendingRewards();
334: uint256 ta = _totalAssets + pending;
335:
336:
337: assets = _previewMint(shares, ta);
338:
339:
340: _processDeposit(msg.sender, receiver, assets, shares, ta, pending);
341:
342: _gaugePool().deposit(address(this), receiver, shares);
343: }
['142']
142: function _mint(
143: uint256 shares,
144: address receiver
145: ) internal override returns (uint256 assets) {
146: if (shares == 0) {
147: revert CTokenPrimitive__ZeroShares();
148: }
149:
150:
151:
152: marketManager.canMint(address(this));
153:
154:
155: uint256 ta = _totalAssets;
156:
157:
158: assets = _previewMint(shares, ta);
159:
160:
161: _processDeposit(msg.sender, receiver, assets, shares, ta);
162:
163: _gaugePool().deposit(address(this), receiver, shares);
164: }
['1149']
1149: function _mint(
1150: address minter,
1151: address recipient,
1152: uint256 amount
1153: ) internal {
1154:
1155: accrueInterest();
1156:
1157:
1158: marketManager.canMint(address(this));
1159:
1160:
1161: uint256 er = exchangeRateCached();
1162:
1163:
1164: SafeTransferLib.safeTransferFrom(
1165: underlying,
1166: minter,
1167: address(this),
1168: amount
1169: );
1170:
1171:
1172: uint256 tokens = (amount * WAD) / er;
1173:
1174:
1175: unchecked {
1176: totalSupply = totalSupply + tokens;
1177:
1178: balanceOf[recipient] = balanceOf[recipient] + tokens;
1179: }
1180:
1181:
1182: _gaugePool().deposit(address(this), recipient, tokens);
1183:
1184: emit Transfer(address(0), recipient, tokens);
1185: }
['393']
393: function mint(uint256 shares, address to) public virtual returns (uint256 assets) {
394: if (shares > maxMint(to)) _revert(0x6a695959);
395: assets = previewMint(shares);
396: _deposit(msg.sender, to, assets, shares);
397: }
When settings fees state variables, ensure there a require checks in place to prevent incorrect values from being set. This is particularly important when dealing with fee values as without checks fees can be set to 100%
Num of instances: 1
Click to show findings
['52']
52: function setExitFee(uint256 newExitFee) external {
53: _checkElevatedPermissions();
54: _setExitFee(newExitFee);
55: }
Dividing by large numbers in Solidity can cause a loss of precision due to the language's inherent integer division behavior. Solidity does not support floating-point arithmetic, and as a result, division between integers yields an integer result, truncating any fractional part. When dividing by a large number, the resulting value may become significantly smaller, leading to a loss of precision, as the fractional part is discarded.
Num of instances: 40
Click to show findings
['212']
212: function _parseData(
213: AdaptorData memory data,
214: bool inUSD
215: ) internal view returns (PriceReturnData memory pData) {
216: uint256 price = _extractPrice(data.symbolHash);
217:
218:
219: uint256 quoteDecimals = data.decimals;
220: if (quoteDecimals != 18) {
221:
222:
223: if (quoteDecimals < 18) {
224: price = price * (10 ** (18 - quoteDecimals));
225: } else {
226:
227:
228: price = price / (10 ** (quoteDecimals - 18));
229: }
230: }
231:
232: pData.hadError = _verifyData(price, data.max);
233:
234: if (!pData.hadError) {
235: pData.inUSD = inUSD;
236: pData.price = uint240(price);
237: }
238: }
['217']
217: function _getFairPrice(
218: uint256 reserve0,
219: uint256 reserve1,
220: uint256 price0,
221: uint256 price1,
222: uint256 totalSupply
223: ) internal pure returns (uint256) {
224:
225: uint256 sqrtReserve = FixedPointMathLib.sqrt(
226: FixedPointMathLib.sqrt(reserve0 * reserve1) *
227: FixedPointMathLib.sqrt(
228: reserve0 * reserve0 + reserve1 * reserve1
229: )
230: );
231: uint256 ratio = ((1e18) * price0) / price1; // <= FOUND
232: uint256 sqrtPrice = FixedPointMathLib.sqrt(
233: FixedPointMathLib.sqrt((1e18) * ratio) *
234: FixedPointMathLib.sqrt(1e36 + ratio * ratio)
235: );
236: return
237: ((((1e18) * sqrtReserve) / sqrtPrice) * price0 * 2) / totalSupply;
238: }
['227']
227: function balanceOfUnderlyingSafe(
228: address account
229: ) external view returns (uint256) {
230: return ((convertToAssetsSafe(WAD) * balanceOf(account)) / WAD); // <= FOUND
231: }
['236']
236: function balanceOfUnderlying(
237: address account
238: ) external view returns (uint256) {
239: return ((convertToAssets(WAD) * balanceOf(account)) / WAD); // <= FOUND
240: }
['204']
204: function currentEpoch(uint256 time) external view returns (uint256) { // <= FOUND
205: if (time < genesisEpoch) {
206: return 0;
207: }
208:
209: return ((time - genesisEpoch) / EPOCH_DURATION);
210: }
['463']
463: function _calculateRewards(
464: address user,
465: uint256 epochs
466: ) internal returns (uint256) {
467: uint256 startEpoch = userNextClaimIndex[user];
468: uint256 rewards;
469:
470: for (uint256 i; i < epochs; ) {
471: unchecked {
472: rewards += _calculateRewardsForEpoch(user, startEpoch + i++);
473: }
474: }
475:
476:
477:
478: unchecked {
479: userNextClaimIndex[user] += epochs;
480: }
481:
482:
483: return rewards / WAD;
484: }
['249']
249: function _parseData(
250: AdaptorData memory data,
251: bool inUSD
252: ) internal view returns (PriceReturnData memory pData) {
253: pData.inUSD = inUSD;
254: if (!IOracleRouter(centralRegistry.oracleRouter()).isSequencerValid()) {
255: pData.hadError = true;
256: return pData;
257: }
258:
259: (, int256 price, , uint256 updatedAt, ) = IChainlink(data.aggregator)
260: .latestRoundData();
261:
262:
263: if (price <= 0) {
264: pData.hadError = true;
265: return pData;
266: }
267:
268: uint256 newPrice = (uint256(price) * WAD) / (10 ** data.decimals);
269:
270: pData.price = uint240(newPrice);
271: pData.hadError = _verifyData(
272: uint256(price),
273: updatedAt,
274: data.max,
275: data.min,
276: data.heartbeat
277: );
278: }
['178']
178: function claim() external returns (uint256 amount) { // <= FOUND
179: SaleStatus saleStatus = currentStatus();
180: if (saleStatus == SaleStatus.NotStarted) {
181: revert CurvanceDAOLBP__NotStarted();
182: }
183: if (saleStatus == SaleStatus.InSale) {
184: revert CurvanceDAOLBP__InSale();
185: }
186:
187: uint256 payAmount = userCommitted[msg.sender];
188: userCommitted[msg.sender] = 0;
189:
190: uint256 price = currentPrice();
191: uint256 adjustedPayAmount = _adjustDecimals(
192: payAmount,
193: paymentTokenDecimals,
194: 18
195: );
196: amount = (adjustedPayAmount * WAD) / price; // <= FOUND
197:
198: SafeTransferLib.safeTransfer(cve, msg.sender, amount);
199:
200: emit Claimed(msg.sender, amount);
201: }
['232']
232: function softCap() public view returns (uint256) { // <= FOUND
233: return (softPriceInpaymentToken * cveAmountForSale) / WAD; // <= FOUND
234: }
['392']
392: function repayWithBadDebt(
393: address liquidator,
394: address account,
395: uint256 repayRatio
396: ) external nonReentrant {
397:
398:
399:
400:
401:
402: if (msg.sender != address(marketManager)) {
403: _revert(_UNAUTHORIZED_SELECTOR);
404: }
405:
406:
407:
408:
409:
410:
411: uint256 accountDebt = debtBalanceCached(account);
412: uint256 repayAmount = (accountDebt * repayRatio) / WAD; // <= FOUND
413:
414:
415:
416:
417:
418:
419:
420: SafeTransferLib.safeTransferFrom(
421: underlying,
422: liquidator,
423: address(this),
424: repayAmount
425: );
426:
427:
428:
429: delete _debtOf[account].principal;
430: totalBorrows -= accountDebt;
431:
432: emit Repay(liquidator, account, repayAmount);
433: emit BadDebtRecognized(liquidator, account, accountDebt - repayAmount);
434: }
['472']
472: function redeem(uint256 tokens) external nonReentrant { // <= FOUND
473:
474: accrueInterest();
475:
476:
477:
478: marketManager.canRedeem(address(this), msg.sender, tokens);
479:
480: _redeem(
481: msg.sender,
482: msg.sender,
483: tokens,
484: (exchangeRateCached() * tokens) / WAD
485: );
486: }
['497']
497: function redeemFor(
498: address account,
499: address recipient,
500: uint256 tokens
501: ) external nonReentrant {
502: if (!_checkIsDelegate(account, msg.sender)) {
503: _revert(_UNAUTHORIZED_SELECTOR);
504: }
505:
506:
507: accrueInterest();
508:
509:
510:
511: marketManager.canRedeem(address(this), account, tokens);
512:
513: _redeem(
514: account,
515: recipient,
516: tokens,
517: (exchangeRateCached() * tokens) / WAD
518: );
519: }
['532']
532: function redeemUnderlyingForPositionFolding(
533: address account,
534: uint256 amount,
535: bytes calldata params
536: ) external nonReentrant {
537: if (msg.sender != marketManager.positionFolding()) {
538: _revert(_UNAUTHORIZED_SELECTOR);
539: }
540:
541:
542: accrueInterest();
543:
544: _redeem(
545: account,
546: msg.sender,
547: (amount * WAD) / exchangeRateCached(),
548: amount
549: );
550:
551: IPositionFolding(msg.sender).onRedeem(
552: address(this),
553: account,
554: amount,
555: params
556: );
557:
558:
559:
560: marketManager.canRedeem(address(this), account, 0);
561: }
['594']
594: function depositReserves(uint256 amount) external nonReentrant { // <= FOUND
595: _checkDaoPermissions();
596:
597:
598: accrueInterest();
599:
600:
601: uint256 tokens = (amount * WAD) / exchangeRateCached();
602:
603:
604: SafeTransferLib.safeTransferFrom(
605: underlying,
606: msg.sender,
607: address(this),
608: amount
609: );
610:
611:
612: address daoAddress = centralRegistry.daoAddress();
613:
614:
615: _gaugePool().deposit(address(this), daoAddress, tokens);
616:
617:
618: totalReserves = totalReserves + tokens;
619: }
['627']
627: function withdrawReserves(uint256 amount) external nonReentrant { // <= FOUND
628: _checkDaoPermissions();
629:
630:
631: accrueInterest();
632:
633:
634: if (marketUnderlyingHeld() < amount) {
635: revert DToken__InsufficientUnderlyingHeld();
636: }
637:
638:
639:
640: uint256 tokens = (amount * WAD) / exchangeRateCached();
641:
642:
643: totalReserves = totalReserves - tokens;
644:
645:
646: address daoAddress = centralRegistry.daoAddress();
647:
648:
649: _gaugePool().withdraw(address(this), daoAddress, tokens);
650:
651: SafeTransferLib.safeTransfer(underlying, daoAddress, amount);
652: }
['659']
659: function processWithdrawReserves() external { // <= FOUND
660:
661: if (msg.sender != address(centralRegistry)) {
662: _revert(_UNAUTHORIZED_SELECTOR);
663: }
664:
665:
666: accrueInterest();
667:
668: uint256 totalReservesCached = totalReserves;
669: uint256 amount = (totalReservesCached * exchangeRateCached()) / WAD; // <= FOUND
670:
671:
672: if (marketUnderlyingHeld() < amount) {
673: revert DToken__InsufficientUnderlyingHeld();
674: }
675:
676:
677: delete totalReserves;
678:
679:
680: address daoAddress = centralRegistry.daoAddress();
681:
682: _gaugePool().withdraw(address(this), daoAddress, totalReservesCached);
683:
684:
685: SafeTransferLib.safeTransfer(underlying, daoAddress, amount);
686: }
['764']
764: function balanceOfUnderlyingSafe(
765: address account
766: ) external returns (uint256) {
767: return ((exchangeRateWithUpdateSafe() * balanceOf[account]) / WAD); // <= FOUND
768: }
['1149']
1149: function _mint(
1150: address minter,
1151: address recipient,
1152: uint256 amount
1153: ) internal {
1154:
1155: accrueInterest();
1156:
1157:
1158: marketManager.canMint(address(this));
1159:
1160:
1161: uint256 er = exchangeRateCached();
1162:
1163:
1164: SafeTransferLib.safeTransferFrom(
1165: underlying,
1166: minter,
1167: address(this),
1168: amount
1169: );
1170:
1171:
1172: uint256 tokens = (amount * WAD) / er;
1173:
1174:
1175: unchecked {
1176: totalSupply = totalSupply + tokens;
1177:
1178: balanceOf[recipient] = balanceOf[recipient] + tokens;
1179: }
1180:
1181:
1182: _gaugePool().deposit(address(this), recipient, tokens);
1183:
1184: emit Transfer(address(0), recipient, tokens);
1185: }
['363']
363: function getBorrowRatePerYear(
364: uint256 cash,
365: uint256 borrows,
366: uint256 reserves
367: ) external view returns (uint256) {
368: return
369: _SECONDS_PER_YEAR *
370: (getBorrowRate(cash, borrows, reserves) / INTEREST_COMPOUND_RATE);
371: }
['436']
436: function getPredictedBorrowRate(
437: uint256 cash,
438: uint256 borrows,
439: uint256 reserves
440: ) public view returns (uint256) {
441: uint256 util = utilizationRate(cash, borrows, reserves);
442: RatesConfiguration memory config = ratesConfig;
443: uint256 vertexPoint = config.vertexStartingPoint;
444:
445:
446:
447: if (util <= vertexPoint) {
448: return _getBaseInterestRate(util);
449: }
450:
451: if (vertexMultiplier() == WAD && util < config.increaseThreshold) {
452: return (_getVertexInterestRate(util - vertexPoint) +
453: _getBaseInterestRate(vertexPoint));
454: }
455:
456: uint256 vertexInterestRate = ratesConfig.vertexInterestRate;
457: uint256 newMultiplier = _updateForAboveVertex(config, util);
458:
459: return (util * vertexInterestRate * newMultiplier) / WAD_SQUARED;
460: }
['496']
496: function getSupplyRate(
497: uint256 cash,
498: uint256 borrows,
499: uint256 reserves,
500: uint256 interestFee
501: ) public view returns (uint256) {
502:
503: uint256 rateToPool = (getBorrowRate(cash, borrows, reserves) *
504: (WAD - interestFee)) / WAD;
505:
506:
507: return (utilizationRate(cash, borrows, reserves) * rateToPool) / WAD;
508: }
['536']
536: function _getBaseInterestRate(
537: uint256 util
538: ) internal view returns (uint256) {
539: return (util * ratesConfig.baseInterestRate) / WAD; // <= FOUND
540: }
['696']
696: function _updateForAboveVertex(
697: RatesConfiguration memory config,
698: uint256 util
699: ) internal view returns (uint256) {
700: uint256 currentMultiplier = vertexMultiplier();
701:
702: uint256 decay = (currentMultiplier * config.decayRate) / WAD;
703: uint256 newMultiplier;
704:
705: if (util <= config.increaseThreshold) {
706: newMultiplier = currentMultiplier - decay;
707:
708:
709: return newMultiplier < WAD ? WAD : newMultiplier;
710: }
711:
712:
713:
714:
715: newMultiplier = _getPositiveCFactorResult(
716: currentMultiplier,
717: config.adjustmentVelocity,
718: decay,
719: util,
720: config.increaseThreshold,
721: config.increaseThresholdMax
722: );
723:
724:
725:
726:
727: if (newMultiplier < WAD) {
728: return WAD;
729: }
730:
731:
732:
733: return
734: newMultiplier < config.vertexMultiplierMax
735: ? newMultiplier
736: : config.vertexMultiplierMax;
737: }
['758']
758: function _updateForBelowVertex(
759: RatesConfiguration memory config,
760: uint256 util
761: ) internal view returns (uint256) {
762: uint256 currentMultiplier = vertexMultiplier();
763:
764: uint256 decay = (currentMultiplier * config.decayRate) / WAD;
765: uint256 newMultiplier;
766:
767: if (util <= config.decreaseThresholdMax) {
768:
769:
770:
771:
772: newMultiplier =
773: ((currentMultiplier * WAD) /
774: (WAD + config.adjustmentVelocity)) -
775: decay;
776:
777:
778: return newMultiplier < WAD ? WAD : newMultiplier;
779: }
780:
781:
782:
783:
784: newMultiplier = _getNegativeCFactorResult(
785: currentMultiplier,
786: config.adjustmentVelocity,
787: decay,
788: util,
789: config.decreaseThreshold,
790: config.decreaseThresholdMax
791: );
792:
793:
794:
795: return newMultiplier < WAD ? WAD : newMultiplier;
796: }
['821']
821: function _getPositiveCFactorResult(
822: uint256 multiplier,
823: uint256 adjustmentVelocity,
824: uint256 decay,
825: uint256 current,
826: uint256 start,
827: uint256 end
828: ) internal pure returns (uint256) {
829:
830:
831:
832:
833: uint256 cFactor = ((current - start) * WAD) / (end - start);
834:
835:
836:
837: cFactor = WAD_SQUARED + (cFactor * adjustmentVelocity);
838:
839:
840:
841: return ((multiplier * cFactor) / WAD_SQUARED) - decay;
842: }
['867']
867: function _getNegativeCFactorResult(
868: uint256 multiplier,
869: uint256 adjustmentVelocity,
870: uint256 decay,
871: uint256 current,
872: uint256 start,
873: uint256 end
874: ) internal pure returns (uint256) {
875:
876:
877:
878: uint256 cFactor = ((start - current) * WAD) / (start - end);
879:
880:
881:
882: cFactor = WAD_SQUARED + (cFactor * adjustmentVelocity);
883:
884:
885:
886: return ((multiplier * WAD_SQUARED) / cFactor) - decay;
887: }
['260']
260: function executeOTC(
261: address tokenToOTC,
262: uint256 amountToOTC
263: ) external nonReentrant {
264: _checkDaoPermissions();
265:
266:
267: if (rewardTokenInfo[tokenToOTC].forOTC < 2) {
268: revert FeeAccumulator__TokenIsNotEarmarked();
269: }
270:
271:
272: IOracleRouter oracleRouter = IOracleRouter(
273: centralRegistry.oracleRouter()
274: );
275:
276: (uint256 priceSwap, uint256 errorCodeSwap) = oracleRouter.getPrice(
277: tokenToOTC,
278: true,
279: true
280: );
281: (uint256 priceFeeToken, uint256 errorCodeFeeToken) = oracleRouter
282: .getPrice(feeToken, true, true);
283:
284:
285: if (errorCodeFeeToken == 2 || errorCodeSwap == 2) {
286: revert FeeAccumulator__ConfigurationError();
287: }
288:
289: address daoAddress = centralRegistry.daoAddress();
290:
291:
292: uint256 feeTokenRequiredForOTC = (
293: ((priceSwap * amountToOTC * _feeTokenUnit) / priceFeeToken)
294: ) / 10 ** IERC20(tokenToOTC).decimals();
295:
296: SafeTransferLib.safeTransferFrom(
297: feeToken,
298: msg.sender,
299: address(this),
300: feeTokenRequiredForOTC
301: );
302:
303: SafeTransferLib.safeTransfer(
304: feeToken,
305: oneBalanceFeeManager,
306: (feeTokenRequiredForOTC * vaultCompoundFee()) / vaultYieldFee()
307: );
308:
309:
310: SafeTransferLib.safeTransfer(tokenToOTC, daoAddress, amountToOTC);
311: }
['748']
748: function _executeEpochFeeRouter(
749: ChainData memory chainData,
750: uint256 numChains,
751: uint256 epoch
752: ) internal returns (uint256) {
753: IProtocolMessagingHub messagingHub = IProtocolMessagingHub(
754: centralRegistry.protocolMessagingHub()
755: );
756:
757: IVeCVE veCVE = IVeCVE(centralRegistry.veCVE());
758: uint256 lockedTokens = (veCVE.chainPoints() -
759: veCVE.chainUnlocksByEpoch(epoch));
760:
761: uint256 totalLockedTokens = lockedTokens;
762:
763:
764:
765: for (uint256 i; i < numChains; ) {
766: totalLockedTokens += crossChainLockData[i].lockAmount;
767:
768: unchecked {
769: ++i;
770: }
771: }
772:
773: uint256 feeTokenBalance = IERC20(feeToken).balanceOf(address(this));
774:
775:
776:
777: SafeTransferLib.safeTransfer(
778: feeToken,
779: oneBalanceFeeManager,
780: (feeTokenBalance * vaultCompoundFee()) /
781: centralRegistry.protocolHarvestFee()
782: );
783:
784: feeTokenBalance = IERC20(feeToken).balanceOf(address(this));
785:
786: uint256 chainId;
787: uint256 feeTokenBalanceForChain;
788:
789:
790:
791: for (uint256 i; i < numChains; ) {
792: chainId = crossChainLockData[i].chainId;
793: chainData = centralRegistry.supportedChainData(chainId);
794:
795:
796:
797:
798:
799:
800:
801: feeTokenBalanceForChain =
802: (((feeTokenBalance * WAD) / totalLockedTokens) *
803: crossChainLockData[i].lockAmount) /
804: WAD;
805:
806: messagingHub.sendFees(
807: chainId,
808: chainData.messagingHub,
809: feeTokenBalanceForChain
810: );
811:
812: unchecked {
813: ++i;
814: }
815: }
816:
817:
818:
819:
820:
821:
822:
823:
824: feeTokenBalanceForChain =
825: (((feeTokenBalance * WAD) / totalLockedTokens) * lockedTokens) /
826: WAD;
827: uint256 epochRewardsPerCVE = (feeTokenBalance * WAD) /
828: totalLockedTokens;
829:
830: ICVELocker locker = ICVELocker(centralRegistry.cveLocker());
831:
832:
833:
834: if (locker.isShutdown() == 2) {
835: SafeTransferLib.safeTransfer(
836: feeToken,
837: centralRegistry.daoAddress(),
838: feeTokenBalanceForChain
839: );
840: return epochRewardsPerCVE;
841: }
842:
843:
844: SafeTransferLib.safeTransfer(
845: feeToken,
846: address(locker),
847: feeTokenBalanceForChain
848: );
849: ICVELocker(locker).recordEpochRewards(epochRewardsPerCVE);
850:
851: return epochRewardsPerCVE;
852: }
['145']
145: function epochOfTimestamp(
146: uint256 timestamp
147: ) public view returns (uint256) {
148: _checkGaugeHasStarted();
149: return (timestamp - startTime) / EPOCH_WINDOW; // <= FOUND
150: }
['670']
670: function _assetValue(
671: uint256 amount,
672: uint256 price,
673: uint256 decimals
674: ) internal pure returns (uint256) {
675: return (amount * price) / (10 ** decimals); // <= FOUND
676: }
['687']
687: function _redemptionValue(
688: uint256 amount,
689: uint256 exchangeRate,
690: uint256 price,
691: uint256 decimals,
692: uint256 collRatio
693: ) internal pure returns (uint256) {
694: uint256 assetValue = _assetValue(
695: (amount * exchangeRate) / WAD,
696: price,
697: decimals
698: );
699:
700:
701: return ((assetValue * collRatio) / WAD);
702: }
['715']
715: function _liquidityValue(
716: uint256 liqForBorrowPrior,
717: uint256 posted,
718: uint256 exchangeRate,
719: uint256 price,
720: uint256 decimals,
721: uint256 collRatio
722: ) internal pure returns (uint256) {
723: uint256 assetValue = _assetValue(
724: ((posted * exchangeRate) / WAD),
725: price,
726: decimals
727: );
728:
729: return (liqForBorrowPrior + (assetValue * collRatio) / WAD);
730: }
['744']
744: function _addLiquidationValues(
745: AccountSnapshot memory snapshot,
746: address account,
747: uint256 price,
748: uint256 softSumPrior,
749: uint256 hardSumPrior
750: ) internal view returns (uint256, uint256) {
751: uint256 assetValue = _assetValue(
752: ((tokenData[snapshot.asset].accountPositions[account].collateralPosted *
753: snapshot.exchangeRate) / WAD),
754: price,
755: snapshot.decimals
756: ) * WAD;
757:
758: return (
759: softSumPrior +
760: (assetValue / tokenData[snapshot.asset].collReqSoft),
761: hardSumPrior + (assetValue / tokenData[snapshot.asset].collReqHard)
762: );
763: }
['856']
856: function _convertETHUSD(
857: uint240 currentPrice,
858: uint256 conversionRate,
859: bool currentlyInUSD
860: ) internal pure returns (uint256) {
861: if (!currentlyInUSD) {
862:
863: return (currentPrice * conversionRate) / WAD;
864: }
865:
866: return (currentPrice * WAD) / conversionRate;
867: }
['877']
877: function _calculateLowerPrice(
878: uint256 a,
879: uint256 b
880: ) internal view returns (uint256, uint256) {
881: if (a <= b) {
882:
883:
884: if (((a * cautionDivergenceFlag) / DENOMINATOR) < b) {
885:
886:
887:
888: if (((a * badSourceDivergenceFlag) / DENOMINATOR) < b) {
889: return (a, BAD_SOURCE);
890: }
891:
892:
893:
894:
895: return (a, CAUTION);
896: }
897:
898: return (a, NO_ERROR);
899: }
900:
901:
902:
903: if (((b * cautionDivergenceFlag) / DENOMINATOR) < a) {
904:
905:
906:
907: if (((b * badSourceDivergenceFlag) / DENOMINATOR) < a) {
908: return (b, BAD_SOURCE);
909: }
910:
911:
912:
913:
914: return (b, CAUTION);
915: }
916:
917: return (b, NO_ERROR);
918: }
['928']
928: function _calculateHigherPrice(
929: uint256 a,
930: uint256 b
931: ) internal view returns (uint256, uint256) {
932: if (a >= b) {
933:
934:
935: if (((b * cautionDivergenceFlag) / DENOMINATOR) < a) {
936:
937:
938:
939: if (((b * badSourceDivergenceFlag) / DENOMINATOR) < a) {
940: return (a, BAD_SOURCE);
941: }
942:
943:
944:
945:
946: return (a, CAUTION);
947: }
948:
949: return (a, NO_ERROR);
950: }
951:
952:
953:
954: if (((a * cautionDivergenceFlag) / DENOMINATOR) < b) {
955:
956:
957:
958: if (((a * badSourceDivergenceFlag) / DENOMINATOR) < b) {
959: return (b, BAD_SOURCE);
960: }
961:
962:
963:
964:
965: return (b, CAUTION);
966: }
967:
968: return (b, NO_ERROR);
969: }
['994']
994: function currentEpoch(uint256 time) public view returns (uint256) { // <= FOUND
995: if (time < genesisEpoch) {
996: return 0;
997: }
998:
999:
1000: return ((time - genesisEpoch) / EPOCH_DURATION);
1001: }
['1040']
1040: function getVotesForSingleLockForTime(
1041: address user,
1042: uint256 lockIndex,
1043: uint256 time,
1044: uint256 currentLockBoost
1045: ) public view returns (uint256) {
1046: Lock storage lock = userLocks[user][lockIndex];
1047:
1048: if (lock.unlockTime < time) {
1049: return 0;
1050: }
1051:
1052: if (lock.unlockTime == CONTINUOUS_LOCK_VALUE) {
1053: unchecked {
1054: return ((lock.amount * currentLockBoost) / 10000);
1055: }
1056: }
1057:
1058:
1059:
1060: return
1061: (lock.amount * ((lock.unlockTime - time) / EPOCH_DURATION)) /
1062: LOCK_DURATION_EPOCHS;
1063: }
['1408']
1408: function _getUnlockPenalty(
1409: uint256 amount,
1410: uint256 penalty,
1411: uint256 unlockTime
1412: ) internal view returns (uint256) {
1413:
1414:
1415:
1416: return
1417: (amount *
1418: ((penalty * (LOCK_DURATION - (unlockTime - block.timestamp))) /
1419: LOCK_DURATION)) / WAD;
1420: }
['224']
224: function _optimalDeposit(
225: address factory,
226: address lpToken,
227: uint256 amount0,
228: uint256 reserve0,
229: uint256 reserve1,
230: uint256 decimals0,
231: uint256 decimals1,
232: bool stable
233: ) internal view returns (uint256) {
234:
235: uint256 swapFee = IVeloPairFactory(factory).getFee(lpToken, stable);
236: uint256 a;
237:
238:
239: if (stable) {
240: a = (((amount0 * 10000) / (10000 - swapFee)) * 1e18) / decimals0; // <= FOUND
241:
242: uint256 x = (reserve0 * 1e18) / decimals0;
243: uint256 y = (reserve1 * 1e18) / decimals1; // <= FOUND
244: uint256 x2 = (x * x) / 1e18;
245: uint256 y2 = (y * y) / 1e18;
246: uint256 p = (y * (((x2 * 3 + y2) * 1e18) / (y2 * 3 + x2))) / x; // <= FOUND
247:
248: uint256 num = a * y;
249: uint256 den = ((a + x) * p) / 1e18 + y;
250:
251: return ((num / den) * decimals0) / 1e18;
252: }
253:
254:
255: uint256 swapFeeFactor = 10000 - swapFee;
256:
257: a = (10000 + swapFeeFactor) * reserve0;
258: uint256 b = amount0 * 10000 * reserve0 * 4 * swapFeeFactor;
259: uint256 c = FixedPointMathLib.sqrt(a * a + b);
260: uint256 d = swapFeeFactor * 2;
261: return (c - a) / d; // <= FOUND
262:
263: }
In Solidity, constructors often take address parameters to initialize important components of a contract, such as owner or linked contracts. However, without a check, there's a risk that an address parameter could be mistakenly set to the zero address (0x0). This could occur due to a mistake or oversight during contract deployment. A zero address in a crucial role can cause serious issues, as it cannot perform actions like a normal address, and any funds sent to it are irretrievable. Therefore, it's crucial to include a zero address check in constructors to prevent such potential problems. If a zero address is detected, the constructor should revert the transaction.
Num of instances: 22
Click to show findings
['69']
67: constructor(
68: ICentralRegistry centralRegistry_,
69: IERC20 asset_, // <= FOUND
70: address marketManager_, // <= FOUND
71: IVeloGauge gauge,
72: IVeloPairFactory pairFactory,
73: IVeloRouter router
74: ) CTokenCompounding(centralRegistry_, asset_, marketManager_) {
75: if (block.chainid != 8453) {
76: revert AerodromeStableCToken__ChainIsNotSupported();
77: }
78:
79:
80: address _asset = asset(); // <= FOUND
81:
82:
83: if (gauge.stakingToken() != _asset) {
84: revert AerodromeStableCToken__StakingTokenIsNotAsset(
85: gauge.stakingToken()
86: );
87: }
88:
89:
90: if (!IVeloPool(_asset).stable()) {
91: revert AerodromeStableCToken__AssetIsNotStable();
92: }
93:
94:
95: strategyData.token0 = IVeloPool(_asset).token0();
96: strategyData.token1 = IVeloPool(_asset).token1();
97:
98:
99: if (strategyData.token1 == address(rewardToken)) {
100: strategyData.token1 = strategyData.token0;
101: strategyData.token0 = address(rewardToken);
102: }
103: strategyData.decimalsA = 10 ** IERC20(strategyData.token0).decimals();
104: strategyData.decimalsB = 10 ** IERC20(strategyData.token1).decimals();
105:
106: strategyData.gauge = gauge;
107: strategyData.router = router;
108: strategyData.pairFactory = pairFactory;
109:
110: isUnderlyingToken[strategyData.token0] = true;
111: isUnderlyingToken[strategyData.token1] = true;
112:
113: rewardTokenIsUnderlying = (address(rewardToken) ==
114: strategyData.token0 ||
115: address(rewardToken) == strategyData.token1);
116: }
['67']
65: constructor(
66: ICentralRegistry centralRegistry_,
67: IERC20 asset_, // <= FOUND
68: address marketManager_, // <= FOUND
69: IVeloGauge gauge,
70: IVeloPairFactory pairFactory,
71: IVeloRouter router
72: ) CTokenCompounding(centralRegistry_, asset_, marketManager_) {
73: if (block.chainid != 8453) {
74: revert AerodromeVolatileCToken__ChainIsNotSupported();
75: }
76:
77:
78: address _asset = asset(); // <= FOUND
79:
80:
81: if (gauge.stakingToken() != _asset) {
82: revert AerodromeVolatileCToken__StakingTokenIsNotAsset(
83: gauge.stakingToken()
84: );
85: }
86:
87:
88: if (IVeloPool(_asset).stable()) {
89: revert AerodromeVolatileCToken__AssetIsNotStable();
90: }
91:
92:
93: strategyData.token0 = IVeloPool(_asset).token0();
94: strategyData.token1 = IVeloPool(_asset).token1();
95:
96:
97: if (strategyData.token1 == address(rewardToken)) {
98: strategyData.token1 = strategyData.token0;
99: strategyData.token0 = address(rewardToken);
100: }
101: strategyData.gauge = gauge;
102: strategyData.router = router;
103: strategyData.pairFactory = pairFactory;
104:
105: isUnderlyingToken[strategyData.token0] = true;
106: isUnderlyingToken[strategyData.token1] = true;
107:
108: rewardTokenIsUnderlying = (address(rewardToken) ==
109: strategyData.token0 ||
110: address(rewardToken) == strategyData.token1);
111: }
['65']
63: constructor(
64: ICentralRegistry centralRegistry_,
65: IERC20 asset_, // <= FOUND
66: address marketManager_, // <= FOUND
67: uint256 pid_,
68: address rewarder_, // <= FOUND
69: address booster_ // <= FOUND
70: ) CTokenCompounding(centralRegistry_, asset_, marketManager_) {
71: strategyData.pid = pid_;
72: strategyData.booster = IBooster(booster_);
73:
74:
75: (address pidToken, , , address balRewards, , bool shutdown) = IBooster( // <= FOUND
76: booster_
77: ).poolInfo(strategyData.pid);
78:
79:
80:
81: if (pidToken != asset() || shutdown || balRewards != rewarder_) {
82: revert AuraCToken__InvalidVaultConfig();
83: }
84:
85: strategyData.rewarder = IBaseRewardPool(rewarder_);
86: strategyData.balancerVault = IBalancerVault(
87: IBalancerPool(pidToken).getVault()
88: );
89: strategyData.balancerPoolId = IBalancerPool(pidToken).getPoolId();
90:
91:
92:
93: strategyData.rewardTokens.push() = _BAL;
94:
95:
96: strategyData.rewardTokens.push() = _AURA;
97:
98: uint256 extraRewardsLength = IBaseRewardPool(rewarder_)
99: .extraRewardsLength();
100: for (uint256 i; i < extraRewardsLength; ) {
101: unchecked {
102: address rewardToken = IStashWrapper( // <= FOUND
103: IRewards(IBaseRewardPool(rewarder_).extraRewards(i++))
104: .rewardToken()
105: ).baseToken();
106:
107: if (rewardToken != _AURA && rewardToken != _BAL) {
108: strategyData.rewardTokens.push() = rewardToken;
109: }
110: }
111: }
112:
113:
114: (address[] memory queriedTokens, , ) = strategyData
115: .balancerVault
116: .getPoolTokens(strategyData.balancerPoolId);
117: strategyData.underlyingTokens = queriedTokens;
118:
119: uint256 numUnderlyingTokens = strategyData.underlyingTokens.length;
120: for (uint256 i; i < numUnderlyingTokens; ) {
121: unchecked {
122: isUnderlyingToken[strategyData.underlyingTokens[i++]] = true;
123: }
124: }
125: }
['30']
28: constructor(
29: ICentralRegistry centralRegistry_,
30: IERC20 asset_, // <= FOUND
31: address marketManager_ // <= FOUND
32: ) CTokenCompounding(
33: centralRegistry_,
34: asset_,
35: marketManager_
36: ) {
37: nativeYieldManager = IBlastCentralRegistry(address(centralRegistry_)).nativeYieldManager();
38:
39:
40:
41: CHAIN_YIELD_MANAGER.configureClaimableGas();
42: }
['101']
99: constructor(
100: ICentralRegistry centralRegistry_,
101: IERC20 asset_, // <= FOUND
102: address MarketManager_ // <= FOUND
103: ) Delegable(centralRegistry_) {
104: _asset = asset_;
105: _name = string.concat("Curvance collateralized ", asset_.name());
106: _symbol = string.concat("c", asset_.symbol());
107: _decimals = asset_.decimals();
108:
109: if (
110: !ERC165Checker.supportsInterface(
111: address(centralRegistry_),
112: type(ICentralRegistry).interfaceId
113: )
114: ) {
115: revert CTokenBase__InvalidCentralRegistry();
116: }
117:
118:
119: if (!centralRegistry.isMarketManager(MarketManager_)) {
120: revert CTokenBase__InvalidMarketManager();
121: }
122:
123:
124: marketManager = IMarketManager(MarketManager_);
125:
126:
127:
128: if (asset_.totalSupply() >= type(uint232).max) {
129: revert CTokenBase__UnderlyingAssetTotalSupplyExceedsMaximum();
130: }
131: }
['37']
35: constructor(
36: ICentralRegistry centralRegistry_,
37: IERC20 asset_, // <= FOUND
38: address marketManager_, // <= FOUND
39: uint256 exitFee_
40: ) CTokenCompounding(centralRegistry_, asset_, marketManager_) {
41: _setExitFee(exitFee_);
42: }
['21']
21: constructor(address _target) { // <= FOUND
22: target = _target;
23: }
['91']
89: constructor(
90: ICentralRegistry centralRegistry_,
91: address marketManager_, // <= FOUND
92: address WETH_ // <= FOUND
93: ) {
94: if (
95: !ERC165Checker.supportsInterface(
96: address(centralRegistry_),
97: type(ICentralRegistry).interfaceId
98: )
99: ) {
100: revert ComplexZapper__InvalidCentralRegistry();
101: }
102:
103: centralRegistry = centralRegistry_;
104:
105:
106:
107: if (!centralRegistry.isMarketManager(marketManager_)) {
108: revert ComplexZapper__InvalidMarketManager();
109: }
110:
111: marketManager = IMarketManager(marketManager_);
112: WETH = WETH_;
113: }
['67']
65: constructor(
66: ICentralRegistry centralRegistry_,
67: IERC20 asset_, // <= FOUND
68: address marketManager_, // <= FOUND
69: uint256 pid_,
70: address rewarder_, // <= FOUND
71: address booster_ // <= FOUND
72: ) CTokenCompounding(centralRegistry_, asset_, marketManager_) {
73:
74:
75: if (pid_ <= 176) {
76: revert Convex2PoolCToken__UnsafePool();
77: }
78:
79: strategyData.pid = pid_;
80: strategyData.booster = IBooster(booster_);
81:
82:
83: (address pidToken, , , address crvRewards, , bool shutdown) = IBooster( // <= FOUND
84: booster_
85: ).poolInfo(strategyData.pid);
86:
87:
88:
89: if (
90: pidToken != address(asset_) || shutdown || crvRewards != rewarder_
91: ) {
92: revert Convex2PoolCToken__InvalidVaultConfig();
93: }
94:
95: strategyData.curvePool = ICurveFi(pidToken); // <= FOUND
96:
97: uint256 coinsLength;
98: address token; // <= FOUND
99:
100:
101: while (true) {
102: try ICurveFi(pidToken).coins(coinsLength) {
103: ++coinsLength;
104: } catch {
105: break;
106: }
107: }
108:
109:
110: if (coinsLength != 2) {
111: revert Convex2PoolCToken__InvalidCoinLength();
112: }
113:
114: strategyData.rewarder = IBaseRewardPool(rewarder_);
115:
116:
117:
118: reQueryRewardTokens();
119:
120:
121: strategyData.underlyingTokens = new address[](coinsLength);
122: for (uint256 i; i < coinsLength; ) {
123: token = ICurveFi(pidToken).coins(i);
124: strategyData.underlyingTokens[i] = token;
125: isUnderlyingToken[token] = true;
126:
127: unchecked {
128: ++i;
129: }
130: }
131: }
['67']
65: constructor(
66: ICentralRegistry centralRegistry_,
67: IERC20 asset_, // <= FOUND
68: address marketManager_, // <= FOUND
69: uint256 pid_,
70: address rewarder_, // <= FOUND
71: address booster_ // <= FOUND
72: ) CTokenCompounding(centralRegistry_, asset_, marketManager_) {
73:
74:
75: if (pid_ <= 176) {
76: revert Convex3PoolCToken__UnsafePool();
77: }
78:
79: strategyData.pid = pid_;
80: strategyData.booster = IBooster(booster_);
81:
82:
83: (address pidToken, , , address crvRewards, , bool shutdown) = IBooster( // <= FOUND
84: booster_
85: ).poolInfo(strategyData.pid);
86:
87:
88:
89: if (
90: pidToken != address(asset_) || shutdown || crvRewards != rewarder_
91: ) {
92: revert Convex3PoolCToken__InvalidVaultConfig();
93: }
94:
95: strategyData.curvePool = ICurveFi(pidToken); // <= FOUND
96:
97: uint256 coinsLength;
98: address token; // <= FOUND
99:
100:
101: while (true) {
102: try ICurveFi(pidToken).coins(coinsLength) {
103: ++coinsLength;
104: } catch {
105: break;
106: }
107: }
108:
109:
110: if (coinsLength != 3) {
111: revert Convex3PoolCToken__InvalidCoinLength();
112: }
113:
114: strategyData.rewarder = IBaseRewardPool(rewarder_);
115:
116:
117:
118: reQueryRewardTokens();
119:
120:
121: strategyData.underlyingTokens = new address[](coinsLength);
122: for (uint256 i; i < coinsLength; ) {
123: token = ICurveFi(pidToken).coins(i);
124: strategyData.underlyingTokens[i] = token;
125: isUnderlyingToken[token] = true;
126:
127: unchecked {
128: ++i;
129: }
130: }
131: }
['162']
160: constructor(
161: ICentralRegistry centralRegistry_,
162: address underlying_, // <= FOUND
163: address marketManager_, // <= FOUND
164: address interestRateModel_ // <= FOUND
165: ) Delegable(centralRegistry_) {
166: if (
167: !ERC165Checker.supportsInterface(
168: address(centralRegistry_),
169: type(ICentralRegistry).interfaceId
170: )
171: ) {
172: revert DToken__InvalidCentralRegistry();
173: }
174:
175:
176:
177: if (!centralRegistry.isMarketManager(marketManager_)) {
178: revert DToken__MarketManagerIsNotLendingMarket();
179: }
180:
181:
182: marketManager = IMarketManager(marketManager_);
183:
184:
185: marketData.lastTimestampUpdated = uint40(block.timestamp);
186: marketData.exchangeRate = uint216(WAD);
187:
188: _setInterestRateModel(IInterestRateModel(interestRateModel_));
189:
190:
191:
192: uint256 newInterestFactor = centralRegistry.protocolInterestFactor(
193: marketManager_
194: );
195: interestFactor = newInterestFactor;
196:
197: emit NewInterestFactor(0, newInterestFactor);
198:
199: underlying = underlying_;
200: name = string.concat(
201: "Curvance interest bearing ",
202: IERC20(underlying_).name()
203: );
204: symbol = string.concat("c", IERC20(underlying_).symbol());
205:
206:
207:
208: if (IERC20(underlying).totalSupply() >= type(uint232).max) {
209: revert DToken__UnderlyingAssetTotalSupplyExceedsMaximum();
210: }
211: }
['78']
76: constructor(
77: ICentralRegistry centralRegistry_,
78: address gmxReader_, // <= FOUND
79: address gmxDataStore_ // <= FOUND
80: ) BaseOracleAdaptor(centralRegistry_) {
81: if (block.chainid != 42161) {
82: revert GMAdaptor__ChainIsNotSupported();
83: }
84:
85: _setGMXReader(gmxReader_);
86: _setGMXDataStore(gmxDataStore_);
87: }
['185']
183: constructor(
184: ICentralRegistry centralRegistry_,
185: address gaugePool_ // <= FOUND
186: ) LiquidityManager(centralRegistry_) {
187: if (
188: !ERC165Checker.supportsInterface(
189: address(gaugePool_),
190: type(IGaugePool).interfaceId
191: )
192: ) {
193: _revert(_INVALID_PARAMETER_SELECTOR);
194: }
195:
196: gaugePool = IGaugePool(gaugePool_); // <= FOUND
197: }
['61']
59: constructor(
60: ICentralRegistry centralRegistry_,
61: IERC20 asset_, // <= FOUND
62: address marketManager_, // <= FOUND
63: IPendleRouter router_
64: ) CTokenCompounding(centralRegistry_, asset_, marketManager_) {
65: strategyData.router = router_;
66: strategyData.lp = IPMarket(address(asset_));
67:
68: (strategyData.sy, strategyData.pt, strategyData.yt) = strategyData
69: .lp
70: .readTokens();
71:
72: strategyData.rewardTokens = strategyData.lp.getRewardTokens();
73:
74:
75:
76: strategyData.underlyingTokens = strategyData.sy.getTokensIn();
77: uint256 numUnderlyingTokens = strategyData.underlyingTokens.length;
78: for (uint256 i; i < numUnderlyingTokens; ) {
79: unchecked {
80: isUnderlyingToken[strategyData.underlyingTokens[i++]] = true;
81: }
82: }
83: }
['139']
137: constructor(
138: ICentralRegistry centralRegistry_,
139: address marketManager_ // <= FOUND
140: ) Delegable(centralRegistry_) {
141: if (
142: !ERC165Checker.supportsInterface(
143: address(centralRegistry_),
144: type(ICentralRegistry).interfaceId
145: )
146: ) {
147: revert PositionFolding__InvalidCentralRegistry();
148: }
149:
150:
151:
152: if (!centralRegistry_.isMarketManager(marketManager_)) {
153: revert PositionFolding__InvalidMarketManager();
154: }
155:
156: marketManager = IMarketManager(marketManager_);
157: }
['15']
15: constructor(address _sDai, address _dai, address _daiAggregator) { // <= FOUND
16: sDai = _sDai;
17: dai = _dai;
18: daiAggregator = _daiAggregator;
19: }
['55']
53: constructor(
54: ICentralRegistry centralRegistry_,
55: address marketManager_, // <= FOUND
56: address WETH_ // <= FOUND
57: ) {
58: if (
59: !ERC165Checker.supportsInterface(
60: address(centralRegistry_),
61: type(ICentralRegistry).interfaceId
62: )
63: ) {
64: revert SimpleZapper__InvalidCentralRegistry();
65: }
66:
67: centralRegistry = centralRegistry_;
68:
69:
70:
71: if (!centralRegistry.isMarketManager(marketManager_)) {
72: revert SimpleZapper__InvalidMarketManager();
73: }
74:
75: marketManager = IMarketManager(marketManager_);
76: WETH = WETH_;
77: }
['15']
15: constructor(address _sFrax, address _frax, address _fraxAggregator) { // <= FOUND
16: sFrax = _sFrax;
17: frax = _frax;
18: fraxAggregator = _fraxAggregator;
19: }
['68']
65: constructor(
66: ICentralRegistry centralRegistry_,
67: IStaticOracle oracleAddress_,
68: address WETH_ // <= FOUND
69: ) BaseOracleAdaptor(centralRegistry_) {
70: uniswapOracleRouter = oracleAddress_;
71: WETH = WETH_;
72: }
['70']
68: constructor(
69: ICentralRegistry centralRegistry_,
70: IERC20 asset_, // <= FOUND
71: address marketManager_, // <= FOUND
72: IVeloGauge gauge,
73: IVeloPairFactory pairFactory,
74: IVeloRouter router
75: ) CTokenCompounding(centralRegistry_, asset_, marketManager_) {
76: if (block.chainid != 10) {
77: revert VelodromeStableCToken__ChainIsNotSupported();
78: }
79:
80:
81: address _asset = asset(); // <= FOUND
82:
83:
84: if (gauge.stakingToken() != _asset) {
85: revert VelodromeStableCToken__StakingTokenIsNotAsset(
86: gauge.stakingToken()
87: );
88: }
89:
90:
91: if (!IVeloPool(_asset).stable()) {
92: revert VelodromeStableCToken__AssetIsNotStable();
93: }
94:
95:
96: strategyData.token0 = IVeloPool(_asset).token0();
97: strategyData.token1 = IVeloPool(_asset).token1();
98:
99:
100: if (strategyData.token1 == address(rewardToken)) {
101: strategyData.token1 = strategyData.token0;
102: strategyData.token0 = address(rewardToken);
103: }
104: strategyData.decimalsA = 10 ** IERC20(strategyData.token0).decimals();
105: strategyData.decimalsB = 10 ** IERC20(strategyData.token1).decimals();
106:
107: strategyData.gauge = gauge;
108: strategyData.router = router;
109: strategyData.pairFactory = pairFactory;
110:
111: isUnderlyingToken[strategyData.token0] = true;
112: isUnderlyingToken[strategyData.token1] = true;
113:
114: rewardTokenIsUnderlying = (address(rewardToken) ==
115: strategyData.token0 ||
116: address(rewardToken) == strategyData.token1);
117: }
['60']
58: constructor(
59: ICentralRegistry centralRegistry_,
60: IERC20 asset_, // <= FOUND
61: address marketManager_, // <= FOUND
62: IVeloGauge gauge,
63: IVeloPairFactory pairFactory,
64: IVeloRouter router
65: ) CTokenCompounding(centralRegistry_, asset_, marketManager_) {
66: if (block.chainid != 10) {
67: revert VelodromeVolatileCToken__ChainIsNotSupported();
68: }
69:
70:
71: address _asset = asset(); // <= FOUND
72:
73:
74: if (gauge.stakingToken() != _asset) {
75: revert VelodromeVolatileCToken__StakingTokenIsNotAsset(
76: gauge.stakingToken()
77: );
78: }
79:
80:
81: if (IVeloPool(_asset).stable()) {
82: revert VelodromeVolatileCToken__AssetIsNotStable();
83: }
84:
85:
86: strategyData.token0 = IVeloPool(_asset).token0();
87: strategyData.token1 = IVeloPool(_asset).token1();
88:
89:
90: if (strategyData.token1 == address(rewardToken)) {
91: strategyData.token1 = strategyData.token0;
92: strategyData.token0 = address(rewardToken);
93: }
94: strategyData.gauge = gauge;
95: strategyData.router = router;
96: strategyData.pairFactory = pairFactory;
97:
98: isUnderlyingToken[strategyData.token0] = true;
99: isUnderlyingToken[strategyData.token1] = true;
100:
101: rewardTokenIsUnderlying = (address(rewardToken) ==
102: strategyData.token0 ||
103: address(rewardToken) == strategyData.token1);
104: }
['15']
15: constructor(address _wstETH, address _stETH, address _stETHAggregator) { // <= FOUND
16: wstETH = _wstETH;
17: stETH = _stETH;
18: stETHAggregator = _stETHAggregator;
19: }
Taking 0 as a valid argument in Solidity without checks can lead to severe security issues. A historical example is the infamous 0x0 address bug where numerous tokens were lost. This happens because '0' can be interpreted as an uninitialized address, leading to transfers to the '0x0' address, effectively burning tokens. Moreover, 0 as a denominator in division operations would cause a runtime exception. It's also often indicative of a logical error in the caller's code. It's important to always validate input and handle edge cases like 0 appropriately. Use require()
statements to enforce conditions and provide clear error messages to facilitate debugging and safer code.
Num of instances: 16
Click to show findings
['129']
129: function harvest(
130: bytes calldata data
131: ) external override returns (uint256 yield) {
132:
133: _canCompound();
134:
135:
136: _vestIfNeeded();
137:
138:
139: if (_checkVestStatus(_vaultData)) {
140: _updateVestingPeriodIfNeeded();
141:
142:
143: StrategyData memory sd = strategyData;
144:
145:
146: sd.gauge.getReward(address(this));
147:
148: {
149: uint256 rewardAmount = rewardToken.balanceOf(address(this));
150:
151:
152: if (rewardAmount > 0) {
153:
154:
155: uint256 protocolFee = FixedPointMathLib.mulDiv(
156: rewardAmount,
157: centralRegistry.protocolHarvestFee(),
158: 1e18
159: );
160: rewardAmount -= protocolFee;
161: SafeTransferLib.safeTransfer(
162: address(rewardToken),
163: centralRegistry.feeAccumulator(),
164: protocolFee
165: );
166:
167:
168: if (!rewardTokenIsUnderlying) {
169: SwapperLib.Swap memory swapData = abi.decode(
170: data,
171: (SwapperLib.Swap)
172: );
173:
174: if (!centralRegistry.isSwapper(swapData.target)) {
175: revert AerodromeStableCToken__InvalidSwapper(
176: swapData.target
177: );
178: }
179:
180: SwapperLib.swap(centralRegistry, swapData);
181: }
182: }
183: }
184:
185: uint256 totalAmountA = IERC20(sd.token0).balanceOf(address(this));
186:
187:
188: if (totalAmountA == 0) {
189: revert AerodromeStableCToken__SlippageError();
190: }
191:
192:
193: address _asset = asset();
194:
195:
196: (uint256 r0, uint256 r1, ) = IVeloPair(_asset).getReserves();
197: (uint256 reserveA, uint256 reserveB) = sd.token0 ==
198: IVeloPair(_asset).token0()
199: ? (r0, r1)
200: : (r1, r0);
201:
202:
203: uint256 swapAmount = VelodromeLib._optimalDeposit(
204: address(sd.pairFactory),
205: _asset,
206: totalAmountA,
207: reserveA,
208: reserveB,
209: sd.decimalsA,
210: sd.decimalsB,
211: true
212: );
213:
214: VelodromeLib._swapExactTokensForTokens(
215: address(sd.router),
216: _asset,
217: sd.token0,
218: sd.token1,
219: swapAmount,
220: true
221: );
222: totalAmountA -= swapAmount;
223:
224:
225: yield = VelodromeLib._addLiquidity(
226: address(sd.router),
227: sd.token0,
228: sd.token1,
229: true,
230: totalAmountA,
231: IERC20(sd.token1).balanceOf(address(this)),
232: VelodromeLib.VELODROME_ADD_LIQUIDITY_SLIPPAGE
233: );
234:
235:
236:
237: _afterDeposit(yield, 0); // <= FOUND
238:
239:
240: _setNewVaultData(yield, vestPeriod);
241:
242: emit Harvest(yield);
243: }
244: }
['124']
124: function harvest(
125: bytes calldata data
126: ) external override returns (uint256 yield) {
127:
128: _canCompound();
129:
130:
131: _vestIfNeeded();
132:
133:
134: if (_checkVestStatus(_vaultData)) {
135: _updateVestingPeriodIfNeeded();
136:
137:
138: StrategyData memory sd = strategyData;
139:
140:
141: sd.gauge.getReward(address(this));
142:
143: {
144: uint256 rewardAmount = rewardToken.balanceOf(address(this));
145:
146: if (rewardAmount > 0) {
147:
148:
149: uint256 protocolFee = FixedPointMathLib.mulDiv(
150: rewardAmount,
151: centralRegistry.protocolHarvestFee(),
152: 1e18
153: );
154: rewardAmount -= protocolFee;
155: SafeTransferLib.safeTransfer(
156: address(rewardToken),
157: centralRegistry.feeAccumulator(),
158: protocolFee
159: );
160:
161:
162: if (!rewardTokenIsUnderlying) {
163: SwapperLib.Swap memory swapData = abi.decode(
164: data,
165: (SwapperLib.Swap)
166: );
167:
168: if (!centralRegistry.isSwapper(swapData.target)) {
169: revert AerodromeVolatileCToken__InvalidSwapper(
170: swapData.target
171: );
172: }
173:
174: SwapperLib.swap(centralRegistry, swapData);
175: }
176: }
177: }
178:
179: uint256 totalAmountA = IERC20(sd.token0).balanceOf(address(this));
180:
181: if (totalAmountA == 0) {
182: revert AerodromeVolatileCToken__SlippageError();
183: }
184:
185:
186: address _asset = asset();
187:
188:
189: (uint256 r0, uint256 r1, ) = IVeloPair(_asset).getReserves();
190: uint256 reserveA = sd.token0 == IVeloPair(_asset).token0()
191: ? r0
192: : r1;
193:
194:
195:
196:
197: uint256 swapAmount = VelodromeLib._optimalDeposit(
198: address(sd.pairFactory),
199: _asset,
200: totalAmountA,
201: reserveA,
202: 0,
203: 0,
204: 0,
205: false
206: );
207:
208: VelodromeLib._swapExactTokensForTokens(
209: address(sd.router),
210: _asset,
211: sd.token0,
212: sd.token1,
213: swapAmount,
214: false
215: );
216: totalAmountA -= swapAmount;
217:
218:
219: yield = VelodromeLib._addLiquidity(
220: address(sd.router),
221: sd.token0,
222: sd.token1,
223: false,
224: totalAmountA,
225: IERC20(sd.token1).balanceOf(address(this)),
226: VelodromeLib.VELODROME_ADD_LIQUIDITY_SLIPPAGE
227: );
228:
229:
230:
231: _afterDeposit(yield, 0); // <= FOUND
232:
233:
234: _setNewVaultData(yield, vestPeriod);
235:
236: emit Harvest(yield);
237: }
238:
239: }
['70']
70: function harvest(
71: bytes calldata data
72: ) external override returns (uint256 yield) {
73:
74: _canCompound();
75:
76:
77: _vestIfNeeded();
78:
79:
80: if (_checkVestStatus(_vaultData)) {
81: _updateVestingPeriodIfNeeded();
82:
83:
84: rewardRouter.handleRewards(
85: true,
86: true,
87: true,
88: true,
89: true,
90: true,
91: false
92: );
93: uint256 rewardAmount = WETH.balanceOf(address(this));
94:
95:
96: if (rewardAmount > 0) {
97:
98:
99: uint256 protocolFee = FixedPointMathLib.mulDiv(
100: rewardAmount,
101: centralRegistry.protocolHarvestFee(),
102: 1e18
103: );
104: rewardAmount -= protocolFee;
105: SafeTransferLib.safeTransfer(
106: address(WETH),
107: centralRegistry.feeAccumulator(),
108: protocolFee
109: );
110:
111: SwapperLib.Swap memory swapData = abi.decode(
112: data,
113: (SwapperLib.Swap)
114: );
115:
116: if (!centralRegistry.isSwapper(swapData.target)) {
117: revert StakedGMXCToken__InvalidSwapper(swapData.target);
118: }
119:
120: yield = SwapperLib.swap(centralRegistry, swapData);
121:
122:
123: if (yield == 0) {
124: revert StakedGMXCToken__SlippageError();
125: }
126: }
127:
128:
129:
130: _afterDeposit(yield, 0); // <= FOUND
131:
132:
133: _setNewVaultData(yield, vestPeriod);
134:
135: emit Harvest(yield);
136: }
137: }
['130']
130: function harvest(
131: bytes calldata data
132: ) external override returns (uint256 yield) {
133:
134: _canCompound();
135:
136:
137: _vestIfNeeded();
138:
139:
140: if (_checkVestStatus(_vaultData)) {
141: _updateVestingPeriodIfNeeded();
142:
143:
144: StrategyData memory sd = strategyData;
145:
146:
147: sd.gauge.getReward(address(this));
148:
149: {
150: uint256 rewardAmount = rewardToken.balanceOf(address(this));
151:
152: if (rewardAmount > 0) {
153:
154:
155: uint256 protocolFee = FixedPointMathLib.mulDiv(
156: rewardAmount,
157: centralRegistry.protocolHarvestFee(),
158: 1e18
159: );
160: rewardAmount -= protocolFee;
161: SafeTransferLib.safeTransfer(
162: address(rewardToken),
163: centralRegistry.feeAccumulator(),
164: protocolFee
165: );
166:
167:
168: if (!rewardTokenIsUnderlying) {
169: SwapperLib.Swap memory swapData = abi.decode(
170: data,
171: (SwapperLib.Swap)
172: );
173:
174: if (!centralRegistry.isSwapper(swapData.target)) {
175: revert VelodromeStableCToken__InvalidSwapper(
176: swapData.target
177: );
178: }
179:
180: SwapperLib.swap(centralRegistry, swapData);
181: }
182: }
183: }
184:
185: uint256 totalAmountA = IERC20(sd.token0).balanceOf(address(this));
186:
187:
188: if (totalAmountA == 0) {
189: revert VelodromeStableCToken__SlippageError();
190: }
191:
192:
193: address _asset = asset();
194:
195:
196: (uint256 r0, uint256 r1, ) = IVeloPair(_asset).getReserves();
197: (uint256 reserveA, uint256 reserveB) = sd.token0 ==
198: IVeloPair(_asset).token0()
199: ? (r0, r1)
200: : (r1, r0);
201:
202:
203: uint256 swapAmount = VelodromeLib._optimalDeposit(
204: address(sd.pairFactory),
205: _asset,
206: totalAmountA,
207: reserveA,
208: reserveB,
209: sd.decimalsA,
210: sd.decimalsB,
211: true
212: );
213:
214: VelodromeLib._swapExactTokensForTokens(
215: address(sd.router),
216: _asset,
217: sd.token0,
218: sd.token1,
219: swapAmount,
220: true
221: );
222: totalAmountA -= swapAmount;
223:
224:
225: yield = VelodromeLib._addLiquidity(
226: address(sd.router),
227: sd.token0,
228: sd.token1,
229: true,
230: totalAmountA,
231: IERC20(sd.token1).balanceOf(address(this)),
232: VelodromeLib.VELODROME_ADD_LIQUIDITY_SLIPPAGE
233: );
234:
235:
236:
237: _afterDeposit(yield, 0); // <= FOUND
238:
239:
240: _setNewVaultData(yield, vestPeriod);
241:
242: emit Harvest(yield);
243: }
244: }
['117']
117: function harvest(
118: bytes calldata data
119: ) external override returns (uint256 yield) {
120:
121: _canCompound();
122:
123:
124: _vestIfNeeded();
125:
126:
127: if (_checkVestStatus(_vaultData)) {
128: _updateVestingPeriodIfNeeded();
129:
130:
131: StrategyData memory sd = strategyData;
132:
133:
134: sd.gauge.getReward(address(this));
135:
136: {
137: uint256 rewardAmount = rewardToken.balanceOf(address(this));
138:
139: if (rewardAmount > 0) {
140:
141:
142: uint256 protocolFee = FixedPointMathLib.mulDiv(
143: rewardAmount,
144: centralRegistry.protocolHarvestFee(),
145: 1e18
146: );
147: rewardAmount -= protocolFee;
148: SafeTransferLib.safeTransfer(
149: address(rewardToken),
150: centralRegistry.feeAccumulator(),
151: protocolFee
152: );
153:
154:
155: if (!rewardTokenIsUnderlying) {
156: SwapperLib.Swap memory swapData = abi.decode(
157: data,
158: (SwapperLib.Swap)
159: );
160:
161: if (!centralRegistry.isSwapper(swapData.target)) {
162: revert VelodromeVolatileCToken__InvalidSwapper(
163: swapData.target
164: );
165: }
166:
167: SwapperLib.swap(centralRegistry, swapData);
168: }
169: }
170: }
171:
172: uint256 totalAmountA = IERC20(sd.token0).balanceOf(address(this));
173:
174:
175: if (totalAmountA == 0) {
176: revert VelodromeVolatileCToken__SlippageError();
177: }
178:
179:
180: address _asset = asset();
181:
182:
183: (uint256 r0, uint256 r1, ) = IVeloPair(_asset).getReserves();
184: uint256 reserveA = sd.token0 == IVeloPair(_asset).token0()
185: ? r0
186: : r1;
187:
188:
189:
190:
191: uint256 swapAmount = VelodromeLib._optimalDeposit(
192: address(sd.pairFactory),
193: _asset,
194: totalAmountA,
195: reserveA,
196: 0,
197: 0,
198: 0,
199: false
200: );
201:
202: VelodromeLib._swapExactTokensForTokens(
203: address(sd.router),
204: _asset,
205: sd.token0,
206: sd.token1,
207: swapAmount,
208: false
209: );
210: totalAmountA -= swapAmount;
211:
212:
213: yield = VelodromeLib._addLiquidity(
214: address(sd.router),
215: sd.token0,
216: sd.token1,
217: false,
218: totalAmountA,
219: IERC20(sd.token1).balanceOf(address(this)),
220: VelodromeLib.VELODROME_ADD_LIQUIDITY_SLIPPAGE
221: );
222:
223:
224:
225: _afterDeposit(yield, 0); // <= FOUND
226:
227:
228: _setNewVaultData(yield, vestPeriod);
229:
230: emit Harvest(yield);
231: }
232: }
['212']
212: function harvest(
213: bytes calldata data
214: ) external override returns (uint256 yield) {
215:
216: _canCompound();
217:
218:
219: _vestIfNeeded();
220:
221:
222: if (_checkVestStatus(_vaultData)) {
223: _updateVestingPeriodIfNeeded();
224:
225:
226: StrategyData memory sd = strategyData;
227:
228:
229: sd.rewarder.getReward(address(this), true);
230:
231: (SwapperLib.Swap[] memory swapDataArray, uint256 minLPAmount) = abi
232: .decode(data, (SwapperLib.Swap[], uint256));
233:
234: {
235:
236: uint256 numRewardTokens = sd.rewardTokens.length;
237: address rewardToken;
238: uint256 rewardAmount;
239: uint256 protocolFee;
240:
241:
242: address feeAccumulator = centralRegistry.feeAccumulator();
243: uint256 harvestFee = centralRegistry.protocolHarvestFee();
244:
245: for (uint256 i; i < numRewardTokens; ++i) {
246: rewardToken = sd.rewardTokens[i];
247: rewardAmount = IERC20(rewardToken).balanceOf(
248: address(this)
249: );
250:
251:
252:
253: if (rewardAmount == 0) {
254: continue;
255: }
256:
257:
258:
259: protocolFee = FixedPointMathLib.mulDiv(
260: rewardAmount,
261: harvestFee,
262: 1e18
263: );
264: rewardAmount -= protocolFee;
265: SafeTransferLib.safeTransfer(
266: rewardToken,
267: feeAccumulator,
268: protocolFee
269: );
270:
271:
272: if (!isUnderlyingToken[rewardToken]) {
273: if (
274: !centralRegistry.isSwapper(swapDataArray[i].target)
275: ) {
276: revert AuraCToken__InvalidSwapper(
277: i,
278: swapDataArray[i].target
279: );
280: }
281:
282: SwapperLib.swap(centralRegistry, swapDataArray[i]);
283: }
284: }
285: }
286:
287:
288: {
289:
290: uint256 numUnderlyingTokens = sd.underlyingTokens.length;
291: address[] memory assets = new address[](numUnderlyingTokens);
292: uint256[] memory maxAmountsIn = new uint256[](
293: numUnderlyingTokens
294: );
295: address underlyingToken;
296:
297: for (uint256 i; i < numUnderlyingTokens; ++i) {
298: underlyingToken = sd.underlyingTokens[i];
299: assets[i] = underlyingToken;
300: maxAmountsIn[i] = IERC20(underlyingToken).balanceOf(
301: address(this)
302: );
303:
304: SwapperLib._approveTokenIfNeeded(
305: underlyingToken,
306: address(sd.balancerVault),
307: maxAmountsIn[i]
308: );
309: }
310:
311:
312: sd.balancerVault.joinPool(
313: sd.balancerPoolId,
314: address(this),
315: address(this),
316: IBalancerVault.JoinPoolRequest(
317: assets,
318: maxAmountsIn,
319: abi.encode(
320: IBalancerVault
321: .JoinKind
322: .EXACT_TOKENS_IN_FOR_BPT_OUT,
323: maxAmountsIn,
324: minLPAmount
325: ),
326: false
327: )
328: );
329: }
330:
331:
332: yield = IERC20(asset()).balanceOf(address(this));
333: _afterDeposit(yield, 0); // <= FOUND
334:
335:
336: _setNewVaultData(yield, vestPeriod);
337:
338: emit Harvest(yield);
339: }
340: }
['177']
177: function harvest(
178: bytes calldata data
179: ) external override returns (uint256 yield) {
180:
181: _canCompound();
182:
183:
184: _vestIfNeeded();
185:
186:
187: if (_checkVestStatus(_vaultData)) {
188: _updateVestingPeriodIfNeeded();
189:
190:
191: StrategyData memory sd = strategyData;
192:
193:
194: sd.rewarder.getReward(address(this), true);
195:
196: (SwapperLib.Swap[] memory swapDataArray, uint256 minLPAmount) = abi
197: .decode(data, (SwapperLib.Swap[], uint256));
198:
199: uint256 numRewardTokens = sd.rewardTokens.length;
200: address rewardToken;
201: uint256 rewardAmount;
202: uint256 protocolFee;
203:
204: {
205:
206:
207: address feeAccumulator = centralRegistry.feeAccumulator();
208: uint256 harvestFee = centralRegistry.protocolHarvestFee();
209:
210: for (uint256 i; i < numRewardTokens; ++i) {
211: rewardToken = sd.rewardTokens[i];
212: rewardAmount = IERC20(rewardToken).balanceOf(
213: address(this)
214: );
215:
216:
217:
218: if (rewardAmount == 0) {
219: continue;
220: }
221:
222:
223:
224: protocolFee = FixedPointMathLib.mulDiv(
225: rewardAmount,
226: harvestFee,
227: 1e18
228: );
229: rewardAmount -= protocolFee;
230: SafeTransferLib.safeTransfer(
231: address(rewardToken),
232: feeAccumulator,
233: protocolFee
234: );
235: }
236: }
237:
238:
239: {
240: uint256 numSwapData = swapDataArray.length;
241: for (uint256 i; i < numSwapData; ++i) {
242: if (!centralRegistry.isSwapper(swapDataArray[i].target)) {
243: revert Convex2PoolCToken__InvalidSwapper(
244: i,
245: swapDataArray[i].target
246: );
247: }
248: SwapperLib.swap(centralRegistry, swapDataArray[i]);
249: }
250: }
251:
252:
253: _addLiquidityToCurve(minLPAmount);
254:
255:
256: yield = IERC20(asset()).balanceOf(address(this));
257: if (yield == 0) {
258: revert Convex2PoolCToken__NoYield();
259: }
260: _afterDeposit(yield, 0); // <= FOUND
261:
262:
263: _setNewVaultData(yield, vestPeriod);
264:
265: emit Harvest(yield);
266: }
267: }
['177']
177: function harvest(
178: bytes calldata data
179: ) external override returns (uint256 yield) {
180:
181: _canCompound();
182:
183:
184: _vestIfNeeded();
185:
186:
187: if (_checkVestStatus(_vaultData)) {
188: _updateVestingPeriodIfNeeded();
189:
190:
191: StrategyData memory sd = strategyData;
192:
193:
194: sd.rewarder.getReward(address(this), true);
195:
196: (SwapperLib.Swap[] memory swapDataArray, uint256 minLPAmount) = abi
197: .decode(data, (SwapperLib.Swap[], uint256));
198:
199: uint256 numRewardTokens = sd.rewardTokens.length;
200: address rewardToken;
201: uint256 rewardAmount;
202: uint256 protocolFee;
203:
204: {
205:
206:
207: address feeAccumulator = centralRegistry.feeAccumulator();
208: uint256 harvestFee = centralRegistry.protocolHarvestFee();
209:
210: for (uint256 i; i < numRewardTokens; ++i) {
211: rewardToken = sd.rewardTokens[i];
212: rewardAmount = IERC20(rewardToken).balanceOf(
213: address(this)
214: );
215:
216:
217:
218: if (rewardAmount == 0) {
219: continue;
220: }
221:
222:
223:
224: protocolFee = FixedPointMathLib.mulDiv(
225: rewardAmount,
226: harvestFee,
227: 1e18
228: );
229: rewardAmount -= protocolFee;
230: SafeTransferLib.safeTransfer(
231: address(rewardToken),
232: feeAccumulator,
233: protocolFee
234: );
235: }
236: }
237:
238:
239: {
240: uint256 numSwapData = swapDataArray.length;
241: for (uint256 i; i < numSwapData; ++i) {
242: if (!centralRegistry.isSwapper(swapDataArray[i].target)) {
243: revert Convex3PoolCToken__InvalidSwapper(
244: i,
245: swapDataArray[i].target
246: );
247: }
248: SwapperLib.swap(centralRegistry, swapDataArray[i]);
249: }
250: }
251:
252:
253: _addLiquidityToCurve(minLPAmount);
254:
255:
256: yield = IERC20(asset()).balanceOf(address(this));
257: if (yield == 0) {
258: revert Convex3PoolCToken__NoYield();
259: }
260: _afterDeposit(yield, 0); // <= FOUND
261:
262:
263: _setNewVaultData(yield, vestPeriod);
264:
265: emit Harvest(yield);
266: }
267: }
['100']
100: function withdrawByPositionFolding(
101: address owner,
102: uint256 assets,
103: bytes calldata params
104: ) external nonReentrant {
105:
106: if (msg.sender != marketManager.positionFolding()) {
107: _revert(_UNAUTHORIZED_SELECTOR);
108: }
109:
110:
111: uint256 pending = _calculatePendingRewards();
112: uint256 ta = _totalAssets + pending;
113: uint256 balancePrior = balanceOf(owner);
114:
115:
116: if (assets > _convertToAssets(balancePrior, ta)) {
117:
118: _revert(0x2735eaab);
119: }
120:
121:
122: uint256 shares = _previewWithdraw(assets, ta);
123:
124:
125: _gaugePool().withdraw(address(this), owner, shares);
126:
127:
128:
129: _processWithdraw(
130: msg.sender,
131: msg.sender,
132: owner,
133: assets,
134: shares,
135: ta,
136: pending
137: );
138:
139:
140: IPositionFolding(msg.sender).onRedeem(
141: address(this),
142: owner,
143: assets,
144: params
145: );
146:
147:
148: marketManager.reduceCollateralIfNecessary(
149: owner,
150: address(this),
151: balancePrior,
152: shares
153: );
154:
155:
156: marketManager.canRedeemWithPrune(address(this), owner, 0);
157: }
['41']
41: function withdrawByPositionFolding(
42: address owner,
43: uint256 assets,
44: bytes calldata params
45: ) external nonReentrant {
46:
47: if (msg.sender != marketManager.positionFolding()) {
48: _revert(_UNAUTHORIZED_SELECTOR);
49: }
50:
51:
52: uint256 ta = _totalAssets;
53: uint256 balancePrior = balanceOf(owner);
54:
55:
56:
57: if (assets > _convertToAssets(balancePrior, ta)) {
58:
59: _revert(0xc6e63cc0);
60: }
61:
62:
63: uint256 shares = _previewWithdraw(assets, ta);
64:
65:
66: _gaugePool().withdraw(address(this), owner, shares);
67:
68:
69:
70: _processWithdraw(msg.sender, msg.sender, owner, assets, shares, ta);
71:
72:
73: IPositionFolding(msg.sender).onRedeem(
74: address(this),
75: owner,
76: assets,
77: params
78: );
79:
80:
81: marketManager.reduceCollateralIfNecessary(
82: owner,
83: address(this),
84: balancePrior,
85: shares
86: );
87:
88: marketManager.canRedeemWithPrune(address(this), owner, 0);
89: }
['52']
52: function isLocked(
53: address curvePool,
54: uint256 coinsLength
55: ) public view returns (bool) {
56: uint256 gasLimit = reentrancyConfig[coinsLength];
57:
58: if (gasLimit == 0) {
59: revert CurveBaseAdaptor__PoolNotFound();
60: }
61:
62: uint256 gasStart = gasleft();
63:
64: ICurveRemoveLiquidity pool = ICurveRemoveLiquidity(curvePool);
65:
66: if (coinsLength == 2) {
67: uint256[2] memory amounts;
68: try pool.remove_liquidity{ gas: gasLimit }(0, amounts) {} catch ( // <= FOUND
69: bytes memory
70: ) {}
71: } else if (coinsLength == 3) {
72: uint256[3] memory amounts;
73: try pool.remove_liquidity{ gas: gasLimit }(0, amounts) {} catch ( // <= FOUND
74: bytes memory
75: ) {}
76: }
77: if (coinsLength == 4) {
78: uint256[4] memory amounts;
79: try pool.remove_liquidity{ gas: gasLimit }(0, amounts) {} catch ( // <= FOUND
80: bytes memory
81: ) {}
82: }
83:
84: uint256 gasSpent;
85:
86: unchecked {
87: gasSpent = gasStart - gasleft();
88: }
89:
90: return
91: gasSpent > gasLimit
92: ? false
93: : true ;
94: }
['326']
326: function borrowForPositionFolding(
327: address account,
328: uint256 amount,
329: bytes calldata params
330: ) external nonReentrant {
331: if (msg.sender != marketManager.positionFolding()) {
332: _revert(_UNAUTHORIZED_SELECTOR);
333: }
334:
335:
336: accrueInterest();
337:
338:
339:
340: marketManager.notifyBorrow(address(this), account);
341:
342: _borrow(account, amount, msg.sender);
343:
344:
345: IPositionFolding(msg.sender).onBorrow(
346: address(this),
347: account,
348: amount,
349: params
350: );
351:
352:
353:
354: marketManager.canBorrowWithPrune(address(this), account, 0);
355: }
['532']
532: function redeemUnderlyingForPositionFolding(
533: address account,
534: uint256 amount,
535: bytes calldata params
536: ) external nonReentrant {
537: if (msg.sender != marketManager.positionFolding()) {
538: _revert(_UNAUTHORIZED_SELECTOR);
539: }
540:
541:
542: accrueInterest();
543:
544: _redeem(
545: account,
546: msg.sender,
547: (amount * WAD) / exchangeRateCached(),
548: amount
549: );
550:
551: IPositionFolding(msg.sender).onRedeem(
552: address(this),
553: account,
554: amount,
555: params
556: );
557:
558:
559:
560: marketManager.canRedeem(address(this), account, 0);
561: }
['179']
179: function _transferTokenViaWormhole(
180: address token,
181: uint256 dstChainId,
182: address to,
183: uint256 amount,
184: uint256 wormholeFee
185: ) internal returns (uint64) {
186: ITokenBridge tokenBridge = centralRegistry.tokenBridge();
187: uint16 wormholeChainId = centralRegistry.wormholeChainId(dstChainId);
188: IWormhole wormholeCore = centralRegistry.wormholeCore();
189: uint256 messageFee = wormholeCore.messageFee();
190:
191: SwapperLib._approveTokenIfNeeded(token, address(tokenBridge), amount);
192:
193: bytes memory payload = abi.encode(uint8(1), feeToken, amount);
194:
195: uint64 sequence = tokenBridge.transferTokensWithPayload{
196: value: messageFee
197: }(
198: token,
199: amount,
200: wormholeChainId,
201: bytes32(uint256(uint160(to))),
202: 0,
203: payload
204: );
205:
206: IWormholeRelayer.VaaKey[]
207: memory vaaKeys = new IWormholeRelayer.VaaKey[](1);
208: vaaKeys[0] = IWormholeRelayer.VaaKey({
209: emitterAddress: bytes32(uint256(uint160(address(tokenBridge)))),
210: chainId: wormholeCore.chainId(),
211: sequence: sequence
212: });
213:
214: return
215: centralRegistry.wormholeRelayer().sendVaasToEvm{
216: value: wormholeFee - messageFee
217: }(wormholeChainId, to, payload, 0, _GAS_LIMIT, vaaKeys);
218: }
['350']
350: function getPricesForAsset(
351: address asset,
352: bool inUSD
353: ) external view returns (FeedData[] memory) {
354: bool isMToken = mTokenAssets[asset].isMToken;
355: if (isMToken) {
356: asset = mTokenAssets[asset].underlying;
357: }
358:
359: uint256 numFeeds = assetPriceFeeds[asset].length;
360: if (numFeeds == 0) {
361: _revert(_NOT_SUPPORTED_SELECTOR);
362: }
363:
364: FeedData[] memory data = new FeedData[](numFeeds * 2);
365:
366:
367:
368: if (numFeeds < 2) {
369: data[0] = _getPriceFromFeed(asset, 0, inUSD, true); // <= FOUND
370: data[1] = _getPriceFromFeed(asset, 0, inUSD, false); // <= FOUND
371: if (isMToken) {
372: uint256 exchangeRate = IMToken(asset).exchangeRateCached();
373: data[0].price = uint240((data[0].price * exchangeRate) / WAD);
374: data[1].price = uint240((data[1].price * exchangeRate) / WAD);
375: }
376:
377: return data;
378: }
379:
380:
381:
382: data[0] = _getPriceFromFeed(asset, 0, inUSD, true);
383: data[1] = _getPriceFromFeed(asset, 0, inUSD, false); // <= FOUND
384: data[2] = _getPriceFromFeed(asset, 1, inUSD, true);
385: data[3] = _getPriceFromFeed(asset, 1, inUSD, false);
386:
387: if (isMToken) {
388: uint256 exchangeRate = IMToken(asset).exchangeRateCached();
389: data[0].price = uint240((data[0].price * exchangeRate) / WAD);
390: data[1].price = uint240((data[1].price * exchangeRate) / WAD);
391: data[2].price = uint240((data[2].price * exchangeRate) / WAD);
392: data[3].price = uint240((data[3].price * exchangeRate) / WAD);
393: }
394:
395: return data;
396: }
['661']
661: function _getPriceDualFeed(
662: address asset,
663: bool inUSD,
664: bool getLower
665: ) internal view returns (uint256, uint256) {
666: FeedData memory feed0 = _getPriceFromFeed(asset, 0, inUSD, getLower); // <= FOUND
667: FeedData memory feed1 = _getPriceFromFeed(asset, 1, inUSD, getLower);
668:
669:
670:
671: if (feed0.hadError && feed1.hadError) return (0, BAD_SOURCE);
672:
673:
674: if (feed0.hadError || feed1.hadError) {
675: return (_getWorkingPrice(feed0, feed1), CAUTION);
676: }
677: if (getLower) {
678: return _calculateLowerPrice(feed0.price, feed1.price);
679: }
680:
681: return _calculateHigherPrice(feed0.price, feed1.price);
682: }
The use of fixed decimal values such as 1e18 or 1e8 in Solidity contracts can lead to inaccuracies, bugs, and vulnerabilities, particularly when interacting with tokens having different decimal configurations. Not all ERC20 tokens follow the standard 18 decimal places, and assumptions about decimal places can lead to miscalculations.
Resolution: Always retrieve and use the decimals()
function from the token contract itself when performing calculations involving token amounts. This ensures that your contract correctly handles tokens with any number of decimal places, mitigating the risk of numerical errors or under/overflows that could jeopardize contract integrity and user funds.
Num of instances: 32
Click to show findings
['160']
155:
156:
157: uint256 protocolFee = FixedPointMathLib.mulDiv(
158: rewardAmount,
159: centralRegistry.protocolHarvestFee(),
160: 1e18 // <= FOUND
161: );
['230']
224:
225:
226:
227: protocolFee = FixedPointMathLib.mulDiv(
228: rewardAmount,
229: harvestFee,
230: 1e18 // <= FOUND
231: );
['111']
111: reserve0 = (reserve0 * 1e18) / (10 ** data.decimals0); // <= FOUND
['115']
115: reserve1 = (reserve1 * 1e18) / (10 ** data.decimals1); // <= FOUND
['231']
231: uint256 ratio = ((1e18) * price0) / price1; // <= FOUND
['233']
232: uint256 sqrtPrice = FixedPointMathLib.sqrt(
233: FixedPointMathLib.sqrt((1e18) * ratio) * // <= FOUND
234: FixedPointMathLib.sqrt(1e36 + ratio * ratio) // <= FOUND
235: );
['237']
236: return
237: ((((1e18) * sqrtReserve) / sqrtPrice) * price0 * 2) / totalSupply; // <= FOUND
['111']
110:
111: reserve0 = (reserve0 * 1e18) / (10 ** data.decimals0); // <= FOUND
['111']
111: reserve1 = (reserve1 * 1e18) / (10 ** data.decimals1); // <= FOUND
['612']
609:
610:
611: _vaultData = _packVaultData(
612: FixedPointMathLib.mulDiv(yieldToVest, 1e18, periodToVest), // <= FOUND
613: block.timestamp + periodToVest
614: );
['728']
711:
712:
713:
714:
715:
716:
717:
718:
719: pendingRewards =
720: (
721: block.timestamp < vaultData.vestingPeriodEnd
722: ? (vaultData.rewardRate *
723: (block.timestamp - vaultData.lastVestClaim))
724: : (vaultData.rewardRate *
725: (vaultData.vestingPeriodEnd -
726: vaultData.lastVestClaim))
727: ) /
728: 1e18; // <= FOUND
['68']
66:
67:
68: return assets - FixedPointMathLib.mulDivUp(exitFee, assets, 1e18); // <= FOUND
['10']
8:
10: uint256 constant WAD = 1e18; // <= FOUND
['142']
137:
138:
139: uint256 protocolFee = FixedPointMathLib.mulDiv(
140: rewardAmounts[i],
141: harvestFee,
142: 1e18 // <= FOUND
143: );
['158']
154:
155: data[0] = abi.encodeWithSelector(
156: IGMXExchangeRouter.sendWnt.selector,
157: gmxDepositVault,
158: 0.01e18 // <= FOUND
159: );
['188']
175: data[3] = abi.encodeWithSelector(
176: IGMXExchangeRouter.createDeposit.selector,
177: IGMXExchangeRouter.CreateDepositParams(
178: address(this),
179: address(this),
180: address(0),
181: asset(),
182: underlyingTokens[0],
183: underlyingTokens[1],
184: new address[](0),
185: new address[](0),
186: 0,
187: false,
188: 0.01e18, // <= FOUND
189: 500000
190: )
191: );
['195']
193:
194: bytes[] memory results = IGMXExchangeRouter(gmxExchangeRouter)
195: .multicall{ value: 0.01e18 }(data); // <= FOUND
['77']
75:
77: uint256 public constant MAX_COLLATERALIZATION_RATIO = .91e18; // <= FOUND
['83']
81:
83: uint256 public constant MIN_LIQUIDATION_INCENTIVE = .01e18; // <= FOUND
['92']
90:
92: uint256 public constant MIN_BASE_CFACTOR = .1e18; // <= FOUND
['578']
577:
578: return ((maxLeverage - sumDebt) * 1e18) / price; // <= FOUND
['160']
155:
156:
157: uint256 protocolFee = FixedPointMathLib.mulDiv(
158: rewardAmount,
159: centralRegistry.protocolHarvestFee(),
160: 1e18 // <= FOUND
161: );
['240']
240: a = (((amount0 * 10000) / (10000 - swapFee)) * 1e18) / decimals0; // <= FOUND
['243']
242:
243: uint256 x = (reserve0 * 1e18) / decimals0; // <= FOUND
['243']
243: uint256 y = (reserve1 * 1e18) / decimals1; // <= FOUND
['244']
244: uint256 x2 = (x * x) / 1e18; // <= FOUND
['245']
245: uint256 y2 = (y * y) / 1e18; // <= FOUND
['246']
246: uint256 p = (y * (((x2 * 3 + y2) * 1e18) / (y2 * 3 + x2))) / x; // <= FOUND
['249']
249: uint256 den = ((a + x) * p) / 1e18 + y; // <= FOUND
['252']
251:
252: return ((num / den) * decimals0) / 1e18; // <= FOUND
['160']
155:
156:
157: uint256 protocolFee = FixedPointMathLib.mulDiv(
158: rewardAmount,
159: centralRegistry.protocolHarvestFee(),
160: 1e18 // <= FOUND
161: );
['36']
35:
36: return IWstETH(wstETH).getStETHByWstETH(1e18); // <= FOUND
In the instance where the function totalSupply() returns zero, it will inevitably lead to a division by zero error when used in mathematical operations, causing the transaction to fail and potentially disrupting contract functionality. This situation can inadvertently serve as a blocking mechanism, preventing valid transactions and operations. It's crucial to accommodate this special scenario in your code. One resolution could be implementing condition checks in your function to detect a zero totalSupply() and handle it differently, perhaps by returning a specific value or altering the operational flow, thus ensuring that transactions do not revert and the contract functions smoothly even in this edge case.
Num of instances: 2
Click to show findings
['91']
91: function _getPrice(
92: address asset,
93: bool inUSD,
94: bool getLower
95: ) internal view returns (PriceReturnData memory pData) {
96:
97: if (!isSupportedAsset[asset]) {
98: revert BaseVolatileLPAdaptor__AssetIsNotSupported();
99: }
100:
101:
102: AdaptorData memory data = adaptorData[asset];
103: IUniswapV2Pair pool = IUniswapV2Pair(asset);
104:
105:
106: uint256 totalSupply = pool.totalSupply();
107:
108: (uint256 reserve0, uint256 reserve1, ) = pool.getReserves();
109:
110: reserve0 = (reserve0 * 1e18) / (10 ** data.decimals0);
111: reserve1 = (reserve1 * 1e18) / (10 ** data.decimals1);
112:
113:
114: uint256 sqrtReserve = FixedPointMathLib.sqrt(reserve0 * reserve1);
115:
116: uint256 price0;
117: uint256 price1;
118: uint256 errorCode;
119:
120: IOracleRouter oracleRouter = IOracleRouter(
121: centralRegistry.oracleRouter()
122: );
123: (price0, errorCode) = oracleRouter.getPrice(
124: data.token0,
125: inUSD,
126: getLower
127: );
128:
129:
130: if (errorCode > 0) {
131: pData.hadError = true;
132: return pData;
133: }
134:
135: (price1, errorCode) = oracleRouter.getPrice(
136: data.token1,
137: inUSD,
138: getLower
139: );
140:
141:
142: if (errorCode > 0) {
143: pData.hadError = true;
144: return pData;
145: }
146:
147:
148: uint256 finalPrice = (2 *
149: sqrtReserve *
150: FixedPointMathLib.sqrt(price0 * price1)) / totalSupply;
151:
152:
153: if (_checkOracleOverflow(finalPrice)) {
154: pData.hadError = true;
155: return pData;
156: }
157:
158: pData.inUSD = inUSD;
159: pData.price = uint240(finalPrice);
160: }
['952']
952: function exchangeRateCached() public view returns (uint256) { // <= FOUND
953:
954:
955:
956:
957: return
958: ((marketUnderlyingHeld() + totalBorrows - totalReserves) * WAD) /
959: totalSupply;
960: }
Functions that bridge ERC20 tokens often do not interact with Ether (ETH), the native cryptocurrency of Ethereum. In these functions, msg.value
represents the amount of Ether sent in the transaction.
When a function is marked as payable
, it indicates that the function is allowed to receive Ether. However, if these functions are not designed to handle Ether, and someone unintentionally or intentionally sends Ether to these functions, the Ether could be locked in the contract forever, leading to a loss of funds. This is because if the contract does not have a specific function to withdraw or refund this Ether, there's no way to retrieve it.
To mitigate this issue, these functions should explicitly require that msg.value == 0
. This statement ensures that no Ether is being sent in the transaction. If msg.value
is not equal to zero, the transaction will revert, thereby preventing accidental loss of Ether.
In conclusion, requiring msg.value == 0
in functions that bridge ERC20 tokens ensures that only token transactions are processed, and prevents inadvertent loss of Ether, thereby increasing the security of the contract.
Num of instances: 1
Click to show findings
['37']
37: function borrowAndBridge(
38: address dToken,
39: uint256 borrowAmount,
40: SwapperLib.Swap memory swapData,
41: uint256 dstChainId
42: ) external payable nonReentrant {
43: uint256 balancePrior = IERC20(feeToken).balanceOf(address(this));
44:
45:
46: DToken(dToken).borrowFor(msg.sender, address(this), borrowAmount);
47:
48: address underlying = DToken(dToken).underlying();
49:
50:
51: if (underlying != feeToken) {
52: if (
53: swapData.target == address(0) ||
54: swapData.inputToken != underlying ||
55: swapData.outputToken != feeToken ||
56: swapData.inputAmount != borrowAmount
57: ) {
58: revert BorrowZapper__InvalidSwapData();
59: }
60:
61:
62: if (!centralRegistry.isSwapper(swapData.target)) {
63: revert BorrowZapper__InvalidSwapper(swapData.target);
64: }
65: unchecked {
66: SwapperLib.swap(centralRegistry, swapData);
67: }
68: } else {
69: if (swapData.target != address(0)) {
70: revert BorrowZapper__InvalidSwapData();
71: }
72: }
73:
74:
75: _sendFeeToken(
76: dstChainId,
77: msg.sender,
78: IERC20(feeToken).balanceOf(address(this)) - balancePrior
79: );
80: }
Assuming a year is always 365/364 days in a Solidity contract could lead to inaccuracies, especially when dealing with time-sensitive functionalities or calculations. The actual length of a year can vary due to the presence of leap years, which contain an extra day. By not accounting for this variation, contracts may exhibit incorrect behavior or calculations, potentially leading to significant discrepancies over time or vulnerabilities. Therefore, it's crucial to use accurate time calculation methods or libraries that account for such variations.
Num of instances: 1
Click to show findings
['116']
115:
116: uint256 public constant LOCK_DURATION = 52 weeks; // <= FOUND
Chainlink oracle provides reliable, real-time data feeds to smart contracts. However, in order to enhance security and minimize the potential impact of an oracle failure or manipulation, it's a good practice to establish minimum and maximum thresholds for these data inputs. Without this safeguard, an erroneous or maliciously manipulated data point from the oracle could potentially lead to severe consequences in contract behavior. Therefore, the values retrieved from Chainlink's oracle should be cross-verified against preset min/max boundaries to ensure they fall within the expected range. This extra layer of validation adds robustness and reduces the risk of oracle-related issues.
Num of instances: 1
Click to show findings
['823']
823: function _isSequencerValid() internal view returns (bool) {
824: address sequencer = centralRegistry.sequencer();
825:
826: if (sequencer != address(0)) {
827: (, int256 answer, uint256 startedAt, , ) = IChainlink(sequencer)
828: .latestRoundData();
829:
830:
831:
832:
833: if (
834: answer != 0 || block.timestamp < startedAt + GRACE_PERIOD_TIME
835: ) {
836: return false;
837: }
838: }
839:
840: return true;
841: }
Unsafe conversion from uint
to int
in Solidity can lead to unexpected overflows if the unsigned integer value exceeds the positive limit of the corresponding signed integer type. This is due to the fact that signed integers use one bit for the sign, effectively halving the positive range. An example is converting a uint256
number greater than type(uint128).max
to an int256
, which can result in an overflow. To mitigate this risk, consider using libraries like SafeCast, which include functions specifically designed to safely cast between different numerical types. They perform necessary checks and revert the transaction if an unsafe cast is attempted, thereby enhancing the security and robustness of the code.
Num of instances: 2
Click to show findings
['140']
140: return int256(value); // <= FOUND
['174']
174:
175:
176: ICurveSwap(lpMinter).remove_liquidity_one_coin(
177: lpAmount,
178: int128(uint128(singleAssetIndex)), // <= FOUND
179: 0
180: );
OpenZeppelin's AccessControl
library is designed with security in mind, encapsulating common access control patterns. Within this library, the grantRole
function is public and ensures proper access checks before the role is granted. However, by calling the internal _grantRole
function directly, developers bypass these pre-defined access controls. While this may be intentional, allowing for custom access controls, it risks introducing vulnerabilities if not handled with caution. Bypassing the native checks goes against the library's design philosophy, which emphasizes secure defaults. To uphold security, developers should consistently use public functions provided by OpenZeppelin, or, if choosing to call internal functions, ensure they implement and rigorously test their own access controls.
Num of instances: 1
Click to show findings
['57']
57: function updateDaoAddress() external {
58: address daoAddress = centralRegistry.daoAddress();
59: if (daoAddress != _DAO_ADDRESS) {
60: _revokeRole(PROPOSER_ROLE, _DAO_ADDRESS);
61: _revokeRole(EXECUTOR_ROLE, _DAO_ADDRESS);
62:
63: _grantRole(PROPOSER_ROLE, daoAddress); // <= FOUND
64: _grantRole(EXECUTOR_ROLE, daoAddress); // <= FOUND
65: _DAO_ADDRESS = daoAddress;
66: }
67: }
When invoking supportsInterface() on a contract, if the addressed contract doesn't adhere to the ERC-165 standard, the call may revert. This potential reversion isn't solely because of non-compliance; a contract could be designed maliciously to consume the entire transaction's gas. To circumvent these pitfalls, opt for a low-level staticcall() when calling supportsInterface(), setting a defined gas limit, and subsequently evaluating the return code. Alternatively, leverage OpenZeppelin's ERC165Checker.supportsInterface() for a safer approach.
Num of instances: 4
Click to show findings
['699']
699: function transferDaoOwnership(address newDaoAddress) external { // <= FOUND
700: _checkElevatedPermissions();
701:
702:
703: address previousDaoAddress = daoAddress;
704: daoAddress = newDaoAddress;
705:
706:
707: delete hasDaoPermissions[previousDaoAddress];
708:
709: hasDaoPermissions[newDaoAddress] = true;
710: emit OwnershipTransferred(previousDaoAddress, newDaoAddress);
711:
712:
713: if (timelock != address(0)) {
714: if (
715: ERC165Checker.supportsInterface(
716: timelock,
717: type(ITimelock).interfaceId
718: )
719: ) {
720: ITimelock(timelock).updateDaoAddress();
721: }
722: }
723: }
['1141']
1141: function addMarketManager(
1142: address newMarketManager,
1143: uint256 marketInterestFactor
1144: ) public virtual {
1145: _checkElevatedPermissions();
1146:
1147:
1148: if (isMarketManager[newMarketManager]) {
1149: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
1150: }
1151:
1152:
1153: if (
1154: !ERC165Checker.supportsInterface(
1155: newMarketManager,
1156: type(IMarketManager).interfaceId
1157: )
1158: ) {
1159: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
1160: }
1161:
1162:
1163: if (marketInterestFactor > 5000) {
1164: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
1165: }
1166:
1167: isMarketManager[newMarketManager] = true;
1168:
1169: marketManagers.push(newMarketManager);
1170:
1171:
1172: protocolInterestFactor[newMarketManager] = _bpToWad(
1173: marketInterestFactor
1174: );
1175:
1176: emit NewCurvanceContract("Market Manager", newMarketManager);
1177: emit InterestFeeSet(newMarketManager, marketInterestFactor);
1178: }
['1049']
1049: function _setInterestRateModel(
1050: IInterestRateModel newInterestRateModel
1051: ) internal {
1052:
1053: if (
1054: !ERC165Checker.supportsInterface(
1055: address(newInterestRateModel),
1056: type(IInterestRateModel).interfaceId
1057: )
1058: ) {
1059: revert DToken__ValidationFailed();
1060: }
1061:
1062:
1063: address oldInterestRateModel = address(interestRateModel);
1064:
1065:
1066: interestRateModel = newInterestRateModel;
1067: marketData.compoundRate = newInterestRateModel.compoundRate();
1068:
1069: emit NewMarketInterestRateModel(
1070: oldInterestRateModel,
1071: address(newInterestRateModel),
1072: marketData.compoundRate
1073: );
1074: }
['1196']
1196: function setPositionFolding(address newPositionFolding) external { // <= FOUND
1197: _checkElevatedPermissions();
1198:
1199: if (
1200: !ERC165Checker.supportsInterface(
1201: newPositionFolding,
1202: type(IPositionFolding).interfaceId
1203: )
1204: ) {
1205: _revert(_INVALID_PARAMETER_SELECTOR);
1206: }
1207:
1208:
1209: address oldPositionFolding = positionFolding;
1210:
1211:
1212: positionFolding = newPositionFolding;
1213:
1214: emit NewPositionFoldingContract(
1215: oldPositionFolding,
1216: newPositionFolding
1217: );
1218: }
SafeTransferLib as similarly named function as OpenZepelins SafeERC20 module however it's functions such as safeTransferFrom don't check if the contract exists which can result in silent failures when performing such operations. As such it is recommended to perform a contract existence check beforehand.
Num of instances: 6
Click to show findings
['4']
4: import { CTokenCompounding, FixedPointMathLib, SafeTransferLib, IERC20, ICentralRegistry } from "contracts/market/collateral/CTokenCompounding.sol"; // <= FOUND
['11']
11: import { SafeTransferLib } from "contracts/libraries/external/SafeTransferLib.sol"; // <= FOUND
['6']
6: import { ERC4626, SafeTransferLib } from "contracts/libraries/ERC4626.sol"; // <= FOUND
['4']
4: import { CTokenBase, FixedPointMathLib, SafeTransferLib, ERC4626 } from "contracts/market/collateral/CTokenBase.sol"; // <= FOUND
['4']
4: import { CTokenBase, SafeTransferLib, ERC4626 } from "contracts/market/collateral/CTokenBase.sol"; // <= FOUND
['4']
4: import { CTokenCompounding, SafeTransferLib, IERC20, FixedPointMathLib, ICentralRegistry } from "contracts/market/collateral/CTokenCompounding.sol"; // <= FOUND
External calls within modifiers can introduce unintended reentrancy risks and obscure the flow of a contract's logic. Modifiers are designed to perform checks before executing function logic, and using external calls can make the flow unpredictable due to the potential for state changes or reentrancy by the called contract. Such ambiguity makes code harder to audit and understand. To ensure clarity and security, avoid external calls in modifiers. Instead, place them in the function body, where their execution order and effects are more explicit. This practice enhances contract readability, aids auditors, and minimizes unexpected behaviors.
Num of instances: 1
Click to show findings
['110']
110: modifier checkSlippage(address account, uint256 slippage) { // <= FOUND
111: (uint256 collateralBefore, uint256 debtBefore) = marketManager
112: .solvencyOf(account);
113: uint256 liquidityBefore = collateralBefore - debtBefore;
114:
115: _;
116:
117: (uint256 sumCollateral, uint256 sumDebt) = marketManager.solvencyOf(
118: account
119: );
120:
121: uint256 liquidityAfter = sumCollateral - sumDebt;
122:
123: if (liquidityBefore > liquidityAfter) {
124: if (
125: liquidityBefore - liquidityAfter >=
126: (liquidityBefore * slippage) / DENOMINATOR
127: ) {
128: revert PositionFolding__InvalidSlippage();
129: }
130: }
131: }
Using an immutable or constant state variable as a gas limit in a contract can introduce risks, primarily because gas costs on the Ethereum network can change due to various factors like network upgrades. If the contract relies on a hardcoded gas limit, it may either waste gas if the limit is too high or fail to execute if the limit is too low. Moreover, a fixed gas limit doesn't adapt to different scenarios the contract might encounter, potentially becoming a point of failure or inefficiency. It's often better to allow flexibility in setting gas limits to adapt to real-time network conditions.
Num of instances: 1
Click to show findings
['84']
79:
80:
81:
82:
83:
84: (, bytes memory revertData) = address(vault).staticcall{ gas: GAS_LIMIT }( // <= FOUND
It is preferable to skip operations on an array index when a condition is not met rather than reverting the whole transaction as reverting can introduce the possiblity of malicous actors purposefully introducing array objects which fail conditional checks within for/while loops so group operations fail. As such it is recommended to simply skip such array indices over reverting unless there is a valid security or logic reason behind not doing so.
Num of instances: 1
Click to show findings
['647']
647: for (uint256 i; i < numTokenSwaps; ) { // <= FOUND
648:
649: if (!centralRegistry.isSwapper(tokenSwaps[i].target)) {
650: revert ComplexZapper__InvalidSwapper(i, tokenSwaps[i].target); // <= FOUND
651: }
652:
653:
654: unchecked {
655: SwapperLib.swap(centralRegistry, tokenSwaps[i++]);
656: }
657: }
In Solidity, when values are being assigned in constructors to unsigned or integer variables, it's crucial to ensure the provided values adhere to the protocol's specific operational boundaries as laid out in the project specifications and documentation. If the constructors lack appropriate validation checks, there's a risk of setting state variables with values that could cause unexpected and potentially detrimental behavior within the contract's operations, violating the intended logic of the protocol. This can compromise the contract's security and impact the maintainability and reliability of the system. In order to avoid such issues, it is recommended to incorporate rigorous validation checks in constructors. These checks should align with the project's defined rules and constraints, making use of Solidity's built-in require function to enforce these conditions. If the validation checks fail, the require function will cause the transaction to revert, ensuring the integrity and adherence to the protocol's expected behavior.
Num of instances: 35
Click to show findings
['67']
67: constructor(
68: ICentralRegistry centralRegistry_,
69: IERC20 asset_,
70: address marketManager_,
71: IVeloGauge gauge,
72: IVeloPairFactory pairFactory,
73: IVeloRouter router
74: ) CTokenCompounding(centralRegistry_, asset_, marketManager_) {
75: if (block.chainid != 8453) {
76: revert AerodromeStableCToken__ChainIsNotSupported();
77: }
78:
79:
80: address _asset = asset();
81:
82:
83: if (gauge.stakingToken() != _asset) {
84: revert AerodromeStableCToken__StakingTokenIsNotAsset(
85: gauge.stakingToken()
86: );
87: }
88:
89:
90: if (!IVeloPool(_asset).stable()) {
91: revert AerodromeStableCToken__AssetIsNotStable();
92: }
93:
94:
95: strategyData.token0 = IVeloPool(_asset).token0();
96: strategyData.token1 = IVeloPool(_asset).token1();
97:
98:
99: if (strategyData.token1 == address(rewardToken)) {
100: strategyData.token1 = strategyData.token0;
101: strategyData.token0 = address(rewardToken);
102: }
103: strategyData.decimalsA = 10 ** IERC20(strategyData.token0).decimals();
104: strategyData.decimalsB = 10 ** IERC20(strategyData.token1).decimals();
105:
106: strategyData.gauge = gauge; // <= FOUND
107: strategyData.router = router; // <= FOUND
108: strategyData.pairFactory = pairFactory; // <= FOUND
109:
110: isUnderlyingToken[strategyData.token0] = true;
111: isUnderlyingToken[strategyData.token1] = true;
112:
113: rewardTokenIsUnderlying = (address(rewardToken) ==
114: strategyData.token0 ||
115: address(rewardToken) == strategyData.token1);
116: }
['65']
65: constructor(
66: ICentralRegistry centralRegistry_,
67: IERC20 asset_,
68: address marketManager_,
69: IVeloGauge gauge,
70: IVeloPairFactory pairFactory,
71: IVeloRouter router
72: ) CTokenCompounding(centralRegistry_, asset_, marketManager_) {
73: if (block.chainid != 8453) {
74: revert AerodromeVolatileCToken__ChainIsNotSupported();
75: }
76:
77:
78: address _asset = asset();
79:
80:
81: if (gauge.stakingToken() != _asset) {
82: revert AerodromeVolatileCToken__StakingTokenIsNotAsset(
83: gauge.stakingToken()
84: );
85: }
86:
87:
88: if (IVeloPool(_asset).stable()) {
89: revert AerodromeVolatileCToken__AssetIsNotStable();
90: }
91:
92:
93: strategyData.token0 = IVeloPool(_asset).token0();
94: strategyData.token1 = IVeloPool(_asset).token1();
95:
96:
97: if (strategyData.token1 == address(rewardToken)) {
98: strategyData.token1 = strategyData.token0;
99: strategyData.token0 = address(rewardToken);
100: }
101: strategyData.gauge = gauge; // <= FOUND
102: strategyData.router = router; // <= FOUND
103: strategyData.pairFactory = pairFactory; // <= FOUND
104:
105: isUnderlyingToken[strategyData.token0] = true;
106: isUnderlyingToken[strategyData.token1] = true;
107:
108: rewardTokenIsUnderlying = (address(rewardToken) ==
109: strategyData.token0 ||
110: address(rewardToken) == strategyData.token1);
111: }
['63']
63: constructor(
64: ICentralRegistry centralRegistry_,
65: IERC20 asset_,
66: address marketManager_,
67: uint256 pid_,
68: address rewarder_,
69: address booster_
70: ) CTokenCompounding(centralRegistry_, asset_, marketManager_) {
71: strategyData.pid = pid_; // <= FOUND
72: strategyData.booster = IBooster(booster_);
73:
74:
75: (address pidToken, , , address balRewards, , bool shutdown) = IBooster(
76: booster_
77: ).poolInfo(strategyData.pid);
78:
79:
80:
81: if (pidToken != asset() || shutdown || balRewards != rewarder_) {
82: revert AuraCToken__InvalidVaultConfig();
83: }
84:
85: strategyData.rewarder = IBaseRewardPool(rewarder_);
86: strategyData.balancerVault = IBalancerVault(
87: IBalancerPool(pidToken).getVault()
88: );
89: strategyData.balancerPoolId = IBalancerPool(pidToken).getPoolId();
90:
91:
92:
93: strategyData.rewardTokens.push() = _BAL;
94:
95:
96: strategyData.rewardTokens.push() = _AURA;
97:
98: uint256 extraRewardsLength = IBaseRewardPool(rewarder_)
99: .extraRewardsLength();
100: for (uint256 i; i < extraRewardsLength; ) {
101: unchecked {
102: address rewardToken = IStashWrapper(
103: IRewards(IBaseRewardPool(rewarder_).extraRewards(i++))
104: .rewardToken()
105: ).baseToken();
106:
107: if (rewardToken != _AURA && rewardToken != _BAL) {
108: strategyData.rewardTokens.push() = rewardToken;
109: }
110: }
111: }
112:
113:
114: (address[] memory queriedTokens, , ) = strategyData
115: .balancerVault
116: .getPoolTokens(strategyData.balancerPoolId);
117: strategyData.underlyingTokens = queriedTokens;
118:
119: uint256 numUnderlyingTokens = strategyData.underlyingTokens.length;
120: for (uint256 i; i < numUnderlyingTokens; ) {
['29']
29: constructor(
30: ICentralRegistry centralRegistry_,
31: IVault balancerVault_
32: ) BaseOracleAdaptor(centralRegistry_) {
33: balancerVault = balancerVault_; // <= FOUND
34: }
['28']
28: constructor(ICentralRegistry centralRegistry_) {
29: if (
30: !ERC165Checker.supportsInterface(
31: address(centralRegistry_),
32: type(ICentralRegistry).interfaceId
33: )
34: ) {
35: revert BaseOracleAdaptor__InvalidCentralRegistry();
36: }
37:
38: centralRegistry = centralRegistry_; // <= FOUND
39: }
['82']
82: constructor(IBlastCentralRegistry centralRegistry_) {
83: if (
84: !ERC165Checker.supportsInterface(
85: address(centralRegistry_),
86: type(IBlastCentralRegistry).interfaceId
87: )
88: ) {
89: revert BlastNativeYieldManager__InvalidCentralRegistry();
90: }
91:
92: centralRegistry = centralRegistry_; // <= FOUND
93:
94: address[] memory marketManagers = centralRegistry_.marketManagers();
95: uint256 numMarkets = marketManagers.length;
96:
97:
98: for (uint256 i; i < numMarkets; ) {
99: isMarketManager[marketManagers[i++]] = true;
100: }
101:
102:
103:
104: CHAIN_YIELD_MANAGER.configureClaimableGas();
105: CHAIN_YIELD_MANAGER.configureGovernor(centralRegistry_.daoAddress());
106:
107: }
['99']
99: constructor(
100: ICentralRegistry centralRegistry_,
101: IERC20 asset_,
102: address MarketManager_
103: ) Delegable(centralRegistry_) {
104: _asset = asset_; // <= FOUND
105: _name = string.concat("Curvance collateralized ", asset_.name());
106: _symbol = string.concat("c", asset_.symbol());
107: _decimals = asset_.decimals();
108:
109: if (
110: !ERC165Checker.supportsInterface(
111: address(centralRegistry_),
112: type(ICentralRegistry).interfaceId
113: )
114: ) {
115: revert CTokenBase__InvalidCentralRegistry();
116: }
117:
118:
119: if (!centralRegistry.isMarketManager(MarketManager_)) {
120: revert CTokenBase__InvalidMarketManager();
121: }
122:
123:
124: marketManager = IMarketManager(MarketManager_);
125:
126:
127:
128: if (asset_.totalSupply() >= type(uint232).max) {
129: revert CTokenBase__UnderlyingAssetTotalSupplyExceedsMaximum();
130: }
131: }
['57']
57: constructor(ICentralRegistry centralRegistry_, address builder_) {
58: if (
59: !ERC165Checker.supportsInterface(
60: address(centralRegistry_),
61: type(ICentralRegistry).interfaceId
62: )
63: ) {
64: revert CVE__ParametersAreInvalid();
65: }
66:
67: if (builder_ == address(0)) {
68: builder_ = msg.sender;
69: }
70:
71: centralRegistry = centralRegistry_; // <= FOUND
72: tokenGenerationEventTimestamp = block.timestamp;
73: builderAddress = builder_;
74:
75:
76:
77:
78: daoTreasuryAllocation = 60900010e18;
79:
80: initialCommunityAllocation = 1575000259e16;
81:
82: builderAllocation = 44100007245e15;
83:
84: builderAllocationPerMonth = builderAllocation / 48;
85:
86:
87:
88:
89:
90: uint256 initialTokenMint = 50400008285e15;
91:
92: _mint(msg.sender, initialTokenMint);
93: }
['56']
56: constructor(
57: ICentralRegistry centralRegistry_,
58: uint256 maximumClaimAmount_
59: ) {
60: if (
61: !ERC165Checker.supportsInterface(
62: address(centralRegistry_),
63: type(ICentralRegistry).interfaceId
64: )
65: ) {
66: revert CVEInitialDistribution__InvalidCentralRegistry();
67: }
68: centralRegistry = centralRegistry_; // <= FOUND
69:
70:
71:
72:
73:
74: if (maximumClaimAmount_ * lockedClaimMultiplier > 15750002.59 ether) {
75: revert CVEInitialDistribution__InvalidlockedClaimMultiplier();
76: }
77:
78: cve = centralRegistry.cve();
79: veCVE = IVeCVE(centralRegistry.veCVE());
80: maximumClaimAmount = maximumClaimAmount_; // <= FOUND
81: }
['21']
21: constructor(address _target) {
22: target = _target; // <= FOUND
23: }
['248']
248: constructor(
249: address daoAddress_,
250: address timelock_,
251: address emergencyCouncil_,
252: uint256 genesisEpoch_,
253: address sequencer_,
254: address feeToken_
255: ) {
256: if (feeToken_ == address(0)) {
257: revert CentralRegistry__InvalidFeeToken();
258: }
259:
260: if (daoAddress_ == address(0)) {
261: daoAddress_ = msg.sender;
262: }
263:
264: if (timelock_ == address(0)) {
265: timelock_ = msg.sender;
266: }
267:
268: if (emergencyCouncil_ == address(0)) {
269: emergencyCouncil_ = msg.sender;
270: }
271:
272:
273: daoAddress = daoAddress_;
274: timelock = timelock_;
275: emergencyCouncil = emergencyCouncil_;
276:
277:
278:
279: hasDaoPermissions[daoAddress] = true;
280: hasDaoPermissions[timelock] = true;
281: hasDaoPermissions[emergencyCouncil] = true;
282:
283:
284:
285: hasElevatedPermissions[timelock] = true;
286: hasElevatedPermissions[emergencyCouncil] = true;
287:
288: genesisEpoch = genesisEpoch_; // <= FOUND
289: sequencer = sequencer_; // <= FOUND
290:
291: feeToken = feeToken_;
292:
293: emit OwnershipTransferred(address(0), daoAddress_);
294: emit NewTimelockConfiguration(address(0), timelock_);
295: emit EmergencyCouncilTransferred(address(0), emergencyCouncil_);
296: }
['30']
30: constructor(ICentralRegistry centralRegistry_) {
31: if (
32: !ERC165Checker.supportsInterface(
33: address(centralRegistry_),
34: type(ICentralRegistry).interfaceId
35: )
36: ) {
37: revert CVE__ParametersAreInvalid();
38: }
39: centralRegistry = centralRegistry_; // <= FOUND
40: }
['89']
89: constructor(
90: ICentralRegistry centralRegistry_,
91: address marketManager_,
92: address WETH_
93: ) {
94: if (
95: !ERC165Checker.supportsInterface(
96: address(centralRegistry_),
97: type(ICentralRegistry).interfaceId
98: )
99: ) {
100: revert ComplexZapper__InvalidCentralRegistry();
101: }
102:
103: centralRegistry = centralRegistry_; // <= FOUND
104:
105:
106:
107: if (!centralRegistry.isMarketManager(marketManager_)) {
108: revert ComplexZapper__InvalidMarketManager();
109: }
110:
111: marketManager = IMarketManager(marketManager_);
112: WETH = WETH_; // <= FOUND
113: }
['76']
76: constructor(ICentralRegistry centralRegistry_) {
77: if (
78: !ERC165Checker.supportsInterface(
79: address(centralRegistry_),
80: type(ICentralRegistry).interfaceId
81: )
82: ) {
83: revert CurvanceDAOLBP__InvalidCentralRegistry();
84: }
85:
86: centralRegistry = centralRegistry_; // <= FOUND
87: cve = centralRegistry.cve();
88: }
['28']
28: constructor(
29: ICentralRegistry centralRegistry_
30: )
31: TimelockController(
32: MINIMUM_DELAY,
33: new address[](0),
34: new address[](0),
35: address(0)
36: )
37: {
38: if (
39: !ERC165Checker.supportsInterface(
40: address(centralRegistry_),
41: type(ICentralRegistry).interfaceId
42: )
43: ) {
44: revert Timelock__InvalidCentralRegistry(address(centralRegistry_));
45: }
46:
47: centralRegistry = centralRegistry_; // <= FOUND
48:
49:
50: _DAO_ADDRESS = centralRegistry.daoAddress();
51: _grantRole(PROPOSER_ROLE, _DAO_ADDRESS);
52: _grantRole(EXECUTOR_ROLE, _DAO_ADDRESS);
53: }
['160']
160: constructor(
161: ICentralRegistry centralRegistry_,
162: address underlying_,
163: address marketManager_,
164: address interestRateModel_
165: ) Delegable(centralRegistry_) {
166: if (
167: !ERC165Checker.supportsInterface(
168: address(centralRegistry_),
169: type(ICentralRegistry).interfaceId
170: )
171: ) {
172: revert DToken__InvalidCentralRegistry();
173: }
174:
175:
176:
177: if (!centralRegistry.isMarketManager(marketManager_)) {
178: revert DToken__MarketManagerIsNotLendingMarket();
179: }
180:
181:
182: marketManager = IMarketManager(marketManager_);
183:
184:
185: marketData.lastTimestampUpdated = uint40(block.timestamp);
186: marketData.exchangeRate = uint216(WAD);
187:
188: _setInterestRateModel(IInterestRateModel(interestRateModel_));
189:
190:
191:
192: uint256 newInterestFactor = centralRegistry.protocolInterestFactor(
193: marketManager_
194: );
195: interestFactor = newInterestFactor;
196:
197: emit NewInterestFactor(0, newInterestFactor);
198:
199: underlying = underlying_; // <= FOUND
200: name = string.concat(
201: "Curvance interest bearing ",
202: IERC20(underlying_).name()
203: );
204: symbol = string.concat("c", IERC20(underlying_).symbol());
205:
206:
207:
208: if (IERC20(underlying).totalSupply() >= type(uint232).max) {
209: revert DToken__UnderlyingAssetTotalSupplyExceedsMaximum();
210: }
211: }
['45']
45: constructor(ICentralRegistry centralRegistry_) {
46: if (
47: !ERC165Checker.supportsInterface(
48: address(centralRegistry_),
49: type(ICentralRegistry).interfaceId
50: )
51: ) {
52: revert Delegable__InvalidCentralRegistry();
53: }
54:
55: centralRegistry = centralRegistry_; // <= FOUND
56: }
['206']
206: constructor(
207: ICentralRegistry centralRegistry_,
208: uint256 baseRatePerYear,
209: uint256 vertexRatePerYear,
210: uint256 vertexUtilStart,
211: uint256 adjustmentRate,
212: uint256 adjustmentVelocity,
213: uint256 vertexMultiplierMax,
214: uint256 decayRate
215: ) {
216: if (
217: !ERC165Checker.supportsInterface(
218: address(centralRegistry_),
219: type(ICentralRegistry).interfaceId
220: )
221: ) {
222: revert DynamicInterestRateModel__InvalidCentralRegistry();
223: }
224:
225: centralRegistry = centralRegistry_; // <= FOUND
226:
227: _updateDynamicInterestRateModel(
228: baseRatePerYear,
229: vertexRatePerYear,
230: vertexUtilStart,
231: adjustmentRate,
232: adjustmentVelocity,
233: vertexMultiplierMax,
234: decayRate,
235: true
236: );
237: }
['141']
141: constructor(
142: ICentralRegistry centralRegistry_,
143: address oneBalanceFeeManager_
144: ) {
145: if (
146: !ERC165Checker.supportsInterface(
147: address(centralRegistry_),
148: type(ICentralRegistry).interfaceId
149: )
150: ) {
151: revert FeeAccumulator__InvalidCentralRegistry();
152: }
153: if (oneBalanceFeeManager_ == address(0)) {
154: revert FeeAccumulator__OneBalanceFeeManagerIsZeroAddress();
155: }
156:
157: centralRegistry = centralRegistry_; // <= FOUND
158: feeToken = centralRegistry.feeToken();
159: oneBalanceFeeManager = oneBalanceFeeManager_;
160: _feeTokenUnit = 10 ** IERC20(feeToken).decimals();
161:
162:
163: _messagingHubStored = centralRegistry.protocolMessagingHub();
164:
165:
166:
167: SafeTransferLib.safeApprove(
168: feeToken,
169: _messagingHubStored,
170: type(uint256).max
171: );
172: }
['40']
40: constructor(ICentralRegistry centralRegistry_) {
41: if (
42: !ERC165Checker.supportsInterface(
43: address(centralRegistry_),
44: type(ICentralRegistry).interfaceId
45: )
46: ) {
47: revert FeeTokenBridgingHub__InvalidCentralRegistry();
48: }
49:
50: centralRegistry = centralRegistry_; // <= FOUND
51:
52: feeToken = centralRegistry.feeToken();
53: }
['42']
42: constructor(ICentralRegistry centralRegistry_) {
43: if (
44: !ERC165Checker.supportsInterface(
45: address(centralRegistry_),
46: type(ICentralRegistry).interfaceId
47: )
48: ) {
49: revert GaugeErrors.InvalidAddress();
50: }
51: centralRegistry = centralRegistry_; // <= FOUND
52:
53: cve = centralRegistry.cve();
54: veCVE = IVeCVE(centralRegistry.veCVE());
55: }
['170']
170: constructor(ICentralRegistry centralRegistry_) {
171: if (
172: !ERC165Checker.supportsInterface(
173: address(centralRegistry_),
174: type(ICentralRegistry).interfaceId
175: )
176: ) {
177:
178: _revert(0x78eefdcc);
179: }
180:
181: centralRegistry = centralRegistry_; // <= FOUND
182: }
['56']
56: constructor(ICentralRegistry centralRegistry_, address paymentToken_) {
57: _name = "CVE Options";
58: _symbol = "oCVE";
59:
60: if (
61: !ERC165Checker.supportsInterface(
62: address(centralRegistry_),
63: type(ICentralRegistry).interfaceId
64: )
65: ) {
66: revert OCVE__ParametersAreInvalid();
67: }
68:
69: if (paymentToken_ == address(0)) {
70: revert OCVE__ParametersAreInvalid();
71: }
72:
73: centralRegistry = centralRegistry_; // <= FOUND
74: paymentToken = paymentToken_;
75: if (paymentToken_ == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {
76: paymentTokenDecimals = 18;
77: } else {
78: paymentTokenDecimals = ERC20(paymentToken_).decimals();
79: }
80: cve = centralRegistry.cve();
81:
82:
83: _mint(msg.sender, 15750002.59 ether);
84: }
['132']
132: constructor(ICentralRegistry centralRegistry_) {
133: if (
134: !ERC165Checker.supportsInterface(
135: address(centralRegistry_),
136: type(ICentralRegistry).interfaceId
137: )
138: ) {
139: _revert(_INVALID_PARAMETER_SELECTOR);
140: }
141:
142: centralRegistry = centralRegistry_; // <= FOUND
143: }
['59']
59: constructor(
60: ICentralRegistry centralRegistry_,
61: IERC20 asset_,
62: address marketManager_,
63: IPendleRouter router_
64: ) CTokenCompounding(centralRegistry_, asset_, marketManager_) {
65: strategyData.router = router_; // <= FOUND
66: strategyData.lp = IPMarket(address(asset_));
67:
68: (strategyData.sy, strategyData.pt, strategyData.yt) = strategyData
69: .lp
70: .readTokens();
71:
72: strategyData.rewardTokens = strategyData.lp.getRewardTokens();
73:
74:
75:
76: strategyData.underlyingTokens = strategyData.sy.getTokensIn();
77: uint256 numUnderlyingTokens = strategyData.underlyingTokens.length;
78: for (uint256 i; i < numUnderlyingTokens; ) {
79: unchecked {
80: isUnderlyingToken[strategyData.underlyingTokens[i++]] = true;
81: }
82: }
83: }
['69']
69: constructor(
70: ICentralRegistry centralRegistry_,
71: IPendlePTOracle ptOracle_
72: ) BaseOracleAdaptor(centralRegistry_) {
73: ptOracle = ptOracle_; // <= FOUND
74: }
['15']
15: constructor(address _sDai, address _dai, address _daiAggregator) {
16: sDai = _sDai; // <= FOUND
17: dai = _dai; // <= FOUND
18: daiAggregator = _daiAggregator; // <= FOUND
19: }
['62']
62: constructor(ICentralRegistry centralRegistry_, address WETH_) {
63: if (
64: !ERC165Checker.supportsInterface(
65: address(centralRegistry_),
66: type(ICentralRegistry).interfaceId
67: )
68: ) {
69: revert SimpleRewardZapper__InvalidCentralRegistry();
70: }
71:
72: address locker = centralRegistry_.cveLocker();
73:
74:
75:
76: if (locker == address(0)) {
77: revert SimpleRewardZapper__InvalidCVELocker();
78: }
79:
80: centralRegistry = centralRegistry_; // <= FOUND
81: cveLocker = ICVELocker(locker);
82: rewardToken = ICVELocker(locker).rewardToken();
83: WETH = WETH_; // <= FOUND
84: }
['53']
53: constructor(
54: ICentralRegistry centralRegistry_,
55: address marketManager_,
56: address WETH_
57: ) {
58: if (
59: !ERC165Checker.supportsInterface(
60: address(centralRegistry_),
61: type(ICentralRegistry).interfaceId
62: )
63: ) {
64: revert SimpleZapper__InvalidCentralRegistry();
65: }
66:
67: centralRegistry = centralRegistry_; // <= FOUND
68:
69:
70:
71: if (!centralRegistry.isMarketManager(marketManager_)) {
72: revert SimpleZapper__InvalidMarketManager();
73: }
74:
75: marketManager = IMarketManager(marketManager_);
76: WETH = WETH_; // <= FOUND
77: }
['15']
15: constructor(address _sFrax, address _frax, address _fraxAggregator) {
16: sFrax = _sFrax; // <= FOUND
17: frax = _frax; // <= FOUND
18: fraxAggregator = _fraxAggregator; // <= FOUND
19: }
['65']
65: constructor(
66: ICentralRegistry centralRegistry_,
67: IStaticOracle oracleAddress_,
68: address WETH_
69: ) BaseOracleAdaptor(centralRegistry_) {
70: uniswapOracleRouter = oracleAddress_; // <= FOUND
71: WETH = WETH_; // <= FOUND
72: }
['196']
196: constructor(ICentralRegistry centralRegistry_) {
197: _name = "Vote Escrowed CVE";
198: _symbol = "veCVE";
199:
200: if (
201: !ERC165Checker.supportsInterface(
202: address(centralRegistry_),
203: type(ICentralRegistry).interfaceId
204: )
205: ) {
206: revert VeCVE__ParametersAreInvalid();
207: }
208:
209: centralRegistry = centralRegistry_; // <= FOUND
210: genesisEpoch = centralRegistry.genesisEpoch();
211: cve = centralRegistry.cve();
212: cveLocker = ICVELocker(centralRegistry.cveLocker());
213: }
['68']
68: constructor(
69: ICentralRegistry centralRegistry_,
70: IERC20 asset_,
71: address marketManager_,
72: IVeloGauge gauge,
73: IVeloPairFactory pairFactory,
74: IVeloRouter router
75: ) CTokenCompounding(centralRegistry_, asset_, marketManager_) {
76: if (block.chainid != 10) {
77: revert VelodromeStableCToken__ChainIsNotSupported();
78: }
79:
80:
81: address _asset = asset();
82:
83:
84: if (gauge.stakingToken() != _asset) {
85: revert VelodromeStableCToken__StakingTokenIsNotAsset(
86: gauge.stakingToken()
87: );
88: }
89:
90:
91: if (!IVeloPool(_asset).stable()) {
92: revert VelodromeStableCToken__AssetIsNotStable();
93: }
94:
95:
96: strategyData.token0 = IVeloPool(_asset).token0();
97: strategyData.token1 = IVeloPool(_asset).token1();
98:
99:
100: if (strategyData.token1 == address(rewardToken)) {
101: strategyData.token1 = strategyData.token0;
102: strategyData.token0 = address(rewardToken);
103: }
104: strategyData.decimalsA = 10 ** IERC20(strategyData.token0).decimals();
105: strategyData.decimalsB = 10 ** IERC20(strategyData.token1).decimals();
106:
107: strategyData.gauge = gauge; // <= FOUND
108: strategyData.router = router; // <= FOUND
109: strategyData.pairFactory = pairFactory; // <= FOUND
110:
111: isUnderlyingToken[strategyData.token0] = true;
112: isUnderlyingToken[strategyData.token1] = true;
113:
114: rewardTokenIsUnderlying = (address(rewardToken) ==
115: strategyData.token0 ||
116: address(rewardToken) == strategyData.token1);
117: }
['58']
58: constructor(
59: ICentralRegistry centralRegistry_,
60: IERC20 asset_,
61: address marketManager_,
62: IVeloGauge gauge,
63: IVeloPairFactory pairFactory,
64: IVeloRouter router
65: ) CTokenCompounding(centralRegistry_, asset_, marketManager_) {
66: if (block.chainid != 10) {
67: revert VelodromeVolatileCToken__ChainIsNotSupported();
68: }
69:
70:
71: address _asset = asset();
72:
73:
74: if (gauge.stakingToken() != _asset) {
75: revert VelodromeVolatileCToken__StakingTokenIsNotAsset(
76: gauge.stakingToken()
77: );
78: }
79:
80:
81: if (IVeloPool(_asset).stable()) {
82: revert VelodromeVolatileCToken__AssetIsNotStable();
83: }
84:
85:
86: strategyData.token0 = IVeloPool(_asset).token0();
87: strategyData.token1 = IVeloPool(_asset).token1();
88:
89:
90: if (strategyData.token1 == address(rewardToken)) {
91: strategyData.token1 = strategyData.token0;
92: strategyData.token0 = address(rewardToken);
93: }
94: strategyData.gauge = gauge; // <= FOUND
95: strategyData.router = router; // <= FOUND
96: strategyData.pairFactory = pairFactory; // <= FOUND
97:
98: isUnderlyingToken[strategyData.token0] = true;
99: isUnderlyingToken[strategyData.token1] = true;
100:
101: rewardTokenIsUnderlying = (address(rewardToken) ==
102: strategyData.token0 ||
103: address(rewardToken) == strategyData.token1);
104: }
['15']
15: constructor(address _wstETH, address _stETH, address _stETHAggregator) {
16: wstETH = _wstETH; // <= FOUND
17: stETH = _stETH; // <= FOUND
18: stETHAggregator = _stETHAggregator; // <= FOUND
19: }
To ensure accuracy in comparisons within programming, especially when dealing with integers, it's often more efficient to use multiplication rather than division. This approach stems from the fact that division operations are generally slower and more complex than multiplication. And in the context of solidity they can cause precision errors.
Suppose you want to compare if a/b is greater than c/d (where a, b, c, and d are integers). Instead of performing division, which is prone to precision errors, you can cross-multiply to avoid division. The comparison a/b > c/d is equivalent to ad > bc. This way, you only use multiplication, which is faster and avoids potential inaccuracies or complexities associated with division.
Num of instances: 9
Click to show findings
['884']
884:
885:
886: if (((a * cautionDivergenceFlag) / DENOMINATOR) < b) { // <= FOUND
['888']
888:
889:
890:
891: if (((a * badSourceDivergenceFlag) / DENOMINATOR) < b) { // <= FOUND
['903']
903:
904:
905:
906: if (((b * cautionDivergenceFlag) / DENOMINATOR) < a) { // <= FOUND
['907']
907:
908:
909:
910: if (((b * badSourceDivergenceFlag) / DENOMINATOR) < a) { // <= FOUND
['935']
935:
936:
937: if (((b * cautionDivergenceFlag) / DENOMINATOR) < a) { // <= FOUND
['939']
939:
940:
941:
942: if (((b * badSourceDivergenceFlag) / DENOMINATOR) < a) { // <= FOUND
['884']
884:
885:
886:
887: if (((a * cautionDivergenceFlag) / DENOMINATOR) < b) { // <= FOUND
['888']
888:
889:
890:
891: if (((a * badSourceDivergenceFlag) / DENOMINATOR) < b) { // <= FOUND
['1018']
1018:
1019:
1020:
1021: if (collRatio > (WAD_SQUARED / (WAD + collReqSoft))) { // <= FOUND
In smart contract development, particularly for Ethereum, having payable functions without a corresponding withdraw or sweep function can lead to potential issues. Payable functions allow the contract to receive Ether, but without a mechanism to withdraw these funds, the Ether can become locked within the contract indefinitely. This situation might be intentional in some cases (like a burn function), but generally, it’s a design oversight. A withdraw or sweep function is necessary to transfer Ether out of the contract to a specific address, typically the owner's or a designated recipient. Without this, the contract lacks flexibility in managing its funds, potentially leading to lost or inaccessible Ether.
Num of instances: 14
Click to show findings
['26']
26: contract BlastNativeYieldManager is ReentrancyGuard
['12']
12: contract BorrowZapper is FeeTokenBridgingHub
['12']
12: contract CVE is ERC20
['43']
43: contract CVELocker is Delegable, ReentrancyGuard
['12']
12: contract CVE is ERC20
['21']
21: contract ComplexZapper is ReentrancyGuard
['46']
46: contract FeeAccumulator is ReentrancyGuard
['11']
11: contract GMCToken is CTokenCompounding
['12']
12: contract OneBalanceFeeManager is FeeTokenBridgingHub
['27']
27: contract PositionFolding is IPositionFolding, Delegable, ERC165, ReentrancyGuard
['18']
18: contract SimpleRewardZapper is ReentrancyGuard
['17']
17: contract SimpleZapper is ReentrancyGuard
['9']
9: contract StakedGMXCToken is CTokenCompounding
['93']
93: contract VeCVE is ERC20, ReentrancyGuard
Improving code readability and compactness is an integral part of optimal programming practices. The use of ternary operators in place of if-else conditions is one such measure. Ternary operators allow us to write conditional statements in a more concise manner, thereby enhancing readability and simplicity. They follow the syntax condition ? exprIfTrue : exprIfFalse
, which interprets as "if the condition is true, evaluate to exprIfTrue
, else evaluate to exprIfFalse
". By adopting this approach, we make our code more streamlined and intuitive, which could potentially aid in better understanding and maintenance of the codebase.
Num of instances: 71
Click to show findings
['113']
113: if (inUSD) {
114: data = adaptorDataUSD[asset]; // <= FOUND
115: }
['242']
242: if (isSupportedAsset[asset]) {
243: isUpdate = true; // <= FOUND
244: }
['101']
101: if (inUSD) {
102:
103:
104: symbolHash = Bytes32Helper._toBytes32(asset); // <= FOUND
105: }
['121']
121: if (decimals == 0) {
122: data.decimals = 8; // <= FOUND
123: }
['110']
110: if (data.decimals0 != 18) {
111: reserve0 = (reserve0 * 1e18) / (10 ** data.decimals0); // <= FOUND
112: }
['114']
114: if (data.decimals1 != 18) {
115: reserve1 = (reserve1 * 1e18) / (10 ** data.decimals1); // <= FOUND
116: }
['152']
152: if (yieldDestination == address(0)) {
153: yieldDestination = msg.sender; // <= FOUND
154: }
['165']
165: if (pendingWETH > 0) {
166: WETHYield += pendingWETH; // <= FOUND
167: }
['161']
161: if (claimWETHYield) {
162: uint256 pendingWETH = pendingWETHYield[msg.sender]; // <= FOUND
163:
164:
165: if (pendingWETH > 0) {
166: WETHYield += pendingWETH; // <= FOUND
167: }
['175']
175: if (pendingUSDB > 0) {
176: USDBYield += pendingUSDB; // <= FOUND
177: }
['171']
171: if (claimUSDBYield) {
172: uint256 pendingUSDB = pendingUSDBYield[msg.sender]; // <= FOUND
173:
174:
175: if (pendingUSDB > 0) {
176: USDBYield += pendingUSDB; // <= FOUND
177: }
['246']
246: if (msg.sender != owner) {
247: uint256 allowed = allowance(owner, msg.sender); // <= FOUND
248:
249: if (allowed != type(uint256).max) {
250: _spendAllowance(owner, msg.sender, allowed - shares);
251: }
252: }
['67']
67: if (builder_ == address(0)) {
68: builder_ = msg.sender; // <= FOUND
69: }
['197']
197: if (builderAllocation <= _builderAllocationMinted + amount) {
198: amount = builderAllocation - builderAllocationMinted; // <= FOUND
199: }
['715']
715: if (token == address(0)) {
716: if (amount == 0) {
717: amount = address(this).balance; // <= FOUND
718: }
719:
720: SafeTransferLib.forceSafeTransferETH(daoOperator, amount);
721: }
['260']
260: if (isPaused == 1 && currentState == 2) {
261: endClaimTimestamp = block.timestamp + (6 weeks); // <= FOUND
262: }
['260']
260: if (daoAddress_ == address(0)) {
261: daoAddress_ = msg.sender; // <= FOUND
262: }
['264']
264: if (timelock_ == address(0)) {
265: timelock_ = msg.sender; // <= FOUND
266: }
['268']
268: if (emergencyCouncil_ == address(0)) {
269: emergencyCouncil_ = msg.sender; // <= FOUND
270: }
['150']
150: if (bufferedMaxPrice > type(uint240).max) {
151: bufferedMaxPrice = type(uint240).max; // <= FOUND
152: }
['590']
590: if (forceRedeemCollateral) {
591: assets = cToken.redeemCollateralFor( // <= FOUND
592: shares,
593: address(this),
594: msg.sender
595: );
596: }
['217']
217: if (CommonLib.isETH(data.baseToken)) {
218: data.baseTokenDecimals = 18; // <= FOUND
219: }
['1119']
1119: if (spender != from) {
1120:
1121:
1122: allowance[from][spender] = allowance[from][spender] - tokens; // <= FOUND
1123: }
['302']
302: if (belowVertex) {
303: unchecked {
304: borrowRate = _getBaseInterestRate(util); // <= FOUND
305: }
306: }
['238']
238: if (transferToken) {
239:
240: nativeFee += wormholeCore.messageFee(); // <= FOUND
241: }
['183']
183: if (index != (rewardTokensLength - 1)) {
184: rewardTokens[index] = rewardTokens[rewardTokensLength - 1]; // <= FOUND
185: }
['271']
271: if (lastRewardTimestamp == 0) {
272: lastRewardTimestamp = startTime; // <= FOUND
273: }
['611']
611: if (_lastRewardTimestamp == 0) {
612: _lastRewardTimestamp = startTime; // <= FOUND
613: }
['564']
564: if (result.lFactor == 0) {
565:
566: result.lFactor = 1; // <= FOUND
567: }
['1591']
1591: if (!liquidateExact) {
1592: debtAmount = maxAmount; // <= FOUND
1593: }
['75']
75: if (paymentToken_ == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {
76: paymentTokenDecimals = 18; // <= FOUND
77: }
['355']
355: if (isMToken) {
356: asset = mTokenAssets[asset].underlying; // <= FOUND
357: }
['454']
454: if (numFeeds < 2) {
455: (price, errorCode) = _getPriceSingleFeed(asset, inUSD, getLower); // <= FOUND
456: }
['462']
462: if (price == 0 && errorCode < BAD_SOURCE) {
463: errorCode = BAD_SOURCE; // <= FOUND
464: }
['806']
806: if (numFeeds < 2) {
807: (price, errorCode) = _getPriceSingleFeed(ETH, true, getLower); // <= FOUND
808: }
['826']
826: if (sequencer != address(0)) {
827: (, int256 answer, uint256 startedAt, , ) = IChainlink(sequencer) // <= FOUND
828: .latestRoundData();
829:
830:
831:
832:
833: if (
834: answer != 0 || block.timestamp < startedAt + GRACE_PERIOD_TIME
835: ) {
836: return false;
837: }
838: }
['265']
265: if (forceRedeemCollateral && mToken.isCToken()) {
266: assets = mToken.redeemCollateralFor( // <= FOUND
267: shares,
268: address(this),
269: msg.sender
270: );
271: }
['80']
80: if (_checkVestStatus(_vaultData)) {
81: _updateVestingPeriodIfNeeded();
82:
83:
84: rewardRouter.handleRewards(
85: true,
86: true,
87: true,
88: true,
89: true,
90: true,
91: false
92: );
93: uint256 rewardAmount = WETH.balanceOf(address(this)); // <= FOUND
94:
95:
96: if (rewardAmount > 0) {
97:
98:
99: uint256 protocolFee = FixedPointMathLib.mulDiv( // <= FOUND
100: rewardAmount,
101: centralRegistry.protocolHarvestFee(),
102: 1e18
103: );
104: rewardAmount -= protocolFee; // <= FOUND
105: SafeTransferLib.safeTransfer(
106: address(WETH),
107: centralRegistry.feeAccumulator(),
108: protocolFee
109: );
110:
111: SwapperLib.Swap memory swapData = abi.decode( // <= FOUND
112: data,
113: (SwapperLib.Swap)
114: );
115:
116: if (!centralRegistry.isSwapper(swapData.target)) {
117: revert StakedGMXCToken__InvalidSwapper(swapData.target);
118: }
119:
120: yield = SwapperLib.swap(centralRegistry, swapData); // <= FOUND
121:
122:
123: if (yield == 0) {
124: revert StakedGMXCToken__SlippageError();
125: }
126: }
127:
128:
129:
130: _afterDeposit(yield, 0);
131:
132:
133: _setNewVaultData(yield, vestPeriod);
134:
135: emit Harvest(yield);
136: }
['121']
121: if (CommonLib.isETH(zapperCall.inputToken)) {
122: value = zapperCall.inputAmount; // <= FOUND
123: }
['118']
118: if (success) {
119:
120: twapPrice = abi.decode(returnData, (uint256)); // <= FOUND
121: }
['716']
716: if (amount == 0) {
717: amount = address(this).balance; // <= FOUND
718: }
['715']
715: if (token == address(0)) {
716: if (amount == 0) {
717: amount = address(this).balance; // <= FOUND
718: }
['716']
716: if (amount == 0) {
717: amount = address(this).balance; // <= FOUND
718: }
['1265']
1265: if (lockIndex != lastLockIndex) {
1266: user[lockIndex] = user[lastLockIndex]; // <= FOUND
1267: }
['107']
107: if (rewardToken != _AURA && rewardToken != _BAL) {
108: strategyData.rewardTokens.push() = rewardToken; // <= FOUND
109: }
['107']
107: if (rewardToken != _AURA && rewardToken != _BAL) {
108: strategyData.rewardTokens.push() = rewardToken; // <= FOUND
109: }
['220']
220: if (quoteDecimals != 18) {
221:
222:
223: if (quoteDecimals < 18) {
224: price = price * (10 ** (18 - quoteDecimals)); // <= FOUND
225: } else {
226:
227:
228: price = price / (10 ** (quoteDecimals - 18)); // <= FOUND
229: }
230: }
['223']
223: if (quoteDecimals < 18) {
224: price = price * (10 ** (18 - quoteDecimals)); // <= FOUND
225: }
['197']
197: if (msg.sender != owner) {
198: uint256 allowed = allowance(owner, msg.sender); // <= FOUND
199:
200: if (allowed != type(uint256).max) {
201: _spendAllowance(owner, msg.sender, allowed - shares);
202: }
['726']
726: if (amount == 0) {
727: amount = IERC20(token).balanceOf(address(this)); // <= FOUND
728: }
['531']
531: if (rewardsData.asCVE) {
532: SwapperLib.Swap memory swapData = abi.decode( // <= FOUND
533: params,
534: (SwapperLib.Swap)
535: );
536:
537:
538: if (
539: swapData.call.length == 0 ||
540: swapData.inputToken != rewardToken ||
541: swapData.outputToken != cve ||
542: swapData.inputAmount != rewards ||
543: !centralRegistry.isSwapper(swapData.target)
544: ) {
545: revert CVELocker__SwapDataIsInvalid();
546: }
['311']
311: if (amounts[i] > 0) {
312: liquidityAvailable = true; // <= FOUND
313: }
['156']
156: if (data.divideRate0 || data.divideRate1) {
157: uint256[2] memory rates = pool.stored_rates(); // <= FOUND
158: if (data.divideRate0) {
159: price0 = (price0 * WAD) / rates[0]; // <= FOUND
160: }
161: if (data.divideRate1) {
162: price1 = (price1 * WAD) / rates[1]; // <= FOUND
163: }
164: }
['158']
158: if (data.divideRate0) {
159: price0 = (price0 * WAD) / rates[0]; // <= FOUND
160: }
['154']
154: if (data.isCorrelated) {
155:
156: if (data.divideRate0 || data.divideRate1) {
157: uint256[2] memory rates = pool.stored_rates(); // <= FOUND
158: if (data.divideRate0) {
159: price0 = (price0 * WAD) / rates[0]; // <= FOUND
160: }
['217']
217: if (_priceUnit[token] == 0) {
218: _priceUnit[token] = WAD * 10 ** IERC20(token).decimals(); // <= FOUND
219: }
['393']
393: if (maxDebt > newDebt) {
394: unchecked {
395: result.collateralSurplus = maxDebt - newDebt; // <= FOUND
396: }
['121']
121: if (payloadId == 1) {
122: (, bytes32 token) = abi.decode(payload, (uint8, bytes32)); // <= FOUND
123:
124: if (address(uint160(uint256(token))) == feeToken) {
125: _depositOneBalanceFee();
126: }
['634']
634: if (assetPriceFeeds[asset][0] == feed) {
635: assetPriceFeeds[asset][0] = assetPriceFeeds[asset][1]; // <= FOUND
636: }
['715']
715: if (data.inUSD != inUSD) {
716: uint256 newPrice;
717: (newPrice, data.hadError) = _getETHUSD(getLower); // <= FOUND
718: if (data.hadError) {
719: return (0, BAD_SOURCE);
720: }
['96']
96: if (rewardAmount > 0) {
97:
98:
99: uint256 protocolFee = FixedPointMathLib.mulDiv( // <= FOUND
100: rewardAmount,
101: centralRegistry.protocolHarvestFee(),
102: 1e18
103: );
104: rewardAmount -= protocolFee; // <= FOUND
105: SafeTransferLib.safeTransfer(
106: address(WETH),
107: centralRegistry.feeAccumulator(),
108: protocolFee
109: );
110:
111: SwapperLib.Swap memory swapData = abi.decode( // <= FOUND
112: data,
113: (SwapperLib.Swap)
114: );
115:
116: if (!centralRegistry.isSwapper(swapData.target)) {
117: revert StakedGMXCToken__InvalidSwapper(swapData.target);
118: }
119:
120: yield = SwapperLib.swap(centralRegistry, swapData); // <= FOUND
121:
122:
123: if (yield == 0) {
124: revert StakedGMXCToken__SlippageError();
125: }
126: }
['139']
139: if (_checkVestStatus(_vaultData)) {
140: _updateVestingPeriodIfNeeded();
141:
142:
143: StrategyData memory sd = strategyData; // <= FOUND
144:
145:
146: sd.gauge.getReward(address(this));
147:
148: {
149: uint256 rewardAmount = rewardToken.balanceOf(address(this)); // <= FOUND
150:
151:
152: if (rewardAmount > 0) {
153:
154:
155: uint256 protocolFee = FixedPointMathLib.mulDiv( // <= FOUND
156: rewardAmount,
157: centralRegistry.protocolHarvestFee(),
158: 1e18
159: );
160: rewardAmount -= protocolFee; // <= FOUND
161: SafeTransferLib.safeTransfer(
162: address(rewardToken),
163: centralRegistry.feeAccumulator(),
164: protocolFee
165: );
166:
167:
168: if (!rewardTokenIsUnderlying) {
169: SwapperLib.Swap memory swapData = abi.decode( // <= FOUND
170: data,
171: (SwapperLib.Swap)
172: );
173:
174: if (!centralRegistry.isSwapper(swapData.target)) {
175: revert AerodromeStableCToken__InvalidSwapper(
176: swapData.target
177: );
178: }
179:
180: SwapperLib.swap(centralRegistry, swapData);
181: }
182: }
183: }
184:
185: uint256 totalAmountA = IERC20(sd.token0).balanceOf(address(this)); // <= FOUND
186:
187:
188: if (totalAmountA == 0) {
189: revert AerodromeStableCToken__SlippageError();
190: }
191:
192:
193: address _asset = asset(); // <= FOUND
194:
195:
196: (uint256 r0, uint256 r1, ) = IVeloPair(_asset).getReserves(); // <= FOUND
197: (uint256 reserveA, uint256 reserveB) = sd.token0 == // <= FOUND
198: IVeloPair(_asset).token0()
199: ? (r0, r1)
200: : (r1, r0);
201:
202:
203: uint256 swapAmount = VelodromeLib._optimalDeposit( // <= FOUND
204: address(sd.pairFactory),
205: _asset,
206: totalAmountA,
207: reserveA,
208: reserveB,
209: sd.decimalsA,
210: sd.decimalsB,
211: true
212: );
213:
214: VelodromeLib._swapExactTokensForTokens(
215: address(sd.router),
216: _asset,
217: sd.token0,
218: sd.token1,
219: swapAmount,
220: true
221: );
222: totalAmountA -= swapAmount; // <= FOUND
223:
224:
225: yield = VelodromeLib._addLiquidity( // <= FOUND
226: address(sd.router),
227: sd.token0,
228: sd.token1,
229: true,
230: totalAmountA,
231: IERC20(sd.token1).balanceOf(address(this)),
232: VelodromeLib.VELODROME_ADD_LIQUIDITY_SLIPPAGE
233: );
234:
235:
236:
237: _afterDeposit(yield, 0);
238:
239:
240: _setNewVaultData(yield, vestPeriod);
241:
242: emit Harvest(yield);
243: }
['134']
134: if (_checkVestStatus(_vaultData)) {
135: _updateVestingPeriodIfNeeded();
136:
137:
138: StrategyData memory sd = strategyData; // <= FOUND
139:
140:
141: sd.gauge.getReward(address(this));
142:
143: {
144: uint256 rewardAmount = rewardToken.balanceOf(address(this)); // <= FOUND
145:
146: if (rewardAmount > 0) {
147:
148:
149: uint256 protocolFee = FixedPointMathLib.mulDiv( // <= FOUND
150: rewardAmount,
151: centralRegistry.protocolHarvestFee(),
152: 1e18
153: );
154: rewardAmount -= protocolFee; // <= FOUND
155: SafeTransferLib.safeTransfer(
156: address(rewardToken),
157: centralRegistry.feeAccumulator(),
158: protocolFee
159: );
160:
161:
162: if (!rewardTokenIsUnderlying) {
163: SwapperLib.Swap memory swapData = abi.decode( // <= FOUND
164: data,
165: (SwapperLib.Swap)
166: );
167:
168: if (!centralRegistry.isSwapper(swapData.target)) {
169: revert AerodromeVolatileCToken__InvalidSwapper(
170: swapData.target
171: );
172: }
173:
174: SwapperLib.swap(centralRegistry, swapData);
175: }
176: }
177: }
178:
179: uint256 totalAmountA = IERC20(sd.token0).balanceOf(address(this)); // <= FOUND
180:
181: if (totalAmountA == 0) {
182: revert AerodromeVolatileCToken__SlippageError();
183: }
184:
185:
186: address _asset = asset(); // <= FOUND
187:
188:
189: (uint256 r0, uint256 r1, ) = IVeloPair(_asset).getReserves(); // <= FOUND
190: uint256 reserveA = sd.token0 == IVeloPair(_asset).token0() // <= FOUND
191: ? r0
192: : r1;
193:
194:
195:
196:
197: uint256 swapAmount = VelodromeLib._optimalDeposit( // <= FOUND
198: address(sd.pairFactory),
199: _asset,
200: totalAmountA,
201: reserveA,
202: 0,
203: 0,
204: 0,
205: false
206: );
207:
208: VelodromeLib._swapExactTokensForTokens(
209: address(sd.router),
210: _asset,
211: sd.token0,
212: sd.token1,
213: swapAmount,
214: false
215: );
216: totalAmountA -= swapAmount; // <= FOUND
217:
218:
219: yield = VelodromeLib._addLiquidity( // <= FOUND
220: address(sd.router),
221: sd.token0,
222: sd.token1,
223: false,
224: totalAmountA,
225: IERC20(sd.token1).balanceOf(address(this)),
226: VelodromeLib.VELODROME_ADD_LIQUIDITY_SLIPPAGE
227: );
228:
229:
230:
231: _afterDeposit(yield, 0);
232:
233:
234: _setNewVaultData(yield, vestPeriod);
235:
236: emit Harvest(yield);
237: }
['161']
161: if (data.divideRate1) {
162: price1 = (price1 * WAD) / rates[1]; // <= FOUND
163: }
['309']
309: if (result.updateNeeded == 0) {
310: result.updateNeeded = 1; // <= FOUND
311: }
['431']
431: if (tokenData[snapshot.asset].collRatio != 0) {
432: accountCollateral += _assetValue( // <= FOUND
433: ((tokenData[snapshot.asset]
434: .accountPositions[account]
435: .collateralPosted * snapshot.exchangeRate) / WAD),
436: underlyingPrices[i],
437: snapshot.decimals
438: );
439: }
['510']
510: if (snapshot.asset == collateralToken) {
511: result.collateralTokenPrice = underlyingPrices[i]; // <= FOUND
512: }
['515']
515: if (tokenData[snapshot.asset].collRatio != 0) {
516: (
517: accountCollateralSoft,
518: accountCollateralHard
519: ) = _addLiquidationValues( // <= FOUND
520: snapshot,
521: account,
522: underlyingPrices[i],
523: accountCollateralSoft,
524: accountCollateralHard
525: );
526: }
['231']
231: if (snapshot.debtBalance > 0) {
232: accountDebt += _assetValue( // <= FOUND
233: snapshot.debtBalance,
234: underlyingPrices[i],
235: snapshot.decimals
236: );
237: }
['140']
140: if (_checkVestStatus(_vaultData)) {
141: _updateVestingPeriodIfNeeded();
142:
143:
144: StrategyData memory sd = strategyData; // <= FOUND
145:
146:
147: sd.gauge.getReward(address(this));
148:
149: {
150: uint256 rewardAmount = rewardToken.balanceOf(address(this)); // <= FOUND
151:
152: if (rewardAmount > 0) {
153:
154:
155: uint256 protocolFee = FixedPointMathLib.mulDiv( // <= FOUND
156: rewardAmount,
157: centralRegistry.protocolHarvestFee(),
158: 1e18
159: );
160: rewardAmount -= protocolFee; // <= FOUND
161: SafeTransferLib.safeTransfer(
162: address(rewardToken),
163: centralRegistry.feeAccumulator(),
164: protocolFee
165: );
166:
167:
168: if (!rewardTokenIsUnderlying) {
169: SwapperLib.Swap memory swapData = abi.decode( // <= FOUND
170: data,
171: (SwapperLib.Swap)
172: );
173:
174: if (!centralRegistry.isSwapper(swapData.target)) {
175: revert VelodromeStableCToken__InvalidSwapper(
176: swapData.target
177: );
178: }
179:
180: SwapperLib.swap(centralRegistry, swapData);
181: }
182: }
183: }
184:
185: uint256 totalAmountA = IERC20(sd.token0).balanceOf(address(this)); // <= FOUND
186:
187:
188: if (totalAmountA == 0) {
189: revert VelodromeStableCToken__SlippageError();
190: }
191:
192:
193: address _asset = asset(); // <= FOUND
194:
195:
196: (uint256 r0, uint256 r1, ) = IVeloPair(_asset).getReserves(); // <= FOUND
197: (uint256 reserveA, uint256 reserveB) = sd.token0 == // <= FOUND
198: IVeloPair(_asset).token0()
199: ? (r0, r1)
200: : (r1, r0);
201:
202:
203: uint256 swapAmount = VelodromeLib._optimalDeposit( // <= FOUND
204: address(sd.pairFactory),
205: _asset,
206: totalAmountA,
207: reserveA,
208: reserveB,
209: sd.decimalsA,
210: sd.decimalsB,
211: true
212: );
213:
214: VelodromeLib._swapExactTokensForTokens(
215: address(sd.router),
216: _asset,
217: sd.token0,
218: sd.token1,
219: swapAmount,
220: true
221: );
222: totalAmountA -= swapAmount; // <= FOUND
223:
224:
225: yield = VelodromeLib._addLiquidity( // <= FOUND
226: address(sd.router),
227: sd.token0,
228: sd.token1,
229: true,
230: totalAmountA,
231: IERC20(sd.token1).balanceOf(address(this)),
232: VelodromeLib.VELODROME_ADD_LIQUIDITY_SLIPPAGE
233: );
234:
235:
236:
237: _afterDeposit(yield, 0);
238:
239:
240: _setNewVaultData(yield, vestPeriod);
241:
242: emit Harvest(yield);
243: }
['127']
127: if (_checkVestStatus(_vaultData)) {
128: _updateVestingPeriodIfNeeded();
129:
130:
131: StrategyData memory sd = strategyData; // <= FOUND
132:
133:
134: sd.gauge.getReward(address(this));
135:
136: {
137: uint256 rewardAmount = rewardToken.balanceOf(address(this)); // <= FOUND
138:
139: if (rewardAmount > 0) {
140:
141:
142: uint256 protocolFee = FixedPointMathLib.mulDiv( // <= FOUND
143: rewardAmount,
144: centralRegistry.protocolHarvestFee(),
145: 1e18
146: );
147: rewardAmount -= protocolFee; // <= FOUND
148: SafeTransferLib.safeTransfer(
149: address(rewardToken),
150: centralRegistry.feeAccumulator(),
151: protocolFee
152: );
153:
154:
155: if (!rewardTokenIsUnderlying) {
156: SwapperLib.Swap memory swapData = abi.decode( // <= FOUND
157: data,
158: (SwapperLib.Swap)
159: );
160:
161: if (!centralRegistry.isSwapper(swapData.target)) {
162: revert VelodromeVolatileCToken__InvalidSwapper(
163: swapData.target
164: );
165: }
166:
167: SwapperLib.swap(centralRegistry, swapData);
168: }
169: }
170: }
171:
172: uint256 totalAmountA = IERC20(sd.token0).balanceOf(address(this)); // <= FOUND
173:
174:
175: if (totalAmountA == 0) {
176: revert VelodromeVolatileCToken__SlippageError();
177: }
178:
179:
180: address _asset = asset(); // <= FOUND
181:
182:
183: (uint256 r0, uint256 r1, ) = IVeloPair(_asset).getReserves(); // <= FOUND
184: uint256 reserveA = sd.token0 == IVeloPair(_asset).token0() // <= FOUND
185: ? r0
186: : r1;
187:
188:
189:
190:
191: uint256 swapAmount = VelodromeLib._optimalDeposit( // <= FOUND
192: address(sd.pairFactory),
193: _asset,
194: totalAmountA,
195: reserveA,
196: 0,
197: 0,
198: 0,
199: false
200: );
201:
202: VelodromeLib._swapExactTokensForTokens(
203: address(sd.router),
204: _asset,
205: sd.token0,
206: sd.token1,
207: swapAmount,
208: false
209: );
210: totalAmountA -= swapAmount; // <= FOUND
211:
212:
213: yield = VelodromeLib._addLiquidity( // <= FOUND
214: address(sd.router),
215: sd.token0,
216: sd.token1,
217: false,
218: totalAmountA,
219: IERC20(sd.token1).balanceOf(address(this)),
220: VelodromeLib.VELODROME_ADD_LIQUIDITY_SLIPPAGE
221: );
222:
223:
224:
225: _afterDeposit(yield, 0);
226:
227:
228: _setNewVaultData(yield, vestPeriod);
229:
230: emit Harvest(yield);
231: }
Num of instances: 8
Click to show findings
['33']
33:
37: IERC20 public constant rewardToken =
38: IERC20(0x940181a94A35A4569E4529A3CDfB74e38FD98631); // <= FOUND
['17']
17:
21: IBlast public constant CHAIN_YIELD_MANAGER = IBlast(0x4300000000000000000000000000000000000002); // <= FOUND
['19']
19:
20: IERC20Rebasing public constant WETH_YIELD_MANAGER = IERC20Rebasing(0x4300000000000000000000000000000000000004); // <= FOUND
['18']
18:
22: IWETH public constant WETH = IWETH(0x4300000000000000000000000000000000000004); // <= FOUND
['33']
33:
34: IBlast yieldConfiguration = IBlast(0x4300000000000000000000000000000000000002); // <= FOUND
['17']
17:
22: IBlast public constant CHAIN_YIELD_MANAGER = IBlast(0x4300000000000000000000000000000000000002); // <= FOUND
['36']
36:
37: IERC20Rebasing public constant USDB_YIELD_MANAGER = IERC20Rebasing(0x4300000000000000000000000000000000000003); // <= FOUND
['38']
38:
42: IERC20 public constant rewardToken =
43: IERC20(0x9560e827aF36c94D2Ac33a39bCE1Fe78631088Db); // <= FOUND
The "check-effects-interaction" pattern is a best practice in smart contract development, emphasizing the order of operations in functions to prevent reentrancy attacks. Violations arise when a function interacts with external contracts before settling internal state changes or checks. This misordering can expose the contract to potential threats. To adhere to this pattern, first ensure all conditions or checks are satisfied, then update any internal states, and only after these steps, interact with external contracts or addresses. Rearranging operations to this recommended sequence bolsters contract security and aligns with established best practices in the Ethereum community.
Num of instances: 49
Click to show findings
['148']
148: function addAsset(address asset, AdaptorData memory data) external { // <= FOUND
149: _checkElevatedPermissions();
150:
151: IBalancerPool pool = IBalancerPool(asset);
152:
153:
154: data.poolId = pool.getPoolId();
155: data.poolDecimals = pool.decimals();
156:
157: uint256 numUnderlyingOrConstituent = data
158: .underlyingOrConstituent
159: .length;
160:
161:
162: for (uint256 i; i < numUnderlyingOrConstituent; ++i) {
163:
164: if (address(data.underlyingOrConstituent[i]) == address(0)) {
165: continue;
166: }
167:
168: if (
169: !IOracleRouter(centralRegistry.oracleRouter()).isSupportedAsset( // <= FOUND
170: data.underlyingOrConstituent[i]
171: )
172: ) {
173: revert BalancerStablePoolAdaptor__ConfigurationError();
174: }
175:
176: if (data.rateProviders[i] != address(0)) {
177:
178: if (data.rateProviderDecimals[i] == 0) {
179: revert BalancerStablePoolAdaptor__ConfigurationError();
180: }
181:
182:
183: if (IRateProvider(data.rateProviders[i]).getRate() == 0) { // <= FOUND
184: revert BalancerStablePoolAdaptor__ConfigurationError();
185: }
186: }
187: }
188:
189:
190: adaptorData[asset] = data;
191:
192:
193: bool isUpdate;
194: if (isSupportedAsset[asset]) {
195: isUpdate = true;
196: }
197:
198: isSupportedAsset[asset] = true;
199: emit BalancerStablePoolAssetAdded(asset, data, isUpdate);
200: }
['177']
177: function addAsset(address asset, AdaptorData memory data) external { // <= FOUND
178: _checkElevatedPermissions();
179:
180:
181:
182: if (isLocked(data.pool, 2)) {
183: revert Curve2PoolAssetAdaptor__UnsupportedPool();
184: }
185:
186:
187: if (asset == data.baseToken) {
188: revert Curve2PoolAssetAdaptor__InvalidAsset();
189: }
190:
191: address oracleRouter = centralRegistry.oracleRouter();
192:
193:
194:
195: if (!IOracleRouter(oracleRouter).isSupportedAsset(data.baseToken)) { // <= FOUND
196: revert Curve2PoolAssetAdaptor__BaseAssetIsNotSupported();
197: }
198:
199:
200: if (data.lowerBound >= data.upperBound) {
201: revert Curve2PoolAssetAdaptor__InvalidBounds();
202: }
203:
204: ICurvePool pool = ICurvePool(data.pool);
205:
206: if (pool.coins(uint256(uint128(data.quoteTokenIndex))) != asset) {
207: revert Curve2PoolAssetAdaptor__InvalidAssetIndex();
208: }
209: if (
210: pool.coins(uint256(uint128(data.baseTokenIndex))) != data.baseToken
211: ) {
212: revert Curve2PoolAssetAdaptor__InvalidAssetIndex();
213: }
214:
215: data.quoteTokenDecimals = ERC20(asset).decimals(); // <= FOUND
216:
217: if (CommonLib.isETH(data.baseToken)) {
218: data.baseTokenDecimals = 18;
219: } else {
220: data.baseTokenDecimals = ERC20(data.baseToken).decimals(); // <= FOUND
221: }
222:
223:
224:
225:
226:
227: data.lowerBound = _bpToWad(data.lowerBound);
228: data.upperBound = _bpToWad(data.upperBound);
229:
230:
231: if (_MAX_BOUND_RANGE + data.lowerBound < data.upperBound) {
232: revert Curve2PoolAssetAdaptor__InvalidBounds();
233: }
234:
235:
236: uint256 testVirtualPrice = pool.get_virtual_price();
237:
238:
239: _enforceBounds(testVirtualPrice, data.lowerBound, data.upperBound);
240:
241:
242: adaptorData[asset] = data;
243:
244:
245: bool isUpdate;
246: if (isSupportedAsset[asset]) {
247: isUpdate = true;
248: }
249:
250: isSupportedAsset[asset] = true;
251: emit CurvePoolAssetAdded(asset, data, isUpdate);
252: }
['196']
196: function addAsset(address asset, AdaptorData memory data) external { // <= FOUND
197: _checkElevatedPermissions();
198:
199:
200:
201: if (isLocked(asset, 2)) {
202: revert Curve2PoolLPAdaptor__UnsupportedPool();
203: }
204:
205: address oracleRouter = centralRegistry.oracleRouter();
206:
207:
208:
209: if (
210: !IOracleRouter(oracleRouter).isSupportedAsset( // <= FOUND
211: data.underlying0
212: )
213: ) {
214: revert Curve2PoolLPAdaptor__QuoteAssetIsNotSupported();
215: }
216:
217:
218:
219: if (
220: !IOracleRouter(oracleRouter).isSupportedAsset( // <= FOUND
221: data.underlying1
222: )
223: ) {
224: revert Curve2PoolLPAdaptor__QuoteAssetIsNotSupported();
225: }
226:
227:
228: if (data.lowerBound >= data.upperBound) {
229: revert Curve2PoolLPAdaptor__InvalidBounds();
230: }
231:
232: ICurvePool pool = ICurvePool(data.pool);
233: uint256 coinsLength;
234:
235: while (true) {
236: try pool.coins(coinsLength) {
237: ++coinsLength;
238: } catch {
239: break;
240: }
241: }
242:
243:
244: if (coinsLength != 2) {
245: revert Curve2PoolLPAdaptor__UnsupportedPool();
246: }
247:
248: address underlying;
249: for (uint256 i; i < coinsLength; ) {
250: underlying = pool.coins(i++);
251:
252:
253:
254: if (
255: underlying != data.underlying0 &&
256: underlying != data.underlying1
257: ) {
258: revert Curve2PoolLPAdaptor__UnsupportedPool();
259: }
260: }
261:
262:
263:
264:
265:
266: data.lowerBound = _bpToWad(data.lowerBound);
267: data.upperBound = _bpToWad(data.upperBound);
268:
269:
['130']
130: function addAsset(address asset, AdaptorData memory data) external { // <= FOUND
131: _checkElevatedPermissions();
132:
133:
134: (IStandardizedYield sy, IPPrincipalToken pt, ) = IPMarket(asset)
135: .readTokens();
136:
137:
138: if (address(pt) != data.pt) {
139: revert PendleLPTokenAdaptor__WrongMarket();
140: }
141:
142:
143: if (data.twapDuration < MINIMUM_TWAP_DURATION) {
144: revert PendleLPTokenAdaptor__TwapDurationIsLessThanMinimum();
145: }
146:
147:
148: (, address assetAddress, ) = sy.assetInfo();
149: if (assetAddress != data.quoteAsset) {
150: revert PendleLPTokenAdaptor__WrongQuote();
151: }
152:
153:
154: _checkPtTwap(asset, data.twapDuration);
155:
156:
157: if (
158: !IOracleRouter(centralRegistry.oracleRouter()).isSupportedAsset( // <= FOUND
159: data.quoteAsset
160: )
161: ) {
162: revert PendleLPTokenAdaptor__QuoteAssetIsNotSupported();
163: }
164:
165:
166: adaptorData[asset] = data;
167:
168:
169: bool isUpdate;
170: if (isSupportedAsset[asset]) {
171: isUpdate = true;
172: }
173:
174: isSupportedAsset[asset] = true;
175: emit PendleLPAssetAdded(asset, data, isUpdate);
176: }
['131']
131: function addAsset(address asset, AdaptorData memory data) external { // <= FOUND
132: _checkElevatedPermissions();
133:
134:
135: (IStandardizedYield sy, IPPrincipalToken pt, ) = data
136: .market
137: .readTokens();
138:
139:
140: if (address(pt) != asset) {
141: revert PendlePrincipalTokenAdaptor__WrongMarket();
142: }
143:
144:
145: if (data.twapDuration < MINIMUM_TWAP_DURATION) {
146: revert PendlePrincipalTokenAdaptor__TwapDurationIsLessThanMinimum();
147: }
148:
149:
150: (, address assetAddress, ) = sy.assetInfo();
151: if (assetAddress != data.quoteAsset) {
152: revert PendlePrincipalTokenAdaptor__WrongQuote();
153: }
154:
155:
156: _checkPtTwap(address(data.market), data.twapDuration);
157:
158:
159: if (
160: !IOracleRouter(centralRegistry.oracleRouter()).isSupportedAsset( // <= FOUND
161: data.quoteAsset
162: )
163: ) {
164: revert PendlePrincipalTokenAdaptor__QuoteAssetIsNotSupported();
165: }
166:
167:
168: adaptorData[asset] = data;
169:
170:
171: bool isUpdate;
172: if (isSupportedAsset[asset]) {
173: isUpdate = true;
174: }
175:
176: isSupportedAsset[asset] = true;
177: emit PendlePTAssetAdded(asset, data, isUpdate);
178: }
['214']
214: function addAsset(address asset, AdaptorData memory data) external { // <= FOUND
215: _checkElevatedPermissions();
216:
217:
218: if (data.secondsAgo < MINIMUM_SECONDS_AGO) {
219: revert UniswapV3Adaptor__SecondsAgoIsLessThanMinimum();
220: }
221:
222: UniswapV3Pool pool = UniswapV3Pool(data.priceSource);
223:
224:
225: address token0 = pool.token0();
226: address token1 = pool.token1();
227: if (token0 == asset) {
228: data.baseDecimals = ERC20(asset).decimals(); // <= FOUND
229: data.quoteDecimals = ERC20(token1).decimals(); // <= FOUND
230: data.quoteToken = token1;
231: } else if (token1 == asset) {
232: data.baseDecimals = ERC20(asset).decimals(); // <= FOUND
233: data.quoteDecimals = ERC20(token0).decimals(); // <= FOUND
234: data.quoteToken = token0;
235: } else revert UniswapV3Adaptor__AssetIsNotSupported();
236:
237:
238: adaptorData[asset] = data;
239:
240:
241: bool isUpdate;
242: if (isSupportedAsset[asset]) {
243: isUpdate = true;
244: }
245:
246: isSupportedAsset[asset] = true;
247: emit UniswapV3AssetAdded(asset, data, isUpdate);
248: }
['129']
129: function harvest(
130: bytes calldata data
131: ) external override returns (uint256 yield) {
132:
133: _canCompound();
134:
135:
136: _vestIfNeeded();
137:
138:
139: if (_checkVestStatus(_vaultData)) {
140: _updateVestingPeriodIfNeeded();
141:
142:
143: StrategyData memory sd = strategyData;
144:
145:
146: sd.gauge.getReward(address(this));
147:
148: {
149: uint256 rewardAmount = rewardToken.balanceOf(address(this));
150:
151:
152: if (rewardAmount > 0) {
153:
154:
155: uint256 protocolFee = FixedPointMathLib.mulDiv(
156: rewardAmount,
157: centralRegistry.protocolHarvestFee(),
158: 1e18
159: );
160: rewardAmount -= protocolFee;
161: SafeTransferLib.safeTransfer(
162: address(rewardToken),
163: centralRegistry.feeAccumulator(),
164: protocolFee
165: );
166:
167:
168: if (!rewardTokenIsUnderlying) {
169: SwapperLib.Swap memory swapData = abi.decode(
170: data,
171: (SwapperLib.Swap)
172: );
173:
174: if (!centralRegistry.isSwapper(swapData.target)) {
175: revert AerodromeStableCToken__InvalidSwapper(
176: swapData.target
177: );
178: }
179:
180: SwapperLib.swap(centralRegistry, swapData);
181: }
182: }
183: }
184:
185: uint256 totalAmountA = IERC20(sd.token0).balanceOf(address(this)); // <= FOUND
186:
187:
188: if (totalAmountA == 0) {
189: revert AerodromeStableCToken__SlippageError();
190: }
191:
192:
193: address _asset = asset();
194:
195:
196: (uint256 r0, uint256 r1, ) = IVeloPair(_asset).getReserves(); // <= FOUND
197: (uint256 reserveA, uint256 reserveB) = sd.token0 ==
198: IVeloPair(_asset).token0() // <= FOUND
199: ? (r0, r1)
200: : (r1, r0);
201:
202:
203: uint256 swapAmount = VelodromeLib._optimalDeposit(
204: address(sd.pairFactory),
205: _asset,
206: totalAmountA,
207: reserveA,
208: reserveB,
209: sd.decimalsA,
210: sd.decimalsB,
211: true
212: );
213:
214: VelodromeLib._swapExactTokensForTokens(
215: address(sd.router),
216: _asset,
217: sd.token0,
218: sd.token1,
219: swapAmount,
220: true
221: );
222: totalAmountA -= swapAmount;
223:
224:
225: yield = VelodromeLib._addLiquidity(
226: address(sd.router),
227: sd.token0,
228: sd.token1,
229: true,
230: totalAmountA,
231: IERC20(sd.token1).balanceOf(address(this)), // <= FOUND
232: VelodromeLib.VELODROME_ADD_LIQUIDITY_SLIPPAGE
233: );
234:
235:
236:
237: _afterDeposit(yield, 0);
238:
239:
240: _setNewVaultData(yield, vestPeriod);
241:
242: emit Harvest(yield);
243: }
244: }
['124']
124: function harvest(
125: bytes calldata data
126: ) external override returns (uint256 yield) {
127:
128: _canCompound();
129:
130:
131: _vestIfNeeded();
132:
133:
134: if (_checkVestStatus(_vaultData)) {
135: _updateVestingPeriodIfNeeded();
136:
137:
138: StrategyData memory sd = strategyData;
139:
140:
141: sd.gauge.getReward(address(this));
142:
143: {
144: uint256 rewardAmount = rewardToken.balanceOf(address(this));
145:
146: if (rewardAmount > 0) {
147:
148:
149: uint256 protocolFee = FixedPointMathLib.mulDiv(
150: rewardAmount,
151: centralRegistry.protocolHarvestFee(),
152: 1e18
153: );
154: rewardAmount -= protocolFee;
155: SafeTransferLib.safeTransfer(
156: address(rewardToken),
157: centralRegistry.feeAccumulator(),
158: protocolFee
159: );
160:
161:
162: if (!rewardTokenIsUnderlying) {
163: SwapperLib.Swap memory swapData = abi.decode(
164: data,
165: (SwapperLib.Swap)
166: );
167:
168: if (!centralRegistry.isSwapper(swapData.target)) {
169: revert AerodromeVolatileCToken__InvalidSwapper(
170: swapData.target
171: );
172: }
173:
174: SwapperLib.swap(centralRegistry, swapData);
175: }
176: }
177: }
178:
179: uint256 totalAmountA = IERC20(sd.token0).balanceOf(address(this)); // <= FOUND
180:
181: if (totalAmountA == 0) {
182: revert AerodromeVolatileCToken__SlippageError();
183: }
184:
185:
186: address _asset = asset();
187:
188:
189: (uint256 r0, uint256 r1, ) = IVeloPair(_asset).getReserves(); // <= FOUND
190: uint256 reserveA = sd.token0 == IVeloPair(_asset).token0() // <= FOUND
191: ? r0
192: : r1;
193:
194:
195:
196:
197: uint256 swapAmount = VelodromeLib._optimalDeposit(
198: address(sd.pairFactory),
199: _asset,
200: totalAmountA,
201: reserveA,
202: 0,
203: 0,
204: 0,
205: false
206: );
207:
208: VelodromeLib._swapExactTokensForTokens(
209: address(sd.router),
210: _asset,
211: sd.token0,
212: sd.token1,
213: swapAmount,
214: false
215: );
216: totalAmountA -= swapAmount;
217:
218:
219: yield = VelodromeLib._addLiquidity(
220: address(sd.router),
221: sd.token0,
222: sd.token1,
223: false,
224: totalAmountA,
225: IERC20(sd.token1).balanceOf(address(this)), // <= FOUND
226: VelodromeLib.VELODROME_ADD_LIQUIDITY_SLIPPAGE
227: );
228:
229:
230:
231: _afterDeposit(yield, 0);
232:
233:
234: _setNewVaultData(yield, vestPeriod);
235:
236: emit Harvest(yield);
237: }
238:
239: }
['130']
130: function harvest(
131: bytes calldata data
132: ) external override returns (uint256 yield) {
133:
134: _canCompound();
135:
136:
137: _vestIfNeeded();
138:
139:
140: if (_checkVestStatus(_vaultData)) {
141: _updateVestingPeriodIfNeeded();
142:
143:
144: StrategyData memory sd = strategyData;
145:
146:
147: sd.gauge.getReward(address(this));
148:
149: {
150: uint256 rewardAmount = rewardToken.balanceOf(address(this));
151:
152: if (rewardAmount > 0) {
153:
154:
155: uint256 protocolFee = FixedPointMathLib.mulDiv(
156: rewardAmount,
157: centralRegistry.protocolHarvestFee(),
158: 1e18
159: );
160: rewardAmount -= protocolFee;
161: SafeTransferLib.safeTransfer(
162: address(rewardToken),
163: centralRegistry.feeAccumulator(),
164: protocolFee
165: );
166:
167:
168: if (!rewardTokenIsUnderlying) {
169: SwapperLib.Swap memory swapData = abi.decode(
170: data,
171: (SwapperLib.Swap)
172: );
173:
174: if (!centralRegistry.isSwapper(swapData.target)) {
175: revert VelodromeStableCToken__InvalidSwapper(
176: swapData.target
177: );
178: }
179:
180: SwapperLib.swap(centralRegistry, swapData);
181: }
182: }
183: }
184:
185: uint256 totalAmountA = IERC20(sd.token0).balanceOf(address(this)); // <= FOUND
186:
187:
188: if (totalAmountA == 0) {
189: revert VelodromeStableCToken__SlippageError();
190: }
191:
192:
193: address _asset = asset();
194:
195:
196: (uint256 r0, uint256 r1, ) = IVeloPair(_asset).getReserves(); // <= FOUND
197: (uint256 reserveA, uint256 reserveB) = sd.token0 ==
198: IVeloPair(_asset).token0() // <= FOUND
199: ? (r0, r1)
200: : (r1, r0);
201:
202:
203: uint256 swapAmount = VelodromeLib._optimalDeposit(
204: address(sd.pairFactory),
205: _asset,
206: totalAmountA,
207: reserveA,
208: reserveB,
209: sd.decimalsA,
210: sd.decimalsB,
211: true
212: );
213:
214: VelodromeLib._swapExactTokensForTokens(
215: address(sd.router),
216: _asset,
217: sd.token0,
218: sd.token1,
219: swapAmount,
220: true
221: );
222: totalAmountA -= swapAmount;
223:
224:
225: yield = VelodromeLib._addLiquidity(
226: address(sd.router),
227: sd.token0,
228: sd.token1,
229: true,
230: totalAmountA,
231: IERC20(sd.token1).balanceOf(address(this)), // <= FOUND
232: VelodromeLib.VELODROME_ADD_LIQUIDITY_SLIPPAGE
233: );
234:
235:
236:
237: _afterDeposit(yield, 0);
238:
239:
240: _setNewVaultData(yield, vestPeriod);
241:
242: emit Harvest(yield);
243: }
244: }
['117']
117: function harvest(
118: bytes calldata data
119: ) external override returns (uint256 yield) {
120:
121: _canCompound();
122:
123:
124: _vestIfNeeded();
125:
126:
127: if (_checkVestStatus(_vaultData)) {
128: _updateVestingPeriodIfNeeded();
129:
130:
131: StrategyData memory sd = strategyData;
132:
133:
134: sd.gauge.getReward(address(this));
135:
136: {
137: uint256 rewardAmount = rewardToken.balanceOf(address(this));
138:
139: if (rewardAmount > 0) {
140:
141:
142: uint256 protocolFee = FixedPointMathLib.mulDiv(
143: rewardAmount,
144: centralRegistry.protocolHarvestFee(),
145: 1e18
146: );
147: rewardAmount -= protocolFee;
148: SafeTransferLib.safeTransfer(
149: address(rewardToken),
150: centralRegistry.feeAccumulator(),
151: protocolFee
152: );
153:
154:
155: if (!rewardTokenIsUnderlying) {
156: SwapperLib.Swap memory swapData = abi.decode(
157: data,
158: (SwapperLib.Swap)
159: );
160:
161: if (!centralRegistry.isSwapper(swapData.target)) {
162: revert VelodromeVolatileCToken__InvalidSwapper(
163: swapData.target
164: );
165: }
166:
167: SwapperLib.swap(centralRegistry, swapData);
168: }
169: }
170: }
171:
172: uint256 totalAmountA = IERC20(sd.token0).balanceOf(address(this)); // <= FOUND
173:
174:
175: if (totalAmountA == 0) {
176: revert VelodromeVolatileCToken__SlippageError();
177: }
178:
179:
180: address _asset = asset();
181:
182:
183: (uint256 r0, uint256 r1, ) = IVeloPair(_asset).getReserves(); // <= FOUND
184: uint256 reserveA = sd.token0 == IVeloPair(_asset).token0() // <= FOUND
185: ? r0
186: : r1;
187:
188:
189:
190:
191: uint256 swapAmount = VelodromeLib._optimalDeposit(
192: address(sd.pairFactory),
193: _asset,
194: totalAmountA,
195: reserveA,
196: 0,
197: 0,
198: 0,
199: false
200: );
201:
202: VelodromeLib._swapExactTokensForTokens(
203: address(sd.router),
204: _asset,
205: sd.token0,
206: sd.token1,
207: swapAmount,
208: false
209: );
210: totalAmountA -= swapAmount;
211:
212:
213: yield = VelodromeLib._addLiquidity(
214: address(sd.router),
215: sd.token0,
216: sd.token1,
217: false,
218: totalAmountA,
219: IERC20(sd.token1).balanceOf(address(this)), // <= FOUND
220: VelodromeLib.VELODROME_ADD_LIQUIDITY_SLIPPAGE
221: );
222:
223:
224:
225: _afterDeposit(yield, 0);
226:
227:
228: _setNewVaultData(yield, vestPeriod);
229:
230: emit Harvest(yield);
231: }
232: }
['108']
108: function addAsset(
109: address asset,
110: string memory ticker,
111: address proxyFeed,
112: uint256 heartbeat,
113: bool inUSD
114: ) external {
115: _checkElevatedPermissions();
116:
117: if (heartbeat != 0) {
118: if (heartbeat > DEFAULT_HEART_BEAT) {
119: revert Api3Adaptor__InvalidHeartbeat();
120: }
121: }
122:
123: bytes32 dapiName = Bytes32Helper.stringToBytes32(ticker);
124: bytes32 dapiNameHash = keccak256(abi.encodePacked(dapiName));
125:
126:
127:
128: if (dapiNameHash != IProxy(proxyFeed).dapiNameHash()) { // <= FOUND
129: revert Api3Adaptor__DAPINameHashError();
130: }
131:
132: AdaptorData storage data;
133:
134: if (inUSD) {
135: data = adaptorDataUSD[asset];
136: } else {
137: data = adaptorDataNonUSD[asset];
138: }
139:
140: data.heartbeat = heartbeat != 0
141: ? heartbeat
142: : DEFAULT_HEART_BEAT;
143:
144:
145:
146:
147:
148:
149:
150: data.max = (uint256(int256(type(int224).max)) * 9) / 10; // <= FOUND
151: data.dapiNameHash = dapiNameHash;
152: data.proxyFeed = IProxy(proxyFeed);
153: data.isConfigured = true;
154:
155:
156: bool isUpdate;
157: if (isSupportedAsset[asset]) {
158: isUpdate = true;
159: }
160:
161: isSupportedAsset[asset] = true;
162: emit Api3AssetAdded(asset, data, isUpdate);
163: }
['27']
27: function enterBalancer(
28: address balancerVault,
29: bytes32 balancerPoolId,
30: address lpToken,
31: address[] calldata tokens,
32: uint256 lpMinOutAmount
33: ) internal returns (uint256 lpOutAmount) {
34: uint256 numTokens = tokens.length;
35: uint256[] memory balances = new uint256[](numTokens);
36: uint256 value;
37: bool containsEth;
38:
39:
40: for (uint256 i; i < numTokens; ++i) {
41: balances[i] = CommonLib.getTokenBalance(tokens[i]);
42: SwapperLib._approveTokenIfNeeded(
43: tokens[i],
44: balancerVault,
45: balances[i]
46: );
47:
48: if (CommonLib.isETH(tokens[i])) {
49:
50:
51: if (containsEth) {
52: revert BalancerLib__InvalidPoolInvariantError();
53: }
54:
55: value = balances[i];
56: containsEth = true;
57: }
58: }
59:
60:
61: IBalancerVault(balancerVault).joinPool{ value: value }( // <= FOUND
62: balancerPoolId,
63: address(this),
64: address(this),
65: IBalancerVault.JoinPoolRequest(
66: tokens,
67: balances,
68: abi.encode(
69: IBalancerVault.JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT,
70: balances,
71: 1
72: ),
73: false
74: )
75: );
76:
77: lpOutAmount = IERC20(lpToken).balanceOf(address(this)); // <= FOUND
78:
79: if (lpOutAmount < lpMinOutAmount) {
80: revert BalancerLib__ReceivedAmountIsLessThanMinimum(
81: lpOutAmount,
82: lpMinOutAmount
83: );
84: }
85: }
['119']
119: function claimYieldForGauge(
120: address marketManager,
121: bool claimWETHYield,
122: bool claimUSDBYield
123: ) external nonReentrant returns (
124: uint256 WETHYield,
125: uint256 USDBYield
126: ) {
127:
128:
129: if (!isMarketManager[marketManager]) {
130: _revert(_UNAUTHORIZED_SELECTOR);
131: }
132:
133:
134:
135: if (!IMarketManager(marketManager).isListed(msg.sender)) { // <= FOUND
136: _revert(_UNAUTHORIZED_SELECTOR);
137: }
138:
139: uint256 gasYield = CHAIN_YIELD_MANAGER.claimMaxGas(
140: msg.sender,
141: address(this)
142: );
143: uint256 WETHPrior = WETH_YIELD_MANAGER.balanceOf(address(this));
144: uint256 USDBPrior = USDB_YIELD_MANAGER.balanceOf(address(this));
145: uint256 WETHPerSecond;
146: uint256 USDBPerSecond;
147:
148: address yieldDestination = cTokenToDTokenYieldRouted[msg.sender];
149:
150:
151:
152: if (yieldDestination == address(0)) {
153: yieldDestination = msg.sender;
154: }
155:
156: if (gasYield > 0) {
157: IWETH(address(WETH_YIELD_MANAGER)).deposit{ value: gasYield }(); // <= FOUND
158: WETHYield += gasYield;
159: }
160:
161: if (claimWETHYield) {
162: uint256 pendingWETH = pendingWETHYield[msg.sender];
163:
164:
165: if (pendingWETH > 0) {
166: WETHYield += pendingWETH;
167: WETHPerSecond = WETHYield / EPOCH_WINDOW;
168: }
169: }
170:
171: if (claimUSDBYield) {
172: uint256 pendingUSDB = pendingUSDBYield[msg.sender];
173:
174:
175: if (pendingUSDB > 0) {
176: USDBYield += pendingUSDB;
177: USDBPerSecond = USDBYield / EPOCH_WINDOW;
178: }
179: }
180:
181:
182: if (USDBYield == 0 && WETHYield == 0) {
183: revert BlastNativeYieldManager__NoYieldToClaim();
184: }
185:
186:
187: IGaugePool gaugePool = IMarketManager(marketManager).gaugePool(); // <= FOUND
188: uint256 nextEpoch = gaugePool.currentEpoch() + 1;
189:
190:
191:
192: if (epochReported[msg.sender][nextEpoch]) {
193: _revert(_UNAUTHORIZED_SELECTOR);
194: }
195:
196:
197:
198:
199:
200:
202: if (WETHPerSecond > 0){
203:
204: SwapperLib._approveTokenIfNeeded(
205: address(WETH_YIELD_MANAGER),
206: address(gaugePool),
207: WETHYield
208: );
209:
210: gaugePool.setRewardPerSec(
211: yieldDestination,
212: nextEpoch,
213: address(WETH_YIELD_MANAGER),
214: WETHPerSecond
215: );
216:
217:
218: SwapperLib._removeApprovalIfNeeded(
219: address(WETH_YIELD_MANAGER),
220: address(gaugePool)
221: );
222: }
223:
224:
225:
226:
227: uint256 WETHAfter = WETH_YIELD_MANAGER.balanceOf(address(this));
228:
229:
230:
231: WETHPrior -= WETHYield;
232:
233: if (WETHAfter != WETHPrior) {
234:
235:
236: if (WETHAfter < WETHPrior) {
237: revert BlastNativeYieldManager__InvariantError();
['307']
307: function claimYieldForAutoCompounding(
308: address marketManager,
309: bool claimWETHYield,
310: bool claimUSDBYield
311: ) external nonReentrant returns (
312: uint256 WETHYield,
313: uint256 USDBYield
314: ) {
315:
316:
317: if (!isMarketManager[marketManager]) {
318: _revert(_UNAUTHORIZED_SELECTOR);
319: }
320:
321:
322:
323: if (!IMarketManager(marketManager).isListed(msg.sender)) { // <= FOUND
324: _revert(_UNAUTHORIZED_SELECTOR);
325: }
326:
327: if (claimWETHYield) {
328: uint256 pendingWETH = pendingWETHYield[msg.sender];
329:
330:
331: if (pendingWETH > 0) {
332: WETHYield += pendingWETH;
333: }
334: }
335:
336: if (claimUSDBYield) {
337: uint256 pendingUSDB = pendingUSDBYield[msg.sender];
338:
339:
340: if (pendingUSDB > 0) {
341: USDBYield += pendingUSDB;
342: }
343: }
344:
345:
346: if (USDBYield == 0 && WETHYield == 0) {
347: revert BlastNativeYieldManager__NoYieldToClaim();
348: }
349:
350: if (USDBYield != 0) {
351: SafeTransferLib.safeTransfer(
352: address(USDB_YIELD_MANAGER),
353: msg.sender,
354: USDBYield
355: );
356: }
357:
358: if (WETHYield != 0) {
359: SafeTransferLib.safeTransfer(
360: address(WETH_YIELD_MANAGER),
361: msg.sender,
362: WETHYield
363: );
364: }
365: }
['372']
372: function setCTokenToDTokenYieldDonation(
373: address cToken,
374: address dToken
375: ) external {
376: _checkElevatedPermissions();
377:
378: if (
379: IMToken(cToken).marketManager() != // <= FOUND
380: IMToken(dToken).marketManager() // <= FOUND
381: ) {
382: revert BlastNativeYieldManager__MarketManagerMismatch();
383: }
384:
385: if (
386: !IMToken(cToken).isCToken() || // <= FOUND
387: IMToken(dToken).isCToken() // <= FOUND
388: ) {
389: revert BlastNativeYieldManager__InvalidTokenTypes();
390: }
391:
392: cTokenToDTokenYieldRouted[cToken] = dToken;
393: }
['427']
427: function notifyRewards(
428: address marketManager,
429: bool isWETH,
430: uint256 amount
431: ) external {
432:
433:
434: if (!isMarketManager[marketManager]) {
435: _revert(_UNAUTHORIZED_SELECTOR);
436: }
437:
438:
439:
440: if (!IMarketManager(marketManager).isListed(msg.sender)) { // <= FOUND
441: _revert(_UNAUTHORIZED_SELECTOR);
442: }
443:
444: if (isWETH) {
445: pendingWETHYield[msg.sender] = pendingWETHYield[msg.sender] + amount;
446: return;
447: }
448:
449: pendingUSDBYield[msg.sender] = pendingUSDBYield[msg.sender] + amount;
450: }
['189']
189: function rescueToken(address token, uint256 amount) external { // <= FOUND
190: _checkDaoPermissions();
191: address daoOperator = centralRegistry.daoAddress();
192:
193: if (token == address(0)) {
194: if (amount == 0) {
195: amount = address(this).balance; // <= FOUND
196: }
197:
198: SafeTransferLib.forceSafeTransferETH(daoOperator, amount);
199: } else {
200: if (token == cve) {
201: revert CVEInitialDistribution__TransferError();
202: }
203:
204: if (amount == 0) {
205: amount = IERC20(token).balanceOf(address(this)); // <= FOUND
206: }
207:
208: SafeTransferLib.safeTransfer(token, daoOperator, amount);
209: }
210: }
['164']
164: function rescueToken(address token, uint256 amount) external { // <= FOUND
165: _checkDaoPermissions();
166: address daoOperator = centralRegistry.daoAddress();
167:
168: if (token == address(0)) {
169: if (amount == 0) {
170: amount = address(this).balance; // <= FOUND
171: }
172:
173: SafeTransferLib.forceSafeTransferETH(daoOperator, amount);
174: } else {
175: if (token == rewardToken) {
176: _revert(_UNAUTHORIZED_SELECTOR);
177: }
178:
179: if (amount == 0) {
180: amount = IERC20(token).balanceOf(address(this)); // <= FOUND
181: }
182:
183: SafeTransferLib.safeTransfer(token, daoOperator, amount);
184: }
185: }
['711']
711: function rescueToken(address token, uint256 amount) external { // <= FOUND
712: _checkDaoPermissions();
713: address daoOperator = centralRegistry.daoAddress();
714:
715: if (token == address(0)) {
716: if (amount == 0) {
717: amount = address(this).balance; // <= FOUND
718: }
719:
720: SafeTransferLib.forceSafeTransferETH(daoOperator, amount);
721: } else {
722: if (token == underlying) {
723: revert DToken__TransferError();
724: }
725:
726: if (amount == 0) {
727: amount = IERC20(token).balanceOf(address(this)); // <= FOUND
728: }
729:
730: SafeTransferLib.safeTransfer(token, daoOperator, amount);
731: }
732: }
['91']
91: function rescueToken(address token, uint256 amount) external { // <= FOUND
92: _checkDaoPermissions();
93: address daoOperator = centralRegistry.daoAddress();
94:
95: if (token == address(0)) {
96: if (amount == 0) {
97: amount = address(this).balance; // <= FOUND
98: }
99:
100: SafeTransferLib.forceSafeTransferETH(daoOperator, amount);
101: } else {
102: if (token == cve) {
103: revert OCVE__TransferError();
104: }
105:
106: if (amount == 0) {
107: amount = IERC20(token).balanceOf(address(this)); // <= FOUND
108: }
109:
110: SafeTransferLib.safeTransfer(token, daoOperator, amount);
111: }
112: }
['241']
241: function rescueToken(address token, uint256 amount) external { // <= FOUND
242: if (!centralRegistry.hasDaoPermissions(msg.sender)) {
243: _revert(_UNAUTHORIZED_SELECTOR);
244: }
245:
246: address daoOperator = centralRegistry.daoAddress();
247:
248: if (token == address(0)) {
249: if (amount == 0) {
250: amount = address(this).balance; // <= FOUND
251: }
252:
253: SafeTransferLib.forceSafeTransferETH(daoOperator, amount);
254: } else {
255: if (token == address(cve)) {
256: revert VeCVE__NonTransferrable();
257: }
258:
259: if (amount == 0) {
260: amount = IERC20(token).balanceOf(address(this)); // <= FOUND
261: }
262:
263: SafeTransferLib.safeTransfer(token, daoOperator, amount);
264: }
265: }
['36']
36: function addAsset(
37: address asset
38: ) external override {
39: _checkElevatedPermissions();
40:
41: if (!ICamelotPair(asset).stableSwap()) { // <= FOUND
42: revert CamelotStableLPAdaptor__AssetIsNotStableLP();
43: }
44:
45:
46: bool isUpdate;
47: if (isSupportedAsset[asset]) {
48: isUpdate = true;
49: }
50:
51: AdaptorData memory data = _addAsset(asset);
52: emit CamelotStableLPAssetAdded(asset, data, isUpdate);
53: }
['36']
36: function addAsset(
37: address asset
38: ) external override {
39: _checkElevatedPermissions();
40:
41: if (ICamelotPair(asset).stableSwap()) { // <= FOUND
42: revert CamelotVolatileLPAdaptor__AssetIsNotVolatileLP();
43: }
44:
45:
46: bool isUpdate;
47: if (isSupportedAsset[asset]) {
48: isUpdate = true;
49: }
50:
51: AdaptorData memory data = _addAsset(asset);
52: emit CamelotVolatileLPAssetAdded(asset, data, isUpdate);
53: }
['36']
36: function addAsset(
37: address asset
38: ) external override {
39: _checkElevatedPermissions();
40:
41: if (!IVeloPool(asset).stable()) { // <= FOUND
42: revert VelodromeStableLPAdaptor__AssetIsNotStableLP();
43: }
44:
45:
46: bool isUpdate;
47: if (isSupportedAsset[asset]) {
48: isUpdate = true;
49: }
50:
51: AdaptorData memory data = _addAsset(asset);
52: emit VelodromeStableLPAssetAdded(asset, data, isUpdate);
53: }
['38']
38: function addAsset(
39: address asset
40: ) external override {
41: _checkElevatedPermissions();
42:
43: if (IVeloPool(asset).stable()) { // <= FOUND
44: revert VelodromeVolatileLPAdaptor__AssetIsNotVolatileLP();
45: }
46:
47:
48: bool isUpdate;
49: if (isSupportedAsset[asset]) {
50: isUpdate = true;
51: }
52:
53: AdaptorData memory data = _addAsset(asset);
54: emit VelodromeVolatileLPAssetAdded(asset, data, isUpdate);
55: }
['113']
113: function addAsset(
114: address asset,
115: address aggregator,
116: uint256 heartbeat,
117: bool inUSD
118: ) external {
119: _checkElevatedPermissions();
120:
121: if (heartbeat != 0) {
122: if (heartbeat > DEFAULT_HEART_BEAT) {
123: revert ChainlinkAdaptor__InvalidHeartbeat();
124: }
125: }
126:
127:
128: IChainlink feedAggregator = IChainlink(
129: IChainlink(aggregator).aggregator() // <= FOUND
130: );
131:
132:
133: uint256 maxFromChainlink = uint256(
134: uint192(feedAggregator.maxAnswer())
135: );
136: uint256 minFromChainklink = uint256(
137: uint192(feedAggregator.minAnswer())
138: );
139:
140:
141:
142:
143: uint256 bufferedMaxPrice = (maxFromChainlink * 9) / 10;
144: uint256 bufferedMinPrice = (minFromChainklink * 11) / 10;
145:
146:
147:
148:
149:
150: if (bufferedMaxPrice > type(uint240).max) { // <= FOUND
151: bufferedMaxPrice = type(uint240).max; // <= FOUND
152: }
153:
154: if (bufferedMinPrice >= bufferedMaxPrice) {
155: revert ChainlinkAdaptor__InvalidMinMaxConfig();
156: }
157:
158: AdaptorData storage data;
159:
160: if (inUSD) {
161: data = adaptorDataUSD[asset];
162: } else {
163: data = adaptorDataNonUSD[asset];
164: }
165:
166:
167: data.decimals = feedAggregator.decimals();
168: data.max = bufferedMaxPrice;
169: data.min = bufferedMinPrice;
170: data.heartbeat = heartbeat != 0
171: ? heartbeat
172: : DEFAULT_HEART_BEAT;
173: data.aggregator = IChainlink(aggregator);
174: data.isConfigured = true;
175:
176:
177: bool isUpdate;
178: if (isSupportedAsset[asset]) {
179: isUpdate = true;
180: }
181:
182: isSupportedAsset[asset] = true;
183: emit ChainlinkAssetAdded(asset, data, isUpdate);
184: }
['97']
97: function start(
98: uint256 startTimestamp,
99: uint256 softPriceInUSD,
100: uint256 cveAmountInLBP,
101: address paymentTokenAddress
102: ) external {
103: if (!centralRegistry.hasDaoPermissions(msg.sender)) {
104: revert CurvanceDAOLBP__Unauthorized();
105: }
106:
107: if (startTime != 0) {
108: revert CurvanceDAOLBP__AlreadyStarted();
109: }
110:
111: if (startTimestamp < block.timestamp) {
112: revert CurvanceDAOLBP__InvalidStartTime();
113: }
114:
115: uint256 errorCode;
116: (paymentTokenPrice, errorCode) = IOracleRouter(centralRegistry.oracleRouter())
117: .getPrice(paymentTokenAddress, true, true);
118:
119:
120:
121: if (errorCode == 2) {
122: revert CurvanceDAOLBP__InvalidPriceSource();
123: }
124:
125: startTime = startTimestamp;
126: softPriceInpaymentToken = (softPriceInUSD * WAD) / paymentTokenPrice;
127: cveAmountForSale = cveAmountInLBP;
128: paymentToken = paymentTokenAddress;
129: paymentTokenDecimals = IERC20(paymentTokenAddress).decimals(); // <= FOUND
130:
131: emit LBPStarted(startTimestamp);
132: }
['27']
27: function enterCurve(
28: address lpMinter,
29: address lpToken,
30: address[] calldata tokens,
31: uint256 lpMinOutAmount
32: ) internal returns (uint256 lpOutAmount) {
33: uint256 numTokens = tokens.length;
34:
35:
36: if (numTokens > 4 || numTokens < 2) {
37: revert CurveLib__InvalidPoolType();
38: }
39:
40: uint256[] memory balances = new uint256[](numTokens);
41: uint256 value;
42: bool containsEth;
43:
44:
45: for (uint256 i; i < numTokens; ++i) {
46: balances[i] = CommonLib.getTokenBalance(tokens[i]);
47: SwapperLib._approveTokenIfNeeded(
48: tokens[i],
49: lpMinter,
50: balances[i]
51: );
52:
53: if (CommonLib.isETH(tokens[i])) {
54:
55:
56: if (containsEth) {
57: revert CurveLib__InvalidPoolInvariantError();
58: }
59:
60: value = balances[i];
61: containsEth = true;
62: }
63: }
64:
65:
66: if (numTokens == 4) {
67: uint256[4] memory fourPoolAmounts;
68: fourPoolAmounts[0] = balances[0];
69: fourPoolAmounts[1] = balances[1];
70: fourPoolAmounts[2] = balances[2];
71: fourPoolAmounts[3] = balances[3];
72:
73: ICurveSwap(lpMinter).add_liquidity{ value: value }( // <= FOUND
74: fourPoolAmounts,
75: 0
76: );
77: } else if (numTokens == 3) {
78: uint256[3] memory threePoolAmounts;
79: threePoolAmounts[0] = balances[0];
80: threePoolAmounts[1] = balances[1];
81: threePoolAmounts[2] = balances[2];
82:
83: ICurveSwap(lpMinter).add_liquidity{ value: value }( // <= FOUND
84: threePoolAmounts,
85: 0
86: );
87: } else {
88: uint256[2] memory twoPoolAmounts;
89: twoPoolAmounts[0] = balances[0];
90: twoPoolAmounts[1] = balances[1];
91:
92: ICurveSwap(lpMinter).add_liquidity{ value: value }( // <= FOUND
93: twoPoolAmounts,
94: 0
95: );
96: }
97:
98: lpOutAmount = IERC20(lpToken).balanceOf(address(this)); // <= FOUND
99:
100: if (lpOutAmount < lpMinOutAmount) {
101: revert CurveLib__ReceivedAmountIsLessThanMinimum(
102: lpOutAmount,
103: lpMinOutAmount
104: );
105: }
106: }
['260']
260: function executeOTC(
261: address tokenToOTC,
262: uint256 amountToOTC
263: ) external nonReentrant {
264: _checkDaoPermissions();
265:
266:
267: if (rewardTokenInfo[tokenToOTC].forOTC < 2) {
268: revert FeeAccumulator__TokenIsNotEarmarked();
269: }
270:
271:
272: IOracleRouter oracleRouter = IOracleRouter(
273: centralRegistry.oracleRouter()
274: );
275:
276: (uint256 priceSwap, uint256 errorCodeSwap) = oracleRouter.getPrice(
277: tokenToOTC,
278: true,
279: true
280: );
281: (uint256 priceFeeToken, uint256 errorCodeFeeToken) = oracleRouter
282: .getPrice(feeToken, true, true);
283:
284:
285: if (errorCodeFeeToken == 2 || errorCodeSwap == 2) {
286: revert FeeAccumulator__ConfigurationError();
287: }
288:
289: address daoAddress = centralRegistry.daoAddress();
290:
291:
292: uint256 feeTokenRequiredForOTC = (
293: ((priceSwap * amountToOTC * _feeTokenUnit) / priceFeeToken)
294: ) / 10 ** IERC20(tokenToOTC).decimals(); // <= FOUND
295:
296: SafeTransferLib.safeTransferFrom(
297: feeToken,
298: msg.sender,
299: address(this),
300: feeTokenRequiredForOTC
301: );
302:
303: SafeTransferLib.safeTransfer(
304: feeToken,
305: oneBalanceFeeManager,
306: (feeTokenRequiredForOTC * vaultCompoundFee()) / vaultYieldFee()
307: );
308:
309:
310: SafeTransferLib.safeTransfer(tokenToOTC, daoAddress, amountToOTC);
311: }
['221']
221: function tokenDataOf(
222: address account,
223: address mToken
224: ) external view returns (
225: bool hasPosition,
226: uint256 balanceOf,
227: uint256 collateralPostedOf
228: ) {
229: AccountPosition memory accountPositions = tokenData[mToken].accountPositions[account];
230: hasPosition = accountPositions.activePosition == 2;
231: balanceOf = IMToken(mToken).balanceOf(account); // <= FOUND
232: collateralPostedOf = accountPositions.collateralPosted;
233: }
['285']
285: function hypotheticalLiquidityOf(
286: address account,
287: address mTokenModified,
288: uint256 redeemTokens,
289: uint256 borrowAmount
290: ) external view returns (uint256, uint256) {
291:
292:
293: if (IMToken(mTokenModified).isCToken() && borrowAmount > 0) { // <= FOUND
294: _revert(_INVALID_PARAMETER_SELECTOR);
295: }
296:
297: (HypotheticalData memory result,) = _hypotheticalLiquidityOf(
298: account,
299: HypotheticalAction({
300: mTokenModified: mTokenModified,
301: redeemTokens: redeemTokens,
302: borrowAmount: borrowAmount,
303: errorCodeBreakpoint: 2
304: })
305: );
306: return (result.collateralSurplus, result.liquidityDeficit);
307: }
['315']
315: function postCollateral(
316: address account,
317: address cToken,
318: uint256 tokens
319: ) external {
320: if (tokens == 0) {
321: _revert(_INVALID_PARAMETER_SELECTOR);
322: }
323:
324:
325:
326: if (msg.sender != account) {
327: _checkIsToken(cToken);
328: }
329:
330: if (!tokenData[cToken].isListed) {
331: _revert(_TOKEN_NOT_LISTED_SELECTOR);
332: }
333:
334: if (!IMToken(cToken).isCToken()) { // <= FOUND
335: _revert(_INVALID_PARAMETER_SELECTOR);
336: }
337:
338: AccountPosition storage accountPositions = tokenData[cToken].accountPositions[
339: account
340: ];
341:
342:
343: if (
344: accountPositions.collateralPosted + tokens >
345: IMToken(cToken).balanceOf(account) // <= FOUND
346: ) {
347: revert MarketManager__InsufficientCollateral();
348: }
349:
350: _postCollateral(account, accountPositions, cToken, tokens);
351: }
['357']
357: function removeCollateral(
358: address cToken,
359: uint256 tokens
360: ) external {
361: if (tokens == 0) {
362: _revert(_INVALID_PARAMETER_SELECTOR);
363: }
364:
365: AccountPosition storage accountPositions = tokenData[cToken].accountPositions[
366: msg.sender
367: ];
368:
369:
370:
371:
372: if (accountPositions.activePosition != 2) {
373: _revert(_INVARIANT_ERROR_SELECTOR);
374: }
375:
376: if (!IMToken(cToken).isCToken()) { // <= FOUND
377: _revert(_INVALID_PARAMETER_SELECTOR);
378: }
379:
380: if (accountPositions.collateralPosted < tokens) {
381: revert MarketManager__InsufficientCollateral();
382: }
383:
384:
385:
386: _canRedeem(cToken, msg.sender, tokens);
387: _removeCollateral(
388: msg.sender,
389: accountPositions,
390: cToken,
391: tokens
392: );
393: }
['878']
878: function listToken(address mToken) external { // <= FOUND
879: _checkElevatedPermissions();
880:
881: if (tokenData[mToken].isListed) {
882: _revert(_INVALID_PARAMETER_SELECTOR);
883: }
884:
885:
886: IMToken(mToken).isCToken(); // <= FOUND
887:
888:
889:
890: if (!IMToken(mToken).startMarket(msg.sender)) { // <= FOUND
891: _revert(_INVARIANT_ERROR_SELECTOR);
892: }
893:
894: MarketToken storage token = tokenData[mToken];
895: token.isListed = true;
896: token.collRatio = 0;
897:
898: uint256 numTokens = tokensListed.length;
899:
900: for (uint256 i; i < numTokens; ) {
901: unchecked {
902: if (tokensListed[i++] == mToken) {
903: _revert(_INVALID_PARAMETER_SELECTOR);
904: }
905: }
906: }
907:
908: tokensListed.push(mToken);
909: emit TokenListed(mToken);
910: }
['1536']
1536: function _canLiquidate(
1537: address debtToken,
1538: address collateralToken,
1539: address account,
1540: uint256 debtAmount,
1541: bool liquidateExact
1542: ) internal view returns (uint256, uint256, uint256) {
1543: if (!tokenData[debtToken].isListed) {
1544: _revert(_TOKEN_NOT_LISTED_SELECTOR);
1545: }
1546:
1547: MarketToken storage cToken = tokenData[collateralToken];
1548:
1549: if (!cToken.isListed) {
1550: _revert(_TOKEN_NOT_LISTED_SELECTOR);
1551: }
1552:
1553:
1554: if (cToken.collRatio == 0) {
1555: _revert(_INVALID_PARAMETER_SELECTOR);
1556: }
1557:
1558:
1559: LiqData memory data = _LiquidationStatusOf(
1560: account,
1561: debtToken,
1562: collateralToken
1563: );
1564:
1565:
1566: if (data.lFactor == 0) {
1567: revert MarketManager__NoLiquidationAvailable();
1568: }
1569:
1570: uint256 maxAmount;
1571: uint256 debtToCollateralRatio;
1572: {
1573: uint256 cFactor = cToken.baseCFactor +
1574: ((cToken.cFactorCurve * data.lFactor) / WAD);
1575: uint256 incentive = cToken.liqBaseIncentive +
1576: ((cToken.liqCurve * data.lFactor) / WAD);
1577: maxAmount =
1578: (cFactor * IMToken(debtToken).debtBalanceCached(account)) / // <= FOUND
1579: WAD;
1580:
1581:
1582:
1583: debtToCollateralRatio =
1584: (incentive * data.debtTokenPrice * WAD) /
1585: (data.collateralTokenPrice *
1586: IMToken(collateralToken).exchangeRateCached()); // <= FOUND
1587: }
1588:
1589:
1590:
1591: if (!liquidateExact) {
1592: debtAmount = maxAmount;
1593: }
1594:
1595:
1596: uint256 amountAdjusted = (debtAmount *
1597: (10 ** IERC20(collateralToken).decimals())) / // <= FOUND
1598: (10 ** IERC20(debtToken).decimals()); // <= FOUND
1599:
1600: uint256 liquidatedTokens = (amountAdjusted * debtToCollateralRatio) /
1601: WAD;
1602:
1603:
1604: uint256 collateralAvailable = cToken
1605: .accountPositions[account]
1606: .collateralPosted;
1607:
1608:
1609:
1610: if (liquidateExact) {
1611: if (
1612: debtAmount > maxAmount ||
1613: liquidatedTokens > collateralAvailable
1614: ) {
1615:
1616:
1617: _revert(_INVALID_PARAMETER_SELECTOR);
1618: }
1619: } else {
1620: if (liquidatedTokens > collateralAvailable) {
1621: debtAmount =
1622: (debtAmount * collateralAvailable) /
1623: liquidatedTokens;
1624: liquidatedTokens = collateralAvailable;
1625: }
1626: }
1627:
1628:
1629:
1630: return (
1631: debtAmount,
1632: liquidatedTokens,
1633: (liquidatedTokens * cToken.liqFee) / WAD
1634: );
1635: }
['205']
205: function addMTokenSupport(address newMToken) external { // <= FOUND
206: _checkElevatedPermissions();
207:
208: if (mTokenAssets[newMToken].isMToken) {
209: _revert(_INVALID_PARAMETER_SELECTOR);
210: }
211:
212:
213: IMToken(newMToken).isCToken(); // <= FOUND
214:
215: mTokenAssets[newMToken].isMToken = true;
216: mTokenAssets[newMToken].underlying = IMToken(newMToken).underlying(); // <= FOUND
217: }
['350']
350: function getPricesForAsset(
351: address asset,
352: bool inUSD
353: ) external view returns (FeedData[] memory) {
354: bool isMToken = mTokenAssets[asset].isMToken;
355: if (isMToken) {
356: asset = mTokenAssets[asset].underlying;
357: }
358:
359: uint256 numFeeds = assetPriceFeeds[asset].length;
360: if (numFeeds == 0) {
361: _revert(_NOT_SUPPORTED_SELECTOR);
362: }
363:
364: FeedData[] memory data = new FeedData[](numFeeds * 2);
365:
366:
367:
368: if (numFeeds < 2) {
369: data[0] = _getPriceFromFeed(asset, 0, inUSD, true);
370: data[1] = _getPriceFromFeed(asset, 0, inUSD, false);
371: if (isMToken) {
372: uint256 exchangeRate = IMToken(asset).exchangeRateCached(); // <= FOUND
373: data[0].price = uint240((data[0].price * exchangeRate) / WAD);
374: data[1].price = uint240((data[1].price * exchangeRate) / WAD);
375: }
376:
377: return data;
378: }
379:
380:
381:
382: data[0] = _getPriceFromFeed(asset, 0, inUSD, true);
383: data[1] = _getPriceFromFeed(asset, 0, inUSD, false);
384: data[2] = _getPriceFromFeed(asset, 1, inUSD, true);
385: data[3] = _getPriceFromFeed(asset, 1, inUSD, false);
386:
387: if (isMToken) {
388: uint256 exchangeRate = IMToken(asset).exchangeRateCached(); // <= FOUND
389: data[0].price = uint240((data[0].price * exchangeRate) / WAD);
390: data[1].price = uint240((data[1].price * exchangeRate) / WAD);
391: data[2].price = uint240((data[2].price * exchangeRate) / WAD);
392: data[3].price = uint240((data[3].price * exchangeRate) / WAD);
393: }
394:
395: return data;
396: }
['571']
571: function _addFeed(address asset, address feed) internal { // <= FOUND
572:
573: if (!isApprovedAdaptor[feed]) {
574: _revert(_INVALID_PARAMETER_SELECTOR);
575: }
576:
577:
578: if (!IOracleAdaptor(feed).isSupportedAsset(asset)) { // <= FOUND
579: _revert(_INVALID_PARAMETER_SELECTOR);
580: }
581:
582: uint256 numPriceFeeds = assetPriceFeeds[asset].length;
583:
584:
585: if (numPriceFeeds >= 2) {
586: _revert(_INVALID_PARAMETER_SELECTOR);
587: }
588:
589:
590:
591: if (numPriceFeeds != 0 && assetPriceFeeds[asset][0] == feed) {
592: _revert(_INVALID_PARAMETER_SELECTOR);
593: }
594:
595:
596:
597: PriceReturnData memory sampleData = IOracleAdaptor(feed).getPrice( // <= FOUND
598: asset,
599: true,
600: true
601: );
602:
603: if (sampleData.price == 0 || sampleData.hadError) {
604: _revert(_INVALID_PARAMETER_SELECTOR);
605: }
606:
607: assetPriceFeeds[asset].push(feed);
608: }
['694']
694: function _getPriceSingleFeed(
695: address asset,
696: bool inUSD,
697: bool getLower
698: ) internal view returns (uint256, uint256) {
699: address adapter = assetPriceFeeds[asset][0];
700: if (!isApprovedAdaptor[adapter]) {
701: revert OracleRouter__AdaptorIsNotApproved();
702: }
703:
704: PriceReturnData memory data = IOracleAdaptor(adapter).getPrice( // <= FOUND
705: asset,
706: inUSD,
707: getLower
708: );
709:
710: if (data.hadError) {
711: return (0, BAD_SOURCE);
712: }
713:
714:
715: if (data.inUSD != inUSD) {
716: uint256 newPrice;
717: (newPrice, data.hadError) = _getETHUSD(getLower);
718: if (data.hadError) {
719: return (0, BAD_SOURCE);
720: }
721:
722: data.price = uint240(
723: _convertETHUSD(data.price, newPrice, data.inUSD)
724: );
725: }
726:
727: return (data.price, NO_ERROR);
728: }
['744']
744: function _getPriceFromFeed(
745: address asset,
746: uint256 feedNumber,
747: bool inUSD,
748: bool getLower
749: ) internal view returns (FeedData memory) {
750: address adapter = assetPriceFeeds[asset][feedNumber];
751: if (!isApprovedAdaptor[adapter]) {
752: revert OracleRouter__AdaptorIsNotApproved();
753: }
754:
755: PriceReturnData memory data = IOracleAdaptor(adapter).getPrice( // <= FOUND
756: asset,
757: inUSD,
758: getLower
759: );
760:
761: if (data.hadError) {
762: return FeedData({ price: 0, hadError: true });
763: }
764:
765:
766: if (data.inUSD != inUSD) {
767: uint256 newPrice;
768: (newPrice, data.hadError) = _getETHUSD(getLower);
769: if (data.hadError) {
770: return FeedData({ price: 0, hadError: true });
771: }
772:
773: data.price = uint240(
774: _convertETHUSD(data.price, newPrice, data.inUSD)
775: );
776: }
777:
778: return FeedData({ price: data.price, hadError: data.hadError });
779: }
['86']
86: function getPrice(
87: address asset,
88: bool inUSD,
89: bool getLower
90: ) external view override returns (PriceReturnData memory pData) {
91:
92: if (!isSupportedAsset[asset]) {
93: revert PendleLPTokenAdaptor__AssetIsNotSupported();
94: }
95:
96: AdaptorData memory data = adaptorData[asset];
97:
98: uint256 lpRate = IPMarket(asset).getLpToAssetRate(data.twapDuration); // <= FOUND
99:
100: (uint256 price, uint256 errorCode) = IOracleRouter(
101: centralRegistry.oracleRouter()
102: ).getPrice(data.quoteAsset, inUSD, getLower); // <= FOUND
103:
104:
105: if (errorCode > 0) {
106: pData.hadError = true;
107: return pData;
108: }
109:
110:
111:
112: price = (price * lpRate) / WAD;
113:
114:
115: if (_checkOracleOverflow(price)) {
116: pData.hadError = true;
117: return pData;
118: }
119:
120: pData.inUSD = inUSD;
121: pData.price = uint240(price);
122: }
['256']
256: function onBorrow(
257: address borrowToken,
258: address borrower,
259: uint256 borrowAmount,
260: bytes calldata params
261: ) external override {
262:
263:
264: if (msg.sender != borrowToken) {
265: _revert(_UNAUTHORIZED_SELECTOR);
266: }
267:
268:
269:
270: if (!marketManager.isListed(borrowToken)) {
271: _revert(_UNAUTHORIZED_SELECTOR);
272: }
273:
274: LeverageStruct memory leverageData = abi.decode(
275: params,
276: (LeverageStruct)
277: );
278:
279: if (
280: borrowToken != address(leverageData.borrowToken) ||
281: borrowAmount != leverageData.borrowAmount
282: ) {
283: revert PositionFolding__InvalidParam();
284: }
285:
286: address borrowUnderlying = CTokenPrimitive(borrowToken).underlying(); // <= FOUND
287:
288: if (IERC20(borrowUnderlying).balanceOf(address(this)) < borrowAmount) { // <= FOUND
289: revert PositionFolding__InvalidAmount();
290: }
291:
292:
293: uint256 fee = (borrowAmount * getProtocolLeverageFee()) / WAD;
294: if (fee > 0) {
295: SafeTransferLib.safeTransfer(
296: borrowUnderlying,
297: centralRegistry.daoAddress(),
298: fee
299: );
300: }
301:
302:
303: if (leverageData.swapData.call.length > 0) {
304:
305: if (!centralRegistry.isSwapper(leverageData.swapData.target)) {
306: revert PositionFolding__InvalidSwapper(
307: leverageData.swapData.target
308: );
309: }
310:
311:
312: SwapperLib.swap(centralRegistry, leverageData.swapData);
313: }
314:
315:
316: SwapperLib.ZapperCall memory zapperCall = leverageData.zapperCall;
317:
318:
319: if (zapperCall.call.length > 0) {
320:
321: if (!centralRegistry.isZapper(leverageData.zapperCall.target)) {
322: revert PositionFolding__InvalidZapper(
323: leverageData.zapperCall.target
324: );
325: }
326:
327:
328:
329: SwapperLib.zap(zapperCall);
330: }
331:
332:
333:
334:
335:
336: CTokenPrimitive collateralToken = leverageData.collateralToken;
337:
338:
339: address collateralUnderlying = collateralToken.underlying();
340: uint256 amount = IERC20(collateralUnderlying).balanceOf(address(this)); // <= FOUND
341:
342:
343: SwapperLib._approveTokenIfNeeded(
344: collateralUnderlying,
345: address(collateralToken),
346: amount
347: );
348:
349:
350: collateralToken.depositAsCollateral(amount, borrower);
351:
352: uint256 remaining = IERC20(zapperCall.inputToken).balanceOf( // <= FOUND
353: address(this)
354: );
355:
356:
357: if (remaining > 0) {
358: SafeTransferLib.safeTransfer(
359: zapperCall.inputToken,
360: borrower,
361: remaining
362: );
363: }
364:
365: remaining = IERC20(borrowUnderlying).balanceOf(address(this)); // <= FOUND
366:
367:
368: if (remaining > 0) {
369: SafeTransferLib.safeTransfer(
370: borrowUnderlying,
371: borrower,
372: remaining
373: );
374: }
375:
376:
377: SwapperLib._removeApprovalIfNeeded(
378: borrowUnderlying,
379: address(borrowToken)
380: );
381: }
['394']
394: function onRedeem(
395: address collateralToken,
396: address redeemer,
397: uint256 collateralAmount,
398: bytes calldata params
399: ) external override {
400:
401:
402: if (msg.sender != collateralToken) {
403: _revert(_UNAUTHORIZED_SELECTOR);
404: }
405:
406:
407:
408: if (!marketManager.isListed(collateralToken)) {
409: _revert(_UNAUTHORIZED_SELECTOR);
410: }
411:
412: DeleverageStruct memory deleverageData = abi.decode(
413: params,
414: (DeleverageStruct)
415: );
416:
417: if (
418: collateralToken != address(deleverageData.collateralToken) ||
419: collateralAmount != deleverageData.collateralAmount
420: ) {
421: revert PositionFolding__InvalidParam();
422: }
423:
424:
425:
426: address collateralUnderlying = CTokenPrimitive(collateralToken)
427: .underlying();
428:
429: if (
430: IERC20(collateralUnderlying).balanceOf(address(this)) < // <= FOUND
431: collateralAmount
432: ) {
433: revert PositionFolding__InvalidAmount();
434: }
435:
436:
437: uint256 fee = (collateralAmount * getProtocolLeverageFee()) / 10000;
438: if (fee > 0) {
439: collateralAmount -= fee;
440: SafeTransferLib.safeTransfer(
441: collateralUnderlying,
442: centralRegistry.daoAddress(),
443: fee
444: );
445: }
446:
447: SwapperLib.ZapperCall memory zapperCall = deleverageData.zapperCall;
448:
449:
450: if (zapperCall.call.length > 0) {
451: if (collateralUnderlying != zapperCall.inputToken) {
452: revert PositionFolding__InvalidZapperParam();
453: }
454:
455:
456: if (!centralRegistry.isZapper(deleverageData.zapperCall.target)) {
457: revert PositionFolding__InvalidZapper(
458: deleverageData.zapperCall.target
459: );
460: }
461:
462:
463: SwapperLib.zap(zapperCall);
464: }
465:
466:
467: if (deleverageData.swapData.call.length > 0) {
468:
469: if (!centralRegistry.isSwapper(deleverageData.swapData.target)) {
470: revert PositionFolding__InvalidSwapper(
471: deleverageData.swapData.target
472: );
473: }
474:
475:
476: SwapperLib.swap(centralRegistry, deleverageData.swapData);
477: }
478:
479:
480:
481:
482:
483: DToken borrowToken = deleverageData.borrowToken;
484:
485:
486: address borrowUnderlying = borrowToken.underlying();
487: uint256 repayAmount = deleverageData.repayAmount;
488: uint256 remaining = IERC20(borrowUnderlying).balanceOf(address(this)) - // <= FOUND
489: repayAmount;
490:
491:
492: SwapperLib._approveTokenIfNeeded(
493: borrowUnderlying,
494: address(borrowToken),
495: repayAmount
496: );
497:
498:
499: borrowToken.repayFor(redeemer, repayAmount);
500:
501:
502: if (remaining > 0) {
503: SafeTransferLib.safeTransfer(
504: borrowUnderlying,
505: redeemer,
506: remaining
507: );
508: }
509:
510: remaining = IERC20(collateralUnderlying).balanceOf(address(this)); // <= FOUND
511:
512:
513: if (remaining > 0) {
514: SafeTransferLib.safeTransfer(
515: collateralUnderlying,
516: redeemer,
517: remaining
518: );
519: }
520:
521:
522: SwapperLib._removeApprovalIfNeeded(
523: borrowUnderlying,
524: address(borrowToken)
525: );
526: }
['389']
389: function _repayDebt(
390: address dToken,
391: address dTokenUnderlying,
392: uint256 repayAmount,
393: address recipient
394: ) internal returns (uint256 outAmount) {
395:
396:
397:
398:
399:
400: outAmount = IERC20(dTokenUnderlying).balanceOf(address(this)); // <= FOUND
401:
402:
403: if (outAmount < repayAmount) {
404: revert SimpleRewardZapper__InsufficientToRepay();
405: }
406:
407:
408: SwapperLib._approveTokenIfNeeded(
409: dTokenUnderlying,
410: dToken,
411: repayAmount
412: );
413:
414:
415: DToken(dToken).repayFor(recipient, repayAmount); // <= FOUND
416:
417:
418: SwapperLib._removeApprovalIfNeeded(dTokenUnderlying, dToken);
419:
420: outAmount -= repayAmount;
421:
422:
423: if (outAmount > 0) {
424: _transferToRecipient(dTokenUnderlying, recipient, outAmount);
425: }
426: }
['292']
292: function _repayDebt(
293: address dToken,
294: uint256 repayAmount,
295: address recipient
296: ) internal returns (uint256 outAmount) {
297: address dTokenUnderlying = DToken(dToken).underlying(); // <= FOUND
298:
299:
300:
301: outAmount = IERC20(dTokenUnderlying).balanceOf(address(this)); // <= FOUND
302:
303:
304: if (outAmount < repayAmount) {
305: revert SimpleZapper__InsufficientToRepay();
306: }
307:
308:
309: SwapperLib._approveTokenIfNeeded(
310: dTokenUnderlying,
311: dToken,
312: repayAmount
313: );
314:
315:
316: DToken(dToken).repayFor(recipient, repayAmount); // <= FOUND
317:
318:
319: SwapperLib._removeApprovalIfNeeded(dTokenUnderlying, dToken);
320:
321: outAmount -= repayAmount;
322:
323:
324: if (outAmount > 0) {
325: _transferToRecipient(
326: dTokenUnderlying,
327: recipient,
328: outAmount
329: );
330: }
331: }
['759']
759: function bridgeVeCVELock(
760: uint256 lockIndex,
761: uint256 dstChainId,
762: bool continuousLock,
763: RewardsData calldata rewardsData,
764: bytes calldata params,
765: uint256 aux
766: ) external payable nonReentrant returns (uint64 sequence) {
767: if (isShutdown == 2) {
768: _revert(_VECVE_SHUTDOWN_SELECTOR);
769: }
770:
771:
772: _claimRewards(msg.sender, rewardsData, params, aux);
773:
774:
775:
776: Lock[] storage locks = userLocks[msg.sender];
777:
778:
779: if (lockIndex >= locks.length) {
780: _revert(_INVALID_LOCK_SELECTOR);
781: }
782:
783:
784: if (block.timestamp >= locks[lockIndex].unlockTime) {
785: _revert(_INVALID_LOCK_SELECTOR);
786: }
787:
788: Lock memory lock = locks[lockIndex];
789: uint256 amount = lock.amount;
790:
791:
792: _updateDataFromEarlyUnlock(msg.sender, amount, lock.unlockTime);
793:
794:
795: _burn(msg.sender, amount);
796:
797: _removeLock(locks, lockIndex);
798:
799: ICVE(cve).burnVeCVELock(amount); // <= FOUND
800:
801: address messagingHub = centralRegistry.protocolMessagingHub();
802:
803: sequence = IProtocolMessagingHub(messagingHub).bridgeVeCVELock{ // <= FOUND
804: value: msg.value
805: }(dstChainId, msg.sender, amount, continuousLock);
806:
807:
808:
809:
810: if (locks.length == 0 && isShutdown != 2) {
811: cveLocker.resetUserClaimIndex(msg.sender);
812: }
813: }
['41']
41: function enterVelodrome(
42: address router,
43: address factory,
44: address lpToken,
45: uint256 amount0,
46: uint256 amount1,
47: uint256 lpMinOutAmount
48: ) internal returns (uint256 lpOutAmount) {
49: address token0 = IVeloPair(lpToken).token0(); // <= FOUND
50: address token1 = IVeloPair(lpToken).token1(); // <= FOUND
51: bool stable = IVeloPool(lpToken).stable(); // <= FOUND
52:
53:
54: if (amount0 > 0) {
55: (uint256 r0, uint256 r1, ) = IVeloPair(lpToken).getReserves(); // <= FOUND
56:
57: uint256 swapAmount = _optimalDeposit(
58: factory,
59: lpToken,
60: amount0,
61: r0,
62: r1,
63: 10 ** ERC20(token0).decimals(), // <= FOUND
64: 10 ** ERC20(token1).decimals(), // <= FOUND
65: stable
66: );
67:
68:
69: amount1 = _swapExactTokensForTokens(
70: router,
71: lpToken,
72: token0,
73: token1,
74: swapAmount,
75: stable
76: );
77: amount0 -= swapAmount;
78:
79:
80: uint256 newLpOutAmount = _addLiquidity(
81: router,
82: token0,
83: token1,
84: stable,
85: amount0,
86: amount1,
87: VELODROME_ADD_LIQUIDITY_SLIPPAGE
88: );
89:
90: lpOutAmount += newLpOutAmount;
91: }
92:
93: amount1 = CommonLib.getTokenBalance(token1);
94:
95:
96: if (amount1 > 0) {
97: (uint256 r0, uint256 r1, ) = IVeloPair(lpToken).getReserves(); // <= FOUND
98:
99: uint256 swapAmount = _optimalDeposit(
100: factory,
101: lpToken,
102: amount1,
103: r1,
104: r0,
105: 10 ** ERC20(token1).decimals(), // <= FOUND
106: 10 ** ERC20(token0).decimals(), // <= FOUND
107: stable
108: );
109:
110:
111: amount0 = _swapExactTokensForTokens(
112: router,
113: lpToken,
114: token1,
115: token0,
116: swapAmount,
117: stable
118: );
119: amount1 -= swapAmount;
120:
121:
122: uint256 newLpOutAmount = _addLiquidity(
123: router,
124: token0,
125: token1,
126: stable,
127: amount0,
128: amount1,
129: VELODROME_ADD_LIQUIDITY_SLIPPAGE
130: );
131:
132: lpOutAmount += newLpOutAmount;
133: }
134:
135:
136: if (lpOutAmount < lpMinOutAmount) {
137: revert VelodromeLib__ReceivedAmountIsLessThanMinimum(
138: lpOutAmount,
139: lpMinOutAmount
140: );
141: }
142: }
['224']
224: function _optimalDeposit(
225: address factory,
226: address lpToken,
227: uint256 amount0,
228: uint256 reserve0,
229: uint256 reserve1,
230: uint256 decimals0,
231: uint256 decimals1,
232: bool stable
233: ) internal view returns (uint256) {
234:
235: uint256 swapFee = IVeloPairFactory(factory).getFee(lpToken, stable); // <= FOUND
236: uint256 a;
237:
238:
239: if (stable) {
240: a = (((amount0 * 10000) / (10000 - swapFee)) * 1e18) / decimals0;
241:
242: uint256 x = (reserve0 * 1e18) / decimals0;
243: uint256 y = (reserve1 * 1e18) / decimals1;
244: uint256 x2 = (x * x) / 1e18;
245: uint256 y2 = (y * y) / 1e18;
246: uint256 p = (y * (((x2 * 3 + y2) * 1e18) / (y2 * 3 + x2))) / x;
247:
248: uint256 num = a * y;
249: uint256 den = ((a + x) * p) / 1e18 + y;
250:
251: return ((num / den) * decimals0) / 1e18;
252: }
253:
254:
255: uint256 swapFeeFactor = 10000 - swapFee;
256:
257: a = (10000 + swapFeeFactor) * reserve0;
258: uint256 b = amount0 * 10000 * reserve0 * 4 * swapFeeFactor;
259: uint256 c = FixedPointMathLib.sqrt(a * a + b);
260: uint256 d = swapFeeFactor * 2;
261: return (c - a) / d;
262:
263: }
['273']
273: function _swapExactTokensForTokens(
274: address router,
275: address lpToken,
276: address tokenIn,
277: address tokenOut,
278: uint256 amount,
279: bool stable
280: ) internal returns (uint256) {
281:
282: SwapperLib._approveTokenIfNeeded(tokenIn, router, amount);
283:
284: IVeloRouter.Route[] memory routes = new IVeloRouter.Route[](1);
285: routes[0].from = tokenIn;
286: routes[0].to = tokenOut;
287: routes[0].stable = stable;
288: routes[0].factory = IVeloPool(lpToken).factory(); // <= FOUND
289:
290:
291: uint256[] memory amountsOut = IVeloRouter(router)
292: .swapExactTokensForTokens(
293: amount,
294: 0,
295: routes,
296: address(this),
297: block.timestamp
298: );
299:
300:
301: SwapperLib._removeApprovalIfNeeded(tokenIn, router);
302:
303: return amountsOut[amountsOut.length - 1];
304: }
[NonCritical-4] Events may be emitted out of order due to code not follow the best practice of check-effects-interaction
The "check-effects-interaction" pattern also impacts event ordering. When a contract doesn't adhere to this pattern, events might be emitted in a sequence that doesn't reflect the actual logical flow of operations. This can cause confusion during event tracking, potentially leading to erroneous off-chain interpretations. To rectify this, always ensure that checks are performed first, state modifications come next, and interactions with external contracts or addresses are done last. This will ensure events are emitted in a logical, consistent manner, providing a clear and accurate chronological record of on-chain actions for off-chain systems and observers.
Num of instances: 18
Click to show findings
['148']
148: function addAsset(address asset, AdaptorData memory data) external { // <= FOUND
149: _checkElevatedPermissions();
150:
151: IBalancerPool pool = IBalancerPool(asset);
152:
153:
154: data.poolId = pool.getPoolId();
155: data.poolDecimals = pool.decimals();
156:
157: uint256 numUnderlyingOrConstituent = data
158: .underlyingOrConstituent
159: .length;
160:
161:
162: for (uint256 i; i < numUnderlyingOrConstituent; ++i) {
163:
164: if (address(data.underlyingOrConstituent[i]) == address(0)) {
165: continue;
166: }
167:
168: if (
169: !IOracleRouter(centralRegistry.oracleRouter()).isSupportedAsset( // <= FOUND
170: data.underlyingOrConstituent[i]
171: )
172: ) {
173: revert BalancerStablePoolAdaptor__ConfigurationError();
174: }
175:
176: if (data.rateProviders[i] != address(0)) {
177:
178: if (data.rateProviderDecimals[i] == 0) {
179: revert BalancerStablePoolAdaptor__ConfigurationError();
180: }
181:
182:
183: if (IRateProvider(data.rateProviders[i]).getRate() == 0) { // <= FOUND
184: revert BalancerStablePoolAdaptor__ConfigurationError();
185: }
186: }
187: }
188:
189:
190: adaptorData[asset] = data;
191:
192:
193: bool isUpdate;
194: if (isSupportedAsset[asset]) {
195: isUpdate = true;
196: }
197:
198: isSupportedAsset[asset] = true;
199: emit BalancerStablePoolAssetAdded(asset, data, isUpdate); // <= FOUND
200: }
['177']
177: function addAsset(address asset, AdaptorData memory data) external { // <= FOUND
178: _checkElevatedPermissions();
179:
180:
181:
182: if (isLocked(data.pool, 2)) {
183: revert Curve2PoolAssetAdaptor__UnsupportedPool();
184: }
185:
186:
187: if (asset == data.baseToken) {
188: revert Curve2PoolAssetAdaptor__InvalidAsset();
189: }
190:
191: address oracleRouter = centralRegistry.oracleRouter();
192:
193:
194:
195: if (!IOracleRouter(oracleRouter).isSupportedAsset(data.baseToken)) { // <= FOUND
196: revert Curve2PoolAssetAdaptor__BaseAssetIsNotSupported();
197: }
198:
199:
200: if (data.lowerBound >= data.upperBound) {
201: revert Curve2PoolAssetAdaptor__InvalidBounds();
202: }
203:
204: ICurvePool pool = ICurvePool(data.pool);
205:
206: if (pool.coins(uint256(uint128(data.quoteTokenIndex))) != asset) {
207: revert Curve2PoolAssetAdaptor__InvalidAssetIndex();
208: }
209: if (
210: pool.coins(uint256(uint128(data.baseTokenIndex))) != data.baseToken
211: ) {
212: revert Curve2PoolAssetAdaptor__InvalidAssetIndex();
213: }
214:
215: data.quoteTokenDecimals = ERC20(asset).decimals(); // <= FOUND
216:
217: if (CommonLib.isETH(data.baseToken)) {
218: data.baseTokenDecimals = 18;
219: } else {
220: data.baseTokenDecimals = ERC20(data.baseToken).decimals(); // <= FOUND
221: }
222:
223:
224:
225:
226:
227: data.lowerBound = _bpToWad(data.lowerBound);
228: data.upperBound = _bpToWad(data.upperBound);
229:
230:
231: if (_MAX_BOUND_RANGE + data.lowerBound < data.upperBound) {
232: revert Curve2PoolAssetAdaptor__InvalidBounds();
233: }
234:
235:
236: uint256 testVirtualPrice = pool.get_virtual_price();
237:
238:
239: _enforceBounds(testVirtualPrice, data.lowerBound, data.upperBound);
240:
241:
242: adaptorData[asset] = data;
243:
244:
245: bool isUpdate;
246: if (isSupportedAsset[asset]) {
247: isUpdate = true;
248: }
249:
250: isSupportedAsset[asset] = true;
251: emit CurvePoolAssetAdded(asset, data, isUpdate); // <= FOUND
252: }
['196']
196: function addAsset(address asset, AdaptorData memory data) external { // <= FOUND
197: _checkElevatedPermissions();
198:
199:
200:
201: if (isLocked(asset, 2)) {
202: revert Curve2PoolLPAdaptor__UnsupportedPool();
203: }
204:
205: address oracleRouter = centralRegistry.oracleRouter();
206:
207:
208:
209: if (
210: !IOracleRouter(oracleRouter).isSupportedAsset( // <= FOUND
211: data.underlying0
212: )
213: ) {
214: revert Curve2PoolLPAdaptor__QuoteAssetIsNotSupported();
215: }
216:
217:
218:
219: if (
220: !IOracleRouter(oracleRouter).isSupportedAsset( // <= FOUND
221: data.underlying1
222: )
223: ) {
224: revert Curve2PoolLPAdaptor__QuoteAssetIsNotSupported();
225: }
226:
227:
228: if (data.lowerBound >= data.upperBound) {
229: revert Curve2PoolLPAdaptor__InvalidBounds();
230: }
231:
232: ICurvePool pool = ICurvePool(data.pool);
233: uint256 coinsLength;
234:
235: while (true) {
236: try pool.coins(coinsLength) {
237: ++coinsLength;
238: } catch {
239: break;
240: }
241: }
242:
243:
244: if (coinsLength != 2) {
245: revert Curve2PoolLPAdaptor__UnsupportedPool();
246: }
247:
248: address underlying;
249: for (uint256 i; i < coinsLength; ) {
250: underlying = pool.coins(i++);
251:
252:
253:
254: if (
255: underlying != data.underlying0 &&
256: underlying != data.underlying1
257: ) {
258: revert Curve2PoolLPAdaptor__UnsupportedPool();
259: }
260: }
261:
262:
263:
264:
265:
266: data.lowerBound = _bpToWad(data.lowerBound);
267: data.upperBound = _bpToWad(data.upperBound);
268:
269:
270: if (_MAX_BOUND_RANGE + data.lowerBound < data.upperBound) {
271: revert Curve2PoolLPAdaptor__InvalidBounds();
272: }
273:
274:
275: if (data.isCorrelated) {
276:
277:
278: try pool.lp_price() {
279: revert Curve2PoolLPAdaptor__UnsupportedPool();
280: } catch {}
281: } else {
282:
283:
284: try pool.lp_price() {} catch {
285: revert Curve2PoolLPAdaptor__UnsupportedPool();
286: }
287: }
288:
289:
290: uint256 testVirtualPrice = pool.get_virtual_price();
291:
292:
293: _enforceBounds(testVirtualPrice, data.lowerBound, data.upperBound);
294:
295:
296: adaptorData[asset] = data;
297:
298:
299: bool isUpdate;
300: if (isSupportedAsset[asset]) {
301: isUpdate = true;
302: }
303:
304: isSupportedAsset[asset] = true;
305: emit CurvePoolAssetAdded(asset, data, isUpdate); // <= FOUND
306: }
['130']
130: function addAsset(address asset, AdaptorData memory data) external { // <= FOUND
131: _checkElevatedPermissions();
132:
133:
134: (IStandardizedYield sy, IPPrincipalToken pt, ) = IPMarket(asset)
135: .readTokens();
136:
137:
138: if (address(pt) != data.pt) {
139: revert PendleLPTokenAdaptor__WrongMarket();
140: }
141:
142:
143: if (data.twapDuration < MINIMUM_TWAP_DURATION) {
144: revert PendleLPTokenAdaptor__TwapDurationIsLessThanMinimum();
145: }
146:
147:
148: (, address assetAddress, ) = sy.assetInfo();
149: if (assetAddress != data.quoteAsset) {
150: revert PendleLPTokenAdaptor__WrongQuote();
151: }
152:
153:
154: _checkPtTwap(asset, data.twapDuration);
155:
156:
157: if (
158: !IOracleRouter(centralRegistry.oracleRouter()).isSupportedAsset( // <= FOUND
159: data.quoteAsset
160: )
161: ) {
162: revert PendleLPTokenAdaptor__QuoteAssetIsNotSupported();
163: }
164:
165:
166: adaptorData[asset] = data;
167:
168:
169: bool isUpdate;
170: if (isSupportedAsset[asset]) {
171: isUpdate = true;
172: }
173:
174: isSupportedAsset[asset] = true;
175: emit PendleLPAssetAdded(asset, data, isUpdate); // <= FOUND
176: }
['131']
131: function addAsset(address asset, AdaptorData memory data) external { // <= FOUND
132: _checkElevatedPermissions();
133:
134:
135: (IStandardizedYield sy, IPPrincipalToken pt, ) = data
136: .market
137: .readTokens();
138:
139:
140: if (address(pt) != asset) {
141: revert PendlePrincipalTokenAdaptor__WrongMarket();
142: }
143:
144:
145: if (data.twapDuration < MINIMUM_TWAP_DURATION) {
146: revert PendlePrincipalTokenAdaptor__TwapDurationIsLessThanMinimum();
147: }
148:
149:
150: (, address assetAddress, ) = sy.assetInfo();
151: if (assetAddress != data.quoteAsset) {
152: revert PendlePrincipalTokenAdaptor__WrongQuote();
153: }
154:
155:
156: _checkPtTwap(address(data.market), data.twapDuration);
157:
158:
159: if (
160: !IOracleRouter(centralRegistry.oracleRouter()).isSupportedAsset( // <= FOUND
161: data.quoteAsset
162: )
163: ) {
164: revert PendlePrincipalTokenAdaptor__QuoteAssetIsNotSupported();
165: }
166:
167:
168: adaptorData[asset] = data;
169:
170:
171: bool isUpdate;
172: if (isSupportedAsset[asset]) {
173: isUpdate = true;
174: }
175:
176: isSupportedAsset[asset] = true;
177: emit PendlePTAssetAdded(asset, data, isUpdate); // <= FOUND
178: }
['214']
214: function addAsset(address asset, AdaptorData memory data) external { // <= FOUND
215: _checkElevatedPermissions();
216:
217:
218: if (data.secondsAgo < MINIMUM_SECONDS_AGO) {
219: revert UniswapV3Adaptor__SecondsAgoIsLessThanMinimum();
220: }
221:
222: UniswapV3Pool pool = UniswapV3Pool(data.priceSource);
223:
224:
225: address token0 = pool.token0();
226: address token1 = pool.token1();
227: if (token0 == asset) {
228: data.baseDecimals = ERC20(asset).decimals(); // <= FOUND
229: data.quoteDecimals = ERC20(token1).decimals(); // <= FOUND
230: data.quoteToken = token1;
231: } else if (token1 == asset) {
232: data.baseDecimals = ERC20(asset).decimals(); // <= FOUND
233: data.quoteDecimals = ERC20(token0).decimals(); // <= FOUND
234: data.quoteToken = token0;
235: } else revert UniswapV3Adaptor__AssetIsNotSupported();
236:
237:
238: adaptorData[asset] = data;
239:
240:
241: bool isUpdate;
242: if (isSupportedAsset[asset]) {
243: isUpdate = true;
244: }
245:
246: isSupportedAsset[asset] = true;
247: emit UniswapV3AssetAdded(asset, data, isUpdate); // <= FOUND
248: }
['129']
129: function harvest(
130: bytes calldata data
131: ) external override returns (uint256 yield) {
132:
133: _canCompound();
134:
135:
136: _vestIfNeeded();
137:
138:
139: if (_checkVestStatus(_vaultData)) {
140: _updateVestingPeriodIfNeeded();
141:
142:
143: StrategyData memory sd = strategyData;
144:
145:
146: sd.gauge.getReward(address(this));
147:
148: {
149: uint256 rewardAmount = rewardToken.balanceOf(address(this));
150:
151:
152: if (rewardAmount > 0) {
153:
154:
155: uint256 protocolFee = FixedPointMathLib.mulDiv(
156: rewardAmount,
157: centralRegistry.protocolHarvestFee(),
158: 1e18
159: );
160: rewardAmount -= protocolFee;
161: SafeTransferLib.safeTransfer(
162: address(rewardToken),
163: centralRegistry.feeAccumulator(),
164: protocolFee
165: );
166:
167:
168: if (!rewardTokenIsUnderlying) {
169: SwapperLib.Swap memory swapData = abi.decode(
170: data,
171: (SwapperLib.Swap)
172: );
173:
174: if (!centralRegistry.isSwapper(swapData.target)) {
175: revert AerodromeStableCToken__InvalidSwapper(
176: swapData.target
177: );
178: }
179:
180: SwapperLib.swap(centralRegistry, swapData);
181: }
182: }
183: }
184:
185: uint256 totalAmountA = IERC20(sd.token0).balanceOf(address(this)); // <= FOUND
186:
187:
188: if (totalAmountA == 0) {
189: revert AerodromeStableCToken__SlippageError();
190: }
191:
192:
193: address _asset = asset();
194:
195:
196: (uint256 r0, uint256 r1, ) = IVeloPair(_asset).getReserves(); // <= FOUND
197: (uint256 reserveA, uint256 reserveB) = sd.token0 ==
198: IVeloPair(_asset).token0() // <= FOUND
199: ? (r0, r1)
200: : (r1, r0);
201:
202:
203: uint256 swapAmount = VelodromeLib._optimalDeposit(
204: address(sd.pairFactory),
205: _asset,
206: totalAmountA,
207: reserveA,
208: reserveB,
209: sd.decimalsA,
210: sd.decimalsB,
211: true
212: );
213:
214: VelodromeLib._swapExactTokensForTokens(
215: address(sd.router),
216: _asset,
217: sd.token0,
218: sd.token1,
219: swapAmount,
220: true
221: );
222: totalAmountA -= swapAmount;
223:
224:
225: yield = VelodromeLib._addLiquidity(
226: address(sd.router),
227: sd.token0,
228: sd.token1,
229: true,
230: totalAmountA,
231: IERC20(sd.token1).balanceOf(address(this)), // <= FOUND
232: VelodromeLib.VELODROME_ADD_LIQUIDITY_SLIPPAGE
233: );
234:
235:
236:
237: _afterDeposit(yield, 0);
238:
239:
240: _setNewVaultData(yield, vestPeriod);
241:
242: emit Harvest(yield); // <= FOUND
243: }
244: }
['124']
124: function harvest(
125: bytes calldata data
126: ) external override returns (uint256 yield) {
127:
128: _canCompound();
129:
130:
131: _vestIfNeeded();
132:
133:
134: if (_checkVestStatus(_vaultData)) {
135: _updateVestingPeriodIfNeeded();
136:
137:
138: StrategyData memory sd = strategyData;
139:
140:
141: sd.gauge.getReward(address(this));
142:
143: {
144: uint256 rewardAmount = rewardToken.balanceOf(address(this));
145:
146: if (rewardAmount > 0) {
147:
148:
149: uint256 protocolFee = FixedPointMathLib.mulDiv(
150: rewardAmount,
151: centralRegistry.protocolHarvestFee(),
152: 1e18
153: );
154: rewardAmount -= protocolFee;
155: SafeTransferLib.safeTransfer(
156: address(rewardToken),
157: centralRegistry.feeAccumulator(),
158: protocolFee
159: );
160:
161:
162: if (!rewardTokenIsUnderlying) {
163: SwapperLib.Swap memory swapData = abi.decode(
164: data,
165: (SwapperLib.Swap)
166: );
167:
168: if (!centralRegistry.isSwapper(swapData.target)) {
169: revert AerodromeVolatileCToken__InvalidSwapper(
170: swapData.target
171: );
172: }
173:
174: SwapperLib.swap(centralRegistry, swapData);
175: }
176: }
177: }
178:
179: uint256 totalAmountA = IERC20(sd.token0).balanceOf(address(this)); // <= FOUND
180:
181: if (totalAmountA == 0) {
182: revert AerodromeVolatileCToken__SlippageError();
183: }
184:
185:
186: address _asset = asset();
187:
188:
189: (uint256 r0, uint256 r1, ) = IVeloPair(_asset).getReserves(); // <= FOUND
190: uint256 reserveA = sd.token0 == IVeloPair(_asset).token0() // <= FOUND
191: ? r0
192: : r1;
193:
194:
195:
196:
197: uint256 swapAmount = VelodromeLib._optimalDeposit(
198: address(sd.pairFactory),
199: _asset,
200: totalAmountA,
201: reserveA,
202: 0,
203: 0,
204: 0,
205: false
206: );
207:
208: VelodromeLib._swapExactTokensForTokens(
209: address(sd.router),
210: _asset,
211: sd.token0,
212: sd.token1,
213: swapAmount,
214: false
215: );
216: totalAmountA -= swapAmount;
217:
218:
219: yield = VelodromeLib._addLiquidity(
220: address(sd.router),
221: sd.token0,
222: sd.token1,
223: false,
224: totalAmountA,
225: IERC20(sd.token1).balanceOf(address(this)), // <= FOUND
226: VelodromeLib.VELODROME_ADD_LIQUIDITY_SLIPPAGE
227: );
228:
229:
230:
231: _afterDeposit(yield, 0);
232:
233:
234: _setNewVaultData(yield, vestPeriod);
235:
236: emit Harvest(yield); // <= FOUND
237: }
238:
239: }
['130']
130: function harvest(
131: bytes calldata data
132: ) external override returns (uint256 yield) {
133:
134: _canCompound();
135:
136:
137: _vestIfNeeded();
138:
139:
140: if (_checkVestStatus(_vaultData)) {
141: _updateVestingPeriodIfNeeded();
142:
143:
144: StrategyData memory sd = strategyData;
145:
146:
147: sd.gauge.getReward(address(this));
148:
149: {
150: uint256 rewardAmount = rewardToken.balanceOf(address(this));
151:
152: if (rewardAmount > 0) {
153:
154:
155: uint256 protocolFee = FixedPointMathLib.mulDiv(
156: rewardAmount,
157: centralRegistry.protocolHarvestFee(),
158: 1e18
159: );
160: rewardAmount -= protocolFee;
161: SafeTransferLib.safeTransfer(
162: address(rewardToken),
163: centralRegistry.feeAccumulator(),
164: protocolFee
165: );
166:
167:
168: if (!rewardTokenIsUnderlying) {
169: SwapperLib.Swap memory swapData = abi.decode(
170: data,
171: (SwapperLib.Swap)
172: );
173:
174: if (!centralRegistry.isSwapper(swapData.target)) {
175: revert VelodromeStableCToken__InvalidSwapper(
176: swapData.target
177: );
178: }
179:
180: SwapperLib.swap(centralRegistry, swapData);
181: }
182: }
183: }
184:
185: uint256 totalAmountA = IERC20(sd.token0).balanceOf(address(this)); // <= FOUND
186:
187:
188: if (totalAmountA == 0) {
189: revert VelodromeStableCToken__SlippageError();
190: }
191:
192:
193: address _asset = asset();
194:
195:
196: (uint256 r0, uint256 r1, ) = IVeloPair(_asset).getReserves(); // <= FOUND
197: (uint256 reserveA, uint256 reserveB) = sd.token0 ==
198: IVeloPair(_asset).token0() // <= FOUND
199: ? (r0, r1)
200: : (r1, r0);
201:
202:
203: uint256 swapAmount = VelodromeLib._optimalDeposit(
204: address(sd.pairFactory),
205: _asset,
206: totalAmountA,
207: reserveA,
208: reserveB,
209: sd.decimalsA,
210: sd.decimalsB,
211: true
212: );
213:
214: VelodromeLib._swapExactTokensForTokens(
215: address(sd.router),
216: _asset,
217: sd.token0,
218: sd.token1,
219: swapAmount,
220: true
221: );
222: totalAmountA -= swapAmount;
223:
224:
225: yield = VelodromeLib._addLiquidity(
226: address(sd.router),
227: sd.token0,
228: sd.token1,
229: true,
230: totalAmountA,
231: IERC20(sd.token1).balanceOf(address(this)), // <= FOUND
232: VelodromeLib.VELODROME_ADD_LIQUIDITY_SLIPPAGE
233: );
234:
235:
236:
237: _afterDeposit(yield, 0);
238:
239:
240: _setNewVaultData(yield, vestPeriod);
241:
242: emit Harvest(yield); // <= FOUND
243: }
244: }
['117']
117: function harvest(
118: bytes calldata data
119: ) external override returns (uint256 yield) {
120:
121: _canCompound();
122:
123:
124: _vestIfNeeded();
125:
126:
127: if (_checkVestStatus(_vaultData)) {
128: _updateVestingPeriodIfNeeded();
129:
130:
131: StrategyData memory sd = strategyData;
132:
133:
134: sd.gauge.getReward(address(this));
135:
136: {
137: uint256 rewardAmount = rewardToken.balanceOf(address(this));
138:
139: if (rewardAmount > 0) {
140:
141:
142: uint256 protocolFee = FixedPointMathLib.mulDiv(
143: rewardAmount,
144: centralRegistry.protocolHarvestFee(),
145: 1e18
146: );
147: rewardAmount -= protocolFee;
148: SafeTransferLib.safeTransfer(
149: address(rewardToken),
150: centralRegistry.feeAccumulator(),
151: protocolFee
152: );
153:
154:
155: if (!rewardTokenIsUnderlying) {
156: SwapperLib.Swap memory swapData = abi.decode(
157: data,
158: (SwapperLib.Swap)
159: );
160:
161: if (!centralRegistry.isSwapper(swapData.target)) {
162: revert VelodromeVolatileCToken__InvalidSwapper(
163: swapData.target
164: );
165: }
166:
167: SwapperLib.swap(centralRegistry, swapData);
168: }
169: }
170: }
171:
172: uint256 totalAmountA = IERC20(sd.token0).balanceOf(address(this)); // <= FOUND
173:
174:
175: if (totalAmountA == 0) {
176: revert VelodromeVolatileCToken__SlippageError();
177: }
178:
179:
180: address _asset = asset();
181:
182:
183: (uint256 r0, uint256 r1, ) = IVeloPair(_asset).getReserves(); // <= FOUND
184: uint256 reserveA = sd.token0 == IVeloPair(_asset).token0() // <= FOUND
185: ? r0
186: : r1;
187:
188:
189:
190:
191: uint256 swapAmount = VelodromeLib._optimalDeposit(
192: address(sd.pairFactory),
193: _asset,
194: totalAmountA,
195: reserveA,
196: 0,
197: 0,
198: 0,
199: false
200: );
201:
202: VelodromeLib._swapExactTokensForTokens(
203: address(sd.router),
204: _asset,
205: sd.token0,
206: sd.token1,
207: swapAmount,
208: false
209: );
210: totalAmountA -= swapAmount;
211:
212:
213: yield = VelodromeLib._addLiquidity(
214: address(sd.router),
215: sd.token0,
216: sd.token1,
217: false,
218: totalAmountA,
219: IERC20(sd.token1).balanceOf(address(this)), // <= FOUND
220: VelodromeLib.VELODROME_ADD_LIQUIDITY_SLIPPAGE
221: );
222:
223:
224:
225: _afterDeposit(yield, 0);
226:
227:
228: _setNewVaultData(yield, vestPeriod);
229:
230: emit Harvest(yield); // <= FOUND
231: }
232: }
['108']
108: function addAsset(
109: address asset,
110: string memory ticker,
111: address proxyFeed,
112: uint256 heartbeat,
113: bool inUSD
114: ) external {
115: _checkElevatedPermissions();
116:
117: if (heartbeat != 0) {
118: if (heartbeat > DEFAULT_HEART_BEAT) {
119: revert Api3Adaptor__InvalidHeartbeat();
120: }
121: }
122:
123: bytes32 dapiName = Bytes32Helper.stringToBytes32(ticker);
124: bytes32 dapiNameHash = keccak256(abi.encodePacked(dapiName));
125:
126:
127:
128: if (dapiNameHash != IProxy(proxyFeed).dapiNameHash()) { // <= FOUND
129: revert Api3Adaptor__DAPINameHashError();
130: }
131:
132: AdaptorData storage data;
133:
134: if (inUSD) {
135: data = adaptorDataUSD[asset];
136: } else {
137: data = adaptorDataNonUSD[asset];
138: }
139:
140: data.heartbeat = heartbeat != 0
141: ? heartbeat
142: : DEFAULT_HEART_BEAT;
143:
144:
145:
146:
147:
148:
149:
150: data.max = (uint256(int256(type(int224).max)) * 9) / 10; // <= FOUND
151: data.dapiNameHash = dapiNameHash;
152: data.proxyFeed = IProxy(proxyFeed);
153: data.isConfigured = true;
154:
155:
156: bool isUpdate;
157: if (isSupportedAsset[asset]) {
158: isUpdate = true;
159: }
160:
161: isSupportedAsset[asset] = true;
162: emit Api3AssetAdded(asset, data, isUpdate); // <= FOUND
163: }
['36']
36: function addAsset(
37: address asset
38: ) external override {
39: _checkElevatedPermissions();
40:
41: if (!ICamelotPair(asset).stableSwap()) { // <= FOUND
42: revert CamelotStableLPAdaptor__AssetIsNotStableLP();
43: }
44:
45:
46: bool isUpdate;
47: if (isSupportedAsset[asset]) {
48: isUpdate = true;
49: }
50:
51: AdaptorData memory data = _addAsset(asset);
52: emit CamelotStableLPAssetAdded(asset, data, isUpdate); // <= FOUND
53: }
['36']
36: function addAsset(
37: address asset
38: ) external override {
39: _checkElevatedPermissions();
40:
41: if (ICamelotPair(asset).stableSwap()) { // <= FOUND
42: revert CamelotVolatileLPAdaptor__AssetIsNotVolatileLP();
43: }
44:
45:
46: bool isUpdate;
47: if (isSupportedAsset[asset]) {
48: isUpdate = true;
49: }
50:
51: AdaptorData memory data = _addAsset(asset);
52: emit CamelotVolatileLPAssetAdded(asset, data, isUpdate); // <= FOUND
53: }
['36']
36: function addAsset(
37: address asset
38: ) external override {
39: _checkElevatedPermissions();
40:
41: if (!IVeloPool(asset).stable()) { // <= FOUND
42: revert VelodromeStableLPAdaptor__AssetIsNotStableLP();
43: }
44:
45:
46: bool isUpdate;
47: if (isSupportedAsset[asset]) {
48: isUpdate = true;
49: }
50:
51: AdaptorData memory data = _addAsset(asset);
52: emit VelodromeStableLPAssetAdded(asset, data, isUpdate); // <= FOUND
53: }
['38']
38: function addAsset(
39: address asset
40: ) external override {
41: _checkElevatedPermissions();
42:
43: if (IVeloPool(asset).stable()) { // <= FOUND
44: revert VelodromeVolatileLPAdaptor__AssetIsNotVolatileLP();
45: }
46:
47:
48: bool isUpdate;
49: if (isSupportedAsset[asset]) {
50: isUpdate = true;
51: }
52:
53: AdaptorData memory data = _addAsset(asset);
54: emit VelodromeVolatileLPAssetAdded(asset, data, isUpdate); // <= FOUND
55: }
['113']
113: function addAsset(
114: address asset,
115: address aggregator,
116: uint256 heartbeat,
117: bool inUSD
118: ) external {
119: _checkElevatedPermissions();
120:
121: if (heartbeat != 0) {
122: if (heartbeat > DEFAULT_HEART_BEAT) {
123: revert ChainlinkAdaptor__InvalidHeartbeat();
124: }
125: }
126:
127:
128: IChainlink feedAggregator = IChainlink(
129: IChainlink(aggregator).aggregator() // <= FOUND
130: );
131:
132:
133: uint256 maxFromChainlink = uint256(
134: uint192(feedAggregator.maxAnswer())
135: );
136: uint256 minFromChainklink = uint256(
137: uint192(feedAggregator.minAnswer())
138: );
139:
140:
141:
142:
143: uint256 bufferedMaxPrice = (maxFromChainlink * 9) / 10;
144: uint256 bufferedMinPrice = (minFromChainklink * 11) / 10;
145:
146:
147:
148:
149:
150: if (bufferedMaxPrice > type(uint240).max) { // <= FOUND
151: bufferedMaxPrice = type(uint240).max; // <= FOUND
152: }
153:
154: if (bufferedMinPrice >= bufferedMaxPrice) {
155: revert ChainlinkAdaptor__InvalidMinMaxConfig();
156: }
157:
158: AdaptorData storage data;
159:
160: if (inUSD) {
161: data = adaptorDataUSD[asset];
162: } else {
163: data = adaptorDataNonUSD[asset];
164: }
165:
166:
167: data.decimals = feedAggregator.decimals();
168: data.max = bufferedMaxPrice;
169: data.min = bufferedMinPrice;
170: data.heartbeat = heartbeat != 0
171: ? heartbeat
172: : DEFAULT_HEART_BEAT;
173: data.aggregator = IChainlink(aggregator);
174: data.isConfigured = true;
175:
176:
177: bool isUpdate;
178: if (isSupportedAsset[asset]) {
179: isUpdate = true;
180: }
181:
182: isSupportedAsset[asset] = true;
183: emit ChainlinkAssetAdded(asset, data, isUpdate); // <= FOUND
184: }
['97']
97: function start(
98: uint256 startTimestamp,
99: uint256 softPriceInUSD,
100: uint256 cveAmountInLBP,
101: address paymentTokenAddress
102: ) external {
103: if (!centralRegistry.hasDaoPermissions(msg.sender)) {
104: revert CurvanceDAOLBP__Unauthorized();
105: }
106:
107: if (startTime != 0) {
108: revert CurvanceDAOLBP__AlreadyStarted();
109: }
110:
111: if (startTimestamp < block.timestamp) {
112: revert CurvanceDAOLBP__InvalidStartTime();
113: }
114:
115: uint256 errorCode;
116: (paymentTokenPrice, errorCode) = IOracleRouter(centralRegistry.oracleRouter())
117: .getPrice(paymentTokenAddress, true, true);
118:
119:
120:
121: if (errorCode == 2) {
122: revert CurvanceDAOLBP__InvalidPriceSource();
123: }
124:
125: startTime = startTimestamp;
126: softPriceInpaymentToken = (softPriceInUSD * WAD) / paymentTokenPrice;
127: cveAmountForSale = cveAmountInLBP;
128: paymentToken = paymentTokenAddress;
129: paymentTokenDecimals = IERC20(paymentTokenAddress).decimals(); // <= FOUND
130:
131: emit LBPStarted(startTimestamp); // <= FOUND
132: }
['878']
878: function listToken(address mToken) external { // <= FOUND
879: _checkElevatedPermissions();
880:
881: if (tokenData[mToken].isListed) {
882: _revert(_INVALID_PARAMETER_SELECTOR);
883: }
884:
885:
886: IMToken(mToken).isCToken(); // <= FOUND
887:
888:
889:
890: if (!IMToken(mToken).startMarket(msg.sender)) { // <= FOUND
891: _revert(_INVARIANT_ERROR_SELECTOR);
892: }
893:
894: MarketToken storage token = tokenData[mToken];
895: token.isListed = true;
896: token.collRatio = 0;
897:
898: uint256 numTokens = tokensListed.length;
899:
900: for (uint256 i; i < numTokens; ) {
901: unchecked {
902: if (tokensListed[i++] == mToken) {
903: _revert(_INVALID_PARAMETER_SELECTOR);
904: }
905: }
906: }
907:
908: tokensListed.push(mToken);
909: emit TokenListed(mToken); // <= FOUND
910: }
[NonCritical-5] It is standard for all external and public functions to be override from an interface
This is to ensure the whole API is extracted in a interface
Num of instances: 397
Click to show findings
['108']
108: function addAsset(
109: address asset,
110: string memory ticker,
111: address proxyFeed,
112: uint256 heartbeat,
113: bool inUSD
114: ) external
['134']
134: function reQueryRewardTokens() external
['163']
163: function reQueryUnderlyingTokens() external
['157']
157: function rewardTokens() external view returns (address[] memory)
['162']
162: function underlyingTokens() external view returns (address[] memory)
['214']
214: function addAsset(address asset, AdaptorData memory data) external
['93']
93: function addAsset(
94: address asset,
95: bool inUSD,
96: uint8 decimals
97: ) external
['70']
70: function addAsset(address asset) external virtual
['70']
70: function addAsset(address asset) external virtual
['17']
17: function aggregator() external view returns (address)
['22']
22: function maxAnswer() external view returns (int192)
['44']
44: function minAnswer() external view returns (int192)
['67']
67: function decimals() external view returns (uint8)
['81']
81: function latestRoundData()
82: external
83: view
84: returns (
85: uint80 roundId,
86: int256 answer,
87: uint256 startedAt,
88: uint256 updatedAt,
89: uint80 answeredInRound
90: )
91:
['70']
70: function withdrawNativeYield(address[] calldata nonMTokens) external
['119']
119: function claimYieldForGauge(
120: address marketManager,
121: bool claimWETHYield,
122: bool claimUSDBYield
123: ) external nonReentrant returns (
124: uint256 WETHYield,
125: uint256 USDBYield
126: )
['307']
307: function claimYieldForAutoCompounding(
308: address marketManager,
309: bool claimWETHYield,
310: bool claimUSDBYield
311: ) external nonReentrant returns (
312: uint256 WETHYield,
313: uint256 USDBYield
314: )
['372']
372: function setCTokenToDTokenYieldDonation(
373: address cToken,
374: address dToken
375: ) external
['398']
398: function claimPendingNativeYield(address[] calldata nonMTokens) external
['427']
427: function notifyRewards(
428: address marketManager,
429: bool isWETH,
430: uint256 amount
431: ) external
['456']
456: function notifyIsMarketManager(
457: address notifiedMarketManager,
458: bool isSupported
459: ) external
['469']
469: function getClaimableNativeYield(
470: address delegatedAddress
471: ) external view returns (uint256)
['37']
37: function borrowAndBridge(
38: address dToken,
39: uint256 borrowAmount,
40: SwapperLib.Swap memory swapData,
41: uint256 dstChainId
42: ) external payable nonReentrant
['144']
144: function depositAsCollateral(
145: uint256 assets,
146: address receiver
147: ) external nonReentrant returns (uint256 shares)
['170']
170: function depositAsCollateralFor(
171: uint256 assets,
172: address receiver
173: ) external nonReentrant returns (uint256 shares)
['187']
187: function withdrawCollateral(
188: uint256 assets,
189: address receiver,
190: address owner
191: ) external nonReentrant returns (uint256 shares)
['201']
201: function redeemCollateral(
202: uint256 shares,
203: address receiver,
204: address owner
205: ) external nonReentrant returns (uint256 assets)
['216']
216: function redeemCollateralFor(
217: uint256 shares,
218: address receiver,
219: address owner
220: ) external nonReentrant returns (uint256 assets)
['227']
227: function balanceOfUnderlyingSafe(
228: address account
229: ) external view returns (uint256)
['236']
236: function balanceOfUnderlying(
237: address account
238: ) external view returns (uint256)
['244']
244: function exchangeRateSafe() external view returns (uint256)
['250']
250: function exchangeRateCached() external view returns (uint256)
['778']
778: function getSnapshot(
779: address account
780: ) external view returns (uint256, uint256, uint256)
['795']
795: function getSnapshotPacked(
796: address
797: ) external view returns (AccountSnapshot memory)
['288']
288: function startMarket(address by) external virtual returns (bool)
['312']
312: function underlying() external view returns (address)
['484']
484: function seize(
485: address liquidator,
486: address account,
487: uint256 liquidatedTokens,
488: uint256 protocolTokens
489: ) external nonReentrant
['530']
530: function seizeAccountLiquidation(
531: address liquidator,
532: address account,
533: uint256 shares
534: ) external nonReentrant
['41']
41: function withdrawByPositionFolding(
42: address owner,
43: uint256 assets,
44: bytes calldata params
45: ) external nonReentrant
['164']
164: function getVaultYieldStatus() external view returns (VaultData memory)
['169']
169: function vaultCompoundFee() external view returns (uint256)
['174']
174: function vaultYieldFee() external view returns (uint256)
['179']
179: function vaultHarvestFee() external view returns (uint256)
['205']
205: function setVestingPeriod(uint256 newVestingPeriod) external
['219']
219: function setCompoundingPaused(bool state) external
['52']
52: function setExitFee(uint256 newExitFee) external
['41']
41: function withdrawByPositionFolding(
42: address owner,
43: uint256 assets,
44: bytes calldata params
45: ) external nonReentrant
['102']
102: function mintGaugeEmissions(address gaugePool, uint256 amount) external
['113']
113: function mintLockBoost(uint256 amount) external
['126']
126: function mintVeCVELock(uint256 amount) external
['139']
139: function burnVeCVELock(uint256 amount) external
['151']
151: function mintTreasury(uint256 amount) external
['167']
167: function mintCommunityAllocation(uint256 amount) external
['185']
185: function mintBuilder() external
['212']
212: function setBuilderAddress(address newAddress) external
['229']
229: function bridge(
230: uint256 dstChainId,
231: address recipient,
232: uint256 amount
233: ) external payable returns (uint64)
['248']
248: function bridgeFee() external view returns (uint256)
['89']
89: function claim(
90: uint256 amount,
91: bool locked,
92: bytes32[] calldata proof
93: ) external nonReentrant
['162']
162: function canClaim(
163: address user,
164: uint256 amount,
165: bytes32[] calldata proof
166: ) external view returns (bool)
['711']
711: function rescueToken(address token, uint256 amount) external
['215']
215: function withdrawRemainingTokens() external
['234']
234: function setMerkleRoot(bytes32 newRoot) external
['252']
252: function setPauseState(bool paused) external
['132']
132: function recordEpochRewards(uint256 rewardsPerCVE) external
['150']
150: function startLocker() external
['711']
711: function rescueToken(address token, uint256 amount) external
['190']
190: function notifyLockerShutdown() external
['204']
204: function currentEpoch(uint256 time) external view returns (uint256)
['219']
219: function hasRewardsToClaim(address user) external view returns (bool)
['236']
236: function hypotheticalRewardsClaim(
237: address user
238: ) external view returns (uint256)
['278']
278: function updateUserClaimIndex(address user, uint256 index) external
['287']
287: function resetUserClaimIndex(address user) external
['298']
298: function claimRewards(
299: RewardsData calldata rewardsData,
300: bytes calldata params,
301: uint256 aux
302: ) external nonReentrant
['331']
331: function claimRewardsFor(
332: address user,
333: uint256 epochs,
334: RewardsData calldata rewardsData,
335: bytes calldata params,
336: uint256 aux
337: ) external nonReentrant
['355']
355: function manageRewardsFor(
356: address user,
357: uint256 epochs
358: ) external nonReentrant returns (uint256)
['303']
303: function withdrawReservesMulti(address[] calldata dTokens) external
['329']
329: function setCVE(address newCVE) external
['340']
340: function setVeCVE(address newVeCVE) external
['351']
351: function setCVELocker(address newCVELocker) external
['362']
362: function setProtocolMessagingHub(
363: address newProtocolMessagingHub
364: ) external
['385']
385: function setOracleRouter(address newOracleRouter) external
['396']
396: function setFeeAccumulator(address newFeeAccumulator) external
['407']
407: function setWormholeCore(address newWormholeCore) external
['418']
418: function setWormholeRelayer(address newWormholeRelayer) external
['429']
429: function setCircleTokenMessenger(
430: address newCircleTokenMessenger
431: ) external
['442']
442: function setTokenBridge(address newTokenBridge) external
['454']
454: function registerWormholeChainIDs(
455: uint256[] calldata chainIds,
456: uint16[] calldata wormholeChainIds
457: ) external
['472']
472: function registerCCTPDomains(
473: uint256[] calldata chainIds,
474: uint32[] calldata cctpDomains
475: ) external
['490']
490: function setGelatoSponsor(address newGelatoSponsor) external
['504']
504: function setProtocolCompoundFee(uint256 value) external
['529']
529: function setProtocolYieldFee(uint256 value) external
['554']
554: function setProtocolLeverageFee(uint256 value) external
['577']
577: function setProtocolInterestRateFee(
578: address market,
579: uint256 value
580: ) external
['608']
608: function setEarlyUnlockPenaltyMultiplier(uint256 value) external
['634']
634: function setVoteBoostMultiplier(uint256 value) external
['656']
656: function setLockBoostMultiplier(uint256 value) external
['676']
676: function incrementApprovalIndex() external
['687']
687: function disableDelegable(bool delegable) external
['699']
699: function transferDaoOwnership(address newDaoAddress) external
['729']
729: function migrateTimelockConfiguration(address newTimelock) external
['751']
751: function transferEmergencyCouncil(address newEmergencyCouncil) external
['786']
786: function addChainSupport(
787: address newOmnichainOperator,
788: address messagingHub,
789: address cveAddress,
790: uint256 chainId,
791: uint256 sourceAux,
792: uint256 destinationAux,
793: uint16 messagingChainId
794: ) external
['836']
836: function removeChainSupport(
837: address currentOmnichainOperator,
838: uint256 chainId
839: ) external
['883']
883: function setExternalCallDataChecker(
884: address target,
885: address callDataChecker
886: ) external
['898']
898: function addZapper(address newZapper) external
['917']
917: function removeZapper(address currentZapper) external
['936']
936: function addSwapper(address newSwapper) external
['955']
955: function removeSwapper(address currentSwapper) external
['974']
974: function addVeCVELocker(address newVeCVELocker) external
['993']
993: function removeVeCVELocker(address currentVeCVELocker) external
['1012']
1012: function addGaugeController(address newGaugeController) external
['1031']
1031: function removeGaugeController(address currentGaugeController) external
['1053']
1053: function addHarvester(address newHarvester) external
['1072']
1072: function removeHarvester(address currentHarvester) external
['1091']
1091: function addEndpoint(address newEndpoint) external
['1110']
1110: function removeEndpoint(address currentEndpoint) external
['1123']
1123: function getOmnichainOperators(
1124: address _address,
1125: uint256 chainID
1126: ) external view returns (OmnichainData memory)
['113']
113: function addAsset(
114: address asset,
115: address aggregator,
116: uint256 heartbeat,
117: bool inUSD
118: ) external
['102']
102: function mintGaugeEmissions(address gaugePool, uint256 amount) external
['113']
113: function mintLockBoost(uint256 amount) external
['126']
126: function mintVeCVELock(uint256 amount) external
['139']
139: function burnVeCVELock(uint256 amount) external
['229']
229: function bridge(
230: uint256 dstChainId,
231: address recipient,
232: uint256 amount
233: ) external payable returns (uint64)
['126']
126: function enterCurve(
127: address cToken,
128: ZapperData calldata zapData,
129: SwapperLib.Swap[] calldata tokenSwaps,
130: address lpMinter,
131: address[] calldata tokens,
132: address recipient
133: ) external payable nonReentrant returns (uint256 outAmount)
['175']
175: function exitCurve(
176: address lpMinter,
177: ZapperData calldata zapData,
178: address[] calldata tokens,
179: uint256 singleAssetWithdraw,
180: uint256 singleAssetIndex,
181: SwapperLib.Swap[] calldata tokenSwaps,
182: address recipient
183: ) external nonReentrant returns (uint256 outAmount)
['227']
227: function redeemAndExitCurve(
228: RedemptionData calldata redemptionData,
229: address lpMinter,
230: ZapperData calldata zapData,
231: address[] calldata tokens,
232: uint256 singleAssetWithdraw,
233: uint256 singleAssetIndex,
234: SwapperLib.Swap[] calldata tokenSwaps,
235: address recipient
236: ) external nonReentrant returns (uint256 outAmount)
['268']
268: function enterBalancer(
269: address cToken,
270: ZapperData calldata zapData,
271: SwapperLib.Swap[] calldata tokenSwaps,
272: address balancerVault,
273: bytes32 balancerPoolId,
274: address[] calldata tokens,
275: address recipient
276: ) external payable nonReentrant returns (uint256 outAmount)
['321']
321: function exitBalancer(
322: BPTRedemption calldata balancerData,
323: ZapperData calldata zapData,
324: address[] calldata tokens,
325: SwapperLib.Swap[] calldata tokenSwaps,
326: address recipient
327: ) external nonReentrant returns (uint256 outAmount)
['374']
374: function redeemAndExitBalancer(
375: RedemptionData calldata redemptionData,
376: BPTRedemption calldata balancerData,
377: ZapperData calldata zapData,
378: address[] calldata tokens,
379: SwapperLib.Swap[] calldata tokenSwaps,
380: address recipient
381: ) external nonReentrant returns (uint256 outAmount)
['413']
413: function enterVelodrome(
414: address cToken,
415: ZapperData calldata zapData,
416: SwapperLib.Swap[] calldata tokenSwaps,
417: address router,
418: address factory,
419: address recipient
420: ) external payable nonReentrant returns (uint256 outAmount)
['455']
455: function exitVelodrome(
456: address router,
457: ZapperData calldata zapData,
458: SwapperLib.Swap[] calldata tokenSwaps,
459: address recipient
460: ) external nonReentrant returns (uint256 outAmount)
['492']
492: function redeemAndExitVelodrome(
493: RedemptionData calldata redemptionData,
494: address router,
495: ZapperData calldata zapData,
496: SwapperLib.Swap[] calldata tokenSwaps,
497: address recipient
498: ) external nonReentrant returns (uint256 outAmount)
['97']
97: function start(
98: uint256 startTimestamp,
99: uint256 softPriceInUSD,
100: uint256 cveAmountInLBP,
101: address paymentTokenAddress
102: ) external
['138']
138: function commit(uint256 amount) external
['160']
160: function commitFor(uint256 amount, address recipient) external
['178']
178: function claim() external returns (uint256 amount)
['207']
207: function withdrawFunds() external
['57']
57: function updateDaoAddress() external
['88']
88: function setReentrancyConfig(
89: uint256 coinsLength,
90: uint256 gasLimit
91: ) external
['214']
214: function addAsset(address asset, AdaptorData memory data) external
['343']
343: function raiseBounds(
344: address asset,
345: uint256 newLowerBound,
346: uint256 newUpperBound
347: ) external
['88']
88: function setReentrancyConfig(
89: uint256 coinsLength,
90: uint256 gasLimit
91: ) external
['214']
214: function addAsset(address asset, AdaptorData memory data) external
['343']
343: function raiseBounds(
344: address asset,
345: uint256 newLowerBound,
346: uint256 newUpperBound
347: ) external
['222']
222: function startMarket(address by) external nonReentrant returns (bool)
['250']
250: function transfer(
251: address to,
252: uint256 tokens
253: ) external nonReentrant returns (bool)
['263']
263: function transferFrom(
264: address from,
265: address to,
266: uint256 tokens
267: ) external nonReentrant returns (bool)
['276']
276: function borrow(uint256 amount) external nonReentrant
['298']
298: function borrowFor(
299: address account,
300: address recipient,
301: uint256 amount
302: ) external nonReentrant
['326']
326: function borrowForPositionFolding(
327: address account,
328: uint256 amount,
329: bytes calldata params
330: ) external nonReentrant
['361']
361: function repay(uint256 amount) external nonReentrant
['373']
373: function repayFor(address account, uint256 amount) external nonReentrant
['392']
392: function repayWithBadDebt(
393: address liquidator,
394: address account,
395: uint256 repayRatio
396: ) external nonReentrant
['442']
442: function liquidateExact(
443: address account,
444: uint256 amount,
445: IMToken collateralToken
446: ) external nonReentrant
['456']
456: function liquidate(
457: address account,
458: IMToken collateralToken
459: ) external nonReentrant
['472']
472: function redeem(uint256 tokens) external nonReentrant
['497']
497: function redeemFor(
498: address account,
499: address recipient,
500: uint256 tokens
501: ) external nonReentrant
['532']
532: function redeemUnderlyingForPositionFolding(
533: address account,
534: uint256 amount,
535: bytes calldata params
536: ) external nonReentrant
['569']
569: function mint(uint256 amount) external nonReentrant returns (bool)
['581']
581: function mintFor(
582: uint256 amount,
583: address recipient
584: ) external nonReentrant returns (bool)
['594']
594: function depositReserves(uint256 amount) external nonReentrant
['627']
627: function withdrawReserves(uint256 amount) external nonReentrant
['659']
659: function processWithdrawReserves() external
['696']
696: function approve(address spender, uint256 tokens) external returns (bool)
['711']
711: function rescueToken(address token, uint256 amount) external
['738']
738: function setInterestRateModel(address newInterestRateModel) external
['751']
751: function setInterestFactor(uint256 newInterestFactor) external
['764']
764: function balanceOfUnderlyingSafe(
765: address account
766: ) external returns (uint256)
['778']
778: function getSnapshot(
779: address account
780: ) external view returns (uint256, uint256, uint256)
['795']
795: function getSnapshotPacked(
796: address account
797: ) external view returns (AccountSnapshot memory)
['812']
812: function utilizationRate() external view returns (uint256)
['824']
824: function borrowRatePerYear() external view returns (uint256)
['837']
837: function predictedBorrowRatePerYear() external view returns (uint256)
['849']
849: function supplyRatePerYear() external view returns (uint256)
['863']
863: function totalBorrowsWithUpdateSafe()
864: external
865: nonReentrant
866: returns (uint256)
867:
['879']
879: function debtBalanceWithUpdateSafe(
880: address account
881: ) external nonReentrant returns (uint256)
['109']
109: function setDelegateApproval(
110: address delegate,
111: bool isApproved
112: ) external
['258']
258: function updateDynamicInterestRateModel(
259: uint256 baseRatePerYear,
260: uint256 vertexRatePerYear,
261: uint256 vertexUtilStart,
262: uint256 adjustmentRate,
263: uint256 adjustmentVelocity,
264: uint256 vertexMultiplierMax,
265: uint256 decayRate,
266: bool vertexReset
267: ) external
['290']
290: function getBorrowRateWithUpdate(
291: uint256 cash,
292: uint256 borrows,
293: uint256 reserves
294: ) external returns (uint256 borrowRate)
['347']
347: function getPredictedBorrowRatePerYear(
348: uint256 cash,
349: uint256 borrows,
350: uint256 reserves
351: ) external view returns (uint256)
['363']
363: function getBorrowRatePerYear(
364: uint256 cash,
365: uint256 borrows,
366: uint256 reserves
367: ) external view returns (uint256)
['380']
380: function getSupplyRatePerYear(
381: uint256 cash,
382: uint256 borrows,
383: uint256 reserves,
384: uint256 interestFee
385: ) external view returns (uint256)
['393']
393: function compoundRate() external pure returns (uint256)
['401']
401: function currentRatesData() external view returns (uint256, uint256)
['181']
181: function multiSwap(
182: bytes calldata data,
183: address[] calldata tokens
184: ) external nonReentrant
['260']
260: function executeOTC(
261: address tokenToOTC,
262: uint256 amountToOTC
263: ) external nonReentrant
['317']
317: function sendWormholeMessages(
318: uint256 dstChainId,
319: address toAddress
320: ) external
['371']
371: function receiveExecutableLockData(uint256 amount) external
['392']
392: function receiveCrossChainLockData(
393: EpochRolloverData memory data
394: ) external
['420']
420: function executeEpochFeeRouter(uint256 chainId) external
['491']
491: function migrateFeeAccumulator() external
['534']
534: function setEarmarked(address token, bool state) external
['542']
542: function notifyUpdatedMessagingHub() external
['568']
568: function addRewardTokens(address[] calldata newTokens) external
['592']
592: function removeRewardToken(address rewardTokenToRemove) external
['639']
639: function getRewardTokenBalances()
640: external
641: view
642: returns (uint256[] memory)
643:
['62']
62: function quoteWormholeFee(
63: uint256 dstChainId,
64: bool transferToken
65: ) external view returns (uint256)
['169']
169: function addAsset(address asset, address alteredToken) external
['267']
267: function setGMXReader(address newReader) external
['275']
275: function setGMXDataStore(address newDataStore) external
['206']
206: function afterDepositExecution(
207: bytes32 key,
208: IGMXDeposit.Props memory,
209: IGMXEventUtils.EventLogData memory eventData
210: ) external
['230']
230: function setGMXDepositVault(address newDepositVault) external
['238']
238: function setGMXExchangeRouter(address newExchangeRouter) external
['246']
246: function setGMXRouter(address newRouter) external
['275']
275: function setGMXDataStore(address newDataStore) external
['262']
262: function setGMXDepositHandler(address newDepositHandler) external
['62']
62: function gaugeWeight(
63: uint256 epoch,
64: address token
65: ) external view returns (uint256, uint256)
['126']
126: function massUpdatePools(address[] calldata tokens) external
['126']
126: function start(address marketManager_) external
['145']
145: function addExtraReward(address newReward) external
['168']
168: function removeExtraReward(uint256 index, address newReward) external
['193']
193: function getRewardTokensLength() external view returns (uint256)
['204']
204: function setRewardPerSec(
205: address token,
206: uint256 epoch,
207: address rewardToken,
208: uint256 newRewardPerSec
209: ) external
['318']
318: function pendingRewards(
319: address token,
320: address user
321: ) external view returns (uint256[] memory results)
['334']
334: function deposit(
335: address token,
336: address user,
337: uint256 amount
338: ) external nonReentrant
['401']
401: function withdraw(
402: address token,
403: address user,
404: uint256 amount
405: ) external nonReentrant
['436']
436: function claim(address token) external nonReentrant
['482']
482: function claimAndExtendLock(
483: address token,
484: uint256 lockIndex,
485: bool continuousLock,
486: RewardsData memory rewardsData,
487: bytes memory params,
488: uint256 aux
489: ) external nonReentrant
['547']
547: function claimAndLock(
548: address token,
549: bool continuousLock,
550: RewardsData memory rewardsData,
551: bytes memory params,
552: uint256 aux
553: ) external nonReentrant
['203']
203: function isListed(address mToken) external view returns (bool)
['212']
212: function assetsOf(
213: address account
214: ) external view returns (IMToken[] memory)
['221']
221: function tokenDataOf(
222: address account,
223: address mToken
224: ) external view returns (
225: bool hasPosition,
226: uint256 balanceOf,
227: uint256 collateralPostedOf
228: )
['241']
241: function statusOf(
242: address account
243: ) external view returns (uint256, uint256, uint256)
['252']
252: function solvencyOf(
253: address account
254: ) external view returns (uint256, uint256)
['264']
264: function flaggedForLiquidation(
265: address account
266: ) external view returns (bool)
['285']
285: function hypotheticalLiquidityOf(
286: address account,
287: address mTokenModified,
288: uint256 redeemTokens,
289: uint256 borrowAmount
290: ) external view returns (uint256, uint256)
['315']
315: function postCollateral(
316: address account,
317: address cToken,
318: uint256 tokens
319: ) external
['357']
357: function removeCollateral(
358: address cToken,
359: uint256 tokens
360: ) external
['402']
402: function reduceCollateralIfNecessary(
403: address account,
404: address cToken,
405: uint256 balance,
406: uint256 tokens
407: ) external
['415']
415: function canMint(address mToken) external view
['431']
431: function canRedeem(
432: address mToken,
433: address account,
434: uint256 amount
435: ) external view
['445']
445: function canRedeemWithPrune(
446: address mToken,
447: address account,
448: uint256 amount
449: ) external
['473']
473: function canRedeemWithCollateralRemoval(
474: address mToken,
475: address account,
476: uint256 balance,
477: uint256 amount,
478: bool forceRedeemCollateral
479: ) external
['506']
506: function canBorrow(
507: address dToken,
508: address account,
509: uint256 amount
510: ) external
['520']
520: function canBorrowWithPrune(
521: address dToken,
522: address account,
523: uint256 amount
524: ) external
['543']
543: function canBorrowWithNotify(
544: address dToken,
545: address account,
546: uint256 amount
547: ) external
['565']
565: function notifyBorrow(address mToken, address account) external
['577']
577: function canRepay(address mToken, address account) external view
['609']
609: function canLiquidate(
610: address dToken,
611: address cToken,
612: address account,
613: uint256 amount,
614: bool liquidateExact
615: ) external view returns (uint256, uint256, uint256)
['635']
635: function canLiquidateWithExecution(
636: address dToken,
637: address cToken,
638: address account,
639: uint256 amount,
640: bool liquidateExact
641: ) external returns (uint256, uint256, uint256)
['668']
668: function canSeize(
669: address collateralToken,
670: address debtToken
671: ) external view
['697']
697: function canTransfer(
698: address mToken,
699: address from,
700: uint256 amount
701: ) external view
['714']
714: function canTransferWithPrune(
715: address mToken,
716: address from,
717: uint256 amount
718: ) external
['743']
743: function liquidateAccount(address account) external
['878']
878: function listToken(address mToken) external
['927']
927: function updateCollateralToken(
928: IMToken mToken,
929: uint256 collRatio,
930: uint256 collReqSoft,
931: uint256 collReqHard,
932: uint256 liqIncSoft,
933: uint256 liqIncHard,
934: uint256 liqFee,
935: uint256 baseCFactor
936: ) external
['1086']
1086: function setCTokenCollateralCaps(
1087: address[] calldata mTokens,
1088: uint256[] calldata newCollateralCaps
1089: ) external
['1131']
1131: function setMintPaused(address mToken, bool state) external
['1147']
1147: function setBorrowPaused(address mToken, bool state) external
['1162']
1162: function setRedeemPaused(bool state) external
['1173']
1173: function setTransferPaused(bool state) external
['1184']
1184: function setSeizePaused(bool state) external
['1196']
1196: function setPositionFolding(address newPositionFolding) external
['711']
711: function rescueToken(address token, uint256 amount) external
['116']
116: function withdrawRemainingAirdropTokens() external
['136']
136: function setOptionsTerms(
137: uint256 timestampStart,
138: uint256 strikePrice
139: ) external
['70']
70: function depositOneBalanceFee() external nonReentrant
['94']
94: function receiveWormholeMessages(
95: bytes memory payload,
96: bytes[] memory ,
97: bytes32 ,
98: uint16 ,
99: bytes32 deliveryHash
100: ) external payable
['133']
133: function setOneBalanceAddress(address newGelatoOneBalance) external
['152']
152: function addAssetPriceFeed(address asset, address feed) external
['164']
164: function replaceAssetPriceFeed(
165: address asset,
166: address feedToRemove,
167: address feedToAdd
168: ) external
['185']
185: function removeAssetPriceFeed(address asset, address feed) external
['194']
194: function notifyFeedRemoval(address asset) external
['205']
205: function addMTokenSupport(address newMToken) external
['222']
222: function removeMTokenSupport(address mTokenToRemove) external
['235']
235: function addApprovedAdaptor(address adaptorToAdd) external
['251']
251: function replaceApprovedAdaptor(
252: address adaptorToRemove,
253: address adaptorToAdd
254: ) external
['280']
280: function removeApprovedAdaptor(address adaptorToRemove) external
['299']
299: function setDivergenceFlags(
300: uint256 maxCautionDivergence,
301: uint256 maxBadSourceDivergence
302: ) external
['328']
328: function setChainlinkDelay(uint256 delay) external
['350']
350: function getPricesForAsset(
351: address asset,
352: bool inUSD
353: ) external view returns (FeedData[] memory)
['403']
403: function isSupportedAsset(address asset) external view returns (bool)
['413']
413: function isSequencerValid() external view returns (bool)
['483']
483: function getPrices(
484: address[] calldata assets,
485: bool[] calldata inUSD,
486: bool[] calldata getLower
487: ) external view returns (uint256[] memory, uint256[] memory)
['52']
52: function getPricesForMarket(
53: address account,
54: IMToken[] calldata assets,
55: uint256 errorCodeBreakpoint
56: )
57: external
58: view
59: returns (AccountSnapshot[] memory, uint256[] memory, uint256)
60:
['134']
134: function reQueryRewardTokens() external
['163']
163: function reQueryUnderlyingTokens() external
['214']
214: function addAsset(address asset, AdaptorData memory data) external
['214']
214: function addAsset(address asset, AdaptorData memory data) external
['174']
174: function leverage(
175: LeverageStruct calldata leverageData,
176: uint256 slippage
177: ) external checkSlippage(msg.sender, slippage) nonReentrant
['194']
194: function leverageFor(
195: LeverageStruct calldata leverageData,
196: address account,
197: uint256 slippage
198: ) external checkSlippage(account, slippage) nonReentrant
['217']
217: function deleverage(
218: DeleverageStruct calldata deleverageData,
219: uint256 slippage
220: ) external checkSlippage(msg.sender, slippage) nonReentrant
['234']
234: function deleverageFor(
235: DeleverageStruct calldata deleverageData,
236: address account,
237: uint256 slippage
238: ) external checkSlippage(account, slippage) nonReentrant
['97']
97: function receiveWormholeMessages(
98: bytes memory payload,
99: bytes[] memory ,
100: bytes32 srcAddress,
101: uint16 srcChainId,
102: bytes32 deliveryHash
103: ) external payable
['289']
289: function sendFees(
290: uint256 dstChainId,
291: address to,
292: uint256 amount
293: ) external
['349']
349: function bridgeCVE(
350: uint256 dstChainId,
351: address recipient,
352: uint256 amount
353: ) external payable returns (uint64)
['375']
375: function bridgeVeCVELock(
376: uint256 dstChainId,
377: address recipient,
378: uint256 amount,
379: bool continuousLock
380: ) external payable returns (uint64)
['408']
408: function sendWormholeMessages(
409: uint256 dstChainId,
410: address toAddress,
411: bytes calldata payload
412: ) external payable returns (uint64)
['431']
431: function cveBridgeFee(
432: uint256 dstChainId
433: ) external view returns (uint256)
['441']
441: function flipMessagingHubStatus() external
['466']
466: function returnReimbursedFees() external
['481']
481: function withdrawNative(uint256 amount) external
['93']
93: function claimAndSwap(
94: SwapperLib.Swap memory swapperData,
95: address recipient
96: ) external nonReentrant returns (uint256 outAmount)
['150']
150: function claimZapAndDeposit(
151: SwapperLib.ZapperCall memory zapperCall,
152: address marketManager,
153: address cToken,
154: address recipient
155: ) external nonReentrant returns (uint256)
['214']
214: function claimSwapAndRepay(
215: SwapperLib.Swap memory swapperData,
216: address marketManager,
217: address dToken,
218: uint256 repayAmount,
219: address recipient
220: ) external nonReentrant returns (uint256)
['281']
281: function addAuthorizedMarketManager(address newMarketManager) external
['302']
302: function removeAuthorizedMarketManager(
303: address currentMarketManager
304: ) external
['319']
319: function addAuthorizedOutputToken(address outputToken) external
['336']
336: function removeAuthorizedOutputToken(address outputToken) external
['88']
88: function zapAndDeposit(
89: SwapperLib.ZapperCall memory zapperCall,
90: address cToken,
91: address recipient
92: ) external payable nonReentrant returns (uint256)
['133']
133: function swapAndRepay(
134: SwapperLib.Swap memory swapperData,
135: address dToken,
136: uint256 repayAmount,
137: address recipient
138: ) external payable nonReentrant returns (uint256)
['183']
183: function redeemAndSwap(
184: RedemptionData calldata redemptionData,
185: SwapperLib.Swap memory swapperData,
186: address recipient
187: ) external nonReentrant returns (uint256)
['140']
140: function setRewardRouter(address newRouter) external
['214']
214: function addAsset(address asset, AdaptorData memory data) external
['220']
220: function queryUserLocks(
221: address user
222: ) external view returns (uint256[] memory, uint256[] memory)
['711']
711: function rescueToken(address token, uint256 amount) external
['269']
269: function shutdown() external
['285']
285: function createLock(
286: uint256 amount,
287: bool continuousLock,
288: RewardsData calldata rewardsData,
289: bytes calldata params,
290: uint256 aux
291: ) external nonReentrant
['317']
317: function createLockFor(
318: address recipient,
319: uint256 amount,
320: bool continuousLock,
321: RewardsData calldata rewardsData,
322: bytes calldata params,
323: uint256 aux
324: ) external nonReentrant
['356']
356: function extendLock(
357: uint256 lockIndex,
358: bool continuousLock,
359: RewardsData calldata rewardsData,
360: bytes calldata params,
361: uint256 aux
362: ) external nonReentrant
['422']
422: function increaseAmountAndExtendLock(
423: uint256 amount,
424: uint256 lockIndex,
425: bool continuousLock,
426: RewardsData calldata rewardsData,
427: bytes calldata params,
428: uint256 aux
429: ) external nonReentrant
['460']
460: function increaseAmountAndExtendLockFor(
461: address recipient,
462: uint256 amount,
463: uint256 lockIndex,
464: bool continuousLock,
465: RewardsData calldata rewardsData,
466: bytes calldata params,
467: uint256 aux
468: ) external nonReentrant
['502']
502: function disableContinuousLock(
503: uint256 lockIndex,
504: RewardsData calldata rewardsData,
505: bytes calldata params,
506: uint256 aux
507: ) external nonReentrant
['540']
540: function combineAllLocks(
541: bool continuousLock,
542: RewardsData calldata rewardsData,
543: bytes calldata params,
544: uint256 aux
545: ) external nonReentrant
['666']
666: function processExpiredLock(
667: uint256 lockIndex,
668: bool relock,
669: bool continuousLock,
670: RewardsData calldata rewardsData,
671: bytes calldata params,
672: uint256 aux
673: ) external nonReentrant
['759']
759: function bridgeVeCVELock(
760: uint256 lockIndex,
761: uint256 dstChainId,
762: bool continuousLock,
763: RewardsData calldata rewardsData,
764: bytes calldata params,
765: uint256 aux
766: ) external payable nonReentrant returns (uint64 sequence)
['821']
821: function earlyExpireLock(
822: uint256 lockIndex,
823: RewardsData calldata rewardsData,
824: bytes calldata params,
825: uint256 aux
826: ) external nonReentrant
['901']
901: function updateUserPoints(address user, uint256 epoch) external
['920']
920: function getVotes(address user) external view returns (uint256)
['950']
950: function getVotesForEpoch(
951: address user,
952: uint256 epoch
953: ) external view returns (uint256)
['105']
105: function underlyingAssetAggregator()
106: public
107: view
108: virtual
109: returns (address)
110:
['115']
115: function getWrappedAssetWeight() public view virtual returns (uint256)
['18']
18: function stringToBytes32(
19: string memory stringData
20: ) public pure returns (bytes32 result)
['417']
417: function redeemFor(
418: uint256 shares,
419: address receiver,
420: address owner
421: ) public nonReentrant returns (uint256 assets)
['932']
932: function isCToken() public pure returns (bool)
['563']
563: function supportsInterface(
564: bytes4 interfaceId
565: ) public pure virtual returns (bool)
['574']
574: function totalAssetsSafe()
575: public
576: view
577: virtual
578: nonReadReentrant
579: returns (uint256)
580:
['597']
597: function convertToSharesSafe(
598: uint256 assets
599: ) public view nonReadReentrant returns (uint256)
['621']
621: function convertToAssetsSafe(
622: uint256 shares
623: ) public view nonReadReentrant returns (uint256)
['248']
248: function rewardRate() public view returns (uint256)
['255']
255: function vestingPeriodEnd() public view returns (uint256)
['263']
263: function lastVestClaim() public view returns (uint256)
['376']
376: function epochsToClaim(address user) public view returns (uint256)
['1141']
1141: function addMarketManager(
1142: address newMarketManager,
1143: uint256 marketInterestFactor
1144: ) public virtual
['1186']
1186: function removeMarketManager(
1187: address currentMarketManager
1188: ) public virtual
['140']
140: function reQueryRewardTokens() public
['140']
140: function reQueryRewardTokens() public
['232']
232: function softCap() public view returns (uint256)
['237']
237: function priceAt(
238: uint256 amount
239: ) public view returns (uint256 price)
['254']
254: function currentPrice() public view returns (uint256)
['259']
259: function currentStatus() public view returns (SaleStatus)
['52']
52: function isLocked(
53: address curvePool,
54: uint256 coinsLength
55: ) public view returns (bool)
['894']
894: function debtBalanceCached(address account) public view returns (uint256)
['917']
917: function decimals() public view returns (uint8)
['925']
925: function marketUnderlyingHeld() public view returns (uint256)
['932']
932: function isCToken() public pure returns (bool)
['939']
939: function exchangeRateWithUpdateSafe()
940: public
941: nonReentrant
942: returns (uint256)
943:
['952']
952: function exchangeRateCached() public view returns (uint256)
['977']
977: function accrueInterest() public
['67']
67: function isDelegate(
68: address user,
69: address delegate
70: ) public view returns (bool)
['82']
82: function getUserApprovalIndex(
83: address user
84: ) public view returns (uint256)
['93']
93: function hasDelegatingDisabled(
94: address user
95: ) public view returns (bool)
['137']
137: function _checkIsDelegate(
138: address user,
139: address delegate
140: ) public view returns (bool)
['417']
417: function utilizationRate(
418: uint256 cash,
419: uint256 borrows,
420: uint256 reserves
421: ) public pure returns (uint256)
['436']
436: function getPredictedBorrowRate(
437: uint256 cash,
438: uint256 borrows,
439: uint256 reserves
440: ) public view returns (uint256)
['467']
467: function getBorrowRate(
468: uint256 cash,
469: uint256 borrows,
470: uint256 reserves
471: ) public view returns (uint256)
['496']
496: function getSupplyRate(
497: uint256 cash,
498: uint256 borrows,
499: uint256 reserves,
500: uint256 interestFee
501: ) public view returns (uint256)
['512']
512: function vertexMultiplier() public view returns (uint256)
['518']
518: function updateTimestamp() public view returns (uint256)
['152']
152: function totalAssets() public view virtual returns (uint256 assets)
['167']
167: function convertToShares(uint256 assets) public view virtual returns (uint256 shares)
['192']
192: function convertToAssets(uint256 shares) public view virtual returns (uint256 assets)
['220']
220: function previewDeposit(uint256 assets) public view virtual returns (uint256 shares)
['238']
238: function previewMint(uint256 shares) public view virtual returns (uint256 assets)
['266']
266: function previewWithdraw(uint256 assets) public view virtual returns (uint256 shares)
['294']
294: function previewRedeem(uint256 shares) public view virtual returns (uint256 assets)
['326']
326: function maxDeposit(address to) public view virtual returns (uint256 maxAssets)
['337']
337: function maxMint(address to) public view virtual returns (uint256 maxShares)
['347']
347: function maxWithdraw(address owner) public view virtual returns (uint256 maxAssets)
['357']
357: function maxRedeem(address owner) public view virtual returns (uint256 maxShares)
['376']
376: function deposit(uint256 assets, address to) public virtual returns (uint256 shares)
['393']
393: function mint(uint256 shares, address to) public virtual returns (uint256 assets)
['409']
409: function withdraw(uint256 assets, address to, address owner)
410: public
411: virtual
412: returns (uint256 shares)
413:
['429']
429: function redeem(uint256 shares, address to, address owner)
430: public
431: virtual
432: returns (uint256 assets)
433:
['665']
665: function getOracleRouter() public view returns (IOracleRouter)
['672']
672: function vaultCompoundFee() public view returns (uint256)
['678']
678: function vaultYieldFee() public view returns (uint256)
['139']
139: function currentEpoch() public view returns (uint256)
['145']
145: function epochOfTimestamp(
146: uint256 timestamp
147: ) public view returns (uint256)
['154']
154: function epochStartTime(uint256 epoch) public view returns (uint256)
['161']
161: function epochEndTime(uint256 epoch) public view returns (uint256)
['169']
169: function isGaugeEnabled(
170: uint256 epoch,
171: address token
172: ) public view returns (bool)
['196']
196: function updatePool(address token) public virtual
['247']
247: function rewardAllocation(
248: address token,
249: uint256 epoch,
250: address rewardToken
251: ) public view returns (uint256)
['263']
263: function pendingRewards(
264: address token,
265: address user,
266: address rewardToken
267: ) public view returns (uint256)
['453']
453: function LiquidationStatusOf(
454: address account,
455: address debtToken,
456: address collateralToken
457: )
458: public view
459: returns (
460: uint256 lfactor,
461: uint256 debtTokenPrice,
462: uint256 collateralTokenPrice
463: )
464:
['202']
202: function optionsExercisable() public view returns (bool)
['210']
210: function exerciseOption(uint256 amount) public payable
['435']
435: function getPrice(
436: address asset,
437: bool inUSD,
438: bool getLower
439: ) public view returns (uint256 price, uint256 errorCode)
['160']
160: function getProtocolLeverageFee() public view returns (uint256)
['539']
539: function queryAmountToBorrowForLeverageMax(
540: address account,
541: address borrowToken
542: ) public view returns (uint256)
['994']
994: function currentEpoch(uint256 time) public view returns (uint256)
['1005']
1005: function nextEpochStartTime() public view returns (uint256)
['1014']
1014: function freshLockEpoch() public view returns (uint256)
['1021']
1021: function freshLockTimestamp() public view returns (uint40)
['1040']
1040: function getVotesForSingleLockForTime(
1041: address user,
1042: uint256 lockIndex,
1043: uint256 time,
1044: uint256 currentLockBoost
1045: ) public view returns (uint256)
['1072']
1072: function getUnlockPenalty(
1073: address user,
1074: uint256 lockIndex
1075: ) public view returns (uint256)
Consider using abi.encode as this pads data to 32 byte segments
Num of instances: 1
Click to show findings
['179']
174:
175: return
176: verify(
177: proof,
178: merkleRoot,
179: keccak256(abi.encodePacked(user, amount)) // <= FOUND
180: );
To maintain readability in code, particularly in Solidity which can involve complex mathematical operations, it is often recommended to limit the number of arithmetic operations to a maximum of 2-3 per line. Too many operations in a single line can make the code difficult to read and understand, increase the likelihood of mistakes, and complicate the process of debugging and reviewing the code. Consider splitting such operations over more than one line, take special care when dealing with division however. Try to limit the number of arithmetic operations to a maximum of 3 per line.
Num of instances: 14
Click to show findings
['237']
236: return
237: ((((1e18) * sqrtReserve) / sqrtPrice) * price0 * 2) / totalSupply; // <= FOUND
['472']
472: rewards += _calculateRewardsForEpoch(user, startEpoch + i++); // <= FOUND
['157']
156:
157: uint256 price = (out * WAD * (10 ** data.quoteTokenDecimals)) / // <= FOUND
158: sample /
159: (10 ** data.baseTokenDecimals);
['962']
957:
958:
959:
960:
961: return
962: ((marketUnderlyingHeld() + totalBorrows - totalReserves) * WAD) / // <= FOUND
963: totalSupply;
['428']
427:
428: return (borrows * WAD) / (cash + borrows - reserves); // <= FOUND
['837']
833:
834:
835:
836:
837: uint256 cFactor = ((current - start) * WAD) / (end - start); // <= FOUND
['881']
878:
879:
880:
881: uint256 cFactor = ((start - current) * WAD) / (start - end); // <= FOUND
['833']
824:
825:
826:
827:
828:
829:
830:
831:
832: feeTokenBalanceForChain =
833: (((feeTokenBalance * WAD) / totalLockedTokens) * lockedTokens) / // <= FOUND
834: WAD;
['1064']
1060:
1061:
1062:
1063: return
1064: (lock.amount * ((lock.unlockTime - time) / EPOCH_DURATION)) / // <= FOUND
1065: LOCK_DURATION_EPOCHS;
['1421']
1416:
1417:
1418:
1419: return
1420: (amount *
1421: ((penalty * (LOCK_DURATION - (unlockTime - block.timestamp))) / // <= FOUND
1422: LOCK_DURATION)) / WAD;
['240']
240: a = (((amount0 * 10000) / (10000 - swapFee)) * 1e18) / decimals0; // <= FOUND
['246']
246: uint256 p = (y * (((x2 * 3 + y2) * 1e18) / (y2 * 3 + x2))) / x; // <= FOUND
['249']
249: uint256 den = ((a + x) * p) / 1e18 + y; // <= FOUND
['258']
258: uint256 b = amount0 * 10000 * reserve0 * 4 * swapFeeFactor; // <= FOUND
Placing the closing and opening brackets of distinct code blocks on the same line can impair code readability and clarity, leading to potential misinterpretations. To improve maintainability and reduce the chances of introducing errors, it is advisable to start each code block on a new line, making the boundaries between different code sections clearer and easier to discern unless it is an else statement.
Num of instances: 2
In smart contract development, especially within Ethereum, gas optimization is crucial. Utilizing constants directly, instead of assigning them to a variable (caching) before use, can save gas as reading from a constant is cheaper than reading from storage or a variable. Constants in Solidity are replaced by their actual value in the EVM bytecode, eliminating the need for a SLOAD operation, which costs more gas. Hence, if a value will not change throughout the contract's life, defining it as a constant and using it directly in expressions/functions can be a gas-efficient practice.
Num of instances: 1
[NonCritical-10] State variables which are not modified within functions should be set as constants or immutable for values set at deployment
Set state variables listed below as constant or immutable for values set at deployment. Ensure it is safe to do so
Num of instances: 18
Click to show findings
['47']
47: uint256 public paymentTokenPrice; // <= FOUND
['49']
49: uint256 public saleDecimalAdjustment; // <= FOUND
['79']
79: string public name; // <= FOUND
['81']
81: string public symbol; // <= FOUND
['104']
104: internal _epochRewardPerSec; // <= FOUND
['24']
24: address public polygonOneBalanceFeeManager; // <= FOUND
['11']
11: address public sDai; // <= FOUND
['12']
12: address public dai; // <= FOUND
['13']
13: address public daiAggregator; // <= FOUND
['11']
11: address public sFrax; // <= FOUND
['12']
12: address public frax; // <= FOUND
['13']
13: address public fraxAggregator; // <= FOUND
['11']
11: address public wstETH; // <= FOUND
['12']
12: address public stETH; // <= FOUND
['13']
13: address public stETHAggregator; // <= FOUND
['84']
84: string internal _name; // <= FOUND
['86']
86: string internal _symbol; // <= FOUND
['26']
26: internal _isDelegate; // <= FOUND
When making external calls, the called contract can intentionally or unintentionally consume all provided gas, leading to unintended transaction reversion. To mitigate this risk, it's crucial to specify a gas limit when making the call. By using addr.call{gas: <amount>}("")
, you allocate a specific amount of gas to the external call, ensuring the parent transaction has gas left for post-call operations. This approach safeguards against malevolent contracts aiming to exhaust gas and provides greater control over transaction execution.
Num of instances: 1
In instances where withdrawals/redeems are paused, the maxWithdraw/maxRedeem functions should return 0 as stated in the spec.
Num of instances: 2
Click to show findings
['347']
347: function maxWithdraw(address owner) public view virtual returns (uint256 maxAssets) { // <= FOUND
348: maxAssets = convertToAssets(balanceOf(owner));
349: }
['357']
357: function maxRedeem(address owner) public view virtual returns (uint256 maxShares) { // <= FOUND
358: maxShares = balanceOf(owner);
359: }
Emits are designed to make users aware of state variable changes. As such the event declaration should be clear on what it will output, by passing in function calls this can affect the readability of a emit declaration. As such it is advisable to make function calls outside of the event emit and pass the return value into the emit instead.
Num of instances: 133
Click to show findings
['129']
129: function harvest(
130: bytes calldata data
131: ) external override returns (uint256 yield) {
132:
133: _canCompound();
134:
135:
136: _vestIfNeeded();
137:
138:
139: if (_checkVestStatus(_vaultData)) {
140: _updateVestingPeriodIfNeeded();
141:
142:
143: StrategyData memory sd = strategyData;
144:
145:
146: sd.gauge.getReward(address(this));
147:
148: {
149: uint256 rewardAmount = rewardToken.balanceOf(address(this));
150:
151:
152: if (rewardAmount > 0) {
153:
154:
155: uint256 protocolFee = FixedPointMathLib.mulDiv(
156: rewardAmount,
157: centralRegistry.protocolHarvestFee(),
158: 1e18
159: );
160: rewardAmount -= protocolFee;
161: SafeTransferLib.safeTransfer(
162: address(rewardToken),
163: centralRegistry.feeAccumulator(),
164: protocolFee
165: );
166:
167:
168: if (!rewardTokenIsUnderlying) {
169: SwapperLib.Swap memory swapData = abi.decode(
170: data,
171: (SwapperLib.Swap)
172: );
173:
174: if (!centralRegistry.isSwapper(swapData.target)) {
175: revert AerodromeStableCToken__InvalidSwapper(
176: swapData.target
177: );
178: }
179:
180: SwapperLib.swap(centralRegistry, swapData);
181: }
182: }
183: }
184:
185: uint256 totalAmountA = IERC20(sd.token0).balanceOf(address(this));
186:
187:
188: if (totalAmountA == 0) {
189: revert AerodromeStableCToken__SlippageError();
190: }
191:
192:
193: address _asset = asset();
194:
195:
196: (uint256 r0, uint256 r1, ) = IVeloPair(_asset).getReserves();
197: (uint256 reserveA, uint256 reserveB) = sd.token0 ==
198: IVeloPair(_asset).token0()
199: ? (r0, r1)
200: : (r1, r0);
201:
202:
203: uint256 swapAmount = VelodromeLib._optimalDeposit(
204: address(sd.pairFactory),
205: _asset,
206: totalAmountA,
207: reserveA,
208: reserveB,
209: sd.decimalsA,
210: sd.decimalsB,
211: true
212: );
213:
214: VelodromeLib._swapExactTokensForTokens(
215: address(sd.router),
216: _asset,
217: sd.token0,
218: sd.token1,
219: swapAmount,
220: true
221: );
222: totalAmountA -= swapAmount;
223:
224:
225: yield = VelodromeLib._addLiquidity(
226: address(sd.router),
227: sd.token0,
228: sd.token1,
229: true,
230: totalAmountA,
231: IERC20(sd.token1).balanceOf(address(this)),
232: VelodromeLib.VELODROME_ADD_LIQUIDITY_SLIPPAGE
233: );
234:
235:
236:
237: _afterDeposit(yield, 0);
238:
239:
240: _setNewVaultData(yield, vestPeriod);
241:
242: emit Harvest(yield);
243: }
244: }
['124']
124: function harvest(
125: bytes calldata data
126: ) external override returns (uint256 yield) {
127:
128: _canCompound();
129:
130:
131: _vestIfNeeded();
132:
133:
134: if (_checkVestStatus(_vaultData)) {
135: _updateVestingPeriodIfNeeded();
136:
137:
138: StrategyData memory sd = strategyData;
139:
140:
141: sd.gauge.getReward(address(this));
142:
143: {
144: uint256 rewardAmount = rewardToken.balanceOf(address(this));
145:
146: if (rewardAmount > 0) {
147:
148:
149: uint256 protocolFee = FixedPointMathLib.mulDiv(
150: rewardAmount,
151: centralRegistry.protocolHarvestFee(),
152: 1e18
153: );
154: rewardAmount -= protocolFee;
155: SafeTransferLib.safeTransfer(
156: address(rewardToken),
157: centralRegistry.feeAccumulator(),
158: protocolFee
159: );
160:
161:
162: if (!rewardTokenIsUnderlying) {
163: SwapperLib.Swap memory swapData = abi.decode(
164: data,
165: (SwapperLib.Swap)
166: );
167:
168: if (!centralRegistry.isSwapper(swapData.target)) {
169: revert AerodromeVolatileCToken__InvalidSwapper(
170: swapData.target
171: );
172: }
173:
174: SwapperLib.swap(centralRegistry, swapData);
175: }
176: }
177: }
178:
179: uint256 totalAmountA = IERC20(sd.token0).balanceOf(address(this));
180:
181: if (totalAmountA == 0) {
182: revert AerodromeVolatileCToken__SlippageError();
183: }
184:
185:
186: address _asset = asset();
187:
188:
189: (uint256 r0, uint256 r1, ) = IVeloPair(_asset).getReserves();
190: uint256 reserveA = sd.token0 == IVeloPair(_asset).token0()
191: ? r0
192: : r1;
193:
194:
195:
196:
197: uint256 swapAmount = VelodromeLib._optimalDeposit(
198: address(sd.pairFactory),
199: _asset,
200: totalAmountA,
201: reserveA,
202: 0,
203: 0,
204: 0,
205: false
206: );
207:
208: VelodromeLib._swapExactTokensForTokens(
209: address(sd.router),
210: _asset,
211: sd.token0,
212: sd.token1,
213: swapAmount,
214: false
215: );
216: totalAmountA -= swapAmount;
217:
218:
219: yield = VelodromeLib._addLiquidity(
220: address(sd.router),
221: sd.token0,
222: sd.token1,
223: false,
224: totalAmountA,
225: IERC20(sd.token1).balanceOf(address(this)),
226: VelodromeLib.VELODROME_ADD_LIQUIDITY_SLIPPAGE
227: );
228:
229:
230:
231: _afterDeposit(yield, 0);
232:
233:
234: _setNewVaultData(yield, vestPeriod);
235:
236: emit Harvest(yield);
237: }
238:
239: }
['212']
212: function harvest(
213: bytes calldata data
214: ) external override returns (uint256 yield) {
215:
216: _canCompound();
217:
218:
219: _vestIfNeeded();
220:
221:
222: if (_checkVestStatus(_vaultData)) {
223: _updateVestingPeriodIfNeeded();
224:
225:
226: StrategyData memory sd = strategyData;
227:
228:
229: sd.rewarder.getReward(address(this), true);
230:
231: (SwapperLib.Swap[] memory swapDataArray, uint256 minLPAmount) = abi
232: .decode(data, (SwapperLib.Swap[], uint256));
233:
234: {
235:
236: uint256 numRewardTokens = sd.rewardTokens.length;
237: address rewardToken;
238: uint256 rewardAmount;
239: uint256 protocolFee;
240:
241:
242: address feeAccumulator = centralRegistry.feeAccumulator();
243: uint256 harvestFee = centralRegistry.protocolHarvestFee();
244:
245: for (uint256 i; i < numRewardTokens; ++i) {
246: rewardToken = sd.rewardTokens[i];
247: rewardAmount = IERC20(rewardToken).balanceOf(
248: address(this)
249: );
250:
251:
252:
253: if (rewardAmount == 0) {
254: continue;
255: }
256:
257:
258:
259: protocolFee = FixedPointMathLib.mulDiv(
260: rewardAmount,
261: harvestFee,
262: 1e18
263: );
264: rewardAmount -= protocolFee;
265: SafeTransferLib.safeTransfer(
266: rewardToken,
267: feeAccumulator,
268: protocolFee
269: );
270:
271:
272: if (!isUnderlyingToken[rewardToken]) {
273: if (
274: !centralRegistry.isSwapper(swapDataArray[i].target)
275: ) {
276: revert AuraCToken__InvalidSwapper(
277: i,
278: swapDataArray[i].target
279: );
280: }
281:
282: SwapperLib.swap(centralRegistry, swapDataArray[i]);
283: }
284: }
285: }
286:
287:
288: {
289:
290: uint256 numUnderlyingTokens = sd.underlyingTokens.length;
291: address[] memory assets = new address[](numUnderlyingTokens);
292: uint256[] memory maxAmountsIn = new uint256[](
293: numUnderlyingTokens
294: );
295: address underlyingToken;
296:
297: for (uint256 i; i < numUnderlyingTokens; ++i) {
298: underlyingToken = sd.underlyingTokens[i];
299: assets[i] = underlyingToken;
300: maxAmountsIn[i] = IERC20(underlyingToken).balanceOf(
301: address(this)
302: );
303:
304: SwapperLib._approveTokenIfNeeded(
305: underlyingToken,
306: address(sd.balancerVault),
307: maxAmountsIn[i]
308: );
309: }
310:
311:
312: sd.balancerVault.joinPool(
313: sd.balancerPoolId,
314: address(this),
315: address(this),
316: IBalancerVault.JoinPoolRequest(
317: assets,
318: maxAmountsIn,
319: abi.encode(
320: IBalancerVault
321: .JoinKind
322: .EXACT_TOKENS_IN_FOR_BPT_OUT,
323: maxAmountsIn,
324: minLPAmount
325: ),
326: false
327: )
328: );
329: }
330:
331:
332: yield = IERC20(asset()).balanceOf(address(this));
333: _afterDeposit(yield, 0);
334:
335:
336: _setNewVaultData(yield, vestPeriod);
337:
338: emit Harvest(yield);
339: }
340: }
['177']
177: function harvest(
178: bytes calldata data
179: ) external override returns (uint256 yield) {
180:
181: _canCompound();
182:
183:
184: _vestIfNeeded();
185:
186:
187: if (_checkVestStatus(_vaultData)) {
188: _updateVestingPeriodIfNeeded();
189:
190:
191: StrategyData memory sd = strategyData;
192:
193:
194: sd.rewarder.getReward(address(this), true);
195:
196: (SwapperLib.Swap[] memory swapDataArray, uint256 minLPAmount) = abi
197: .decode(data, (SwapperLib.Swap[], uint256));
198:
199: uint256 numRewardTokens = sd.rewardTokens.length;
200: address rewardToken;
201: uint256 rewardAmount;
202: uint256 protocolFee;
203:
204: {
205:
206:
207: address feeAccumulator = centralRegistry.feeAccumulator();
208: uint256 harvestFee = centralRegistry.protocolHarvestFee();
209:
210: for (uint256 i; i < numRewardTokens; ++i) {
211: rewardToken = sd.rewardTokens[i];
212: rewardAmount = IERC20(rewardToken).balanceOf(
213: address(this)
214: );
215:
216:
217:
218: if (rewardAmount == 0) {
219: continue;
220: }
221:
222:
223:
224: protocolFee = FixedPointMathLib.mulDiv(
225: rewardAmount,
226: harvestFee,
227: 1e18
228: );
229: rewardAmount -= protocolFee;
230: SafeTransferLib.safeTransfer(
231: address(rewardToken),
232: feeAccumulator,
233: protocolFee
234: );
235: }
236: }
237:
238:
239: {
240: uint256 numSwapData = swapDataArray.length;
241: for (uint256 i; i < numSwapData; ++i) {
242: if (!centralRegistry.isSwapper(swapDataArray[i].target)) {
243: revert Convex2PoolCToken__InvalidSwapper(
244: i,
245: swapDataArray[i].target
246: );
247: }
248: SwapperLib.swap(centralRegistry, swapDataArray[i]);
249: }
250: }
251:
252:
253: _addLiquidityToCurve(minLPAmount);
254:
255:
256: yield = IERC20(asset()).balanceOf(address(this));
257: if (yield == 0) {
258: revert Convex2PoolCToken__NoYield();
259: }
260: _afterDeposit(yield, 0);
261:
262:
263: _setNewVaultData(yield, vestPeriod);
264:
265: emit Harvest(yield);
266: }
267: }
['177']
177: function harvest(
178: bytes calldata data
179: ) external override returns (uint256 yield) {
180:
181: _canCompound();
182:
183:
184: _vestIfNeeded();
185:
186:
187: if (_checkVestStatus(_vaultData)) {
188: _updateVestingPeriodIfNeeded();
189:
190:
191: StrategyData memory sd = strategyData;
192:
193:
194: sd.rewarder.getReward(address(this), true);
195:
196: (SwapperLib.Swap[] memory swapDataArray, uint256 minLPAmount) = abi
197: .decode(data, (SwapperLib.Swap[], uint256));
198:
199: uint256 numRewardTokens = sd.rewardTokens.length;
200: address rewardToken;
201: uint256 rewardAmount;
202: uint256 protocolFee;
203:
204: {
205:
206:
207: address feeAccumulator = centralRegistry.feeAccumulator();
208: uint256 harvestFee = centralRegistry.protocolHarvestFee();
209:
210: for (uint256 i; i < numRewardTokens; ++i) {
211: rewardToken = sd.rewardTokens[i];
212: rewardAmount = IERC20(rewardToken).balanceOf(
213: address(this)
214: );
215:
216:
217:
218: if (rewardAmount == 0) {
219: continue;
220: }
221:
222:
223:
224: protocolFee = FixedPointMathLib.mulDiv(
225: rewardAmount,
226: harvestFee,
227: 1e18
228: );
229: rewardAmount -= protocolFee;
230: SafeTransferLib.safeTransfer(
231: address(rewardToken),
232: feeAccumulator,
233: protocolFee
234: );
235: }
236: }
237:
238:
239: {
240: uint256 numSwapData = swapDataArray.length;
241: for (uint256 i; i < numSwapData; ++i) {
242: if (!centralRegistry.isSwapper(swapDataArray[i].target)) {
243: revert Convex3PoolCToken__InvalidSwapper(
244: i,
245: swapDataArray[i].target
246: );
247: }
248: SwapperLib.swap(centralRegistry, swapDataArray[i]);
249: }
250: }
251:
252:
253: _addLiquidityToCurve(minLPAmount);
254:
255:
256: yield = IERC20(asset()).balanceOf(address(this));
257: if (yield == 0) {
258: revert Convex3PoolCToken__NoYield();
259: }
260: _afterDeposit(yield, 0);
261:
262:
263: _setNewVaultData(yield, vestPeriod);
264:
265: emit Harvest(yield);
266: }
267: }
['147']
147: function harvest(
148: bytes calldata data
149: ) external override returns (uint256 yield) {
150:
151: _canCompound();
152:
153:
154: _vestIfNeeded();
155:
156:
157: if (_checkVestStatus(_vaultData)) {
158: _updateVestingPeriodIfNeeded();
159:
160:
161: StrategyData memory sd = strategyData;
162:
163:
164: sd.lp.redeemRewards(address(this));
165:
166: (
167: SwapperLib.Swap[] memory swapDataArray,
168: uint256 minLPAmount,
169: ApproxParams memory approx,
170: LimitOrderData memory limit
171: ) = abi.decode(data, (SwapperLib.Swap[], uint256, ApproxParams, LimitOrderData));
172:
173: {
174:
175: uint256 numRewardTokens = sd.rewardTokens.length;
176: address rewardToken;
177: uint256 rewardAmount;
178: uint256 protocolFee;
179:
180:
181: address feeAccumulator = centralRegistry.feeAccumulator();
182: uint256 harvestFee = centralRegistry.protocolHarvestFee();
183:
184: for (uint256 i; i < numRewardTokens; ++i) {
185: rewardToken = sd.rewardTokens[i];
186: rewardAmount = IERC20(rewardToken).balanceOf(
187: address(this)
188: );
189:
190:
191:
192: if (rewardAmount == 0) {
193: continue;
194: }
195:
196:
197:
198: protocolFee = FixedPointMathLib.mulDiv(
199: rewardAmount,
200: harvestFee,
201: 1e18
202: );
203: rewardAmount -= protocolFee;
204: SafeTransferLib.safeTransfer(
205: rewardToken,
206: feeAccumulator,
207: protocolFee
208: );
209:
210:
211: if (!isUnderlyingToken[rewardToken]) {
212: if (
213: !centralRegistry.isSwapper(swapDataArray[i].target)
214: ) {
215: revert PendleLPCToken__InvalidSwapper(
216: i,
217: swapDataArray[i].target
218: );
219: }
220:
221: SwapperLib.swap(centralRegistry, swapDataArray[i]);
222: }
223: }
224: }
225:
226:
227: {
228: uint256 numUnderlyingTokens = sd.underlyingTokens.length;
229: address underlyingToken;
230: uint256 balance;
231: for (uint256 i; i < numUnderlyingTokens; ++i) {
232: underlyingToken = sd.underlyingTokens[i];
233:
234: if (underlyingToken == address(0)) {
235: balance = address(this).balance;
236: if (balance > 0) {
237:
238: sd.sy.deposit{ value: balance }(
239: address(this),
240: underlyingToken,
241: balance,
242: 0
243: );
244: }
245: } else {
246: balance = IERC20(underlyingToken).balanceOf(
247: address(this)
248: );
249: if (balance > 0) {
250: SwapperLib._approveTokenIfNeeded(
251: underlyingToken,
252: address(sd.sy),
253: balance
254: );
255:
256: sd.sy.deposit(
257: address(this),
258: underlyingToken,
259: balance,
260: 0
261: );
262: }
263: }
264: }
265: }
266:
267: {
268: uint256 balance = sd.sy.balanceOf(address(this));
269: SwapperLib._approveTokenIfNeeded(
270: address(sd.sy),
271: address(sd.router),
272: balance
273: );
274:
275:
276: (yield, ) = sd.router.addLiquiditySingleSy(
277: address(this),
278: address(sd.lp),
279: balance,
280: minLPAmount,
281: approx,
282: limit
283: );
284: }
285:
286:
287: _setNewVaultData(yield, vestPeriod);
288:
289: emit Harvest(yield);
290: }
291: }
['70']
70: function harvest(
71: bytes calldata data
72: ) external override returns (uint256 yield) {
73:
74: _canCompound();
75:
76:
77: _vestIfNeeded();
78:
79:
80: if (_checkVestStatus(_vaultData)) {
81: _updateVestingPeriodIfNeeded();
82:
83:
84: rewardRouter.handleRewards(
85: true,
86: true,
87: true,
88: true,
89: true,
90: true,
91: false
92: );
93: uint256 rewardAmount = WETH.balanceOf(address(this));
94:
95:
96: if (rewardAmount > 0) {
97:
98:
99: uint256 protocolFee = FixedPointMathLib.mulDiv(
100: rewardAmount,
101: centralRegistry.protocolHarvestFee(),
102: 1e18
103: );
104: rewardAmount -= protocolFee;
105: SafeTransferLib.safeTransfer(
106: address(WETH),
107: centralRegistry.feeAccumulator(),
108: protocolFee
109: );
110:
111: SwapperLib.Swap memory swapData = abi.decode(
112: data,
113: (SwapperLib.Swap)
114: );
115:
116: if (!centralRegistry.isSwapper(swapData.target)) {
117: revert StakedGMXCToken__InvalidSwapper(swapData.target);
118: }
119:
120: yield = SwapperLib.swap(centralRegistry, swapData);
121:
122:
123: if (yield == 0) {
124: revert StakedGMXCToken__SlippageError();
125: }
126: }
127:
128:
129:
130: _afterDeposit(yield, 0);
131:
132:
133: _setNewVaultData(yield, vestPeriod);
134:
135: emit Harvest(yield);
136: }
137: }
['130']
130: function harvest(
131: bytes calldata data
132: ) external override returns (uint256 yield) {
133:
134: _canCompound();
135:
136:
137: _vestIfNeeded();
138:
139:
140: if (_checkVestStatus(_vaultData)) {
141: _updateVestingPeriodIfNeeded();
142:
143:
144: StrategyData memory sd = strategyData;
145:
146:
147: sd.gauge.getReward(address(this));
148:
149: {
150: uint256 rewardAmount = rewardToken.balanceOf(address(this));
151:
152: if (rewardAmount > 0) {
153:
154:
155: uint256 protocolFee = FixedPointMathLib.mulDiv(
156: rewardAmount,
157: centralRegistry.protocolHarvestFee(),
158: 1e18
159: );
160: rewardAmount -= protocolFee;
161: SafeTransferLib.safeTransfer(
162: address(rewardToken),
163: centralRegistry.feeAccumulator(),
164: protocolFee
165: );
166:
167:
168: if (!rewardTokenIsUnderlying) {
169: SwapperLib.Swap memory swapData = abi.decode(
170: data,
171: (SwapperLib.Swap)
172: );
173:
174: if (!centralRegistry.isSwapper(swapData.target)) {
175: revert VelodromeStableCToken__InvalidSwapper(
176: swapData.target
177: );
178: }
179:
180: SwapperLib.swap(centralRegistry, swapData);
181: }
182: }
183: }
184:
185: uint256 totalAmountA = IERC20(sd.token0).balanceOf(address(this));
186:
187:
188: if (totalAmountA == 0) {
189: revert VelodromeStableCToken__SlippageError();
190: }
191:
192:
193: address _asset = asset();
194:
195:
196: (uint256 r0, uint256 r1, ) = IVeloPair(_asset).getReserves();
197: (uint256 reserveA, uint256 reserveB) = sd.token0 ==
198: IVeloPair(_asset).token0()
199: ? (r0, r1)
200: : (r1, r0);
201:
202:
203: uint256 swapAmount = VelodromeLib._optimalDeposit(
204: address(sd.pairFactory),
205: _asset,
206: totalAmountA,
207: reserveA,
208: reserveB,
209: sd.decimalsA,
210: sd.decimalsB,
211: true
212: );
213:
214: VelodromeLib._swapExactTokensForTokens(
215: address(sd.router),
216: _asset,
217: sd.token0,
218: sd.token1,
219: swapAmount,
220: true
221: );
222: totalAmountA -= swapAmount;
223:
224:
225: yield = VelodromeLib._addLiquidity(
226: address(sd.router),
227: sd.token0,
228: sd.token1,
229: true,
230: totalAmountA,
231: IERC20(sd.token1).balanceOf(address(this)),
232: VelodromeLib.VELODROME_ADD_LIQUIDITY_SLIPPAGE
233: );
234:
235:
236:
237: _afterDeposit(yield, 0);
238:
239:
240: _setNewVaultData(yield, vestPeriod);
241:
242: emit Harvest(yield);
243: }
244: }
['117']
117: function harvest(
118: bytes calldata data
119: ) external override returns (uint256 yield) {
120:
121: _canCompound();
122:
123:
124: _vestIfNeeded();
125:
126:
127: if (_checkVestStatus(_vaultData)) {
128: _updateVestingPeriodIfNeeded();
129:
130:
131: StrategyData memory sd = strategyData;
132:
133:
134: sd.gauge.getReward(address(this));
135:
136: {
137: uint256 rewardAmount = rewardToken.balanceOf(address(this));
138:
139: if (rewardAmount > 0) {
140:
141:
142: uint256 protocolFee = FixedPointMathLib.mulDiv(
143: rewardAmount,
144: centralRegistry.protocolHarvestFee(),
145: 1e18
146: );
147: rewardAmount -= protocolFee;
148: SafeTransferLib.safeTransfer(
149: address(rewardToken),
150: centralRegistry.feeAccumulator(),
151: protocolFee
152: );
153:
154:
155: if (!rewardTokenIsUnderlying) {
156: SwapperLib.Swap memory swapData = abi.decode(
157: data,
158: (SwapperLib.Swap)
159: );
160:
161: if (!centralRegistry.isSwapper(swapData.target)) {
162: revert VelodromeVolatileCToken__InvalidSwapper(
163: swapData.target
164: );
165: }
166:
167: SwapperLib.swap(centralRegistry, swapData);
168: }
169: }
170: }
171:
172: uint256 totalAmountA = IERC20(sd.token0).balanceOf(address(this));
173:
174:
175: if (totalAmountA == 0) {
176: revert VelodromeVolatileCToken__SlippageError();
177: }
178:
179:
180: address _asset = asset();
181:
182:
183: (uint256 r0, uint256 r1, ) = IVeloPair(_asset).getReserves();
184: uint256 reserveA = sd.token0 == IVeloPair(_asset).token0()
185: ? r0
186: : r1;
187:
188:
189:
190:
191: uint256 swapAmount = VelodromeLib._optimalDeposit(
192: address(sd.pairFactory),
193: _asset,
194: totalAmountA,
195: reserveA,
196: 0,
197: 0,
198: 0,
199: false
200: );
201:
202: VelodromeLib._swapExactTokensForTokens(
203: address(sd.router),
204: _asset,
205: sd.token0,
206: sd.token1,
207: swapAmount,
208: false
209: );
210: totalAmountA -= swapAmount;
211:
212:
213: yield = VelodromeLib._addLiquidity(
214: address(sd.router),
215: sd.token0,
216: sd.token1,
217: false,
218: totalAmountA,
219: IERC20(sd.token1).balanceOf(address(this)),
220: VelodromeLib.VELODROME_ADD_LIQUIDITY_SLIPPAGE
221: );
222:
223:
224:
225: _afterDeposit(yield, 0);
226:
227:
228: _setNewVaultData(yield, vestPeriod);
229:
230: emit Harvest(yield);
231: }
232: }
['108']
108: function addAsset(
109: address asset,
110: string memory ticker,
111: address proxyFeed,
112: uint256 heartbeat,
113: bool inUSD
114: ) external {
115: _checkElevatedPermissions();
116:
117: if (heartbeat != 0) {
118: if (heartbeat > DEFAULT_HEART_BEAT) {
119: revert Api3Adaptor__InvalidHeartbeat();
120: }
121: }
122:
123: bytes32 dapiName = Bytes32Helper.stringToBytes32(ticker);
124: bytes32 dapiNameHash = keccak256(abi.encodePacked(dapiName));
125:
126:
127:
128: if (dapiNameHash != IProxy(proxyFeed).dapiNameHash()) {
129: revert Api3Adaptor__DAPINameHashError();
130: }
131:
132: AdaptorData storage data;
133:
134: if (inUSD) {
135: data = adaptorDataUSD[asset];
136: } else {
137: data = adaptorDataNonUSD[asset];
138: }
139:
140: data.heartbeat = heartbeat != 0
141: ? heartbeat
142: : DEFAULT_HEART_BEAT;
143:
144:
145:
146:
147:
148:
149:
150: data.max = (uint256(int256(type(int224).max)) * 9) / 10;
151: data.dapiNameHash = dapiNameHash;
152: data.proxyFeed = IProxy(proxyFeed);
153: data.isConfigured = true;
154:
155:
156: bool isUpdate;
157: if (isSupportedAsset[asset]) {
158: isUpdate = true;
159: }
160:
161: isSupportedAsset[asset] = true;
162: emit Api3AssetAdded(asset, data, isUpdate); // <= FOUND
163: }
['170']
170: function removeAsset(address asset) external override { // <= FOUND
171: _checkElevatedPermissions();
172:
173:
174: if (!isSupportedAsset[asset]) {
175: revert Api3Adaptor__AssetIsNotSupported();
176: }
177:
178:
179: delete isSupportedAsset[asset];
180:
181:
182: delete adaptorDataUSD[asset];
183: delete adaptorDataNonUSD[asset];
184:
185:
186: IOracleRouter(centralRegistry.oracleRouter()).notifyFeedRemoval(asset);
187:
188: emit Api3AssetRemoved(asset);
189: }
['148']
148: function addAsset(address asset, AdaptorData memory data) external { // <= FOUND
149: _checkElevatedPermissions();
150:
151: IBalancerPool pool = IBalancerPool(asset);
152:
153:
154: data.poolId = pool.getPoolId();
155: data.poolDecimals = pool.decimals();
156:
157: uint256 numUnderlyingOrConstituent = data
158: .underlyingOrConstituent
159: .length;
160:
161:
162: for (uint256 i; i < numUnderlyingOrConstituent; ++i) {
163:
164: if (address(data.underlyingOrConstituent[i]) == address(0)) {
165: continue;
166: }
167:
168: if (
169: !IOracleRouter(centralRegistry.oracleRouter()).isSupportedAsset(
170: data.underlyingOrConstituent[i]
171: )
172: ) {
173: revert BalancerStablePoolAdaptor__ConfigurationError();
174: }
175:
176: if (data.rateProviders[i] != address(0)) {
177:
178: if (data.rateProviderDecimals[i] == 0) {
179: revert BalancerStablePoolAdaptor__ConfigurationError();
180: }
181:
182:
183: if (IRateProvider(data.rateProviders[i]).getRate() == 0) {
184: revert BalancerStablePoolAdaptor__ConfigurationError();
185: }
186: }
187: }
188:
189:
190: adaptorData[asset] = data;
191:
192:
193: bool isUpdate;
194: if (isSupportedAsset[asset]) {
195: isUpdate = true;
196: }
197:
198: isSupportedAsset[asset] = true;
199: emit BalancerStablePoolAssetAdded(asset, data, isUpdate); // <= FOUND
200: }
['207']
207: function removeAsset(address asset) external override { // <= FOUND
208: _checkElevatedPermissions();
209:
210:
211: if (!isSupportedAsset[asset]) {
212: revert BalancerStablePoolAdaptor__AssetIsNotSupported();
213: }
214:
215:
216:
217: delete isSupportedAsset[asset];
218: delete adaptorData[asset];
219:
220:
221:
222: IOracleRouter(centralRegistry.oracleRouter()).notifyFeedRemoval(asset);
223: emit BalancerStablePoolAssetRemoved(asset); // <= FOUND
224: }
['93']
93: function addAsset(
94: address asset,
95: bool inUSD,
96: uint8 decimals
97: ) external {
98: _checkElevatedPermissions();
99:
100: bytes32 symbolHash;
101: if (inUSD) {
102:
103:
104: symbolHash = Bytes32Helper._toBytes32(asset);
105: } else {
106:
107:
108: symbolHash = Bytes32Helper._toBytes32WithETH(asset);
109: }
110:
111: AdaptorData storage data;
112:
113: if (inUSD) {
114: data = adaptorDataUSD[asset];
115: } else {
116: data = adaptorDataNonUSD[asset];
117: }
118:
119:
120:
121: if (decimals == 0) {
122: data.decimals = 8;
123: } else {
124:
125:
126: data.decimals = uint256(decimals);
127: }
128:
129:
130:
131:
132:
133:
134:
135: data.max = uint192(uint256(type(uint192).max) * 9 / 10);
136: data.symbolHash = symbolHash;
137: data.isConfigured = true;
138:
139:
140: bool isUpdate;
141: if (isSupportedAsset[asset]) {
142: isUpdate = true;
143: }
144:
145: isSupportedAsset[asset] = true;
146: emit RedstoneCoreAssetAdded(asset, data, isUpdate); // <= FOUND
147: }
['154']
154: function removeAsset(address asset) external override { // <= FOUND
155: _checkElevatedPermissions();
156:
157:
158: if (!isSupportedAsset[asset]) {
159: revert BaseRedstoneCoreAdaptor__AssetIsNotSupported();
160: }
161:
162:
163:
164: delete isSupportedAsset[asset];
165: delete adaptorDataUSD[asset];
166: delete adaptorDataNonUSD[asset];
167:
168:
169:
170: IOracleRouter(centralRegistry.oracleRouter()).notifyFeedRemoval(asset);
171:
172: emit RedstoneCoreAssetRemoved(asset);
173: }
['219']
219: function setCompoundingPaused(bool state) external { // <= FOUND
220:
221:
222: if (lastVestClaim() == 0) {
223: _revert(_UNAUTHORIZED_SELECTOR);
224: }
225:
226: if (state) {
227: _checkDaoPermissions();
228: } else {
229: _checkElevatedPermissions();
230: }
231:
232:
233: compoundingPaused = state ? 2 : 1;
234: emit CompoundingPaused(state); // <= FOUND
235: }
['103']
103: function _setExitFee(uint256 newExitFee) internal { // <= FOUND
104:
105: newExitFee = _bpToWad(newExitFee);
106:
107:
108: if (newExitFee > MAXIMUM_EXIT_FEE) {
109: revert CTokenCompoundingWithExitFee__InvalidExitFee();
110: }
111:
112:
113: uint256 oldExitFee = exitFee;
114:
115:
116: exitFee = newExitFee;
117: emit ExitFeeSet(oldExitFee, newExitFee); // <= FOUND
118: }
['89']
89: function claim(
90: uint256 amount,
91: bool locked,
92: bytes32[] calldata proof
93: ) external nonReentrant {
94: if (isPaused == 2) {
95: revert CVEInitialDistribution__Paused();
96: }
97:
98:
99: if (amount > maximumClaimAmount) {
100: revert CVEInitialDistribution__ParametersAreInvalid();
101: }
102:
103:
104: if (merkleRoot == bytes32(0)) {
105: revert CVEInitialDistribution__Unauthorized();
106: }
107:
108:
109: if (block.timestamp >= endClaimTimestamp) {
110: revert CVEInitialDistribution__NotEligible();
111: }
112:
113:
114: if (distributionClaimed[msg.sender]) {
115: revert CVEInitialDistribution__NotEligible();
116: }
117:
118:
119:
120: if (
121: !verify(
122: proof,
123: merkleRoot,
124: keccak256(abi.encodePacked(msg.sender, amount))
125: )
126: ) {
127: revert CVEInitialDistribution__NotEligible();
128: }
129:
130:
131: distributionClaimed[msg.sender] = true;
132:
133:
134:
135: if (locked) {
136: RewardsData memory emptyData;
137: uint256 boostedAmount = amount * lockedClaimMultiplier;
138: SafeTransferLib.safeApprove(cve, address(veCVE), boostedAmount);
139:
140:
141: veCVE.createLockFor(
142: msg.sender,
143: boostedAmount,
144: true,
145: emptyData,
146: "",
147: 0
148: );
149: } else {
150:
151: SafeTransferLib.safeTransfer(cve, msg.sender, amount);
152: }
153:
154:
155: emit DistributionClaimed(msg.sender, amount);
156: }
['215']
215: function withdrawRemainingTokens() external { // <= FOUND
216: _checkDaoPermissions();
217:
218: if (block.timestamp < endClaimTimestamp) {
219: revert CVEInitialDistribution__TransferError();
220: }
221:
222: uint256 amount = IERC20(cve).balanceOf(address(this));
223: SafeTransferLib.safeTransfer(
224: cve,
225: centralRegistry.daoAddress(),
226: amount
227: );
228:
229: emit RemainingTokensWithdrawn(amount);
230: }
['400']
400: function _claimRewards(
401: address user,
402: address recipient,
403: uint256 epochs,
404: RewardsData calldata rewardsData,
405: bytes calldata params,
406: uint256 aux
407: ) internal {
408: uint256 rewards = _calculateRewards(user, epochs);
409:
410:
411:
412: uint256 rewardAmount = _processRewards(
413: recipient,
414: rewards,
415: rewardsData,
416: params,
417: aux
418: );
419:
420:
421:
422: if (rewardAmount > 0) {
423: emit RewardPaid(
424: user,
425: rewardsData.asCVE ? cve : rewardToken,
426: rewardAmount
427: );
428: }
429: }
['437']
437: function _claimRewardsDirect(
438: address user,
439: uint256 epochs
440: ) internal returns (uint256 rewards) {
441: rewards = _calculateRewards(user, epochs);
442:
443:
444:
445: if (rewards > 0) {
446:
447:
448: SafeTransferLib.safeTransfer(rewardToken, msg.sender, rewards);
449:
450: emit RewardPaid(user, rewardToken, rewards);
451: }
452: }
['36']
36: function addAsset(
37: address asset
38: ) external override {
39: _checkElevatedPermissions();
40:
41: if (!ICamelotPair(asset).stableSwap()) {
42: revert CamelotStableLPAdaptor__AssetIsNotStableLP();
43: }
44:
45:
46: bool isUpdate;
47: if (isSupportedAsset[asset]) {
48: isUpdate = true;
49: }
50:
51: AdaptorData memory data = _addAsset(asset);
52: emit CamelotStableLPAssetAdded(asset, data, isUpdate); // <= FOUND
53: }
['60']
60: function removeAsset(address asset) external override { // <= FOUND
61: _checkElevatedPermissions();
62:
63: _removeAsset(asset);
64: emit CamelotStableLPAssetRemoved(asset); // <= FOUND
65: }
['36']
36: function addAsset(
37: address asset
38: ) external override {
39: _checkElevatedPermissions();
40:
41: if (ICamelotPair(asset).stableSwap()) {
42: revert CamelotVolatileLPAdaptor__AssetIsNotVolatileLP();
43: }
44:
45:
46: bool isUpdate;
47: if (isSupportedAsset[asset]) {
48: isUpdate = true;
49: }
50:
51: AdaptorData memory data = _addAsset(asset);
52: emit CamelotVolatileLPAssetAdded(asset, data, isUpdate); // <= FOUND
53: }
['60']
60: function removeAsset(address asset) external virtual override { // <= FOUND
61: _checkElevatedPermissions();
62:
63: _removeAsset(asset);
64: emit CamelotVolatileLPAssetRemoved(asset); // <= FOUND
65: }
['329']
329: function setCVE(address newCVE) external { // <= FOUND
330: _checkElevatedPermissions();
331:
332: cve = newCVE;
333: emit CoreContractSet("CVE", newCVE); // <= FOUND
334: }
['340']
340: function setVeCVE(address newVeCVE) external { // <= FOUND
341: _checkElevatedPermissions();
342:
343: veCVE = newVeCVE;
344: emit CoreContractSet("VeCVE", newVeCVE); // <= FOUND
345: }
['351']
351: function setCVELocker(address newCVELocker) external { // <= FOUND
352: _checkElevatedPermissions();
353:
354: cveLocker = newCVELocker;
355: emit CoreContractSet("CVE Locker", newCVELocker); // <= FOUND
356: }
['362']
362: function setProtocolMessagingHub(
363: address newProtocolMessagingHub
364: ) external {
365: _checkElevatedPermissions();
366:
367: protocolMessagingHub = newProtocolMessagingHub;
368:
369:
370:
371: if (feeAccumulator != address(0)) {
372: IFeeAccumulator(feeAccumulator).notifyUpdatedMessagingHub();
373: }
374:
375: emit CoreContractSet(
376: "Protocol Messaging Hub",
377: newProtocolMessagingHub
378: );
379: }
['385']
385: function setOracleRouter(address newOracleRouter) external { // <= FOUND
386: _checkElevatedPermissions();
387:
388: oracleRouter = newOracleRouter;
389: emit CoreContractSet("Oracle Router", newOracleRouter); // <= FOUND
390: }
['396']
396: function setFeeAccumulator(address newFeeAccumulator) external { // <= FOUND
397: _checkElevatedPermissions();
398:
399: feeAccumulator = newFeeAccumulator;
400: emit CoreContractSet("Fee Accumulator", newFeeAccumulator); // <= FOUND
401: }
['407']
407: function setWormholeCore(address newWormholeCore) external { // <= FOUND
408: _checkElevatedPermissions();
409:
410: wormholeCore = IWormhole(newWormholeCore);
411: emit WormholeCoreSet(newWormholeCore); // <= FOUND
412: }
['418']
418: function setWormholeRelayer(address newWormholeRelayer) external { // <= FOUND
419: _checkElevatedPermissions();
420:
421: wormholeRelayer = IWormholeRelayer(newWormholeRelayer);
422: emit WormholeRelayerSet(newWormholeRelayer); // <= FOUND
423: }
['429']
429: function setCircleTokenMessenger(
430: address newCircleTokenMessenger
431: ) external {
432: _checkElevatedPermissions();
433:
434: circleTokenMessenger = ITokenMessenger(newCircleTokenMessenger);
435: emit CircleTokenMessengerSet(newCircleTokenMessenger); // <= FOUND
436: }
['442']
442: function setTokenBridge(address newTokenBridge) external { // <= FOUND
443: _checkElevatedPermissions();
444:
445: tokenBridge = ITokenBridge(newTokenBridge);
446: emit TokenBridgeSet(newTokenBridge); // <= FOUND
447: }
['454']
454: function registerWormholeChainIDs(
455: uint256[] calldata chainIds,
456: uint16[] calldata wormholeChainIds
457: ) external {
458: _checkElevatedPermissions();
459:
460: uint256 numChainIds = chainIds.length;
461: for (uint256 i; i < numChainIds; ++i) {
462: wormholeChainId[chainIds[i]] = wormholeChainIds[i];
463: }
464: emit WormholeChainIDsSet(chainIds, wormholeChainIds); // <= FOUND
465: }
['472']
472: function registerCCTPDomains(
473: uint256[] calldata chainIds,
474: uint32[] calldata cctpDomains
475: ) external {
476: _checkElevatedPermissions();
477:
478: uint256 numChainIds = chainIds.length;
479:
480: for (uint256 i; i < numChainIds; ++i) {
481: cctpDomain[chainIds[i]] = cctpDomains[i];
482: }
483: emit CCTPDomainsSet(chainIds, cctpDomains); // <= FOUND
484: }
['490']
490: function setGelatoSponsor(address newGelatoSponsor) external { // <= FOUND
491: _checkElevatedPermissions();
492:
493: gelatoSponsor = newGelatoSponsor;
494: emit GelatoSponsorSet(newGelatoSponsor); // <= FOUND
495: }
['504']
504: function setProtocolCompoundFee(uint256 value) external { // <= FOUND
505: _checkElevatedPermissions();
506:
507:
508: if (value > 500) {
509: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
510: }
511:
512:
513:
514: protocolCompoundFee = _bpToWad(value);
515:
516:
517: protocolHarvestFee = protocolYieldFee + _bpToWad(value);
518:
519: emit FeeSet("Compound", value);
520: }
['529']
529: function setProtocolYieldFee(uint256 value) external { // <= FOUND
530: _checkElevatedPermissions();
531:
532:
533: if (value > 5000) {
534: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
535: }
536:
537:
538:
539: protocolYieldFee = _bpToWad(value);
540:
541:
542: protocolHarvestFee = _bpToWad(value) + protocolCompoundFee;
543:
544: emit FeeSet("Yield", value);
545: }
['554']
554: function setProtocolLeverageFee(uint256 value) external { // <= FOUND
555: _checkElevatedPermissions();
556:
557:
558: if (value > 200) {
559: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
560: }
561:
562:
563:
564: protocolLeverageFee = _bpToWad(value);
565:
566: emit FeeSet("Leverage", value);
567: }
['577']
577: function setProtocolInterestRateFee(
578: address market,
579: uint256 value
580: ) external {
581: _checkElevatedPermissions();
582:
583:
584: if (value > 5000) {
585: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
586: }
587:
588:
589: if (!isMarketManager[market]) {
590: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
591: }
592:
593:
594:
595:
596: protocolInterestFactor[market] = _bpToWad(value);
597:
598: emit InterestFeeSet(market, value);
599: }
['608']
608: function setEarlyUnlockPenaltyMultiplier(uint256 value) external { // <= FOUND
609: _checkElevatedPermissions();
610:
611:
612: if (value > 9000) {
613: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
614: }
615:
616:
617:
618: if (value < 3000 && value != 0) {
619: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
620: }
621:
622: earlyUnlockPenaltyMultiplier = value;
623:
624: emit MultiplierSet("Early Unlock Penalty", value);
625: }
['634']
634: function setVoteBoostMultiplier(uint256 value) external { // <= FOUND
635: _checkElevatedPermissions();
636:
637:
638:
639: if (value < DENOMINATOR && value != 0) {
640: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
641: }
642:
643: voteBoostMultiplier = value;
644:
645: emit MultiplierSet("Vote Boost", value);
646: }
['656']
656: function setLockBoostMultiplier(uint256 value) external { // <= FOUND
657: _checkElevatedPermissions();
658:
659:
660: if (value < DENOMINATOR && value != 0) {
661: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
662: }
663:
664: lockBoostMultiplier = value;
665:
666: emit MultiplierSet("Lock Boost", value);
667: }
['676']
676: function incrementApprovalIndex() external { // <= FOUND
677: uint256 newIndex = userApprovalIndex[msg.sender] + 1;
678: userApprovalIndex[msg.sender] = newIndex;
679:
680: emit ApprovalIndexIncremented(msg.sender, newIndex);
681: }
['687']
687: function disableDelegable(bool delegable) external { // <= FOUND
688: delegatingDisabled[msg.sender] = delegable;
689:
690: emit DelegableStatusSet(msg.sender, delegable);
691: }
['699']
699: function transferDaoOwnership(address newDaoAddress) external { // <= FOUND
700: _checkElevatedPermissions();
701:
702:
703: address previousDaoAddress = daoAddress;
704: daoAddress = newDaoAddress;
705:
706:
707: delete hasDaoPermissions[previousDaoAddress];
708:
709: hasDaoPermissions[newDaoAddress] = true;
710: emit OwnershipTransferred(previousDaoAddress, newDaoAddress); // <= FOUND
711:
712:
713: if (timelock != address(0)) {
714: if (
715: ERC165Checker.supportsInterface(
716: timelock,
717: type(ITimelock).interfaceId
718: )
719: ) {
720: ITimelock(timelock).updateDaoAddress();
721: }
722: }
723: }
['729']
729: function migrateTimelockConfiguration(address newTimelock) external { // <= FOUND
730: _checkEmergencyCouncilPermissions();
731:
732:
733: address previousTimelock = timelock;
734: timelock = newTimelock;
735:
736:
737: delete hasDaoPermissions[previousTimelock];
738: delete hasElevatedPermissions[previousTimelock];
739:
740:
741: hasDaoPermissions[newTimelock] = true;
742: hasElevatedPermissions[newTimelock] = true;
743:
744: emit NewTimelockConfiguration(previousTimelock, newTimelock);
745: }
['751']
751: function transferEmergencyCouncil(address newEmergencyCouncil) external { // <= FOUND
752: _checkEmergencyCouncilPermissions();
753:
754:
755: address previousEmergencyCouncil = emergencyCouncil;
756: emergencyCouncil = newEmergencyCouncil;
757:
758:
759: delete hasDaoPermissions[previousEmergencyCouncil];
760: delete hasElevatedPermissions[previousEmergencyCouncil];
761:
762:
763: hasDaoPermissions[newEmergencyCouncil] = true;
764: hasElevatedPermissions[newEmergencyCouncil] = true;
765:
766: emit EmergencyCouncilTransferred(
767: previousEmergencyCouncil,
768: newEmergencyCouncil
769: );
770: }
['786']
786: function addChainSupport(
787: address newOmnichainOperator,
788: address messagingHub,
789: address cveAddress,
790: uint256 chainId,
791: uint256 sourceAux,
792: uint256 destinationAux,
793: uint16 messagingChainId
794: ) external {
795: _checkElevatedPermissions();
796:
797:
798: if (
799: omnichainOperators[newOmnichainOperator][chainId].isAuthorized == 2
800: ) {
801: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
802: }
803:
804:
805: if (supportedChainData[chainId].isSupported == 2) {
806: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
807: }
808:
809: supportedChainData[chainId] = ChainData({
810: isSupported: 2,
811: messagingHub: messagingHub,
812: asSourceAux: sourceAux,
813: asDestinationAux: destinationAux,
814: cveAddress: cveAddress
815: });
816: messagingToGETHChainId[messagingChainId] = chainId;
817: GETHToMessagingChainId[chainId] = messagingChainId;
818: supportedChains++;
819: omnichainOperators[newOmnichainOperator][chainId] = OmnichainData({
820: isAuthorized: 2,
821: messagingChainId: messagingChainId,
822: cveAddress: cveAddress
823: });
824:
825: emit NewChainAdded(chainId, newOmnichainOperator);
826: }
['836']
836: function removeChainSupport(
837: address currentOmnichainOperator,
838: uint256 chainId
839: ) external {
840:
841:
842: _checkDaoPermissions();
843:
844: OmnichainData storage operatorToRemove = omnichainOperators[
845: currentOmnichainOperator
846: ][chainId];
847:
848: if (
849: omnichainOperators[currentOmnichainOperator][chainId]
850: .isAuthorized < 2
851: ) {
852: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
853: }
854:
855:
856: if (supportedChainData[chainId].isSupported < 2) {
857: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
858: }
859:
860:
861: supportedChainData[chainId].isSupported = 1;
862:
863: operatorToRemove.isAuthorized = 1;
864:
865: supportedChains--;
866:
867: delete GETHToMessagingChainId[
868: messagingToGETHChainId[operatorToRemove.messagingChainId]
869: ];
870: delete messagingToGETHChainId[operatorToRemove.messagingChainId];
871:
872: emit RemovedChain(chainId, currentOmnichainOperator);
873: }
['898']
898: function addZapper(address newZapper) external { // <= FOUND
899: _checkElevatedPermissions();
900:
901:
902: if (isZapper[newZapper]) {
903: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
904: }
905:
906: isZapper[newZapper] = true;
907:
908: emit NewCurvanceContract("Zapper", newZapper);
909: }
['917']
917: function removeZapper(address currentZapper) external { // <= FOUND
918: _checkElevatedPermissions();
919:
920:
921: if (!isZapper[currentZapper]) {
922: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
923: }
924:
925: delete isZapper[currentZapper];
926:
927: emit RemovedCurvanceContract("Zapper", currentZapper);
928: }
['936']
936: function addSwapper(address newSwapper) external { // <= FOUND
937: _checkElevatedPermissions();
938:
939:
940: if (isSwapper[newSwapper]) {
941: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
942: }
943:
944: isSwapper[newSwapper] = true;
945:
946: emit NewCurvanceContract("Swapper", newSwapper);
947: }
['955']
955: function removeSwapper(address currentSwapper) external { // <= FOUND
956: _checkElevatedPermissions();
957:
958:
959: if (!isSwapper[currentSwapper]) {
960: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
961: }
962:
963: delete isSwapper[currentSwapper];
964:
965: emit RemovedCurvanceContract("Swapper", currentSwapper);
966: }
['974']
974: function addVeCVELocker(address newVeCVELocker) external { // <= FOUND
975: _checkElevatedPermissions();
976:
977:
978: if (isVeCVELocker[newVeCVELocker]) {
979: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
980: }
981:
982: isVeCVELocker[newVeCVELocker] = true;
983:
984: emit NewCurvanceContract("VeCVELocker", newVeCVELocker);
985: }
['993']
993: function removeVeCVELocker(address currentVeCVELocker) external { // <= FOUND
994: _checkElevatedPermissions();
995:
996:
997: if (!isVeCVELocker[currentVeCVELocker]) {
998: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
999: }
1000:
1001: delete isVeCVELocker[currentVeCVELocker];
1002:
1003: emit RemovedCurvanceContract("VeCVELocker", currentVeCVELocker);
1004: }
['1012']
1012: function addGaugeController(address newGaugeController) external { // <= FOUND
1013: _checkElevatedPermissions();
1014:
1015:
1016: if (isGaugeController[newGaugeController]) {
1017: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
1018: }
1019:
1020: isGaugeController[newGaugeController] = true;
1021:
1022: emit NewCurvanceContract("Gauge Controller", newGaugeController);
1023: }
['1031']
1031: function removeGaugeController(address currentGaugeController) external { // <= FOUND
1032: _checkElevatedPermissions();
1033:
1034:
1035: if (!isGaugeController[currentGaugeController]) {
1036: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
1037: }
1038:
1039: delete isGaugeController[currentGaugeController];
1040:
1041: emit RemovedCurvanceContract(
1042: "Gauge Controller",
1043: currentGaugeController
1044: );
1045: }
['1053']
1053: function addHarvester(address newHarvester) external { // <= FOUND
1054: _checkElevatedPermissions();
1055:
1056:
1057: if (isHarvester[newHarvester]) {
1058: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
1059: }
1060:
1061: isHarvester[newHarvester] = true;
1062:
1063: emit NewCurvanceContract("Harvestor", newHarvester);
1064: }
['1072']
1072: function removeHarvester(address currentHarvester) external { // <= FOUND
1073: _checkElevatedPermissions();
1074:
1075:
1076: if (!isHarvester[currentHarvester]) {
1077: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
1078: }
1079:
1080: delete isHarvester[currentHarvester];
1081:
1082: emit RemovedCurvanceContract("Harvestor", currentHarvester);
1083: }
['1091']
1091: function addEndpoint(address newEndpoint) external { // <= FOUND
1092: _checkElevatedPermissions();
1093:
1094:
1095: if (isEndpoint[newEndpoint]) {
1096: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
1097: }
1098:
1099: isEndpoint[newEndpoint] = true;
1100:
1101: emit NewCurvanceContract("Endpoint", newEndpoint);
1102: }
['1110']
1110: function removeEndpoint(address currentEndpoint) external { // <= FOUND
1111: _checkElevatedPermissions();
1112:
1113:
1114: if (!isEndpoint[currentEndpoint]) {
1115: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
1116: }
1117:
1118: delete isEndpoint[currentEndpoint];
1119:
1120: emit RemovedCurvanceContract("Endpoint", currentEndpoint);
1121: }
['1141']
1141: function addMarketManager(
1142: address newMarketManager,
1143: uint256 marketInterestFactor
1144: ) public virtual {
1145: _checkElevatedPermissions();
1146:
1147:
1148: if (isMarketManager[newMarketManager]) {
1149: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
1150: }
1151:
1152:
1153: if (
1154: !ERC165Checker.supportsInterface(
1155: newMarketManager,
1156: type(IMarketManager).interfaceId
1157: )
1158: ) {
1159: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
1160: }
1161:
1162:
1163: if (marketInterestFactor > 5000) {
1164: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
1165: }
1166:
1167: isMarketManager[newMarketManager] = true;
1168:
1169: marketManagers.push(newMarketManager);
1170:
1171:
1172: protocolInterestFactor[newMarketManager] = _bpToWad(
1173: marketInterestFactor
1174: );
1175:
1176: emit NewCurvanceContract("Market Manager", newMarketManager);
1177: emit InterestFeeSet(newMarketManager, marketInterestFactor); // <= FOUND
1178: }
['1186']
1186: function removeMarketManager(
1187: address currentMarketManager
1188: ) public virtual {
1189: _checkElevatedPermissions();
1190:
1191:
1192: if (!isMarketManager[currentMarketManager]) {
1193: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
1194: }
1195:
1196: delete isMarketManager[currentMarketManager];
1197:
1198:
1199: uint256 numMarkets = marketManagers.length;
1200: uint256 marketIndex = numMarkets;
1201:
1202: for (uint256 i; i < numMarkets; ++i) {
1203: if (marketManagers[i] == currentMarketManager) {
1204: marketIndex = i;
1205: break;
1206: }
1207: }
1208:
1209:
1210:
1211:
1212: if (marketIndex >= numMarkets--) {
1213: _revert(_PARAMETERS_MISCONFIGURED_SELECTOR);
1214: }
1215:
1216:
1217: marketManagers[marketIndex] = marketManagers[numMarkets];
1218:
1219:
1220: marketManagers.pop();
1221:
1222: emit RemovedCurvanceContract("Market Manager", currentMarketManager);
1223: }
['113']
113: function addAsset(
114: address asset,
115: address aggregator,
116: uint256 heartbeat,
117: bool inUSD
118: ) external {
119: _checkElevatedPermissions();
120:
121: if (heartbeat != 0) {
122: if (heartbeat > DEFAULT_HEART_BEAT) {
123: revert ChainlinkAdaptor__InvalidHeartbeat();
124: }
125: }
126:
127:
128: IChainlink feedAggregator = IChainlink(
129: IChainlink(aggregator).aggregator()
130: );
131:
132:
133: uint256 maxFromChainlink = uint256(
134: uint192(feedAggregator.maxAnswer())
135: );
136: uint256 minFromChainklink = uint256(
137: uint192(feedAggregator.minAnswer())
138: );
139:
140:
141:
142:
143: uint256 bufferedMaxPrice = (maxFromChainlink * 9) / 10;
144: uint256 bufferedMinPrice = (minFromChainklink * 11) / 10;
145:
146:
147:
148:
149:
150: if (bufferedMaxPrice > type(uint240).max) {
151: bufferedMaxPrice = type(uint240).max;
152: }
153:
154: if (bufferedMinPrice >= bufferedMaxPrice) {
155: revert ChainlinkAdaptor__InvalidMinMaxConfig();
156: }
157:
158: AdaptorData storage data;
159:
160: if (inUSD) {
161: data = adaptorDataUSD[asset];
162: } else {
163: data = adaptorDataNonUSD[asset];
164: }
165:
166:
167: data.decimals = feedAggregator.decimals();
168: data.max = bufferedMaxPrice;
169: data.min = bufferedMinPrice;
170: data.heartbeat = heartbeat != 0
171: ? heartbeat
172: : DEFAULT_HEART_BEAT;
173: data.aggregator = IChainlink(aggregator);
174: data.isConfigured = true;
175:
176:
177: bool isUpdate;
178: if (isSupportedAsset[asset]) {
179: isUpdate = true;
180: }
181:
182: isSupportedAsset[asset] = true;
183: emit ChainlinkAssetAdded(asset, data, isUpdate); // <= FOUND
184: }
['191']
191: function removeAsset(address asset) external override { // <= FOUND
192: _checkElevatedPermissions();
193:
194:
195: if (!isSupportedAsset[asset]) {
196: revert ChainlinkAdaptor__AssetIsNotSupported();
197: }
198:
199:
200: delete isSupportedAsset[asset];
201:
202:
203: delete adaptorDataUSD[asset];
204: delete adaptorDataNonUSD[asset];
205:
206:
207:
208: IOracleRouter(centralRegistry.oracleRouter()).notifyFeedRemoval(asset);
209: emit ChainlinkAssetRemoved(asset); // <= FOUND
210: }
['97']
97: function start(
98: uint256 startTimestamp,
99: uint256 softPriceInUSD,
100: uint256 cveAmountInLBP,
101: address paymentTokenAddress
102: ) external {
103: if (!centralRegistry.hasDaoPermissions(msg.sender)) {
104: revert CurvanceDAOLBP__Unauthorized();
105: }
106:
107: if (startTime != 0) {
108: revert CurvanceDAOLBP__AlreadyStarted();
109: }
110:
111: if (startTimestamp < block.timestamp) {
112: revert CurvanceDAOLBP__InvalidStartTime();
113: }
114:
115: uint256 errorCode;
116: (paymentTokenPrice, errorCode) = IOracleRouter(centralRegistry.oracleRouter())
117: .getPrice(paymentTokenAddress, true, true);
118:
119:
120:
121: if (errorCode == 2) {
122: revert CurvanceDAOLBP__InvalidPriceSource();
123: }
124:
125: startTime = startTimestamp;
126: softPriceInpaymentToken = (softPriceInUSD * WAD) / paymentTokenPrice;
127: cveAmountForSale = cveAmountInLBP;
128: paymentToken = paymentTokenAddress;
129: paymentTokenDecimals = IERC20(paymentTokenAddress).decimals();
130:
131: emit LBPStarted(startTimestamp);
132: }
['178']
178: function claim() external returns (uint256 amount) { // <= FOUND
179: SaleStatus saleStatus = currentStatus();
180: if (saleStatus == SaleStatus.NotStarted) {
181: revert CurvanceDAOLBP__NotStarted();
182: }
183: if (saleStatus == SaleStatus.InSale) {
184: revert CurvanceDAOLBP__InSale();
185: }
186:
187: uint256 payAmount = userCommitted[msg.sender];
188: userCommitted[msg.sender] = 0;
189:
190: uint256 price = currentPrice();
191: uint256 adjustedPayAmount = _adjustDecimals(
192: payAmount,
193: paymentTokenDecimals,
194: 18
195: );
196: amount = (adjustedPayAmount * WAD) / price;
197:
198: SafeTransferLib.safeTransfer(cve, msg.sender, amount);
199:
200: emit Claimed(msg.sender, amount);
201: }
['289']
289: function _commit(uint256 amount, address recipient) internal { // <= FOUND
290: userCommitted[recipient] += amount;
291: saleCommitted += amount;
292:
293: emit Committed(recipient, amount);
294: }
['177']
177: function addAsset(address asset, AdaptorData memory data) external { // <= FOUND
178: _checkElevatedPermissions();
179:
180:
181:
182: if (isLocked(data.pool, 2)) {
183: revert Curve2PoolAssetAdaptor__UnsupportedPool();
184: }
185:
186:
187: if (asset == data.baseToken) {
188: revert Curve2PoolAssetAdaptor__InvalidAsset();
189: }
190:
191: address oracleRouter = centralRegistry.oracleRouter();
192:
193:
194:
195: if (!IOracleRouter(oracleRouter).isSupportedAsset(data.baseToken)) {
196: revert Curve2PoolAssetAdaptor__BaseAssetIsNotSupported();
197: }
198:
199:
200: if (data.lowerBound >= data.upperBound) {
201: revert Curve2PoolAssetAdaptor__InvalidBounds();
202: }
203:
204: ICurvePool pool = ICurvePool(data.pool);
205:
206: if (pool.coins(uint256(uint128(data.quoteTokenIndex))) != asset) {
207: revert Curve2PoolAssetAdaptor__InvalidAssetIndex();
208: }
209: if (
210: pool.coins(uint256(uint128(data.baseTokenIndex))) != data.baseToken
211: ) {
212: revert Curve2PoolAssetAdaptor__InvalidAssetIndex();
213: }
214:
215: data.quoteTokenDecimals = ERC20(asset).decimals();
216:
217: if (CommonLib.isETH(data.baseToken)) {
218: data.baseTokenDecimals = 18;
219: } else {
220: data.baseTokenDecimals = ERC20(data.baseToken).decimals();
221: }
222:
223:
224:
225:
226:
227: data.lowerBound = _bpToWad(data.lowerBound);
228: data.upperBound = _bpToWad(data.upperBound);
229:
230:
231: if (_MAX_BOUND_RANGE + data.lowerBound < data.upperBound) {
232: revert Curve2PoolAssetAdaptor__InvalidBounds();
233: }
234:
235:
236: uint256 testVirtualPrice = pool.get_virtual_price();
237:
238:
239: _enforceBounds(testVirtualPrice, data.lowerBound, data.upperBound);
240:
241:
242: adaptorData[asset] = data;
243:
244:
245: bool isUpdate;
246: if (isSupportedAsset[asset]) {
247: isUpdate = true;
248: }
249:
250: isSupportedAsset[asset] = true;
251: emit CurvePoolAssetAdded(asset, data, isUpdate); // <= FOUND
252: }
['196']
196: function addAsset(address asset, AdaptorData memory data) external { // <= FOUND
197: _checkElevatedPermissions();
198:
199:
200:
201: if (isLocked(asset, 2)) {
202: revert Curve2PoolLPAdaptor__UnsupportedPool();
203: }
204:
205: address oracleRouter = centralRegistry.oracleRouter();
206:
207:
208:
209: if (
210: !IOracleRouter(oracleRouter).isSupportedAsset(
211: data.underlying0
212: )
213: ) {
214: revert Curve2PoolLPAdaptor__QuoteAssetIsNotSupported();
215: }
216:
217:
218:
219: if (
220: !IOracleRouter(oracleRouter).isSupportedAsset(
221: data.underlying1
222: )
223: ) {
224: revert Curve2PoolLPAdaptor__QuoteAssetIsNotSupported();
225: }
226:
227:
228: if (data.lowerBound >= data.upperBound) {
229: revert Curve2PoolLPAdaptor__InvalidBounds();
230: }
231:
232: ICurvePool pool = ICurvePool(data.pool);
233: uint256 coinsLength;
234:
235: while (true) {
236: try pool.coins(coinsLength) {
237: ++coinsLength;
238: } catch {
239: break;
240: }
241: }
242:
243:
244: if (coinsLength != 2) {
245: revert Curve2PoolLPAdaptor__UnsupportedPool();
246: }
247:
248: address underlying;
249: for (uint256 i; i < coinsLength; ) {
250: underlying = pool.coins(i++);
251:
252:
253:
254: if (
255: underlying != data.underlying0 &&
256: underlying != data.underlying1
257: ) {
258: revert Curve2PoolLPAdaptor__UnsupportedPool();
259: }
260: }
261:
262:
263:
264:
265:
266: data.lowerBound = _bpToWad(data.lowerBound);
267: data.upperBound = _bpToWad(data.upperBound);
268:
269:
270: if (_MAX_BOUND_RANGE + data.lowerBound < data.upperBound) {
271: revert Curve2PoolLPAdaptor__InvalidBounds();
272: }
273:
274:
275: if (data.isCorrelated) {
276:
277:
278: try pool.lp_price() {
279: revert Curve2PoolLPAdaptor__UnsupportedPool();
280: } catch {}
281: } else {
282:
283:
284: try pool.lp_price() {} catch {
285: revert Curve2PoolLPAdaptor__UnsupportedPool();
286: }
287: }
288:
289:
290: uint256 testVirtualPrice = pool.get_virtual_price();
291:
292:
293: _enforceBounds(testVirtualPrice, data.lowerBound, data.upperBound);
294:
295:
296: adaptorData[asset] = data;
297:
298:
299: bool isUpdate;
300: if (isSupportedAsset[asset]) {
301: isUpdate = true;
302: }
303:
304: isSupportedAsset[asset] = true;
305: emit CurvePoolAssetAdded(asset, data, isUpdate); // <= FOUND
306: }
['259']
259: function removeAsset(address asset) external override { // <= FOUND
260: _checkElevatedPermissions();
261:
262:
263: if (!isSupportedAsset[asset]) {
264: revert Curve2PoolAssetAdaptor__AssetIsNotSupported();
265: }
266:
267:
268:
269: delete isSupportedAsset[asset];
270: delete adaptorData[asset];
271:
272:
273:
274: IOracleRouter(centralRegistry.oracleRouter()).notifyFeedRemoval(asset);
275: emit CurvePoolAssetRemoved(asset); // <= FOUND
276: }
['313']
313: function removeAsset(address asset) external override { // <= FOUND
314: _checkElevatedPermissions();
315:
316:
317: if (!isSupportedAsset[asset]) {
318: revert Curve2PoolLPAdaptor__AssetIsNotSupported();
319: }
320:
321:
322:
323: delete isSupportedAsset[asset];
324: delete adaptorData[asset];
325:
326:
327:
328: IOracleRouter(centralRegistry.oracleRouter()).notifyFeedRemoval(asset);
329: emit CurvePoolAssetRemoved(asset); // <= FOUND
330: }
['101']
101: function _setReentrancyConfig(
102: uint256 coinsLength,
103: uint256 gasLimit
104: ) internal {
105:
106: if (gasLimit < MIN_GAS_LIMIT) {
107: revert CurveBaseAdaptor__InvalidConfiguration();
108: }
109:
110:
111:
112: if (coinsLength < 2 || coinsLength > 4) {
113: revert CurveBaseAdaptor__InvalidConfiguration();
114: }
115:
116: reentrancyConfig[coinsLength] = gasLimit;
117: emit UpdatedReentrancyConfiguration(coinsLength, gasLimit); // <= FOUND
118: }
['222']
222: function startMarket(address by) external nonReentrant returns (bool) { // <= FOUND
223: if (msg.sender != address(marketManager)) {
224: _revert(_UNAUTHORIZED_SELECTOR);
225: }
226:
227: uint256 amount = _BASE_UNDERLYING_RESERVE;
228: SafeTransferLib.safeTransferFrom(
229: underlying,
230: by,
231: address(this),
232: amount
233: );
234:
235:
236:
237:
238:
239: totalSupply = totalSupply + amount;
240: balanceOf[address(this)] = balanceOf[address(this)] + amount;
241:
242: emit Transfer(address(0), address(this), amount);
243: return true;
244: }
['392']
392: function repayWithBadDebt(
393: address liquidator,
394: address account,
395: uint256 repayRatio
396: ) external nonReentrant {
397:
398:
399:
400:
401:
402: if (msg.sender != address(marketManager)) {
403: _revert(_UNAUTHORIZED_SELECTOR);
404: }
405:
406:
407:
408:
409:
410:
411: uint256 accountDebt = debtBalanceCached(account);
412: uint256 repayAmount = (accountDebt * repayRatio) / WAD;
413:
414:
415:
416:
417:
418:
419:
420: SafeTransferLib.safeTransferFrom(
421: underlying,
422: liquidator,
423: address(this),
424: repayAmount
425: );
426:
427:
428:
429: delete _debtOf[account].principal;
430: totalBorrows -= accountDebt;
431:
432: emit Repay(liquidator, account, repayAmount);
433: emit BadDebtRecognized(liquidator, account, accountDebt - repayAmount); // <= FOUND
434: }
['696']
696: function approve(address spender, uint256 tokens) external returns (bool) { // <= FOUND
697: allowance[msg.sender][spender] = tokens;
698:
699: emit Approval(msg.sender, spender, tokens);
700: return true;
701: }
['977']
977: function accrueInterest() public { // <= FOUND
978:
979: MarketData memory cachedData = marketData;
980:
981:
982: if (
983: cachedData.lastTimestampUpdated + cachedData.compoundRate >
984: block.timestamp
985: ) {
986: return;
987: }
988:
989:
990: uint256 borrowsPrior = totalBorrows;
991: uint256 reservesPrior = totalReserves;
992: uint256 exchangeRatePrior = cachedData.exchangeRate;
993:
994:
995: uint256 borrowRate = interestRateModel.getBorrowRateWithUpdate(
996: marketUnderlyingHeld(),
997: borrowsPrior,
998: reservesPrior
999: );
1000:
1001:
1002:
1003: uint256 interestCompounds = (block.timestamp -
1004: cachedData.lastTimestampUpdated) / cachedData.compoundRate;
1005:
1006: uint256 interestAccumulated = borrowRate * interestCompounds;
1007: uint256 debtAccumulated = (interestAccumulated * borrowsPrior) / WAD;
1008:
1009:
1010: uint256 totalBorrowsNew = debtAccumulated + borrowsPrior;
1011: uint256 exchangeRateNew = ((interestAccumulated * exchangeRatePrior) /
1012: WAD) + exchangeRatePrior;
1013:
1014:
1015: marketData.lastTimestampUpdated = uint40(
1016: cachedData.lastTimestampUpdated +
1017: (interestCompounds * cachedData.compoundRate)
1018: );
1019: marketData.exchangeRate = uint216(exchangeRateNew);
1020: totalBorrows = totalBorrowsNew;
1021:
1022:
1023:
1024: uint256 newReserves = ((interestFactor * debtAccumulated) / WAD);
1025: if (newReserves > 0) {
1026: totalReserves = newReserves + reservesPrior;
['1049']
1049: function _setInterestRateModel(
1050: IInterestRateModel newInterestRateModel
1051: ) internal {
1052:
1053: if (
1054: !ERC165Checker.supportsInterface(
1055: address(newInterestRateModel),
1056: type(IInterestRateModel).interfaceId
1057: )
1058: ) {
1059: revert DToken__ValidationFailed();
1060: }
1061:
1062:
1063: address oldInterestRateModel = address(interestRateModel);
1064:
1065:
1066: interestRateModel = newInterestRateModel;
1067: marketData.compoundRate = newInterestRateModel.compoundRate();
1068:
1069: emit NewMarketInterestRateModel(
1070: oldInterestRateModel,
1071: address(newInterestRateModel),
1072: marketData.compoundRate
1073: );
1074: }
['1080']
1080: function _setInterestFactor(uint256 newInterestFactor) internal { // <= FOUND
1081:
1082: if (newInterestFactor > 5000) {
1083: revert DToken__ExcessiveValue();
1084: }
1085:
1086:
1087: uint256 oldInterestFactor = interestFactor;
1088:
1089:
1090:
1091:
1092: interestFactor = newInterestFactor * 1e14;
1093:
1094: emit NewInterestFactor(oldInterestFactor, newInterestFactor);
1095: }
['1104']
1104: function _transfer(
1105: address spender,
1106: address from,
1107: address to,
1108: uint256 tokens
1109: ) internal {
1110:
1111: if (from == to) {
1112: revert DToken__TransferError();
1113: }
1114:
1115:
1116: marketManager.canTransfer(address(this), from, tokens);
1117:
1118:
1119: if (spender != from) {
1120:
1121:
1122: allowance[from][spender] = allowance[from][spender] - tokens;
1123: }
1124:
1125:
1126: balanceOf[from] = balanceOf[from] - tokens;
1127:
1128:
1129: unchecked {
1130: balanceOf[to] = balanceOf[to] + tokens;
1131: }
1132:
1133:
1134: GaugePool gaugePool = _gaugePool();
1135: gaugePool.withdraw(address(this), from, tokens);
1136: gaugePool.deposit(address(this), to, tokens);
1137:
1138:
1139: emit Transfer(from, to, tokens);
1140: }
['1149']
1149: function _mint(
1150: address minter,
1151: address recipient,
1152: uint256 amount
1153: ) internal {
1154:
1155: accrueInterest();
1156:
1157:
1158: marketManager.canMint(address(this));
1159:
1160:
1161: uint256 er = exchangeRateCached();
1162:
1163:
1164: SafeTransferLib.safeTransferFrom(
1165: underlying,
1166: minter,
1167: address(this),
1168: amount
1169: );
1170:
1171:
1172: uint256 tokens = (amount * WAD) / er;
1173:
1174:
1175: unchecked {
1176: totalSupply = totalSupply + tokens;
1177:
1178: balanceOf[recipient] = balanceOf[recipient] + tokens;
1179: }
1180:
1181:
1182: _gaugePool().deposit(address(this), recipient, tokens);
1183:
1184: emit Transfer(address(0), recipient, tokens);
1185: }
['1194']
1194: function _redeem(
1195: address account,
1196: address recipient,
1197: uint256 tokens,
1198: uint256 amount
1199: ) internal {
1200:
1201:
1202:
1203:
1204: if (marketUnderlyingHeld() < amount) {
1205: revert DToken__InsufficientUnderlyingHeld();
1206: }
1207:
1208:
1209: balanceOf[account] = balanceOf[account] - tokens;
1210:
1211:
1212: unchecked {
1213: totalSupply = totalSupply - tokens;
1214: }
1215:
1216:
1217:
1218: _gaugePool().withdraw(address(this), account, tokens);
1219:
1220:
1221: SafeTransferLib.safeTransfer(underlying, recipient, amount);
1222:
1223: emit Transfer(account, address(0), tokens);
1224: }
['1231']
1231: function _borrow(
1232: address account,
1233: uint256 amount,
1234: address recipient
1235: ) internal {
1236:
1237:
1238:
1239:
1240:
1241:
1242:
1243:
1244: if (
1245: marketUnderlyingHeld() - totalReserves <
1246: amount + _BASE_UNDERLYING_RESERVE
1247: ) {
1248: revert DToken__InsufficientUnderlyingHeld();
1249: }
1250:
1251:
1252:
1253: _debtOf[account].principal = debtBalanceCached(account) + amount;
1254: _debtOf[account].accountExchangeRate = marketData.exchangeRate;
1255: totalBorrows = totalBorrows + amount;
1256:
1257:
1258: SafeTransferLib.safeTransfer(underlying, recipient, amount);
1259:
1260: emit Borrow(account, amount);
1261: }
['1271']
1271: function _repay(
1272: address payer,
1273: address account,
1274: uint256 amount
1275: ) internal returns (uint256) {
1276:
1277: marketManager.canRepay(address(this), account);
1278:
1279:
1280: uint256 accountDebt = debtBalanceCached(account);
1281:
1282:
1283: if (amount > accountDebt) {
1284: revert DToken__ExcessiveValue();
1285: }
1286:
1287:
1288: amount = amount == 0 ? accountDebt : amount;
1289:
1290: SafeTransferLib.safeTransferFrom(
1291: underlying,
1292: payer,
1293: address(this),
1294: amount
1295: );
1296:
1297:
1298:
1299:
1300: unchecked {
1301: _debtOf[account].principal = accountDebt - amount;
1302: }
1303: _debtOf[account].accountExchangeRate = marketData.exchangeRate;
1304: totalBorrows -= amount;
1305:
1306: emit Repay(payer, account, amount);
1307: return amount;
1308: }
['1321']
1321: function _liquidate(
1322: address liquidator,
1323: address account,
1324: uint256 amount,
1325: IMToken collateralToken,
1326: bool exactAmount
1327: ) internal {
1328:
1329: accrueInterest();
1330:
1331:
1332: assembly {
1333: if eq(account, caller()) {
1334:
1335: mstore(0x00, 0xefeae624)
1336: revert(0x1c, 0x04)
1337: }
1338: }
1339:
1340:
1341: if (!collateralToken.isCToken()) {
1342: revert DToken__ValidationFailed();
1343: }
1344:
1345: uint256 liquidatedTokens;
1346: uint256 protocolTokens;
1347:
1348:
1349:
1350: (amount, liquidatedTokens, protocolTokens) = marketManager
1351: .canLiquidateWithExecution(
1352: address(this),
1353: address(collateralToken),
1354: account,
1355: amount,
1356: exactAmount
1357: );
1358:
1359:
1360: if (!marketManager.isListed(address(this))) {
1361: revert DToken__ValidationFailed();
1362: }
1363:
1364:
1365: uint256 accountDebt = debtBalanceCached(account);
1366:
1367:
1368: SafeTransferLib.safeTransferFrom(
1369: underlying,
1370: liquidator,
1371: address(this),
1372: amount
1373: );
1374:
1375:
1376:
1377: _debtOf[account].principal = accountDebt - amount;
1378: _debtOf[account].accountExchangeRate = marketData.exchangeRate;
1379: totalBorrows -= amount;
1380:
1381: emit Repay(liquidator, account, amount);
1382:
1383:
1384:
1385:
1386: collateralToken.seize(
1387: liquidator,
1388: account,
1389: liquidatedTokens,
1390: protocolTokens
1391: );
1392:
1393: emit Liquidated(
1394: liquidator,
1395: account,
1396: amount,
1397: address(collateralToken),
1398: liquidatedTokens
1399: );
1400: }
['109']
109: function setDelegateApproval(
110: address delegate,
111: bool isApproved
112: ) external {
113: if (hasDelegatingDisabled(msg.sender)) {
114: revert Delegable__DelegatingDisabled();
115: }
116:
117: uint256 approvalIndex = getUserApprovalIndex(msg.sender);
118: _isDelegate[msg.sender][approvalIndex][delegate] = isApproved;
119:
120: emit DelegateApproval(
121: msg.sender,
122: delegate,
123: approvalIndex,
124: isApproved
125: );
126: }
['578']
578: function _updateDynamicInterestRateModel(
579: uint256 baseRatePerYear,
580: uint256 vertexRatePerYear,
581: uint256 vertexUtilStart,
582: uint256 adjustmentRate,
583: uint256 adjustmentVelocity,
584: uint256 vertexMultiplierMax,
585: uint256 decayRate,
586: bool vertexReset
587: ) internal {
588:
589:
590:
591: baseRatePerYear = _bpToWad(baseRatePerYear);
592: vertexRatePerYear = _bpToWad(vertexRatePerYear);
593: vertexUtilStart = _bpToWad(vertexUtilStart);
594: adjustmentVelocity = _bpToWad(adjustmentVelocity);
595: vertexMultiplierMax = _bpToWad(vertexMultiplierMax);
596: decayRate = _bpToWad(decayRate);
597:
598:
599: if (
600: adjustmentVelocity > MAX_VERTEX_ADJUSTMENT_VELOCITY ||
601: adjustmentVelocity < MIN_VERTEX_ADJUSTMENT_VELOCITY
602: ) {
603: revert DynamicInterestRateModel__InvalidAdjustmentVelocity();
604: }
605:
606:
607: if (
608: adjustmentRate > MAX_VERTEX_ADJUSTMENT_RATE ||
609: adjustmentRate < MIN_VERTEX_ADJUSTMENT_RATE
610: ) {
611: revert DynamicInterestRateModel__InvalidAdjustmentRate();
612: }
613:
614:
615: if (decayRate > MAX_VERTEX_DECAY_RATE) {
616: revert DynamicInterestRateModel__InvalidDecayRate();
617: }
618:
619:
620:
621: if (vertexMultiplierMax * vertexRatePerYear > type(uint192).max) {
622: revert DynamicInterestRateModel__InvalidMultiplierMax();
623: }
624:
625: RatesConfiguration storage config = ratesConfig;
626:
627: config.baseInterestRate =
628: (INTEREST_COMPOUND_RATE * baseRatePerYear * WAD) /
629: (_SECONDS_PER_YEAR * vertexUtilStart);
630: config.vertexInterestRate =
631: (INTEREST_COMPOUND_RATE * vertexRatePerYear) /
632: _SECONDS_PER_YEAR;
633:
634: config.vertexStartingPoint = vertexUtilStart;
635: config.adjustmentRate = adjustmentRate;
636: config.adjustmentVelocity = adjustmentVelocity;
637:
638: {
639:
640: uint256 newMultiplier = vertexReset ? WAD : vertexMultiplier();
641: _currentRates = _packRatesData(
642: newMultiplier,
643: uint64(block.timestamp + config.adjustmentRate)
644: );
645: }
646:
647: config.decayRate = decayRate;
648:
649:
650:
651: uint256 thresholdLength = (WAD - vertexUtilStart) / 2;
652: config.increaseThreshold = vertexUtilStart + thresholdLength;
653: config.increaseThresholdMax = WAD;
654:
655:
656:
657: config.decreaseThreshold = vertexUtilStart;
658: config.decreaseThresholdMax = vertexUtilStart - thresholdLength;
659:
660: RatesConfiguration memory cachedConfig = config;
661:
662: emit NewDynamicInterestRateModel(
663: cachedConfig.baseInterestRate,
664: cachedConfig.vertexInterestRate,
665: vertexUtilStart,
666: adjustmentRate,
667: adjustmentVelocity,
668: vertexMultiplierMax,
669: decayRate,
670: cachedConfig.increaseThreshold,
671: WAD,
672: cachedConfig.decreaseThreshold,
673: cachedConfig.decreaseThresholdMax,
674: vertexReset
675: );
676: }
['179']
179: function _transferTokenViaWormhole(
180: address token,
181: uint256 dstChainId,
182: address to,
183: uint256 amount,
184: uint256 wormholeFee
185: ) internal returns (uint64) {
186: ITokenBridge tokenBridge = centralRegistry.tokenBridge();
187: uint16 wormholeChainId = centralRegistry.wormholeChainId(dstChainId);
188: IWormhole wormholeCore = centralRegistry.wormholeCore();
189: uint256 messageFee = wormholeCore.messageFee();
190:
191: SwapperLib._approveTokenIfNeeded(token, address(tokenBridge), amount);
192:
193: bytes memory payload = abi.encode(uint8(1), feeToken, amount);
194:
195: uint64 sequence = tokenBridge.transferTokensWithPayload{
196: value: messageFee
197: }(
198: token,
199: amount,
200: wormholeChainId,
201: bytes32(uint256(uint160(to))),
202: 0,
203: payload
204: );
205:
206: IWormholeRelayer.VaaKey[]
207: memory vaaKeys = new IWormholeRelayer.VaaKey[](1);
208: vaaKeys[0] = IWormholeRelayer.VaaKey({
209: emitterAddress: bytes32(uint256(uint160(address(tokenBridge)))),
210: chainId: wormholeCore.chainId(),
211: sequence: sequence
212: });
213:
214: return
215: centralRegistry.wormholeRelayer().sendVaasToEvm{
216: value: wormholeFee - messageFee
217: }(wormholeChainId, to, payload, 0, _GAS_LIMIT, vaaKeys);
218: }
['169']
169: function addAsset(address asset, address alteredToken) external { // <= FOUND
170: _checkElevatedPermissions();
171:
172: IReader.MarketProps memory market = gmxReader.getMarket(
173: gmxDataStore,
174: asset
175: );
176:
177: bool isSynthetic = market.indexToken.code.length == 0;
178:
179:
180: if (
181: market.indexToken == address(0) ||
182: market.longToken == address(0) ||
183: market.shortToken == address(0)
184: ) {
185: revert GMAdaptor__MarketIsInvalid();
186: }
187:
188:
189:
190: if (
191: (isSynthetic && alteredToken == address(0)) ||
192: (!isSynthetic && alteredToken != address(0))
193: ) {
194: revert GMAdaptor__AlteredTokenIsInvalid();
195: }
196:
197: IOracleRouter oracleRouter = IOracleRouter(
198: centralRegistry.oracleRouter()
199: );
200:
201: address[] memory tokens = new address[](4);
202: tokens[0] = isSynthetic ? alteredToken : market.indexToken;
203: tokens[1] = market.longToken;
204: tokens[2] = market.shortToken;
205: tokens[3] = market.indexToken;
206:
207: address token;
208:
209:
210: for (uint256 i; i < 3; ++i) {
211: token = tokens[i];
212:
213: if (!oracleRouter.isSupportedAsset(token)) {
214: revert GMAdaptor__MarketTokenIsNotSupported(token);
215: }
216:
217: if (_priceUnit[token] == 0) {
218: _priceUnit[token] = WAD * 10 ** IERC20(token).decimals();
['246']
246: function removeAsset(address asset) external override { // <= FOUND
247: _checkElevatedPermissions();
248:
249:
250: if (!isSupportedAsset[asset]) {
251: revert GMAdaptor__AssetIsNotSupported();
252: }
253:
254:
255:
256: delete isSupportedAsset[asset];
257: delete marketData[asset];
258:
259:
260:
261: IOracleRouter(centralRegistry.oracleRouter()).notifyFeedRemoval(asset);
262: emit GMXGMAssetRemoved(asset); // <= FOUND
263: }
['206']
206: function afterDepositExecution(
207: bytes32 key,
208: IGMXDeposit.Props memory,
209: IGMXEventUtils.EventLogData memory eventData
210: ) external {
211: if (msg.sender != gmxDepositHandler) {
212: revert GMCToken__CallerIsNotGMXDepositHandler();
213: }
214: if (!_isDepositKey[key]) {
215: revert GMCToken__InvalidDepositKey();
216: }
217:
218: uint256 yield = eventData.uintItems.items[0].value;
219:
220:
221: _setNewVaultData(yield, vestPeriod);
222:
223: delete _isDepositKey[key];
224:
225: emit Harvest(yield);
226: }
['145']
145: function addExtraReward(address newReward) external { // <= FOUND
146: _checkDaoPermissions();
147:
148: if (newReward == address(0)) {
149: revert GaugeErrors.InvalidAddress();
150: }
151:
152: uint256 rewardTokensLength = rewardTokens.length;
153: for (uint256 i; i < rewardTokensLength; ) {
154:
155: if (rewardTokens[i++] == newReward) {
156: revert GaugeErrors.InvalidAddress();
157: }
158: }
159:
160: rewardTokens.push(newReward);
161:
162: emit AddExtraReward(newReward);
163: }
['168']
168: function removeExtraReward(uint256 index, address newReward) external { // <= FOUND
169: _checkDaoPermissions();
170:
171:
172: if (newReward == cve) {
173: revert GaugeErrors.Unauthorized();
174: }
175:
176: if (newReward != address(rewardTokens[index])) {
177: revert GaugeErrors.InvalidAddress();
178: }
179:
180:
181:
182: uint256 rewardTokensLength = rewardTokens.length;
183: if (index != (rewardTokensLength - 1)) {
184: rewardTokens[index] = rewardTokens[rewardTokensLength - 1];
185: }
186: rewardTokens.pop();
187:
188: emit RemoveExtraReward(newReward);
189: }
['334']
334: function deposit(
335: address token,
336: address user,
337: uint256 amount
338: ) external nonReentrant {
339: if (amount == 0) {
340: revert GaugeErrors.InvalidAmount();
341: }
342:
343:
344:
345: if (
346: msg.sender != token ||
347: !IMarketManager(marketManager).isListed(token)
348: ) {
349: revert GaugeErrors.InvalidToken();
350: }
351:
352: updatePool(token);
353:
354: _calcPending(user, token);
355:
356: balanceOf[token][user] += amount;
357: totalSupply[token] += amount;
358:
359:
360:
361: if (block.timestamp > startTime) {
362:
363:
364: if (firstDeposit == 0) {
365:
366:
367: firstDeposit = block.timestamp;
368: updatePool(token);
369:
370: uint256 rewardTokensLength = rewardTokens.length;
371: for (uint256 i; i < rewardTokensLength; ) {
372:
373: address rewardToken = rewardTokens[i++];
374: uint256 unallocatedRewards = (poolAccRewardPerShare[token][
375: rewardToken
376: ] * totalSupply[token]) / WAD_SQUARED;
377: if (unallocatedRewards > 0) {
378: SafeTransferLib.safeTransfer(
379: rewardToken,
380: centralRegistry.daoAddress(),
381: unallocatedRewards
382: );
383: }
384: }
385: }
386: }
387:
388: _calcDebt(user, token);
389:
390: emit Deposit(user, token, amount);
391: }
['401']
401: function withdraw(
402: address token,
403: address user,
404: uint256 amount
405: ) external nonReentrant {
406: if (amount == 0) {
407: revert GaugeErrors.InvalidAmount();
408: }
409:
410:
411:
412: if (
413: msg.sender != token ||
414: !IMarketManager(marketManager).isListed(token)
415: ) {
416: revert GaugeErrors.InvalidToken();
417: }
418:
419: if (balanceOf[token][user] < amount) {
420: revert GaugeErrors.InvalidAmount();
421: }
422:
423: updatePool(token);
424: _calcPending(user, token);
425:
426: balanceOf[token][user] -= amount;
427: totalSupply[token] -= amount;
428:
429: _calcDebt(user, token);
430:
431: emit Withdraw(user, token, amount);
432: }
['436']
436: function claim(address token) external nonReentrant { // <= FOUND
437: if (block.timestamp < startTime) {
438: revert GaugeErrors.NotStarted();
439: }
440:
441: updatePool(token);
442: _calcPending(msg.sender, token);
443:
444: bool hasRewards;
445: uint256 rewardTokensLength = rewardTokens.length;
446:
447: for (uint256 i; i < rewardTokensLength; ) {
448:
449: address rewardToken = rewardTokens[i++];
450: uint256 rewards = userDebtInfo[token][msg.sender][rewardToken]
451: .rewardPending;
452:
453:
454: if (rewards > 0) {
455: hasRewards = true;
456: SafeTransferLib.safeTransfer(rewardToken, msg.sender, rewards);
457: }
458:
459:
460: userDebtInfo[token][msg.sender][rewardToken].rewardPending = 0;
461: }
462: if (!hasRewards) {
463: revert GaugeErrors.NoReward();
464: }
465:
466: _calcDebt(msg.sender, token);
467:
468: emit Claim(msg.sender, token);
469: }
['482']
482: function claimAndExtendLock(
483: address token,
484: uint256 lockIndex,
485: bool continuousLock,
486: RewardsData memory rewardsData,
487: bytes memory params,
488: uint256 aux
489: ) external nonReentrant {
490:
491:
492: if (block.timestamp < startTime) {
493: revert GaugeErrors.NotStarted();
494: }
495:
496: updatePool(token);
497: _calcPending(msg.sender, token);
498:
499:
500: uint256 rewards = userDebtInfo[token][msg.sender][cve].rewardPending;
501: if (rewards == 0) {
502: revert GaugeErrors.NoReward();
503: }
504:
505:
506: userDebt