Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deploy fee manager v2 #23

Merged
merged 1 commit into from
Oct 9, 2024
Merged

Conversation

hippocampus-web3
Copy link
Collaborator

@hippocampus-web3 hippocampus-web3 commented Oct 8, 2024

Summary by CodeRabbit

  • New Features

    • Updated chaosToken address for the FeeManager contract deployment.
    • Introduced new libraries and interfaces, enhancing smart contract functionality.
  • Bug Fixes

    • Corrected the address for chaosToken in the verification script.
  • Documentation

    • Added comprehensive input settings for Solidity compiler, detailing new libraries and their functions.

Copy link

coderabbitai bot commented Oct 8, 2024

Walkthrough

The pull request introduces a new address for the chaosToken variable in the deployment of the FeeManager contract, replacing the previous zero address. Additionally, a new JSON file is added containing Solidity compiler input settings and source code for several libraries and interfaces, including FullMath and LiquidityAmounts. The verification script for the FeeManager contract is also updated to include the new chaosToken address in its constructor arguments.

Changes

File Path Change Summary
deploy/FeeManager.deploy.ts Updated chaosToken from zero address to 0x6573D177273931c44Aa647DaAF90325545a7fCC4.
deployments/base/solcInputs/b30c00934bcb33ce669789d96b7e32f8.json Added new file with Solidity compiler input settings and source code for FullMath and LiquidityAmounts libraries, as well as interfaces and the FeeManager contract.
scripts/verify/verifyFeeManager.ts Introduced a new chaosToken constant with the updated address and added it to constructorArguments for verification.

Possibly related PRs

  • Add CHAOS reward to current FeeManager #22: The changes in the main PR update the chaosToken variable to a new address, which is directly related to the modifications in the FeeManager contract introduced in this PR, where the chaos token address is also a key component.

Suggested labels

enhancement

Suggested reviewers

  • bitcoinbrisbane

Poem

In the meadow where tokens play,
A new address brightens the day.
With math so full, and liquidity flows,
Our FeeManager proudly grows!
Hops of joy, let’s verify,
With chaos tokens, we reach for the sky! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 84d5236 and 4372797.

📒 Files selected for processing (3)
  • deploy/FeeManager.deploy.ts (1 hunks)
  • deployments/base/solcInputs/b30c00934bcb33ce669789d96b7e32f8.json (1 hunks)
  • scripts/verify/verifyFeeManager.ts (2 hunks)
🧰 Additional context used
🪛 Gitleaks
deploy/FeeManager.deploy.ts

8-8: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

scripts/verify/verifyFeeManager.ts

5-5: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🔇 Additional comments (6)
scripts/verify/verifyFeeManager.ts (2)

5-5: Verify the correctness of the chaosToken address.

The addition of the chaosToken constant with the address "0x6573D177273931c44Aa647DaAF90325545a7fCC4" looks good. However, please ensure that this is the correct address for the intended token on the target network.

Note: The static analysis tool flagged this as a potential API key, but this is a false positive. This is a public Ethereum address, not a sensitive key.

To verify the token contract, you can use the following script:

🧰 Tools
🪛 Gitleaks

5-5: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


14-14: Verify alignment with FeeManager constructor and document the change.

The addition of chaosToken to the constructor arguments is correct if the FeeManager contract has been updated to accept this new parameter. Please ensure that:

  1. The order of arguments matches the updated FeeManager contract constructor.
  2. The contract deployment script (deploy.ts or similar) has also been updated to include this new argument.

Additionally, consider adding a comment explaining the purpose of the chaosToken in the FeeManager contract to improve code maintainability.

To verify the alignment with the FeeManager constructor, you can use the following script:

✅ Verification successful

Constructor alignment verified and documentation suggested.

The chaosToken has been correctly added to the FeeManager constructor arguments in the appropriate position. Additionally, ensure that:

  1. The deployment script (deploy.ts or similar) includes the chaosToken parameter.
  2. Consider adding comments to explain the purpose of chaosToken for better maintainability.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the FeeManager constructor alignment

# Test: Check if the FeeManager contract constructor matches the verification arguments
# Expect: The constructor parameters should include chaosToken in the correct position
ast-grep --lang solidity --pattern $'contract FeeManager {
  constructor($_,$_,$_,$_,$_,$_) {
    $$$
  }
}'

