-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add morpho strategy and factory (#168)
- Loading branch information
Showing
3 changed files
with
589 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity >=0.8.22; | ||
|
||
import { IERC4626, IERC20 } from "@openzeppelin/contracts/interfaces/IERC4626.sol"; | ||
import { IEarnStrategy, StrategyId, IEarnVault } from "@balmy/earn-core/interfaces/IEarnStrategy.sol"; | ||
import { Clone } from "../base/Clone.sol"; | ||
import { IGlobalEarnRegistry } from "../../../interfaces/IGlobalEarnRegistry.sol"; | ||
import { MorphoConnector } from "../../layers/connector/morpho/MorphoConnector.sol"; | ||
import { ExternalFees } from "../../layers/fees/external/ExternalFees.sol"; | ||
import { ExternalGuardian } from "../../layers/guardian/external/ExternalGuardian.sol"; | ||
import { RegistryBasedCreationValidation } from | ||
"../../layers/creation-validation/external/RegistryBasedCreationValidation.sol"; | ||
import { ExternalLiquidityMining } from "../../layers/liquidity-mining/external/ExternalLiquidityMining.sol"; | ||
import { BaseStrategy } from "../base/BaseStrategy.sol"; | ||
|
||
contract MorphoStrategy is | ||
BaseStrategy, | ||
Clone, | ||
MorphoConnector, | ||
ExternalLiquidityMining, | ||
ExternalFees, | ||
ExternalGuardian, | ||
RegistryBasedCreationValidation | ||
{ | ||
// slither-disable-next-line reentrancy-benign | ||
function initAndRegister( | ||
address owner, | ||
bytes calldata creationValidationData, | ||
bytes calldata guardianData, | ||
bytes calldata feesData, | ||
bytes calldata liquidityMiningData | ||
) | ||
external | ||
returns (StrategyId strategyId_) | ||
{ | ||
strategyId_ = _baseStrategy_registerStrategy(owner); | ||
init({ | ||
creationValidationData: creationValidationData, | ||
guardianData: guardianData, | ||
feesData: feesData, | ||
liquidityMiningData: liquidityMiningData | ||
}); | ||
} | ||
|
||
// slither-disable-next-line reentrancy-benign | ||
function initWithId( | ||
StrategyId strategyId_, | ||
bytes calldata creationValidationData, | ||
bytes calldata guardianData, | ||
bytes calldata feesData, | ||
bytes calldata liquidityMiningData | ||
) | ||
external | ||
{ | ||
_strategyId = strategyId_; | ||
init({ | ||
creationValidationData: creationValidationData, | ||
guardianData: guardianData, | ||
feesData: feesData, | ||
liquidityMiningData: liquidityMiningData | ||
}); | ||
} | ||
|
||
// slither-disable-next-line reentrancy-benign | ||
function init( | ||
bytes calldata creationValidationData, | ||
bytes calldata guardianData, | ||
bytes calldata feesData, | ||
bytes calldata liquidityMiningData | ||
) | ||
public | ||
initializer | ||
{ | ||
_connector_init(); | ||
_creationValidation_init(creationValidationData); | ||
_guardian_init(guardianData); | ||
_fees_init(feesData); | ||
_liquidity_mining_init(liquidityMiningData); | ||
} | ||
|
||
function strategyId() | ||
public | ||
view | ||
override(ExternalLiquidityMining, ExternalFees, ExternalGuardian, RegistryBasedCreationValidation, BaseStrategy) | ||
returns (StrategyId) | ||
{ | ||
return BaseStrategy.strategyId(); | ||
} | ||
|
||
// Immutable params: | ||
// 1. Earn Vault (20B) | ||
// 2. Global Registry (20B) | ||
// 3. Morpho vault (20B) | ||
// 4. Asset (20B) | ||
|
||
function _earnVault() internal view override returns (IEarnVault) { | ||
return IEarnVault(_getArgAddress(0)); | ||
} | ||
|
||
function globalRegistry() | ||
public | ||
view | ||
override(ExternalLiquidityMining, ExternalFees, ExternalGuardian, RegistryBasedCreationValidation, MorphoConnector) | ||
returns (IGlobalEarnRegistry) | ||
{ | ||
return IGlobalEarnRegistry(_getArgAddress(20)); | ||
} | ||
|
||
// slither-disable-next-line naming-convention | ||
function ERC4626Vault() public view override returns (IERC4626) { | ||
return IERC4626(_getArgAddress(40)); | ||
} | ||
|
||
function _asset() internal view override returns (IERC20) { | ||
return IERC20(_getArgAddress(60)); | ||
} | ||
|
||
// slither-disable-next-line naming-convention,dead-code | ||
function _fees_underlying_asset() internal view override returns (address asset) { | ||
return _connector_asset(); | ||
} | ||
|
||
// slither-disable-next-line naming-convention,dead-code | ||
function _guardian_rescueFee() internal view override returns (uint16) { | ||
return _getFees().rescueFee; | ||
} | ||
} |
170 changes: 170 additions & 0 deletions
170
src/strategies/instances/morpho/MorphoStrategyFactory.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity >=0.8.22; | ||
|
||
import { IEarnVault } from "@balmy/earn-core/interfaces/IEarnStrategy.sol"; | ||
import { StrategyId, StrategyIdConstants } from "@balmy/earn-core/types/StrategyId.sol"; | ||
import { IEarnBalmyStrategy } from "../../../interfaces/IEarnBalmyStrategy.sol"; | ||
import { IGlobalEarnRegistry } from "../../../interfaces/IGlobalEarnRegistry.sol"; | ||
import { BaseStrategyFactory } from "../base/BaseStrategyFactory.sol"; | ||
import { MorphoStrategy, IGlobalEarnRegistry, IERC4626 } from "./MorphoStrategy.sol"; | ||
|
||
struct MorphoStrategyData { | ||
IEarnVault earnVault; | ||
IGlobalEarnRegistry globalRegistry; | ||
IERC4626 morphoVault; | ||
bytes creationValidationData; | ||
bytes guardianData; | ||
bytes feesData; | ||
bytes liquidityMiningData; | ||
} | ||
|
||
contract MorphoStrategyFactory is BaseStrategyFactory { | ||
constructor(MorphoStrategy implementation_) BaseStrategyFactory(implementation_) { } | ||
|
||
function cloneStrategy(MorphoStrategyData calldata strategyData) public returns (MorphoStrategy clone) { | ||
bytes memory immutableData = _calculateImmutableData(strategyData); | ||
IEarnBalmyStrategy clone_ = _clone(immutableData); | ||
clone = MorphoStrategy(payable(address(clone_))); | ||
emit StrategyCloned(clone, StrategyIdConstants.NO_STRATEGY); | ||
clone.init({ | ||
creationValidationData: strategyData.creationValidationData, | ||
guardianData: strategyData.guardianData, | ||
feesData: strategyData.feesData, | ||
liquidityMiningData: strategyData.liquidityMiningData | ||
}); | ||
} | ||
|
||
function cloneStrategyAndRegister( | ||
address owner, | ||
MorphoStrategyData calldata strategyData | ||
) | ||
external | ||
returns (MorphoStrategy clone, StrategyId strategyId) | ||
{ | ||
bytes memory immutableData = _calculateImmutableData(strategyData); | ||
IEarnBalmyStrategy clone_ = _clone(immutableData); | ||
clone = MorphoStrategy(payable(address(clone_))); | ||
strategyId = clone.initAndRegister({ | ||
owner: owner, | ||
creationValidationData: strategyData.creationValidationData, | ||
guardianData: strategyData.guardianData, | ||
feesData: strategyData.feesData, | ||
liquidityMiningData: strategyData.liquidityMiningData | ||
}); | ||
// slither-disable-next-line reentrancy-events | ||
emit StrategyCloned(clone, strategyId); | ||
} | ||
|
||
function cloneStrategyWithId( | ||
StrategyId strategyId, | ||
MorphoStrategyData calldata strategyData | ||
) | ||
external | ||
returns (MorphoStrategy clone) | ||
{ | ||
bytes memory immutableData = _calculateImmutableData(strategyData); | ||
IEarnBalmyStrategy clone_ = _clone(immutableData); | ||
clone = MorphoStrategy(payable(address(clone_))); | ||
emit StrategyCloned(clone, strategyId); | ||
clone.initWithId({ | ||
strategyId_: strategyId, | ||
creationValidationData: strategyData.creationValidationData, | ||
guardianData: strategyData.guardianData, | ||
feesData: strategyData.feesData, | ||
liquidityMiningData: strategyData.liquidityMiningData | ||
}); | ||
} | ||
|
||
function clone2Strategy( | ||
MorphoStrategyData calldata strategyData, | ||
bytes32 salt | ||
) | ||
external | ||
returns (MorphoStrategy clone) | ||
{ | ||
bytes memory immutableData = _calculateImmutableData(strategyData); | ||
IEarnBalmyStrategy clone_ = _clone2(immutableData, salt); | ||
clone = MorphoStrategy(payable(address(clone_))); | ||
emit StrategyCloned(clone, StrategyIdConstants.NO_STRATEGY); | ||
clone.init({ | ||
creationValidationData: strategyData.creationValidationData, | ||
guardianData: strategyData.guardianData, | ||
feesData: strategyData.feesData, | ||
liquidityMiningData: strategyData.liquidityMiningData | ||
}); | ||
} | ||
|
||
function clone2StrategyAndRegister( | ||
address owner, | ||
MorphoStrategyData calldata strategyData, | ||
bytes32 salt | ||
) | ||
external | ||
returns (MorphoStrategy clone, StrategyId strategyId) | ||
{ | ||
bytes memory immutableData = _calculateImmutableData(strategyData); | ||
IEarnBalmyStrategy clone_ = _clone2(immutableData, salt); | ||
clone = MorphoStrategy(payable(address(clone_))); | ||
strategyId = clone.initAndRegister({ | ||
owner: owner, | ||
creationValidationData: strategyData.creationValidationData, | ||
guardianData: strategyData.guardianData, | ||
feesData: strategyData.feesData, | ||
liquidityMiningData: strategyData.liquidityMiningData | ||
}); | ||
// slither-disable-next-line reentrancy-events | ||
emit StrategyCloned(clone, strategyId); | ||
} | ||
|
||
function clone2StrategyWithId( | ||
StrategyId strategyId, | ||
MorphoStrategyData calldata strategyData, | ||
bytes32 salt | ||
) | ||
external | ||
returns (MorphoStrategy clone) | ||
{ | ||
bytes memory immutableData = _calculateImmutableData(strategyData); | ||
IEarnBalmyStrategy clone_ = _clone2(immutableData, salt); | ||
clone = MorphoStrategy(payable(address(clone_))); | ||
emit StrategyCloned(clone, strategyId); | ||
clone.initWithId({ | ||
strategyId_: strategyId, | ||
creationValidationData: strategyData.creationValidationData, | ||
guardianData: strategyData.guardianData, | ||
feesData: strategyData.feesData, | ||
liquidityMiningData: strategyData.liquidityMiningData | ||
}); | ||
} | ||
|
||
function addressOfClone2( | ||
IEarnVault earnVault, | ||
IGlobalEarnRegistry globalRegistry, | ||
IERC4626 erc4626Vault, | ||
bytes32 salt | ||
) | ||
external | ||
view | ||
returns (address clone) | ||
{ | ||
bytes memory immutableData = _calculateImmutableData(earnVault, globalRegistry, erc4626Vault); | ||
return _addressOfClone2(immutableData, salt); | ||
} | ||
|
||
function _calculateImmutableData(MorphoStrategyData calldata strategyData) internal view returns (bytes memory) { | ||
return _calculateImmutableData(strategyData.earnVault, strategyData.globalRegistry, strategyData.morphoVault); | ||
} | ||
|
||
function _calculateImmutableData( | ||
IEarnVault earnVault, | ||
IGlobalEarnRegistry globalRegistry, | ||
IERC4626 erc4626Vault | ||
) | ||
internal | ||
view | ||
returns (bytes memory) | ||
{ | ||
address asset = erc4626Vault.asset(); | ||
return abi.encodePacked(earnVault, globalRegistry, erc4626Vault, asset); | ||
} | ||
} |
Oops, something went wrong.