From dfec9bfe90610af1efcaf4ea4f1deeb1163ce88b Mon Sep 17 00:00:00 2001 From: Dmitry Date: Fri, 8 Dec 2023 17:37:02 +0100 Subject: [PATCH] Adding deposit and redeem functionality Renamed AcreRouter to Dispatcher and introduced an abstract contract called Router that will handle moving funds between Acre and Vaults. In order to deposit / redeem assets, Acre contract should approve assets for Dispatcher to spend and call depositToVault or redeemFromVault functions. These Acre's functions can be also called by a bot for rebalancing purposes. --- core/contracts/Dispatcher.sol | 26 ++++++++++++++++ core/contracts/Router.sol | 57 +++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 core/contracts/Router.sol diff --git a/core/contracts/Dispatcher.sol b/core/contracts/Dispatcher.sol index 309da2ae8..6a17bcf91 100644 --- a/core/contracts/Dispatcher.sol +++ b/core/contracts/Dispatcher.sol @@ -2,6 +2,8 @@ pragma solidity ^0.8.21; import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/interfaces/IERC4626.sol"; +import "./Router.sol"; /// @title Dispatcher /// @notice Dispatcher is a contract that routes TBTC from stBTC (Acre) to @@ -66,4 +68,28 @@ contract Dispatcher is Ownable { function getVaults() external view returns (address[] memory) { return vaults; } + + // TODO: add documentation + function depositToVault( + address vault, + uint256 amount, + uint256 minSharesOut + ) public { + require(msg.sender == address(stBTC), "stBTC only"); + require(vaultsInfo[vault].authorized, "Vault is not approved"); + + deposit(IERC4626(vault), address(stBTC), amount, minSharesOut); + } + + // TODO: add documentation + function redeemFromVault( + address vault, + uint256 shares, + uint256 minAssetsOut + ) public { + require(msg.sender == address(stBTC), "stBTC only"); + require(vaultsInfo[vault].authorized, "Vault is not approved"); + + redeem(IERC4626(vault), address(stBTC), shares, minAssetsOut); + } } diff --git a/core/contracts/Router.sol b/core/contracts/Router.sol new file mode 100644 index 000000000..7a965d264 --- /dev/null +++ b/core/contracts/Router.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@openzeppelin/contracts/interfaces/IERC20.sol"; +import "@openzeppelin/contracts/interfaces/IERC4626.sol"; + +/// TODO: Add documentation +abstract contract Router { + using SafeERC20 for IERC20; + + /// @notice Routes funds from stBTC (Acre) to a vault. The amount of tBTC to + /// Shares of deposited tBTC are minted to the stBTC contract. + /// @param vault Address of the vault to route the funds to. + /// @param to Address of the receiver of the shares. + /// @param amount Amount of tBTC to deposit. + /// @param minSharesOut Minimum amount of shares to receive. + function deposit( + IERC4626 vault, + address to, + uint256 amount, + uint256 minSharesOut + ) public returns (uint256 sharesOut) { + IERC20(vault.asset()).safeTransferFrom( + msg.sender, + address(this), + amount + ); + IERC20(vault.asset()).safeIncreaseAllowance(address(vault), amount); + if ((sharesOut = vault.deposit(amount, to)) < minSharesOut) { + revert("Not enough shares received"); + } + } + + /// @notice Redeem tBTC from a vault and approve tokens to be transferred + /// by stBTC (Acre) + /// @param vault Address of the vault to collect the assets from. + /// @param to Address of the receiver of the assets. + /// @param shares Amount of shares to collect. Shares are the internal representation + /// of the underlying asset in the vault. Concrete amount of the + /// underlying asset is calculated by calling `convertToAssets` on + /// the vault and the shares are burned. + /// @param minAssetsOut Minimum amount of TBTC to receive. + function redeem( + IERC4626 vault, + address to, + uint256 shares, + uint256 minAssetsOut + ) public returns (uint256 assetsOut) { + if ( + (assetsOut = vault.redeem(shares, address(this), to)) < minAssetsOut + ) { + revert("Not enough assets received"); + } + IERC20(vault.asset()).safeIncreaseAllowance(to, assetsOut); + } +}