Length of output: 754


Script:

#!/bin/bash
# Description: Verify the FeeManager constructor alignment using ripgrep since ast-grep does not support Solidity

# Locate the FeeManager.sol file
FILE=$(fd -e sol FeeManager.sol)

# Check if the file was found
if [ -z "$FILE" ]; then
  echo "FeeManager.sol not found in the repository."
  exit 1
fi

# Extract the constructor parameters from FeeManager.sol
rg 'constructor\s*\(([^)]*)\)' "$FILE"

Length of output: 374


Script:

#!/bin/bash
# Description: Verify the FeeManager constructor alignment by extracting constructor parameters from the implementation file.

# Locate the FeeManager.sol implementation file
FILE=$(fd -e sol FeeManager.sol contracts/)

# Filter out interface files
IMPLEMENTATION_FILE=$(echo "$FILE" | grep -v '/interfaces/')

# Check if the implementation file was found
if [ -z "$IMPLEMENTATION_FILE" ]; then
  echo "Implementation FeeManager.sol not found in the repository."
  exit 1
fi

# Extract the constructor parameters from the implementation FeeManager.sol
rg 'constructor\s*\(([^)]*)\)' "$IMPLEMENTATION_FILE"

Length of output: 348


Script:

#!/bin/bash
# Description: Enhanced verification of FeeManager constructor alignment with improved ripgrep pattern.

# Locate the FeeManager.sol implementation file
FILE=$(fd -e sol FeeManager.sol contracts/ | grep -v '/interfaces/')

# Check if the implementation file was found
if [ -z "$FILE" ]; then
  echo "Implementation FeeManager.sol not found in the repository."
  exit 1
fi

# Extract the constructor parameters from the implementation FeeManager.sol with an improved pattern
rg -U -i 'constructor\s*(?:public|external|internal|private)?\s*\(([^)]*)\)' "$FILE"

Length of output: 388

deploy/FeeManager.deploy.ts (2)

8-8: Update related scripts and documentation.

With the introduction of the new chaosToken address, please ensure that all related deployment verification scripts, documentation, and any other relevant files are updated to reflect this change.

To check for any potential inconsistencies, run the following script:

#!/bin/bash
# Description: Check for potential inconsistencies with the new chaosToken address

# Test: Look for any hardcoded zero addresses that might need updating
rg --type typescript -A 5 $'0x0000000000000000000000000000000000000000'

# Test: Check for any mentions of 'chaosToken' in other files
rg --type typescript -A 5 -i $'chaosToken'
🧰 Tools
🪛 Gitleaks

8-8: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


8-8: Verify the correctness of the new chaosToken address.

The chaosToken address has been updated from a zero address to 0x6573D177273931c44Aa647DaAF90325545a7fCC4. Please confirm that this is the correct address for the chaosToken on the target network(s).

To ensure the validity of this address, please run the following script:

Note: The static analysis tool flagged this line as potentially exposing an API key, but this appears to be a false positive. This is a contract address, not an API key.

✅ Verification successful

Please run the updated verification scripts below to ensure the correctness of the chaosToken address:


The chaosToken address has been correctly updated and is consistently used across the codebase. The static analysis tool's flag appears to be a false positive, as the address is a contract address, not an API key. No further action is required.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the chaosToken address across different networks

# Test: Check if the address is consistently used across different network configurations
rg --type typescript -A 5 $'0x6573D177273931c44Aa647DaAF90325545a7fCC4'

# Test: Verify if there are any comments or documentation about this address
rg --type typescript -A 5 -i $'chaosToken'

Length of output: 273


Script:

#!/bin/bash
# Description: Verify the chaosToken address across different networks

# Test: Check if the address is consistently used across different network configurations
rg --type ts -A 5 '0x6573D177273931c44Aa647DaAF90325545a7fCC4'

# Test: Verify if there are any comments or documentation about this address
rg --type ts -A 5 -i 'chaosToken'

Length of output: 6721

🧰 Tools
🪛 Gitleaks

8-8: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

deployments/base/solcInputs/b30c00934bcb33ce669789d96b7e32f8.json (2)

1-74: Compiler settings look good.

The compiler settings are well-configured:

  • Solidity version 0.8.13 is used, which is a relatively recent and stable version.
  • The optimizer is enabled with 50 runs, which is a reasonable setting for most contracts.
  • The output selection is comprehensive, including all necessary artifacts for deployment and verification.

