Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Base Bundler #430

Merged
merged 51 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from 49 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
4014e7e
feat: base bundler
MathisGD May 6, 2024
afad0b9
chore: readd removed files
MathisGD May 6, 2024
70c3052
chore: fix ci
MathisGD May 6, 2024
03c63b0
chore: improve ci names
MathisGD May 6, 2024
7a711c1
test: make tests pass
MathisGD May 7, 2024
72d6a3a
test: fix permit test
MathisGD May 7, 2024
22cc6d1
chore: rename ethereum folder fork
MathisGD May 7, 2024
73b4a60
test: remove ethereum test helper
MathisGD May 7, 2024
8d46f69
test: rename files
MathisGD May 7, 2024
613bddc
test: harmonization
MathisGD May 7, 2024
7bec750
chore: little fixes in the ci
MathisGD May 13, 2024
ccac0bf
test: remove mocks
MathisGD May 13, 2024
13c711f
test: fix wrong changes in refactor
MathisGD May 13, 2024
1e9b7d3
test: fix aave v3 test not working (dai not listed on base)
MathisGD May 13, 2024
2c982d4
chore: remove chain matrix for local tests
MathisGD May 13, 2024
86b7a5d
refactor: pass weth address as argument to have the same init bytecod…
MathisGD May 13, 2024
de336f3
test: fix tests on base
MathisGD May 13, 2024
ee89eba
Merge branch 'feat/base' into refactor/bytecode
MathisGD May 13, 2024
90aa49f
Merge branch 'feat/base' into test/refactor
MathisGD May 13, 2024
99cb382
style: rename base bundler
MathisGD May 13, 2024
7cc029a
test: rename baseTest
MathisGD May 13, 2024
46cc4c5
test: fix test on ethereum
MathisGD May 14, 2024
516a56d
Merge branch 'feat/base' into refactor/bytecode
MathisGD May 14, 2024
b9d5c80
Merge branch 'feat/base' into style/rootbundler
MathisGD May 14, 2024
ad02191
test: fix base test
MathisGD May 14, 2024
cf9bbdc
Merge branch 'feat/base' into style/rootbundler
MathisGD May 14, 2024
61cd8bb
Merge branch 'feat/base' into refactor/bytecode
MathisGD May 14, 2024
29b9b8b
Merge branch 'feat/base' into test/refactor
MathisGD May 14, 2024
0d9ad2a
Merge remote-tracking branch 'origin/test/refactor' into test/refactor
MathisGD May 14, 2024
5ec8016
test: docs
MathisGD May 14, 2024
21dace2
style: rename root => core
MathisGD May 14, 2024
38dd53f
chore: use relative path
MathisGD May 14, 2024
980905d
Merge pull request #434 from morpho-org/style/rootbundler
MathisGD May 14, 2024
cefa93d
Merge branch 'feat/base' into refactor/bytecode
MathisGD May 14, 2024
0b63fe5
Merge pull request #433 from morpho-org/refactor/bytecode
MathisGD May 14, 2024
d1e033b
test: one single mock
MathisGD May 14, 2024
ed250d5
Merge branch 'feat/base' into test/refactor
MathisGD May 14, 2024
534b13c
Merge branch 'main' into feat/base
MathisGD May 14, 2024
0268771
Merge remote-tracking branch 'origin/feat/base' into test/refactor
MathisGD May 14, 2024
dc0248c
test: rename files
MathisGD May 14, 2024
42a5e62
test: rename files
MathisGD May 14, 2024
703aac3
test: rename files
MathisGD May 14, 2024
3c545fb
Merge branch 'feat/base' into test/refactor
MathisGD May 14, 2024
5603f2a
test: fix renaming issues
MathisGD May 14, 2024
79da167
Merge branch 'feat/base' into test/refactor
MathisGD May 14, 2024
916df26
Merge pull request #432 from morpho-org/test/refactor
MathisGD May 14, 2024
bee2439
docs: document agnostic bunder
MathisGD May 14, 2024
3bec728
test: minor improvements
MathisGD May 14, 2024
3b916f6
test: minor improvements
MathisGD May 14, 2024
4b42813
test: run fork tests by default on Ethereum
MathisGD May 15, 2024
c5eeccf
docs: forge t --chain
MathisGD May 15, 2024
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
11 changes: 6 additions & 5 deletions .github/workflows/foundry.yml
MathisGD marked this conversation as resolved.
Show resolved Hide resolved
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]
MathisGD marked this conversation as resolved.
Show resolved Hide resolved
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
2 changes: 1 addition & 1 deletion README.md
MathisGD marked this conversation as resolved.
Show resolved Hide resolved
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 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>`)");
MerlinEgalite marked this conversation as resolved.
Show resolved Hide resolved
} 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",
MathisGD marked this conversation as resolved.
Show resolved Hide resolved
"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"
MathisGD marked this conversation as resolved.
Show resolved Hide resolved
}
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 security@morpho.org
/// @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 security@morpho.org
/// @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 security@morpho.org
/// @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 security@morpho.xyz
/// @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 security@morpho.xyz
/// @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 security@morpho.org
/// @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 security@morpho.org
/// @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 security@morpho.xyz
/// @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 security@morpho.org
/// @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
Loading