编译器
0.8.28+commit.7893614a
文件 1 的 16: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 的 16: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 的 16: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 的 16: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 的 16:Errors.sol
pragma solidity ^0.8.20;
library Errors {
error InsufficientBalance(uint256 balance, uint256 needed);
error FailedCall();
error FailedDeployment();
error MissingPrecompile(address);
}
文件 6 的 16: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 的 16: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 的 16:IERC165.sol
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";
文件 9 的 16:IERC20.sol
pragma solidity ^0.8.20;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
文件 10 的 16: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);
event ZkTokenCreated(address indexed _token);
event FlashWithdraw(address indexed _user, address indexed _token, uint256 indexed _amount, uint _fee);
event UpdatePenaltyRate(uint indexed oldRate, uint indexed newRate);
event CancelClaim(address indexed user, address indexed _token, uint256 indexed _amount, uint256 _id);
function stake_66380860(address _token, uint256 _stakedAmount) external;
function requestClaim_8135334(address _token, uint256 _amount) external returns(uint256);
function cancelClaim(uint _queueId, address _token) external;
function claim_41202704(uint256 _queueID, address token) external;
function flashWithdrawWithPenalty(address _token, uint256 _amount) external;
function sendLpTokens(address token, address to, uint amount, bool flag) external;
function transferToCeffu(address _token, uint256 _amount) external;
function emergencyWithdraw(address _token, address _receiver) external;
function addSupportedToken(address _token, uint256 _minAmount, uint256 _maxAmount, address _zkToken) external;
function setRewardRate(address _token, uint256 _newRewardRate) external;
function setPenaltyRate(uint256 _newRate) external;
function setAirdropAddr(address newAirdropAddr) external;
function setStakeLimit(address _token, uint256 _minAmount, uint256 _maxAmount) external;
function setCeffu(address _newCeffu) external;
function setWaitingTime(uint256 _newWaitingTIme) external;
function pause() external;
function unpause() external;
function convertToShares(uint tokenAmount, address _token) external view returns (uint256);
function convertToAssets(uint shares, address _token) external view returns (uint256);
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);
function getZKTokenAmount(address _user, address _token) external view returns(uint256);
function lastClaimQueueID() external view returns(uint256);
}
文件 11 的 16:IWithdrawVault.sol
pragma solidity =0.8.28;
interface IWithdrawVault {
function transfer(address, address, uint256) external;
function addSupportedToken(address) external;
function setVault(address) external;
function getSupportedTokens() external view returns (address[] memory);
function getBalance(address) external view returns (uint256);
function emergencyWithdraw(address, address, uint) external;
function transferToCeffu(address token, uint amount)external;
}
文件 12 的 16:IzkToken.sol
pragma solidity =0.8.28;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IzkToken is IERC20 {
function mint(address to, uint256 amount) external;
function burn(address from, uint256 amount) external;
function setMinter(address minter, address vault) external;
function updateAllowance(address from, address to, uint256 amount) external;
}
文件 13 的 16: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());
}
}
文件 14 的 16: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);
}
}
文件 15 的 16: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 "./IzkToken.sol";
import "./IWithdrawVault.sol";
import "./IVault.sol";
import "./utils.sol";
contract Vault is Pausable, AccessControl, IVault {
using SafeERC20 for IERC20;
using SafeERC20 for IzkToken;
mapping(address => uint256) private tvl;
mapping(address => bool) public supportedTokens;
mapping(address => IzkToken) public supportedTokenToZkToken;
mapping(address => address) public zkTokenToSupportedToken;
uint256 public lastClaimQueueID = 10_000;
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 private constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
bytes32 private constant BOT_ROLE = keccak256("BOT_ROLE");
address private ceffu;
uint256 private penaltyRate = 50;
mapping(address => uint256) public minStakeAmount;
mapping(address => uint256) public maxStakeAmount;
uint256 public WAITING_TIME;
uint256 private constant BASE = 10_000;
mapping(address => uint256) public totalStakeAmountByToken;
mapping(address => uint256) private _lastRewardUpdatedTime;
mapping(address => uint256) public totalRewardsAmountByToken;
uint256 private initialTime;
IWithdrawVault private withdrawVault;
address private airdropAddr;
bool flashNotEnable;
bool cancelNotEnable = true;
constructor(
address[] memory _tokens,
address[] memory _zkTokens,
uint256[] memory _newRewardRate,
uint256[] memory _minStakeAmount,
uint256[] memory _maxStakeAmount,
address _admin,
address _bot,
address _ceffu,
uint256 _waitingTime,
address payable withdrawVaultAddress,
address _airdropAddr
) {
Utils.CheckIsZeroAddress(_ceffu);
Utils.CheckIsZeroAddress(_admin);
Utils.CheckIsZeroAddress(_bot);
airdropAddr = _airdropAddr;
uint256 len = _tokens.length;
require(Utils.MustGreaterThanZero(len));
require(
len == _newRewardRate.length &&
len == _minStakeAmount.length &&
len == _maxStakeAmount.length &&
len == _zkTokens.length
);
_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);
initialTime = block.timestamp;
for (uint256 i = 0; i < len; i++) {
require(_minStakeAmount[i] < _maxStakeAmount[i]);
address token = _tokens[i];
minStakeAmount[token] = _minStakeAmount[i];
maxStakeAmount[token] = _maxStakeAmount[i];
supportedTokens[token] = true;
emit AddSupportedToken(token, _minStakeAmount[i], _maxStakeAmount[i]);
IzkToken tokenTemp = IzkToken(_zkTokens[i]);
supportedTokenToZkToken[token] = tokenTemp;
zkTokenToSupportedToken[address(tokenTemp)] = token;
emit ZkTokenCreated(address(tokenTemp));
RewardRateState memory rewardRateItem = RewardRateState({
token: token,
rewardRate: _newRewardRate[i],
updatedTime: block.timestamp
});
rewardRateState[token].push(rewardRateItem);
emit UpdateRewardRate(token, 0, _newRewardRate[i]);
_lastRewardUpdatedTime[token] = block.timestamp;
}
withdrawVault = IWithdrawVault(withdrawVaultAddress);
_pause();
}
modifier OnlyFlashEnable{
require(!flashNotEnable, "flash withdraw not enable");
_;
}
modifier OnlyCancelEnable{
require(!cancelNotEnable, "cancel claim not enable");
_;
}
event FlashStatusChanged(bool indexed oldStatus, bool indexed newStatus);
event CancelStatusChanged(bool indexed oldStatus, bool indexed newStatus);
function setFlashEnable(bool _enable) external onlyRole(DEFAULT_ADMIN_ROLE){
require(_enable != flashNotEnable, "nothing changed");
bool oldStatus = flashNotEnable;
flashNotEnable = _enable;
emit FlashStatusChanged(oldStatus, _enable);
}
function setCancelEnable(bool _enable) external onlyRole(DEFAULT_ADMIN_ROLE){
require(_enable != cancelNotEnable, "nothing changed");
bool oldStatus = cancelNotEnable;
cancelNotEnable = _enable;
emit CancelStatusChanged(oldStatus, _enable);
}
modifier onlySupportedToken(address _token) {
require(supportedTokens[_token], "Unsupported");
_;
}
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]);
require(Utils.Add(currentStakedAmount, _stakedAmount) <= maxStakeAmount[_token]);
IERC20(_token).safeTransferFrom(msg.sender, address(this), _stakedAmount);
_updateRewardState(msg.sender, _token);
uint256 exchangeRate = _getExchangeRate(_token);
totalStakeAmountByToken[_token] += _stakedAmount;
uint256 mintAmount = _stakedAmount * 1e18 / exchangeRate;
supportedTokenToZkToken[_token].mint(msg.sender, mintAmount);
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);
uint256 exchangeRate = _getExchangeRate(_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;
(totalAmount, , ) = _handleWithdraw(_amount, assetsInfo, queueItem, false);
require(totalAmount > 0, "No assets to withdraw");
assetsInfo.pendingClaimQueueIDs.push(lastClaimQueueID);
totalStakeAmountByToken[_token] -= queueItem.principalAmount;
totalRewardsAmountByToken[_token] -= queueItem.rewardAmount;
uint256 sharesToBurn = totalAmount * 1e18 / exchangeRate;
uint256 zkBalance = supportedTokenToZkToken[_token].balanceOf(msg.sender);
if(sharesToBurn > zkBalance || assetsInfo.stakedAmount == 0) sharesToBurn = zkBalance;
supportedTokenToZkToken[_token].burn(msg.sender, sharesToBurn);
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 cancelClaim(uint256 _queueId, address _token) external whenNotPaused OnlyCancelEnable{
ClaimItem memory claimItem = claimQueue[_queueId];
delete 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));
require(claimItem.user == msg.sender);
require(!claimItem.isDone, "claimed");
require(token == _token, "wrong token");
for(uint256 i = 0; i < pendingClaimQueueIDs.length; i++) {
if(pendingClaimQueueIDs[i] == _queueId) {
assetsInfo.pendingClaimQueueIDs[i] = pendingClaimQueueIDs[pendingClaimQueueIDs.length-1];
assetsInfo.pendingClaimQueueIDs.pop();
break;
}
}
uint256 principal = claimItem.principalAmount;
uint256 reward = claimItem.rewardAmount;
assetsInfo.stakedAmount += principal;
assetsInfo.accumulatedReward += reward;
assetsInfo.lastRewardUpdateTime = block.timestamp;
_updateRewardState(msg.sender, _token);
uint256 exchangeRate = _getExchangeRate(_token);
uint256 amountToMint = (principal + reward) * 1e18 / exchangeRate;
totalStakeAmountByToken[_token] += principal;
totalRewardsAmountByToken[_token] += reward;
supportedTokenToZkToken[_token].mint(msg.sender, amountToMint);
emit CancelClaim(msg.sender, _token, principal + reward, _queueId);
}
function claim_41202704(uint256 _queueID, address _token) 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));
require(block.timestamp >= claimItem.claimTime);
require(claimItem.user == msg.sender);
require(!claimItem.isDone, "claimed");
require(token == _token, "wrong token");
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
})
);
withdrawVault.transfer(token, msg.sender, claimItem.totalAmount);
emit ClaimAssets(msg.sender, token, claimItem.totalAmount, _queueID);
}
function flashWithdrawWithPenalty(
address _token,
uint256 _amount
) external onlySupportedToken(_token) whenNotPaused OnlyFlashEnable{
AssetsInfo storage assetsInfo = userAssetsInfo[msg.sender][_token];
_updateRewardState(msg.sender, _token);
uint256 exchangeRate = _getExchangeRate(_token);
uint256 currentStakedAmount = assetsInfo.stakedAmount;
uint256 currentAccumulatedRewardAmount = assetsInfo.accumulatedReward;
require(
Utils.MustGreaterThanZero(_amount) &&
(_amount <= Utils.Add(currentStakedAmount, currentAccumulatedRewardAmount) || _amount == type(uint256).max)
);
uint256 totalAmount = _amount;
uint256 principalAmount;
uint256 rewardAmount;
(totalAmount, principalAmount, rewardAmount) = _handleWithdraw(_amount, assetsInfo, claimQueue[lastClaimQueueID], true);
require(totalAmount > 0, "no assets to withdraw");
totalStakeAmountByToken[_token] -= principalAmount;
totalRewardsAmountByToken[_token] -= rewardAmount;
uint256 sharesToBurn = (totalAmount * 1e18) / exchangeRate;
uint256 zkBalance = supportedTokenToZkToken[_token].balanceOf(msg.sender);
if(sharesToBurn > zkBalance || assetsInfo.stakedAmount == 0) sharesToBurn = zkBalance;
supportedTokenToZkToken[_token].burn(msg.sender, sharesToBurn);
uint256 amountToSent = totalAmount * (BASE - penaltyRate) / BASE;
uint256 fee = totalAmount - amountToSent;
require(getContractBalance(_token) >= amountToSent, "not enough balance");
IERC20(_token).safeTransfer(msg.sender, amountToSent);
tvl[_token] -= principalAmount;
assetsInfo.claimHistory.push(
ClaimItem({
isDone: true,
token: _token,
user: msg.sender,
totalAmount: totalAmount,
principalAmount: principalAmount,
rewardAmount: rewardAmount,
requestTime: block.timestamp,
claimTime: block.timestamp
})
);
emit FlashWithdraw(msg.sender, _token, totalAmount, fee);
}
function _handleWithdraw(
uint256 _amount,
AssetsInfo storage assetsInfo,
ClaimItem storage queueItem,
bool isFlash
) internal returns(uint256, uint256, uint256){
uint256 totalAmount = _amount;
uint256 principalAmount;
uint256 rewardAmount;
uint256 currentAccumulatedRewardAmount = assetsInfo.accumulatedReward;
if(_amount == type(uint256).max){
totalAmount = Utils.Add(currentAccumulatedRewardAmount, assetsInfo.stakedAmount);
rewardAmount = currentAccumulatedRewardAmount;
assetsInfo.accumulatedReward = 0;
principalAmount = assetsInfo.stakedAmount;
assetsInfo.stakedAmount = 0;
}else if(currentAccumulatedRewardAmount >= _amount) {
assetsInfo.accumulatedReward -= _amount;
rewardAmount = _amount;
} else {
rewardAmount = currentAccumulatedRewardAmount;
assetsInfo.accumulatedReward = 0;
uint256 difference = _amount - currentAccumulatedRewardAmount;
assetsInfo.stakedAmount -= difference;
principalAmount = difference;
}
if(!isFlash) {
queueItem.rewardAmount = rewardAmount;
queueItem.principalAmount = principalAmount;
}
return(totalAmount, principalAmount, rewardAmount);
}
function _updateRewardState(address _user, address _token) internal {
AssetsInfo storage assetsInfo = userAssetsInfo[_user][_token];
uint256 newAccumulatedReward = 0;
uint256 newAccumulatedRewardForAll;
if(assetsInfo.lastRewardUpdateTime != 0) {
newAccumulatedReward = _getClaimableRewards(_user, _token);
}
newAccumulatedRewardForAll = _getClaimableRewards(address(this), _token);
assetsInfo.accumulatedReward = newAccumulatedReward;
assetsInfo.lastRewardUpdateTime = block.timestamp;
_lastRewardUpdatedTime[_token] = block.timestamp;
totalRewardsAmountByToken[_token] = newAccumulatedRewardForAll;
}
function _getExchangeRate(address _token) internal view returns(uint256 exchangeRate){
uint256 totalSupplyZKToken = supportedTokenToZkToken[_token].totalSupply();
if (totalSupplyZKToken == 0) {
exchangeRate = 1e18;
} else {
exchangeRate = ((totalStakeAmountByToken[_token] + totalRewardsAmountByToken[_token]) * 1e18) / totalSupplyZKToken;
}
}
function convertToShares(uint256 tokenAmount, address _token) public view returns(uint256 shares) {
uint256 totalSupplyZKToken = supportedTokenToZkToken[_token].totalSupply();
uint256 totalStaked = totalStakeAmountByToken[_token];
uint256 totalRewards = _getClaimableRewards(address(this), _token);
uint256 exchangeRate = totalSupplyZKToken == 0 ?
1e18 : (totalStaked + totalRewards) * 1e18 / totalSupplyZKToken;
shares = (tokenAmount * 1e18) / exchangeRate;
}
function convertToAssets(uint256 shares, address _token) public view returns(uint256 tokenAmount) {
uint256 totalSupplyZKToken = supportedTokenToZkToken[_token].totalSupply();
uint256 totalStaked = totalStakeAmountByToken[_token];
uint256 totalRewards = _getClaimableRewards(address(this), _token);
uint256 exchangeRate = totalSupplyZKToken == 0 ?
1e18 : (totalStaked + totalRewards) * 1e18 / totalSupplyZKToken;
tokenAmount = (shares * exchangeRate) / 1e18;
}
function transferOrTransferFrom(address token, address from, address to, uint256 amount) public returns (bool) {
require(from != to, "from can not be same as the to");
require(amount > 0, "amount must be greater than 0");
uint256 tokenBefore = getZKTokenAmount(from, token);
require(tokenBefore >= amount, "balance");
if(msg.sender != from){
require(supportedTokenToZkToken[token].allowance(from, msg.sender) >= amount, "allowance");
supportedTokenToZkToken[token].updateAllowance(from, msg.sender, amount);
supportedTokenToZkToken[token].transferFrom(from, to, amount);
}else{
supportedTokenToZkToken[token].transferFrom(msg.sender, to, amount);
}
_assetsInfoUpdate(token, from, to, amount, tokenBefore);
return true;
}
function sendLpTokens(address token, address to, uint256 amount, bool flag) external {
require(msg.sender == airdropAddr);
supportedTokenToZkToken[token].transferFrom(airdropAddr, to, amount);
AssetsInfo storage assetsInfo = userAssetsInfo[to][token];
if(flag == true){
assetsInfo.lastRewardUpdateTime = initialTime;
}else{
_updateRewardState(to, token);
}
assetsInfo.stakedAmount += amount;
totalStakeAmountByToken[token] += amount;
tvl[token] += amount;
}
function _assetsInfoUpdate(address token, address from, address to, uint256 amount, uint256 tokenBefore) internal{
_updateRewardState(from, token);
_updateRewardState(to, token);
AssetsInfo storage assetsInfoFrom = userAssetsInfo[from][token];
uint256 stakedAmount = assetsInfoFrom.stakedAmount;
uint256 accumulatedReward = assetsInfoFrom.accumulatedReward;
AssetsInfo storage assetsInfoTo = userAssetsInfo[to][token];
uint256 percent = amount * 1e18 / tokenBefore;
uint256 deltaStaked = (stakedAmount * percent / 1e18);
uint256 deltaReward = (accumulatedReward * percent / 1e18);
assetsInfoTo.stakedAmount += deltaStaked;
assetsInfoFrom.stakedAmount -= deltaStaked;
assetsInfoTo.accumulatedReward += deltaReward;
assetsInfoFrom.accumulatedReward -= deltaReward;
assetsInfoTo.lastRewardUpdateTime = block.timestamp ;
}
function transferToCeffu(
address _token,
uint256 _amount
) external onlySupportedToken(_token) onlyRole(BOT_ROLE) {
require(Utils.MustGreaterThanZero(_amount), "must > 0");
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,
address _zkToken
) external onlyRole(DEFAULT_ADMIN_ROLE) {
Utils.CheckIsZeroAddress(_token);
require(!supportedTokens[_token], "Supported");
supportedTokens[_token] = true;
setStakeLimit(_token, _minAmount, _maxAmount);
emit AddSupportedToken(_token, _minAmount, _maxAmount);
IzkToken tokenTemp = IzkToken(_zkToken);
supportedTokenToZkToken[_token] = tokenTemp;
zkTokenToSupportedToken[address(tokenTemp)] = _token;
emit ZkTokenCreated(address(tokenTemp));
}
function setRewardRate(
address _token,
uint256 _newRewardRate
) external onlySupportedToken(_token) onlyRole(DEFAULT_ADMIN_ROLE) {
require(_newRewardRate < BASE, "Invalid rate");
RewardRateState[] memory rewardRateArray = rewardRateState[_token];
uint256 currentRewardRate = rewardRateArray[rewardRateArray.length - 1].rewardRate;
require(currentRewardRate != _newRewardRate && Utils.MustGreaterThanZero(_newRewardRate), "Invalid new rate");
RewardRateState memory rewardRateItem = RewardRateState({
updatedTime: block.timestamp,
token: _token,
rewardRate: _newRewardRate
});
rewardRateState[_token].push(rewardRateItem);
emit UpdateRewardRate(_token, currentRewardRate, _newRewardRate);
}
function setAirdropAddr(address newAirdropAddr) external onlyRole(DEFAULT_ADMIN_ROLE) {
airdropAddr = newAirdropAddr;
}
function setPenaltyRate(uint256 newRate) external onlyRole(DEFAULT_ADMIN_ROLE) {
require(newRate <= BASE && newRate != penaltyRate, "Invalid");
emit UpdatePenaltyRate(penaltyRate, newRate);
penaltyRate = newRate;
}
function setCeffu(address _newCeffu) external onlyRole(DEFAULT_ADMIN_ROLE) {
Utils.CheckIsZeroAddress(_newCeffu);
require(_newCeffu != ceffu);
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);
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, "Invalid");
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) {
uint256 currentStakedAmount;
uint256 lastRewardUpdate;
uint256 currentRewardAmount;
if(_user != address(this)){
AssetsInfo memory assetsInfo = userAssetsInfo[_user][_token];
currentStakedAmount = assetsInfo.stakedAmount;
lastRewardUpdate = assetsInfo.lastRewardUpdateTime;
currentRewardAmount = assetsInfo.accumulatedReward;
} else {
currentStakedAmount = totalStakeAmountByToken[_token];
lastRewardUpdate = _lastRewardUpdatedTime[_token];
currentRewardAmount = totalRewardsAmountByToken[_token];
}
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 - lastRewardUpdate;
uint256 reward = calculateReward(
currentStakedAmount,
currentRewardRateState.rewardRate,
elapsedTime
);
return currentRewardAmount + 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{
currentRewardAmount += tempReward;
}
}
uint256 elapsedTime = block.timestamp - currentRewardRateState.updatedTime;
uint256 reward = calculateReward(
currentStakedAmount,
currentRewardRateState.rewardRate,
elapsedTime
);
return currentRewardAmount + 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 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) public view onlySupportedToken(_token) returns (uint256) {
AssetsInfo memory stakeInfo = userAssetsInfo[_user][_token];
return stakeInfo.stakedAmount;
}
function getZKTokenAmount(address _user, address _token) public view onlySupportedToken(_token) returns (uint256) {
return supportedTokenToZkToken[_token].balanceOf(_user);
}
function getContractBalance(address _token) public 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, "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, "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) public 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();
}
}
文件 16 的 16: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": "0x8724d1b62ddf87d830811c9dcb2e1a6494c9c117"
},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 20
},
"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/"
],
"viaIR": true
}
[{"inputs":[{"internalType":"address[]","name":"_tokens","type":"address[]"},{"internalType":"address[]","name":"_zkTokens","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"},{"internalType":"address payable","name":"withdrawVaultAddress","type":"address"},{"internalType":"address","name":"_airdropAddr","type":"address"}],"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":"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":"CancelClaim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bool","name":"oldStatus","type":"bool"},{"indexed":true,"internalType":"bool","name":"newStatus","type":"bool"}],"name":"CancelStatusChanged","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":true,"internalType":"bool","name":"oldStatus","type":"bool"},{"indexed":true,"internalType":"bool","name":"newStatus","type":"bool"}],"name":"FlashStatusChanged","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":"_fee","type":"uint256"}],"name":"FlashWithdraw","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":true,"internalType":"uint256","name":"oldRate","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newRate","type":"uint256"}],"name":"UpdatePenaltyRate","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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"}],"name":"ZkTokenCreated","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_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"},{"internalType":"address","name":"_zkToken","type":"address"}],"name":"addSupportedToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_queueId","type":"uint256"},{"internalType":"address","name":"_token","type":"address"}],"name":"cancelClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_queueID","type":"uint256"},{"internalType":"address","name":"_token","type":"address"}],"name":"claim_41202704","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"_token","type":"address"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"address","name":"_token","type":"address"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","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":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"flashWithdrawWithPenalty","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":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"getZKTokenAmount","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":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"flag","type":"bool"}],"name":"sendLpTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAirdropAddr","type":"address"}],"name":"setAirdropAddr","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_enable","type":"bool"}],"name":"setCancelEnable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newCeffu","type":"address"}],"name":"setCeffu","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_enable","type":"bool"}],"name":"setFlashEnable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newRate","type":"uint256"}],"name":"setPenaltyRate","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":"supportedTokenToZkToken","outputs":[{"internalType":"contract IzkToken","name":"","type":"address"}],"stateMutability":"view","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":"","type":"address"}],"name":"totalRewardsAmountByToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalStakeAmountByToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferOrTransferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","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"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"zkTokenToSupportedToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]