// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;/**
* @notice Emitted when the account is not a contract
* @param account The account address
*/errorNonContractAddressError(address account);
/**
* @notice Function to check if the account is a contract
* @return The account contract status flag
*/functionisContract(address _account) viewreturns (bool) {
return _account.code.length>0;
}
/**
* @notice Function to require an account to be a contract
*/functionrequireContract(address _account) view{
if (!isContract(_account)) {
revert NonContractAddressError(_account);
}
}
/**
* @notice Function to require an account to be a contract or a zero address
*/functionrequireContractOrZeroAddress(address _account) view{
if (_account !=address(0)) {
requireContract(_account);
}
}
Contract Source Code
File 2 of 25: AssetSpenderRole.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;import { RoleBearers } from'./RoleBearers.sol';
/**
* @title AssetSpenderRole
* @notice Base contract that implements the Asset Spender role
*/abstractcontractAssetSpenderRoleisRoleBearers{
bytes32privateconstant ROLE_KEY =keccak256('AssetSpender');
/**
* @notice Emitted when the Asset Spender role status for the account is updated
* @param account The account address
* @param value The Asset Spender role status flag
*/eventSetAssetSpender(addressindexed account, boolindexed value);
/**
* @notice Emitted when the caller is not an Asset Spender role bearer
*/errorOnlyAssetSpenderError();
/**
* @dev Modifier to check if the caller is an Asset Spender role bearer
*/modifieronlyAssetSpender() {
if (!isAssetSpender(msg.sender)) {
revert OnlyAssetSpenderError();
}
_;
}
/**
* @notice Getter of the Asset Spender role bearer count
* @return The Asset Spender role bearer count
*/functionassetSpenderCount() externalviewreturns (uint256) {
return _roleBearerCount(ROLE_KEY);
}
/**
* @notice Getter of the complete list of the Asset Spender role bearers
* @return The complete list of the Asset Spender role bearers
*/functionfullAssetSpenderList() externalviewreturns (address[] memory) {
return _fullRoleBearerList(ROLE_KEY);
}
/**
* @notice Getter of the Asset Spender role bearer status
* @param _account The account address
*/functionisAssetSpender(address _account) publicviewreturns (bool) {
return _isRoleBearer(ROLE_KEY, _account);
}
function_setAssetSpender(address _account, bool _value) internal{
_setRoleBearer(ROLE_KEY, _account, _value);
emit SetAssetSpender(_account, _value);
}
}
Contract Source Code
File 3 of 25: BalanceManagement.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;import { ITokenBalance } from'./interfaces/ITokenBalance.sol';
import { ManagerRole } from'./roles/ManagerRole.sol';
import'./helpers/TransferHelper.sol'asTransferHelper;
import'./Constants.sol'asConstants;
/**
* @title BalanceManagement
* @notice Base contract for the withdrawal of tokens, except for reserved ones
*/abstractcontractBalanceManagementisManagerRole{
/**
* @notice Emitted when the specified token is reserved
*/errorReservedTokenError();
/**
* @notice Performs the withdrawal of tokens, except for reserved ones
* @dev Use the "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" address for the native token
* @param _tokenAddress The address of the token
* @param _tokenAmount The amount of the token
*/functioncleanup(address _tokenAddress, uint256 _tokenAmount) externalonlyManager{
if (isReservedToken(_tokenAddress)) {
revert ReservedTokenError();
}
if (_tokenAddress == Constants.NATIVE_TOKEN_ADDRESS) {
TransferHelper.safeTransferNative(msg.sender, _tokenAmount);
} else {
TransferHelper.safeTransfer(_tokenAddress, msg.sender, _tokenAmount);
}
}
/**
* @notice Getter of the token balance of the current contract
* @dev Use the "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" address for the native token
* @param _tokenAddress The address of the token
* @return The token balance of the current contract
*/functiontokenBalance(address _tokenAddress) publicviewreturns (uint256) {
if (_tokenAddress == Constants.NATIVE_TOKEN_ADDRESS) {
returnaddress(this).balance;
} else {
return ITokenBalance(_tokenAddress).balanceOf(address(this));
}
}
/**
* @notice Getter of the reserved token flag
* @dev Override to add reserved token addresses
* @param _tokenAddress The address of the token
* @return The reserved token flag
*/functionisReservedToken(address _tokenAddress) publicviewvirtualreturns (bool) {
// The function returns false by default.// The explicit return statement is omitted to avoid the unused parameter warning.// See https://github.com/ethereum/solidity/issues/5295
}
}
Contract Source Code
File 4 of 25: BurnerRole.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;import { RoleBearers } from'./RoleBearers.sol';
/**
* @title BurnerRole
* @notice Base contract that implements the Burner role
*/abstractcontractBurnerRoleisRoleBearers{
bytes32privateconstant ROLE_KEY =keccak256('Burner');
/**
* @notice Emitted when the Burner role status for the account is updated
* @param account The account address
* @param value The Burner role status flag
*/eventSetBurner(addressindexed account, boolindexed value);
/**
* @notice Getter of the Burner role bearer count
* @return The Burner role bearer count
*/functionburnerCount() externalviewreturns (uint256) {
return _roleBearerCount(ROLE_KEY);
}
/**
* @notice Getter of the complete list of the Burner role bearers
* @return The complete list of the Burner role bearers
*/functionfullBurnerList() externalviewreturns (address[] memory) {
return _fullRoleBearerList(ROLE_KEY);
}
/**
* @notice Getter of the Burner role bearer status
* @param _account The account address
*/functionisBurner(address _account) publicviewreturns (bool) {
return _isRoleBearer(ROLE_KEY, _account);
}
function_setBurner(address _account, bool _value) internal{
_setRoleBearer(ROLE_KEY, _account, _value);
emit SetBurner(_account, _value);
}
}
Contract Source Code
File 5 of 25: CallerGuard.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;import { ManagerRole } from'./roles/ManagerRole.sol';
import'./helpers/AddressHelper.sol'asAddressHelper;
import'./Constants.sol'asConstants;
import'./DataStructures.sol'asDataStructures;
/**
* @title CallerGuard
* @notice Base contract to control access from other contracts
*/abstractcontractCallerGuardisManagerRole{
/**
* @dev Caller guard mode enumeration
*/enumCallerGuardMode {
ContractForbidden,
ContractList,
ContractAllowed
}
/**
* @dev Caller guard mode value
*/
CallerGuardMode public callerGuardMode = CallerGuardMode.ContractForbidden;
/**
* @dev Registered contract list for "ContractList" mode
*/address[] public listedCallerGuardContractList;
/**
* @dev Registered contract list indices for "ContractList" mode
*/mapping(address/*account*/=> DataStructures.OptionalValue /*index*/)
public listedCallerGuardContractIndexMap;
/**
* @notice Emitted when the caller guard mode is set
* @param callerGuardMode The caller guard mode
*/eventSetCallerGuardMode(CallerGuardMode indexed callerGuardMode);
/**
* @notice Emitted when a registered contract for "ContractList" mode is added or removed
* @param contractAddress The contract address
* @param isListed The registered contract list inclusion flag
*/eventSetListedCallerGuardContract(addressindexed contractAddress, boolindexed isListed);
/**
* @notice Emitted when the caller is not allowed to perform the intended action
*/errorCallerGuardError(address caller);
/**
* @dev Modifier to check if the caller is allowed to perform the intended action
*/modifiercheckCaller() {
if (msg.sender!=tx.origin) {
bool condition = (callerGuardMode == CallerGuardMode.ContractAllowed ||
(callerGuardMode == CallerGuardMode.ContractList &&
isListedCallerGuardContract(msg.sender)));
if (!condition) {
revert CallerGuardError(msg.sender);
}
}
_;
}
/**
* @notice Sets the caller guard mode
* @param _callerGuardMode The caller guard mode
*/functionsetCallerGuardMode(CallerGuardMode _callerGuardMode) externalonlyManager{
callerGuardMode = _callerGuardMode;
emit SetCallerGuardMode(_callerGuardMode);
}
/**
* @notice Updates the list of registered contracts for the "ContractList" mode
* @param _items The addresses and flags for the contracts
*/functionsetListedCallerGuardContracts(
DataStructures.AccountToFlag[] calldata _items
) externalonlyManager{
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);
}
}
/**
* @notice Getter of the registered contract count
* @return The registered contract count
*/functionlistedCallerGuardContractCount() externalviewreturns (uint256) {
return listedCallerGuardContractList.length;
}
/**
* @notice Getter of the complete list of registered contracts
* @return The complete list of registered contracts
*/functionfullListedCallerGuardContractList() externalviewreturns (address[] memory) {
return listedCallerGuardContractList;
}
/**
* @notice Getter of a listed contract flag
* @param _account The contract address
* @return The listed contract flag
*/functionisListedCallerGuardContract(address _account) publicviewreturns (bool) {
return listedCallerGuardContractIndexMap[_account].isSet;
}
}
Contract Source Code
File 6 of 25: Constants.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;/**
* @dev The default token decimals value
*/uint256constant DECIMALS_DEFAULT =18;
/**
* @dev The maximum uint256 value for swap amount limit settings
*/uint256constant INFINITY =type(uint256).max;
/**
* @dev The default limit of account list size
*/uint256constant LIST_SIZE_LIMIT_DEFAULT =100;
/**
* @dev The limit of swap router list size
*/uint256constant LIST_SIZE_LIMIT_ROUTERS =200;
/**
* @dev The factor for percentage settings. Example: 100 is 0.1%
*/uint256constant MILLIPERCENT_FACTOR =100_000;
/**
* @dev The de facto standard address to denote the native token
*/addressconstant NATIVE_TOKEN_ADDRESS =0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
Contract Source Code
File 7 of 25: Context.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)pragmasolidity ^0.8.0;/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
returnmsg.data;
}
}
Contract Source Code
File 8 of 25: DataStructures.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;/**
* @notice Optional value structure
* @dev Is used in mappings to allow zero values
* @param isSet Value presence flag
* @param value Numeric value
*/structOptionalValue {
bool isSet;
uint256 value;
}
/**
* @notice Key-to-value structure
* @dev Is used as an array parameter item to perform multiple key-value settings
* @param key Numeric key
* @param value Numeric value
*/structKeyToValue {
uint256 key;
uint256 value;
}
/**
* @notice Key-to-value structure for address values
* @dev Is used as an array parameter item to perform multiple key-value settings with address values
* @param key Numeric key
* @param value Address value
*/structKeyToAddressValue {
uint256 key;
address value;
}
/**
* @notice Address-to-flag structure
* @dev Is used as an array parameter item to perform multiple settings
* @param account Account address
* @param flag Flag value
*/structAccountToFlag {
address account;
bool flag;
}
/**
* @notice Emitted when a list exceeds the size limit
*/errorListSizeLimitError();
/**
* @notice Sets or updates a value in a combined map (a mapping with a key list and key index mapping)
* @param _map The mapping reference
* @param _keyList The key list reference
* @param _keyIndexMap The key list index mapping reference
* @param _key The numeric key
* @param _value The address value
* @param _sizeLimit The map and list size limit
* @return isNewKey True if the key was just added, otherwise false
*/functioncombinedMapSet(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;
}
/**
* @notice Removes a value from a combined map (a mapping with a key list and key index mapping)
* @param _map The mapping reference
* @param _keyList The key list reference
* @param _keyIndexMap The key list index mapping reference
* @param _key The numeric key
* @return isChanged True if the combined map was changed, otherwise false
*/functioncombinedMapRemove(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);
}
}
/**
* @notice Adds a value to a unique value list (a list with value index mapping)
* @param _list The list reference
* @param _indexMap The value index mapping reference
* @param _value The numeric value
* @param _sizeLimit The list size limit
* @return isChanged True if the list was changed, otherwise false
*/functionuniqueListAdd(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);
}
}
/**
* @notice Removes a value from a unique value list (a list with value index mapping)
* @param _list The list reference
* @param _indexMap The value index mapping reference
* @param _value The numeric value
* @return isChanged True if the list was changed, otherwise false
*/functionuniqueListRemove(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];
}
}
/**
* @notice Adds a value to a unique address value list (a list with value index mapping)
* @param _list The list reference
* @param _indexMap The value index mapping reference
* @param _value The address value
* @param _sizeLimit The list size limit
* @return isChanged True if the list was changed, otherwise false
*/functionuniqueAddressListAdd(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);
}
}
/**
* @notice Removes a value from a unique address value list (a list with value index mapping)
* @param _list The list reference
* @param _indexMap The value index mapping reference
* @param _value The address value
* @return isChanged True if the list was changed, otherwise false
*/functionuniqueAddressListRemove(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];
}
}
/**
* @notice Adds or removes a value to/from a unique address value list (a list with value index mapping)
* @dev The list size limit is checked on items adding only
* @param _list The list reference
* @param _indexMap The value index mapping reference
* @param _value The address value
* @param _flag The value inclusion flag
* @param _sizeLimit The list size limit
* @return isChanged True if the list was changed, otherwise false
*/functionuniqueAddressListUpdate(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);
}
Contract Source Code
File 9 of 25: ERC20.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity >=0.8.0;/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation./// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.abstractcontractERC20{
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/eventTransfer(addressindexedfrom, addressindexed to, uint256 amount);
eventApproval(addressindexed owner, addressindexed spender, uint256 amount);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/stringpublic name;
stringpublic symbol;
uint8publicimmutable decimals;
/*//////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/uint256public totalSupply;
mapping(address=>uint256) public balanceOf;
mapping(address=>mapping(address=>uint256)) public allowance;
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/uint256internalimmutable INITIAL_CHAIN_ID;
bytes32internalimmutable INITIAL_DOMAIN_SEPARATOR;
mapping(address=>uint256) public nonces;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/constructor(stringmemory _name,
stringmemory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID =block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/*//////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/functionapprove(address spender, uint256 amount) publicvirtualreturns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
returntrue;
}
functiontransfer(address to, uint256 amount) publicvirtualreturns (bool) {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user// balances can't exceed the max uint256 value.unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
returntrue;
}
functiontransferFrom(addressfrom,
address to,
uint256 amount
) publicvirtualreturns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.if (allowed !=type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user// balances can't exceed the max uint256 value.unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
returntrue;
}
/*//////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/functionpermit(address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) publicvirtual{
require(deadline >=block.timestamp, "PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing// the owner's nonce which cannot realistically overflow.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);
}
functionDOMAIN_SEPARATOR() publicviewvirtualreturns (bytes32) {
returnblock.chainid== INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
functioncomputeDomainSeparator() internalviewvirtualreturns (bytes32) {
returnkeccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/function_mint(address to, uint256 amount) internalvirtual{
totalSupply += amount;
// Cannot overflow because the sum of all user// balances can't exceed the max uint256 value.unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function_burn(addressfrom, uint256 amount) internalvirtual{
balanceOf[from] -= amount;
// Cannot underflow because a user's balance// will never be larger than the total supply.unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}
Contract Source Code
File 10 of 25: Errors.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;/**
* @notice Emitted when an attempt to burn a token fails
*/errorTokenBurnError();
/**
* @notice Emitted when an attempt to mint a token fails
*/errorTokenMintError();
/**
* @notice Emitted when a zero address is specified where it is not allowed
*/errorZeroAddressError();
Contract Source Code
File 11 of 25: ITokenBalance.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;/**
* @title ITokenBalance
* @notice Token balance interface
*/interfaceITokenBalance{
/**
* @notice Getter of the token balance by the account
* @param _account The account address
* @return Token balance
*/functionbalanceOf(address _account) externalviewreturns (uint256);
}
Contract Source Code
File 12 of 25: ITokenBurn.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;/**
* @title ITokenBurn
* @notice Token burning interface
*/interfaceITokenBurn{
/**
* @notice Burns tokens from the account, reducing the total supply
* @param _from The token holder account address
* @param _amount The number of tokens to burn
* @return Token burning success status
*/functionburn(address _from, uint256 _amount) externalreturns (bool);
}
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;import { Ownable } from'@openzeppelin/contracts/access/Ownable.sol';
import { RoleBearers } from'./RoleBearers.sol';
/**
* @title ManagerRole
* @notice Base contract that implements the Manager role.
* The manager role is a high-permission role for core team members only.
* Managers can set vaults and routers addresses, fees, cross-chain protocols,
* and other parameters for Interchain (cross-chain) swaps and single-network swaps.
* Please note, the manager role is unique for every contract,
* hence different addresses may be assigned as managers for different contracts.
*/abstractcontractManagerRoleisOwnable, RoleBearers{
bytes32privateconstant ROLE_KEY =keccak256('Manager');
/**
* @notice Emitted when the Manager role status for the account is updated
* @param account The account address
* @param value The Manager role status flag
*/eventSetManager(addressindexed account, boolindexed value);
/**
* @notice Emitted when the Manager role status for the account is renounced
* @param account The account address
*/eventRenounceManagerRole(addressindexed account);
/**
* @notice Emitted when the caller is not a Manager role bearer
*/errorOnlyManagerError();
/**
* @dev Modifier to check if the caller is a Manager role bearer
*/modifieronlyManager() {
if (!isManager(msg.sender)) {
revert OnlyManagerError();
}
_;
}
/**
* @notice Updates the Manager role status for the account
* @param _account The account address
* @param _value The Manager role status flag
*/functionsetManager(address _account, bool _value) publiconlyOwner{
_setRoleBearer(ROLE_KEY, _account, _value);
emit SetManager(_account, _value);
}
/**
* @notice Renounces the Manager role
*/functionrenounceManagerRole() externalonlyManager{
_setRoleBearer(ROLE_KEY, msg.sender, false);
emit RenounceManagerRole(msg.sender);
}
/**
* @notice Getter of the Manager role bearer count
* @return The Manager role bearer count
*/functionmanagerCount() externalviewreturns (uint256) {
return _roleBearerCount(ROLE_KEY);
}
/**
* @notice Getter of the complete list of the Manager role bearers
* @return The complete list of the Manager role bearers
*/functionfullManagerList() externalviewreturns (address[] memory) {
return _fullRoleBearerList(ROLE_KEY);
}
/**
* @notice Getter of the Manager role bearer status
* @param _account The account address
*/functionisManager(address _account) publicviewreturns (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);
}
}
}
Contract Source Code
File 15 of 25: MinterRole.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;import { RoleBearers } from'./RoleBearers.sol';
/**
* @title MinterRole
* @notice Base contract that implements the Minter role
*/abstractcontractMinterRoleisRoleBearers{
bytes32privateconstant ROLE_KEY =keccak256('Minter');
/**
* @notice Emitted when the Minter role status for the account is updated
* @param account The account address
* @param value The Minter role status flag
*/eventSetMinter(addressindexed account, boolindexed value);
/**
* @notice Getter of the Minter role bearer count
* @return The Minter role bearer count
*/functionminterCount() externalviewreturns (uint256) {
return _roleBearerCount(ROLE_KEY);
}
/**
* @notice Getter of the complete list of the Minter role bearers
* @return The complete list of the Minter role bearers
*/functionfullMinterList() externalviewreturns (address[] memory) {
return _fullRoleBearerList(ROLE_KEY);
}
/**
* @notice Getter of the Minter role bearer status
* @param _account The account address
*/functionisMinter(address _account) publicviewreturns (bool) {
return _isRoleBearer(ROLE_KEY, _account);
}
function_setMinter(address _account, bool _value) internal{
_setRoleBearer(ROLE_KEY, _account, _value);
emit SetMinter(_account, _value);
}
}
Contract Source Code
File 16 of 25: MultichainRouterRole.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;import { RoleBearers } from'./RoleBearers.sol';
/**
* @title MultichainRouterRole
* @notice Base contract that implements the Multichain Router role
*/abstractcontractMultichainRouterRoleisRoleBearers{
bytes32privateconstant ROLE_KEY =keccak256('MultichainRouter');
/**
* @notice Emitted when the Multichain Router role status for the account is updated
* @param account The account address
* @param value The Multichain Router role status flag
*/eventSetMultichainRouter(addressindexed account, boolindexed value);
/**
* @notice Getter of the Multichain Router role bearer count
* @return The Multichain Router role bearer count
*/functionmultichainRouterCount() externalviewreturns (uint256) {
return _roleBearerCount(ROLE_KEY);
}
/**
* @notice Getter of the complete list of the Multichain Router role bearers
* @return The complete list of the Multichain Router role bearers
*/functionfullMultichainRouterList() externalviewreturns (address[] memory) {
return _fullRoleBearerList(ROLE_KEY);
}
/**
* @notice Getter of the Multichain Router role bearer status
* @param _account The account address
*/functionisMultichainRouter(address _account) publicviewreturns (bool) {
return _isRoleBearer(ROLE_KEY, _account);
}
function_setMultichainRouter(address _account, bool _value) internal{
_setRoleBearer(ROLE_KEY, _account, _value);
emit SetMultichainRouter(_account, _value);
}
}
Contract Source Code
File 17 of 25: MultichainTokenBase.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 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'asConstants;
/**
* @title MultichainTokenBase
* @notice Base contract that implements the Multichain token logic
*/abstractcontractMultichainTokenBaseisPausable, ERC20, MultichainRouterRole{
/**
* @dev Anyswap ERC20 standard
*/addresspublicimmutable underlying;
boolprivateimmutable useExplicitAccess;
/**
* @notice Emitted when token burning is not allowed to the caller
*/errorBurnAccessError();
/**
* @notice Emitted when the token allowance is not sufficient for burning
*/errorBurnAllowanceError();
/**
* @notice Emitted when token minting is not allowed to the caller
*/errorMintAccessError();
/**
* @notice Initializes the MultichainTokenBase properties of descendant contracts
* @param _name The ERC20 token name
* @param _symbol The ERC20 token symbol
* @param _decimals The ERC20 token decimals
* @param _useExplicitAccess The mint and burn actions access flag
*/constructor(stringmemory _name,
stringmemory _symbol,
uint8 _decimals,
bool _useExplicitAccess
) ERC20(_name, _symbol, _decimals) {
underlying =address(0);
useExplicitAccess = _useExplicitAccess;
}
/**
* @notice Updates the Multichain Router role status for the account
* @param _account The account address
* @param _value The Multichain Router role status flag
*/functionsetMultichainRouter(address _account, bool _value) externalonlyManager{
_setMultichainRouter(_account, _value);
}
/**
* @notice Mints tokens and assigns them to the account, increasing the total supply
* @dev The mint function returns a boolean value, as required by the Anyswap ERC20 standard
* @param _to The token receiver account address
* @param _amount The number of tokens to mint
* @return Token minting success status
*/functionmint(address _to, uint256 _amount) externalwhenNotPausedreturns (bool) {
bool condition = isMultichainRouter(msg.sender) ||
(useExplicitAccess && _isExplicitMinter());
if (!condition) {
revert MintAccessError();
}
_mint(_to, _amount);
returntrue;
}
/**
* @notice Burns tokens from the account, reducing the total supply
* @dev The burn function returns a boolean value, as required by the Anyswap ERC20 standard
* @param _from The token holder account address
* @param _amount The number of tokens to burn
* @return Token burning success status
*/functionburn(address _from, uint256 _amount) externalwhenNotPausedreturns (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) {
// Cannot overflow because the allowed value// is greater or equal to the amountunchecked {
allowance[_from][msg.sender] = allowed - _amount;
}
}
_burn(_from, _amount);
returntrue;
}
/**
* @dev Override to add explicit minter access
*/function_isExplicitMinter() internalviewvirtualreturns (bool) {
returnfalse;
}
/**
* @dev Override to add explicit burner access
*/function_isExplicitBurner() internalviewvirtualreturns (bool) {
returnfalse;
}
}
Contract Source Code
File 18 of 25: Ownable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)pragmasolidity ^0.8.0;import"../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/abstractcontractOwnableisContext{
addressprivate _owner;
eventOwnershipTransferred(addressindexed previousOwner, addressindexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/functionowner() publicviewvirtualreturns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/function_checkOwner() internalviewvirtual{
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/functionrenounceOwnership() publicvirtualonlyOwner{
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/functiontransferOwnership(address newOwner) publicvirtualonlyOwner{
require(newOwner !=address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/function_transferOwnership(address newOwner) internalvirtual{
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
Contract Source Code
File 19 of 25: Pausable.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;import { PausableasPausableBase } from'@openzeppelin/contracts/security/Pausable.sol';
import { ManagerRole } from'./roles/ManagerRole.sol';
/**
* @title Pausable
* @notice Base contract that implements the emergency pause mechanism
*/abstractcontractPausableisPausableBase, ManagerRole{
/**
* @notice Enter pause state
*/functionpause() externalonlyManagerwhenNotPaused{
_pause();
}
/**
* @notice Exit pause state
*/functionunpause() externalonlyManagerwhenPaused{
_unpause();
}
}
Contract Source Code
File 20 of 25: ReentrancyGuard.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)pragmasolidity ^0.8.0;/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/abstractcontractReentrancyGuard{
// Booleans are more expensive than uint256 or any type that takes up a full// word because each write operation emits an extra SLOAD to first read the// slot's contents, replace the bits taken up by the boolean, and then write// back. This is the compiler's defense against contract upgrades and// pointer aliasing, and it cannot be disabled.// The values being non-zero value makes deployment a bit more expensive,// but in exchange the refund on every call to nonReentrant will be lower in// amount. Since refunds are capped to a percentage of the total// transaction's gas, it is best to keep them low in cases like this one, to// increase the likelihood of the full refund coming into effect.uint256privateconstant _NOT_ENTERED =1;
uint256privateconstant _ENTERED =2;
uint256private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/modifiernonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function_nonReentrantBefore() private{
// On the first call to nonReentrant, _status will be _NOT_ENTEREDrequire(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function_nonReentrantAfter() private{
// By storing the original value once again, a refund is triggered (see// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;/**
* @title SystemVersionId
* @notice Base contract providing the system version identifier
*/abstractcontractSystemVersionId{
/**
* @dev The system version identifier
*/uint256publicconstant SYSTEM_VERSION_ID =uint256(keccak256('Initial'));
}
Contract Source Code
File 23 of 25: TransferHelper.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;/**
* @notice Emitted when an approval action fails
*/errorSafeApproveError();
/**
* @notice Emitted when a transfer action fails
*/errorSafeTransferError();
/**
* @notice Emitted when a transferFrom action fails
*/errorSafeTransferFromError();
/**
* @notice Emitted when a transfer of the native token fails
*/errorSafeTransferNativeError();
/**
* @notice Safely approve the token to the account
* @param _token The token address
* @param _to The token approval recipient address
* @param _value The token approval amount
*/functionsafeApprove(address _token, address _to, uint256 _value) {
// 0x095ea7b3 is the selector for "approve(address,uint256)"
(bool success, bytesmemory data) = _token.call(
abi.encodeWithSelector(0x095ea7b3, _to, _value)
);
bool condition = success && (data.length==0||abi.decode(data, (bool)));
if (!condition) {
revert SafeApproveError();
}
}
/**
* @notice Safely transfer the token to the account
* @param _token The token address
* @param _to The token transfer recipient address
* @param _value The token transfer amount
*/functionsafeTransfer(address _token, address _to, uint256 _value) {
// 0xa9059cbb is the selector for "transfer(address,uint256)"
(bool success, bytesmemory data) = _token.call(
abi.encodeWithSelector(0xa9059cbb, _to, _value)
);
bool condition = success && (data.length==0||abi.decode(data, (bool)));
if (!condition) {
revert SafeTransferError();
}
}
/**
* @notice Safely transfer the token between the accounts
* @param _token The token address
* @param _from The token transfer source address
* @param _to The token transfer recipient address
* @param _value The token transfer amount
*/functionsafeTransferFrom(address _token, address _from, address _to, uint256 _value) {
// 0x23b872dd is the selector for "transferFrom(address,address,uint256)"
(bool success, bytesmemory data) = _token.call(
abi.encodeWithSelector(0x23b872dd, _from, _to, _value)
);
bool condition = success && (data.length==0||abi.decode(data, (bool)));
if (!condition) {
revert SafeTransferFromError();
}
}
/**
* @notice Safely transfer the native token to the account
* @param _to The native token transfer recipient address
* @param _value The native token transfer amount
*/functionsafeTransferNative(address _to, uint256 _value) {
(bool success, ) = _to.call{ value: _value }(newbytes(0));
if (!success) {
revert SafeTransferNativeError();
}
}
Contract Source Code
File 24 of 25: Vault.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 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'asAddressHelper;
import'./helpers/TransferHelper.sol'asTransferHelper;
/**
* @title Vault
* @notice The vault contract
*/contractVaultisSystemVersionId, VaultBase, AssetSpenderRole, BalanceManagement{
/**
* @dev The variable token contract address, can be a zero address
*/addresspublic variableToken;
/**
* @dev The state of variable token and balance actions
*/boolpublic variableRepaymentEnabled;
/**
* @notice Emitted when the state of variable token and balance actions is updated
* @param variableRepaymentEnabled The state of variable token and balance actions
*/eventSetVariableRepaymentEnabled(boolindexed variableRepaymentEnabled);
/**
* @notice Emitted when the variable token contract address is updated
* @param variableToken The address of the variable token contract
*/eventSetVariableToken(addressindexed variableToken);
/**
* @notice Emitted when the variable tokens are redeemed for the vault asset
* @param caller The address of the vault asset receiver account
* @param amount The amount of redeemed variable tokens
*/eventRedeemVariableToken(addressindexed caller, uint256 amount);
/**
* @notice Emitted when the variable token decimals do not match the vault asset
*/errorTokenDecimalsError();
/**
* @notice Emitted when a variable token or balance action is not allowed
*/errorVariableRepaymentNotEnabledError();
/**
* @notice Emitted when setting the variable token is attempted while the token is already set
*/errorVariableTokenAlreadySetError();
/**
* @notice Emitted when a variable token action is attempted while the token address is not set
*/errorVariableTokenNotSetError();
/**
* @notice Deploys the VariableToken contract
* @param _asset The vault asset address
* @param _name The ERC20 token name
* @param _symbol The ERC20 token symbol
* @param _assetSpenders The addresses of initial asset spenders
* @param _depositAllowed The initial state of deposit availability
* @param _variableRepaymentEnabled The initial state of variable token and balance actions
* @param _owner The address of the initial owner of the contract
* @param _managers The addresses of initial managers of the contract
* @param _addOwnerToManagers The flag to optionally add the owner to the list of managers
*/constructor(address _asset,
stringmemory _name,
stringmemory _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);
}
/**
* @notice Updates the Asset Spender role status for the account
* @param _account The account address
* @param _value The Asset Spender role status flag
*/functionsetAssetSpender(address _account, bool _value) externalonlyManager{
_setAssetSpender(_account, _value);
}
/**
* @notice Sets the variable token contract address
* @dev Setting the address value is possible only once
* @param _variableToken The address of the variable token contract
*/functionsetVariableToken(address _variableToken) externalonlyManager{
if (variableToken !=address(0)) {
revert VariableTokenAlreadySetError();
}
AddressHelper.requireContract(_variableToken);
if (ITokenDecimals(_variableToken).decimals() != decimals) {
revert TokenDecimalsError();
}
variableToken = _variableToken;
emit SetVariableToken(_variableToken);
}
/**
* @notice Updates the state of variable token and balance actions
* @param _variableRepaymentEnabled The state of variable token and balance actions
*/functionsetVariableRepaymentEnabled(bool _variableRepaymentEnabled) externalonlyManager{
_setVariableRepaymentEnabled(_variableRepaymentEnabled);
}
/**
* @notice Requests the vault asset tokens
* @param _amount The amount of the vault asset tokens
* @param _to The address of the vault asset tokens receiver
* @param _forVariableBalance True if the request is made for a variable balance repayment, otherwise false
* @return assetAddress The address of the vault asset token
*/functionrequestAsset(uint256 _amount,
address _to,
bool _forVariableBalance
) externalwhenNotPausedonlyAssetSpenderreturns (address assetAddress) {
if (_forVariableBalance &&!variableRepaymentEnabled) {
revert VariableRepaymentNotEnabledError();
}
TransferHelper.safeTransfer(asset, _to, _amount);
return asset;
}
/**
* @notice Redeems variable tokens for the vault asset
* @param _amount The number of variable tokens to redeem
*/functionredeemVariableToken(uint256 _amount) externalwhenNotPausednonReentrantcheckCaller{
checkVariableTokenState();
bool burnSuccess = ITokenBurn(variableToken).burn(msg.sender, _amount);
if (!burnSuccess) {
revert TokenBurnError();
}
emit RedeemVariableToken(msg.sender, _amount);
TransferHelper.safeTransfer(asset, msg.sender, _amount);
}
/**
* @notice Checks the status of the variable token and balance actions and the variable token address
* @dev Throws an error if variable token actions are not allowed
* @return The address of the variable token
*/functioncheckVariableTokenState() publicviewreturns (address) {
if (!variableRepaymentEnabled) {
revert VariableRepaymentNotEnabledError();
}
if (variableToken ==address(0)) {
revert VariableTokenNotSetError();
}
return variableToken;
}
/**
* @notice Getter of the reserved token flag
* @dev Returns true if the provided token address is the address of the vault asset
* @param _tokenAddress The address of the token
* @return The reserved token flag
*/functionisReservedToken(address _tokenAddress) publicviewoverridereturns (bool) {
return _tokenAddress == asset;
}
function_setVariableRepaymentEnabled(bool _variableRepaymentEnabled) private{
variableRepaymentEnabled = _variableRepaymentEnabled;
emit SetVariableRepaymentEnabled(_variableRepaymentEnabled);
}
}
Contract Source Code
File 25 of 25: VaultBase.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 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'asTransferHelper;
import'./Constants.sol'asConstants;
/**
* @title VaultBase
* @notice Base contract that implements the vault logic
*/abstractcontractVaultBaseisMultichainTokenBase, ReentrancyGuard, CallerGuard{
/**
* @dev The vault asset address
*/addresspublicimmutable asset;
/**
* @dev The total vault token supply limit
*/uint256public totalSupplyLimit;
/**
* @notice Emitted when the total supply limit is set
* @param limit The total supply limit value
*/eventSetTotalSupplyLimit(uint256 limit);
/**
* @notice Emitted when a deposit action is performed
* @param caller The address of the depositor account
* @param assetAmount The amount of the deposited asset
*/eventDeposit(addressindexed caller, uint256 assetAmount);
/**
* @notice Emitted when a withdrawal action is performed
* @param caller The address of the withdrawal account
* @param assetAmount The amount of the withdrawn asset
*/eventWithdraw(addressindexed caller, uint256 assetAmount);
/**
* @notice Emitted when the total supply limit is exceeded
*/errorTotalSupplyLimitError();
/**
* @notice Emitted when a deposit is attempted with a zero amount
*/errorZeroAmountError();
/**
* @notice Initializes the VaultBase properties of descendant contracts
* @param _asset The vault asset address
* @param _name The ERC20 token name
* @param _symbol The ERC20 token symbol
* @param _depositAllowed The initial state of deposit availability
*/constructor(address _asset,
stringmemory _name,
stringmemory _symbol,
bool _depositAllowed
) MultichainTokenBase(_name, _symbol, ITokenDecimals(_asset).decimals(), false) {
asset = _asset;
_setTotalSupplyLimit(_depositAllowed ? Constants.INFINITY : 0);
}
/**
* @notice Sets the total supply
* @dev Decimals = vault token decimals = asset decimals
* @param _limit The total supply limit value
*/functionsetTotalSupplyLimit(uint256 _limit) externalonlyManager{
_setTotalSupplyLimit(_limit);
}
/**
* @notice Performs a deposit action. User deposits usdc/usdt for iusdc/iusdt used in Stablecoin Farm.
* @param _assetAmount The amount of the deposited asset
*/functiondeposit(uint256 _assetAmount) externalvirtualwhenNotPausednonReentrantcheckCaller{
if (_assetAmount ==0) {
revert ZeroAmountError();
}
if (totalSupply + _assetAmount > totalSupplyLimit) {
revert TotalSupplyLimitError();
}
// Need to transfer before minting or ERC777s could reenter
TransferHelper.safeTransferFrom(asset, msg.sender, address(this), _assetAmount);
_mint(msg.sender, _assetAmount);
emit Deposit(msg.sender, _assetAmount);
}
/**
* @notice Performs a withdrawal action
* @param _assetAmount The amount of the withdrawn asset
*/functionwithdraw(uint256 _assetAmount
) externalvirtualwhenNotPausednonReentrantcheckCaller{
_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);
}
}