编译器
0.8.19+commit.7dd6d404
文件 1 的 25:AddressHelper.sol
pragma solidity 0.8.19;
error NonContractAddressError(address account);
function isContract(address _account) view returns (bool) {
return _account.code.length > 0;
}
function requireContract(address _account) view {
if (!isContract(_account)) {
revert NonContractAddressError(_account);
}
}
function requireContractOrZeroAddress(address _account) view {
if (_account != address(0)) {
requireContract(_account);
}
}
文件 2 的 25:AssetSpenderRole.sol
pragma solidity 0.8.19;
import { RoleBearers } from './RoleBearers.sol';
abstract contract AssetSpenderRole is RoleBearers {
bytes32 private constant ROLE_KEY = keccak256('AssetSpender');
event SetAssetSpender(address indexed account, bool indexed value);
error OnlyAssetSpenderError();
modifier onlyAssetSpender() {
if (!isAssetSpender(msg.sender)) {
revert OnlyAssetSpenderError();
}
_;
}
function assetSpenderCount() external view returns (uint256) {
return _roleBearerCount(ROLE_KEY);
}
function fullAssetSpenderList() external view returns (address[] memory) {
return _fullRoleBearerList(ROLE_KEY);
}
function isAssetSpender(address _account) public view returns (bool) {
return _isRoleBearer(ROLE_KEY, _account);
}
function _setAssetSpender(address _account, bool _value) internal {
_setRoleBearer(ROLE_KEY, _account, _value);
emit SetAssetSpender(_account, _value);
}
}
文件 3 的 25:BalanceManagement.sol
pragma solidity 0.8.19;
import { ITokenBalance } from './interfaces/ITokenBalance.sol';
import { ManagerRole } from './roles/ManagerRole.sol';
import './helpers/TransferHelper.sol' as TransferHelper;
import './Constants.sol' as Constants;
abstract contract BalanceManagement is ManagerRole {
error ReservedTokenError();
function cleanup(address _tokenAddress, uint256 _tokenAmount) external onlyManager {
if (isReservedToken(_tokenAddress)) {
revert ReservedTokenError();
}
if (_tokenAddress == Constants.NATIVE_TOKEN_ADDRESS) {
TransferHelper.safeTransferNative(msg.sender, _tokenAmount);
} else {
TransferHelper.safeTransfer(_tokenAddress, msg.sender, _tokenAmount);
}
}
function tokenBalance(address _tokenAddress) public view returns (uint256) {
if (_tokenAddress == Constants.NATIVE_TOKEN_ADDRESS) {
return address(this).balance;
} else {
return ITokenBalance(_tokenAddress).balanceOf(address(this));
}
}
function isReservedToken(address _tokenAddress) public view virtual returns (bool) {
}
}
文件 4 的 25:BurnerRole.sol
pragma solidity 0.8.19;
import { RoleBearers } from './RoleBearers.sol';
abstract contract BurnerRole is RoleBearers {
bytes32 private constant ROLE_KEY = keccak256('Burner');
event SetBurner(address indexed account, bool indexed value);
function burnerCount() external view returns (uint256) {
return _roleBearerCount(ROLE_KEY);
}
function fullBurnerList() external view returns (address[] memory) {
return _fullRoleBearerList(ROLE_KEY);
}
function isBurner(address _account) public view returns (bool) {
return _isRoleBearer(ROLE_KEY, _account);
}
function _setBurner(address _account, bool _value) internal {
_setRoleBearer(ROLE_KEY, _account, _value);
emit SetBurner(_account, _value);
}
}
文件 5 的 25:CallerGuard.sol
pragma solidity 0.8.19;
import { ManagerRole } from './roles/ManagerRole.sol';
import './helpers/AddressHelper.sol' as AddressHelper;
import './Constants.sol' as Constants;
import './DataStructures.sol' as DataStructures;
abstract contract CallerGuard is ManagerRole {
enum CallerGuardMode {
ContractForbidden,
ContractList,
ContractAllowed
}
CallerGuardMode public callerGuardMode = CallerGuardMode.ContractForbidden;
address[] public listedCallerGuardContractList;
mapping(address => DataStructures.OptionalValue )
public listedCallerGuardContractIndexMap;
event SetCallerGuardMode(CallerGuardMode indexed callerGuardMode);
event SetListedCallerGuardContract(address indexed contractAddress, bool indexed isListed);
error CallerGuardError(address caller);
modifier checkCaller() {
if (msg.sender != tx.origin) {
bool condition = (callerGuardMode == CallerGuardMode.ContractAllowed ||
(callerGuardMode == CallerGuardMode.ContractList &&
isListedCallerGuardContract(msg.sender)));
if (!condition) {
revert CallerGuardError(msg.sender);
}
}
_;
}
function setCallerGuardMode(CallerGuardMode _callerGuardMode) external onlyManager {
callerGuardMode = _callerGuardMode;
emit SetCallerGuardMode(_callerGuardMode);
}
function setListedCallerGuardContracts(
DataStructures.AccountToFlag[] calldata _items
) external onlyManager {
for (uint256 index; index < _items.length; index++) {
DataStructures.AccountToFlag calldata item = _items[index];
if (item.flag) {
AddressHelper.requireContract(item.account);
}
DataStructures.uniqueAddressListUpdate(
listedCallerGuardContractList,
listedCallerGuardContractIndexMap,
item.account,
item.flag,
Constants.LIST_SIZE_LIMIT_DEFAULT
);
emit SetListedCallerGuardContract(item.account, item.flag);
}
}
function listedCallerGuardContractCount() external view returns (uint256) {
return listedCallerGuardContractList.length;
}
function fullListedCallerGuardContractList() external view returns (address[] memory) {
return listedCallerGuardContractList;
}
function isListedCallerGuardContract(address _account) public view returns (bool) {
return listedCallerGuardContractIndexMap[_account].isSet;
}
}
文件 6 的 25:Constants.sol
pragma solidity 0.8.19;
uint256 constant DECIMALS_DEFAULT = 18;
uint256 constant INFINITY = type(uint256).max;
uint256 constant LIST_SIZE_LIMIT_DEFAULT = 100;
uint256 constant LIST_SIZE_LIMIT_ROUTERS = 200;
uint256 constant MILLIPERCENT_FACTOR = 100_000;
address constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
文件 7 的 25: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;
}
}
文件 8 的 25:DataStructures.sol
pragma solidity 0.8.19;
struct OptionalValue {
bool isSet;
uint256 value;
}
struct KeyToValue {
uint256 key;
uint256 value;
}
struct KeyToAddressValue {
uint256 key;
address value;
}
struct AccountToFlag {
address account;
bool flag;
}
error ListSizeLimitError();
function combinedMapSet(
mapping(uint256 => address) storage _map,
uint256[] storage _keyList,
mapping(uint256 => OptionalValue) storage _keyIndexMap,
uint256 _key,
address _value,
uint256 _sizeLimit
) returns (bool isNewKey) {
isNewKey = !_keyIndexMap[_key].isSet;
if (isNewKey) {
uniqueListAdd(_keyList, _keyIndexMap, _key, _sizeLimit);
}
_map[_key] = _value;
}
function combinedMapRemove(
mapping(uint256 => address) storage _map,
uint256[] storage _keyList,
mapping(uint256 => OptionalValue) storage _keyIndexMap,
uint256 _key
) returns (bool isChanged) {
isChanged = _keyIndexMap[_key].isSet;
if (isChanged) {
delete _map[_key];
uniqueListRemove(_keyList, _keyIndexMap, _key);
}
}
function uniqueListAdd(
uint256[] storage _list,
mapping(uint256 => OptionalValue) storage _indexMap,
uint256 _value,
uint256 _sizeLimit
) returns (bool isChanged) {
isChanged = !_indexMap[_value].isSet;
if (isChanged) {
if (_list.length >= _sizeLimit) {
revert ListSizeLimitError();
}
_indexMap[_value] = OptionalValue(true, _list.length);
_list.push(_value);
}
}
function uniqueListRemove(
uint256[] storage _list,
mapping(uint256 => OptionalValue) storage _indexMap,
uint256 _value
) returns (bool isChanged) {
OptionalValue storage indexItem = _indexMap[_value];
isChanged = indexItem.isSet;
if (isChanged) {
uint256 itemIndex = indexItem.value;
uint256 lastIndex = _list.length - 1;
if (itemIndex != lastIndex) {
uint256 lastValue = _list[lastIndex];
_list[itemIndex] = lastValue;
_indexMap[lastValue].value = itemIndex;
}
_list.pop();
delete _indexMap[_value];
}
}
function uniqueAddressListAdd(
address[] storage _list,
mapping(address => OptionalValue) storage _indexMap,
address _value,
uint256 _sizeLimit
) returns (bool isChanged) {
isChanged = !_indexMap[_value].isSet;
if (isChanged) {
if (_list.length >= _sizeLimit) {
revert ListSizeLimitError();
}
_indexMap[_value] = OptionalValue(true, _list.length);
_list.push(_value);
}
}
function uniqueAddressListRemove(
address[] storage _list,
mapping(address => OptionalValue) storage _indexMap,
address _value
) returns (bool isChanged) {
OptionalValue storage indexItem = _indexMap[_value];
isChanged = indexItem.isSet;
if (isChanged) {
uint256 itemIndex = indexItem.value;
uint256 lastIndex = _list.length - 1;
if (itemIndex != lastIndex) {
address lastValue = _list[lastIndex];
_list[itemIndex] = lastValue;
_indexMap[lastValue].value = itemIndex;
}
_list.pop();
delete _indexMap[_value];
}
}
function uniqueAddressListUpdate(
address[] storage _list,
mapping(address => OptionalValue) storage _indexMap,
address _value,
bool _flag,
uint256 _sizeLimit
) returns (bool isChanged) {
return
_flag
? uniqueAddressListAdd(_list, _indexMap, _value, _sizeLimit)
: uniqueAddressListRemove(_list, _indexMap, _value);
}
文件 9 的 25: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);
}
}
文件 10 的 25:Errors.sol
pragma solidity 0.8.19;
error TokenBurnError();
error TokenMintError();
error ZeroAddressError();
文件 11 的 25:ITokenBalance.sol
pragma solidity 0.8.19;
interface ITokenBalance {
function balanceOf(address _account) external view returns (uint256);
}
文件 12 的 25:ITokenBurn.sol
pragma solidity 0.8.19;
interface ITokenBurn {
function burn(address _from, uint256 _amount) external returns (bool);
}
文件 13 的 25:ITokenDecimals.sol
pragma solidity 0.8.19;
interface ITokenDecimals {
function decimals() external pure returns (uint8);
}
文件 14 的 25:ManagerRole.sol
pragma solidity 0.8.19;
import { Ownable } from '@openzeppelin/contracts/access/Ownable.sol';
import { RoleBearers } from './RoleBearers.sol';
abstract contract ManagerRole is Ownable, RoleBearers {
bytes32 private constant ROLE_KEY = keccak256('Manager');
event SetManager(address indexed account, bool indexed value);
event RenounceManagerRole(address indexed account);
error OnlyManagerError();
modifier onlyManager() {
if (!isManager(msg.sender)) {
revert OnlyManagerError();
}
_;
}
function setManager(address _account, bool _value) public onlyOwner {
_setRoleBearer(ROLE_KEY, _account, _value);
emit SetManager(_account, _value);
}
function renounceManagerRole() external onlyManager {
_setRoleBearer(ROLE_KEY, msg.sender, false);
emit RenounceManagerRole(msg.sender);
}
function managerCount() external view returns (uint256) {
return _roleBearerCount(ROLE_KEY);
}
function fullManagerList() external view returns (address[] memory) {
return _fullRoleBearerList(ROLE_KEY);
}
function isManager(address _account) public view returns (bool) {
return _isRoleBearer(ROLE_KEY, _account);
}
function _initRoles(
address _owner,
address[] memory _managers,
bool _addOwnerToManagers
) internal {
address ownerAddress = _owner == address(0) ? msg.sender : _owner;
for (uint256 index; index < _managers.length; index++) {
setManager(_managers[index], true);
}
if (_addOwnerToManagers && !isManager(ownerAddress)) {
setManager(ownerAddress, true);
}
if (ownerAddress != msg.sender) {
transferOwnership(ownerAddress);
}
}
}
文件 15 的 25:MinterRole.sol
pragma solidity 0.8.19;
import { RoleBearers } from './RoleBearers.sol';
abstract contract MinterRole is RoleBearers {
bytes32 private constant ROLE_KEY = keccak256('Minter');
event SetMinter(address indexed account, bool indexed value);
function minterCount() external view returns (uint256) {
return _roleBearerCount(ROLE_KEY);
}
function fullMinterList() external view returns (address[] memory) {
return _fullRoleBearerList(ROLE_KEY);
}
function isMinter(address _account) public view returns (bool) {
return _isRoleBearer(ROLE_KEY, _account);
}
function _setMinter(address _account, bool _value) internal {
_setRoleBearer(ROLE_KEY, _account, _value);
emit SetMinter(_account, _value);
}
}
文件 16 的 25:MultichainRouterRole.sol
pragma solidity 0.8.19;
import { RoleBearers } from './RoleBearers.sol';
abstract contract MultichainRouterRole is RoleBearers {
bytes32 private constant ROLE_KEY = keccak256('MultichainRouter');
event SetMultichainRouter(address indexed account, bool indexed value);
function multichainRouterCount() external view returns (uint256) {
return _roleBearerCount(ROLE_KEY);
}
function fullMultichainRouterList() external view returns (address[] memory) {
return _fullRoleBearerList(ROLE_KEY);
}
function isMultichainRouter(address _account) public view returns (bool) {
return _isRoleBearer(ROLE_KEY, _account);
}
function _setMultichainRouter(address _account, bool _value) internal {
_setRoleBearer(ROLE_KEY, _account, _value);
emit SetMultichainRouter(_account, _value);
}
}
文件 17 的 25:MultichainTokenBase.sol
pragma solidity 0.8.19;
import { ERC20 } from 'solmate/src/tokens/ERC20.sol';
import { BurnerRole } from './roles/BurnerRole.sol';
import { MinterRole } from './roles/MinterRole.sol';
import { MultichainRouterRole } from './roles/MultichainRouterRole.sol';
import { Pausable } from './Pausable.sol';
import { ZeroAddressError } from './Errors.sol';
import './Constants.sol' as Constants;
abstract contract MultichainTokenBase is Pausable, ERC20, MultichainRouterRole {
address public immutable underlying;
bool private immutable useExplicitAccess;
error BurnAccessError();
error BurnAllowanceError();
error MintAccessError();
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals,
bool _useExplicitAccess
) ERC20(_name, _symbol, _decimals) {
underlying = address(0);
useExplicitAccess = _useExplicitAccess;
}
function setMultichainRouter(address _account, bool _value) external onlyManager {
_setMultichainRouter(_account, _value);
}
function mint(address _to, uint256 _amount) external whenNotPaused returns (bool) {
bool condition = isMultichainRouter(msg.sender) ||
(useExplicitAccess && _isExplicitMinter());
if (!condition) {
revert MintAccessError();
}
_mint(_to, _amount);
return true;
}
function burn(address _from, uint256 _amount) external whenNotPaused returns (bool) {
bool condition = isMultichainRouter(msg.sender) ||
(useExplicitAccess && _isExplicitBurner());
if (!condition) {
revert BurnAccessError();
}
if (_from == address(0)) {
revert ZeroAddressError();
}
uint256 allowed = allowance[_from][msg.sender];
if (allowed < _amount) {
revert BurnAllowanceError();
}
if (allowed != Constants.INFINITY) {
unchecked {
allowance[_from][msg.sender] = allowed - _amount;
}
}
_burn(_from, _amount);
return true;
}
function _isExplicitMinter() internal view virtual returns (bool) {
return false;
}
function _isExplicitBurner() internal view virtual returns (bool) {
return false;
}
}
文件 18 的 25:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 19 的 25: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());
}
}
文件 20 的 25: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() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
}
function _nonReentrantAfter() private {
_status = _NOT_ENTERED;
}
}
文件 21 的 25:RoleBearers.sol
pragma solidity 0.8.19;
import '../Constants.sol' as Constants;
import '../DataStructures.sol' as DataStructures;
abstract contract RoleBearers {
mapping(bytes32 => address[] ) private roleBearerTable;
mapping(bytes32 => mapping(address => DataStructures.OptionalValue ))
private roleBearerIndexTable;
function _setRoleBearer(bytes32 _roleKey, address _account, bool _value) internal {
DataStructures.uniqueAddressListUpdate(
roleBearerTable[_roleKey],
roleBearerIndexTable[_roleKey],
_account,
_value,
Constants.LIST_SIZE_LIMIT_DEFAULT
);
}
function _isRoleBearer(bytes32 _roleKey, address _account) internal view returns (bool) {
return roleBearerIndexTable[_roleKey][_account].isSet;
}
function _roleBearerCount(bytes32 _roleKey) internal view returns (uint256) {
return roleBearerTable[_roleKey].length;
}
function _fullRoleBearerList(bytes32 _roleKey) internal view returns (address[] memory) {
return roleBearerTable[_roleKey];
}
}
文件 22 的 25:SystemVersionId.sol
pragma solidity 0.8.19;
abstract contract SystemVersionId {
uint256 public constant SYSTEM_VERSION_ID = uint256(keccak256('Initial'));
}
文件 23 的 25:TransferHelper.sol
pragma solidity 0.8.19;
error SafeApproveError();
error SafeTransferError();
error SafeTransferFromError();
error SafeTransferNativeError();
function safeApprove(address _token, address _to, uint256 _value) {
(bool success, bytes memory data) = _token.call(
abi.encodeWithSelector(0x095ea7b3, _to, _value)
);
bool condition = success && (data.length == 0 || abi.decode(data, (bool)));
if (!condition) {
revert SafeApproveError();
}
}
function safeTransfer(address _token, address _to, uint256 _value) {
(bool success, bytes memory data) = _token.call(
abi.encodeWithSelector(0xa9059cbb, _to, _value)
);
bool condition = success && (data.length == 0 || abi.decode(data, (bool)));
if (!condition) {
revert SafeTransferError();
}
}
function safeTransferFrom(address _token, address _from, address _to, uint256 _value) {
(bool success, bytes memory data) = _token.call(
abi.encodeWithSelector(0x23b872dd, _from, _to, _value)
);
bool condition = success && (data.length == 0 || abi.decode(data, (bool)));
if (!condition) {
revert SafeTransferFromError();
}
}
function safeTransferNative(address _to, uint256 _value) {
(bool success, ) = _to.call{ value: _value }(new bytes(0));
if (!success) {
revert SafeTransferNativeError();
}
}
文件 24 的 25:Vault.sol
pragma solidity 0.8.19;
import { ITokenBurn } from './interfaces/ITokenBurn.sol';
import { ITokenDecimals } from './interfaces/ITokenDecimals.sol';
import { AssetSpenderRole } from './roles/AssetSpenderRole.sol';
import { BalanceManagement } from './BalanceManagement.sol';
import { SystemVersionId } from './SystemVersionId.sol';
import { VaultBase } from './VaultBase.sol';
import { TokenBurnError } from './Errors.sol';
import './helpers/AddressHelper.sol' as AddressHelper;
import './helpers/TransferHelper.sol' as TransferHelper;
contract Vault is SystemVersionId, VaultBase, AssetSpenderRole, BalanceManagement {
address public variableToken;
bool public variableRepaymentEnabled;
event SetVariableRepaymentEnabled(bool indexed variableRepaymentEnabled);
event SetVariableToken(address indexed variableToken);
event RedeemVariableToken(address indexed caller, uint256 amount);
error TokenDecimalsError();
error VariableRepaymentNotEnabledError();
error VariableTokenAlreadySetError();
error VariableTokenNotSetError();
constructor(
address _asset,
string memory _name,
string memory _symbol,
address[] memory _assetSpenders,
bool _depositAllowed,
bool _variableRepaymentEnabled,
address _owner,
address[] memory _managers,
bool _addOwnerToManagers
) VaultBase(_asset, _name, _symbol, _depositAllowed) {
for (uint256 index; index < _assetSpenders.length; index++) {
_setAssetSpender(_assetSpenders[index], true);
}
_setVariableRepaymentEnabled(_variableRepaymentEnabled);
_initRoles(_owner, _managers, _addOwnerToManagers);
}
function setAssetSpender(address _account, bool _value) external onlyManager {
_setAssetSpender(_account, _value);
}
function setVariableToken(address _variableToken) external onlyManager {
if (variableToken != address(0)) {
revert VariableTokenAlreadySetError();
}
AddressHelper.requireContract(_variableToken);
if (ITokenDecimals(_variableToken).decimals() != decimals) {
revert TokenDecimalsError();
}
variableToken = _variableToken;
emit SetVariableToken(_variableToken);
}
function setVariableRepaymentEnabled(bool _variableRepaymentEnabled) external onlyManager {
_setVariableRepaymentEnabled(_variableRepaymentEnabled);
}
function requestAsset(
uint256 _amount,
address _to,
bool _forVariableBalance
) external whenNotPaused onlyAssetSpender returns (address assetAddress) {
if (_forVariableBalance && !variableRepaymentEnabled) {
revert VariableRepaymentNotEnabledError();
}
TransferHelper.safeTransfer(asset, _to, _amount);
return asset;
}
function redeemVariableToken(uint256 _amount) external whenNotPaused nonReentrant checkCaller {
checkVariableTokenState();
bool burnSuccess = ITokenBurn(variableToken).burn(msg.sender, _amount);
if (!burnSuccess) {
revert TokenBurnError();
}
emit RedeemVariableToken(msg.sender, _amount);
TransferHelper.safeTransfer(asset, msg.sender, _amount);
}
function checkVariableTokenState() public view returns (address) {
if (!variableRepaymentEnabled) {
revert VariableRepaymentNotEnabledError();
}
if (variableToken == address(0)) {
revert VariableTokenNotSetError();
}
return variableToken;
}
function isReservedToken(address _tokenAddress) public view override returns (bool) {
return _tokenAddress == asset;
}
function _setVariableRepaymentEnabled(bool _variableRepaymentEnabled) private {
variableRepaymentEnabled = _variableRepaymentEnabled;
emit SetVariableRepaymentEnabled(_variableRepaymentEnabled);
}
}
文件 25 的 25:VaultBase.sol
pragma solidity 0.8.19;
import { ERC20 } from 'solmate/src/tokens/ERC20.sol';
import { ReentrancyGuard } from '@openzeppelin/contracts/security/ReentrancyGuard.sol';
import { ITokenDecimals } from './interfaces/ITokenDecimals.sol';
import { CallerGuard } from './CallerGuard.sol';
import { MultichainTokenBase } from './MultichainTokenBase.sol';
import './helpers/TransferHelper.sol' as TransferHelper;
import './Constants.sol' as Constants;
abstract contract VaultBase is MultichainTokenBase, ReentrancyGuard, CallerGuard {
address public immutable asset;
uint256 public totalSupplyLimit;
event SetTotalSupplyLimit(uint256 limit);
event Deposit(address indexed caller, uint256 assetAmount);
event Withdraw(address indexed caller, uint256 assetAmount);
error TotalSupplyLimitError();
error ZeroAmountError();
constructor(
address _asset,
string memory _name,
string memory _symbol,
bool _depositAllowed
) MultichainTokenBase(_name, _symbol, ITokenDecimals(_asset).decimals(), false) {
asset = _asset;
_setTotalSupplyLimit(_depositAllowed ? Constants.INFINITY : 0);
}
function setTotalSupplyLimit(uint256 _limit) external onlyManager {
_setTotalSupplyLimit(_limit);
}
function deposit(uint256 _assetAmount) external virtual whenNotPaused nonReentrant checkCaller {
if (_assetAmount == 0) {
revert ZeroAmountError();
}
if (totalSupply + _assetAmount > totalSupplyLimit) {
revert TotalSupplyLimitError();
}
TransferHelper.safeTransferFrom(asset, msg.sender, address(this), _assetAmount);
_mint(msg.sender, _assetAmount);
emit Deposit(msg.sender, _assetAmount);
}
function withdraw(
uint256 _assetAmount
) external virtual whenNotPaused nonReentrant checkCaller {
_burn(msg.sender, _assetAmount);
emit Withdraw(msg.sender, _assetAmount);
TransferHelper.safeTransfer(asset, msg.sender, _assetAmount);
}
function _setTotalSupplyLimit(uint256 _limit) private {
totalSupplyLimit = _limit;
emit SetTotalSupplyLimit(_limit);
}
}
{
"compilationTarget": {
"contracts/Vault.sol": "Vault"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"address[]","name":"_assetSpenders","type":"address[]"},{"internalType":"bool","name":"_depositAllowed","type":"bool"},{"internalType":"bool","name":"_variableRepaymentEnabled","type":"bool"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address[]","name":"_managers","type":"address[]"},{"internalType":"bool","name":"_addOwnerToManagers","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BurnAccessError","type":"error"},{"inputs":[],"name":"BurnAllowanceError","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerGuardError","type":"error"},{"inputs":[],"name":"ListSizeLimitError","type":"error"},{"inputs":[],"name":"MintAccessError","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NonContractAddressError","type":"error"},{"inputs":[],"name":"OnlyAssetSpenderError","type":"error"},{"inputs":[],"name":"OnlyManagerError","type":"error"},{"inputs":[],"name":"ReservedTokenError","type":"error"},{"inputs":[],"name":"SafeTransferError","type":"error"},{"inputs":[],"name":"SafeTransferFromError","type":"error"},{"inputs":[],"name":"SafeTransferNativeError","type":"error"},{"inputs":[],"name":"TokenBurnError","type":"error"},{"inputs":[],"name":"TokenDecimalsError","type":"error"},{"inputs":[],"name":"TotalSupplyLimitError","type":"error"},{"inputs":[],"name":"VariableRepaymentNotEnabledError","type":"error"},{"inputs":[],"name":"VariableTokenAlreadySetError","type":"error"},{"inputs":[],"name":"VariableTokenNotSetError","type":"error"},{"inputs":[],"name":"ZeroAddressError","type":"error"},{"inputs":[],"name":"ZeroAmountError","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"assetAmount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RedeemVariableToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"RenounceManagerRole","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"bool","name":"value","type":"bool"}],"name":"SetAssetSpender","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum CallerGuard.CallerGuardMode","name":"callerGuardMode","type":"uint8"}],"name":"SetCallerGuardMode","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":true,"internalType":"bool","name":"isListed","type":"bool"}],"name":"SetListedCallerGuardContract","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"bool","name":"value","type":"bool"}],"name":"SetManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"bool","name":"value","type":"bool"}],"name":"SetMultichainRouter","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"limit","type":"uint256"}],"name":"SetTotalSupplyLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bool","name":"variableRepaymentEnabled","type":"bool"}],"name":"SetVariableRepaymentEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"variableToken","type":"address"}],"name":"SetVariableToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"assetAmount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SYSTEM_VERSION_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetSpenderCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"callerGuardMode","outputs":[{"internalType":"enum CallerGuard.CallerGuardMode","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"checkVariableTokenState","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"cleanup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetAmount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fullAssetSpenderList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fullListedCallerGuardContractList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fullManagerList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fullMultichainRouterList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isAssetSpender","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isListedCallerGuardContract","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isMultichainRouter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"isReservedToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"listedCallerGuardContractCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"listedCallerGuardContractIndexMap","outputs":[{"internalType":"bool","name":"isSet","type":"bool"},{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"listedCallerGuardContractList","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"managerCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"multichainRouterCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","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":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"redeemVariableToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceManagerRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"bool","name":"_forVariableBalance","type":"bool"}],"name":"requestAsset","outputs":[{"internalType":"address","name":"assetAddress","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"bool","name":"_value","type":"bool"}],"name":"setAssetSpender","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum CallerGuard.CallerGuardMode","name":"_callerGuardMode","type":"uint8"}],"name":"setCallerGuardMode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"flag","type":"bool"}],"internalType":"struct AccountToFlag[]","name":"_items","type":"tuple[]"}],"name":"setListedCallerGuardContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"bool","name":"_value","type":"bool"}],"name":"setManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"bool","name":"_value","type":"bool"}],"name":"setMultichainRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"setTotalSupplyLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_variableRepaymentEnabled","type":"bool"}],"name":"setVariableRepaymentEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_variableToken","type":"address"}],"name":"setVariableToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"tokenBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupplyLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"variableRepaymentEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"variableToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetAmount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]