-
Notifications
You must be signed in to change notification settings - Fork 2
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
ERC4626 contracts #40
Closed
Closed
Changes from 6 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
89ffa04
Adding solmate lib 6.2.0
dimpar 675a44a
Copying ERC4626 related contracts from ERC4626-Alliance
dimpar 8103f81
Adding support for Solidity 0.8.10. Used by ERC4626 contracts
dimpar 509ddfa
Adding annotation that these contracts were copied from ERC4626-Allia…
dimpar 14b965a
Ignoring styling of added Solidity ERC4626 lib contracts
dimpar bc2ccbc
Moving erc4626 contracts under lib/erc4626 dir
dimpar 8d0a932
Removing components of ERC4626RouterBase
dimpar 93ee2bc
Adding IERC4626 interface
dimpar c2dbefe
Merge remote-tracking branch 'origin' into erc4626-contracts
dimpar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 |
---|---|---|
|
@@ -4,3 +4,4 @@ deployments/ | |
export.json | ||
export/ | ||
typechain/ | ||
contracts/lib/ |
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 |
---|---|---|
@@ -1 +1,2 @@ | ||
node_modules/ | ||
contracts/lib/ |
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,66 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
// Copied from https://github.com/ERC4626-Alliance/ERC4626-Contracts based on | ||
// the project commit 643cd04 from Apr 20, 2022 | ||
|
||
pragma solidity 0.8.10; | ||
|
||
import {IERC4626, IERC4626RouterBase, ERC20} from "./interfaces/IERC4626RouterBase.sol"; | ||
import {SafeTransferLib} from "solmate/src/utils/SafeTransferLib.sol"; | ||
|
||
import {SelfPermit} from "./external/SelfPermit.sol"; | ||
import {Multicall} from "./external/Multicall.sol"; | ||
import {PeripheryPayments, IWETH9} from "./external/PeripheryPayments.sol"; | ||
|
||
/// @title ERC4626 Router Base Contract | ||
abstract contract ERC4626RouterBase is IERC4626RouterBase, SelfPermit, Multicall, PeripheryPayments { | ||
using SafeTransferLib for ERC20; | ||
|
||
/// @inheritdoc IERC4626RouterBase | ||
function mint( | ||
IERC4626 vault, | ||
address to, | ||
uint256 shares, | ||
uint256 maxAmountIn | ||
) public payable virtual override returns (uint256 amountIn) { | ||
if ((amountIn = vault.mint(shares, to)) > maxAmountIn) { | ||
revert MaxAmountError(); | ||
} | ||
} | ||
|
||
/// @inheritdoc IERC4626RouterBase | ||
function deposit( | ||
IERC4626 vault, | ||
address to, | ||
uint256 amount, | ||
uint256 minSharesOut | ||
) public payable virtual override returns (uint256 sharesOut) { | ||
if ((sharesOut = vault.deposit(amount, to)) < minSharesOut) { | ||
revert MinSharesError(); | ||
} | ||
} | ||
|
||
/// @inheritdoc IERC4626RouterBase | ||
function withdraw( | ||
IERC4626 vault, | ||
address to, | ||
uint256 amount, | ||
uint256 maxSharesOut | ||
) public payable virtual override returns (uint256 sharesOut) { | ||
if ((sharesOut = vault.withdraw(amount, to, msg.sender)) > maxSharesOut) { | ||
revert MaxSharesError(); | ||
} | ||
} | ||
|
||
/// @inheritdoc IERC4626RouterBase | ||
function redeem( | ||
IERC4626 vault, | ||
address to, | ||
uint256 shares, | ||
uint256 minAmountOut | ||
) public payable virtual override returns (uint256 amountOut) { | ||
if ((amountOut = vault.redeem(shares, to, msg.sender)) < minAmountOut) { | ||
revert MinAmountError(); | ||
} | ||
} | ||
} |
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,33 @@ | ||
// forked from https://github.com/Uniswap/v3-periphery/blob/main/contracts/base/Multicall.sol | ||
|
||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
// Copied from https://github.com/ERC4626-Alliance/ERC4626-Contracts based on | ||
// the project commit 643cd04 from Apr 20, 2022 | ||
|
||
pragma solidity >=0.7.6; | ||
|
||
import './interfaces/IMulticall.sol'; | ||
|
||
/// @title Multicall | ||
/// @notice Enables calling multiple methods in a single call to the contract | ||
abstract contract Multicall is IMulticall { | ||
/// @inheritdoc IMulticall | ||
function multicall(bytes[] calldata data) public payable override returns (bytes[] memory results) { | ||
results = new bytes[](data.length); | ||
for (uint256 i = 0; i < data.length; i++) { | ||
(bool success, bytes memory result) = address(this).delegatecall(data[i]); | ||
|
||
if (!success) { | ||
// Next 5 lines from https://ethereum.stackexchange.com/a/83577 | ||
if (result.length < 68) revert(); | ||
assembly { | ||
result := add(result, 0x04) | ||
} | ||
revert(abi.decode(result, (string))); | ||
} | ||
|
||
results[i] = result; | ||
} | ||
} | ||
} |
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,80 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
// Copied from https://github.com/ERC4626-Alliance/ERC4626-Contracts based on | ||
// the project commit 643cd04 from Apr 20, 2022 | ||
|
||
pragma solidity >=0.7.5; | ||
|
||
import "solmate/src/utils/SafeTransferLib.sol"; | ||
|
||
/** | ||
@title Periphery Payments | ||
@notice Immutable state used by periphery contracts | ||
Largely Forked from https://github.com/Uniswap/v3-periphery/blob/main/contracts/base/PeripheryPayments.sol | ||
Changes: | ||
* no interface | ||
* no inheritdoc | ||
* add immutable WETH9 in constructor instead of PeripheryImmutableState | ||
* receive from any address | ||
* Solmate interfaces and transfer lib | ||
* casting | ||
* add approve, wrapWETH9 and pullToken | ||
*/ | ||
abstract contract PeripheryPayments { | ||
using SafeTransferLib for *; | ||
|
||
IWETH9 public immutable WETH9; | ||
|
||
constructor(IWETH9 _WETH9) { | ||
WETH9 = _WETH9; | ||
} | ||
|
||
receive() external payable {} | ||
|
||
function approve(ERC20 token, address to, uint256 amount) public payable { | ||
token.safeApprove(to, amount); | ||
} | ||
|
||
function unwrapWETH9(uint256 amountMinimum, address recipient) public payable { | ||
uint256 balanceWETH9 = WETH9.balanceOf(address(this)); | ||
require(balanceWETH9 >= amountMinimum, 'Insufficient WETH9'); | ||
|
||
if (balanceWETH9 > 0) { | ||
WETH9.withdraw(balanceWETH9); | ||
recipient.safeTransferETH(balanceWETH9); | ||
} | ||
} | ||
|
||
function wrapWETH9() public payable { | ||
if (address(this).balance > 0) WETH9.deposit{value: address(this).balance}(); // wrap everything | ||
} | ||
|
||
function pullToken(ERC20 token, uint256 amount, address recipient) public payable { | ||
token.safeTransferFrom(msg.sender, recipient, amount); | ||
} | ||
|
||
function sweepToken( | ||
ERC20 token, | ||
uint256 amountMinimum, | ||
address recipient | ||
) public payable { | ||
uint256 balanceToken = token.balanceOf(address(this)); | ||
require(balanceToken >= amountMinimum, 'Insufficient token'); | ||
|
||
if (balanceToken > 0) { | ||
token.safeTransfer(recipient, balanceToken); | ||
} | ||
} | ||
|
||
function refundETH() external payable { | ||
if (address(this).balance > 0) SafeTransferLib.safeTransferETH(msg.sender, address(this).balance); | ||
} | ||
} | ||
|
||
abstract contract IWETH9 is ERC20 { | ||
/// @notice Deposit ether to get wrapped ether | ||
function deposit() external payable virtual; | ||
|
||
/// @notice Withdraw wrapped ether to get ether | ||
function withdraw(uint256) external virtual; | ||
} |
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,66 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
// Copied from https://github.com/ERC4626-Alliance/ERC4626-Contracts based on | ||
// the project commit 643cd04 from Apr 20, 2022 | ||
|
||
pragma solidity >=0.5.0; | ||
|
||
import {ERC20} from "solmate/src/tokens/ERC20.sol"; | ||
|
||
import './interfaces/ISelfPermit.sol'; | ||
import './interfaces/IERC20PermitAllowed.sol'; | ||
|
||
/// @title Self Permit | ||
/// @notice Functionality to call permit on any EIP-2612-compliant token for use in the route | ||
/// @dev These functions are expected to be embedded in multicalls to allow EOAs to approve a contract and call a function | ||
/// that requires an approval in a single transaction. | ||
abstract contract SelfPermit is ISelfPermit { | ||
/// @inheritdoc ISelfPermit | ||
function selfPermit( | ||
address token, | ||
uint256 value, | ||
uint256 deadline, | ||
uint8 v, | ||
bytes32 r, | ||
bytes32 s | ||
) public payable override { | ||
ERC20(token).permit(msg.sender, address(this), value, deadline, v, r, s); | ||
} | ||
|
||
/// @inheritdoc ISelfPermit | ||
function selfPermitIfNecessary( | ||
address token, | ||
uint256 value, | ||
uint256 deadline, | ||
uint8 v, | ||
bytes32 r, | ||
bytes32 s | ||
) external payable override { | ||
if (ERC20(token).allowance(msg.sender, address(this)) < value) selfPermit(token, value, deadline, v, r, s); | ||
} | ||
|
||
/// @inheritdoc ISelfPermit | ||
function selfPermitAllowed( | ||
address token, | ||
uint256 nonce, | ||
uint256 expiry, | ||
uint8 v, | ||
bytes32 r, | ||
bytes32 s | ||
) public payable override { | ||
IERC20PermitAllowed(token).permit(msg.sender, address(this), nonce, expiry, true, v, r, s); | ||
} | ||
|
||
/// @inheritdoc ISelfPermit | ||
function selfPermitAllowedIfNecessary( | ||
address token, | ||
uint256 nonce, | ||
uint256 expiry, | ||
uint8 v, | ||
bytes32 r, | ||
bytes32 s | ||
) external payable override { | ||
if (ERC20(token).allowance(msg.sender, address(this)) < type(uint256).max) | ||
selfPermitAllowed(token, nonce, expiry, v, r, s); | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
core/contracts/lib/erc4626/external/interfaces/IERC20PermitAllowed.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,33 @@ | ||
// forked from https://github.com/Uniswap/v3-periphery/blob/main/contracts/interfaces/external/IERC20PermitAllowed.sol | ||
|
||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
// Copied from https://github.com/ERC4626-Alliance/ERC4626-Contracts based on | ||
// the project commit 643cd04 from Apr 20, 2022 | ||
|
||
pragma solidity >=0.5.0; | ||
|
||
/// @title Interface for permit | ||
/// @notice Interface used by DAI/CHAI for permit | ||
interface IERC20PermitAllowed { | ||
/// @notice Approve the spender to spend some tokens via the holder signature | ||
/// @dev This is the permit interface used by DAI and CHAI | ||
/// @param holder The address of the token holder, the token owner | ||
/// @param spender The address of the token spender | ||
/// @param nonce The holder's nonce, increases at each call to permit | ||
/// @param expiry The timestamp at which the permit is no longer valid | ||
/// @param allowed Boolean that sets approval amount, true for type(uint256).max and false for 0 | ||
/// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` | ||
/// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` | ||
/// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` | ||
function permit( | ||
address holder, | ||
address spender, | ||
uint256 nonce, | ||
uint256 expiry, | ||
bool allowed, | ||
uint8 v, | ||
bytes32 r, | ||
bytes32 s | ||
) external; | ||
} |
18 changes: 18 additions & 0 deletions
18
core/contracts/lib/erc4626/external/interfaces/IMulticall.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,18 @@ | ||
// forked from https://github.com/Uniswap/v3-periphery/blob/main/contracts/interfaces/IMulticall.sol | ||
|
||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
// Copied from https://github.com/ERC4626-Alliance/ERC4626-Contracts based on | ||
// the project commit 643cd04 from Apr 20, 2022 | ||
|
||
pragma solidity >=0.7.5; | ||
|
||
/// @title Multicall interface | ||
/// @notice Enables calling multiple methods in a single call to the contract | ||
interface IMulticall { | ||
/// @notice Call multiple functions in the current contract and return the data from all of them if they all succeed | ||
/// @dev The `msg.value` should not be trusted for any method callable from multicall. | ||
/// @param data The encoded function data for each of the calls to make to this contract | ||
/// @return results The results from each of the calls passed in via data | ||
function multicall(bytes[] calldata data) external payable returns (bytes[] memory results); | ||
} |
82 changes: 82 additions & 0 deletions
82
core/contracts/lib/erc4626/external/interfaces/ISelfPermit.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,82 @@ | ||
// forked from https://github.com/Uniswap/v3-periphery/blob/main/contracts/interfaces/ISelfPermit.sol | ||
|
||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
// Copied from https://github.com/ERC4626-Alliance/ERC4626-Contracts based on | ||
// the project commit 643cd04 from Apr 20, 2022 | ||
|
||
pragma solidity >=0.7.5; | ||
|
||
/// @title Self Permit | ||
/// @notice Functionality to call permit on any EIP-2612-compliant token for use in the route | ||
interface ISelfPermit { | ||
/// @notice Permits this contract to spend a given token from `msg.sender` | ||
/// @dev The `owner` is always msg.sender and the `spender` is always address(this). | ||
/// @param token The address of the token spent | ||
/// @param value The amount that can be spent of token | ||
/// @param deadline A timestamp, the current blocktime must be less than or equal to this timestamp | ||
/// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` | ||
/// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` | ||
/// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` | ||
function selfPermit( | ||
address token, | ||
uint256 value, | ||
uint256 deadline, | ||
uint8 v, | ||
bytes32 r, | ||
bytes32 s | ||
) external payable; | ||
|
||
/// @notice Permits this contract to spend a given token from `msg.sender` | ||
/// @dev The `owner` is always msg.sender and the `spender` is always address(this). | ||
/// Can be used instead of #selfPermit to prevent calls from failing due to a frontrun of a call to #selfPermit | ||
/// @param token The address of the token spent | ||
/// @param value The amount that can be spent of token | ||
/// @param deadline A timestamp, the current blocktime must be less than or equal to this timestamp | ||
/// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` | ||
/// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` | ||
/// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` | ||
function selfPermitIfNecessary( | ||
address token, | ||
uint256 value, | ||
uint256 deadline, | ||
uint8 v, | ||
bytes32 r, | ||
bytes32 s | ||
) external payable; | ||
|
||
/// @notice Permits this contract to spend the sender's tokens for permit signatures that have the `allowed` parameter | ||
/// @dev The `owner` is always msg.sender and the `spender` is always address(this) | ||
/// @param token The address of the token spent | ||
/// @param nonce The current nonce of the owner | ||
/// @param expiry The timestamp at which the permit is no longer valid | ||
/// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` | ||
/// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` | ||
/// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` | ||
function selfPermitAllowed( | ||
address token, | ||
uint256 nonce, | ||
uint256 expiry, | ||
uint8 v, | ||
bytes32 r, | ||
bytes32 s | ||
) external payable; | ||
|
||
/// @notice Permits this contract to spend the sender's tokens for permit signatures that have the `allowed` parameter | ||
/// @dev The `owner` is always msg.sender and the `spender` is always address(this) | ||
/// Can be used instead of #selfPermitAllowed to prevent calls from failing due to a frontrun of a call to #selfPermitAllowed. | ||
/// @param token The address of the token spent | ||
/// @param nonce The current nonce of the owner | ||
/// @param expiry The timestamp at which the permit is no longer valid | ||
/// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` | ||
/// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` | ||
/// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` | ||
function selfPermitAllowedIfNecessary( | ||
address token, | ||
uint256 nonce, | ||
uint256 expiry, | ||
uint8 v, | ||
bytes32 r, | ||
bytes32 s | ||
) external payable; | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure we will need the
ERC4626RouterBase
in the current form. Especially due to thePeripheryPayments
dependency which is flavoured with WETH9.Could we focus this PR around pure ERC4626 and skip the router for now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here are the reasons why I think we should leave
ERC4626RouterBase
:minAmountOut
assets param that protects us from redeeming less than we want.PeripheryPayments
has some basic build-in functions for pulling tokens from Allocators(erc4626) or approving vaults. Also, I'm not yet sure how the Reserve will be used, maybe there will be a need of allocating WBTC / WETH through the Router contract and these wrappers ETH<->WETH might be handy actually.Multicall
might also be handy if we'd want to use multiple methods of a contract in a single call that will optimize gas usage.If we were to use
erc4626
from Alliance using Foundry or just from git submodule then these functionalities (and even more) are embeded in the lib. I've already cut some of the corners removingERC4626Router
andENSReverseRecord
. The bottom line I'm treating these contracts as a library and although I do agree that some of the functions might not be used, but this is the case with any lib.But as always, if you feel strongly against having this
ERC4626RouterBase
in Acre, I'll remove it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The router in our case will be used to route tBTC from the main Acre contract to the ERC4626 Vaults. I don't think we will need the feature of WETH9 wrapping.
ERC4626RouterBase
implementation is extensive and seems pretty opinionated. I'm afraid it introduces a code that won't be used but may bring a risk of including hidden bugs.Moreover, the
ERC4626-Alliance
library hasn't been extensively audited and doesn't seem like it is actively maintained (the last commit was in April 2022). There is also a bug in the xERC4626 implementation that hasn't been fixed ERC4626-Alliance/ERC4626-Contracts#24.The EIP-4626 hasn't defined the router contract, it's a very individual decision on how it will be implemented. I would feel more comfortable if we implement our router contract by taking inspiration from the ERC4626RouterBase and pulling only the code that actually will be needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right,
ERC4626RouterBase
is a utility lib, but written by one of the authors of EIP-4626 and it's considered to be a canonical router that other project(s) such as Yearn base their routers too.This lib is used by for example by Fei Protocol and it was audited as part their tribe-turbo project here
Very recently Aug 29, 2023 Yearn also based their router on
ERC4626RouterBase
which was also audited hereMy point is that this lib has been out there for a while, was audited and already big players use it or base their routers on the canonical ERC4626RouterBase contract.
Agree it's upon us. And as I mentioned, if you don't feel comfortable, I'll remove it in the next commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to clarify, it has nothing to do with a Router, so I'm a bit confused, do you want to remove
xERC4626
also? My understanding was thatstBTC
will inherit fromxERC4626
which helps to distribute rewards over time rather than immediately and has some other improvement features over ERC4626.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing ERC4626RouterBase and its components: 8d0a932
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It shows that there may be other hidden bugs in the library that hasn't been discovered yet.
In this PR we should focus on ERC4626/xERC4626 to unblock staking work and carry on with router in a separate PR. I don't want to rush into copying the ERC4626RouterBase until we fully understand what we need.
Thank you!