编译器
0.8.21+commit.d9974bed
文件 1 的 18:AccountantWithRateProviders.sol
pragma solidity 0.8.21;
import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol";
import {IRateProvider} from "src/interfaces/IRateProvider.sol";
import {ERC20} from "@solmate/tokens/ERC20.sol";
import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol";
import {BoringVault} from "src/base/BoringVault.sol";
import {Auth, Authority} from "@solmate/auth/Auth.sol";
contract AccountantWithRateProviders is Auth, IRateProvider {
using FixedPointMathLib for uint256;
using SafeTransferLib for ERC20;
struct AccountantState {
address payoutAddress;
uint96 highwaterMark;
uint128 feesOwedInBase;
uint128 totalSharesLastUpdate;
uint96 exchangeRate;
uint16 allowedExchangeRateChangeUpper;
uint16 allowedExchangeRateChangeLower;
uint64 lastUpdateTimestamp;
bool isPaused;
uint24 minimumUpdateDelayInSeconds;
uint16 managementFee;
uint16 performanceFee;
}
struct RateProviderData {
bool isPeggedToBase;
IRateProvider rateProvider;
}
AccountantState public accountantState;
mapping(ERC20 => RateProviderData) public rateProviderData;
error AccountantWithRateProviders__UpperBoundTooSmall();
error AccountantWithRateProviders__LowerBoundTooLarge();
error AccountantWithRateProviders__ManagementFeeTooLarge();
error AccountantWithRateProviders__PerformanceFeeTooLarge();
error AccountantWithRateProviders__Paused();
error AccountantWithRateProviders__ZeroFeesOwed();
error AccountantWithRateProviders__OnlyCallableByBoringVault();
error AccountantWithRateProviders__UpdateDelayTooLarge();
error AccountantWithRateProviders__ExchangeRateAboveHighwaterMark();
event Paused();
event Unpaused();
event DelayInSecondsUpdated(uint24 oldDelay, uint24 newDelay);
event UpperBoundUpdated(uint16 oldBound, uint16 newBound);
event LowerBoundUpdated(uint16 oldBound, uint16 newBound);
event ManagementFeeUpdated(uint16 oldFee, uint16 newFee);
event PerformanceFeeUpdated(uint16 oldFee, uint16 newFee);
event PayoutAddressUpdated(address oldPayout, address newPayout);
event RateProviderUpdated(address asset, bool isPegged, address rateProvider);
event ExchangeRateUpdated(uint96 oldRate, uint96 newRate, uint64 currentTime);
event FeesClaimed(address indexed feeAsset, uint256 amount);
event HighwaterMarkReset();
ERC20 public immutable base;
uint8 public immutable decimals;
BoringVault public immutable vault;
uint256 internal immutable ONE_SHARE;
constructor(
address _owner,
address _vault,
address payoutAddress,
uint96 startingExchangeRate,
address _base,
uint16 allowedExchangeRateChangeUpper,
uint16 allowedExchangeRateChangeLower,
uint24 minimumUpdateDelayInSeconds,
uint16 managementFee,
uint16 performanceFee
) Auth(_owner, Authority(address(0))) {
base = ERC20(_base);
decimals = ERC20(_base).decimals();
vault = BoringVault(payable(_vault));
ONE_SHARE = 10 ** vault.decimals();
accountantState = AccountantState({
payoutAddress: payoutAddress,
highwaterMark: startingExchangeRate,
feesOwedInBase: 0,
totalSharesLastUpdate: uint128(vault.totalSupply()),
exchangeRate: startingExchangeRate,
allowedExchangeRateChangeUpper: allowedExchangeRateChangeUpper,
allowedExchangeRateChangeLower: allowedExchangeRateChangeLower,
lastUpdateTimestamp: uint64(block.timestamp),
isPaused: false,
minimumUpdateDelayInSeconds: minimumUpdateDelayInSeconds,
managementFee: managementFee,
performanceFee: performanceFee
});
}
function pause() external requiresAuth {
accountantState.isPaused = true;
emit Paused();
}
function unpause() external requiresAuth {
accountantState.isPaused = false;
emit Unpaused();
}
function updateDelay(uint24 minimumUpdateDelayInSeconds) external requiresAuth {
if (minimumUpdateDelayInSeconds > 14 days) revert AccountantWithRateProviders__UpdateDelayTooLarge();
uint24 oldDelay = accountantState.minimumUpdateDelayInSeconds;
accountantState.minimumUpdateDelayInSeconds = minimumUpdateDelayInSeconds;
emit DelayInSecondsUpdated(oldDelay, minimumUpdateDelayInSeconds);
}
function updateUpper(uint16 allowedExchangeRateChangeUpper) external requiresAuth {
if (allowedExchangeRateChangeUpper < 1e4) revert AccountantWithRateProviders__UpperBoundTooSmall();
uint16 oldBound = accountantState.allowedExchangeRateChangeUpper;
accountantState.allowedExchangeRateChangeUpper = allowedExchangeRateChangeUpper;
emit UpperBoundUpdated(oldBound, allowedExchangeRateChangeUpper);
}
function updateLower(uint16 allowedExchangeRateChangeLower) external requiresAuth {
if (allowedExchangeRateChangeLower > 1e4) revert AccountantWithRateProviders__LowerBoundTooLarge();
uint16 oldBound = accountantState.allowedExchangeRateChangeLower;
accountantState.allowedExchangeRateChangeLower = allowedExchangeRateChangeLower;
emit LowerBoundUpdated(oldBound, allowedExchangeRateChangeLower);
}
function updateManagementFee(uint16 managementFee) external requiresAuth {
if (managementFee > 0.2e4) revert AccountantWithRateProviders__ManagementFeeTooLarge();
uint16 oldFee = accountantState.managementFee;
accountantState.managementFee = managementFee;
emit ManagementFeeUpdated(oldFee, managementFee);
}
function updatePerformanceFee(uint16 performanceFee) external requiresAuth {
if (performanceFee > 0.5e4) revert AccountantWithRateProviders__PerformanceFeeTooLarge();
uint16 oldFee = accountantState.performanceFee;
accountantState.performanceFee = performanceFee;
emit PerformanceFeeUpdated(oldFee, performanceFee);
}
function updatePayoutAddress(address payoutAddress) external requiresAuth {
address oldPayout = accountantState.payoutAddress;
accountantState.payoutAddress = payoutAddress;
emit PayoutAddressUpdated(oldPayout, payoutAddress);
}
function setRateProviderData(ERC20 asset, bool isPeggedToBase, address rateProvider) external requiresAuth {
rateProviderData[asset] =
RateProviderData({isPeggedToBase: isPeggedToBase, rateProvider: IRateProvider(rateProvider)});
emit RateProviderUpdated(address(asset), isPeggedToBase, rateProvider);
}
function resetHighwaterMark() external requiresAuth {
AccountantState storage state = accountantState;
if (state.exchangeRate > state.highwaterMark) {
revert AccountantWithRateProviders__ExchangeRateAboveHighwaterMark();
}
uint64 currentTime = uint64(block.timestamp);
uint256 currentTotalShares = vault.totalSupply();
_calculateFeesOwed(state, state.exchangeRate, state.exchangeRate, currentTotalShares, currentTime);
state.totalSharesLastUpdate = uint128(currentTotalShares);
state.highwaterMark = accountantState.exchangeRate;
state.lastUpdateTimestamp = currentTime;
emit HighwaterMarkReset();
}
function updateExchangeRate(uint96 newExchangeRate) external requiresAuth {
AccountantState storage state = accountantState;
if (state.isPaused) revert AccountantWithRateProviders__Paused();
uint64 currentTime = uint64(block.timestamp);
uint256 currentExchangeRate = state.exchangeRate;
uint256 currentTotalShares = vault.totalSupply();
if (
currentTime < state.lastUpdateTimestamp + state.minimumUpdateDelayInSeconds
|| newExchangeRate > currentExchangeRate.mulDivDown(state.allowedExchangeRateChangeUpper, 1e4)
|| newExchangeRate < currentExchangeRate.mulDivDown(state.allowedExchangeRateChangeLower, 1e4)
) {
state.isPaused = true;
} else {
_calculateFeesOwed(state, newExchangeRate, currentExchangeRate, currentTotalShares, currentTime);
}
state.exchangeRate = newExchangeRate;
state.totalSharesLastUpdate = uint128(currentTotalShares);
state.lastUpdateTimestamp = currentTime;
emit ExchangeRateUpdated(uint96(currentExchangeRate), newExchangeRate, currentTime);
}
function claimFees(ERC20 feeAsset) external {
if (msg.sender != address(vault)) revert AccountantWithRateProviders__OnlyCallableByBoringVault();
AccountantState storage state = accountantState;
if (state.isPaused) revert AccountantWithRateProviders__Paused();
if (state.feesOwedInBase == 0) revert AccountantWithRateProviders__ZeroFeesOwed();
uint256 feesOwedInFeeAsset;
RateProviderData memory data = rateProviderData[feeAsset];
if (address(feeAsset) == address(base)) {
feesOwedInFeeAsset = state.feesOwedInBase;
} else {
uint8 feeAssetDecimals = ERC20(feeAsset).decimals();
uint256 feesOwedInBaseUsingFeeAssetDecimals =
changeDecimals(state.feesOwedInBase, decimals, feeAssetDecimals);
if (data.isPeggedToBase) {
feesOwedInFeeAsset = feesOwedInBaseUsingFeeAssetDecimals;
} else {
uint256 rate = data.rateProvider.getRate();
feesOwedInFeeAsset = feesOwedInBaseUsingFeeAssetDecimals.mulDivDown(10 ** feeAssetDecimals, rate);
}
}
state.feesOwedInBase = 0;
feeAsset.safeTransferFrom(msg.sender, state.payoutAddress, feesOwedInFeeAsset);
emit FeesClaimed(address(feeAsset), feesOwedInFeeAsset);
}
function getRate() public view returns (uint256 rate) {
rate = accountantState.exchangeRate;
}
function getRateSafe() external view returns (uint256 rate) {
if (accountantState.isPaused) revert AccountantWithRateProviders__Paused();
rate = getRate();
}
function getRateInQuote(ERC20 quote) public view returns (uint256 rateInQuote) {
if (address(quote) == address(base)) {
rateInQuote = accountantState.exchangeRate;
} else {
RateProviderData memory data = rateProviderData[quote];
uint8 quoteDecimals = ERC20(quote).decimals();
uint256 exchangeRateInQuoteDecimals = changeDecimals(accountantState.exchangeRate, decimals, quoteDecimals);
if (data.isPeggedToBase) {
rateInQuote = exchangeRateInQuoteDecimals;
} else {
uint256 quoteRate = data.rateProvider.getRate();
uint256 oneQuote = 10 ** quoteDecimals;
rateInQuote = oneQuote.mulDivDown(exchangeRateInQuoteDecimals, quoteRate);
}
}
}
function getRateInQuoteSafe(ERC20 quote) external view returns (uint256 rateInQuote) {
if (accountantState.isPaused) revert AccountantWithRateProviders__Paused();
rateInQuote = getRateInQuote(quote);
}
function changeDecimals(uint256 amount, uint8 fromDecimals, uint8 toDecimals) internal pure returns (uint256) {
if (fromDecimals == toDecimals) {
return amount;
} else if (fromDecimals < toDecimals) {
return amount * 10 ** (toDecimals - fromDecimals);
} else {
return amount / 10 ** (fromDecimals - toDecimals);
}
}
function _calculateFeesOwed(
AccountantState storage state,
uint96 newExchangeRate,
uint256 currentExchangeRate,
uint256 currentTotalShares,
uint64 currentTime
) internal {
uint256 shareSupplyToUse = currentTotalShares;
if (state.totalSharesLastUpdate < shareSupplyToUse) {
shareSupplyToUse = state.totalSharesLastUpdate;
}
uint256 timeDelta = currentTime - state.lastUpdateTimestamp;
uint256 minimumAssets = newExchangeRate > currentExchangeRate
? shareSupplyToUse.mulDivDown(currentExchangeRate, ONE_SHARE)
: shareSupplyToUse.mulDivDown(newExchangeRate, ONE_SHARE);
uint256 managementFeesAnnual = minimumAssets.mulDivDown(state.managementFee, 1e4);
uint256 newFeesOwedInBase = managementFeesAnnual.mulDivDown(timeDelta, 365 days);
if (newExchangeRate > state.highwaterMark) {
if (state.performanceFee > 0) {
uint256 changeInExchangeRate = newExchangeRate - state.highwaterMark;
uint256 yieldEarned = changeInExchangeRate.mulDivDown(shareSupplyToUse, ONE_SHARE);
uint256 performanceFeesOwedInBase = yieldEarned.mulDivDown(state.performanceFee, 1e4);
newFeesOwedInBase += performanceFeesOwedInBase;
}
state.highwaterMark = newExchangeRate;
}
state.feesOwedInBase += uint128(newFeesOwedInBase);
}
}
文件 2 的 18:Address.sol
pragma solidity ^0.8.20;
library Address {
error AddressInsufficientBalance(address account);
error AddressEmptyCode(address target);
error FailedInnerCall();
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
function _revert(bytes memory returndata) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}
文件 3 的 18:Auth.sol
pragma solidity >=0.8.0;
abstract contract Auth {
event OwnershipTransferred(address indexed user, address indexed newOwner);
event AuthorityUpdated(address indexed user, Authority indexed newAuthority);
address public owner;
Authority public authority;
constructor(address _owner, Authority _authority) {
owner = _owner;
authority = _authority;
emit OwnershipTransferred(msg.sender, _owner);
emit AuthorityUpdated(msg.sender, _authority);
}
modifier requiresAuth() virtual {
require(isAuthorized(msg.sender, msg.sig), "UNAUTHORIZED");
_;
}
function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) {
Authority auth = authority;
return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig)) || user == owner;
}
function setAuthority(Authority newAuthority) public virtual {
require(msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig));
authority = newAuthority;
emit AuthorityUpdated(msg.sender, newAuthority);
}
function transferOwnership(address newOwner) public virtual requiresAuth {
owner = newOwner;
emit OwnershipTransferred(msg.sender, newOwner);
}
}
interface Authority {
function canCall(
address user,
address target,
bytes4 functionSig
) external view returns (bool);
}
文件 4 的 18:BeforeTransferHook.sol
pragma solidity 0.8.21;
interface BeforeTransferHook {
function beforeTransfer(address from, address to, address operator) external view;
}
文件 5 的 18:BoringVault.sol
pragma solidity 0.8.21;
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol";
import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol";
import {ERC20} from "@solmate/tokens/ERC20.sol";
import {BeforeTransferHook} from "src/interfaces/BeforeTransferHook.sol";
import {Auth, Authority} from "@solmate/auth/Auth.sol";
contract BoringVault is ERC20, Auth, ERC721Holder, ERC1155Holder {
using Address for address;
using SafeTransferLib for ERC20;
using FixedPointMathLib for uint256;
BeforeTransferHook public hook;
event Enter(address indexed from, address indexed asset, uint256 amount, address indexed to, uint256 shares);
event Exit(address indexed to, address indexed asset, uint256 amount, address indexed from, uint256 shares);
constructor(address _owner, string memory _name, string memory _symbol, uint8 _decimals)
ERC20(_name, _symbol, _decimals)
Auth(_owner, Authority(address(0)))
{}
function manage(address target, bytes calldata data, uint256 value)
external
requiresAuth
returns (bytes memory result)
{
result = target.functionCallWithValue(data, value);
}
function manage(address[] calldata targets, bytes[] calldata data, uint256[] calldata values)
external
requiresAuth
returns (bytes[] memory results)
{
uint256 targetsLength = targets.length;
results = new bytes[](targetsLength);
for (uint256 i; i < targetsLength; ++i) {
results[i] = targets[i].functionCallWithValue(data[i], values[i]);
}
}
function enter(address from, ERC20 asset, uint256 assetAmount, address to, uint256 shareAmount)
external
requiresAuth
{
if (assetAmount > 0) asset.safeTransferFrom(from, address(this), assetAmount);
_mint(to, shareAmount);
emit Enter(from, address(asset), assetAmount, to, shareAmount);
}
function exit(address to, ERC20 asset, uint256 assetAmount, address from, uint256 shareAmount)
external
requiresAuth
{
_burn(from, shareAmount);
if (assetAmount > 0) asset.safeTransfer(to, assetAmount);
emit Exit(to, address(asset), assetAmount, from, shareAmount);
}
function setBeforeTransferHook(address _hook) external requiresAuth {
hook = BeforeTransferHook(_hook);
}
function _callBeforeTransfer(address from, address to) internal view {
if (address(hook) != address(0)) hook.beforeTransfer(from, to, msg.sender);
}
function transfer(address to, uint256 amount) public override returns (bool) {
_callBeforeTransfer(msg.sender, to);
return super.transfer(to, amount);
}
function transferFrom(address from, address to, uint256 amount) public override returns (bool) {
_callBeforeTransfer(from, to);
return super.transferFrom(from, to, amount);
}
receive() external payable {}
}
文件 6 的 18:ERC1155Holder.sol
pragma solidity ^0.8.20;
import {IERC165, ERC165} from "../../../utils/introspection/ERC165.sol";
import {IERC1155Receiver} from "../IERC1155Receiver.sol";
abstract contract ERC1155Holder is ERC165, IERC1155Receiver {
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);
}
function onERC1155Received(
address,
address,
uint256,
uint256,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC1155Received.selector;
}
function onERC1155BatchReceived(
address,
address,
uint256[] memory,
uint256[] memory,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC1155BatchReceived.selector;
}
}
文件 7 的 18:ERC165.sol
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 8 的 18:ERC20.sol
pragma solidity >=0.8.0;
abstract contract ERC20 {
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
string public name;
string public symbol;
uint8 public immutable decimals;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender];
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}
文件 9 的 18:ERC721Holder.sol
pragma solidity ^0.8.20;
import {IERC721Receiver} from "../IERC721Receiver.sol";
abstract contract ERC721Holder is IERC721Receiver {
function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) {
return this.onERC721Received.selector;
}
}
文件 10 的 18:FixedPointMathLib.sol
pragma solidity >=0.8.0;
library FixedPointMathLib {
uint256 internal constant MAX_UINT256 = 2**256 - 1;
uint256 internal constant WAD = 1e18;
function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, y, WAD);
}
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, y, WAD);
}
function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, WAD, y);
}
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, WAD, y);
}
function mulDivDown(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
assembly {
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
z := div(mul(x, y), denominator)
}
}
function mulDivUp(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
assembly {
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
}
}
function rpow(
uint256 x,
uint256 n,
uint256 scalar
) internal pure returns (uint256 z) {
assembly {
switch x
case 0 {
switch n
case 0 {
z := scalar
}
default {
z := 0
}
}
default {
switch mod(n, 2)
case 0 {
z := scalar
}
default {
z := x
}
let half := shr(1, scalar)
for {
n := shr(1, n)
} n {
n := shr(1, n)
} {
if shr(128, x) {
revert(0, 0)
}
let xx := mul(x, x)
let xxRound := add(xx, half)
if lt(xxRound, xx) {
revert(0, 0)
}
x := div(xxRound, scalar)
if mod(n, 2) {
let zx := mul(z, x)
if iszero(eq(div(zx, x), z)) {
if iszero(iszero(x)) {
revert(0, 0)
}
}
let zxRound := add(zx, half)
if lt(zxRound, zx) {
revert(0, 0)
}
z := div(zxRound, scalar)
}
}
}
}
}
function sqrt(uint256 x) internal pure returns (uint256 z) {
assembly {
let y := x
z := 181
if iszero(lt(y, 0x10000000000000000000000000000000000)) {
y := shr(128, y)
z := shl(64, z)
}
if iszero(lt(y, 0x1000000000000000000)) {
y := shr(64, y)
z := shl(32, z)
}
if iszero(lt(y, 0x10000000000)) {
y := shr(32, y)
z := shl(16, z)
}
if iszero(lt(y, 0x1000000)) {
y := shr(16, y)
z := shl(8, z)
}
z := shr(18, mul(z, add(y, 65536)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := sub(z, lt(div(x, z), z))
}
}
function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly {
z := mod(x, y)
}
}
function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
assembly {
r := div(x, y)
}
}
function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly {
z := add(gt(mod(x, y), 0), div(x, y))
}
}
}
文件 11 的 18:IERC1155Receiver.sol
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
interface IERC1155Receiver is IERC165 {
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}
文件 12 的 18:IERC165.sol
pragma solidity ^0.8.20;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 13 的 18:IERC721Receiver.sol
pragma solidity ^0.8.20;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 14 的 18:IRateProvider.sol
pragma solidity ^0.8.0;
interface IRateProvider {
function getRate() external view returns (uint256);
}
文件 15 的 18:ReentrancyGuard.sol
pragma solidity >=0.8.0;
abstract contract ReentrancyGuard {
uint256 private locked = 1;
modifier nonReentrant() virtual {
require(locked == 1, "REENTRANCY");
locked = 2;
_;
locked = 1;
}
}
文件 16 的 18:SafeTransferLib.sol
pragma solidity >=0.8.0;
import {ERC20} from "../tokens/ERC20.sol";
library SafeTransferLib {
function safeTransferETH(address to, uint256 amount) internal {
bool success;
assembly {
success := call(gas(), to, amount, 0, 0, 0, 0)
}
require(success, "ETH_TRANSFER_FAILED");
}
function safeTransferFrom(
ERC20 token,
address from,
address to,
uint256 amount
) internal {
bool success;
assembly {
let freeMemoryPointer := mload(0x40)
mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(freeMemoryPointer, 68), amount)
success := and(
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
)
}
require(success, "TRANSFER_FROM_FAILED");
}
function safeTransfer(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
assembly {
let freeMemoryPointer := mload(0x40)
mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(freeMemoryPointer, 36), amount)
success := and(
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "TRANSFER_FAILED");
}
function safeApprove(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
assembly {
let freeMemoryPointer := mload(0x40)
mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(freeMemoryPointer, 36), amount)
success := and(
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "APPROVE_FAILED");
}
}
文件 17 的 18:TellerWithMultiAssetSupport.sol
pragma solidity 0.8.21;
import {ERC20} from "@solmate/tokens/ERC20.sol";
import {WETH} from "@solmate/tokens/WETH.sol";
import {BoringVault} from "src/base/BoringVault.sol";
import {AccountantWithRateProviders} from "src/base/Roles/AccountantWithRateProviders.sol";
import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol";
import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol";
import {BeforeTransferHook} from "src/interfaces/BeforeTransferHook.sol";
import {Auth, Authority} from "@solmate/auth/Auth.sol";
import {ReentrancyGuard} from "@solmate/utils/ReentrancyGuard.sol";
contract TellerWithMultiAssetSupport is Auth, BeforeTransferHook, ReentrancyGuard {
using FixedPointMathLib for uint256;
using SafeTransferLib for ERC20;
using SafeTransferLib for WETH;
address internal constant NATIVE = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
uint256 internal constant MAX_SHARE_LOCK_PERIOD = 3 days;
mapping(ERC20 => bool) public isSupported;
uint96 public depositNonce = 1;
uint64 public shareLockPeriod;
bool public isPaused;
mapping(uint256 => bytes32) public publicDepositHistory;
mapping(address => uint256) public shareUnlockTime;
mapping(address => bool) public fromDenyList;
mapping(address => bool) public toDenyList;
mapping(address => bool) public operatorDenyList;
error TellerWithMultiAssetSupport__ShareLockPeriodTooLong();
error TellerWithMultiAssetSupport__SharesAreLocked();
error TellerWithMultiAssetSupport__SharesAreUnLocked();
error TellerWithMultiAssetSupport__BadDepositHash();
error TellerWithMultiAssetSupport__AssetNotSupported();
error TellerWithMultiAssetSupport__ZeroAssets();
error TellerWithMultiAssetSupport__MinimumMintNotMet();
error TellerWithMultiAssetSupport__MinimumAssetsNotMet();
error TellerWithMultiAssetSupport__PermitFailedAndAllowanceTooLow();
error TellerWithMultiAssetSupport__ZeroShares();
error TellerWithMultiAssetSupport__DualDeposit();
error TellerWithMultiAssetSupport__Paused();
error TellerWithMultiAssetSupport__TransferDenied(address from, address to, address operator);
event Paused();
event Unpaused();
event AssetAdded(address indexed asset);
event AssetRemoved(address indexed asset);
event Deposit(
uint256 indexed nonce,
address indexed receiver,
address indexed depositAsset,
uint256 depositAmount,
uint256 shareAmount,
uint256 depositTimestamp,
uint256 shareLockPeriodAtTimeOfDeposit
);
event BulkDeposit(address indexed asset, uint256 depositAmount);
event BulkWithdraw(address indexed asset, uint256 shareAmount);
event DepositRefunded(uint256 indexed nonce, bytes32 depositHash, address indexed user);
event DenyFrom(address indexed user);
event DenyTo(address indexed user);
event DenyOperator(address indexed user);
event AllowFrom(address indexed user);
event AllowTo(address indexed user);
event AllowOperator(address indexed user);
BoringVault public immutable vault;
AccountantWithRateProviders public immutable accountant;
uint256 internal immutable ONE_SHARE;
WETH public immutable nativeWrapper;
constructor(address _owner, address _vault, address _accountant, address _weth)
Auth(_owner, Authority(address(0)))
{
vault = BoringVault(payable(_vault));
ONE_SHARE = 10 ** vault.decimals();
accountant = AccountantWithRateProviders(_accountant);
nativeWrapper = WETH(payable(_weth));
}
function pause() external requiresAuth {
isPaused = true;
emit Paused();
}
function unpause() external requiresAuth {
isPaused = false;
emit Unpaused();
}
function addAsset(ERC20 asset) external requiresAuth {
isSupported[asset] = true;
emit AssetAdded(address(asset));
}
function removeAsset(ERC20 asset) external requiresAuth {
isSupported[asset] = false;
emit AssetRemoved(address(asset));
}
function setShareLockPeriod(uint64 _shareLockPeriod) external requiresAuth {
if (_shareLockPeriod > MAX_SHARE_LOCK_PERIOD) revert TellerWithMultiAssetSupport__ShareLockPeriodTooLong();
shareLockPeriod = _shareLockPeriod;
}
function denyAll(address user) external requiresAuth {
fromDenyList[user] = true;
toDenyList[user] = true;
operatorDenyList[user] = true;
emit DenyFrom(user);
emit DenyTo(user);
emit DenyOperator(user);
}
function allowAll(address user) external requiresAuth {
fromDenyList[user] = false;
toDenyList[user] = false;
operatorDenyList[user] = false;
emit AllowFrom(user);
emit AllowTo(user);
emit AllowOperator(user);
}
function denyFrom(address user) external requiresAuth {
fromDenyList[user] = true;
emit DenyFrom(user);
}
function allowFrom(address user) external requiresAuth {
fromDenyList[user] = false;
emit AllowFrom(user);
}
function denyTo(address user) external requiresAuth {
toDenyList[user] = true;
emit DenyTo(user);
}
function allowTo(address user) external requiresAuth {
toDenyList[user] = false;
emit AllowTo(user);
}
function denyOperator(address user) external requiresAuth {
operatorDenyList[user] = true;
emit DenyOperator(user);
}
function allowOperator(address user) external requiresAuth {
operatorDenyList[user] = false;
emit AllowOperator(user);
}
function beforeTransfer(address from, address to, address operator) public view virtual {
if (fromDenyList[from] || toDenyList[to] || operatorDenyList[operator]) {
revert TellerWithMultiAssetSupport__TransferDenied(from, to, operator);
}
if (shareUnlockTime[from] >= block.timestamp) revert TellerWithMultiAssetSupport__SharesAreLocked();
}
function refundDeposit(
uint256 nonce,
address receiver,
address depositAsset,
uint256 depositAmount,
uint256 shareAmount,
uint256 depositTimestamp,
uint256 shareLockUpPeriodAtTimeOfDeposit
) external requiresAuth {
if ((block.timestamp - depositTimestamp) > shareLockUpPeriodAtTimeOfDeposit) {
revert TellerWithMultiAssetSupport__SharesAreUnLocked();
}
bytes32 depositHash = keccak256(
abi.encode(
receiver, depositAsset, depositAmount, shareAmount, depositTimestamp, shareLockUpPeriodAtTimeOfDeposit
)
);
if (publicDepositHistory[nonce] != depositHash) revert TellerWithMultiAssetSupport__BadDepositHash();
delete publicDepositHistory[nonce];
depositAsset = depositAsset == NATIVE ? address(nativeWrapper) : depositAsset;
vault.exit(receiver, ERC20(depositAsset), depositAmount, receiver, shareAmount);
emit DepositRefunded(nonce, depositHash, receiver);
}
function deposit(ERC20 depositAsset, uint256 depositAmount, uint256 minimumMint)
external
payable
requiresAuth
nonReentrant
returns (uint256 shares)
{
if (isPaused) revert TellerWithMultiAssetSupport__Paused();
if (!isSupported[depositAsset]) revert TellerWithMultiAssetSupport__AssetNotSupported();
if (address(depositAsset) == NATIVE) {
if (msg.value == 0) revert TellerWithMultiAssetSupport__ZeroAssets();
nativeWrapper.deposit{value: msg.value}();
depositAmount = msg.value;
shares = depositAmount.mulDivDown(ONE_SHARE, accountant.getRateInQuoteSafe(nativeWrapper));
if (shares < minimumMint) revert TellerWithMultiAssetSupport__MinimumMintNotMet();
nativeWrapper.safeApprove(address(vault), depositAmount);
vault.enter(address(this), nativeWrapper, depositAmount, msg.sender, shares);
} else {
if (msg.value > 0) revert TellerWithMultiAssetSupport__DualDeposit();
shares = _erc20Deposit(depositAsset, depositAmount, minimumMint, msg.sender);
}
_afterPublicDeposit(msg.sender, depositAsset, depositAmount, shares, shareLockPeriod);
}
function depositWithPermit(
ERC20 depositAsset,
uint256 depositAmount,
uint256 minimumMint,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external requiresAuth nonReentrant returns (uint256 shares) {
if (isPaused) revert TellerWithMultiAssetSupport__Paused();
if (!isSupported[depositAsset]) revert TellerWithMultiAssetSupport__AssetNotSupported();
try depositAsset.permit(msg.sender, address(vault), depositAmount, deadline, v, r, s) {}
catch {
if (depositAsset.allowance(msg.sender, address(vault)) < depositAmount) {
revert TellerWithMultiAssetSupport__PermitFailedAndAllowanceTooLow();
}
}
shares = _erc20Deposit(depositAsset, depositAmount, minimumMint, msg.sender);
_afterPublicDeposit(msg.sender, depositAsset, depositAmount, shares, shareLockPeriod);
}
function bulkDeposit(ERC20 depositAsset, uint256 depositAmount, uint256 minimumMint, address to)
external
requiresAuth
nonReentrant
returns (uint256 shares)
{
if (!isSupported[depositAsset]) revert TellerWithMultiAssetSupport__AssetNotSupported();
shares = _erc20Deposit(depositAsset, depositAmount, minimumMint, to);
emit BulkDeposit(address(depositAsset), depositAmount);
}
function bulkWithdraw(ERC20 withdrawAsset, uint256 shareAmount, uint256 minimumAssets, address to)
external
requiresAuth
returns (uint256 assetsOut)
{
if (!isSupported[withdrawAsset]) revert TellerWithMultiAssetSupport__AssetNotSupported();
if (shareAmount == 0) revert TellerWithMultiAssetSupport__ZeroShares();
assetsOut = shareAmount.mulDivDown(accountant.getRateInQuoteSafe(withdrawAsset), ONE_SHARE);
if (assetsOut < minimumAssets) revert TellerWithMultiAssetSupport__MinimumAssetsNotMet();
vault.exit(to, withdrawAsset, assetsOut, msg.sender, shareAmount);
emit BulkWithdraw(address(withdrawAsset), shareAmount);
}
function _erc20Deposit(ERC20 depositAsset, uint256 depositAmount, uint256 minimumMint, address to)
internal
returns (uint256 shares)
{
if (depositAmount == 0) revert TellerWithMultiAssetSupport__ZeroAssets();
shares = depositAmount.mulDivDown(ONE_SHARE, accountant.getRateInQuoteSafe(depositAsset));
if (shares < minimumMint) revert TellerWithMultiAssetSupport__MinimumMintNotMet();
vault.enter(msg.sender, depositAsset, depositAmount, to, shares);
}
function _afterPublicDeposit(
address user,
ERC20 depositAsset,
uint256 depositAmount,
uint256 shares,
uint256 currentShareLockPeriod
) internal {
shareUnlockTime[user] = block.timestamp + currentShareLockPeriod;
uint256 nonce = depositNonce;
publicDepositHistory[nonce] =
keccak256(abi.encode(user, depositAsset, depositAmount, shares, block.timestamp, currentShareLockPeriod));
depositNonce++;
emit Deposit(nonce, user, address(depositAsset), depositAmount, shares, block.timestamp, currentShareLockPeriod);
}
}
文件 18 的 18:WETH.sol
pragma solidity >=0.8.0;
import {ERC20} from "./ERC20.sol";
import {SafeTransferLib} from "../utils/SafeTransferLib.sol";
contract WETH is ERC20("Wrapped Ether", "WETH", 18) {
using SafeTransferLib for address;
event Deposit(address indexed from, uint256 amount);
event Withdrawal(address indexed to, uint256 amount);
function deposit() public payable virtual {
_mint(msg.sender, msg.value);
emit Deposit(msg.sender, msg.value);
}
function withdraw(uint256 amount) public virtual {
_burn(msg.sender, amount);
emit Withdrawal(msg.sender, amount);
msg.sender.safeTransferETH(amount);
}
receive() external payable virtual {
deposit();
}
}
{
"compilationTarget": {
"src/base/Roles/TellerWithMultiAssetSupport.sol": "TellerWithMultiAssetSupport"
},
"evmVersion": "shanghai",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@ds-test/=lib/forge-std/lib/ds-test/src/",
":@forge-std/=lib/forge-std/src/",
":@openzeppelin/=lib/openzeppelin-contracts/",
":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
":@solmate/=lib/solmate/src/",
":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/",
":solmate/=lib/solmate/src/"
]
}
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_accountant","type":"address"},{"internalType":"address","name":"_weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"TellerWithMultiAssetSupport__AssetNotSupported","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__BadDepositHash","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__DualDeposit","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__MinimumAssetsNotMet","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__MinimumMintNotMet","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__Paused","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__PermitFailedAndAllowanceTooLow","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__ShareLockPeriodTooLong","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__SharesAreLocked","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__SharesAreUnLocked","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"TellerWithMultiAssetSupport__TransferDenied","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__ZeroAssets","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__ZeroShares","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"AllowFrom","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"AllowOperator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"AllowTo","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"}],"name":"AssetAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"}],"name":"AssetRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"AuthorityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"depositAmount","type":"uint256"}],"name":"BulkDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"shareAmount","type":"uint256"}],"name":"BulkWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"DenyFrom","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"DenyOperator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"DenyTo","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"depositAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"depositAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shareAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"depositTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shareLockPeriodAtTimeOfDeposit","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"depositHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"DepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpaused","type":"event"},{"inputs":[],"name":"accountant","outputs":[{"internalType":"contract AccountantWithRateProviders","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"asset","type":"address"}],"name":"addAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"allowAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"allowFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"allowOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"allowTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"authority","outputs":[{"internalType":"contract Authority","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"beforeTransfer","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"depositAsset","type":"address"},{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"uint256","name":"minimumMint","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"bulkDeposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"withdrawAsset","type":"address"},{"internalType":"uint256","name":"shareAmount","type":"uint256"},{"internalType":"uint256","name":"minimumAssets","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"bulkWithdraw","outputs":[{"internalType":"uint256","name":"assetsOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"denyAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"denyFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"denyOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"denyTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"depositAsset","type":"address"},{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"uint256","name":"minimumMint","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"depositNonce","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"depositAsset","type":"address"},{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"uint256","name":"minimumMint","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"depositWithPermit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"fromDenyList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"name":"isSupported","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nativeWrapper","outputs":[{"internalType":"contract WETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"operatorDenyList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"publicDepositHistory","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"depositAsset","type":"address"},{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"uint256","name":"shareAmount","type":"uint256"},{"internalType":"uint256","name":"depositTimestamp","type":"uint256"},{"internalType":"uint256","name":"shareLockUpPeriodAtTimeOfDeposit","type":"uint256"}],"name":"refundDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"asset","type":"address"}],"name":"removeAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"setAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_shareLockPeriod","type":"uint64"}],"name":"setShareLockPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shareLockPeriod","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"shareUnlockTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"toDenyList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract BoringVault","name":"","type":"address"}],"stateMutability":"view","type":"function"}]