Skip to content

Commit

Permalink
Merge pull request #430 from morpho-org/feat/base
Browse files Browse the repository at this point in the history
Base Bundler
  • Loading branch information
MathisGD authored May 15, 2024
2 parents 2241f19 + c5eeccf commit 5bef994
Show file tree
Hide file tree
Showing 62 changed files with 341 additions and 366 deletions.
11 changes: 6 additions & 5 deletions .github/workflows/foundry.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,22 +104,23 @@ jobs:

- uses: ./.github/actions/install-cache

- name: Run local tests in ${{ matrix.type }} mode
- name: Run local tests on chain ${{ matrix.chain }} in ${{ matrix.type }} mode
run: yarn test:forge:local
env:
FOUNDRY_FUZZ_RUNS: ${{ matrix.fuzz-runs }}
FOUNDRY_FUZZ_MAX_TEST_REJECTS: ${{ matrix.max-test-rejects }}
FOUNDRY_FUZZ_SEED: 0x${{ github.event.pull_request.base.sha || github.sha }}

test-ethereum:
test-fork:
needs: build-no-ir

name: Ethereum tests
name: Fork tests (chainid=${{ matrix.chain }})
runs-on: ubuntu-latest

strategy:
fail-fast: true
matrix:
chain: [1, 8453]
type: ["slow", "fast"]
include:
- type: "slow"
Expand All @@ -145,8 +146,8 @@ jobs:

- uses: ./.github/actions/install-cache

- name: Run ethereum tests in ${{ matrix.type }} mode
run: yarn test:forge:ethereum
- name: Run fork tests on chain ${{ matrix.chain }} in ${{ matrix.type }} mode
run: yarn test:forge:fork --chain ${{ matrix.chain }}
env:
ALCHEMY_KEY: ${{ secrets.ALCHEMY_KEY }}
FOUNDRY_FUZZ_RUNS: ${{ matrix.fuzz-runs }}
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

![image (4)](https://github.com/morpho-org/morpho-blue-bundlers/assets/44097430/5cb0796b-c20c-415e-840d-8b0705836dc8)

Each Bundler is a domain-specific abstract layer of contract that implements some functions that can be bundled in a single call by EOAs to a single contract. They all inherit from [`BaseBundler`](./src/BaseBundler.sol) that enables bundling multiple function calls into a single `multicall(bytes[] calldata data)` call to the end bundler contract. Each chain-specific bundler is available under their chain-specific folder (e.g. [`ethereum`](./src/ethereum/)).
Each Bundler is a domain-specific abstract layer of contract that implements some functions that can be bundled in a single call by EOAs to a single contract. They all inherit from [`CoreBundler`](./src/CoreBundler.sol) that enables bundling multiple function calls into a single `multicall(bytes[] calldata data)` call to the end bundler contract. Each chain-specific bundler is available under their chain-specific folder (e.g. [`ethereum`](./src/ethereum/)).

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)).

Expand All @@ -16,7 +16,7 @@ User-end bundlers are provided in each chain-specific folder, instanciating all

Install dependencies with `yarn`.

Run tests with `yarn test:forge`.
Run tests with `yarn test:forge --chain <chainid>` (chainid can be 1 or 8453).

Note that the `EthereumBundlerV2` has been deployed with 80 000 optimizer runs.
To compile contracts with the same configuration, run `FOUNDRY_PROFILE=ethereumBundlerV2 forge b`.
Expand Down
33 changes: 25 additions & 8 deletions config/Configured.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {Config, ConfigMarket, ConfigLib} from "./ConfigLib.sol";

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

import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";

