Skip to content

Commit

Permalink
Adding deposit and redeem functionality
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
dimpar committed Dec 8, 2023
1 parent 2bbf761 commit f1f439d
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 4 deletions.
44 changes: 40 additions & 4 deletions core/contracts/AcreRouter.sol → core/contracts/Dispatcher.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,25 @@
pragma solidity ^0.8.21;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/interfaces/IERC4626.sol";
import "./Router.sol";

/// @title AcreRouter
/// @notice AcreRouter is a contract that routes TBTC from stBTC (Acre) to
/// @title Dispatcher
/// @notice Dispatcher is a contract that routes tBTC from stBTC (Acre) to
/// a given vault and back. Vaults supply yield strategies with TBTC that
/// generate yield for Bitcoin holders.
contract AcreRouter is Ownable {
/// TODO: add more description around vaults.
contract Dispatcher is Router, Ownable {
using SafeERC20 for IERC20;

struct Vault {
bool approved;
}

IERC20 public immutable stBTC; // Acre contract
IERC20 public immutable tBTC;

/// @notice Approved vaults within the Yiern Modules that implement ERC4626
/// standard. These vaults deposit assets to yield strategies, e.g.
/// Uniswap V3 WBTC/TBTC pool. Vault can be a part of Acre ecosystem
Expand All @@ -24,7 +33,10 @@ contract AcreRouter is Ownable {
event VaultAdded(address indexed vault);
event VaultRemoved(address indexed vault);

constructor() Ownable(msg.sender) {}
constructor(IERC20 _stBTC, IERC20 _tBTC) Ownable(msg.sender) {
stBTC = _stBTC;
tBTC = _tBTC;
}

/// @notice Adds a vault to the list of approved vaults.
/// @param vault Address of the vault to add.
Expand Down Expand Up @@ -59,4 +71,28 @@ contract AcreRouter is Ownable {
function vaultsLength() external view returns (uint256) {
return vaults.length;
}

// TODO: add documentation
function depositToVault(
address vault,
uint256 amount,
uint256 minSharesOut
) public {
require(msg.sender == address(stBTC), "stBTC only");
require(vaultsInfo[vault].approved, "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].approved, "Vault is not approved");

redeem(IERC4626(vault), address(stBTC), shares, minAssetsOut);
}
}
57 changes: 57 additions & 0 deletions core/contracts/Router.sol
Original file line number Diff line number Diff line change
@@ -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);
}
}

0 comments on commit f1f439d

Please sign in to comment.