diff --git a/client/library/library/audits/sevenSeas-50.html b/client/library/library/audits/sevenSeas-50.html
new file mode 100644
index 00000000..41eb5cfa
--- /dev/null
+++ b/client/library/library/audits/sevenSeas-50.html
@@ -0,0 +1,54 @@
+
+
+
+ The security audit performed by the Macro security team over multiple days starting June 16th-20th, 2025.
+
+
+
+
+ - Discussions with the {{page.clientName}} team.
+ - Available documentation in the repository.
+
+
+
+
+ ## Trusted Entities:
+ Solver: Executes users signed intents to deposit or withdraw from the vault. They are trusted to execute these orders in a timely manner.
+
+ Strategist: Can call [rebalance()](https://github.com/Veda-Labs/flux/blob/2085f721c4a2d66b41b2d6411115aa4f2759788d/src/managers/UniswapV4FluxManager.sol#L221-L315) to adjust assets in the vault. Allows them to swap tokens via accepted aggregators or directly with the corresponding uniswapV4 pool, as well as provide or remove liquidity. A portion of the profits from these rebalances, typically via rewards earned by providing liquidity, are distributed to the set `payout` address. It is trusted that they act in the best interest of the protocol, and to not manipulate the vault to extract profit.
+
+ Admin: Can set the rebalance deviations, performance fees, payout address, the price oracle and trusted aggregators, Is trusted to set reasonable values, and set proper aggregators and price oracles. It is understood that a malicious aggregator or oracle could be used to extract value from the vault.
+
+ Multisig: Can pause and unpause the Intents teller and the flux manager, preventing deposits, withdrawals or rebalancing. They are trusted to only pause these contracts when necessary.
+
+ Owner: Can set deposit and withdrawal asset data, share lock period and intent max deadlines, as well as control permissioned operators as well as allowing and denying transfers for select users. They are trusted to set proper values that benefit the protocol, as well as only freeze transfers of those that are adversely effecting the protocol or its users.
+
+ Denier: Can allow or deny users and operators to transfer shares. Like the owner is trusted to only freeze a users assets when necessary and in the interest of the protocol.
+
+
+
+
+
+
+ -
+ Commit Hash:
2085f721c4a2d66b41b2d6411115aa4f2759788d
+
+ 68b602725125a157c3082905e18c9d779451ca3b197f6502807cace96ad2a141 src/datums/ChainlinkDatum.sol
+ 2ccc468b04d7fe0784f1aab6c3bbc1003b1ed029eb9111764e06f7f33afce119 src/managers/FluxManager.sol
+ de5b12678a827c5e44324abccff7f5aa6e8eb866716945006f77d0dec643f431 src/managers/UniswapV4FluxManager.sol
+ e78f1de1061ca64c3c0637e5a3f84a28757e22267144014cfad850da344f4fa8 src/tellers/IntentsTeller.sol
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/content/collections/public/sevenSeas-50-issues.html b/content/collections/public/sevenSeas-50-issues.html
new file mode 100644
index 00000000..b6415908
--- /dev/null
+++ b/content/collections/public/sevenSeas-50-issues.html
@@ -0,0 +1,420 @@
+-
+ Protocol Design
+ high
+ high
+ fixed
+ 76c3f12f42ba79b97e086dcb2a21e01506db7f9b
+
+ ## [H-1] Shares may not be locked for receiver on deposit
+
+ When a deposit intent is fulfilled by the solver, the user that signed the intent pays the required assets, and a shareLock period is set for this user if the share locking is enforced:
+
+ ```solidity
+ if (enforceShareLock) {
+ _afterPublicDeposit(depositData.user, depositData.asset, depositData.amountIn, shares, shareLockPeriod);
+ ```
+ Reference: [IntentsTeller.sol#L546-547](https://github.com/Veda-Labs/flux/blob/2085f721c4a2d66b41b2d6411115aa4f2759788d/src/tellers/IntentsTeller.sol#L546-L547)
+
+ ```solidity
+ function _afterPublicDeposit(
+ address user,
+ ERC20 depositAsset,
+ uint256 depositAmount,
+ uint256 shares,
+ uint256 currentShareLockPeriod
+ ) internal {
+ // Increment then assign as its slightly more gas efficient.
+ uint256 nonce = ++depositNonce;
+ // Only set share unlock time and history if share lock period is greater than 0.
+ if (currentShareLockPeriod > 0) {
+ beforeTransferData[user].shareUnlockTime = uint64(block.timestamp + currentShareLockPeriod);
+ publicDepositHistory[nonce] = keccak256(
+ abi.encode(user, depositAsset, depositAmount, shares, block.timestamp, currentShareLockPeriod)
+ );
+ }
+ emit Deposit(nonce, user, address(depositAsset), depositAmount, shares, block.timestamp, currentShareLockPeriod);
+ }
+ ```
+ Reference: [IntentsTeller#L590-607](https://github.com/Veda-Labs/flux/blob/2085f721c4a2d66b41b2d6411115aa4f2759788d/src/tellers/IntentsTeller.sol#L590-L607)
+
+ When a users shares are locked, it prevents shares from being transferred until the period has elapsed. The intent of this is to prevent users from withdrawing immediately and potentially take advantage of arbitrage opportunities, or take short term profit in volatile events of price swings.
+
+ However, a deposit does not always result in the users receiving the shares, as they can specify a `to` address which is the receiver when calling `boringVault.enter()`:
+
+ ```solidity
+ vault.enter(depositData.user, depositData.asset, depositData.amountIn, depositData.to, shares);
+ ```
+
+ Reference: [IntentsTeller.sol#544](https://github.com/Veda-Labs/flux/blob/2085f721c4a2d66b41b2d6411115aa4f2759788d/src/tellers/IntentsTeller.sol#L544)
+
+ This means that if the user and the receiving to address differ, the receiver is able to bypass the share lock period and thus able to freely transfer and withdraw immediately after receiving their assets.
+
+ **Remediations to Consider**
+
+ Do not allow a receiving address to be specified, and send shares to the user instead. Otherwise if you allow a specified receiver and lock their shares as intended it opens up griefing vectors.
+
+
+
+
+ -
+ DOS
+ high
+ high
+ fixed
+ f7c0051a2d84bbf16f7d55daaded80ed1e7fd25a
+
+ ## [H-2] Native token operations will consistently fail
+
+ The `IntentsTeller` contract is designed to facilitate deposits and withdrawals for `token0` and `token1` as defined by its associated `fluxManager`. However, if `token0` is configured to be the native token (represented by `address(0)`), all deposit and withdrawal operations for this asset will fail.
+
+ The root cause of this issue lies within the [`_erc20Deposit()`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/tellers/IntentsTeller.sol#L525) and [`_erc20Withdraw()`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/tellers/IntentsTeller.sol#L553) functions in `IntentsTeller` contract. These functions directly pass the asset's address from `ActionData` to the `enter()` and `exit()` functions of the `BoringVault` contract.
+
+ The `BoringVault` contract's `enter()` and `exit()` methods are designed to work exclusively with ERC20 tokens. They execute `asset.safeTransferFrom()` and `asset.safeTransfer()` respectively. When `depositData.asset` or `withdrawData.asset` is `address(0)`, these calls will revert because `address(0)` is not a contract and has no functions to call.
+
+ The highest impact scenario occurs when the contract is deployed with the native token as one of the core assets in the liquidity pool. This would render the primary functionality of depositing and withdrawing that native asset completely inoperable.
+
+ **Remediations to Consider**
+
+ To support native assets, the logic in `_erc20Deposit()` and `_erc20Withdraw()` should be updated. When `depositData.asset` corresponds to the native token, the contract should instead use its wrapped ERC20 counterpart (e.g., WETH) for interactions with the `BoringVault`.
+
+ ```diff
+ vault.enter(
+ depositData.user,
+ - depositData.asset,
+ + depositData.asset == address(0) ? nativeWrapper : depositData.asset,
+ depositData.amountIn,
+ depositData.to,
+ shares
+ );
+
+ vault.exit(
+ withdrawData.to,
+ - withdrawData.asset,
+ + withdrawData.asset == address(0) ? nativeWrapper : withdrawData.asset,
+ assetsOut,
+ withdrawData.user,
+ withdrawData.amountIn
+ );
+ ```
+
+
+
+ -
+ Signatures
+ high
+ low
+ fixed
+ e8628d0e7556ad37d55ecced5ebba9e682046550
+
+ ## [M-1] Signed intents can be used for either deposit or withdrawals
+
+ [ActionData](https://github.com/Veda-Labs/flux/blob/2085f721c4a2d66b41b2d6411115aa4f2759788d/src/tellers/IntentsTeller.sol#L33-L55) is signed by users to define their intent of depositing or withdrawing and their acceptable parameters. This is then used by a address with the Solver permission to call either [deposit()](https://github.com/Veda-Labs/flux/blob/2085f721c4a2d66b41b2d6411115aa4f2759788d/src/tellers/IntentsTeller.sol#L463-L477) or [withdraw()](https://github.com/Veda-Labs/flux/blob/2085f721c4a2d66b41b2d6411115aa4f2759788d/src/tellers/IntentsTeller.sol#L479-L488). Each validates that intents data user signed it, and hasn’t been used prior, before executing it. Notably the value `isWithdrawal` is signed and verified in [_verifySignedMessage()](https://github.com/Veda-Labs/flux/blob/2085f721c4a2d66b41b2d6411115aa4f2759788d/src/tellers/IntentsTeller.sol#L609-L642), however it is not used to check if the intended function [deposit()](https://github.com/Veda-Labs/flux/blob/2085f721c4a2d66b41b2d6411115aa4f2759788d/src/tellers/IntentsTeller.sol#L463-L477) or [withdraw()](https://github.com/Veda-Labs/flux/blob/2085f721c4a2d66b41b2d6411115aa4f2759788d/src/tellers/IntentsTeller.sol#L479-L488) is executing either. This allows for the solver to ignore the `isWithdrawal` intent and call either function. Typically the Solver is trusted to execute these intents as intended, if a solver were to call the wrong function it would likely be detrimental to the user.
+
+ **Remediations to Consider**
+
+ Validate the intended function, [deposit()](https://github.com/Veda-Labs/flux/blob/2085f721c4a2d66b41b2d6411115aa4f2759788d/src/tellers/IntentsTeller.sol#L463-L477) or [withdraw()](https://github.com/Veda-Labs/flux/blob/2085f721c4a2d66b41b2d6411115aa4f2759788d/src/tellers/IntentsTeller.sol#L479-L488) is called based on the `isWithdrawal` value.
+
+
+
+
+ -
+ Fee Mechanism
+ high
+ low
+ fixed
+ 5426f94f0fa85580da70c1e99506fe3e46bbd138
+
+ ## [M-2] Incorrect asset denomination in fee claiming leads to fund misappropriation
+
+ There is a discrepancy between how performance fees are calculated and claimed. The `pendingFee` is calculated in `rebalance()` [based on the immutable `baseIn0Or1` flag](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/managers/UniswapV4FluxManager.sol#L308-L312), which determines whether the fee is denominated in `token0` or `token1`. However, the [`claimFees()`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/managers/FluxManager.sol#L139) function takes a `token0Or1` parameter that allows the fee to be paid out in an asset independent of how it was calculated. This allows an admin to withdraw fees in the wrong asset, leading to a misinterpretation of value due to differing token decimals and prices. As the result, admin may mistakenly claim more or less value as fee than expected. Moreover, in extreme case that admin claim way more than expected, it can massively drop the price of BoringVault share.
+
+ **Remediations to Consider**
+
+ The `claimFees()` function should not accept a parameter for the token type. It should instead use the `baseIn0Or1` flag to ensure fees are always claimed in the same asset they were denominated in.
+
+
+
+
+ -
+ Type Mismatch
+ medium
+ low
+ fixed
+ 5426f94f0fa85580da70c1e99506fe3e46bbd138
+
+ ## [L-1] Mismatched data types in function parameters may lead to unexpected behaviour
+
+ The [`_mint()`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/managers/UniswapV4FluxManager.sol#L352) function in the `UniswapV4FluxManager` contract defines parameters with data types that are inconsistent with the official [Uniswap V4 documentation](https://docs.uniswap.org/contracts/v4/quickstart/manage-liquidity/mint-position#3-encode-parameters).
+
+ In `_mint()` function, the `liquidity` parameter is `uint128` while the documentation specifies `uint256`. This unnecessarily restricts the amount of liquidity that can be added.
+
+ Conversely, `amount0Max` and `amount1Max` are `uint256` instead of `uint128`. When decoding, Uniswap uses a [low-level method](https://github.com/Uniswap/v4-periphery/blob/ad04c9f24a170accf5ea1b2836bbafd514537ca6/src/libraries/CalldataDecoder.sol#L107-L132) instead of a standard `abi.decode`. This means that when the values are greater than `type(uint128).max`, instead of throwing an error, Uniswap will use the 128 least significant bits. As a result, this can lead to unexpected values for `amount0Max` and `amount1Max`.
+
+ Other functions like [`_burn()`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/managers/UniswapV4FluxManager.sol#L379), [`_increaseLiquidity()`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/managers/UniswapV4FluxManager.sol#L391), and [`_decreaseLiquidity()`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/managers/UniswapV4FluxManager.sol#L413) are also affected by similar issues.
+
+ **Remediations to Consider**
+ Align the data types in the `_mint()`, `_burn()`, `_increaseLiquidity()`, and `_decreaseLiquidity()` functions with the Uniswap V4 documentation.
+
+
+
+ -
+ Accounting
+ low
+ low
+ fixed
+ 2994d483b6d556e7772e4511d2b1657431d24ade
+
+ ## [L-2] Unclaimed native ETH not included in initial rebalance calculations
+
+ In [`UniswapV4FluxManager.sol`](https://github.com/Veda-Labs/flux/blob/feat/add-new-teller/src/managers/https://github.com/Veda-Labs/flux/blob/feat/add-new-teller/src/managers/UniswapV4FluxManager.solUniswapV4FluxManager.sol), a user with the strategist role can call [`rebalance()`](https://github.com/Veda-Labs/flux/blob/feat/add-new-teller/src/managers/UniswapV4FluxManager.sol#L221-L315) which allow for adjusting assets in the vault via actions like swapping tokens, providing or removing liquidity. As safeguard to ensure asset value is relatively the same after the call to rebalance, the value before and after is calculated and checked that the delta does not exceed set rebalance deviations. The initial token balances are refreshed before unwrapping any wETH into native ETH before calculating the total assets:
+
+ ```solidity
+ _refreshInternalFluxAccounting();
+ if (address(token0) == address(0)) {
+ _unwrapAllNative();
+ }
+ uint256 totalSupplyBefore = boringVault.totalSupply();
+ uint256 totalAssetsInBaseBefore = totalAssets(exchangeRate, baseIn0Or1);
+ ```
+ Reference: [UniswapV4FluxManager.sol#L226-231](https://github.com/Veda-Labs/flux/blob/feat/add-new-teller/src/managers/UniswapV4FluxManager.sol#L226-L231)
+
+ ```solidity
+ /// @notice Refresh internal flux constants.
+ /// @dev For Uniswap V4 this is token0 and token1 contract balances
+ function _refreshInternalFluxAccounting() internal override {
+ token0Balance = address(token0) == address(0)
+ ? SafeCast.toUint128(ERC20(nativeWrapper).balanceOf(address(boringVault)))
+ : SafeCast.toUint128(token0.balanceOf(address(boringVault)));
+ token1Balance = SafeCast.toUint128(token1.balanceOf(address(boringVault)));
+ }
+ ```
+ Reference: [UniswapV4FluxManager.sol#L179-186](https://github.com/Veda-Labs/flux/blob/feat/add-new-teller/src/managers/UniswapV4FluxManager.sol#L179-L186)
+
+ However, in the case where the boring vault has a native ETH balance, it will not be included in the token balance initially calculated in [_refreshInternalFluxAccounting()](https://github.com/Veda-Labs/flux/blob/feat/add-new-teller/src/managers/UniswapV4FluxManager.sol#L179-L186), it will however be included after the rebalance as all ETH is wrapped back to wETH before [_refreshInternalFluxAccounting()](https://github.com/Veda-Labs/flux/blob/feat/add-new-teller/src/managers/UniswapV4FluxManager.sol#L179-L186) is called and total assets calculated. This results is potentially inaccurate differences in asset value as a result of the rebalance and could effect whether the rebalance deviation is triggered. Unaccounted for native ETH could result in a rebalance that loses excessive funds to not revert as expected, or if there is an excessive amount of unaccounted for ETH, it could prevent any rebalance occurring as it would trigger the upper rebalance deviation threshold.
+
+ **Remediations to Consider**
+
+ In [_refreshInternalFluxAccounting()](https://github.com/Veda-Labs/flux/blob/feat/add-new-teller/src/managers/UniswapV4FluxManager.sol#L179-L186) account for native ETH as well as wETH as required to ensure accurate accounting.
+
+
+
+ -
+ Signatures
+ low
+ low
+ ack
+
+ ## [L-3] Use nonces for Intents to prevent collision
+
+ [ActionData](https://github.com/Veda-Labs/flux/blob/2085f721c4a2d66b41b2d6411115aa4f2759788d/src/tellers/IntentsTeller.sol#L33-L55) parameters are signed by users and validated in [_verifySignedMessage()](https://github.com/Veda-Labs/flux/blob/2085f721c4a2d66b41b2d6411115aa4f2759788d/src/tellers/IntentsTeller.sol#L609-L642), where if valid it will mark the digest as used to prevent the signature from being re-used:
+
+ ```solidity
+ if (usedSignatures[digest]) {
+ revert IntentsTeller__DuplicateSignature();
+ }
+
+ usedSignatures[digest] = true;
+ ```
+ Reference: [IntentsTeller.sol#L637-641](https://github.com/Veda-Labs/flux/blob/2085f721c4a2d66b41b2d6411115aa4f2759788d/src/tellers/IntentsTeller.sol#L637-L641)
+
+ However, in the case where the same data is intended to be used multiple times, they will share the same digest and only one can execute. Although this case may be rare, it is good to include the possibility of multiple of the same intents.
+
+ **Remediations to Consider**
+
+ Include a nonce in each intent to distinguish from other intents with the same values.
+
+
+
+
+ -
+ Specifications
+ low
+ low
+ fixed
+ 663c01c6ac95a7b2624c88752ec823184a4eb4dc
+
+ ## [L-4] Use a Hash Struct for EIP712 signatures
+
+ Currently parameters in [ActionData](https://github.com/Veda-Labs/flux/blob/2085f721c4a2d66b41b2d6411115aa4f2759788d/src/tellers/IntentsTeller.sol#L33-L55) are signed by users to agree to an intent to either deposit or withdraw into the boring vault. However, [EIP712](https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct) expects a hash struct to be signed, which includes a type hash which describes the struct being signed, as well as the encoded parameters. This is the expected way to interact with the EIP712 standard to help ensure signatures can only be used for specific actions in a contract.
+
+ **Remediations to Consider**
+
+ Include a type hash of the data being signed.
+
+
+
+
+ -
+ Redundancy
+ low
+ fixed
+ 663c01c6ac95a7b2624c88752ec823184a4eb4dc
+
+ ## [Q-1] Redundant address in EIP-712 signed message
+
+ The [`_verifySignedMessage()`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/tellers/IntentsTeller.sol#L615) function in the `IntentsTeller` contract includes `address(this)` when constructing the EIP-712 message hash. The underlying `_hashTypedDataV4()` function from OpenZeppelin's `EIP712` contract already incorporates the contract's address via the domain separator. Consider excluding `address(this)` when constructing the EIP-712 message hash to avoid redundancy.
+
+
+
+
+ -
+ Redundancy
+ low
+ fixed
+ a32b4af73bd5cf5cf5fd7a5569869c188c707cb1
+
+ ## [Q-2] Redundant calculations
+
+ The `getRate()` and `totalAssets()` functions in `FluxManager` contract contain redundant arithmetic, performing division operations where the numerator and denominator share a common factor.
+
+ 1. [managers/FluxManager.sol#L217](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/managers/FluxManager.sol#L217)
+
+ ```diff
+ - return uint256(10 ** decimals1).mulDivDown(exchangeRate, 10 ** decimals1);
+ + return exchangeRate;
+ ```
+
+ 2. [managers/FluxManager.sol#L187-L189](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/managers/FluxManager.sol#L187-L189)
+
+ ```diff
+ - uint256 converted = token1Assets * (10 ** decimals0);
+ - converted = converted.mulDivDown(10 ** decimals1, exchangeRate);
+ - converted /= 10 ** decimals1;
+
+ + uint256 converted = token1Assets.mulDivDown(10 ** decimals0, exchangeRate);
+ ```
+
+ 3. [managers/FluxManager.sol#L193-L195](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/managers/FluxManager.sol#L193-L195)
+
+ ```diff
+ - uint256 converted = token0Assets * (10 ** decimals1);
+ - converted = converted.mulDivDown(exchangeRate, 10 ** decimals1);
+ - converted /= 10 ** decimals0;
+
+ + uint256 converted = token0Assets.mulDivDown(exchangeRate, 10 ** decimals0);
+ ```
+
+
+
+ -
+ Redundancy
+ low
+ fixed
+ 1a4e7bce7af166a7b7ea1be99a5bd34222cd7681
+
+ ## [Q-3] Unused state variables
+
+ The state variables [`lastPerformanceReview`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/managers/FluxManager.sol#L43), [`performanceReviewFrequency`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/managers/FluxManager.sol#L44), and [`totalSupplyLastReview`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/managers/FluxManager.sol#L47) are declared in `FluxManager` contract but are never utilized. Consider removing these variables will optimize gas usage and improve code clarity.
+
+
+
+
+ -
+ Gas Optimization
+ low
+ ack
+
+ ## [G-1] Inefficient lookup of position data using loops
+
+ The `UniswapV4FluxManager` contract uses loops in [`_removePositionIfPresent()`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/managers/UniswapV4FluxManager.sol#L623), [`_incrementLiquidity()`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/managers/UniswapV4FluxManager.sol#L589), and [`_decrementLiquidity()`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/managers/UniswapV4FluxManager.sol#L606) functions to find position data. As the number of tracked positions increases, the gas cost for these functions will grow, leading to higher operational costs. The use of loops for searching through an array is the root cause.
+
+ Consider replacing the loop with a mapping from `positionId` to its index in the `trackedPositions` array. This provides an O(1) lookup, significantly reducing gas costs.
+
+
+
+
+ -
+ Redundancy
+ low
+ ack
+
+ ## [G-2] Redundant data validation
+
+ In `FluxManager` contract, the [`getRate()`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/managers/FluxManager.sol#L209) function calls [`totalAssets()`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/managers/FluxManager.sol#L200) function within its execution path. Both of these functions are decorated with the [`checkDatum`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/managers/FluxManager.sol#L74) modifier. Consequently, when `getRate()` is called and the vault's total supply is non-zero, the `checkDatum` validation, which involves an external call, is performed twice. This redundancy leads to unnecessary gas consumption for core vault operations like deposits and withdrawals.
+
+ The recommended solution is to remove the `checkDatum` modifier from `getRate` and explicitly perform the validation only within the code paths where the total supply is zero. The following diff illustrates this change:
+
+ ```diff
+ - function getRate(uint256 exchangeRate, bool quoteIn0Or1) public view checkDatum(exchangeRate) returns (uint256) {
+ + function getRate(uint256 exchangeRate, bool quoteIn0Or1) public view returns (uint256) {
+ uint256 ts = boringVault.totalSupply();
+ if (ts == 0) {
+ + datum.validateExchangeRateWithDatum(exchangeRate, decimals1, datumLowerBound, datumUpperBound);
+ if (baseIn0Or1 && quoteIn0Or1) {
+ return 10 ** decimals0;
+ } else if (!baseIn0Or1 && quoteIn0Or1) {
+ return uint256(10 ** decimals0).mulDivDown(10 ** decimals1, exchangeRate);
+ } else if (baseIn0Or1 && !quoteIn0Or1) {
+ return uint256(10 ** decimals1).mulDivDown(exchangeRate, 10 ** decimals1);
+ } else if (!baseIn0Or1 && !quoteIn0Or1) {
+ return 10 ** decimals1;
+ } else {
+ // Generic revert as we will never actually reach this branch.
+ revert();
+ }
+ } else {
+ uint256 ta = totalAssets(exchangeRate, quoteIn0Or1);
+ return ta.mulDivDown(10 ** decimalsBoring, ts);
+ }
+ }
+ ```
+
+
+
+ -
+ Gas Optimization
+ low
+ fixed
+ 2994d483b6d556e7772e4511d2b1657431d24ade
+
+ ## [G-3] Redundant State Variables for Token Balances Cause Gas Inefficiency
+
+ The state variables [`token0Balance` and `token1Balance`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/managers/UniswapV4FluxManager.sol#L98-L99) in `UniswapV4FluxManager` contract cache token balances from `BoringVault`. These balances are immediately refreshed via [`_refreshInternalFluxAccounting()`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/managers/UniswapV4FluxManager.sol#L182-L185) at the start of every function that uses them, such as [`rebalance()`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/managers/UniswapV4FluxManager.sol#L226) in `UniswapV4FluxManager` contract and [`deposit()`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/tellers/IntentsTeller.sol#L468)/[`withdraw()`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/tellers/IntentsTeller.sol#L484)/[`bulkActions()`](https://github.com/Veda-Labs/flux/blob/ed3472c3ab2dd43451f94fd3b245c75c3f1a1f86/src/tellers/IntentsTeller.sol#L490) in `IntentsTeller` contract.
+
+ This immediate refresh treats the cached values as transient for a single transaction, making their storage in state redundant and incurring unnecessary `SSTORE` gas costs. This design also adds complexity by requiring developers to manually call the refresh function. Fetching balances directly when needed makes the contract simpler, less error-prone, and more gas-efficient.
+
+ Consider removing the `token0Balance` and `token1Balance` state variables and the now-obsolete `_refreshInternalFluxAccounting()` function. Instead, fetch balances directly from token contracts inside the functions that use them. This eliminates `SSTORE` costs and simplifies the logic.
+
+ ```diff
+ - function _refreshInternalFluxAccounting() internal override {
+ - token0Balance = address(token0) == address(0)
+ - ? SafeCast.toUint128(ERC20(nativeWrapper).balanceOf(address(boringVault)))
+ - : SafeCast.toUint128(token0.balanceOf(address(boringVault)));
+ - token1Balance = SafeCast.toUint128(token1.balanceOf(address(boringVault)));
+ - }
+
+ function _totalAssets(uint256 exchangeRate)
+ internal
+ view
+ override
+ returns (uint256 token0Assets, uint256 token1Assets)
+ {
+ - token0Assets = token0Balance;
+ - token1Assets = token1Balance;
+ + token0Assets = address(token0) == address(0)
+ + ? SafeCast.toUint128(ERC20(nativeWrapper).balanceOf(address(boringVault)))
+ + : SafeCast.toUint128(token0.balanceOf(address(boringVault)));
+ + token1Assets = SafeCast.toUint128(token1.balanceOf(address(boringVault)));
+
+ // Calculate the current sqrtPrice.
+ uint256 ratioX192 = FullMath.mulDiv(exchangeRate, 2 ** 192, 10 ** decimals0);
+ uint160 sqrtPriceX96 = SafeCast.toUint160(_sqrt(ratioX192));
+
+ // Iterate through tracked position data and aggregate token balances
+ uint256 positionCount = trackedPositionData.length;
+ for (uint256 i; i < positionCount; ++i) {
+ PositionData memory data = trackedPositionData[i];
+ (uint256 amount0, uint256 amount1) = LiquidityAmounts.getAmountsForLiquidity(
+ sqrtPriceX96,
+ TickMath.getSqrtRatioAtTick(data.tickLower),
+ TickMath.getSqrtRatioAtTick(data.tickUpper),
+ data.liquidity
+ );
+ token0Assets += amount0;
+ token1Assets += amount1;
+ }
+ }
+ ```
+
+
+
\ No newline at end of file