Skip to content

Commit

Permalink
Merge pull request #301 from morpho-labs/main
Browse files Browse the repository at this point in the history
update `review-cantina`
  • Loading branch information
MerlinEgalite authored Oct 21, 2023
2 parents cdf0034 + 9c73205 commit 4238903
Show file tree
Hide file tree
Showing 54 changed files with 197 additions and 202 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,9 @@ Each Bundler is a domain-specific abstract layer of contract that implements som
Some chain-specific domains are also scoped to the chain-specific folder, because they are not expected to be used on any other chain (e.g. DAI and its specific `permit` function is only available on Ethereum - see [`EthereumPermitBundler`](./src/ethereum/EthereumPermitBundler.sol)).

User-end bundlers are provided in each chain-specific folder, instanciating all the intermediary domain-specific bundlers and associated parameters (such as chain-specific protocol addresses, e.g. [`EthereumBundler`](./src/ethereum/EthereumBundler.sol)).

## Get Started

Install dependencies with `yarn`.

The first time running the tests with `yarn test:forge` will build Morpho Blue.
2 changes: 1 addition & 1 deletion config/ConfigLib.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import {stdJson} from "@forge-std/StdJson.sol";
import {stdJson} from "../lib/forge-std/src/StdJson.sol";

struct Config {
string json;
Expand Down
2 changes: 1 addition & 1 deletion config/Configured.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity ^0.8.0;

import {Config, ConfigMarket, ConfigLib} from "./ConfigLib.sol";

import {StdChains, VmSafe} from "@forge-std/StdChains.sol";
import {StdChains, VmSafe} from "../lib/forge-std/src/StdChains.sol";

abstract contract Configured is StdChains {
using ConfigLib for Config;
Expand Down
1 change: 1 addition & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ fs_permissions = [
{ access = "read", path = "./config/"},
{ access = "read", path = "./lib/morpho-blue/out/"}
]
libs = ["lib"]

[profile.default.fuzz]
runs = 32
Expand Down
1 change: 1 addition & 0 deletions lib/forge-std
Submodule forge-std added at f73c73
2 changes: 1 addition & 1 deletion lib/morpho-blue
21 changes: 2 additions & 19 deletions remappings.txt
Original file line number Diff line number Diff line change
@@ -1,22 +1,5 @@
config/=config/
src/=src/
test/=test/
config/=config/

solmate/=lib/solmate/

@forge-std/=lib/morpho-blue/lib/forge-std/src/
@solmate/=lib/solmate/src/
@morpho-v1/=lib/morpho-v1/src/
@morpho-blue/=lib/morpho-blue/src/
@morpho-utils/=lib/morpho-utils/src/
@universal-rewards-distributor/=lib/universal-rewards-distributor/src/
@morpho-aave-v3/=lib/morpho-aave-v3/src
@openzeppelin/=lib/openzeppelin-contracts/contracts/
@permit2/=lib/permit2/src/

@uniswap/v3-core=lib/v3-core/contracts/
@uniswap/v3-periphery=lib/v3-periphery/contracts/

@aave/v3-core=lib/aave-v3-core/contracts/

@murky/=lib/murky/
solmate/=lib/morpho-aave-v3/lib/permit2/lib/solmate/
19 changes: 14 additions & 5 deletions src/BaseBundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ pragma solidity 0.8.21;
import {IMulticall} from "./interfaces/IMulticall.sol";

import {ErrorsLib} from "./libraries/ErrorsLib.sol";
import {UNSET_INITIATOR} from "./libraries/ConstantsLib.sol";

/// @title BaseBundler
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Enables calling multiple functions in a single call to the same contract (self).
/// @dev Every Bundler must inherit from this contract.
/// @dev Every bundler must inherit from this contract.
/// @dev Every bundler inheriting from this contract must have their external functions payable as they will be
/// delegate called by the `multicall` function (which is payable, and thus might pass a non-null ETH value). It is
/// recommended not to rely on `msg.value` as the same value can be reused for multiple calls.
Expand All @@ -18,19 +19,27 @@ abstract contract BaseBundler is IMulticall {

/// @notice Keeps track of the bundler's latest bundle initiator.
/// @dev Also prevents interacting with the bundler outside of an initiated execution context.
address public initiator;
address private _initiator = UNSET_INITIATOR;

/* PUBLIC */

/// @notice Returns the address of the initiator of the multicall transaction.
/// @dev Specialized getter to prevent using `_initiator` directly.
function initiator() public view returns (address) {
return _initiator;
}

/* EXTERNAL */

/// @notice Executes a series of delegate calls to the contract itself.
/// @dev Locks the initiator so that the sender can uniquely be identified in callbacks.
/// @dev All functions delegatecalled must be `payable` if `msg.value` is non-zero.
function multicall(bytes[] memory data) external payable {
initiator = msg.sender;
_initiator = msg.sender;

_multicall(data);

delete initiator;
_initiator = UNSET_INITIATOR;
}

/* INTERNAL */
Expand All @@ -48,7 +57,7 @@ abstract contract BaseBundler is IMulticall {

/// @dev Checks that the contract is in an initiated execution context.
function _checkInitiated() internal view {
require(initiator != address(0), ErrorsLib.UNINITIATED);
require(_initiator != UNSET_INITIATOR, ErrorsLib.UNINITIATED);
}

/// @dev Bubbles up the revert reason / custom error encoded in `returnData`.
Expand Down
10 changes: 7 additions & 3 deletions src/ERC4626Bundler.sol
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.21;

import {IERC4626} from "@openzeppelin/interfaces/IERC4626.sol";
import {IERC4626} from "../lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol";

import {Math} from "@morpho-utils/math/Math.sol";
import {Math} from "../lib/morpho-utils/src/math/Math.sol";
import {ErrorsLib} from "./libraries/ErrorsLib.sol";
import {SafeTransferLib, ERC20} from "solmate/src/utils/SafeTransferLib.sol";
import {SafeTransferLib, ERC20} from "../lib/solmate/src/utils/SafeTransferLib.sol";

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

Expand Down Expand Up @@ -67,6 +67,8 @@ abstract contract ERC4626Bundler is BaseBundler {
require(receiver != address(0), ErrorsLib.ZERO_ADDRESS);
/// Do not check `receiver != address(this)` to allow the bundler to receive the underlying asset.

address initiator = initiator();

assets = Math.min(assets, IERC4626(vault).maxWithdraw(initiator));

require(assets != 0, ErrorsLib.ZERO_AMOUNT);
Expand All @@ -82,6 +84,8 @@ abstract contract ERC4626Bundler is BaseBundler {
require(receiver != address(0), ErrorsLib.ZERO_ADDRESS);
/// Do not check `receiver != address(this)` to allow the bundler to receive the underlying asset.

address initiator = initiator();

shares = Math.min(shares, IERC4626(vault).maxRedeem(initiator));

require(shares != 0, ErrorsLib.ZERO_SHARES);
Expand Down
14 changes: 7 additions & 7 deletions src/MorphoBundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
pragma solidity 0.8.21;

import {IMorphoBundler} from "./interfaces/IMorphoBundler.sol";
import {MarketParams, Signature, Authorization, IMorpho} from "@morpho-blue/interfaces/IMorpho.sol";
import {MarketParams, Signature, Authorization, IMorpho} from "../lib/morpho-blue/src/interfaces/IMorpho.sol";

import {ErrorsLib} from "./libraries/ErrorsLib.sol";

import {Math} from "@morpho-utils/math/Math.sol";
import {SafeTransferLib, ERC20} from "solmate/src/utils/SafeTransferLib.sol";
import {Math} from "../lib/morpho-utils/src/math/Math.sol";
import {SafeTransferLib, ERC20} from "../lib/solmate/src/utils/SafeTransferLib.sol";

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

Expand Down Expand Up @@ -56,7 +56,7 @@ abstract contract MorphoBundler is BaseBundler, IMorphoBundler {
/* ACTIONS */

/// @notice Approves this contract to manage the `authorization.authorizer`'s position via EIP712 `signature`.
/// @dev Pass `skipRevert == true` to avoid reverting the whole bundle in case the signature expired.
/// @dev Pass `skipRevert = true` to avoid reverting the whole bundle in case the signature expired.
function morphoSetAuthorizationWithSig(
Authorization calldata authorization,
Signature calldata signature,
Expand Down Expand Up @@ -117,7 +117,7 @@ abstract contract MorphoBundler is BaseBundler, IMorphoBundler {
external
payable
{
MORPHO.borrow(marketParams, amount, shares, initiator, receiver);
MORPHO.borrow(marketParams, amount, shares, initiator(), receiver);
}

/// @notice Repays `amount` of `asset` on behalf of `onBehalf`.
Expand Down Expand Up @@ -148,7 +148,7 @@ abstract contract MorphoBundler is BaseBundler, IMorphoBundler {
external
payable
{
MORPHO.withdraw(marketParams, amount, shares, initiator, receiver);
MORPHO.withdraw(marketParams, amount, shares, initiator(), receiver);
}

/// @notice Withdraws `amount` of the collateral asset on behalf of sender.
Expand All @@ -158,7 +158,7 @@ abstract contract MorphoBundler is BaseBundler, IMorphoBundler {
external
payable
{
MORPHO.withdrawCollateral(marketParams, amount, initiator, receiver);
MORPHO.withdrawCollateral(marketParams, amount, initiator(), receiver);
}

/// @notice Triggers a liquidation on Morpho.
Expand Down
7 changes: 4 additions & 3 deletions src/Permit2Bundler.sol
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.21;

import {ISignatureTransfer} from "@permit2/interfaces/ISignatureTransfer.sol";
import {ISignatureTransfer} from "../lib/permit2/src/interfaces/ISignatureTransfer.sol";

import "./libraries/ConstantsLib.sol";
import {ErrorsLib} from "./libraries/ErrorsLib.sol";
import {Math} from "@morpho-utils/math/Math.sol";
import {ERC20} from "solmate/src/tokens/ERC20.sol";
import {Math} from "../lib/morpho-utils/src/math/Math.sol";
import {ERC20} from "../lib/solmate/src/tokens/ERC20.sol";

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

Expand All @@ -24,6 +24,7 @@ abstract contract Permit2Bundler is BaseBundler {
external
payable
{
address initiator = initiator();
uint256 amount = Math.min(permit.permitted.amount, ERC20(permit.permitted.token).balanceOf(initiator));

require(amount != 0, ErrorsLib.ZERO_AMOUNT);
Expand Down
4 changes: 2 additions & 2 deletions src/PermitBundler.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.21;

import {IERC20Permit} from "@openzeppelin/token/ERC20/extensions/IERC20Permit.sol";
import {IERC20Permit} from "../lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol";

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

Expand All @@ -18,7 +18,7 @@ abstract contract PermitBundler is BaseBundler {
external
payable
{
try IERC20Permit(asset).permit(initiator, address(this), amount, deadline, v, r, s) {}
try IERC20Permit(asset).permit(initiator(), address(this), amount, deadline, v, r, s) {}
catch (bytes memory returnData) {
if (!skipRevert) _revert(returnData);
}
Expand Down
7 changes: 2 additions & 5 deletions src/StEthBundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ pragma solidity 0.8.21;
import {IWstEth} from "./interfaces/IWstEth.sol";
import {IStEth} from "./interfaces/IStEth.sol";

import {Math} from "@morpho-utils/math/Math.sol";
import {Math} from "../lib/morpho-utils/src/math/Math.sol";
import {ErrorsLib} from "./libraries/ErrorsLib.sol";
import {SafeTransferLib, ERC20} from "solmate/src/utils/SafeTransferLib.sol";
import {SafeTransferLib, ERC20} from "../lib/solmate/src/utils/SafeTransferLib.sol";

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

Expand Down Expand Up @@ -38,7 +38,6 @@ abstract contract StEthBundler is BaseBundler {
/* ACTIONS */

/// @notice Stakes the given `amount` of ETH via Lido, using the `referral` id.
/// @dev Use `BaseBundler.erc20Transfer` to transfer the stEth to some `receiver`.
/// @dev Pass `amount = type(uint256).max` to stake all.
function stakeEth(uint256 amount, address referral) external payable {
amount = Math.min(amount, address(this).balance);
Expand All @@ -48,7 +47,6 @@ abstract contract StEthBundler is BaseBundler {
}

/// @notice Wraps the given `amount` of stETH to wstETH.
/// @dev Use `BaseBundler.erc20Transfer` to transfer the wrapped stEth to some `receiver`.
/// @dev Pass `amount = type(uint256).max` to wrap all.
function wrapStEth(uint256 amount) external payable {
amount = Math.min(amount, ERC20(ST_ETH).balanceOf(address(this)));
Expand All @@ -59,7 +57,6 @@ abstract contract StEthBundler is BaseBundler {
}

/// @notice Unwraps the given `amount` of wstETH to stETH.
/// @dev Use `BaseBundler.erc20Transfer` to transfer the unwrapped stEth to some `receiver`.
/// @dev Pass `amount = type(uint256).max` to unwrap all.
function unwrapStEth(uint256 amount) external payable {
amount = Math.min(amount, ERC20(WST_ETH).balanceOf(address(this)));
Expand Down
5 changes: 3 additions & 2 deletions src/TransferBundler.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.21;

import {Math} from "@morpho-utils/math/Math.sol";
import {Math} from "../lib/morpho-utils/src/math/Math.sol";
import {ErrorsLib} from "./libraries/ErrorsLib.sol";
import {SafeTransferLib, ERC20} from "solmate/src/utils/SafeTransferLib.sol";
import {SafeTransferLib, ERC20} from "../lib/solmate/src/utils/SafeTransferLib.sol";

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

Expand Down Expand Up @@ -49,6 +49,7 @@ abstract contract TransferBundler is BaseBundler {
/// @notice Warning: should only be called via the bundler's `multicall` function.
/// @dev Pass `amount = type(uint256).max` to transfer all.
function erc20TransferFrom(address asset, uint256 amount) external payable {
address initiator = initiator();
amount = Math.min(amount, ERC20(asset).balanceOf(initiator));

require(amount != 0, ErrorsLib.ZERO_AMOUNT);
Expand Down
5 changes: 3 additions & 2 deletions src/UrdBundler.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.21;

import {IUniversalRewardsDistributor} from "@universal-rewards-distributor/interfaces/IUniversalRewardsDistributor.sol";
import {IUniversalRewardsDistributor} from
"../lib/universal-rewards-distributor/src/interfaces/IUniversalRewardsDistributor.sol";

import {ErrorsLib} from "./libraries/ErrorsLib.sol";

Expand All @@ -14,7 +15,7 @@ import {BaseBundler} from "./BaseBundler.sol";
abstract contract UrdBundler is BaseBundler {
/// @notice Claims `amount` of `reward` on behalf of `account` on the given rewards distributor, using `proof`.
/// @dev Assumes the given distributor implements IUniversalRewardsDistributor.
/// @dev Pass `skipRevert == true` to avoid reverting the whole bundle in case the proof expired.
/// @dev Pass `skipRevert = true` to avoid reverting the whole bundle in case the proof expired.
function urdClaim(
address distributor,
address account,
Expand Down
6 changes: 2 additions & 4 deletions src/WNativeBundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ pragma solidity 0.8.21;

import {IWNative} from "./interfaces/IWNative.sol";

import {Math} from "@morpho-utils/math/Math.sol";
import {Math} from "../lib/morpho-utils/src/math/Math.sol";
import {ErrorsLib} from "./libraries/ErrorsLib.sol";
import {SafeTransferLib, ERC20} from "solmate/src/utils/SafeTransferLib.sol";
import {SafeTransferLib, ERC20} from "../lib/solmate/src/utils/SafeTransferLib.sol";

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

Expand Down Expand Up @@ -39,7 +39,6 @@ abstract contract WNativeBundler is BaseBundler {

/// @notice Wraps the given `amount` of the native token to wNative.
/// @notice Warning: should only be called via the bundler's `multicall` function.
/// @dev Use `BaseBundler.erc20Transfer` to transfer the wrapped native tokens to some `receiver`.
/// @dev Pass `amount = type(uint256).max` to wrap all.
function wrapNative(uint256 amount) external payable {
amount = Math.min(amount, address(this).balance);
Expand All @@ -51,7 +50,6 @@ abstract contract WNativeBundler is BaseBundler {

/// @notice Unwraps the given `amount` of wNative to the native token.
/// @notice Warning: should only be called via the bundler's `multicall` function.
/// @dev Use `BaseBundler.nativeTransfer` to transfer the unwrapped native tokens to some `receiver`.
/// @dev Pass `amount = type(uint256).max` to unwrap all.
function unwrapNative(uint256 amount) external payable {
amount = Math.min(amount, ERC20(WRAPPED_NATIVE).balanceOf(address(this)));
Expand Down
4 changes: 2 additions & 2 deletions src/ethereum/EthereumPermitBundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ abstract contract EthereumPermitBundler is PermitBundler {
/// @notice Permits DAI from sender to be spent by the bundler with the given `nonce`, `expiry` & EIP-712
/// signature's `v`, `r` & `s`.
/// @notice Warning: should only be called via the bundler's `multicall` function.
/// @dev Pass `skipRevert == true` to avoid reverting the whole bundle in case the signature expired.
/// @dev Pass `skipRevert = true` to avoid reverting the whole bundle in case the signature expired.
function permitDai(uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s, bool skipRevert)
external
payable
{
try IDaiPermit(MainnetLib.DAI).permit(initiator, address(this), nonce, expiry, allowed, v, r, s) {}
try IDaiPermit(MainnetLib.DAI).permit(initiator(), address(this), nonce, expiry, allowed, v, r, s) {}
catch (bytes memory returnData) {
if (!skipRevert) _revert(returnData);
}
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/IMorphoBundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
IMorphoSupplyCallback,
IMorphoSupplyCollateralCallback,
IMorphoFlashLoanCallback
} from "@morpho-blue/interfaces/IMorphoCallbacks.sol";
} from "../../lib/morpho-blue/src/interfaces/IMorphoCallbacks.sol";

interface IMorphoBundler is
IMorphoSupplyCallback,
Expand Down
3 changes: 3 additions & 0 deletions src/libraries/ConstantsLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ pragma solidity ^0.8.0;

/// @dev The address of the Permit2 contract on all chains.
address constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;

/// @dev The default value of the initiator of the multicall transaction is not the address zero to save gas.
address constant UNSET_INITIATOR = address(1);
Loading

0 comments on commit 4238903

Please sign in to comment.