编译器
0.8.10+commit.fc410830
文件 1 的 24:AccessControl.sol
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(uint160(account), 20),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}
文件 2 的 24:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 3 的 24:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 4 的 24:Counters.sol
pragma solidity ^0.8.0;
library Counters {
struct Counter {
uint256 _value;
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
unchecked {
counter._value += 1;
}
}
function decrement(Counter storage counter) internal {
uint256 value = counter._value;
require(value > 0, "Counter: decrement overflow");
unchecked {
counter._value = value - 1;
}
}
function reset(Counter storage counter) internal {
counter._value = 0;
}
}
文件 5 的 24:CurveSwapper.sol
pragma solidity =0.8.10;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {ICurve} from "../interfaces/curve/ICurve.sol";
abstract contract CurveSwapper {
using SafeERC20 for IERC20;
struct Swapper {
ICurve pool;
uint8 tokenDecimals;
uint8 underlyingDecimals;
int128 tokenI;
int128 underlyingI;
}
struct SwapPoolParam {
address token;
address pool;
int128 tokenI;
int128 underlyingI;
}
event CurveSwapPoolAdded(
address indexed token,
address indexed pool,
int128 tokenI,
int128 underlyingI
);
event CurveSwapPoolRemoved(address indexed token);
event Swap(
address indexed fromToken,
address indexed toToken,
uint256 fromAmount,
uint256 toAmount
);
mapping(address => Swapper) public swappers;
function getUnderlying() public view virtual returns (address);
function _swapIntoUnderlying(
address _token,
uint256 _amount,
uint256 _slippage
) internal returns (uint256 amount) {
address underlyingToken = getUnderlying();
if (_token == underlyingToken) {
return _amount;
}
Swapper storage swapper = swappers[_token];
require(
address(swapper.pool) != address(0x0),
"non-existing swap pool"
);
uint256 minAmount = _calcMinDy(
_amount,
swapper.tokenDecimals,
swapper.underlyingDecimals,
_slippage
);
amount = swapper.pool.exchange_underlying(
swapper.tokenI,
swapper.underlyingI,
_amount,
minAmount
);
emit Swap(_token, underlyingToken, _amount, amount);
}
function _swapFromUnderlying(
address _token,
uint256 _amount,
uint256 _slippage
) internal returns (uint256 amount) {
if (_token == getUnderlying()) {
return _amount;
}
Swapper storage swapper = swappers[_token];
uint256 minAmount = _calcMinDy(
_amount,
swapper.underlyingDecimals,
swapper.tokenDecimals,
_slippage
);
amount = swapper.pool.exchange_underlying(
swapper.underlyingI,
swapper.tokenI,
_amount,
minAmount
);
emit Swap(getUnderlying(), _token, _amount, amount);
}
function _calcMinDy(
uint256 _amount,
uint8 _fromDecimals,
uint8 _toDecimals,
uint256 _slippage
) internal pure returns (uint256) {
return
(_amount * _slippage * 10**_toDecimals) / (10**_fromDecimals * 10000);
}
function _approveIfNecessary(address _token, address _pool) internal {
uint256 allowance = IERC20(_token).allowance(address(this), _pool);
if (allowance == 0) {
IERC20(_token).safeApprove(_pool, type(uint256).max);
}
}
function _addPools(SwapPoolParam[] memory _swapPools) internal {
uint256 length = _swapPools.length;
for (uint256 i = 0; i < length; ++i) {
_addPool(_swapPools[i]);
}
}
function _addPool(SwapPoolParam memory _param) internal {
require(
address(swappers[_param.token].pool) == address(0),
"token already has a swap pool"
);
require(
ICurve(_param.pool).coins(uint256(uint128(_param.underlyingI))) ==
getUnderlying(),
"_underlyingI does not match underlying token"
);
uint256 tokenDecimals = IERC20Metadata(_param.token).decimals();
uint256 underlyingDecimals = IERC20Metadata(getUnderlying()).decimals();
swappers[_param.token] = Swapper(
ICurve(_param.pool),
uint8(tokenDecimals),
uint8(underlyingDecimals),
_param.tokenI,
_param.underlyingI
);
_approveIfNecessary(getUnderlying(), address(_param.pool));
_approveIfNecessary(_param.token, address(_param.pool));
emit CurveSwapPoolAdded(
_param.token,
_param.pool,
_param.tokenI,
_param.underlyingI
);
}
function _removePool(address _inputToken) internal {
require(
address(swappers[_inputToken].pool) != address(0),
"pool does not exist"
);
delete swappers[_inputToken];
emit CurveSwapPoolRemoved(_inputToken);
}
}
文件 6 的 24:CustomErrors.sol
pragma solidity =0.8.10;
interface CustomErrors {
error VaultSenderNotOwnerOfGroupId();
error VaultInvalidInvestpct();
error VaultInvalidPerformanceFee();
error VaultNoPerformanceFee();
error VaultInvalidLossTolerance();
error VaultUnderlyingCannotBe0Address();
error VaultTreasuryCannotBe0Address();
error VaultAdminCannotBe0Address();
error VaultCannotTransferAdminRightsToSelf();
error VaultCallerNotAdmin();
error VaultCallerNotSettings();
error VaultCallerNotKeeper();
error VaultCallerNotSponsor();
error VaultDestinationCannotBe0Address();
error VaultStrategyNotSet();
error VaultInvalidMinLockPeriod();
error VaultInvalidLockPeriod();
error VaultCannotDeposit0();
error VaultCannotSponsor0();
error VaultCannotDepositWhenYieldNegative();
error VaultCannotDepositWhenClaimerInDebt();
error VaultCannotWithdrawWhenYieldNegative();
error VaultNothingToDo();
error VaultNotEnoughToRebalance();
error VaultInvalidVault();
error VaultStrategyHasInvestedFunds();
error VaultNotEnoughFunds();
error VaultNotAllowed();
error VaultAmountLocked();
error VaultDepositLocked();
error VaultNotSponsor();
error VaultNotDeposit();
error VaultClaimPercentageCannotBe0();
error VaultClaimerCannotBe0();
error VaultClaimsDontAddUp();
error VaultNotOwnerOfDeposit();
error VaultCannotWithdrawMoreThanAvailable();
error VaultMustUseForceWithdrawToAcceptLosses();
error VaultAmountDoesNotMatchParams();
error VaultCannotComputeSharesWithoutPrincipal();
error VaultDepositNameTooShort();
error VaultNoYieldToClaim();
error StrategyAdminCannotBe0Address();
error StrategyCannotTransferAdminRightsToSelf();
error StrategyUnderlyingCannotBe0Address();
error StrategyNotIVault();
error StrategyCallerNotManager();
error StrategyCallerNotSettings();
error StrategyCallerNotAdmin();
error StrategyAmountZero();
error StrategyNotRunning();
error StrategyNoUnderlying();
error StrategyNotEnoughShares();
}
文件 7 的 24:ERC165.sol
pragma solidity ^0.8.0;
import "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 8 的 24:ExitPausable.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/Context.sol";
abstract contract ExitPausable is Context {
event ExitPaused(address account);
event ExitUnpaused(address account);
bool private _exitPaused;
constructor() {
_exitPaused = false;
}
modifier whenNotExitPaused() {
_requireNotExitPaused();
_;
}
modifier whenExitPaused() {
_requireExitPaused();
_;
}
function exitPaused() public view virtual returns (bool) {
return _exitPaused;
}
function _requireNotExitPaused() internal view virtual {
require(!exitPaused(), "Pausable: ExitPaused");
}
function _requireExitPaused() internal view virtual {
require(exitPaused(), "Pausable: not ExitPaused");
}
function _exitPause() internal virtual whenNotExitPaused {
_exitPaused = true;
emit ExitPaused(_msgSender());
}
function _exitUnpause() internal virtual whenExitPaused {
_exitPaused = false;
emit ExitUnpaused(_msgSender());
}
}
文件 9 的 24:IAccessControl.sol
pragma solidity ^0.8.0;
interface IAccessControl {
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address account) external;
}
文件 10 的 24:ICurve.sol
pragma solidity =0.8.10;
interface ICurve {
function exchange_underlying(
int128 i,
int128 j,
uint256 dx,
uint256 min_dy
) external returns (uint256);
function coins(uint256 i) external view returns (address);
}
文件 11 的 24:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 12 的 24:IERC20.sol
pragma solidity ^0.8.0;
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 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
文件 13 的 24:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 14 的 24:IStrategy.sol
pragma solidity =0.8.10;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IStrategy {
event StrategyInvested(uint256 amount);
event StrategyWithdrawn(uint256 amount);
function isSync() external view returns (bool);
function vault() external view returns (address);
function withdrawToVault(uint256 amount) external;
function investedAssets() external view returns (uint256);
function hasAssets() external view returns (bool);
function invest() external;
}
文件 15 的 24:IVault.sol
pragma solidity =0.8.10;
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
interface IVault {
struct ClaimParams {
uint16 pct;
address beneficiary;
bytes data;
}
struct DepositParams {
address inputToken;
uint64 lockDuration;
uint256 amount;
ClaimParams[] claims;
string name;
uint256 slippage;
}
struct Deposit {
uint256 amount;
address owner;
address claimerId;
uint256 lockedUntil;
}
struct Claimer {
uint256 totalPrincipal;
uint256 totalShares;
}
event DepositMinted(
uint256 indexed id,
uint256 groupId,
uint256 amount,
uint256 shares,
address indexed depositor,
address indexed claimer,
address claimerId,
uint64 lockedUntil,
bytes data,
string name
);
event DepositWithdrawn(
uint256 indexed id,
uint256 shares,
uint256 amount,
address indexed to,
bool burned
);
event Invested(uint256 amount);
event Disinvested(uint256 amount);
event YieldClaimed(
address claimerId,
address indexed to,
uint256 amount,
uint256 burnedShares,
uint256 perfFee,
uint256 totalUnderlying,
uint256 totalShares
);
event FeeWithdrawn(uint256 amount);
function updateInvested() external;
function investState()
external
view
returns (uint256 maxInvestableAmount, uint256 alreadyInvested);
function investPct() external view returns (uint16);
function underlying() external view returns (IERC20Metadata);
function minLockPeriod() external view returns (uint64);
function totalUnderlying() external view returns (uint256);
function totalShares() external view returns (uint256);
function yieldFor(address _to)
external
view
returns (
uint256,
uint256,
uint256
);
function claimYield(address _to) external;
function depositForGroupId(uint256 _groupId, DepositParams calldata _params)
external
returns (uint256[] memory);
function deposit(DepositParams calldata _params)
external
returns (uint256[] memory);
function withdraw(address _to, uint256[] calldata _ids) external;
function forceWithdraw(address _to, uint256[] calldata _ids) external;
function withdrawPerformanceFee() external;
}
文件 16 的 24:IVaultSettings.sol
pragma solidity =0.8.10;
interface IVaultSettings {
event InvestPctUpdated(uint256 percentage);
event TreasuryUpdated(address indexed treasury);
event PerfFeePctUpdated(uint16 pct);
event StrategyUpdated(address indexed strategy);
event LossTolerancePctUpdated(uint16 pct);
function setInvestPct(uint16 _investPct) external;
function setTreasury(address _treasury) external;
function setPerfFeePct(uint16 _perfFeePct) external;
function setStrategy(address _strategy) external;
function setLossTolerancePct(uint16 _pct) external;
}
文件 17 的 24:IVaultSponsoring.sol
pragma solidity =0.8.10;
interface IVaultSponsoring {
event Sponsored(
uint256 indexed id,
uint256 amount,
address indexed depositor,
uint256 lockedUntil
);
event Unsponsored(
uint256 indexed id,
uint256 amount,
address indexed to,
bool burned
);
function totalSponsored() external view returns (uint256);
function sponsor(
address _inputToken,
uint256 _amount,
uint256 _lockedUntil,
uint256 _slippage
) external;
function unsponsor(address _to, uint256[] calldata _ids) external;
function partialUnsponsor(
address _to,
uint256[] calldata _ids,
uint256[] calldata _amounts
) external;
}
文件 18 的 24:Pausable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Pausable is Context {
event Paused(address account);
event Unpaused(address account);
bool private _paused;
constructor() {
_paused = false;
}
modifier whenNotPaused() {
_requireNotPaused();
_;
}
modifier whenPaused() {
_requirePaused();
_;
}
function paused() public view virtual returns (bool) {
return _paused;
}
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
文件 19 的 24:PercentMath.sol
pragma solidity =0.8.10;
library PercentMath {
uint256 public constant PCT_DIVISOR = 10000;
function validPct(uint256 _amount) internal pure returns (bool) {
return _amount <= PCT_DIVISOR;
}
function pctOf(uint256 _amount, uint16 _fracNum)
internal
pure
returns (uint256)
{
return (_amount * _fracNum) / PCT_DIVISOR;
}
function is100Pct(uint256 _perc) internal pure returns (bool) {
return _perc == PCT_DIVISOR;
}
}
文件 20 的 24:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 21 的 24:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 22 的 24:Strings.sol
pragma solidity ^0.8.0;
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
function toString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}
文件 23 的 24:Vault.sol
pragma solidity =0.8.10;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol";
import {Counters} from "@openzeppelin/contracts/utils/Counters.sol";
import {IVault} from "./vault/IVault.sol";
import {IVaultSponsoring} from "./vault/IVaultSponsoring.sol";
import {IVaultSettings} from "./vault/IVaultSettings.sol";
import {CurveSwapper} from "./vault/CurveSwapper.sol";
import {PercentMath} from "./lib/PercentMath.sol";
import {ExitPausable} from "./lib/ExitPausable.sol";
import {IStrategy} from "./strategy/IStrategy.sol";
import {CustomErrors} from "./interfaces/CustomErrors.sol";
contract Vault is
IVault,
IVaultSponsoring,
IVaultSettings,
CurveSwapper,
Context,
ERC165,
AccessControl,
ReentrancyGuard,
Pausable,
ExitPausable,
CustomErrors
{
using SafeERC20 for IERC20;
using SafeERC20 for IERC20Metadata;
using PercentMath for uint256;
using PercentMath for uint16;
using Counters for Counters.Counter;
bytes32 public constant KEEPER_ROLE = keccak256("KEEPER_ROLE");
bytes32 public constant SETTINGS_ROLE = keccak256("SETTINGS_ROLE");
bytes32 public constant SPONSOR_ROLE = keccak256("SPONSOR_ROLE");
uint64 public constant MIN_SPONSOR_LOCK_DURATION = 2 weeks;
uint64 public constant MAX_SPONSOR_LOCK_DURATION = 24 weeks;
uint64 public constant MAX_DEPOSIT_LOCK_DURATION = 24 weeks;
uint256 public constant SHARES_MULTIPLIER = 1e18;
IERC20Metadata public override(IVault) underlying;
uint16 public override(IVault) investPct;
uint64 public immutable override(IVault) minLockPeriod;
uint256 public override(IVaultSponsoring) totalSponsored;
uint256 public override(IVault) totalShares;
IStrategy public strategy;
uint256 private _depositGroupIds;
mapping(uint256 => address) public depositGroupIdOwner;
mapping(uint256 => Deposit) public deposits;
Counters.Counter private _depositTokenIds;
mapping(address => Claimer) public claimer;
uint256 public totalPrincipal;
address public treasury;
uint16 public perfFeePct;
uint256 public accumulatedPerfFee;
uint16 public lossTolerancePct;
uint256 private immutable rebalanceMinimum;
constructor(
IERC20Metadata _underlying,
uint64 _minLockPeriod,
uint16 _investPct,
address _treasury,
address _admin,
uint16 _perfFeePct,
uint16 _lossTolerancePct,
SwapPoolParam[] memory _swapPools
) {
if (!_investPct.validPct()) revert VaultInvalidInvestpct();
if (!_perfFeePct.validPct()) revert VaultInvalidPerformanceFee();
if (!_lossTolerancePct.validPct()) revert VaultInvalidLossTolerance();
if (address(_underlying) == address(0x0))
revert VaultUnderlyingCannotBe0Address();
if (_treasury == address(0x0)) revert VaultTreasuryCannotBe0Address();
if (_admin == address(0x0)) revert VaultAdminCannotBe0Address();
if (_minLockPeriod == 0 || _minLockPeriod > MAX_DEPOSIT_LOCK_DURATION)
revert VaultInvalidMinLockPeriod();
_grantRole(DEFAULT_ADMIN_ROLE, _admin);
_grantRole(KEEPER_ROLE, _admin);
_grantRole(SETTINGS_ROLE, _admin);
_grantRole(SPONSOR_ROLE, _admin);
investPct = _investPct;
underlying = _underlying;
treasury = _treasury;
minLockPeriod = _minLockPeriod;
perfFeePct = _perfFeePct;
lossTolerancePct = _lossTolerancePct;
rebalanceMinimum = 10 * 10**underlying.decimals();
_addPools(_swapPools);
emit TreasuryUpdated(_treasury);
}
modifier onlyAdmin() {
if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender))
revert VaultCallerNotAdmin();
_;
}
modifier onlySettings() {
if (!hasRole(SETTINGS_ROLE, msg.sender))
revert VaultCallerNotSettings();
_;
}
modifier onlyKeeper() {
if (!hasRole(KEEPER_ROLE, msg.sender)) revert VaultCallerNotKeeper();
_;
}
modifier onlySponsor() {
if (!hasRole(SPONSOR_ROLE, msg.sender)) revert VaultCallerNotSponsor();
_;
}
function transferAdminRights(address _newAdmin) external onlyAdmin {
if (_newAdmin == address(0x0)) revert VaultAdminCannotBe0Address();
if (_newAdmin == msg.sender)
revert VaultCannotTransferAdminRightsToSelf();
_grantRole(DEFAULT_ADMIN_ROLE, _newAdmin);
_grantRole(KEEPER_ROLE, _newAdmin);
_grantRole(SETTINGS_ROLE, _newAdmin);
_grantRole(SPONSOR_ROLE, _newAdmin);
_revokeRole(DEFAULT_ADMIN_ROLE, msg.sender);
_revokeRole(KEEPER_ROLE, msg.sender);
_revokeRole(SETTINGS_ROLE, msg.sender);
_revokeRole(SPONSOR_ROLE, msg.sender);
}
function totalUnderlying() public view override(IVault) returns (uint256) {
if (address(strategy) != address(0)) {
return
underlying.balanceOf(address(this)) + strategy.investedAssets();
}
return underlying.balanceOf(address(this));
}
function yieldFor(address _to)
public
view
override(IVault)
returns (
uint256 claimableYield,
uint256 shares,
uint256 perfFee
)
{
uint256 claimerPrincipal = claimer[_to].totalPrincipal;
uint256 claimerShares = claimer[_to].totalShares;
uint256 _totalUnderlyingMinusSponsored = totalUnderlyingMinusSponsored();
uint256 currentClaimerPrincipal = _computeAmount(
claimerShares,
totalShares,
_totalUnderlyingMinusSponsored
);
if (currentClaimerPrincipal <= claimerPrincipal) {
return (0, 0, 0);
}
uint256 yieldWithPerfFee = currentClaimerPrincipal - claimerPrincipal;
shares = _computeShares(
yieldWithPerfFee,
totalShares,
_totalUnderlyingMinusSponsored
);
uint256 sharesAmount = _computeAmount(
shares,
totalShares,
_totalUnderlyingMinusSponsored
);
perfFee = sharesAmount.pctOf(perfFeePct);
claimableYield = sharesAmount - perfFee;
}
function depositForGroupId(uint256 _groupId, DepositParams calldata _params)
external
nonReentrant
whenNotPaused
returns (uint256[] memory depositIds)
{
if (depositGroupIdOwner[_groupId] != msg.sender)
revert VaultSenderNotOwnerOfGroupId();
depositIds = _doDeposit(_groupId, _params);
}
function deposit(DepositParams calldata _params)
external
nonReentrant
whenNotPaused
returns (uint256[] memory depositIds)
{
uint256 depositGroupId = _depositGroupIds;
_depositGroupIds = depositGroupId + 1;
depositGroupIdOwner[depositGroupId] = msg.sender;
depositIds = _doDeposit(depositGroupId, _params);
}
function _doDeposit(uint256 _groupId, DepositParams calldata _params)
internal
returns (uint256[] memory depositIds)
{
if (_params.amount == 0) revert VaultCannotDeposit0();
if (
_params.lockDuration < minLockPeriod ||
_params.lockDuration > MAX_DEPOSIT_LOCK_DURATION
) revert VaultInvalidLockPeriod();
if (bytes(_params.name).length < 3) revert VaultDepositNameTooShort();
uint256 principalMinusStrategyFee = _applyLossTolerance(totalPrincipal);
uint256 previousTotalUnderlying = totalUnderlyingMinusSponsored();
if (principalMinusStrategyFee > previousTotalUnderlying)
revert VaultCannotDepositWhenYieldNegative();
_transferAndCheckInputToken(
msg.sender,
_params.inputToken,
_params.amount
);
uint256 newUnderlyingAmount = _swapIntoUnderlying(
_params.inputToken,
_params.amount,
_params.slippage
);
uint64 lockedUntil = _params.lockDuration + _blockTimestamp();
depositIds = _createDeposit(
previousTotalUnderlying,
newUnderlyingAmount,
lockedUntil,
_params.claims,
_params.name,
_groupId
);
}
function claimYield(address _to)
external
override(IVault)
nonReentrant
whenNotExitPaused
{
if (_to == address(0)) revert VaultDestinationCannotBe0Address();
(uint256 yield, uint256 shares, uint256 fee) = yieldFor(msg.sender);
if (yield == 0) revert VaultNoYieldToClaim();
uint256 _totalUnderlyingMinusSponsored = totalUnderlyingMinusSponsored();
uint256 _totalShares = totalShares;
accumulatedPerfFee += fee;
_rebalanceBeforeWithdrawing(yield);
underlying.safeTransfer(_to, yield);
claimer[msg.sender].totalShares -= shares;
totalShares -= shares;
emit YieldClaimed(
msg.sender,
_to,
yield,
shares,
fee,
_totalUnderlyingMinusSponsored,
_totalShares
);
}
function withdraw(address _to, uint256[] calldata _ids)
external
override(IVault)
nonReentrant
whenNotExitPaused
{
if (_to == address(0)) revert VaultDestinationCannotBe0Address();
if (totalPrincipal > totalUnderlyingMinusSponsored())
revert VaultCannotWithdrawWhenYieldNegative();
_withdrawAll(_to, _ids, false);
}
function forceWithdraw(address _to, uint256[] calldata _ids)
external
nonReentrant
whenNotExitPaused
{
if (_to == address(0)) revert VaultDestinationCannotBe0Address();
_withdrawAll(_to, _ids, true);
}
function partialWithdraw(
address _to,
uint256[] calldata _ids,
uint256[] calldata _amounts
) external nonReentrant whenNotExitPaused {
if (_to == address(0)) revert VaultDestinationCannotBe0Address();
_withdrawPartial(_to, _ids, _amounts);
}
function investState()
public
view
override(IVault)
returns (uint256 maxInvestableAmount, uint256 alreadyInvested)
{
if (address(strategy) == address(0)) {
return (0, 0);
}
maxInvestableAmount = totalUnderlying().pctOf(investPct);
alreadyInvested = strategy.investedAssets();
}
function updateInvested() external override(IVault) onlyKeeper {
if (address(strategy) == address(0)) revert VaultStrategyNotSet();
(uint256 maxInvestableAmount, uint256 alreadyInvested) = investState();
if (maxInvestableAmount == alreadyInvested) revert VaultNothingToDo();
if (alreadyInvested > maxInvestableAmount) {
uint256 disinvestAmount = alreadyInvested - maxInvestableAmount;
if (disinvestAmount < rebalanceMinimum)
revert VaultNotEnoughToRebalance();
strategy.withdrawToVault(disinvestAmount);
emit Disinvested(disinvestAmount);
return;
}
uint256 investAmount = maxInvestableAmount - alreadyInvested;
if (investAmount < rebalanceMinimum) revert VaultNotEnoughToRebalance();
underlying.safeTransfer(address(strategy), investAmount);
strategy.invest();
emit Invested(investAmount);
}
function withdrawPerformanceFee() external override(IVault) onlyKeeper {
uint256 _perfFee = accumulatedPerfFee;
if (_perfFee == 0) revert VaultNoPerformanceFee();
accumulatedPerfFee = 0;
_rebalanceBeforeWithdrawing(_perfFee);
emit FeeWithdrawn(_perfFee);
underlying.safeTransfer(treasury, _perfFee);
}
function sponsor(
address _inputToken,
uint256 _amount,
uint256 _lockDuration,
uint256 _slippage
)
external
override(IVaultSponsoring)
nonReentrant
onlySponsor
whenNotPaused
{
if (_amount == 0) revert VaultCannotSponsor0();
if (
_lockDuration < MIN_SPONSOR_LOCK_DURATION ||
_lockDuration > MAX_SPONSOR_LOCK_DURATION
) revert VaultInvalidLockPeriod();
uint256 lockedUntil = _lockDuration + block.timestamp;
_depositTokenIds.increment();
uint256 tokenId = _depositTokenIds.current();
_transferAndCheckInputToken(msg.sender, _inputToken, _amount);
uint256 underlyingAmount = _swapIntoUnderlying(
_inputToken,
_amount,
_slippage
);
deposits[tokenId] = Deposit(
underlyingAmount,
msg.sender,
address(0),
lockedUntil
);
totalSponsored += underlyingAmount;
emit Sponsored(tokenId, underlyingAmount, msg.sender, lockedUntil);
}
function unsponsor(address _to, uint256[] calldata _ids)
external
nonReentrant
whenNotExitPaused
{
if (_to == address(0)) revert VaultDestinationCannotBe0Address();
_unsponsor(_to, _ids);
}
function partialUnsponsor(
address _to,
uint256[] calldata _ids,
uint256[] calldata _amounts
) external nonReentrant whenNotExitPaused {
if (_to == address(0)) revert VaultDestinationCannotBe0Address();
_partialUnsponsor(_to, _ids, _amounts);
}
function getUnderlying()
public
view
override(CurveSwapper)
returns (address)
{
return address(underlying);
}
function addPool(SwapPoolParam memory _param) external onlyAdmin {
_addPool(_param);
}
function removePool(address _inputToken) external onlyAdmin {
_removePool(_inputToken);
}
function setInvestPct(uint16 _investPct)
external
override(IVaultSettings)
onlySettings
{
if (!PercentMath.validPct(_investPct)) revert VaultInvalidInvestpct();
emit InvestPctUpdated(_investPct);
investPct = _investPct;
}
function setTreasury(address _treasury)
external
override(IVaultSettings)
onlySettings
{
if (address(_treasury) == address(0x0))
revert VaultTreasuryCannotBe0Address();
treasury = _treasury;
emit TreasuryUpdated(_treasury);
}
function setPerfFeePct(uint16 _perfFeePct)
external
override(IVaultSettings)
onlySettings
{
if (!PercentMath.validPct(_perfFeePct))
revert VaultInvalidPerformanceFee();
perfFeePct = _perfFeePct;
emit PerfFeePctUpdated(_perfFeePct);
}
function setStrategy(address _strategy)
external
override(IVaultSettings)
onlySettings
{
if (_strategy == address(0)) revert VaultStrategyNotSet();
if (IStrategy(_strategy).vault() != address(this))
revert VaultInvalidVault();
if (address(strategy) != address(0) && strategy.hasAssets())
revert VaultStrategyHasInvestedFunds();
strategy = IStrategy(_strategy);
emit StrategyUpdated(_strategy);
}
function setLossTolerancePct(uint16 pct)
external
override(IVaultSettings)
onlySettings
{
if (!pct.validPct()) revert VaultInvalidLossTolerance();
lossTolerancePct = pct;
emit LossTolerancePctUpdated(pct);
}
function totalUnderlyingMinusSponsored() public view returns (uint256) {
uint256 _totalUnderlying = totalUnderlying();
uint256 deductAmount = totalSponsored + accumulatedPerfFee;
if (deductAmount > _totalUnderlying) {
return 0;
}
return _totalUnderlying - deductAmount;
}
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(ERC165, AccessControl)
returns (bool)
{
return
interfaceId == type(IVault).interfaceId ||
interfaceId == type(IVaultSponsoring).interfaceId ||
super.supportsInterface(interfaceId);
}
function _withdrawAll(
address _to,
uint256[] calldata _ids,
bool _force
) internal {
uint256 localTotalShares = totalShares;
uint256 localTotalPrincipal = totalUnderlyingMinusSponsored();
uint256 amount;
uint256 idsLen = _ids.length;
for (uint256 i = 0; i < idsLen; ++i) {
uint256 depositAmount = deposits[_ids[i]].amount;
amount += _withdrawSingle(
_ids[i],
localTotalShares,
localTotalPrincipal,
_to,
_force,
depositAmount
);
}
_rebalanceBeforeWithdrawing(amount);
underlying.safeTransfer(_to, amount);
}
function _withdrawPartial(
address _to,
uint256[] calldata _ids,
uint256[] calldata _amounts
) internal {
uint256 localTotalShares = totalShares;
uint256 localTotalPrincipal = totalUnderlyingMinusSponsored();
uint256 amount;
uint256 idsLen = _ids.length;
for (uint256 i = 0; i < idsLen; ++i) {
amount += _withdrawSingle(
_ids[i],
localTotalShares,
localTotalPrincipal,
_to,
false,
_amounts[i]
);
}
_rebalanceBeforeWithdrawing(amount);
underlying.safeTransfer(_to, amount);
}
function _rebalanceBeforeWithdrawing(uint256 _amount) internal {
uint256 vaultBalance = underlying.balanceOf(address(this));
if (_amount <= vaultBalance) return;
if (!strategy.isSync()) revert VaultNotEnoughFunds();
uint256 expectedReserves = (totalUnderlying() - _amount).pctOf(
10000 - investPct
);
uint256 needed = _amount + expectedReserves - vaultBalance;
strategy.withdrawToVault(needed);
emit Disinvested(needed);
}
function _unsponsor(address _to, uint256[] calldata _ids) internal {
uint256 sponsorAmount;
uint256 idsLen = _ids.length;
for (uint8 i = 0; i < idsLen; ++i) {
uint256 tokenId = _ids[i];
uint256 amount = deposits[tokenId].amount;
_unsponsorSingle(_to, tokenId, amount);
sponsorAmount += amount;
}
_decreaseTotalSponsoredAndTransfer(_to, sponsorAmount);
}
function _partialUnsponsor(
address _to,
uint256[] calldata _ids,
uint256[] calldata _amounts
) internal {
uint256 sponsorAmount;
uint256 idsLen = _ids.length;
for (uint8 i = 0; i < idsLen; ++i) {
uint256 depositId = _ids[i];
uint256 amount = _amounts[i];
_unsponsorSingle(_to, depositId, amount);
sponsorAmount += amount;
}
_decreaseTotalSponsoredAndTransfer(_to, sponsorAmount);
}
function _unsponsorSingle(
address _to,
uint256 _tokenId,
uint256 _amount
) internal {
Deposit memory _deposit = deposits[_tokenId];
if (_deposit.owner != msg.sender) revert VaultNotAllowed();
if (_deposit.lockedUntil > block.timestamp) revert VaultAmountLocked();
if (_deposit.claimerId != address(0)) revert VaultNotSponsor();
if (_deposit.amount < _amount)
revert VaultCannotWithdrawMoreThanAvailable();
bool isFull = _amount == _deposit.amount;
emit Unsponsored(_tokenId, _amount, _to, isFull);
if (!isFull) {
deposits[_tokenId].amount -= _amount;
return;
}
delete deposits[_tokenId];
}
function _decreaseTotalSponsoredAndTransfer(address _to, uint256 _amount)
internal
{
if (_amount > totalUnderlying()) revert VaultNotEnoughFunds();
totalSponsored -= _amount;
_rebalanceBeforeWithdrawing(_amount);
underlying.safeTransfer(_to, _amount);
}
struct CreateDepositLocals {
uint256 totalShares;
uint256 totalUnderlying;
uint16 accumulatedPct;
uint256 accumulatedAmount;
uint256 claimsLen;
}
function _createDeposit(
uint256 _previousTotalUnderlying,
uint256 _amount,
uint64 _lockedUntil,
ClaimParams[] calldata claims,
string calldata _name,
uint256 _groupId
) internal returns (uint256[] memory) {
CreateDepositLocals memory locals = CreateDepositLocals({
totalShares: totalShares,
totalUnderlying: _previousTotalUnderlying,
accumulatedPct: 0,
accumulatedAmount: 0,
claimsLen: claims.length
});
uint256[] memory result = new uint256[](locals.claimsLen);
for (uint256 i = 0; i < locals.claimsLen; ++i) {
ClaimParams memory data = claims[i];
if (data.pct == 0) revert VaultClaimPercentageCannotBe0();
if (data.beneficiary == address(0)) revert VaultClaimerCannotBe0();
uint256 localAmount = i == locals.claimsLen - 1
? _amount - locals.accumulatedAmount
: _amount.pctOf(data.pct);
result[i] = _createClaim(
_groupId,
localAmount,
_lockedUntil,
data,
locals.totalShares,
locals.totalUnderlying,
_name
);
locals.accumulatedPct += data.pct;
locals.accumulatedAmount += localAmount;
}
if (!locals.accumulatedPct.is100Pct()) revert VaultClaimsDontAddUp();
return result;
}
struct CreateClaimLocals {
uint256 newShares;
address claimerId;
uint256 tokenId;
}
function _createClaim(
uint256 _depositGroupId,
uint256 _amount,
uint64 _lockedUntil,
ClaimParams memory _claim,
uint256 _localTotalShares,
uint256 _localTotalPrincipal,
string calldata _name
) internal returns (uint256) {
_depositTokenIds.increment();
CreateClaimLocals memory locals = CreateClaimLocals({
newShares: _computeShares(
_amount,
_localTotalShares,
_localTotalPrincipal
),
claimerId: _claim.beneficiary,
tokenId: _depositTokenIds.current()
});
if (
_computeShares(
_applyLossTolerance(claimer[locals.claimerId].totalPrincipal),
_localTotalShares,
_localTotalPrincipal
) > claimer[locals.claimerId].totalShares
) revert VaultCannotDepositWhenClaimerInDebt();
claimer[locals.claimerId].totalShares += locals.newShares;
claimer[locals.claimerId].totalPrincipal += _amount;
totalShares += locals.newShares;
totalPrincipal += _amount;
deposits[locals.tokenId] = Deposit(
_amount,
msg.sender,
locals.claimerId,
_lockedUntil
);
emit DepositMinted(
locals.tokenId,
_depositGroupId,
_amount,
locals.newShares,
msg.sender,
_claim.beneficiary,
locals.claimerId,
_lockedUntil,
_claim.data,
_name
);
return locals.tokenId;
}
function _withdrawSingle(
uint256 _tokenId,
uint256 _totalShares,
uint256 _totalUnderlyingMinusSponsored,
address _to,
bool _force,
uint256 _amount
) internal returns (uint256) {
if (deposits[_tokenId].owner != msg.sender)
revert VaultNotOwnerOfDeposit();
Deposit memory _deposit = deposits[_tokenId];
Claimer memory _claim = claimer[_deposit.claimerId];
if (_deposit.lockedUntil > block.timestamp) revert VaultDepositLocked();
if (_deposit.claimerId == address(0)) revert VaultNotDeposit();
if (_deposit.amount < _amount)
revert VaultCannotWithdrawMoreThanAvailable();
uint256 amountShares = _computeShares(
_amount,
_totalShares,
_totalUnderlyingMinusSponsored
);
uint256 claimerShares = (_amount * _claim.totalShares) /
_claim.totalPrincipal;
if (!_force && amountShares > claimerShares)
revert VaultMustUseForceWithdrawToAcceptLosses();
uint256 sharesToBurn = amountShares;
if (_force && amountShares > claimerShares)
sharesToBurn = claimerShares;
claimer[_deposit.claimerId].totalShares -= sharesToBurn;
claimer[_deposit.claimerId].totalPrincipal -= _amount;
totalShares -= sharesToBurn;
totalPrincipal -= _amount;
bool isFull = _deposit.amount == _amount;
if (isFull) {
delete deposits[_tokenId];
} else {
deposits[_tokenId].amount -= _amount;
}
uint256 amount = _computeAmount(
sharesToBurn,
_totalShares,
_totalUnderlyingMinusSponsored
);
emit DepositWithdrawn(_tokenId, sharesToBurn, amount, _to, isFull);
return amount;
}
function _transferAndCheckInputToken(
address _from,
address _token,
uint256 _amount
) internal {
uint256 balanceBefore = IERC20(_token).balanceOf(address(this));
IERC20(_token).safeTransferFrom(_from, address(this), _amount);
uint256 balanceAfter = IERC20(_token).balanceOf(address(this));
if (balanceAfter != balanceBefore + _amount)
revert VaultAmountDoesNotMatchParams();
}
function _blockTimestamp() internal view returns (uint64) {
return uint64(block.timestamp);
}
function _computeShares(
uint256 _amount,
uint256 _totalShares,
uint256 _totalUnderlyingMinusSponsored
) internal pure returns (uint256) {
if (_amount == 0) return 0;
if (_totalShares == 0) return _amount * SHARES_MULTIPLIER;
if (_totalUnderlyingMinusSponsored == 0)
revert VaultCannotComputeSharesWithoutPrincipal();
return (_amount * _totalShares) / _totalUnderlyingMinusSponsored;
}
function _computeAmount(
uint256 _shares,
uint256 _totalShares,
uint256 _totalUnderlyingMinusSponsored
) internal pure returns (uint256) {
if (
_shares == 0 ||
_totalShares == 0 ||
_totalUnderlyingMinusSponsored == 0
) {
return 0;
}
return ((_totalUnderlyingMinusSponsored * _shares) / _totalShares);
}
function _applyLossTolerance(uint256 _amount)
internal
view
returns (uint256)
{
return _amount - _amount.pctOf(lossTolerancePct);
}
function sharesOf(address claimerId) external view returns (uint256) {
return claimer[claimerId].totalShares;
}
function principalOf(address claimerId) external view returns (uint256) {
return claimer[claimerId].totalPrincipal;
}
function pause() external onlyAdmin {
_pause();
}
function unpause() external onlyAdmin {
_unpause();
}
function exitPause() external onlyRole(DEFAULT_ADMIN_ROLE) {
_exitPause();
}
function exitUnpause() external onlyRole(DEFAULT_ADMIN_ROLE) {
_exitUnpause();
}
}
文件 24 的 24:draft-IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
{
"compilationTarget": {
"contracts/Vault.sol": "Vault"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 1000
},
"remappings": []
}
[{"inputs":[{"internalType":"contract IERC20Metadata","name":"_underlying","type":"address"},{"internalType":"uint64","name":"_minLockPeriod","type":"uint64"},{"internalType":"uint16","name":"_investPct","type":"uint16"},{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_admin","type":"address"},{"internalType":"uint16","name":"_perfFeePct","type":"uint16"},{"internalType":"uint16","name":"_lossTolerancePct","type":"uint16"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"pool","type":"address"},{"internalType":"int128","name":"tokenI","type":"int128"},{"internalType":"int128","name":"underlyingI","type":"int128"}],"internalType":"struct CurveSwapper.SwapPoolParam[]","name":"_swapPools","type":"tuple[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"StrategyAdminCannotBe0Address","type":"error"},{"inputs":[],"name":"StrategyAmountZero","type":"error"},{"inputs":[],"name":"StrategyCallerNotAdmin","type":"error"},{"inputs":[],"name":"StrategyCallerNotManager","type":"error"},{"inputs":[],"name":"StrategyCallerNotSettings","type":"error"},{"inputs":[],"name":"StrategyCannotTransferAdminRightsToSelf","type":"error"},{"inputs":[],"name":"StrategyNoUnderlying","type":"error"},{"inputs":[],"name":"StrategyNotEnoughShares","type":"error"},{"inputs":[],"name":"StrategyNotIVault","type":"error"},{"inputs":[],"name":"StrategyNotRunning","type":"error"},{"inputs":[],"name":"StrategyUnderlyingCannotBe0Address","type":"error"},{"inputs":[],"name":"VaultAdminCannotBe0Address","type":"error"},{"inputs":[],"name":"VaultAmountDoesNotMatchParams","type":"error"},{"inputs":[],"name":"VaultAmountLocked","type":"error"},{"inputs":[],"name":"VaultCallerNotAdmin","type":"error"},{"inputs":[],"name":"VaultCallerNotKeeper","type":"error"},{"inputs":[],"name":"VaultCallerNotSettings","type":"error"},{"inputs":[],"name":"VaultCallerNotSponsor","type":"error"},{"inputs":[],"name":"VaultCannotComputeSharesWithoutPrincipal","type":"error"},{"inputs":[],"name":"VaultCannotDeposit0","type":"error"},{"inputs":[],"name":"VaultCannotDepositWhenClaimerInDebt","type":"error"},{"inputs":[],"name":"VaultCannotDepositWhenYieldNegative","type":"error"},{"inputs":[],"name":"VaultCannotSponsor0","type":"error"},{"inputs":[],"name":"VaultCannotTransferAdminRightsToSelf","type":"error"},{"inputs":[],"name":"VaultCannotWithdrawMoreThanAvailable","type":"error"},{"inputs":[],"name":"VaultCannotWithdrawWhenYieldNegative","type":"error"},{"inputs":[],"name":"VaultClaimPercentageCannotBe0","type":"error"},{"inputs":[],"name":"VaultClaimerCannotBe0","type":"error"},{"inputs":[],"name":"VaultClaimsDontAddUp","type":"error"},{"inputs":[],"name":"VaultDepositLocked","type":"error"},{"inputs":[],"name":"VaultDepositNameTooShort","type":"error"},{"inputs":[],"name":"VaultDestinationCannotBe0Address","type":"error"},{"inputs":[],"name":"VaultInvalidInvestpct","type":"error"},{"inputs":[],"name":"VaultInvalidLockPeriod","type":"error"},{"inputs":[],"name":"VaultInvalidLossTolerance","type":"error"},{"inputs":[],"name":"VaultInvalidMinLockPeriod","type":"error"},{"inputs":[],"name":"VaultInvalidPerformanceFee","type":"error"},{"inputs":[],"name":"VaultInvalidVault","type":"error"},{"inputs":[],"name":"VaultMustUseForceWithdrawToAcceptLosses","type":"error"},{"inputs":[],"name":"VaultNoPerformanceFee","type":"error"},{"inputs":[],"name":"VaultNoYieldToClaim","type":"error"},{"inputs":[],"name":"VaultNotAllowed","type":"error"},{"inputs":[],"name":"VaultNotDeposit","type":"error"},{"inputs":[],"name":"VaultNotEnoughFunds","type":"error"},{"inputs":[],"name":"VaultNotEnoughToRebalance","type":"error"},{"inputs":[],"name":"VaultNotOwnerOfDeposit","type":"error"},{"inputs":[],"name":"VaultNotSponsor","type":"error"},{"inputs":[],"name":"VaultNothingToDo","type":"error"},{"inputs":[],"name":"VaultSenderNotOwnerOfGroupId","type":"error"},{"inputs":[],"name":"VaultStrategyHasInvestedFunds","type":"error"},{"inputs":[],"name":"VaultStrategyNotSet","type":"error"},{"inputs":[],"name":"VaultTreasuryCannotBe0Address","type":"error"},{"inputs":[],"name":"VaultUnderlyingCannotBe0Address","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"int128","name":"tokenI","type":"int128"},{"indexed":false,"internalType":"int128","name":"underlyingI","type":"int128"}],"name":"CurveSwapPoolAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"CurveSwapPoolRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"groupId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":true,"internalType":"address","name":"claimer","type":"address"},{"indexed":false,"internalType":"address","name":"claimerId","type":"address"},{"indexed":false,"internalType":"uint64","name":"lockedUntil","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"string","name":"name","type":"string"}],"name":"DepositMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"bool","name":"burned","type":"bool"}],"name":"DepositWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Disinvested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"ExitPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"ExitUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeeWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"percentage","type":"uint256"}],"name":"InvestPctUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Invested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"pct","type":"uint16"}],"name":"LossTolerancePctUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"pct","type":"uint16"}],"name":"PerfFeePctUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"lockedUntil","type":"uint256"}],"name":"Sponsored","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"}],"name":"StrategyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"fromToken","type":"address"},{"indexed":true,"internalType":"address","name":"toToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"fromAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toAmount","type":"uint256"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"treasury","type":"address"}],"name":"TreasuryUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"bool","name":"burned","type":"bool"}],"name":"Unsponsored","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"claimerId","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"burnedShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"perfFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalUnderlying","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalShares","type":"uint256"}],"name":"YieldClaimed","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"KEEPER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_DEPOSIT_LOCK_DURATION","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SPONSOR_LOCK_DURATION","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_SPONSOR_LOCK_DURATION","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SETTINGS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHARES_MULTIPLIER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SPONSOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accumulatedPerfFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"pool","type":"address"},{"internalType":"int128","name":"tokenI","type":"int128"},{"internalType":"int128","name":"underlyingI","type":"int128"}],"internalType":"struct CurveSwapper.SwapPoolParam","name":"_param","type":"tuple"}],"name":"addPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"claimYield","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"claimer","outputs":[{"internalType":"uint256","name":"totalPrincipal","type":"uint256"},{"internalType":"uint256","name":"totalShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"uint64","name":"lockDuration","type":"uint64"},{"internalType":"uint256","name":"amount","type":"uint256"},{"components":[{"internalType":"uint16","name":"pct","type":"uint16"},{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IVault.ClaimParams[]","name":"claims","type":"tuple[]"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"slippage","type":"uint256"}],"internalType":"struct IVault.DepositParams","name":"_params","type":"tuple"}],"name":"deposit","outputs":[{"internalType":"uint256[]","name":"depositIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_groupId","type":"uint256"},{"components":[{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"uint64","name":"lockDuration","type":"uint64"},{"internalType":"uint256","name":"amount","type":"uint256"},{"components":[{"internalType":"uint16","name":"pct","type":"uint16"},{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IVault.ClaimParams[]","name":"claims","type":"tuple[]"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"slippage","type":"uint256"}],"internalType":"struct IVault.DepositParams","name":"_params","type":"tuple"}],"name":"depositForGroupId","outputs":[{"internalType":"uint256[]","name":"depositIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"depositGroupIdOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"deposits","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"claimerId","type":"address"},{"internalType":"uint256","name":"lockedUntil","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exitPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exitPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exitUnpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"}],"name":"forceWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUnderlying","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"investPct","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"investState","outputs":[{"internalType":"uint256","name":"maxInvestableAmount","type":"uint256"},{"internalType":"uint256","name":"alreadyInvested","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lossTolerancePct","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minLockPeriod","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"partialUnsponsor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"partialWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"perfFeePct","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"claimerId","type":"address"}],"name":"principalOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_inputToken","type":"address"}],"name":"removePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_investPct","type":"uint16"}],"name":"setInvestPct","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"pct","type":"uint16"}],"name":"setLossTolerancePct","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_perfFeePct","type":"uint16"}],"name":"setPerfFeePct","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"}],"name":"setStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"claimerId","type":"address"}],"name":"sharesOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_inputToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_lockDuration","type":"uint256"},{"internalType":"uint256","name":"_slippage","type":"uint256"}],"name":"sponsor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"strategy","outputs":[{"internalType":"contract IStrategy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"swappers","outputs":[{"internalType":"contract ICurve","name":"pool","type":"address"},{"internalType":"uint8","name":"tokenDecimals","type":"uint8"},{"internalType":"uint8","name":"underlyingDecimals","type":"uint8"},{"internalType":"int128","name":"tokenI","type":"int128"},{"internalType":"int128","name":"underlyingI","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalPrincipal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSponsored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalUnderlyingMinusSponsored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newAdmin","type":"address"}],"name":"transferAdminRights","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"}],"name":"unsponsor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateInvested","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawPerformanceFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"yieldFor","outputs":[{"internalType":"uint256","name":"claimableYield","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"perfFee","type":"uint256"}],"stateMutability":"view","type":"function"}]