Skip to content

Feat/aave and morpho vaults#185

Merged
dmytro-horbatenko merged 23 commits intomainfrom
feat/aave-and-morpho-vaults
Apr 2, 2026
Merged

Feat/aave and morpho vaults#185
dmytro-horbatenko merged 23 commits intomainfrom
feat/aave-and-morpho-vaults

Conversation

@dmytro-horbatenko
Copy link
Copy Markdown
Contributor

No description provided.

@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello @dmytro-horbatenko, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly expands the redemption capabilities by integrating with Aave V3 and Morpho vaults. These new redemption mechanisms allow the system to source liquidity from these popular DeFi protocols when the vault's internal balance is insufficient, enhancing flexibility and robustness. The changes encompass new smart contracts, updated deployment infrastructure, and thorough testing to ensure proper functionality and security.

Highlights

  • New Redemption Vaults: Introduced two new redemption vault types: RedemptionVaultWithAave and RedemptionVaultWithMorpho, enabling redemptions by interacting with Aave V3 and Morpho (ERC-4626) protocols respectively.
  • Smart Contract Implementations: Added new Solidity contracts for RedemptionVaultWithAave and RedemptionVaultWithMorpho, along with their respective interfaces and mock implementations for testing purposes.
  • Deployment and Configuration Updates: Updated deployment scripts, configuration generation, and helper utilities to support the new Aave and Morpho redemption vault types, including their specific initialization parameters.
  • Comprehensive Testing: Included new unit and integration tests for both RedemptionVaultWithAave and RedemptionVaultWithMorpho, covering various scenarios including direct redemptions, withdrawals from external protocols, partial withdrawals, and error handling.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • config/constants/addresses.ts
    • Added 'redemptionVaultAave' and 'redemptionVaultMorpho' to RedemptionVaultType.
  • contracts/RedemptionVaultWithAave.sol
    • Added new contract RedemptionVaultWithAave for Aave V3 integrated redemptions.
  • contracts/RedemptionVaultWithMorpho.sol
    • Added new contract RedemptionVaultWithMorpho for Morpho Vault integrated redemptions.
  • contracts/interfaces/aave/IAaveV3Pool.sol
    • Added a minimal interface for the Aave V3 Pool contract.
  • contracts/interfaces/morpho/IERC4626Vault.sol
    • Added a minimal ERC-4626 interface for Morpho Vaults.
  • contracts/mocks/AaveV3PoolMock.sol
    • Added a mock contract for Aave V3 Pool for testing purposes.
  • contracts/mocks/ERC20Mock.sol
    • Added a 'burn' function to the ERC20Mock contract.
  • contracts/mocks/MorphoVaultMock.sol
    • Added a mock contract for Morpho Vault for testing purposes.
  • contracts/testers/RedemptionVaultWithAaveTest.sol
    • Added a tester contract for RedemptionVaultWithAave to expose internal functions for testing.
  • contracts/testers/RedemptionVaultWithMorphoTest.sol
    • Added a tester contract for RedemptionVaultWithMorpho to expose internal functions for testing.
  • helpers/contracts.ts
    • Updated contract name mappings and types to include new Aave and Morpho redemption vaults.
  • scripts/deploy/codegen/common/index.ts
    • Updated imports and the 'generatorPerContract' map to include new Aave and Morpho vault templates.
  • scripts/deploy/codegen/common/templates/index.ts
    • Added new template exports for rv-aave and rv-morpho.
  • scripts/deploy/codegen/common/templates/rv-aave.template.ts
    • Added a new template for generating RedemptionVaultWithAave contracts.
  • scripts/deploy/codegen/common/templates/rv-morpho.template.ts
    • Added a new template for generating RedemptionVaultWithMorpho contracts.
  • scripts/deploy/codegen/common/ui/deployment-config.ts
    • Updated deployment configuration UI to include options for Aave and Morpho redemption vaults.
  • scripts/deploy/codegen/common/ui/deployment-contracts.ts
    • Updated contract generation UI to include Aave and Morpho redemption vaults.
  • scripts/deploy/common/rv.ts
    • Updated deployment types and logic for redemption vaults to support Aave and Morpho integrations.
  • scripts/deploy/common/types.ts
    • Updated deployment configuration types to include new Aave and Morpho redemption vault options.
  • scripts/deploy/deploy_RVAave.ts
    • Added a new deployment script for RedemptionVaultWithAave.
  • scripts/deploy/deploy_RVMorpho.ts
    • Added a new deployment script for RedemptionVaultWithMorpho.
  • test/common/deposit-vault-ustb.helpers.ts
    • Refactored depositInstantWithUstbTest to remove specific fee and amount calculations, allowing for dynamic USTB minted expectations.
  • test/common/fixtures.ts
    • Updated defaultDeploy fixture to include deployment and initialization of Aave and Morpho mock contracts and their respective redemption vaults.
  • test/common/manageable-vault.helpers.ts
    • Updated CommonParamsChangePaymentToken type to include RedemptionVaultWithAave and RedemptionVaultWithMorpho.
  • test/common/redemption-vault-aave.helpers.ts
    • Added new helper functions for testing RedemptionVaultWithAave scenarios.
  • test/common/redemption-vault-morpho.helpers.ts
    • Added new helper functions for testing RedemptionVaultWithMorpho scenarios.
  • test/common/redemption-vault.helpers.ts
    • Updated redemption vault helper types to include RedemptionVaultWithAave and RedemptionVaultWithMorpho.
  • test/integration/DepositVaultWithUSTB.test.ts
    • Removed explicit expectedUstbMinted value in integration tests, allowing for dynamic calculation.
  • test/integration/RedemptionVaultWithAave.test.ts
    • Added new integration tests for RedemptionVaultWithAave, covering various redemption scenarios and error conditions.
  • test/integration/RedemptionVaultWithMorpho.test
    • Added new integration tests for RedemptionVaultWithMorpho, covering various redemption scenarios and error conditions.
  • test/integration/fixtures/aave.fixture.ts
    • Added a new fixture for setting up Aave redemption vault integration tests with mainnet forking.
  • test/integration/fixtures/morpho.fixture.ts
    • Added a new fixture for setting up Morpho redemption vault integration tests with mainnet forking.
  • test/integration/helpers/mainnet-addresses.ts
    • Added mainnet addresses for Aave V3 Pool, aUSDC, Morpho Steakhouse USDC Vault, and their respective whale accounts.
  • test/unit/RedemptionVaultWithAave.test.ts
    • Added comprehensive unit tests for RedemptionVaultWithAave, covering deployment, initialization, admin functions, and redemption logic.
  • test/unit/RedemptionVaultWithMorpho.test.ts
    • Added comprehensive unit tests for RedemptionVaultWithMorpho, covering deployment, initialization, admin functions, and redemption logic.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces new redemption vaults that integrate with Aave and Morpho, allowing the system to tap into external liquidity sources. The implementation is well-structured and includes comprehensive tests. I've identified a critical issue in the Aave integration regarding the handling of withdrawal amounts, along with some opportunities for code cleanup to improve readability and gas efficiency in both new vault contracts.

@dmytro-horbatenko
Copy link
Copy Markdown
Contributor Author

/gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces new vault types for integrating with Aave and Morpho, as well as a vault that can invest in other mTokens. This is a significant feature addition that expands the capabilities of the platform. The changes include new contracts for these vaults, updates to configuration and deployment scripts, and extensive tests.

My review focuses on the new Solidity contracts. I've identified a critical re-initialization vulnerability in DepositVaultWithAave and DepositVaultWithMToken due to a missing initializer modifier. I've also pointed out a potential high-severity re-entrancy risk across all new vault contracts due to the lack of re-entrancy guards. Additionally, I've suggested improvements to the allowance-setting pattern for better security and recommended removing redundant variables for code clarity and gas optimization.

The rest of the changes, including the TypeScript files for deployment and testing, seem well-structured and correctly implement support for the new vaults. The refactoring to use a vault-resolver is a good improvement for maintainability.

Comment on lines +140 to +143
IERC20(tokenIn).safeIncreaseAllowance(
address(aavePool),
transferredAmount
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using safeIncreaseAllowance can be problematic if a previous transaction that set an allowance failed, leaving a non-zero allowance. A more robust pattern is to reset the allowance to zero before setting the new value. This prevents unexpected behavior from leftover allowances.

        IERC20(tokenIn).safeApprove(address(aavePool), 0);
        IERC20(tokenIn).safeApprove(address(aavePool), transferredAmount);

Comment on lines +150 to +153
IERC20(tokenIn).safeIncreaseAllowance(
address(mTokenDepositVault),
transferredAmount
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using safeIncreaseAllowance can be problematic if a previous transaction that set an allowance failed, leaving a non-zero allowance. A more robust pattern is to reset the allowance to zero before setting the new value. This prevents unexpected behavior from leftover allowances.

        IERC20(tokenIn).safeApprove(address(mTokenDepositVault), 0);
        IERC20(tokenIn).safeApprove(address(mTokenDepositVault), transferredAmount);

Comment on lines +136 to +139
IERC20(tokenIn).safeIncreaseAllowance(
address(vault),
transferredAmount
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using safeIncreaseAllowance can be problematic if a previous transaction that set an allowance failed, leaving a non-zero allowance. A more robust pattern is to reset the allowance to zero before setting the new value. This prevents unexpected behavior from leftover allowances.

        IERC20(tokenIn).safeApprove(address(vault), 0);
        IERC20(tokenIn).safeApprove(address(vault), transferredAmount);

Comment on lines +127 to +129
uint256 amountMTokenInCopy = amountMTokenIn;
address tokenOutCopy = tokenOut;
uint256 minReceiveAmountCopy = minReceiveAmount;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The local variables amountMTokenInCopy, tokenOutCopy, and minReceiveAmountCopy are initialized with the values of the function parameters and then used in place of them. Since the original parameters are not modified, these copies are redundant. Removing them will improve code clarity and provide minor gas savings. The original parameters amountMTokenIn, tokenOut, and minReceiveAmount can be used directly throughout the function. This also applies to RedemptionVaultWithMToken and RedemptionVaultWithMorpho.

Comment on lines +236 to +239
IERC20(mTokenA).safeIncreaseAllowance(
address(redemptionVault),
mTokenAAmount
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using safeIncreaseAllowance can be problematic if a previous transaction that set an allowance failed, leaving a non-zero allowance. A more robust pattern is to reset the allowance to zero before setting the new value. This prevents unexpected behavior from leftover allowances.

        IERC20(mTokenA).safeApprove(address(redemptionVault), 0);
        IERC20(mTokenA).safeApprove(address(redemptionVault), mTokenAAmount);

@dmytro-horbatenko
Copy link
Copy Markdown
Contributor Author

/gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces new vault types for interacting with Aave and Morpho protocols, as well as a new mToken-based strategy. The changes are extensive, touching contracts, tests, deployment scripts, and configurations. The new contracts are well-structured and inherit from existing base vaults, which is a good design choice. I've identified a critical issue in the RedemptionVaultWithAave contract related to an incorrect balance check that could cause legitimate transactions to fail. Additionally, I've pointed out the use of a deprecated function across several new contracts and suggested a safer alternative. Overall, this is a significant feature addition that expands the platform's capabilities.

Note: Security Review did not run due to the size of the PR.

@dmytro-horbatenko dmytro-horbatenko force-pushed the feat/aave-and-morpho-vaults branch from 3c8e79d to 675402c Compare March 5, 2026 13:10
@dmytro-horbatenko
Copy link
Copy Markdown
Contributor Author

/gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces new vault types that integrate with Aave and Morpho for yield generation, and also allows vault-to-vault deposits between mTokens. The changes are extensive, covering new smart contracts, interfaces, tests, and deployment scripts. The new contracts are well-structured and follow security best practices like using storage gaps for upgradeability and access control. The addition of comprehensive tests and updates to the deployment infrastructure is a great sign of quality. I have a couple of suggestions for improvement regarding code duplication and the use of deprecated functions, which would enhance maintainability and adherence to the latest best practices.

Note: Security Review did not run due to the size of the PR.

tokensDecimals
);

IERC20(tokenIn).safeIncreaseAllowance(address(pool), transferredAmount);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

safeIncreaseAllowance is deprecated in recent OpenZeppelin Contracts versions in favor of safeApprove. While its use here is not necessarily unsafe, switching to safeApprove would be more idiomatic and future-proof. To be absolutely safe against all token implementations, it's best practice to reset the allowance to 0 before setting a new value. This pattern should be applied across all new vault contracts in this PR that use safeIncreaseAllowance (DepositVaultWithMToken, DepositVaultWithMorpho, RedemptionVaultWithMToken).

        IERC20(tokenIn).safeApprove(address(pool), 0);
        IERC20(tokenIn).safeApprove(address(pool), transferredAmount);

Comment on lines +91 to +161
function _redeemInstant(
address tokenOut,
uint256 amountMTokenIn,
uint256 minReceiveAmount,
address recipient
)
internal
override
returns (
CalcAndValidateRedeemResult memory calcResult,
uint256 amountTokenOutWithoutFee
)
{
address user = msg.sender;

calcResult = _calcAndValidateRedeem(
user,
tokenOut,
amountMTokenIn,
true,
false
);

_requireAndUpdateLimit(amountMTokenIn);

uint256 tokenDecimals = _tokenDecimals(tokenOut);

uint256 amountMTokenInCopy = amountMTokenIn;
address tokenOutCopy = tokenOut;
uint256 minReceiveAmountCopy = minReceiveAmount;

(uint256 amountMTokenInUsd, uint256 mTokenRate) = _convertMTokenToUsd(
amountMTokenInCopy
);
(uint256 amountTokenOut, uint256 tokenOutRate) = _convertUsdToToken(
amountMTokenInUsd,
tokenOutCopy
);

_requireAndUpdateAllowance(tokenOutCopy, amountTokenOut);

mToken.burn(user, calcResult.amountMTokenWithoutFee);
if (calcResult.feeAmount > 0)
_tokenTransferFromUser(
address(mToken),
feeReceiver,
calcResult.feeAmount,
18
);

uint256 amountTokenOutWithoutFeeFrom18 = ((calcResult
.amountMTokenWithoutFee * mTokenRate) / tokenOutRate)
.convertFromBase18(tokenDecimals);

amountTokenOutWithoutFee = amountTokenOutWithoutFeeFrom18
.convertToBase18(tokenDecimals);

require(
amountTokenOutWithoutFee >= minReceiveAmountCopy,
"RVA: minReceiveAmount > actual"
);

_checkAndRedeemAave(tokenOutCopy, amountTokenOutWithoutFeeFrom18);

_tokenTransferToUser(
tokenOutCopy,
recipient,
amountTokenOutWithoutFee,
tokenDecimals
);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The _redeemInstant function contains a large block of code that is duplicated across RedemptionVaultWithAave, RedemptionVaultWithMorpho, and RedemptionVaultWithMToken. This duplication makes the code harder to maintain, as any change to the core redemption logic needs to be applied in multiple places. Consider refactoring this common logic into a shared internal function within the base RedemptionVault contract, perhaps using a hook that child contracts can override for their specific withdrawal logic. For example, an internal function like _prepareRedemption could handle the common calculations and checks, returning the necessary values to the caller.

@dmytro-horbatenko dmytro-horbatenko merged commit d533abc into main Apr 2, 2026
4 checks passed
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