Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions contracts/contracts/mocks/MockERC4626Vault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ contract MockERC4626Vault is IERC4626, ERC20 {

function deposit(uint256 assets, address receiver)
public
virtual
override
returns (uint256 shares)
{
Expand All @@ -46,7 +47,7 @@ contract MockERC4626Vault is IERC4626, ERC20 {
uint256 assets,
address receiver,
address owner
) public override returns (uint256 shares) {
) public virtual override returns (uint256 shares) {
shares = previewWithdraw(assets);
if (msg.sender != owner) {
// No approval check for mock
Expand All @@ -70,7 +71,7 @@ contract MockERC4626Vault is IERC4626, ERC20 {
return assets;
}

function totalAssets() public view override returns (uint256) {
function totalAssets() public view virtual override returns (uint256) {
return IERC20(asset).balanceOf(address(this));
}

Expand Down Expand Up @@ -110,11 +111,23 @@ contract MockERC4626Vault is IERC4626, ERC20 {
return type(uint256).max;
}

function maxWithdraw(address owner) public view override returns (uint256) {
function maxWithdraw(address owner)
public
view
virtual
override
returns (uint256)
{
return convertToAssets(balanceOf(owner));
}

function maxRedeem(address owner) public view override returns (uint256) {
function maxRedeem(address owner)
public
view
virtual
override
returns (uint256)
{
return balanceOf(owner);
}

Expand Down
75 changes: 75 additions & 0 deletions contracts/contracts/mocks/MockMorphoV2CreditVault.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import { MockERC4626Vault } from "./MockERC4626Vault.sol";

/**
* @title Mock Morpho Vault V2 credit vault
* @notice ERC-4626 mock that decouples the reported position value (previewRedeem) from the
* liquid balance available to withdraw, so tests can model accrued-but-unrealized
* interest and OToken that has been borrowed out.
* @dev Mirrors production: maxWithdraw()/maxRedeem() return 0 (the strategy reads liquidity via
* MorphoV2VaultUtils, not these), and a liquidityAdapter() getter is exposed. The strategy
* is the sole depositor in the gated vault, so it always holds 100% of the shares and
* previewRedeem(allShares) == reported total assets.
*/
contract MockMorphoV2CreditVault is MockERC4626Vault {
using SafeERC20 for IERC20;

/// @notice Reported total assets, driving previewRedeem independent of the idle balance.
uint256 private _reportedTotalAssets;

/// @notice The Morpho V1 liquidity adapter address.
address public liquidityAdapter;

constructor(address _asset) MockERC4626Vault(_asset) {}

function setLiquidityAdapter(address _liquidityAdapter) external {
liquidityAdapter = _liquidityAdapter;
}

/// @dev Reported value, not the idle token balance.
function totalAssets() public view override returns (uint256) {
return _reportedTotalAssets;
}

function deposit(uint256 assets, address receiver)
public
override
returns (uint256 shares)
{
shares = super.deposit(assets, receiver);
_reportedTotalAssets += assets;
}

function withdraw(
uint256 assets,
address receiver,
address owner
) public override returns (uint256 shares) {
shares = super.withdraw(assets, receiver, owner);
_reportedTotalAssets -= assets;
}

/// @notice Simulate interest accruing as a claim: lifts previewRedeem without adding liquidity.
function simulateInterest(uint256 amount) external {
_reportedTotalAssets += amount;
}

/// @notice Simulate OToken being borrowed/drawn: removes idle liquidity without changing value.
function simulateBorrow(uint256 amount, address to) external {
IERC20(asset).safeTransfer(to, amount);
}

/// @dev Morpho V2 vaults return 0 from these; liquidity is read via MorphoV2VaultUtils.
function maxWithdraw(address) public view override returns (uint256) {
return 0;
}

function maxRedeem(address) public view override returns (uint256) {
return 0;
}
}
9 changes: 9 additions & 0 deletions contracts/contracts/proxies/Proxies.sol
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,15 @@ contract OUSDMorphoV2StrategyProxy is InitializeGovernedUpgradeabilityProxy {

}

/**
* @notice OUSDCreditMarketAMOStrategyProxy delegates calls to a CreditMarketAMOStrategy implementation
*/
contract OUSDCreditMarketAMOStrategyProxy is
InitializeGovernedUpgradeabilityProxy
{

}

/**
* @notice Legacy Supernova AMO proxy
*/
Expand Down
53 changes: 53 additions & 0 deletions contracts/contracts/strategies/AbstractMerkleClaimStrategy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

/**
* @title Abstract strategy with Merkl reward claiming
* @notice Adds the ability to claim rewards from the Merkl Distributor to a strategy.
* @dev Holds no storage so it is safe to insert into the inheritance chain of an
* already deployed upgradeable strategy without shifting any storage slots.
* @author Origin Protocol Inc
*/
import { InitializableAbstractStrategy } from "../utils/InitializableAbstractStrategy.sol";
import { IDistributor } from "../interfaces/IMerkl.sol";

abstract contract AbstractMerkleClaimStrategy is InitializableAbstractStrategy {
Comment thread
shahthepro marked this conversation as resolved.
/// @notice The address of the Merkle Distributor contract.
IDistributor public constant merkleDistributor =
IDistributor(0x3Ef3D8bA38EBe18DB133cEc108f4D14CE00Dd9Ae);

event ClaimedRewards(address indexed token, uint256 amount);

/**
* @param _baseConfig The platform and OToken vault addresses
*/
constructor(BaseStrategyConfig memory _baseConfig)
InitializableAbstractStrategy(_baseConfig)
{}

/// @notice Claim tokens from the Merkle Distributor
/// @param token The address of the token to claim.
/// @param amount The amount of tokens to claim.
/// @param proof The Merkle proof to validate the claim.
function merkleClaim(
address token,
uint256 amount,
bytes32[] calldata proof
) external {
address[] memory users = new address[](1);
users[0] = address(this);

address[] memory tokens = new address[](1);
tokens[0] = token;

uint256[] memory amounts = new uint256[](1);
amounts[0] = amount;

bytes32[][] memory proofs = new bytes32[][](1);
proofs[0] = proof;

merkleDistributor.claim(users, tokens, amounts, proofs);

emit ClaimedRewards(token, amount);
}
}
Loading
Loading