编译器
0.8.26+commit.8a97fa7a
文件 1 的 13:AccessControl.sol
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => 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 returns (bool) {
return _roles[role].hasRole[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 AccessControlUnauthorizedAccount(account, role);
}
}
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
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 returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}
文件 2 的 13:Context.sol
pragma solidity ^0.8.20;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
文件 3 的 13: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;
}
}
文件 4 的 13:ERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view virtual returns (string memory) {
return _name;
}
function symbol() public view virtual returns (string memory) {
return _symbol;
}
function decimals() public view virtual returns (uint8) {
return 18;
}
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
_totalSupply -= value;
}
} else {
unchecked {
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}
文件 5 的 13:Errors.sol
pragma solidity 0.8.26;
error InvalidToken();
error InvalidAsset();
error InsufficientBalance();
error InvalidOracle();
error InvalidPrice();
error InvalidArrayLength();
error DepositCapped();
error DepositPaused();
error ZeroShares();
error ZeroAmount();
error NoRequestingShares();
error NoClaimableRedeem();
error ZeroAddress();
error InvalidRequest();
error InvalidRequestToken();
error CannotRemove();
error InvalidDecimals();
error InvalidFeeRate();
error NoFeeRecipient();
文件 6 的 13:IAccessControl.sol
pragma solidity ^0.8.20;
interface IAccessControl {
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
error AccessControlBadConfirmation();
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 callerConfirmation) external;
}
文件 7 的 13:IERC165.sol
pragma solidity ^0.8.20;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 8 的 13:IERC20.sol
pragma solidity ^0.8.20;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
文件 9 的 13:IERC20Metadata.sol
pragma solidity ^0.8.20;
import {IERC20} from "../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);
}
文件 10 的 13:SBTCBeraVault.sol
pragma solidity 0.8.26;
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {TransferHelper} from "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
import {Token} from "./Token.sol";
import "./Errors.sol";
contract SBTCBeraVault is AccessControl {
bytes32 public constant VAULT_OPERATOR_ROLE =
keccak256("VAULT_OPERATOR_ROLE");
bytes32 public constant ASSETS_MANAGEMENT_ROLE =
keccak256("ASSETS_MANAGEMENT_ROLE");
uint256 public constant D18 = 1e18;
uint256 public constant D6 = 1e6;
Token public immutable lpToken;
address[] public underlyingAssets;
address[] public withdrawTokens;
mapping(address => uint8) public tokenDecimals;
mapping(address => bool) public isUnderlyingAsset;
mapping(address => bool) public isWithdrawToken;
mapping(address => RedeemRequest) public redeemRequests;
mapping(address => bool) public depositPaused;
uint256 public latestRoundID;
uint256 public cap;
uint256 public requestingSharesInPast;
mapping(address => uint256) public requestingSharesInRound;
mapping(address => uint256) public redeemableAmountInPast;
mapping(address => uint256) public feeRate;
address public feeRecipient;
struct RedeemRequest {
uint256 requestRound;
address requestToken;
uint256 requestShares;
}
event Deposit(
address indexed caller,
address indexed owner,
address indexed asset,
uint256 amount,
uint256 shares
);
event RedeemRequested(
address indexed owner,
address indexed requestToken,
uint256 shares,
uint256 round
);
event RedeemCancelled(
address indexed owner,
address indexed requestToken,
uint256 shares,
uint256 round
);
event RedeemClaimed(
address indexed owner,
address indexed claimToken,
uint256 amount
);
event RollToNextRound(uint256 round, uint256 share);
event FeeCharged(address recipient, uint256 fee);
event SetFeeRate(address indexed asset, uint256 feeRate);
event SetFeeRecipient(address oldValue, address newValue);
event SetCap(uint256 oldValue, uint256 newValue);
event SetDepositPause(address indexed asset, bool flag);
event AddUnderlyingAsset(address indexed asset);
event RemoveUnderlyingAsset(address indexed asset);
event AddWithdrawToken(address indexed withdrawToken);
event RemoveWithdrawToken(address indexed withdrawToken);
event AssetsWithdrawn(address indexed asset, uint256 amount);
event AssetsRepaid(address indexed asset, uint256 amount);
constructor(address _lpToken, uint256 _cap) {
if (_lpToken == address(0)) revert ZeroAddress();
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
lpToken = Token(_lpToken);
cap = _cap;
emit SetCap(0, _cap);
}
function deposit(
address _asset,
uint256 _amount,
address _receiver
) public returns (uint256 shares) {
if ((shares = previewDeposit(_asset, _amount)) == 0)
revert ZeroShares();
TransferHelper.safeTransferFrom(
_asset,
msg.sender,
address(this),
_amount
);
uint256 fee;
uint256 rate = feeRate[_asset];
if (rate != 0) {
fee = (shares * rate) / D6;
}
if (fee == 0) {
lpToken.mint(_receiver, shares);
} else {
shares -= fee;
lpToken.mint(_receiver, shares);
lpToken.mint(feeRecipient, fee);
emit FeeCharged(feeRecipient, fee);
}
emit Deposit(msg.sender, _receiver, _asset, _amount, shares);
}
function mint(
address _asset,
uint256 _shares,
address _receiver
) external returns (uint256 assets) {
if (_shares == 0) revert ZeroShares();
assets = previewMint(_asset, _shares);
if (assets == 0) revert ZeroAmount();
TransferHelper.safeTransferFrom(
_asset,
msg.sender,
address(this),
assets
);
uint256 fee;
uint256 rate = feeRate[_asset];
if (rate != 0) {
fee = (_shares * rate) / D6;
}
if (fee == 0) {
lpToken.mint(_receiver, _shares);
} else {
_shares -= fee;
lpToken.mint(_receiver, _shares);
lpToken.mint(feeRecipient, fee);
emit FeeCharged(feeRecipient, fee);
}
emit Deposit(msg.sender, _receiver, _asset, assets, _shares);
}
function requestRedeem(address _requestToken, uint256 _shares) external {
if (!isWithdrawToken[_requestToken]) revert InvalidRequestToken();
if (_shares == 0) revert ZeroShares();
if (_shares > lpToken.balanceOf(msg.sender))
revert InsufficientBalance();
TransferHelper.safeTransferFrom(
address(lpToken),
msg.sender,
address(this),
_shares
);
RedeemRequest storage redeemRequest = redeemRequests[msg.sender];
if (
redeemRequest.requestShares > 0 &&
redeemRequest.requestRound < latestRoundID
) {
claimRedeemRequest();
}
if (redeemRequest.requestRound == latestRoundID) {
if (
redeemRequest.requestToken != address(0) &&
redeemRequest.requestToken != _requestToken
) revert InvalidRequest();
redeemRequest.requestToken = _requestToken;
redeemRequest.requestShares += _shares;
} else {
redeemRequest.requestRound = latestRoundID;
redeemRequest.requestToken = _requestToken;
redeemRequest.requestShares = _shares;
}
requestingSharesInRound[_requestToken] += _shares;
emit RedeemRequested(msg.sender, _requestToken, _shares, latestRoundID);
}
function cancelRequest() external {
(
address requestToken,
uint256 requestingShares
) = pendingRedeemRequest();
if (requestingShares == 0) revert NoRequestingShares();
RedeemRequest storage redeemRequest = redeemRequests[msg.sender];
redeemRequest.requestShares = 0;
redeemRequest.requestToken = address(0);
requestingSharesInRound[requestToken] -= requestingShares;
TransferHelper.safeTransfer(
address(lpToken),
msg.sender,
requestingShares
);
emit RedeemCancelled(
msg.sender,
requestToken,
requestingShares,
latestRoundID
);
}
function claimRedeemRequest() public {
RedeemRequest storage redeemRequest = redeemRequests[msg.sender];
address requestToken = redeemRequest.requestToken;
uint256 requestShares = redeemRequest.requestShares;
uint256 round = redeemRequest.requestRound;
uint256 claimable;
if (round < latestRoundID && requestShares != 0) {
uint8 decimals = tokenDecimals[requestToken];
claimable = requestShares / (10 ** (18 - decimals));
} else {
revert NoClaimableRedeem();
}
lpToken.burn(address(this), requestShares);
redeemRequest.requestToken = address(0);
redeemRequest.requestShares = 0;
redeemableAmountInPast[requestToken] -= claimable;
requestingSharesInPast -= requestShares;
if (claimable != 0) {
TransferHelper.safeTransfer(requestToken, msg.sender, claimable);
}
emit RedeemClaimed(msg.sender, requestToken, claimable);
}
function pendingRedeemRequest()
public
view
returns (address requestToken, uint256 shares)
{
RedeemRequest memory redeemRequest = redeemRequests[msg.sender];
if (redeemRequest.requestRound == latestRoundID) {
requestToken = redeemRequest.requestToken;
shares = redeemRequest.requestShares;
}
}
function claimableRedeemRequest()
external
view
returns (address requestToken, uint256 assets)
{
RedeemRequest memory redeemRequest = redeemRequests[msg.sender];
requestToken = redeemRequest.requestToken;
uint256 round = redeemRequest.requestRound;
uint256 shares = redeemRequest.requestShares;
if (round < latestRoundID && shares != 0) {
uint8 decimals = tokenDecimals[requestToken];
assets = shares / (10 ** (18 - decimals));
}
}
function previewDeposit(
address _asset,
uint256 _amount
) public view returns (uint256 shares) {
if (depositPaused[_asset]) revert DepositPaused();
if (!isUnderlyingAsset[_asset]) revert InvalidAsset();
uint8 decimal = tokenDecimals[_asset];
shares = _amount * (10 ** (18 - decimal));
if (lpToken.totalSupply() + shares > cap) revert DepositCapped();
}
function previewMint(
address _asset,
uint256 _shares
) public view returns (uint256 assets) {
if (depositPaused[_asset]) revert DepositPaused();
if (!isUnderlyingAsset[_asset]) revert InvalidAsset();
if (lpToken.totalSupply() + _shares > cap) revert DepositCapped();
uint8 decimal = tokenDecimals[_asset];
assets = _shares / (10 ** (18 - decimal));
}
function getRate() public pure returns (uint256 rate) {
return D18;
}
function getUnderlyings()
external
view
returns (address[] memory underlyings)
{
return underlyingAssets;
}
function getWithdrawTokens()
external
view
returns (address[] memory tokens)
{
return withdrawTokens;
}
function rollToNextRound() external onlyRole(VAULT_OPERATOR_ROLE) {
address[] memory tokens = withdrawTokens;
uint256 requestingShares;
uint256 length = tokens.length;
uint256 i;
for (i; i < length; i++) {
address token = tokens[i];
uint256 shares = requestingSharesInRound[token];
uint8 decimal = tokenDecimals[token];
uint256 withdrawAmount = shares / (10 ** (18 - decimal));
if (
ERC20(token).balanceOf(address(this)) <
redeemableAmountInPast[token] + withdrawAmount
) revert InsufficientBalance();
requestingShares += shares;
redeemableAmountInPast[token] += withdrawAmount;
requestingSharesInRound[token] = 0;
}
requestingSharesInPast += requestingShares;
latestRoundID++;
emit RollToNextRound(latestRoundID, requestingShares);
}
function withdrawAssets(
address _asset,
uint256 _amount
) external onlyRole(ASSETS_MANAGEMENT_ROLE) {
if (!isUnderlyingAsset[_asset]) revert InvalidAsset();
uint256 balance = ERC20(_asset).balanceOf(address(this));
if (balance < _amount) revert InsufficientBalance();
if (
isWithdrawToken[_asset] &&
balance < redeemableAmountInPast[_asset] + _amount
) revert InsufficientBalance();
TransferHelper.safeTransfer(_asset, msg.sender, _amount);
emit AssetsWithdrawn(_asset, _amount);
}
function repayAssets(
address _asset,
uint256 _amount
) external onlyRole(ASSETS_MANAGEMENT_ROLE) {
if (!isUnderlyingAsset[_asset]) revert InvalidAsset();
TransferHelper.safeTransferFrom(
_asset,
msg.sender,
address(this),
_amount
);
emit AssetsRepaid(_asset, _amount);
}
function setCap(uint256 _cap) external onlyRole(VAULT_OPERATOR_ROLE) {
emit SetCap(cap, _cap);
cap = _cap;
}
function addUnderlyingAsset(
address _asset
) external onlyRole(VAULT_OPERATOR_ROLE) {
if (_asset == address(0) || isUnderlyingAsset[_asset])
revert InvalidAsset();
isUnderlyingAsset[_asset] = true;
underlyingAssets.push(_asset);
uint8 decimals = ERC20(_asset).decimals();
if (decimals > 18) revert InvalidDecimals();
tokenDecimals[_asset] = decimals;
emit AddUnderlyingAsset(_asset);
}
function removeUnderlyingAsset(
address _asset
) external onlyRole(VAULT_OPERATOR_ROLE) {
if (!isUnderlyingAsset[_asset]) revert InvalidAsset();
address[] memory assets = underlyingAssets;
uint256 length = assets.length;
uint256 i;
for (i; i < length; i++) {
if (assets[i] == _asset) {
underlyingAssets[i] = underlyingAssets[length - 1];
underlyingAssets.pop();
break;
}
}
isUnderlyingAsset[_asset] = false;
emit RemoveUnderlyingAsset(_asset);
}
function addWithdrawToken(
address _withdrawToken
) external onlyRole(VAULT_OPERATOR_ROLE) {
if (_withdrawToken == address(0) || isWithdrawToken[_withdrawToken])
revert InvalidAsset();
isWithdrawToken[_withdrawToken] = true;
withdrawTokens.push(_withdrawToken);
emit AddWithdrawToken(_withdrawToken);
}
function removeWithdrawToken(
address _withdrawToken
) external onlyRole(VAULT_OPERATOR_ROLE) {
if (!isWithdrawToken[_withdrawToken]) revert InvalidAsset();
if (requestingSharesInRound[_withdrawToken] != 0) revert CannotRemove();
address[] memory assets = withdrawTokens;
uint256 length = assets.length;
uint256 i;
for (i; i < length; i++) {
if (assets[i] == _withdrawToken) {
withdrawTokens[i] = withdrawTokens[length - 1];
withdrawTokens.pop();
break;
}
}
isWithdrawToken[_withdrawToken] = false;
emit RemoveWithdrawToken(_withdrawToken);
}
function setDepositPause(
address _token,
bool _pause
) external onlyRole(VAULT_OPERATOR_ROLE) {
depositPaused[_token] = _pause;
emit SetDepositPause(_token, _pause);
}
function setFeeRate(
address _token,
uint256 _feeRate
) external onlyRole(VAULT_OPERATOR_ROLE) {
if (feeRecipient == address(0)) revert NoFeeRecipient();
if (!isUnderlyingAsset[_token]) revert InvalidAsset();
if (_feeRate > D6) revert InvalidFeeRate();
feeRate[_token] = _feeRate;
emit SetFeeRate(_token, _feeRate);
}
function setFeeRecipient(
address _feeRecipient
) external onlyRole(VAULT_OPERATOR_ROLE) {
if (_feeRecipient == address(0)) revert ZeroAddress();
emit SetFeeRecipient(feeRecipient, _feeRecipient);
feeRecipient = _feeRecipient;
}
}
文件 11 的 13:Token.sol
pragma solidity 0.8.26;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
contract Token is ERC20, AccessControl {
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
constructor(
string memory _name,
string memory _symbol
) ERC20(_name, _symbol) {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
function mint(address _to, uint256 _amount) external onlyRole(MINTER_ROLE) {
_mint(_to, _amount);
}
function burn(
address _from,
uint256 _amount
) external onlyRole(BURNER_ROLE) {
_burn(_from, _amount);
}
}
文件 12 的 13:TransferHelper.sol
pragma solidity >=0.6.0;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
library TransferHelper {
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
(bool success, bytes memory data) =
token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'STF');
}
function safeTransfer(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'ST');
}
function safeApprove(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'SA');
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, 'STE');
}
}
文件 13 的 13:draft-IERC6093.sol
pragma solidity ^0.8.20;
interface IERC20Errors {
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
error ERC20InvalidSender(address sender);
error ERC20InvalidReceiver(address receiver);
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
error ERC20InvalidApprover(address approver);
error ERC20InvalidSpender(address spender);
}
interface IERC721Errors {
error ERC721InvalidOwner(address owner);
error ERC721NonexistentToken(uint256 tokenId);
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
error ERC721InvalidSender(address sender);
error ERC721InvalidReceiver(address receiver);
error ERC721InsufficientApproval(address operator, uint256 tokenId);
error ERC721InvalidApprover(address approver);
error ERC721InvalidOperator(address operator);
}
interface IERC1155Errors {
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
error ERC1155InvalidSender(address sender);
error ERC1155InvalidReceiver(address receiver);
error ERC1155MissingApprovalForAll(address operator, address owner);
error ERC1155InvalidApprover(address approver);
error ERC1155InvalidOperator(address operator);
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
{
"compilationTarget": {
"src/SBTCBeraVault.sol": "SBTCBeraVault"
},
"evmVersion": "shanghai",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
":@uniswap/v3-periphery/contracts/=lib/v3-periphery/contracts/",
":ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
":forge-std/=lib/forge-std/src/",
":halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/",
":v3-periphery/=lib/v3-periphery/contracts/"
]
}
[{"inputs":[{"internalType":"address","name":"_lpToken","type":"address"},{"internalType":"uint256","name":"_cap","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"CannotRemove","type":"error"},{"inputs":[],"name":"DepositCapped","type":"error"},{"inputs":[],"name":"DepositPaused","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidAsset","type":"error"},{"inputs":[],"name":"InvalidDecimals","type":"error"},{"inputs":[],"name":"InvalidFeeRate","type":"error"},{"inputs":[],"name":"InvalidRequest","type":"error"},{"inputs":[],"name":"InvalidRequestToken","type":"error"},{"inputs":[],"name":"NoClaimableRedeem","type":"error"},{"inputs":[],"name":"NoFeeRecipient","type":"error"},{"inputs":[],"name":"NoRequestingShares","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"inputs":[],"name":"ZeroShares","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"}],"name":"AddUnderlyingAsset","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"withdrawToken","type":"address"}],"name":"AddWithdrawToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AssetsRepaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AssetsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"FeeCharged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"requestToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"}],"name":"RedeemCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"claimToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RedeemClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"requestToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"}],"name":"RedeemRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"}],"name":"RemoveUnderlyingAsset","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"withdrawToken","type":"address"}],"name":"RemoveWithdrawToken","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":false,"internalType":"uint256","name":"round","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"share","type":"uint256"}],"name":"RollToNextRound","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"SetCap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"bool","name":"flag","type":"bool"}],"name":"SetDepositPause","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"feeRate","type":"uint256"}],"name":"SetFeeRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldValue","type":"address"},{"indexed":false,"internalType":"address","name":"newValue","type":"address"}],"name":"SetFeeRecipient","type":"event"},{"inputs":[],"name":"ASSETS_MANAGEMENT_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"D18","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"D6","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VAULT_OPERATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"addUnderlyingAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_withdrawToken","type":"address"}],"name":"addWithdrawToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimRedeemRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimableRedeemRequest","outputs":[{"internalType":"address","name":"requestToken","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"depositPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"feeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRate","outputs":[{"internalType":"uint256","name":"rate","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUnderlyings","outputs":[{"internalType":"address[]","name":"underlyings","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawTokens","outputs":[{"internalType":"address[]","name":"tokens","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":[{"internalType":"address","name":"","type":"address"}],"name":"isUnderlyingAsset","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isWithdrawToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestRoundID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpToken","outputs":[{"internalType":"contract Token","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_shares","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pendingRedeemRequest","outputs":[{"internalType":"address","name":"requestToken","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"redeemRequests","outputs":[{"internalType":"uint256","name":"requestRound","type":"uint256"},{"internalType":"address","name":"requestToken","type":"address"},{"internalType":"uint256","name":"requestShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"redeemableAmountInPast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"removeUnderlyingAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_withdrawToken","type":"address"}],"name":"removeWithdrawToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"repayAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_requestToken","type":"address"},{"internalType":"uint256","name":"_shares","type":"uint256"}],"name":"requestRedeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requestingSharesInPast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"requestingSharesInRound","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rollToNextRound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_cap","type":"uint256"}],"name":"setCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"bool","name":"_pause","type":"bool"}],"name":"setDepositPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_feeRate","type":"uint256"}],"name":"setFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeRecipient","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","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":"tokenDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"underlyingAssets","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"withdrawTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]