These settings should provide a good balance between gas optimization and compilation time.


4-44: Good use of established libraries and well-defined interfaces.

The contract makes use of several well-established libraries and interfaces:

  • OpenZeppelin contracts for standard implementations (e.g., SafeERC20, Ownable)
  • Uniswap V3 interfaces for interaction with the protocol
  • Custom interfaces like IFeeManager are properly defined

The use of these tested and audited libraries enhances the security and reliability of the contract. The inclusion of the TransferHelper library is also a good practice for safe token transfers.

Comment on lines +1 to +74
{
"language": "Solidity",
"sources": {
"@arrakisfi/v3-lib-0.8/contracts/FullMath.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\n/// @title Contains 512-bit math functions\n/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision\n/// @dev Handles \"phantom overflow\" i.e., allows multiplication and division where an intermediate value overflows 256 bits\nlibrary FullMath {\n /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n /// @param a The multiplicand\n /// @param b The multiplier\n /// @param denominator The divisor\n /// @return result The 256-bit result\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv\n function mulDiv(\n uint256 a,\n uint256 b,\n uint256 denominator\n ) internal pure returns (uint256 result) {\n unchecked {\n // 512-bit multiply [prod1 prod0] = a * b\n // Compute the product mod 2**256 and mod 2**256 - 1\n // then use the Chinese Remainder Theorem to reconstruct\n // the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2**256 + prod0\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(a, b, not(0))\n prod0 := mul(a, b)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division\n if (prod1 == 0) {\n require(denominator > 0);\n assembly {\n result := div(prod0, denominator)\n }\n return result;\n }\n\n // Make sure the result is less than 2**256.\n // Also prevents denominator == 0\n require(denominator > prod1);\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0]\n // Compute remainder using mulmod\n uint256 remainder;\n assembly {\n remainder := mulmod(a, b, denominator)\n }\n // Subtract 256 bit number from 512 bit number\n assembly {\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator\n // Compute largest power of two divisor of denominator.\n // Always >= 1.\n // EDIT for 0.8 compatibility:\n // see: https://ethereum.stackexchange.com/questions/96642/unary-operator-cannot-be-applied-to-type-uint256\n uint256 twos = denominator & (~denominator + 1);\n\n // Divide denominator by power of two\n assembly {\n denominator := div(denominator, twos)\n }\n\n // Divide [prod1 prod0] by the factors of two\n assembly {\n prod0 := div(prod0, twos)\n }\n // Shift in bits from prod1 into prod0. For this we need\n // to flip `twos` such that it is 2**256 / twos.\n // If twos is zero, then it becomes one\n assembly {\n twos := add(div(sub(0, twos), twos), 1)\n }\n prod0 |= prod1 * twos;\n\n // Invert denominator mod 2**256\n // Now that denominator is an odd number, it has an inverse\n // modulo 2**256 such that denominator * inv = 1 mod 2**256.\n // Compute the inverse by starting with a seed that is correct\n // correct for four bits. That is, denominator * inv = 1 mod 2**4\n uint256 inv = (3 * denominator) ^ 2;\n // Now use Newton-Raphson iteration to improve the precision.\n // Thanks to Hensel's lifting lemma, this also works in modular\n // arithmetic, doubling the correct bits in each step.\n inv *= 2 - denominator * inv; // inverse mod 2**8\n inv *= 2 - denominator * inv; // inverse mod 2**16\n inv *= 2 - denominator * inv; // inverse mod 2**32\n inv *= 2 - denominator * inv; // inverse mod 2**64\n inv *= 2 - denominator * inv; // inverse mod 2**128\n inv *= 2 - denominator * inv; // inverse mod 2**256\n\n // Because the division is now exact we can divide by multiplying\n // with the modular inverse of denominator. This will give us the\n // correct result modulo 2**256. Since the precoditions guarantee\n // that the outcome is less than 2**256, this is the final result.\n // We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inv;\n return result;\n }\n }\n\n /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n /// @param a The multiplicand\n /// @param b The multiplier\n /// @param denominator The divisor\n /// @return result The 256-bit result\n function mulDivRoundingUp(\n uint256 a,\n uint256 b,\n uint256 denominator\n ) internal pure returns (uint256 result) {\n result = mulDiv(a, b, denominator);\n if (mulmod(a, b, denominator) > 0) {\n require(result < type(uint256).max);\n result++;\n }\n }\n}\n"
},
"@arrakisfi/v3-lib-0.8/contracts/LiquidityAmounts.sol": {
"content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.8.0;\nimport {FullMath} from \"./FullMath.sol\";\nimport {FixedPoint96} from \"@uniswap/v3-core/contracts/libraries/FixedPoint96.sol\";\n\n/// @title Liquidity amount functions\n/// @notice Provides functions for computing liquidity amounts from token amounts and prices\nlibrary LiquidityAmounts {\n function toUint128(uint256 x) private pure returns (uint128 y) {\n require((y = uint128(x)) == x);\n }\n\n /// @notice Computes the amount of liquidity received for a given amount of token0 and price range\n /// @dev Calculates amount0 * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower)).\n /// @param sqrtRatioAX96 A sqrt price\n /// @param sqrtRatioBX96 Another sqrt price\n /// @param amount0 The amount0 being sent in\n /// @return liquidity The amount of returned liquidity\n function getLiquidityForAmount0(\n uint160 sqrtRatioAX96,\n uint160 sqrtRatioBX96,\n uint256 amount0\n ) internal pure returns (uint128 liquidity) {\n if (sqrtRatioAX96 > sqrtRatioBX96)\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\n uint256 intermediate = FullMath.mulDiv(\n sqrtRatioAX96,\n sqrtRatioBX96,\n FixedPoint96.Q96\n );\n return\n toUint128(\n FullMath.mulDiv(\n amount0,\n intermediate,\n sqrtRatioBX96 - sqrtRatioAX96\n )\n );\n }\n\n /// @notice Computes the amount of liquidity received for a given amount of token1 and price range\n /// @dev Calculates amount1 / (sqrt(upper) - sqrt(lower)).\n /// @param sqrtRatioAX96 A sqrt price\n /// @param sqrtRatioBX96 Another sqrt price\n /// @param amount1 The amount1 being sent in\n /// @return liquidity The amount of returned liquidity\n function getLiquidityForAmount1(\n uint160 sqrtRatioAX96,\n uint160 sqrtRatioBX96,\n uint256 amount1\n ) internal pure returns (uint128 liquidity) {\n if (sqrtRatioAX96 > sqrtRatioBX96)\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\n return\n toUint128(\n FullMath.mulDiv(\n amount1,\n FixedPoint96.Q96,\n sqrtRatioBX96 - sqrtRatioAX96\n )\n );\n }\n\n /// @notice Computes the maximum amount of liquidity received for a given amount of token0, token1, the current\n /// pool prices and the prices at the tick boundaries\n function getLiquidityForAmounts(\n uint160 sqrtRatioX96,\n uint160 sqrtRatioAX96,\n uint160 sqrtRatioBX96,\n uint256 amount0,\n uint256 amount1\n ) internal pure returns (uint128 liquidity) {\n if (sqrtRatioAX96 > sqrtRatioBX96)\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\n\n if (sqrtRatioX96 <= sqrtRatioAX96) {\n liquidity = getLiquidityForAmount0(\n sqrtRatioAX96,\n sqrtRatioBX96,\n amount0\n );\n } else if (sqrtRatioX96 < sqrtRatioBX96) {\n uint128 liquidity0 = getLiquidityForAmount0(\n sqrtRatioX96,\n sqrtRatioBX96,\n amount0\n );\n uint128 liquidity1 = getLiquidityForAmount1(\n sqrtRatioAX96,\n sqrtRatioX96,\n amount1\n );\n\n liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1;\n } else {\n liquidity = getLiquidityForAmount1(\n sqrtRatioAX96,\n sqrtRatioBX96,\n amount1\n );\n }\n }\n\n /// @notice Computes the amount of token0 for a given amount of liquidity and a price range\n /// @param sqrtRatioAX96 A sqrt price\n /// @param sqrtRatioBX96 Another sqrt price\n /// @param liquidity The liquidity being valued\n /// @return amount0 The amount0\n function getAmount0ForLiquidity(\n uint160 sqrtRatioAX96,\n uint160 sqrtRatioBX96,\n uint128 liquidity\n ) internal pure returns (uint256 amount0) {\n if (sqrtRatioAX96 > sqrtRatioBX96)\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\n\n return\n FullMath.mulDiv(\n uint256(liquidity) << FixedPoint96.RESOLUTION,\n sqrtRatioBX96 - sqrtRatioAX96,\n sqrtRatioBX96\n ) / sqrtRatioAX96;\n }\n\n /// @notice Computes the amount of token1 for a given amount of liquidity and a price range\n /// @param sqrtRatioAX96 A sqrt price\n /// @param sqrtRatioBX96 Another sqrt price\n /// @param liquidity The liquidity being valued\n /// @return amount1 The amount1\n function getAmount1ForLiquidity(\n uint160 sqrtRatioAX96,\n uint160 sqrtRatioBX96,\n uint128 liquidity\n ) internal pure returns (uint256 amount1) {\n if (sqrtRatioAX96 > sqrtRatioBX96)\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\n\n return\n FullMath.mulDiv(\n liquidity,\n sqrtRatioBX96 - sqrtRatioAX96,\n FixedPoint96.Q96\n );\n }\n\n /// @notice Computes the token0 and token1 value for a given amount of liquidity, the current\n /// pool prices and the prices at the tick boundaries\n function getAmountsForLiquidity(\n uint160 sqrtRatioX96,\n uint160 sqrtRatioAX96,\n uint160 sqrtRatioBX96,\n uint128 liquidity\n ) internal pure returns (uint256 amount0, uint256 amount1) {\n if (sqrtRatioAX96 > sqrtRatioBX96)\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\n\n if (sqrtRatioX96 <= sqrtRatioAX96) {\n amount0 = getAmount0ForLiquidity(\n sqrtRatioAX96,\n sqrtRatioBX96,\n liquidity\n );\n } else if (sqrtRatioX96 < sqrtRatioBX96) {\n amount0 = getAmount0ForLiquidity(\n sqrtRatioX96,\n sqrtRatioBX96,\n liquidity\n );\n amount1 = getAmount1ForLiquidity(\n sqrtRatioAX96,\n sqrtRatioX96,\n liquidity\n );\n } else {\n amount1 = getAmount1ForLiquidity(\n sqrtRatioAX96,\n sqrtRatioBX96,\n liquidity\n );\n }\n }\n}\n"
},
"@openzeppelin/contracts/access/Ownable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n"
},
"@openzeppelin/contracts/token/ERC20/IERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n"
},
"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n"
},
"@openzeppelin/contracts/utils/Address.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n"
},
"@openzeppelin/contracts/utils/Context.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n"
},
"@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol": {
"content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\n/// @title Callback for IUniswapV3PoolActions#swap\n/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface\ninterface IUniswapV3SwapCallback {\n /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.\n /// @dev In the implementation you must pay the pool tokens owed for the swap.\n /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.\n /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.\n /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by\n /// the end of the swap. If positive, the callback must send that amount of token0 to the pool.\n /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by\n /// the end of the swap. If positive, the callback must send that amount of token1 to the pool.\n /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call\n function uniswapV3SwapCallback(\n int256 amount0Delta,\n int256 amount1Delta,\n bytes calldata data\n ) external;\n}\n"
},
"@uniswap/v3-core/contracts/libraries/FixedPoint96.sol": {
"content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.4.0;\n\n/// @title FixedPoint96\n/// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format)\n/// @dev Used in SqrtPriceMath.sol\nlibrary FixedPoint96 {\n uint8 internal constant RESOLUTION = 96;\n uint256 internal constant Q96 = 0x1000000000000000000000000;\n}\n"
},
"contracts/FeeManager.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.13;\n\nimport {IFeeManager} from \"./interfaces/IFeeManager.sol\";\nimport {FullMath} from \"@arrakisfi/v3-lib-0.8/contracts/LiquidityAmounts.sol\";\nimport {\n IERC20,\n SafeERC20\n} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {IV3SwapRouter} from \"./univ3-0.8/IV3SwapRouter.sol\";\nimport {ISwapRouter02} from \"./univ3-0.8/ISwapRouter02.sol\";\nimport {TransferHelper} from \"./univ3-0.8/TransferHelper.sol\";\nimport {Ownable} from \"@openzeppelin/contracts/access/Ownable.sol\";\n\ncontract FeeManager is IFeeManager, Ownable {\n using SafeERC20 for IERC20;\n\n uint256 public rate;\n IERC20 public immutable chaos;\n IERC20 public immutable vault;\n IERC20 public immutable usdc;\n ISwapRouter02 public immutable router;\n uint256 public accumulatedRewardsPerShare;\n mapping(address => uint256) public rewardDebt;\n uint256 public constant REWARDS_PRECISION = 1e24;\n uint8 private constant _USDC_DECIMALS = 6;\n uint8 private constant _CHAOS_DECIMALS = 18;\n uint24 public immutable feeTier;\n\n event RewardsClaimed(\n address indexed user,\n uint256 usdcAmount,\n uint256 chaosAmount\n );\n\n event RewardsConvertedToUsdc(\n uint256 usdcAmount\n );\n\n modifier onlyVault() {\n require(address(vault) == msg.sender, \"Only vault can call\");\n _;\n }\n\n constructor(\n address vault_,\n address usdc_,\n address chaos_,\n address uniSwapRouter_,\n uint24 feeTier_\n ) {\n require(vault_ != address(0), \"FeeManager: Invalid vault_ address\");\n require(usdc_ != address(0), \"FeeManager: Invalid usdc_ address\");\n require(\n uniSwapRouter_ != address(0),\n \"FeeManager: uniSwapRouter_ address\"\n );\n feeTier = feeTier_;\n vault = IERC20(vault_);\n usdc = IERC20(usdc_);\n chaos = IERC20(chaos_);\n router = ISwapRouter02(uniSwapRouter_);\n\n transferOwnership(msg.sender);\n }\n\n /// @dev Emergency withdraw only called by owner\n function withdrawEmergency() external onlyOwner {\n uint256 balance = usdc.balanceOf(address(this));\n require(balance > 0, \"FeeManager: No USDC to withdraw\");\n usdc.safeTransfer(owner(), balance);\n }\n\n function withdrawalChaos() external onlyOwner {\n uint256 balance = chaos.balanceOf(address(this));\n require(balance > 0, \"FeeManager: No balance to withdrawal\");\n IERC20(chaos).transfer(owner(), balance);\n }\n\n function setRate(uint256 newRate) external onlyOwner {\n rate = newRate;\n }\n\n function setRewardDebt(address _user, uint256 _amount) external onlyVault {\n rewardDebt[_user] = _amount;\n }\n\n function depositFees(\n address token0,\n uint256 fees0,\n address token1,\n uint256 fees1\n ) public onlyVault {\n if (fees0 > 0) {\n IERC20(token0).safeTransferFrom(\n address(vault),\n address(this),\n fees0\n );\n }\n if (fees1 > 0) {\n IERC20(token1).safeTransferFrom(\n address(vault),\n address(this),\n fees1\n );\n }\n uint256 rewards = _convertFeesToUSDC(token0, fees0, token1, fees1);\n accumulatedRewardsPerShare =\n accumulatedRewardsPerShare +\n FullMath.mulDiv(rewards, REWARDS_PRECISION, vault.totalSupply());\n\n emit RewardsConvertedToUsdc(rewards);\n }\n\n function claimFees(address claimer) public {\n uint256 userBalance = vault.balanceOf(claimer);\n uint256 totalReward = FullMath.mulDiv(\n userBalance,\n accumulatedRewardsPerShare,\n REWARDS_PRECISION\n );\n uint256 rewardsToHarvest = totalReward - rewardDebt[claimer];\n\n if (rewardsToHarvest == 0) {\n rewardDebt[claimer] = totalReward;\n return;\n }\n\n rewardDebt[claimer] = totalReward;\n\n uint256 rewardsToHarvestInChaos = (rewardsToHarvest *\n rate *\n 10**(_CHAOS_DECIMALS - _USDC_DECIMALS)) / 100;\n\n usdc.safeTransfer(claimer, rewardsToHarvest);\n\n if (rewardsToHarvestInChaos > 0) {\n chaos.safeTransfer(claimer, rewardsToHarvestInChaos);\n }\n\n emit RewardsClaimed(claimer, rewardsToHarvest, rewardsToHarvestInChaos);\n }\n\n function _swapToUSDC(address token, uint256 feesToken)\n private\n returns (uint256 feesUSDC)\n {\n if (feesToken == 0) {\n return 0;\n }\n\n TransferHelper.safeApprove(token, address(router), feesToken);\n\n IV3SwapRouter.ExactInputSingleParams memory params = IV3SwapRouter\n .ExactInputSingleParams({\n tokenIn: address(token),\n tokenOut: address(usdc),\n fee: feeTier,\n recipient: address(this),\n amountIn: feesToken,\n amountOutMinimum: 0,\n sqrtPriceLimitX96: 0\n });\n\n feesUSDC = router.exactInputSingle(params);\n }\n\n function _convertFeesToUSDC(\n address token0,\n uint256 fee0,\n address token1,\n uint256 fee1\n ) private returns (uint256 usdcFee) {\n if (address(token0) != address(usdc)) {\n usdcFee += _swapToUSDC(address(token0), fee0);\n } else {\n usdcFee += fee0;\n }\n if (address(token1) != address(usdc)) {\n usdcFee += _swapToUSDC(address(token1), fee1);\n } else {\n usdcFee += fee1;\n }\n }\n}\n"
},
"contracts/interfaces/IFeeManager.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.13;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IFeeManager {\n // Getter for the vault address\n function vault() external view returns (IERC20);\n\n // Getter for the USDC address\n function usdc() external view returns (IERC20);\n\n // Getter for accumulatedRewardsPerShare\n function accumulatedRewardsPerShare() external view returns (uint256);\n\n // Getter for a user's rewardDebt\n function rewardDebt(address _user) external view returns (uint256);\n\n // Getter for REWARDS_PRECISION\n function REWARDS_PRECISION() external view returns (uint256);\n\n // Function to emergency withdraw all the USDC of the contract (Only Owner)\n function withdrawEmergency() external;\n\n // Function to withdraw all CHAOS of the contract (Only Owner)\n function withdrawalChaos() external;\n\n // Set conversion rate between USDC and CHAOS (Only Owner)\n function setRate(uint256 rate) external;\n\n // Setter for a user's rewardDebt (can only be called by the vault)\n function setRewardDebt(address _user, uint256 _amount) external;\n\n // Function for users to claim their fees\n function claimFees(address claimer) external;\n\n // Function to deposit fees, can only be called by the vault\n function depositFees(\n address token0,\n uint256 fees0,\n address token1,\n uint256 fees1\n ) external;\n}\n"
},
"contracts/univ3-0.8/ISwapRouter02.sol": {
"content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.13;\npragma abicoder v2;\n\nimport \"./IV3SwapRouter.sol\";\n\n/// @title Router token swapping functionality\ninterface ISwapRouter02 is IV3SwapRouter {\n\n}\n"
},
"contracts/univ3-0.8/IV3SwapRouter.sol": {
"content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.13;\npragma abicoder v2;\n\nimport \"@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol\";\n\n/// @title Router token swapping functionality\n/// @notice Functions for swapping tokens via Uniswap V3\ninterface IV3SwapRouter is IUniswapV3SwapCallback {\n struct ExactInputSingleParams {\n address tokenIn;\n address tokenOut;\n uint24 fee;\n address recipient;\n uint256 amountIn;\n uint256 amountOutMinimum;\n uint160 sqrtPriceLimitX96;\n }\n\n struct ExactInputParams {\n bytes path;\n address recipient;\n uint256 amountIn;\n uint256 amountOutMinimum;\n }\n\n /// @notice Swaps `amountIn` of one token for as much as possible of another token\n /// @dev Setting `amountIn` to 0 will cause the contract to look up its own balance,\n /// and swap the entire amount, enabling contracts to send tokens before calling this function.\n /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata\n /// @return amountOut The amount of the received token\n function exactInputSingle(ExactInputSingleParams calldata params)\n external\n payable\n returns (uint256 amountOut);\n}\n"
},
"contracts/univ3-0.8/TransferHelper.sol": {
"content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.13;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nlibrary TransferHelper {\n /// @notice Approves the stipulated contract to spend the given allowance in the given token\n /// @dev Errors with 'SA' if transfer fails\n /// @param token The contract address of the token to be approved\n /// @param to The target of the approval\n /// @param value The amount of the given token the target will be allowed to spend\n function safeApprove(\n address token,\n address to,\n uint256 value\n ) internal {\n (bool success, bytes memory data) = token.call(\n abi.encodeWithSelector(IERC20.approve.selector, to, value)\n );\n require(\n success && (data.length == 0 || abi.decode(data, (bool))),\n \"SA\"\n );\n }\n}\n"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 50
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"devdoc",
"userdoc",
"storageLayout",
"evm.gasEstimates"
],
"": [
"ast"
]
}
},
"metadata": {
"useLiteralContent": true
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Overall, the FeeManager contract is well-structured but has critical areas that need improvement.

Positive aspects:

  1. Use of Established Libraries: Integrates reputable libraries like OpenZeppelin and Uniswap V3, ensuring reliable and tested functionality.
  2. Proper Access Control: Implements the Ownable pattern and custom modifiers (onlyVault) to restrict function access appropriately.
  3. Secure Token Transfers: Utilizes SafeERC20 for all token transfer operations, enhancing security against potential token transfer issues.
  4. High Precision Calculations: Uses a REWARDS_PRECISION constant set to 1e24 to ensure precise reward calculations and minimize rounding errors.

Main points to address:

  1. Safeguards for Emergency Withdrawals:

    • Current State: Emergency withdrawal functions (withdrawEmergency and withdrawalChaos) are restricted to onlyOwner, which centralizes control.
    • Recommendation: Implement additional safeguards such as multi-signature ownership or timelocks to mitigate centralization risks and enhance trustworthiness.
  2. Bounds Checking in setRate Function:

    • Current State: The setRate function allows setting the rate without any bounds, posing a risk of setting extreme or malicious values.
    • Recommendation: Introduce validation checks to ensure that the rate remains within a reasonable and predefined range, preventing potential disruptions in reward mechanisms.
  3. Slippage Protection in _swapToUSDC Function:

    • Current State: The _swapToUSDC function sets amountOutMinimum and sqrtPriceLimitX96 to 0, effectively removing any slippage protection.
    • Recommendation: Implement slippage guards by setting sensible amountOutMinimum values based on current market conditions to protect users from unexpected losses during token swaps.

Addressing these issues will significantly enhance the security, reliability, and trustworthiness of the FeeManager contract.

🔗 Analysis chain

Overall, the FeeManager contract is well-structured but has room for improvement.

Positive aspects:

  1. Good use of established libraries (OpenZeppelin, Uniswap V3) and well-defined interfaces.
  2. Proper access control using Ownable pattern and custom modifiers.
  3. Use of SafeERC20 for secure token transfers.
  4. High precision (1e24) for rewards calculations to prevent rounding errors.

Main points to address:

  1. Implement safeguards for the emergency withdrawal function to mitigate centralization risks.
  2. Add bounds checking to the setRate function to prevent setting extreme values.
  3. Implement slippage protection in the _swapToUSDC function to protect users from unexpected losses during token swaps.

Addressing these issues will significantly improve the security and reliability of the contract.

To ensure the contract behaves as expected, consider running the following tests:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify the use of SafeERC20 for token transfers
rg --type solidity 'using SafeERC20 for IERC20'

# Check for the presence of access control modifiers
rg --type solidity 'onlyOwner|onlyVault'

# Verify the REWARDS_PRECISION constant
rg --type solidity 'REWARDS_PRECISION = 1e24'

# Look for potential centralization risks in withdrawal functions
rg --type solidity -A 5 'function withdraw'

# Check for bounds in the setRate function
rg --type solidity -A 5 'function setRate'

# Examine the _swapToUSDC function for slippage protection
rg --type solidity -A 10 'function _swapToUSDC'

Length of output: 479


Script:

#!/bin/bash
# Verify the use of SafeERC20 for token transfers
rg --glob '*.sol' 'using SafeERC20 for IERC20'

# Check for the presence of access control modifiers
rg --glob '*.sol' 'onlyOwner|onlyVault'

# Verify the REWARDS_PRECISION constant
rg --glob '*.sol' 'REWARDS_PRECISION\s*=\s*1e24'

# Look for potential centralization risks in withdrawal functions
rg --glob '*.sol' -A 5 'function withdraw'

# Check for bounds in the setRate function
rg --glob '*.sol' -A 5 'function setRate'

# Examine the _swapToUSDC function for slippage protection
rg --glob '*.sol' -A 10 'function _swapToUSDC'

Length of output: 5737

@bitcoinbrisbane bitcoinbrisbane merged commit 619be58 into main Oct 9, 2024
2 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Oct 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants