Skip to content

Commit

Permalink
Merge branch 'main' of github.com:thesis/acre into error-after-deposi…
Browse files Browse the repository at this point in the history
…t-action
  • Loading branch information
kkosiorowska committed Apr 5, 2024
2 parents 2579533 + 326d35d commit c594284
Show file tree
Hide file tree
Showing 37 changed files with 1,788 additions and 4,562 deletions.
463 changes: 69 additions & 394 deletions core/contracts/AcreBitcoinDepositor.sol

Large diffs are not rendered by default.

104 changes: 104 additions & 0 deletions core/contracts/PausableOwnable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.21;

import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";

import {ZeroAddress} from "./utils/Errors.sol";

/// @title PausableOwnable
/// @notice This abstract contract extracts a common part of the emergency stop
/// mechanism. The emergency stop mechanism can be triggered by an
/// authorized account. Only owner of the contract can update pause
/// admin address.
abstract contract PausableOwnable is
PausableUpgradeable,
Ownable2StepUpgradeable
{
/// @notice An authorized account that can trigger emergency stop mechanism.
address public pauseAdmin;

// Reserved storage space that allows adding more variables without affecting
// the storage layout of the child contracts. The convention from OpenZeppelin
// suggests the storage space should add up to 50 slots. If more variables are
// added in the upcoming versions one need to reduce the array size accordingly.
// See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
// slither-disable-next-line unused-state
uint256[49] private __gap;

/// @notice Emitted when a pause admin address is updated.
/// @param newAccount New pause admin address.
/// @param oldAccount Old pause admin address.
event PauseAdminUpdated(address newAccount, address oldAccount);

/// @notice Reverts when an unauthorized account triggers the emergency stop
/// mechanism.
error PausableUnauthorizedAccount(address account);

/// @notice Reverts if called by any account other than the pause admin
/// or the contract owner.
modifier onlyPauseAdminOrOwner() {
address msgSender = _msgSender();

if (pauseAdmin != msgSender && owner() != msgSender) {
revert PausableUnauthorizedAccount(msgSender);
}
_;
}

/// @notice Initializes the contract. MUST BE CALLED from the child
/// contract initializer.
/// @param initialOwner Initial owner of the contract.
/// @param initialPauseAdmin Initial emergency stop account that can trigger
/// the emergency stop mechanism.
// solhint-disable-next-line func-name-mixedcase
function __PausableOwnable_init(
address initialOwner,
address initialPauseAdmin
) internal onlyInitializing {
__Pausable_init();
__Ownable2Step_init();
__Ownable_init(initialOwner);
__PausableOwnable_init_unchained(initialPauseAdmin);
}

// solhint-disable-next-line func-name-mixedcase
function __PausableOwnable_init_unchained(
address initialPauseAdmin
) internal onlyInitializing {
pauseAdmin = initialPauseAdmin;
}

/// @notice Enables an emergency stop mechanism.
/// @dev Requirements:
/// - The caller must be an authorized account to trigger pause.
/// - The contract must not be already paused.
// solhint-disable-next-line ordering
function pause() external onlyPauseAdminOrOwner {
_pause();
}

/// @notice Turns off the emergency stop mechanism.
/// @dev Requirements:
/// - The caller must be an authorized account to trigger unpause.
/// - The contract must be paused.
function unpause() external onlyPauseAdminOrOwner {
_unpause();
}

/// @notice Updates an authorized account that can trigger emergency stop
/// mechanism.
/// @dev Throws if called by any account other than the owner.
/// @param newPauseAdmin New account that can trigger emergency
/// stop mechanism.
function updatePauseAdmin(address newPauseAdmin) external onlyOwner {
// TODO: Introduce a parameters update process.
if (newPauseAdmin == address(0)) {
revert ZeroAddress();
}

emit PauseAdminUpdated(newPauseAdmin, pauseAdmin);

pauseAdmin = newPauseAdmin;
}
}
128 changes: 128 additions & 0 deletions core/contracts/lib/ERC4626Fees.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// SPDX-License-Identifier: MIT

