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

fix/17-complete-natspec #302

Merged
merged 14 commits into from
Oct 30, 2023
36 changes: 22 additions & 14 deletions src/ERC4626Bundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ abstract contract ERC4626Bundler is BaseBundler {
/* ACTIONS */

/// @notice Mints the given amount of `shares` on the given ERC4626 `vault`, on behalf of `owner`.
/// @dev Pass `type(uint256).max` as `shares` to mint max.
/// @dev Assumes the given `vault` implements EIP-4626.
function erc4626Mint(address vault, uint256 shares, address owner) external payable {
require(owner != address(0), ErrorsLib.ZERO_ADDRESS);
/// Do not check `owner != address(this)` to allow the bundler to receive the vault's shares.
/// @param vault The address of the vault.
/// @param shares The amount of shares to mint. Pass `type(uint256).max` to mint max.
/// @param receiver The address to which shares will be minted.
function erc4626Mint(address vault, uint256 shares, address receiver) external payable {
require(receiver != address(0), ErrorsLib.ZERO_ADDRESS);
/// Do not check `receiver != address(this)` to allow the bundler to receive the vault's shares.

shares = Math.min(shares, IERC4626(vault).maxMint(owner));
shares = Math.min(shares, IERC4626(vault).maxMint(receiver));

address asset = IERC4626(vault).asset();
uint256 assets = Math.min(IERC4626(vault).previewMint(shares), ERC20(asset).balanceOf(address(this)));
Expand All @@ -35,34 +37,38 @@ abstract contract ERC4626Bundler is BaseBundler {
// Approve 0 first to comply with tokens that implement the anti frontrunning approval fix.
ERC20(asset).safeApprove(vault, 0);
ERC20(asset).safeApprove(vault, assets);
IERC4626(vault).mint(shares, owner);
IERC4626(vault).mint(shares, receiver);
}

/// @notice Deposits the given amount of `assets` on the given ERC4626 `vault`, on behalf of `owner`.
/// @dev Pass `type(uint256).max` as `assets` to deposit max.
/// @dev Assumes the given `vault` implements EIP-4626.
function erc4626Deposit(address vault, uint256 assets, address owner) external payable {
require(owner != address(0), ErrorsLib.ZERO_ADDRESS);
/// Do not check `owner != address(this)` to allow the bundler to receive the vault's shares.
/// @param vault The address of the vault.
/// @param assets The amount of assets to deposit. Pass `type(uint256).max` to deposit max.
/// @param receiver The address to which shares will be minted.
function erc4626Deposit(address vault, uint256 assets, address receiver) external payable {
require(receiver != address(0), ErrorsLib.ZERO_ADDRESS);
/// Do not check `receiver != address(this)` to allow the bundler to receive the vault's shares.

address asset = IERC4626(vault).asset();

assets = Math.min(assets, IERC4626(vault).maxDeposit(owner));
assets = Math.min(assets, IERC4626(vault).maxDeposit(receiver));
assets = Math.min(assets, ERC20(asset).balanceOf(address(this)));

require(assets != 0, ErrorsLib.ZERO_AMOUNT);

// Approve 0 first to comply with tokens that implement the anti frontrunning approval fix.
ERC20(asset).safeApprove(vault, 0);
ERC20(asset).safeApprove(vault, assets);
IERC4626(vault).deposit(assets, owner);
IERC4626(vault).deposit(assets, receiver);
}

/// @notice Withdraws the given amount of `assets` from the given ERC4626 `vault`, transferring assets to
/// `receiver`.
/// @notice Warning: should only be called via the bundler's `multicall` function.
/// @dev Pass `type(uint256).max` as `assets` to withdraw max.
/// @dev Assumes the given `vault` implements EIP-4626.
/// @param vault The address of the vault.
/// @param assets The amount of assets to withdraw. Pass `type(uint256).max` to withdraw max.
/// @param receiver The address that will receive the withdrawn assets.
function erc4626Withdraw(address vault, uint256 assets, address receiver) external payable {
require(receiver != address(0), ErrorsLib.ZERO_ADDRESS);
/// Do not check `receiver != address(this)` to allow the bundler to receive the underlying asset.
Expand All @@ -78,8 +84,10 @@ abstract contract ERC4626Bundler is BaseBundler {

/// @notice Redeems the given amount of `shares` from the given ERC4626 `vault`, transferring assets to `receiver`.
/// @notice Warning: should only be called via the bundler's `multicall` function.
/// @dev Pass `type(uint256).max` as `shares` to redeem max.
/// @dev Assumes the given `vault` implements EIP-4626.
/// @param vault The address of the vault.
/// @param shares The amount of shares to burn. Pass `type(uint256).max` to redeem max.
/// @param receiver The address that will receive the withdrawn assets.
function erc4626Redeem(address vault, uint256 shares, address receiver) external payable {
require(receiver != address(0), ErrorsLib.ZERO_ADDRESS);
/// Do not check `receiver != address(this)` to allow the bundler to receive the underlying asset.
Expand Down
51 changes: 43 additions & 8 deletions src/MorphoBundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ 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.
/// @param authorization The `Authorization` struct.
/// @param signature The signature.
/// @param skipRevert Whether to avoid reverting the call in case the signature is frontrunned.
function morphoSetAuthorizationWithSig(
Authorization calldata authorization,
Signature calldata signature,
Expand All @@ -68,9 +70,14 @@ abstract contract MorphoBundler is BaseBundler, IMorphoBundler {
}
}

/// @notice Supplies `amount` of `asset` of `onBehalf` using permit2 in a single tx.
/// @notice Supplies `amount` of the loan asset on behalf of `onBehalf`.
/// @notice The supplied amount cannot be used as collateral but is eligible to earn interest.
/// @dev Pass `amount = type(uint256).max` to supply the bundler's loan asset balance.
/// @param marketParams The Morpho market to supply assets to.
/// @param amount The amount of assets to supply.
/// @param shares The amount of shares to mint.
/// @param onBehalf The address that will own the increased supply position.
/// @param data Arbitrary data to pass to the `onMorphoSupply` callback. Pass empty data if not needed.
function morphoSupply(
MarketParams calldata marketParams,
uint256 amount,
Expand All @@ -90,8 +97,12 @@ abstract contract MorphoBundler is BaseBundler, IMorphoBundler {
MORPHO.supply(marketParams, amount, shares, onBehalf, data);
}

/// @notice Supplies `amount` of `asset` collateral to the pool on behalf of `onBehalf`.
/// @notice Supplies `amount` of the collateral asset on behalf of `onBehalf`.
/// @dev Pass `amount = type(uint256).max` to supply the bundler's collateral asset balance.
/// @param marketParams The Morpho market to supply collateral to.
/// @param amount The amount of collateral to supply.
/// @param onBehalf The address that will own the increased collateral position.
/// @param data Arbitrary data to pass to the `onMorphoSupplyCollateral` callback. Pass empty data if not needed.
function morphoSupplyCollateral(
MarketParams calldata marketParams,
uint256 amount,
Expand All @@ -110,18 +121,27 @@ abstract contract MorphoBundler is BaseBundler, IMorphoBundler {
MORPHO.supplyCollateral(marketParams, amount, onBehalf, data);
}

/// @notice Borrows `amount` of `asset` on behalf of the sender.
/// @notice Borrows `amount` of the loan asset on behalf of the sender.
/// @notice Warning: should only be called via the bundler's `multicall` function.
/// @dev Initiator must have previously authorized the bundler to act on their behalf on Morpho.
/// @param marketParams The Morpho market to borrow assets from.
/// @param amount The amount of assets to borrow.
/// @param shares The amount of shares to mint.
/// @param receiver The address that will receive the borrowed assets.
function morphoBorrow(MarketParams calldata marketParams, uint256 amount, uint256 shares, address receiver)
external
payable
{
MORPHO.borrow(marketParams, amount, shares, initiator(), receiver);
}

/// @notice Repays `amount` of `asset` on behalf of `onBehalf`.
/// @notice Repays `amount` of the loan asset on behalf of `onBehalf`.
/// @dev Pass `amount = type(uint256).max` to repay the bundler's loan asset balance.
/// @param marketParams The Morpho market to repay assets to.
/// @param amount The amount of assets to repay.
/// @param shares The amount of shares to burn.
/// @param onBehalf The address of the owner of the debt position.
/// @param data Arbitrary data to pass to the `onMorphoRepay` callback. Pass empty data if not needed.
function morphoRepay(
MarketParams calldata marketParams,
uint256 amount,
Expand All @@ -144,6 +164,10 @@ abstract contract MorphoBundler is BaseBundler, IMorphoBundler {
/// @notice Withdraws `amount` of the loan asset on behalf of `onBehalf`.
/// @notice Warning: should only be called via the bundler's `multicall` function.
/// @dev Initiator must have previously authorized the bundler to act on their behalf on Morpho.
/// @param marketParams The Morpho market to withdraw assets from.
/// @param amount The amount of assets to withdraw.
/// @param shares The amount of shares to burn.
/// @param receiver The address that will receive the withdrawn assets.
function morphoWithdraw(MarketParams calldata marketParams, uint256 amount, uint256 shares, address receiver)
external
payable
Expand All @@ -154,6 +178,9 @@ abstract contract MorphoBundler is BaseBundler, IMorphoBundler {
/// @notice Withdraws `amount` of the collateral asset on behalf of sender.
/// @notice Warning: should only be called via the bundler's `multicall` function.
/// @dev Initiator must have previously authorized the bundler to act on their behalf on Morpho.
/// @param marketParams The Morpho market to withdraw collateral from.
/// @param amount The amount of collateral to withdraw.
/// @param receiver The address that will receive the collateral assets.
function morphoWithdrawCollateral(MarketParams calldata marketParams, uint256 amount, address receiver)
external
payable
Expand All @@ -162,6 +189,11 @@ abstract contract MorphoBundler is BaseBundler, IMorphoBundler {
}

/// @notice Triggers a liquidation on Morpho.
/// @param marketParams The Morpho market of the position.
/// @param borrower The owner of the position.
/// @param seizedCollateral The amount of collateral to seize.
/// @param repaidShares The amount of shares to repay.
/// @param data Arbitrary data to pass to the `onMorphoLiquidate` callback. Pass empty data if not needed.
function morphoLiquidate(
MarketParams calldata marketParams,
address borrower,
Expand All @@ -175,10 +207,13 @@ abstract contract MorphoBundler is BaseBundler, IMorphoBundler {
}

/// @notice Triggers a flash loan on Morpho.
function morphoFlashLoan(address asset, uint256 amount, bytes calldata data) external payable {
_approveMaxMorpho(asset);
/// @param token The address of the token to flash loan.
/// @param assets The amount of assets to flash loan.
/// @param data Arbitrary data to pass to the `onMorphoFlashLoan` callback.
function morphoFlashLoan(address token, uint256 assets, bytes calldata data) external payable {
_approveMaxMorpho(token);

MORPHO.flashLoan(asset, amount, data);
MORPHO.flashLoan(token, assets, data);
}

/* INTERNAL */
Expand Down
2 changes: 2 additions & 0 deletions src/Permit2Bundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ abstract contract Permit2Bundler is BaseBundler {
/// @notice Permits and performs a transfer from the initiator to the recipient via Permit2.
/// @notice Warning: should only be called via the bundler's `multicall` function.
/// @dev Pass `permit.permitted.amount = type(uint256).max` to transfer all.
/// @param permit The `PermitTransferFrom` struct.
/// @param signature The signature.
function permit2TransferFrom(ISignatureTransfer.PermitTransferFrom memory permit, bytes memory signature)
external
payable
Expand Down
8 changes: 7 additions & 1 deletion src/PermitBundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ abstract contract PermitBundler is BaseBundler {
/// @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`.
/// @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.
/// @param asset The address of the token to be permitted.
/// @param amount The amount of `asset` to be permitted.
/// @param deadline The deadline of the approval.
/// @param v The `v` component of a signature.
/// @param r The `r` component of a signature.
/// @param s The `s` component of a signature.
/// @param skipRevert Whether to avoid reverting the call in case the signature is frontrunned.
function permit(address asset, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s, bool skipRevert)
Rubilmax marked this conversation as resolved.
Show resolved Hide resolved
external
payable
Expand Down
5 changes: 5 additions & 0 deletions src/StEthBundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ abstract contract StEthBundler is BaseBundler {
/* CONSTRUCTOR */

/// @dev Warning: assumes the given addresses are non-zero (they are not expected to be deployment arguments).
/// @param wstEth The address of the wstEth contract.
constructor(address wstEth) {
ST_ETH = IWstEth(wstEth).stETH();
WST_ETH = wstEth;
Expand All @@ -39,6 +40,8 @@ abstract contract StEthBundler is BaseBundler {

/// @notice Stakes the given `amount` of ETH via Lido, using the `referral` id.
/// @dev Pass `amount = type(uint256).max` to stake all.
/// @param amount The amount of ETH to stake.
/// @param referral The address of the referral regarding the Lido Rewards-Share Program.
function stakeEth(uint256 amount, address referral) external payable {
amount = Math.min(amount, address(this).balance);

Expand All @@ -49,6 +52,7 @@ abstract contract StEthBundler is BaseBundler {

/// @notice Wraps the given `amount` of stETH to wstETH.
/// @dev Pass `amount = type(uint256).max` to wrap all.
/// @param amount The amount of stEth to wrap.
function wrapStEth(uint256 amount) external payable {
amount = Math.min(amount, ERC20(ST_ETH).balanceOf(address(this)));

Expand All @@ -59,6 +63,7 @@ abstract contract StEthBundler is BaseBundler {

/// @notice Unwraps the given `amount` of wstETH to stETH.
/// @dev Pass `amount = type(uint256).max` to unwrap all.
/// @param amount The amount of wstEth to unwrap.
function unwrapStEth(uint256 amount) external payable {
amount = Math.min(amount, ERC20(WST_ETH).balanceOf(address(this)));

Expand Down
7 changes: 7 additions & 0 deletions src/TransferBundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ abstract contract TransferBundler is BaseBundler {
/// @notice Transfers the minimum between the given `amount` and the bundler's balance of native asset from the
/// bundler to `recipient`.
/// @dev Pass `amount = type(uint256).max` to transfer all.
/// @param recipient The address that will receive the native tokens.
/// @param amount The amount of native tokens to transfer.
function nativeTransfer(address recipient, uint256 amount) external payable {
require(recipient != address(0), ErrorsLib.ZERO_ADDRESS);
require(recipient != address(this), ErrorsLib.BUNDLER_ADDRESS);
Expand All @@ -34,6 +36,9 @@ abstract contract TransferBundler is BaseBundler {
/// @notice Transfers the minimum between the given `amount` and the bundler's balance of `asset` from the bundler
/// to `recipient`.
/// @dev Pass `amount = type(uint256).max` to transfer all.
/// @param asset The address of the ERC20 token to transfer.
/// @param recipient The address that will receive the tokens.
/// @param amount The amount of `asset` to transfer.
function erc20Transfer(address asset, address recipient, uint256 amount) external payable {
require(recipient != address(0), ErrorsLib.ZERO_ADDRESS);
require(recipient != address(this), ErrorsLib.BUNDLER_ADDRESS);
Expand All @@ -48,6 +53,8 @@ abstract contract TransferBundler is BaseBundler {
/// @notice Transfers the given `amount` of `asset` from sender to this contract via ERC20 transferFrom.
/// @notice Warning: should only be called via the bundler's `multicall` function.
/// @dev Pass `amount = type(uint256).max` to transfer all.
/// @param asset The address of the ERC20 token to transfer.
/// @param amount The amount of `asset` to transfer from the initiator.
function erc20TransferFrom(address asset, uint256 amount) external payable {
address initiator = initiator();
amount = Math.min(amount, ERC20(asset).balanceOf(initiator));
Expand Down
7 changes: 6 additions & 1 deletion src/UrdBundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ 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.
/// @param distributor The address of the reward distributor contract.
/// @param account The address of the owner of the rewards (also the address that will receive the rewards).
/// @param reward The address of the token reward.
/// @param amount The amount of the reward token to claim.
/// @param proof The proof.
/// @param skipRevert Whether to avoid reverting the call in case the proof is frontrunned.
function urdClaim(
Rubilmax marked this conversation as resolved.
Show resolved Hide resolved
address distributor,
address account,
Expand Down
3 changes: 3 additions & 0 deletions src/WNativeBundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ abstract contract WNativeBundler is BaseBundler {
/* CONSTRUCTOR */

/// @dev Warning: assumes the given addresses are non-zero (they are not expected to be deployment arguments).
/// @param wNative The address of the wNative token contract.
constructor(address wNative) {
WRAPPED_NATIVE = wNative;
}
Expand All @@ -41,6 +42,7 @@ 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 Pass `amount = type(uint256).max` to wrap all.
/// @param amount The amount of native token to wrap.
function wrapNative(uint256 amount) external payable {
amount = Math.min(amount, address(this).balance);

Expand All @@ -52,6 +54,7 @@ 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 Pass `amount = type(uint256).max` to unwrap all.
/// @param amount The amount of wrapped native token to unwrap.
function unwrapNative(uint256 amount) external payable {
amount = Math.min(amount, ERC20(WRAPPED_NATIVE).balanceOf(address(this)));

Expand Down
Loading
Loading