abstract contract Configured is StdChains {
using ConfigLib for Config;

Expand All @@ -19,6 +21,10 @@ abstract contract Configured is StdChains {
address internal WBTC;
address internal WETH;
address internal WNATIVE;
address internal ST_ETH;
address internal WST_ETH;
address internal CB_ETH;
address internal S_DAI;
address[] internal allAssets;

address internal AAVE_V2_POOL;
Expand All @@ -32,29 +38,40 @@ abstract contract Configured is StdChains {

ConfigMarket[] internal configMarkets;

function _network() internal view virtual returns (string memory);
string internal network;

function _loadConfig() internal virtual {
if (block.chainid == 0) {
revert("chain id must be specified (`--chain <chainid>`)");
} else if (block.chainid == 1) {
network = "ethereum";
} else if (block.chainid == 8453) {
network = "base";
} else {
revert(string.concat("no config for chain ", Strings.toString(block.chainid)));
}

function _initConfig() internal returns (Config storage) {
// Fetch config.
if (bytes(CONFIG.json).length == 0) {
string memory root = vm.projectRoot();
string memory path = string.concat(root, "/config/", _network(), ".json");
string memory path = string.concat(root, "/config/", network, ".json");

CONFIG.json = vm.readFile(path);
}

return CONFIG;
}

function _loadConfig() internal virtual {
DAI = CONFIG.getAddress("DAI");
USDC = CONFIG.getAddress("USDC");
USDT = CONFIG.getAddress("USDT");
LINK = CONFIG.getAddress("LINK");
WBTC = CONFIG.getAddress("WBTC");
WETH = CONFIG.getAddress("WETH");
WNATIVE = CONFIG.getWrappedNative();
ST_ETH = CONFIG.getAddress("stETH");
WST_ETH = CONFIG.getAddress("wstETH");
CB_ETH = CONFIG.getAddress("cbETH");
S_DAI = CONFIG.getAddress("sDai");

allAssets = [DAI, USDC, USDT, LINK, WBTC, WETH];
allAssets = [DAI, USDC, USDT, LINK, WBTC, WETH, ST_ETH, WST_ETH, CB_ETH, S_DAI];

ConfigMarket[] memory allConfigMarkets = CONFIG.getMarkets();
for (uint256 i; i < allConfigMarkets.length; ++i) {
Expand Down
33 changes: 0 additions & 33 deletions config/ConfiguredEthereum.sol

This file was deleted.

31 changes: 31 additions & 0 deletions config/base.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"chainId": 8453,
"forkBlockNumber": 14000000,
"markets": [
{
"loanToken": "WETH",
"collateralToken": "WETH",
"lltv": 800000000000000000
}
],
"DAI": "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb",
"USDC": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"LINK": "0xC9EbC2469E403DD89eAcA78C6B0b216fc7501011",
"WETH": "0x4200000000000000000000000000000000000006",
"wrappedNative": "WETH",
"aaveV3Pool": "0xA238Dd80C259a72e81d7e4664a9801593F98d1c5",
"cWETHv3": "0x46e6b214b524310239732D51387075E0e70970bf",
"cbETH": "0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22",
"USDT": "0x0000000000000000000000000000000000000000",
"WBTC": "0x0000000000000000000000000000000000000000",
"stETH": "0x0000000000000000000000000000000000000000",
"wstETH": "0x0000000000000000000000000000000000000000",
"rETH": "0x0000000000000000000000000000000000000000",
"sDai": "0x0000000000000000000000000000000000000000",
"aaveV2Pool": "0x0000000000000000000000000000000000000000",
"aaveV3Optimizer": "0x0000000000000000000000000000000000000000",
"comptroller": "0x0000000000000000000000000000000000000000",
"cDAIv2": "0x0000000000000000000000000000000000000000",
"cETHv2": "0x0000000000000000000000000000000000000000",
"cUSDCv2": "0x0000000000000000000000000000000000000000"
}
1 change: 1 addition & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ runs = 16

[profile.default.rpc_endpoints]
ethereum = "https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}"
base = "https://base-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}"
tenderly = "https://rpc.tenderly.co/fork/${TENDERLY_FORK_ID}"


Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"typecheck": "tsc --noEmit",
"test:forge": "FOUNDRY_PROFILE=test forge test",
"test:forge:local": "FOUNDRY_MATCH_CONTRACT=LocalTest yarn test:forge",
"test:forge:ethereum": "FOUNDRY_MATCH_CONTRACT=EthereumTest yarn test:forge",
"test:forge:fork": "FOUNDRY_MATCH_CONTRACT=ForkTest yarn test:forge",
"test:hardhat": "hardhat test",
"lint": "yarn lint:forge && yarn lint:ts",
"lint:ts": "prettier --check pkg",
Expand Down
4 changes: 2 additions & 2 deletions src/BaseBundler.sol → src/CoreBundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import {ErrorsLib} from "./libraries/ErrorsLib.sol";
import {UNSET_INITIATOR} from "./libraries/ConstantsLib.sol";
import {SafeTransferLib, ERC20} from "../lib/solmate/src/utils/SafeTransferLib.sol";

/// @title BaseBundler
/// @title CoreBundler
/// @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 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.
abstract contract BaseBundler is IMulticall {
abstract contract CoreBundler is IMulticall {
using SafeTransferLib for ERC20;

/* STORAGE */
Expand Down
4 changes: 2 additions & 2 deletions src/ERC20WrapperBundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {ErrorsLib} from "./libraries/ErrorsLib.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";
import {CoreBundler} from "./CoreBundler.sol";
import {ERC20Wrapper} from "../lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Wrapper.sol";

/// @title ERC20WrapperBundler
Expand All @@ -14,7 +14,7 @@ import {ERC20Wrapper} from "../lib/openzeppelin-contracts/contracts/token/ERC20/
/// @notice Enables the wrapping and unwrapping of ERC20 tokens. The largest usecase is to wrap permissionless tokens to
/// their permissioned counterparts and access permissioned markets on Morpho Blue. Permissioned tokens can be built
/// using: https://github.com/morpho-org/erc20-permissioned
abstract contract ERC20WrapperBundler is BaseBundler {
abstract contract ERC20WrapperBundler is CoreBundler {
using SafeTransferLib for ERC20;

/* WRAPPER ACTIONS */
Expand Down
4 changes: 2 additions & 2 deletions src/ERC4626Bundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import {Math} from "../lib/morpho-utils/src/math/Math.sol";
import {ErrorsLib} from "./libraries/ErrorsLib.sol";
import {SafeTransferLib, ERC20} from "../lib/solmate/src/utils/SafeTransferLib.sol";

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

/// @title ERC4626Bundler
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Bundler contract managing interactions with ERC4626 compliant tokens.
abstract contract ERC4626Bundler is BaseBundler {
abstract contract ERC4626Bundler is CoreBundler {
using SafeTransferLib for ERC20;

/* ACTIONS */
Expand Down
6 changes: 3 additions & 3 deletions src/MorphoBundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import {MarketParams, Signature, Authorization, IMorpho} from "../lib/morpho-blu
import {ErrorsLib} from "./libraries/ErrorsLib.sol";
import {SafeTransferLib, ERC20} from "../lib/solmate/src/utils/SafeTransferLib.sol";

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

/// @title MorphoBundler
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Bundler contract managing interactions with Morpho.
abstract contract MorphoBundler is BaseBundler, IMorphoBundler {
abstract contract MorphoBundler is CoreBundler, IMorphoBundler {
using SafeTransferLib for ERC20;

/* IMMUTABLES */
Expand Down Expand Up @@ -264,7 +264,7 @@ abstract contract MorphoBundler is BaseBundler, IMorphoBundler {
_multicall(abi.decode(data, (bytes[])));
}

/// @inheritdoc BaseBundler
/// @inheritdoc CoreBundler
function _isSenderAuthorized() internal view virtual override returns (bool) {
return super._isSenderAuthorized() || msg.sender == address(MORPHO);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Permit2Bundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import {Permit2Lib} from "../lib/permit2/src/libraries/Permit2Lib.sol";
import {SafeCast160} from "../lib/permit2/src/libraries/SafeCast160.sol";
import {ERC20} from "../lib/solmate/src/tokens/ERC20.sol";

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

/// @title Permit2Bundler
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Bundler contract managing interactions with Uniswap's Permit2.
abstract contract Permit2Bundler is BaseBundler {
abstract contract Permit2Bundler is CoreBundler {
using SafeCast160 for uint256;

/* ACTIONS */
Expand Down
4 changes: 2 additions & 2 deletions src/PermitBundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ pragma solidity 0.8.24;

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

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

/// @title PermitBundler
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Bundler contract managing interactions with tokens implementing EIP-2612.
abstract contract PermitBundler is BaseBundler {
abstract contract PermitBundler is CoreBundler {
/// @notice Permits the given `amount` of `asset` from sender to be spent by the bundler via EIP-2612 Permit with
/// the given `deadline` & EIP-712 signature's `v`, `r` & `s`.
/// @param asset The address of the token to be permitted.
Expand Down
4 changes: 2 additions & 2 deletions src/StEthBundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import {Math} from "../lib/morpho-utils/src/math/Math.sol";
import {ErrorsLib} from "./libraries/ErrorsLib.sol";
import {SafeTransferLib, ERC20} from "../lib/solmate/src/utils/SafeTransferLib.sol";

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

/// @title StEthBundler
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Contract allowing to bundle multiple interactions with stETH together.
abstract contract StEthBundler is BaseBundler {
abstract contract StEthBundler is CoreBundler {
using SafeTransferLib for ERC20;

/* IMMUTABLES */
Expand Down
4 changes: 2 additions & 2 deletions src/TransferBundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import {Math} from "../lib/morpho-utils/src/math/Math.sol";
import {ErrorsLib} from "./libraries/ErrorsLib.sol";
import {SafeTransferLib, ERC20} from "../lib/solmate/src/utils/SafeTransferLib.sol";

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

/// @title TransferBundler
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Enables transfer of ERC20 and native tokens.
/// @dev Assumes that any tokens left on the contract can be seized by anyone.
abstract contract TransferBundler is BaseBundler {
abstract contract TransferBundler is CoreBundler {
using SafeTransferLib for ERC20;

/* TRANSFER ACTIONS */
Expand Down
4 changes: 2 additions & 2 deletions src/UrdBundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import {IUniversalRewardsDistributor} from

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

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

/// @title UrdBundler
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Bundler that allows to claim token rewards on the Universal Rewards Distributor.
abstract contract UrdBundler is BaseBundler {
abstract contract UrdBundler is CoreBundler {
/// @notice Claims `amount` of `reward` on behalf of `account` on the given rewards distributor, using `proof`.
/// @dev Assumes the given distributor implements IUniversalRewardsDistributor.
/// @param distributor The address of the reward distributor contract.
Expand Down
4 changes: 2 additions & 2 deletions src/WNativeBundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import {Math} from "../lib/morpho-utils/src/math/Math.sol";
import {ErrorsLib} from "./libraries/ErrorsLib.sol";
import {SafeTransferLib, ERC20} from "../lib/solmate/src/utils/SafeTransferLib.sol";

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

/// @title WNativeBundler
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Bundler contract managing interactions with network's wrapped native token.
/// @notice "wrapped native" refers to forks of WETH.
abstract contract WNativeBundler is BaseBundler {
abstract contract WNativeBundler is CoreBundler {
using SafeTransferLib for ERC20;

/* IMMUTABLES */
Expand Down
Loading

0 comments on commit 5bef994

Please sign in to comment.