文件 1 的 9:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 2 的 9: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;
}
}
文件 3 的 9:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
文件 4 的 9:IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
文件 5 的 9:IMozToken.sol
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IMozToken is IERC20{
function lockAndVestAndTransfer(
address walletAddress,
uint256 amount,
uint256 lockStart,
uint256 lockPeriod,
uint256 vestPeriod
) external returns (bool);
function multipleLockAndVestAndTransfer(address[] memory walletAddresses,
uint256[] memory amounts,
uint256 lockStart,
uint256 lockPeriod,
uint256 vestPeriod
) external returns (bool);
function burn(uint256 amount, address from) external;
function mint(uint256 amount, address to) external;
}
文件 6 的 9:IXMozToken.sol
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IXMozToken is IERC20 {
function mint(uint256 amount, address to) external;
function isTransferWhitelisted(address account) external view returns (bool);
function burn(uint256 amount, address to) external;
function updateTransferWhitelist(address account, bool flag) external;
}
文件 7 的 9:MozStaking.sol
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./interfaces/IMozToken.sol";
import "./interfaces/IXMozToken.sol";
contract MozStaking is Ownable {
using Address for address;
using SafeERC20 for IMozToken;
using SafeERC20 for IXMozToken;
struct RedeemInfo {
uint256 mozAmount;
uint256 xMozAmount;
uint256 endTime;
}
IMozToken public mozaicToken;
IXMozToken public xMozToken;
address public daoTreasury;
bool private flag;
uint256 public constant MAX_FIXED_RATIO = 100;
uint256 public minRedeemRatio = 50;
uint256 public mediumRedeemRatio = 75;
uint256 public maxRedeemRatio = 100;
uint256 public minRedeemDuration = 15 days;
uint256 public mediumRedeemDuration = 30 days;
uint256 public maxRedeemDuration = 45 days;
mapping(address => uint256) public xMozRedeemingBalances;
mapping(address => RedeemInfo[]) public userRedeems;
constructor(
address daoTreasury_
) {
require(daoTreasury_ != address(0x0), "Invalid addr");
daoTreasury = daoTreasury_;
}
event Convert(address indexed from, address to, uint256 amount);
event UpdateRedeemSettings(uint256 minRedeemRatio, uint256 mediumRedeemRatio, uint256 maxRedeemRatio, uint256 minRedeemDuration, uint256 mediumRedeemDuration, uint256 maxRedeemDuration);
event Redeem(address indexed userAddress, uint256 xMozAmount, uint256 mozAmount, uint256 duration);
event FinalizeRedeem(address indexed userAddress, uint256 xMozAmount, uint256 mozAmount);
event CancelRedeem(address indexed userAddress, uint256 xMozAmount);
modifier validateRedeem(address userAddress, uint256 redeemIndex) {
require(redeemIndex < userRedeems[userAddress].length, "validateRedeem: redeem entry does not exist");
_;
}
function initialize(address mozaicToken_, address xMoztoken_) external {
require(mozaicToken_ != address(0x0) || xMoztoken_ != address(0x0), "Invalid addr");
require(!flag, "Already initialized");
mozaicToken = IMozToken(mozaicToken_);
xMozToken = IXMozToken(xMoztoken_);
flag = true;
}
function getRedeemingXMozBalance(address userAddress) external view returns (uint256 redeemingAmount) {
uint256 balance = xMozRedeemingBalances[userAddress];
return balance;
}
function getMozByVestingDuration(uint256 amount, uint256 duration) public view returns (uint256) {
uint256 ratio;
if(duration < minRedeemDuration) {
return 0;
}
else if(duration >= minRedeemDuration && duration < mediumRedeemDuration) {
ratio = minRedeemRatio + (mediumRedeemRatio - minRedeemRatio) * (duration - minRedeemDuration) / (mediumRedeemDuration - minRedeemDuration);
}
else if(duration >= mediumRedeemDuration && duration < maxRedeemDuration) {
ratio = mediumRedeemRatio + (maxRedeemRatio - mediumRedeemRatio) * (duration - mediumRedeemDuration) / (maxRedeemDuration - mediumRedeemDuration);
}
else {
ratio = maxRedeemRatio;
}
return amount * ratio / MAX_FIXED_RATIO;
}
function getUserRedeemsLength(address userAddress) external view returns (uint256) {
return userRedeems[userAddress].length;
}
function getUserRedeem(address userAddress, uint256 redeemIndex) external view validateRedeem(userAddress, redeemIndex) returns (uint256 mozAmount, uint256 xMozAmount, uint256 endTime) {
RedeemInfo storage _redeem = userRedeems[userAddress][redeemIndex];
return (_redeem.mozAmount, _redeem.xMozAmount, _redeem.endTime);
}
function updateRedeemSettings(uint256 minRedeemRatio_, uint256 mediumRedeemRatio_, uint256 maxRedeemRatio_, uint256 minRedeemDuration_, uint256 mediumRedeemDuration_, uint256 maxRedeemDuration_) external onlyOwner {
require(minRedeemRatio_ <= mediumRedeemRatio_ && mediumRedeemRatio_ <= maxRedeemRatio_, "updateRedeemSettings: wrong ratio values");
require(minRedeemDuration_ < mediumRedeemDuration_ && mediumRedeemDuration_ < maxRedeemDuration_, "updateRedeemSettings: wrong duration values");
require(maxRedeemRatio_ <= MAX_FIXED_RATIO, "updateRedeemSettings: wrong ratio values");
minRedeemRatio = minRedeemRatio_;
mediumRedeemRatio = mediumRedeemRatio_;
maxRedeemRatio = maxRedeemRatio_;
minRedeemDuration = minRedeemDuration_;
mediumRedeemDuration = mediumRedeemDuration_;
maxRedeemDuration = maxRedeemDuration_;
emit UpdateRedeemSettings(minRedeemRatio_, mediumRedeemRatio_, maxRedeemRatio_, minRedeemDuration_, mediumRedeemDuration_, maxRedeemDuration_);
}
function convert(uint256 amount) external {
_convert(amount, msg.sender);
}
function convertTo(uint256 amount, address to) external {
require(address(msg.sender).isContract(), "convertTo: not allowed");
_convert(amount, to);
}
function redeem(uint256 xMozAmount, uint256 duration) external {
require(xMozAmount > 0, "redeem: xMozAmount cannot be zero");
require(duration >= minRedeemDuration, "redeem: Invalid duration");
uint256 mozAmount = getMozByVestingDuration(xMozAmount, duration);
xMozToken.burn(xMozAmount, msg.sender);
uint256 redeemingAmount = xMozRedeemingBalances[msg.sender];
if (mozAmount > 0) {
emit Redeem(msg.sender, xMozAmount, mozAmount, duration);
xMozRedeemingBalances[msg.sender] = redeemingAmount + xMozAmount;
userRedeems[msg.sender].push(RedeemInfo(mozAmount, xMozAmount, _currentBlockTimestamp() + duration));
}
}
function finalizeRedeem(uint256 redeemIndex) external validateRedeem(msg.sender, redeemIndex) {
uint256 redeemingAmount = xMozRedeemingBalances[msg.sender];
RedeemInfo storage _redeem = userRedeems[msg.sender][redeemIndex];
require(_currentBlockTimestamp() >= _redeem.endTime, "finalizeRedeem: vesting duration has not ended yet");
xMozRedeemingBalances[msg.sender] = redeemingAmount - _redeem.xMozAmount;
_finalizeRedeem(msg.sender, _redeem.xMozAmount, _redeem.mozAmount);
_deleteRedeemEntry(redeemIndex);
}
function cancelRedeem(uint256 redeemIndex) external validateRedeem(msg.sender, redeemIndex) {
uint256 redeemingAmount = xMozRedeemingBalances[msg.sender];
RedeemInfo storage _redeem = userRedeems[msg.sender][redeemIndex];
xMozRedeemingBalances[msg.sender] = redeemingAmount - _redeem.xMozAmount;
xMozToken.mint(_redeem.xMozAmount, msg.sender);
emit CancelRedeem(msg.sender, _redeem.xMozAmount);
_deleteRedeemEntry(redeemIndex);
}
function _convert(uint256 amount, address to) internal {
require(amount != 0, "convert: amount cannot be null");
mozaicToken.burn(amount, msg.sender);
xMozToken.mint(amount, to);
emit Convert(msg.sender, to, amount);
}
function _finalizeRedeem(address userAddress, uint256 xMozAmount, uint256 mozAmount) internal {
uint256 mozExcess = xMozAmount - mozAmount;
mozaicToken.mint(mozAmount, userAddress);
if(mozExcess > 0) {
mozaicToken.mint(mozExcess, daoTreasury);
}
emit FinalizeRedeem(userAddress, xMozAmount, mozAmount);
}
function _deleteRedeemEntry(uint256 index) internal {
userRedeems[msg.sender][index] = userRedeems[msg.sender][userRedeems[msg.sender].length - 1];
userRedeems[msg.sender].pop();
}
function _currentBlockTimestamp() internal view virtual returns (uint256) {
return block.timestamp;
}
}
文件 8 的 9: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);
}
}
文件 9 的 9:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}
{
"compilationTarget": {
"contracts/MozStaking.sol": "MozStaking"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 1000
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"daoTreasury_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"userAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"xMozAmount","type":"uint256"}],"name":"CancelRedeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Convert","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"userAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"xMozAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mozAmount","type":"uint256"}],"name":"FinalizeRedeem","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":true,"internalType":"address","name":"userAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"xMozAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mozAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"duration","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minRedeemRatio","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mediumRedeemRatio","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxRedeemRatio","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minRedeemDuration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mediumRedeemDuration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxRedeemDuration","type":"uint256"}],"name":"UpdateRedeemSettings","type":"event"},{"inputs":[],"name":"MAX_FIXED_RATIO","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"redeemIndex","type":"uint256"}],"name":"cancelRedeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"convert","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"convertTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"daoTreasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"redeemIndex","type":"uint256"}],"name":"finalizeRedeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"getMozByVestingDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"getRedeemingXMozBalance","outputs":[{"internalType":"uint256","name":"redeemingAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"},{"internalType":"uint256","name":"redeemIndex","type":"uint256"}],"name":"getUserRedeem","outputs":[{"internalType":"uint256","name":"mozAmount","type":"uint256"},{"internalType":"uint256","name":"xMozAmount","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"getUserRedeemsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"mozaicToken_","type":"address"},{"internalType":"address","name":"xMoztoken_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxRedeemDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxRedeemRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mediumRedeemDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mediumRedeemRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minRedeemDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minRedeemRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mozaicToken","outputs":[{"internalType":"contract IMozToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"xMozAmount","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minRedeemRatio_","type":"uint256"},{"internalType":"uint256","name":"mediumRedeemRatio_","type":"uint256"},{"internalType":"uint256","name":"maxRedeemRatio_","type":"uint256"},{"internalType":"uint256","name":"minRedeemDuration_","type":"uint256"},{"internalType":"uint256","name":"mediumRedeemDuration_","type":"uint256"},{"internalType":"uint256","name":"maxRedeemDuration_","type":"uint256"}],"name":"updateRedeemSettings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userRedeems","outputs":[{"internalType":"uint256","name":"mozAmount","type":"uint256"},{"internalType":"uint256","name":"xMozAmount","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"xMozRedeemingBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"xMozToken","outputs":[{"internalType":"contract IXMozToken","name":"","type":"address"}],"stateMutability":"view","type":"function"}]