编译器
0.8.21+commit.d9974bed
文件 1 的 13:Context.sol
pragma solidity ^0.8.20;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
文件 2 的 13:FullMath.sol
pragma solidity ^0.8.0;
library FullMath {
function mulDiv(
uint256 a,
uint256 b,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
uint256 prod0;
uint256 prod1;
assembly {
let mm := mulmod(a, b, not(0))
prod0 := mul(a, b)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
require(denominator > 0);
assembly {
result := div(prod0, denominator)
}
return result;
}
require(denominator > prod1);
uint256 remainder;
assembly {
remainder := mulmod(a, b, denominator)
}
assembly {
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
uint256 twos = (0 - denominator) & denominator;
assembly {
denominator := div(denominator, twos)
}
assembly {
prod0 := div(prod0, twos)
}
assembly {
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
uint256 inv = (3 * denominator) ^ 2;
inv *= 2 - denominator * inv;
inv *= 2 - denominator * inv;
inv *= 2 - denominator * inv;
inv *= 2 - denominator * inv;
inv *= 2 - denominator * inv;
inv *= 2 - denominator * inv;
result = prod0 * inv;
return result;
}
}
function mulDivRoundingUp(
uint256 a,
uint256 b,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
result = mulDiv(a, b, denominator);
if (mulmod(a, b, denominator) > 0) {
require(result < type(uint256).max);
result++;
}
}
}
}
文件 3 的 13:IAssetsVault.sol
pragma solidity =0.8.21;
interface IAssetsVault {
function deposit() external payable;
function withdraw(address to, uint256 amount) external;
function setNewVault(address _vault) external;
function getBalance() external view returns (uint256 balanceAmount);
}
文件 4 的 13:IERC20.sol
pragma solidity ^0.8.20;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
文件 5 的 13:IMinter.sol
pragma solidity =0.8.21;
interface IMinter {
function setNewVault(address _vault) external;
function mint(address _to, uint256 _amount) external;
function burn(address _from, uint256 _amount) external;
function real() external view returns (address);
function vault() external view returns (address);
function getTokenPrice() external view returns (uint256 price);
}
文件 6 的 13:IReal.sol
pragma solidity =0.8.21;
import {IERC20} from "oz/token/ERC20/IERC20.sol";
interface IReal is IERC20 {
function mint(address _to, uint256 _amount) external;
function burn(address _from, uint256 _amount) external;
}
文件 7 的 13:IStrategyManager.sol
pragma solidity =0.8.21;
interface IStrategyManager {
function setNewVault(address _vault) external;
function addStrategy(address _strategy) external;
function destroyStrategy(address _strategy) external;
function clearStrategy(address _strategy) external;
function rebaseStrategies(uint256 amountIn, uint256 amountOut) external;
function onlyRebaseStrategies() external;
function forceWithdraw(uint256 ethAmount) external returns (uint256 actualAmount);
function setStrategies(address[] memory _strategies, uint256[] memory _ratios) external;
function assetsVault() external view returns (address vault);
function getAllStrategiesValue() external view returns (uint256 amount);
function getTotalInvestedValue() external view returns (uint256 amount);
function getAllStrategyPendingValue() external view returns (uint256 amount);
}
文件 8 的 13:Ownable.sol
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
error OwnableUnauthorizedAccount(address account);
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 9 的 13:Ownable2Step.sol
pragma solidity ^0.8.20;
import {Ownable} from "./Ownable.sol";
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
function acceptOwnership() public virtual {
address sender = _msgSender();
if (pendingOwner() != sender) {
revert OwnableUnauthorizedAccount(sender);
}
_transferOwnership(sender);
}
}
文件 10 的 13:RealVault.sol
pragma solidity =0.8.21;
import {ReentrancyGuard} from "oz/utils/ReentrancyGuard.sol";
import {Ownable} from "oz/access/Ownable.sol";
import {Ownable2Step} from "oz/access/Ownable2Step.sol";
import {TransferHelper} from "v3-periphery/libraries/TransferHelper.sol";
import {IReal} from "./interfaces/IReal.sol";
import {IMinter} from "./interfaces/IMinter.sol";
import {IAssetsVault} from "./interfaces/IAssetsVault.sol";
import {IStrategyManager} from "./interfaces/IStrategyManager.sol";
import {ShareMath} from "./libraries/ShareMath.sol";
contract RealVault is ReentrancyGuard, Ownable2Step {
uint256 internal constant ONE = 1;
uint256 internal constant MULTIPLIER = 10 ** 18;
uint256 internal constant ONE_HUNDRED_PERCENT = 100_0000;
uint256 internal constant MAXMIUM_FEE_RATE = ONE_HUNDRED_PERCENT / 100;
uint256 internal constant MINIMUM_REBASE_INTERVAL = 60 * 60;
uint256 internal constant NUMBER_OF_DEAD_SHARES = 10 ** 15;
uint256 public minWithdrawableShares = 1_00;
uint256 public rebaseTimeInterval = 24 * 60 * 60;
uint256 public rebaseTime;
address public immutable minter;
address public immutable real;
address payable public immutable assetsVault;
address payable public immutable strategyManager;
address public proposal;
address public feeRecipient;
uint256 public latestRoundID;
uint256 public withdrawFeeRate;
uint256 public withdrawableAmountInPast;
uint256 public withdrawingSharesInPast;
uint256 public withdrawingSharesInRound;
uint256 public withdrawAmountDust;
mapping(uint256 => uint256) public roundPricePerShare;
mapping(uint256 => uint256) public settlementTime;
mapping(address => WithdrawReceipt) public userReceipts;
struct WithdrawReceipt {
uint256 withdrawRound;
uint256 withdrawShares;
uint256 withdrawableAmount;
}
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event InitiateWithdraw(address indexed account, uint256 shares, uint256 round);
event CancelWithdraw(address indexed account, uint256 amount, uint256 round);
event Withdrawn(address indexed account, uint256 amount, uint256 round);
event WithdrawnFromStrategy(
address indexed account, uint256 amount, uint256 actualAmount, uint256 totalAmount, uint256 round
);
event RollToNextRound(uint256 indexed round, uint256 vaultIn, uint256 vaultOut, uint256 sharePrice);
event VaultMigrated(address indexed oldVault, address newVault);
event StrategyAdded(address indexed strategy);
event StrategyDestroyed(address indexed strategy);
event StrategyCleared(address indexed strategy);
event InvestmentPortfolioUpdated(address[] indexed strategies, uint256[] indexed ratios);
event FeeCharged(address indexed account, uint256 amount);
event SetWithdrawFeeRate(uint256 indexed oldRate, uint256 newRate);
event SetFeeRecipient(address indexed oldAddr, address newAddr);
event SetRebaseInterval(uint256 indexed interval);
event SettleWithdrawDust(uint256 indexed dust);
event MinWithdrawableSharesUpdated(uint256 indexed minShares);
event ProposalUpdated(address indexed oldAddr, address newAddr);
error RealVault__NotReady();
error RealVault__Migrated();
error RealVault__InsufficientShares();
error RealVault__InvalidAmount();
error RealVault__ZeroAddress();
error RealVault__MininmumWithdraw();
error RealVault__WithdrawInstantly();
error RealVault__NoRequestFound();
error RealVault__NotProposal();
error RealVault__ExceedBalance();
error RealVault__WaitInQueue();
error RealVault__MinimumWithdrawableShares();
error RealVault__ExceedRequestedAmount(uint256 requestedAmount, uint256 actualAmount);
error RealVault__ExceedWithdrawAmount();
error RealVault__ExceedMaxFeeRate(uint256 _feeRate);
error RealVault__MinimumRebaseInterval(uint256 minInterval);
constructor(
address _intialOwner,
address _minter,
address payable _assetsVault,
address payable _strategyManager,
address _proposal
) payable Ownable(_intialOwner) {
if (_proposal == address(0) || _assetsVault == address(0) || _strategyManager == address(0)) {
revert RealVault__ZeroAddress();
}
minter = _minter;
proposal = _proposal;
assetsVault = _assetsVault;
strategyManager = _strategyManager;
real = IMinter(_minter).real();
rebaseTime = block.timestamp;
if (IReal(real).totalSupply() == 0) {
TransferHelper.safeTransferETH(assetsVault, NUMBER_OF_DEAD_SHARES);
IMinter(minter).mint(address(0xdead), NUMBER_OF_DEAD_SHARES);
}
}
modifier onlyProposal() {
if (proposal != msg.sender) revert RealVault__NotProposal();
_;
}
function deposit(uint256 mintAmountMin) external payable nonReentrant returns (uint256 mintAmount) {
mintAmount = _depositFor(msg.sender, msg.sender, msg.value, mintAmountMin);
}
function depositFor(address receiver, uint256 mintAmountMin)
external
payable
nonReentrant
returns (uint256 mintAmount)
{
mintAmount = _depositFor(msg.sender, receiver, msg.value, mintAmountMin);
}
function requestWithdraw(uint256 _shares) external nonReentrant {
if (_shares == 0) revert RealVault__InvalidAmount();
if (_shares < minWithdrawableShares) revert RealVault__MininmumWithdraw();
uint256 _latestRoundID = latestRoundID;
if (_latestRoundID == 0) revert RealVault__WithdrawInstantly();
IReal realToken = IReal(real);
IMinter realEthMinter = IMinter(minter);
if (realToken.balanceOf(msg.sender) < _shares) revert RealVault__ExceedBalance();
TransferHelper.safeTransferFrom(real, msg.sender, address(this), _shares);
withdrawingSharesInRound = withdrawingSharesInRound + _shares;
WithdrawReceipt memory mReceipt = userReceipts[msg.sender];
if (mReceipt.withdrawRound == _latestRoundID) {
mReceipt.withdrawShares = mReceipt.withdrawShares + _shares;
} else if (mReceipt.withdrawRound == 0) {
mReceipt.withdrawShares = _shares;
mReceipt.withdrawRound = _latestRoundID;
} else {
mReceipt = _updateUserReceipt(mReceipt, realEthMinter, _shares, _latestRoundID);
}
userReceipts[msg.sender] = mReceipt;
emit InitiateWithdraw(msg.sender, _shares, _latestRoundID);
}
function cancelWithdraw(uint256 _shares) external nonReentrant {
if (_shares == 0) revert RealVault__InvalidAmount();
WithdrawReceipt memory mReceipt = userReceipts[msg.sender];
uint256 _latestRoundID = latestRoundID;
if (mReceipt.withdrawRound != _latestRoundID) revert RealVault__NoRequestFound();
if (_shares > mReceipt.withdrawShares) {
revert RealVault__ExceedRequestedAmount(_shares, mReceipt.withdrawShares);
}
unchecked {
mReceipt.withdrawShares -= _shares;
}
if (mReceipt.withdrawShares != 0 && mReceipt.withdrawShares < minWithdrawableShares) {
revert RealVault__MininmumWithdraw();
}
TransferHelper.safeTransfer(real, msg.sender, _shares);
if (mReceipt.withdrawShares == 0) {
mReceipt.withdrawRound = 0;
}
userReceipts[msg.sender] = mReceipt;
withdrawingSharesInRound = withdrawingSharesInRound - _shares;
emit CancelWithdraw(msg.sender, _shares, _latestRoundID);
}
function instantWithdraw(uint256 _amount, uint256 _shares)
external
nonReentrant
returns (uint256 actualWithdrawn)
{
if (_amount == 0 && _shares == 0) revert RealVault__InvalidAmount();
IAssetsVault aVault = IAssetsVault(assetsVault);
IMinter realEthMinter = IMinter(minter);
uint256 _latestRoundID = latestRoundID;
(uint256 idleAmount,) = getVaultAvailableAmount();
if (_amount != 0) {
WithdrawReceipt memory mReceipt = userReceipts[msg.sender];
if (mReceipt.withdrawRound != _latestRoundID && mReceipt.withdrawRound != 0) {
mReceipt = _updateUserReceipt(mReceipt, realEthMinter, 0, 0);
}
if (mReceipt.withdrawableAmount < _amount) revert RealVault__ExceedWithdrawAmount();
unchecked {
mReceipt.withdrawableAmount -= _amount;
}
userReceipts[msg.sender] = mReceipt;
withdrawableAmountInPast = withdrawableAmountInPast - _amount;
actualWithdrawn = _amount;
emit Withdrawn(msg.sender, _amount, _latestRoundID);
}
if (_shares != 0) {
uint256 sharePrice;
if (_latestRoundID == 0) {
sharePrice = MULTIPLIER;
} else {
uint256 currSharePrice = currentSharePrice();
uint256 latestSharePrice;
unchecked {
latestSharePrice = roundPricePerShare[_latestRoundID - ONE];
}
sharePrice = latestSharePrice < currSharePrice ? latestSharePrice : currSharePrice;
}
uint256 ethAmount = ShareMath.sharesToAsset(_shares, sharePrice);
realEthMinter.burn(msg.sender, _shares);
if (ethAmount <= idleAmount) {
actualWithdrawn = actualWithdrawn + ethAmount;
emit Withdrawn(msg.sender, ethAmount, _latestRoundID);
} else {
actualWithdrawn = actualWithdrawn + idleAmount;
unchecked {
ethAmount = ethAmount - idleAmount;
}
IStrategyManager manager = IStrategyManager(strategyManager);
uint256 actualAmount = manager.forceWithdraw(ethAmount);
actualWithdrawn = actualWithdrawn + actualAmount;
emit WithdrawnFromStrategy(msg.sender, ethAmount, actualAmount, actualWithdrawn, _latestRoundID);
}
}
if (aVault.getBalance() < actualWithdrawn) revert RealVault__WaitInQueue();
uint256 withFee;
if (withdrawFeeRate != 0) {
withFee = (actualWithdrawn * withdrawFeeRate) / ONE_HUNDRED_PERCENT;
aVault.withdraw(feeRecipient, withFee);
emit FeeCharged(msg.sender, withFee);
}
unchecked {
aVault.withdraw(msg.sender, actualWithdrawn - withFee);
}
}
function onlyRebaseStrategies() external nonReentrant onlyProposal {
IStrategyManager(strategyManager).onlyRebaseStrategies();
}
function rollToNextRound() external nonReentrant {
if (block.timestamp < rebaseTime + rebaseTimeInterval) revert RealVault__NotReady();
rebaseTime = block.timestamp;
IStrategyManager manager = IStrategyManager(strategyManager);
IAssetsVault aVault = IAssetsVault(assetsVault);
uint256 previewSharePrice = currentSharePrice();
uint256 vaultBalance = aVault.getBalance();
uint256 amountToWithdraw = ShareMath.sharesToAsset(withdrawingSharesInRound, previewSharePrice);
uint256 amountVaultNeed = withdrawableAmountInPast + amountToWithdraw;
uint256 allPendingValue = manager.getAllStrategyPendingValue();
uint256 vaultIn;
uint256 vaultOut;
if (vaultBalance > amountVaultNeed) {
unchecked {
vaultIn = vaultBalance - amountVaultNeed;
}
} else if (vaultBalance + allPendingValue < amountVaultNeed) {
unchecked {
vaultOut = amountVaultNeed - vaultBalance - allPendingValue;
}
}
manager.rebaseStrategies(vaultIn, vaultOut);
uint256 _latestRoundID = latestRoundID;
uint256 newSharePrice = currentSharePrice();
roundPricePerShare[_latestRoundID] = previewSharePrice < newSharePrice ? previewSharePrice : newSharePrice;
settlementTime[_latestRoundID] = block.timestamp;
unchecked {
latestRoundID = _latestRoundID + ONE;
}
withdrawingSharesInPast = withdrawingSharesInPast + withdrawingSharesInRound;
withdrawableAmountInPast =
withdrawableAmountInPast + ShareMath.sharesToAsset(withdrawingSharesInRound, newSharePrice);
withdrawingSharesInRound = 0;
emit RollToNextRound(latestRoundID, vaultIn, vaultOut, newSharePrice);
}
function migrateVault(address _vault) external onlyProposal {
IMinter(minter).setNewVault(_vault);
IAssetsVault(assetsVault).setNewVault(_vault);
IStrategyManager(strategyManager).setNewVault(_vault);
IReal realToken = IReal(real);
uint256 balance = realToken.balanceOf(address(this));
if (balance > 0) TransferHelper.safeTransfer(real, _vault, balance);
emit VaultMigrated(address(this), _vault);
}
function addStrategy(address _strategy) external onlyProposal {
IStrategyManager manager = IStrategyManager(strategyManager);
manager.addStrategy(_strategy);
emit StrategyAdded(_strategy);
}
function destroyStrategy(address _strategy) external onlyOwner {
IStrategyManager manager = IStrategyManager(strategyManager);
manager.destroyStrategy(_strategy);
emit StrategyDestroyed(_strategy);
}
function clearStrategy(address _strategy) external onlyOwner {
IStrategyManager manager = IStrategyManager(strategyManager);
manager.clearStrategy(_strategy);
emit StrategyCleared(_strategy);
}
function updateInvestmentPortfolio(address[] memory _strategies, uint256[] memory _ratios) external onlyProposal {
IStrategyManager manager = IStrategyManager(strategyManager);
manager.setStrategies(_strategies, _ratios);
emit InvestmentPortfolioUpdated(_strategies, _ratios);
}
function updateProposal(address _proposal) external onlyProposal {
if (_proposal == address(0)) revert RealVault__ZeroAddress();
emit ProposalUpdated(proposal, _proposal);
proposal = _proposal;
}
function settleWithdrawDust(uint256 amount) external {
uint256 _withdrawAmountDust = withdrawAmountDust;
if (_withdrawAmountDust < MULTIPLIER) revert RealVault__InvalidAmount();
if (amount > _withdrawAmountDust) revert RealVault__ExceedBalance();
withdrawableAmountInPast -= amount;
withdrawAmountDust -= amount;
emit SettleWithdrawDust(amount);
}
function _depositFor(address caller, address receiver, uint256 assets, uint256 mintAmountMin)
internal
returns (uint256 mintAmount)
{
if (assets == 0) revert RealVault__InvalidAmount();
mintAmount = previewDeposit(address(this).balance);
if (mintAmount < mintAmountMin) revert RealVault__InsufficientShares();
IAssetsVault(assetsVault).deposit{value: address(this).balance}();
IMinter(minter).mint(receiver, mintAmount);
emit Deposit(caller, receiver, assets, mintAmount);
}
function _updateUserReceipt(
WithdrawReceipt memory mReceipt,
IMinter realEthMinter,
uint256 _shares,
uint256 _latestRoundID
) private returns (WithdrawReceipt memory) {
uint256 pps = roundPricePerShare[mReceipt.withdrawRound];
uint256 withdrawAmount = ShareMath.sharesToAsset(mReceipt.withdrawShares, pps);
uint256 convertedShares = ShareMath.assetToShares(withdrawAmount, pps);
if (withdrawAmount > 0 && convertedShares < mReceipt.withdrawShares) {
withdrawAmountDust++;
}
realEthMinter.burn(address(this), mReceipt.withdrawShares);
withdrawingSharesInPast = withdrawingSharesInPast - mReceipt.withdrawShares;
mReceipt.withdrawShares = _shares;
mReceipt.withdrawableAmount = mReceipt.withdrawableAmount + withdrawAmount;
mReceipt.withdrawRound = _latestRoundID;
return mReceipt;
}
function setWithdrawFeeRate(uint256 _withdrawFeeRate) external onlyOwner {
if (_withdrawFeeRate > MAXMIUM_FEE_RATE) revert RealVault__ExceedMaxFeeRate(_withdrawFeeRate);
emit SetWithdrawFeeRate(withdrawFeeRate, _withdrawFeeRate);
withdrawFeeRate = _withdrawFeeRate;
}
function setFeeRecipient(address _feeRecipient) external onlyOwner {
if (_feeRecipient == address(0)) revert RealVault__ZeroAddress();
emit SetFeeRecipient(feeRecipient, _feeRecipient);
feeRecipient = _feeRecipient;
}
function setRebaseInterval(uint256 _interval) external onlyOwner {
if (_interval < MINIMUM_REBASE_INTERVAL) revert RealVault__MinimumRebaseInterval(MINIMUM_REBASE_INTERVAL);
rebaseTimeInterval = _interval;
emit SetRebaseInterval(rebaseTimeInterval);
}
function setMinWithdrawableShares(uint256 _minWithdrawableShares) external onlyOwner {
if (_minWithdrawableShares < 1_00) revert RealVault__MinimumWithdrawableShares();
minWithdrawableShares = _minWithdrawableShares;
emit MinWithdrawableSharesUpdated(_minWithdrawableShares);
}
function previewDeposit(uint256 assets) public view virtual returns (uint256) {
uint256 sharePrice;
if (latestRoundID == 0) {
sharePrice = MULTIPLIER;
} else {
uint256 currSharePrice = currentSharePrice();
uint256 latestSharePrice;
unchecked {
latestSharePrice = roundPricePerShare[latestRoundID - ONE];
}
sharePrice = latestSharePrice > currSharePrice ? latestSharePrice : currSharePrice;
}
return ShareMath.assetToShares(assets, sharePrice);
}
function currentSharePrice() public view returns (uint256 price) {
IReal realToken = IReal(real);
uint256 totalReal = realToken.totalSupply();
if (latestRoundID == 0) {
return MULTIPLIER;
}
uint256 etherAmount = IAssetsVault(assetsVault).getBalance()
+ IStrategyManager(strategyManager).getAllStrategiesValue() - withdrawableAmountInPast;
uint256 activeShare = totalReal - withdrawingSharesInPast;
return (etherAmount * MULTIPLIER) / activeShare;
}
function getVaultAvailableAmount() public view returns (uint256 idleAmount, uint256 investedAmount) {
IAssetsVault vault = IAssetsVault(assetsVault);
if (vault.getBalance() > withdrawableAmountInPast) {
unchecked {
idleAmount = vault.getBalance() - withdrawableAmountInPast;
}
}
investedAmount = IStrategyManager(strategyManager).getTotalInvestedValue();
}
receive() external payable {}
}
文件 11 的 13:ReentrancyGuard.sol
pragma solidity ^0.8.20;
abstract contract ReentrancyGuard {
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
_status = ENTERED;
}
function _nonReentrantAfter() private {
_status = NOT_ENTERED;
}
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
文件 12 的 13:ShareMath.sol
pragma solidity =0.8.21;
import {FullMath} from "v3-core-0.8/libraries/FullMath.sol";
library ShareMath {
uint256 internal constant DECIMAL = 18;
uint256 internal constant DECIMAL_OFFSET = 10 ** DECIMAL;
uint256 internal constant PLACEHOLDER_UINT = 1;
function assetToShares(uint256 assetAmount, uint256 assetPerShare) internal pure returns (uint256) {
require(assetPerShare > PLACEHOLDER_UINT, "ShareMath Lib: Invalid assetPerShare");
return FullMath.mulDiv(assetAmount, DECIMAL_OFFSET, assetPerShare);
}
function sharesToAsset(uint256 shares, uint256 assetPerShare) internal pure returns (uint256) {
require(assetPerShare > PLACEHOLDER_UINT, "ShareMath Lib: Invalid assetPerShare");
return FullMath.mulDiv(shares, assetPerShare, DECIMAL_OFFSET);
}
}
文件 13 的 13:TransferHelper.sol
pragma solidity >=0.6.0;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
library TransferHelper {
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
(bool success, bytes memory data) =
token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'STF');
}
function safeTransfer(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'ST');
}
function safeApprove(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'SA');
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, 'STE');
}
}
{
"compilationTarget": {
"src/RealVault.sol": "RealVault"
},
"evmVersion": "shanghai",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
":@uniswap/v3-core/=lib/v3-core/",
":ds-test/=lib/forge-std/lib/ds-test/src/",
":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
":forge-std/=lib/forge-std/src/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/",
":oz/=lib/openzeppelin-contracts/contracts/",
":src/=src/",
":v3-core-0.8/=lib/v3-core-0.8/contracts/",
":v3-core/=lib/v3-core/",
":v3-periphery/=lib/v3-periphery/contracts/"
]
}
[{"inputs":[{"internalType":"address","name":"_intialOwner","type":"address"},{"internalType":"address","name":"_minter","type":"address"},{"internalType":"address payable","name":"_assetsVault","type":"address"},{"internalType":"address payable","name":"_strategyManager","type":"address"},{"internalType":"address","name":"_proposal","type":"address"}],"stateMutability":"payable","type":"constructor"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"RealVault__ExceedBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"_feeRate","type":"uint256"}],"name":"RealVault__ExceedMaxFeeRate","type":"error"},{"inputs":[{"internalType":"uint256","name":"requestedAmount","type":"uint256"},{"internalType":"uint256","name":"actualAmount","type":"uint256"}],"name":"RealVault__ExceedRequestedAmount","type":"error"},{"inputs":[],"name":"RealVault__ExceedWithdrawAmount","type":"error"},{"inputs":[],"name":"RealVault__InsufficientShares","type":"error"},{"inputs":[],"name":"RealVault__InvalidAmount","type":"error"},{"inputs":[],"name":"RealVault__Migrated","type":"error"},{"inputs":[{"internalType":"uint256","name":"minInterval","type":"uint256"}],"name":"RealVault__MinimumRebaseInterval","type":"error"},{"inputs":[],"name":"RealVault__MinimumWithdrawableShares","type":"error"},{"inputs":[],"name":"RealVault__MininmumWithdraw","type":"error"},{"inputs":[],"name":"RealVault__NoRequestFound","type":"error"},{"inputs":[],"name":"RealVault__NotProposal","type":"error"},{"inputs":[],"name":"RealVault__NotReady","type":"error"},{"inputs":[],"name":"RealVault__WaitInQueue","type":"error"},{"inputs":[],"name":"RealVault__WithdrawInstantly","type":"error"},{"inputs":[],"name":"RealVault__ZeroAddress","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"}],"name":"CancelWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeeCharged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"}],"name":"InitiateWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address[]","name":"strategies","type":"address[]"},{"indexed":true,"internalType":"uint256[]","name":"ratios","type":"uint256[]"}],"name":"InvestmentPortfolioUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"minShares","type":"uint256"}],"name":"MinWithdrawableSharesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAddr","type":"address"},{"indexed":false,"internalType":"address","name":"newAddr","type":"address"}],"name":"ProposalUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"round","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"vaultIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"vaultOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharePrice","type":"uint256"}],"name":"RollToNextRound","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAddr","type":"address"},{"indexed":false,"internalType":"address","name":"newAddr","type":"address"}],"name":"SetFeeRecipient","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"interval","type":"uint256"}],"name":"SetRebaseInterval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"oldRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newRate","type":"uint256"}],"name":"SetWithdrawFeeRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"dust","type":"uint256"}],"name":"SettleWithdrawDust","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"}],"name":"StrategyAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"}],"name":"StrategyCleared","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"}],"name":"StrategyDestroyed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldVault","type":"address"},{"indexed":false,"internalType":"address","name":"newVault","type":"address"}],"name":"VaultMigrated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"}],"name":"Withdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"actualAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"}],"name":"WithdrawnFromStrategy","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"}],"name":"addStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"assetsVault","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"}],"name":"cancelWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"}],"name":"clearStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentSharePrice","outputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"mintAmountMin","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"mintAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"mintAmountMin","type":"uint256"}],"name":"depositFor","outputs":[{"internalType":"uint256","name":"mintAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"}],"name":"destroyStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVaultAvailableAmount","outputs":[{"internalType":"uint256","name":"idleAmount","type":"uint256"},{"internalType":"uint256","name":"investedAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_shares","type":"uint256"}],"name":"instantWithdraw","outputs":[{"internalType":"uint256","name":"actualWithdrawn","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"latestRoundID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"}],"name":"migrateVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minWithdrawableShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"onlyRebaseStrategies","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proposal","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"real","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebaseTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebaseTimeInterval","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"}],"name":"requestWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rollToNextRound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"roundPricePerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_feeRecipient","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minWithdrawableShares","type":"uint256"}],"name":"setMinWithdrawableShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_interval","type":"uint256"}],"name":"setRebaseInterval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_withdrawFeeRate","type":"uint256"}],"name":"setWithdrawFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"settleWithdrawDust","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"settlementTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strategyManager","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_strategies","type":"address[]"},{"internalType":"uint256[]","name":"_ratios","type":"uint256[]"}],"name":"updateInvestmentPortfolio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_proposal","type":"address"}],"name":"updateProposal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userReceipts","outputs":[{"internalType":"uint256","name":"withdrawRound","type":"uint256"},{"internalType":"uint256","name":"withdrawShares","type":"uint256"},{"internalType":"uint256","name":"withdrawableAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawAmountDust","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawableAmountInPast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawingSharesInPast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawingSharesInRound","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]