// Inspired by https://docs.openzeppelin.com/contracts/5.x/erc4626#fees

pragma solidity ^0.8.21;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ERC4626Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC4626Upgradeable.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";

/// @dev ERC4626 vault with entry/exit fees expressed in https://en.wikipedia.org/wiki/Basis_point[basis point (bp)].
abstract contract ERC4626Fees is ERC4626Upgradeable {
using Math for uint256;

uint256 private constant _BASIS_POINT_SCALE = 1e4;

// === Overrides ===

/// @dev Preview taking an entry fee on deposit. See {IERC4626-previewDeposit}.
function previewDeposit(
uint256 assets
) public view virtual override returns (uint256) {
uint256 fee = _feeOnTotal(assets, _entryFeeBasisPoints());
return super.previewDeposit(assets - fee);
}

/// @dev Preview adding an entry fee on mint. See {IERC4626-previewMint}.
function previewMint(
uint256 shares
) public view virtual override returns (uint256) {
uint256 assets = super.previewMint(shares);
return assets + _feeOnRaw(assets, _entryFeeBasisPoints());
}

/// @dev Preview adding an exit fee on withdraw. See {IERC4626-previewWithdraw}.
function previewWithdraw(
uint256 assets
) public view virtual override returns (uint256) {
uint256 fee = _feeOnRaw(assets, _exitFeeBasisPoints());
return super.previewWithdraw(assets + fee);
}

/// @dev Preview taking an exit fee on redeem. See {IERC4626-previewRedeem}.
function previewRedeem(
uint256 shares
) public view virtual override returns (uint256) {
uint256 assets = super.previewRedeem(shares);
return assets - _feeOnTotal(assets, _exitFeeBasisPoints());
}

/// @dev Send entry fee to {_feeRecipient}. See {IERC4626-_deposit}.
function _deposit(
address caller,
address receiver,
uint256 assets,
uint256 shares
) internal virtual override {
uint256 fee = _feeOnTotal(assets, _entryFeeBasisPoints());
address recipient = _feeRecipient();

super._deposit(caller, receiver, assets, shares);

if (fee > 0 && recipient != address(this)) {
SafeERC20.safeTransfer(IERC20(asset()), recipient, fee);
}
}

/// @dev Send exit fee to {_exitFeeRecipient}. See {IERC4626-_deposit}.
function _withdraw(
address caller,
address receiver,
address owner,
uint256 assets,
uint256 shares
) internal virtual override {
uint256 fee = _feeOnRaw(assets, _exitFeeBasisPoints());
address recipient = _feeRecipient();

super._withdraw(caller, receiver, owner, assets, shares);

if (fee > 0 && recipient != address(this)) {
SafeERC20.safeTransfer(IERC20(asset()), recipient, fee);
}
}

// === Fee configuration ===

// slither-disable-next-line dead-code
function _entryFeeBasisPoints() internal view virtual returns (uint256);

// slither-disable-next-line dead-code
function _exitFeeBasisPoints() internal view virtual returns (uint256);

// slither-disable-next-line dead-code
function _feeRecipient() internal view virtual returns (address);

// === Fee operations ===

/// @dev Calculates the fees that should be added to an amount `assets`
/// that does not already include fees.
/// Used in {IERC4626-mint} and {IERC4626-withdraw} operations.
function _feeOnRaw(
uint256 assets,
uint256 feeBasisPoints
) private pure returns (uint256) {
return
assets.mulDiv(
feeBasisPoints,
_BASIS_POINT_SCALE,
Math.Rounding.Ceil
);
}

/// @dev Calculates the fee part of an amount `assets` that already includes fees.
/// Used in {IERC4626-deposit} and {IERC4626-redeem} operations.
function _feeOnTotal(
uint256 assets,
uint256 feeBasisPoints
) private pure returns (uint256) {
return
assets.mulDiv(
feeBasisPoints,
feeBasisPoints + _BASIS_POINT_SCALE,
Math.Rounding.Ceil
);
}
}
Loading

0 comments on commit c594284

Please sign in to comment.