编译器
0.8.28+commit.7893614a
文件 1 的 14:AccessControl.sol
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}
文件 2 的 14:Address.sol
pragma solidity ^0.8.20;
import {Errors} from "./Errors.sol";
library Address {
error AddressEmptyCode(address target);
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert Errors.InsufficientBalance(address(this).balance, amount);
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert Errors.FailedCall();
}
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
function _revert(bytes memory returndata) private pure {
if (returndata.length > 0) {
assembly ("memory-safe") {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert Errors.FailedCall();
}
}
}
文件 3 的 14:Context.sol
pragma solidity ^0.8.20;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
文件 4 的 14:ERC165.sol
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 5 的 14:Errors.sol
pragma solidity ^0.8.20;
library Errors {
error InsufficientBalance(uint256 balance, uint256 needed);
error FailedCall();
error FailedDeployment();
error MissingPrecompile(address);
}
文件 6 的 14:IAccessControl.sol
pragma solidity ^0.8.20;
interface IAccessControl {
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
error AccessControlBadConfirmation();
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address callerConfirmation) external;
}
文件 7 的 14:IERC1363.sol
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
interface IERC1363 is IERC20, IERC165 {
function transferAndCall(address to, uint256 value) external returns (bool);
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
function approveAndCall(address spender, uint256 value) external returns (bool);
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}
文件 8 的 14:IERC165.sol
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";
文件 9 的 14:IERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
文件 10 的 14:IVault.sol
pragma solidity =0.8.28;
struct AssetsInfo {
uint256 stakedAmount;
uint256 accumulatedReward;
uint256 lastRewardUpdateTime;
uint256[] pendingClaimQueueIDs;
StakeItem[] stakeHistory;
ClaimItem[] claimHistory;
}
struct StakeItem {
address token;
address user;
uint256 amount;
uint256 stakeTimestamp;
}
struct ClaimItem {
bool isDone;
address token;
address user;
uint256 totalAmount;
uint256 principalAmount;
uint256 rewardAmount;
uint256 requestTime;
uint256 claimTime;
}
interface IVault {
event Stake(address indexed _user, address indexed _token, uint256 indexed _amount);
event RequestClaim(address _user, address indexed _token, uint256 indexed _amount, uint256 indexed _id);
event ClaimAssets(address indexed _user, address indexed _token, uint256 indexed _amount, uint256 _id);
event UpdateRewardRate(address _token, uint256 _oldRewardRate, uint256 _newRewardRate);
event UpdateCeffu(address _oldCeffu, address _newCeffu);
event UpdateStakeLimit(address indexed _token, uint256 _oldMinAmount, uint256 _oldMaxAmount, uint256 _newMinAmount, uint256 _newMaxAmount);
event CeffuReceive(address indexed _token, address _ceffu, uint256 indexed _amount);
event AddSupportedToken(address indexed _token, uint256 _minAmount, uint256 _maxAmount);
event EmergencyWithdrawal(address indexed _token, address indexed _receiver);
event UpdateWaitingTime(uint256 _oldWaitingTime, uint256 _newWaitingTIme);
function stake_66380860(address _token, uint256 _stakedAmount) external;
function requestClaim_8135334(address _token, uint256 _amount) external returns(uint256);
function claim_41202704(uint256 _queueID) external;
function transferToCeffu(address _token, uint256 _amount) external;
function emergencyWithdraw(address _token, address _receiver) external;
function addSupportedToken(address _token, uint256 _minAmount, uint256 _maxAmount) external;
function setRewardRate(address _token, uint256 _newRewardRate) external;
function setStakeLimit(address _token, uint256 _minAmount, uint256 _maxAmount) external;
function setCeffu(address _newCeffu) external;
function setWaitingTime(uint256 _newWaitingTIme) external;
function getClaimableRewardsWithTargetTime(address _user, address _token, uint256 _targetTime) external view returns (uint256);
function getClaimableAssets(address _user, address _token) external view returns (uint256);
function getClaimableRewards(address _user, address _token) external view returns (uint256);
function getTotalRewards(address _user, address _token) external view returns (uint256);
function getStakedAmount(address _user, address _token) external view returns (uint256);
function getContractBalance(address _token) external view returns (uint256);
function getStakeHistory(address _user, address _token, uint256 _index) external view returns (StakeItem memory);
function getClaimHistory(address _user, address _token, uint256 _index) external view returns (ClaimItem memory);
function getStakeHistoryLength(address _user, address _token) external view returns(uint256);
function getClaimHistoryLength(address _user, address _token) external view returns(uint256);
function getCurrentRewardRate(address _token) external view returns(uint256, uint256);
function getClaimQueueInfo(uint256 _index) external view returns(ClaimItem memory);
function getClaimQueueIDs(address _user, address _token) external view returns(uint256[] memory);
function getTVL(address _token) external view returns(uint256);
}
文件 11 的 14:Pausable.sol
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
abstract contract Pausable is Context {
bool private _paused;
event Paused(address account);
event Unpaused(address account);
error EnforcedPause();
error ExpectedPause();
constructor() {
_paused = false;
}
modifier whenNotPaused() {
_requireNotPaused();
_;
}
modifier whenPaused() {
_requirePaused();
_;
}
function paused() public view virtual returns (bool) {
return _paused;
}
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
文件 12 的 14:SafeERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
import {Address} from "../../../utils/Address.sol";
library SafeERC20 {
error SafeERC20FailedOperation(address token);
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}
文件 13 的 14:Vault.sol
pragma solidity =0.8.28;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import "./IVault.sol";
import "./utils.sol";
contract Vault is Pausable, AccessControl, IVault {
using SafeERC20 for IERC20;
mapping(address => uint256) private tvl;
mapping(address => bool) public supportedTokens;
address[] private supportedTokensArray;
uint256 public lastClaimQueueID = 1;
mapping(uint256 => ClaimItem) private claimQueue;
mapping(address => mapping(address => AssetsInfo)) private userAssetsInfo;
struct RewardRateState {
address token;
uint256 rewardRate;
uint256 updatedTime;
}
mapping(address => RewardRateState[]) private rewardRateState;
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
bytes32 public constant BOT_ROLE = keccak256("BOT_ROLE");
address public ceffu;
mapping(address => uint256) public minStakeAmount;
mapping(address => uint256) public maxStakeAmount;
uint256 public WAITING_TIME;
uint256 private constant BASE = 10_000;
constructor(
address[] memory _tokens,
uint256[] memory _newRewardRate,
uint256[] memory _minStakeAmount,
uint256[] memory _maxStakeAmount,
address _admin,
address _bot,
address _ceffu,
uint256 _waitingTime
) {
Utils.CheckIsZeroAddress(_ceffu);
Utils.CheckIsZeroAddress(_admin);
Utils.CheckIsZeroAddress(_bot);
uint256 len = _tokens.length;
require(Utils.MustGreaterThanZero(len), "Array length can NOT be zero");
require(
len == _newRewardRate.length &&
len == _minStakeAmount.length &&
len == _maxStakeAmount.length,
"The lengths of the arrays MUST be the same"
);
_grantRole(DEFAULT_ADMIN_ROLE, _admin);
_grantRole(PAUSER_ROLE, _admin);
_grantRole(BOT_ROLE, _bot);
ceffu = _ceffu;
emit UpdateCeffu(address(0), _ceffu);
WAITING_TIME = _waitingTime;
emit UpdateWaitingTime(0, _waitingTime);
for (uint256 i = 0; i < len; i++) {
require(_minStakeAmount[i] < _maxStakeAmount[i], "minAmount MUST be less than maxAmount");
address token = _tokens[i];
minStakeAmount[token] = _minStakeAmount[i];
maxStakeAmount[token] = _maxStakeAmount[i];
supportedTokens[token] = true;
supportedTokensArray.push(token);
emit AddSupportedToken(token, _minStakeAmount[i], _maxStakeAmount[i]);
RewardRateState memory rewardRateItem = RewardRateState({
token: token,
rewardRate: _newRewardRate[i],
updatedTime: block.timestamp
});
rewardRateState[token].push(rewardRateItem);
emit UpdateRewardRate(token, 0, _newRewardRate[i]);
}
}
modifier onlySupportedToken(address _token) {
require(supportedTokens[_token], "Unsupported token");
_;
}
function stake_66380860(address _token, uint256 _stakedAmount) external onlySupportedToken(_token) whenNotPaused {
AssetsInfo storage assetsInfo = userAssetsInfo[msg.sender][_token];
uint256 currentStakedAmount = assetsInfo.stakedAmount;
require(Utils.Add(currentStakedAmount, _stakedAmount) >= minStakeAmount[_token], "Amount MUST be greater than minStakeAmount");
require(Utils.Add(currentStakedAmount, _stakedAmount) <= maxStakeAmount[_token], "The deposit amount MUST NOT exceed maxStakeAmount");
IERC20(_token).safeTransferFrom(msg.sender, address(this), _stakedAmount);
_updateRewardState(msg.sender, _token);
assetsInfo.stakeHistory.push(
StakeItem({
stakeTimestamp: block.timestamp,
amount: _stakedAmount,
token: _token,
user: msg.sender
})
);
unchecked {
assetsInfo.stakedAmount += _stakedAmount;
tvl[_token] += _stakedAmount;
}
emit Stake(msg.sender, _token, _stakedAmount);
}
function requestClaim_8135334(
address _token,
uint256 _amount
) external onlySupportedToken(_token) whenNotPaused returns(uint256 _returnID) {
_updateRewardState(msg.sender, _token);
AssetsInfo storage assetsInfo = userAssetsInfo[msg.sender][_token];
uint256 currentStakedAmount = assetsInfo.stakedAmount;
uint256 currentAccumulatedRewardAmount = assetsInfo.accumulatedReward;
require(
Utils.MustGreaterThanZero(_amount) &&
(_amount <= Utils.Add(currentStakedAmount, currentAccumulatedRewardAmount) || _amount == type(uint256).max),
"Invalid amount"
);
ClaimItem storage queueItem = claimQueue[lastClaimQueueID];
uint256 totalAmount = _amount;
if(_amount == type(uint256).max){
totalAmount = Utils.Add(currentAccumulatedRewardAmount, assetsInfo.stakedAmount);
queueItem.rewardAmount = currentAccumulatedRewardAmount;
assetsInfo.accumulatedReward = 0;
queueItem.principalAmount = assetsInfo.stakedAmount;
assetsInfo.stakedAmount = 0;
}else if(currentAccumulatedRewardAmount >= _amount) {
assetsInfo.accumulatedReward -= _amount;
queueItem.rewardAmount = _amount;
} else {
queueItem.rewardAmount = currentAccumulatedRewardAmount;
assetsInfo.accumulatedReward = 0;
uint256 difference = _amount - currentAccumulatedRewardAmount;
assetsInfo.stakedAmount -= difference;
queueItem.principalAmount = difference;
}
assetsInfo.pendingClaimQueueIDs.push(lastClaimQueueID);
queueItem.token = _token;
queueItem.user = msg.sender;
queueItem.totalAmount = totalAmount;
queueItem.requestTime = block.timestamp;
queueItem.claimTime = Utils.Add(block.timestamp, WAITING_TIME);
unchecked {
_returnID = lastClaimQueueID;
++lastClaimQueueID;
}
emit RequestClaim(msg.sender, _token, totalAmount, _returnID);
}
function claim_41202704(uint256 _queueID) external whenNotPaused{
ClaimItem memory claimItem = claimQueue[_queueID];
address token = claimItem.token;
AssetsInfo storage assetsInfo = userAssetsInfo[msg.sender][token];
uint256[] memory pendingClaimQueueIDs = userAssetsInfo[msg.sender][token].pendingClaimQueueIDs;
require(Utils.MustGreaterThanZero(claimItem.totalAmount), "No assets to claim");
require(block.timestamp >= claimItem.claimTime, "Not enough time");
require(claimItem.user == msg.sender, "Invalid caller");
require(claimItem.isDone == false, "The request is completed");
claimQueue[_queueID].isDone = true;
for(uint256 i = 0; i < pendingClaimQueueIDs.length; i++) {
if(pendingClaimQueueIDs[i] == _queueID) {
assetsInfo.pendingClaimQueueIDs[i] = pendingClaimQueueIDs[pendingClaimQueueIDs.length-1];
assetsInfo.pendingClaimQueueIDs.pop();
break;
}
}
tvl[token] -= claimItem.principalAmount;
assetsInfo.claimHistory.push(
ClaimItem({
isDone: true,
token: token,
user: msg.sender,
totalAmount: claimItem.totalAmount,
principalAmount: claimItem.principalAmount,
rewardAmount: claimItem.rewardAmount,
requestTime: claimItem.requestTime,
claimTime: block.timestamp
})
);
IERC20(token).safeTransfer(msg.sender, claimItem.totalAmount);
emit ClaimAssets(msg.sender, token, claimItem.totalAmount, _queueID);
}
function _updateRewardState(address _user, address _token) internal {
AssetsInfo storage assetsInfo = userAssetsInfo[msg.sender][_token];
uint256 newAccumulatedReward = 0;
if(assetsInfo.lastRewardUpdateTime != 0) {
newAccumulatedReward = _getClaimableRewards(_user, _token);
}
assetsInfo.accumulatedReward = newAccumulatedReward;
assetsInfo.lastRewardUpdateTime = block.timestamp;
}
function transferToCeffu(
address _token,
uint256 _amount
) external onlySupportedToken(_token) onlyRole(BOT_ROLE) {
require(Utils.MustGreaterThanZero(_amount), "Amount must be greater than zero");
require(_amount <= IERC20(_token).balanceOf(address(this)), "Not enough balance");
IERC20(_token).safeTransfer(ceffu, _amount);
emit CeffuReceive(_token, ceffu, _amount);
}
function emergencyWithdraw(address _token, address _receiver) external onlyRole(DEFAULT_ADMIN_ROLE) {
Utils.CheckIsZeroAddress(_token);
Utils.CheckIsZeroAddress(_receiver);
IERC20(_token).safeTransfer(_receiver, IERC20(_token).balanceOf(address(this)));
emit EmergencyWithdrawal(_token, _receiver);
}
function pause() external onlyRole(PAUSER_ROLE) {
_pause();
}
function unpause() external onlyRole(PAUSER_ROLE) {
_unpause();
}
function addSupportedToken(
address _token,
uint256 _minAmount,
uint256 _maxAmount
) external onlyRole(DEFAULT_ADMIN_ROLE) {
Utils.CheckIsZeroAddress(_token);
require(!supportedTokens[_token], "The token is already supported");
supportedTokens[_token] = true;
supportedTokensArray.push(_token);
setStakeLimit(_token, _minAmount, _maxAmount);
emit AddSupportedToken(_token, _minAmount, _maxAmount);
}
function setRewardRate(
address _token,
uint256 _newRewardRate
) external onlySupportedToken(_token) onlyRole(DEFAULT_ADMIN_ROLE) {
require(_newRewardRate < BASE, "Invalid new rate");
RewardRateState[] memory rewardRateArray = rewardRateState[_token];
uint256 currentRewardRate = rewardRateArray[rewardRateArray.length - 1].rewardRate;
require(currentRewardRate != _newRewardRate && Utils.MustGreaterThanZero(_newRewardRate), "Invalid new reward rate");
RewardRateState memory rewardRateItem = RewardRateState({
updatedTime: block.timestamp,
token: _token,
rewardRate: _newRewardRate
});
rewardRateState[_token].push(rewardRateItem);
emit UpdateRewardRate(_token, currentRewardRate, _newRewardRate);
}
function setCeffu(address _newCeffu) external onlyRole(DEFAULT_ADMIN_ROLE) {
Utils.CheckIsZeroAddress(_newCeffu);
require(_newCeffu != ceffu, "Invalid new ceffu address");
emit UpdateCeffu(ceffu, _newCeffu);
ceffu = _newCeffu;
}
function setStakeLimit(
address _token,
uint256 _minAmount,
uint256 _maxAmount
) public onlyRole(DEFAULT_ADMIN_ROLE) onlySupportedToken(_token) {
require(Utils.MustGreaterThanZero(_minAmount) && _minAmount < _maxAmount, "Invalid limit range");
emit UpdateStakeLimit(_token, minStakeAmount[_token], maxStakeAmount[_token], _minAmount, _maxAmount);
minStakeAmount[_token] = _minAmount;
maxStakeAmount[_token] = _maxAmount;
}
function setWaitingTime(uint256 _newWaitingTime) external onlyRole(DEFAULT_ADMIN_ROLE){
require(_newWaitingTime != WAITING_TIME, "New waiting time should NOT be the same as the old one");
emit UpdateWaitingTime(WAITING_TIME, _newWaitingTime);
WAITING_TIME = _newWaitingTime;
}
function calculateReward(
uint256 _stakedAmount,
uint256 _rewardRate,
uint256 _elapsedTime
) internal pure returns (uint256 result) {
assembly {
let ONE_YEAR := 31557600
let numerator := mul(_stakedAmount, _rewardRate)
numerator := mul(numerator, _elapsedTime)
let denominator := mul(ONE_YEAR, BASE)
result := div(numerator, denominator)
}
}
function _getClaimableRewards(address _user, address _token) internal view returns (uint256) {
AssetsInfo memory assetsInfo = userAssetsInfo[_user][_token];
uint256 currentStakedAmount = assetsInfo.stakedAmount;
uint256 lastRewardUpdate = assetsInfo.lastRewardUpdateTime;
RewardRateState[] memory rewardRateArray = rewardRateState[_token];
uint256 rewardRateLength = rewardRateArray.length;
RewardRateState memory currentRewardRateState = rewardRateArray[rewardRateLength - 1];
if(lastRewardUpdate == 0) return 0;
if(currentRewardRateState.updatedTime <= lastRewardUpdate){
uint256 elapsedTime = block.timestamp - assetsInfo.lastRewardUpdateTime;
uint256 reward = calculateReward(
currentStakedAmount,
currentRewardRateState.rewardRate,
elapsedTime
);
return assetsInfo.accumulatedReward + reward;
} else {
uint256 beginIndex = 0;
for (uint256 i = 0; i < rewardRateLength; i++) {
if (lastRewardUpdate < rewardRateArray[i].updatedTime) {
beginIndex = i;
break;
}
}
uint256 tempLastRewardUpdateTime = lastRewardUpdate;
for (uint256 i = beginIndex; i < rewardRateLength; i++) {
if(i == 0) continue;
uint256 tempElapsedTime = rewardRateArray[i].updatedTime - tempLastRewardUpdateTime;
uint256 tempReward = calculateReward(
currentStakedAmount,
rewardRateArray[i - 1].rewardRate,
tempElapsedTime
);
tempLastRewardUpdateTime = rewardRateArray[i].updatedTime;
unchecked{
assetsInfo.accumulatedReward += tempReward;
}
}
uint256 elapsedTime = block.timestamp - currentRewardRateState.updatedTime;
uint256 reward = calculateReward(
currentStakedAmount,
currentRewardRateState.rewardRate,
elapsedTime
);
return assetsInfo.accumulatedReward + reward;
}
}
function getClaimableAssets(address _user, address _token) external view returns (uint256) {
AssetsInfo memory assetsInfo = userAssetsInfo[_user][_token];
return Utils.Add(assetsInfo.stakedAmount, _getClaimableRewards(_user, _token));
}
function getClaimableRewards(address _user, address _token) external view returns (uint256) {
return _getClaimableRewards(_user, _token);
}
function getTotalRewards(address _user, address _token) external view returns (uint256) {
uint256 historyRewards = 0;
uint256 currentRewards = _getClaimableRewards(_user, _token);
AssetsInfo memory stakeInfo = userAssetsInfo[_user][_token];
for(uint256 i = 0; i < stakeInfo.claimHistory.length; i++) {
historyRewards += stakeInfo.claimHistory[i].rewardAmount;
}
return Utils.Add(historyRewards, currentRewards);
}
function getClaimableRewardsWithTargetTime(
address _user,
address _token,
uint256 _targetTime
) external view returns (uint256) {
require(_targetTime > block.timestamp, "Invalid target time");
AssetsInfo memory assetsInfo = userAssetsInfo[_user][_token];
RewardRateState[] memory rewardRateArray = rewardRateState[_token];
RewardRateState memory currentRewardRateState = rewardRateArray[rewardRateArray.length - 1];
uint256 newAccumulatedReward = 0;
if(assetsInfo.lastRewardUpdateTime != 0) {
newAccumulatedReward = _getClaimableRewards(_user, _token);
}
uint256 elapsedTime = _targetTime - block.timestamp;
uint256 reward = calculateReward(
assetsInfo.stakedAmount,
currentRewardRateState.rewardRate,
elapsedTime
);
return Utils.Add(newAccumulatedReward, reward);
}
function getStakedAmount(address _user, address _token) external view onlySupportedToken(_token) returns (uint256) {
AssetsInfo memory stakeInfo = userAssetsInfo[_user][_token];
return stakeInfo.stakedAmount;
}
function getContractBalance(address _token) external view returns (uint256) {
Utils.CheckIsZeroAddress(_token);
return IERC20(_token).balanceOf(address(this));
}
function getStakeHistory(
address _user,
address _token,
uint256 _index
) external view onlySupportedToken(_token) returns (StakeItem memory) {
AssetsInfo memory stakeInfo = userAssetsInfo[_user][_token];
require(_index < stakeInfo.stakeHistory.length, "Invalid index");
return stakeInfo.stakeHistory[_index];
}
function getClaimHistory(
address _user,
address _token,
uint256 _index
) external view onlySupportedToken(_token) returns (ClaimItem memory) {
AssetsInfo memory stakeInfo = userAssetsInfo[_user][_token];
require(_index < stakeInfo.claimHistory.length, "Invalid index");
return stakeInfo.claimHistory[_index];
}
function getStakeHistoryLength(address _user, address _token) external view returns(uint256) {
AssetsInfo memory stakeInfo = userAssetsInfo[_user][_token];
return stakeInfo.stakeHistory.length;
}
function getClaimHistoryLength(address _user, address _token) external view returns(uint256) {
AssetsInfo memory stakeInfo = userAssetsInfo[_user][_token];
return stakeInfo.claimHistory.length;
}
function getClaimQueueIDs(address _user, address _token) external view returns (uint256[] memory) {
AssetsInfo memory assetsInfo = userAssetsInfo[_user][_token];
return assetsInfo.pendingClaimQueueIDs;
}
function getCurrentRewardRate(address _token) external view returns (uint256, uint256) {
RewardRateState[] memory rewardRateStateArray = rewardRateState[_token];
RewardRateState memory currentRewardRateState = rewardRateStateArray[rewardRateStateArray.length - 1];
return (currentRewardRateState.rewardRate, BASE);
}
function getClaimQueueInfo(uint256 _index) external view returns(ClaimItem memory) {
return claimQueue[_index];
}
function getTVL(address _token) external view returns(uint256){
return tvl[_token];
}
receive() external payable {
revert("No ether should be here");
}
}
文件 14 的 14:utils.sol
pragma solidity =0.8.28;
library Utils {
function Add(uint _a, uint _b) public pure returns (uint256) {
assembly {
mstore(0x0, add(_a, _b))
return(0x0, 32)
}
}
function CheckIsZeroAddress(address _address) public pure returns (bool) {
assembly {
if iszero(_address) {
mstore(0x00, 0x20)
mstore(0x20, 0x0c)
mstore(0x40, 0x5a65726f20416464726573730000000000000000000000000000000000000000)
revert(0x00, 0x60)
}
}
return true;
}
function MustGreaterThanZero(uint256 _value) internal pure returns (bool result) {
assembly {
result := iszero(iszero(_value))
}
}
}
{
"compilationTarget": {
"src/Vault.sol": "Vault"
},
"evmVersion": "paris",
"libraries": {
"src/utils.sol:Utils": "0x12b4524bffaf804edeabb859d0684f5e8345efbf"
},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@openzeppelin/=lib/openzeppelin-contracts/",
":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
":ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
":forge-std/=lib/forge-std/src/",
":halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/"
]
}
[{"inputs":[{"internalType":"address[]","name":"_tokens","type":"address[]"},{"internalType":"uint256[]","name":"_newRewardRate","type":"uint256[]"},{"internalType":"uint256[]","name":"_minStakeAmount","type":"uint256[]"},{"internalType":"uint256[]","name":"_maxStakeAmount","type":"uint256[]"},{"internalType":"address","name":"_admin","type":"address"},{"internalType":"address","name":"_bot","type":"address"},{"internalType":"address","name":"_ceffu","type":"address"},{"internalType":"uint256","name":"_waitingTime","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"uint256","name":"_minAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_maxAmount","type":"uint256"}],"name":"AddSupportedToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"address","name":"_ceffu","type":"address"},{"indexed":true,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"CeffuReceive","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_id","type":"uint256"}],"name":"ClaimAssets","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"address","name":"_receiver","type":"address"}],"name":"EmergencyWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_user","type":"address"},{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_id","type":"uint256"}],"name":"RequestClaim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Stake","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_oldCeffu","type":"address"},{"indexed":false,"internalType":"address","name":"_newCeffu","type":"address"}],"name":"UpdateCeffu","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"uint256","name":"_oldRewardRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newRewardRate","type":"uint256"}],"name":"UpdateRewardRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"uint256","name":"_oldMinAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_oldMaxAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newMinAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newMaxAmount","type":"uint256"}],"name":"UpdateStakeLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_oldWaitingTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newWaitingTIme","type":"uint256"}],"name":"UpdateWaitingTime","type":"event"},{"inputs":[],"name":"BOT_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WAITING_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_minAmount","type":"uint256"},{"internalType":"uint256","name":"_maxAmount","type":"uint256"}],"name":"addSupportedToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ceffu","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_queueID","type":"uint256"}],"name":"claim_41202704","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getClaimHistory","outputs":[{"components":[{"internalType":"bool","name":"isDone","type":"bool"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"totalAmount","type":"uint256"},{"internalType":"uint256","name":"principalAmount","type":"uint256"},{"internalType":"uint256","name":"rewardAmount","type":"uint256"},{"internalType":"uint256","name":"requestTime","type":"uint256"},{"internalType":"uint256","name":"claimTime","type":"uint256"}],"internalType":"struct ClaimItem","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"getClaimHistoryLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"getClaimQueueIDs","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getClaimQueueInfo","outputs":[{"components":[{"internalType":"bool","name":"isDone","type":"bool"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"totalAmount","type":"uint256"},{"internalType":"uint256","name":"principalAmount","type":"uint256"},{"internalType":"uint256","name":"rewardAmount","type":"uint256"},{"internalType":"uint256","name":"requestTime","type":"uint256"},{"internalType":"uint256","name":"claimTime","type":"uint256"}],"internalType":"struct ClaimItem","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"getClaimableAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"getClaimableRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_targetTime","type":"uint256"}],"name":"getClaimableRewardsWithTargetTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getContractBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getCurrentRewardRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getStakeHistory","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"stakeTimestamp","type":"uint256"}],"internalType":"struct StakeItem","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"getStakeHistoryLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"getStakedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getTVL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"getTotalRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastClaimQueueID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxStakeAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"minStakeAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"requestClaim_8135334","outputs":[{"internalType":"uint256","name":"_returnID","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newCeffu","type":"address"}],"name":"setCeffu","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_newRewardRate","type":"uint256"}],"name":"setRewardRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_minAmount","type":"uint256"},{"internalType":"uint256","name":"_maxAmount","type":"uint256"}],"name":"setStakeLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newWaitingTime","type":"uint256"}],"name":"setWaitingTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_stakedAmount","type":"uint256"}],"name":"stake_66380860","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"supportedTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferToCeffu","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]