编译器
0.8.23+commit.f704f362
文件 1 的 10: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;
}
}
文件 2 的 10:FishStaking.sol
pragma solidity 0.8.23;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "./utils/Proxyable.sol";
import "./interfaces/IFishdRYFT.sol";
contract FishStaking is Ownable, ReentrancyGuard, Proxyable {
struct User {
uint256[] nftIds;
uint256 rewardDebt;
uint256 fishWeight;
uint256 claimedRewards;
uint256 lastStakeTime;
}
address public immutable fishdRYFTContract;
address public rewardToken;
address public treasuryAddress;
bool public stakingEnabled;
uint256 accTokensPerShare;
uint256 public blocksPerDay = 45000;
uint256 public distributionDurationDays = 30;
uint256 lastRewardBlock;
uint256 public rewardPerBlock;
uint256 public stakeLockPeriod = 10 days;
uint256 public startBlock;
uint256 public totalFishWeight;
uint256 public totalReward;
mapping(address => User) public users;
error CannotChangeStartBlock();
error CannotWithdrawRewardToken();
error FailedSendingETH();
error InsufficientBalance();
error StakeLocked();
error StakingDisabled();
error ZeroAddress();
event Claim(address indexed user, uint256 indexed amount);
event EmergencyWithdraw(address indexed user);
event DepositRewards(
uint256 indexed amount,
uint256 indexed newRewardPerBlock
);
event ProxyStake(address user, uint256 nftId, uint256 amount);
event Stake(address indexed user, uint256 nftId, uint256 amount);
event Unstake(address indexed user);
event WithdrawETH(address indexed sender, uint256 indexed balance);
modifier nonZeroAddress(address _address) {
if (_address == address(0)) revert ZeroAddress();
_;
}
modifier updateRewardPerBlock() {
(uint256 blockReward, bool update) = getRewardPerBlock();
if (update) {
rewardPerBlock = blockReward;
}
_;
}
constructor(
address fishdRYFTContract_,
address rewardToken_,
address treasuryAddress_
)
nonZeroAddress(fishdRYFTContract_)
nonZeroAddress(rewardToken_)
nonZeroAddress(treasuryAddress_)
Ownable(msg.sender)
{
fishdRYFTContract = fishdRYFTContract_;
rewardToken = rewardToken_;
treasuryAddress = treasuryAddress_;
}
function onERC1155Received(
address,
address,
uint256,
uint256,
bytes memory
) public virtual returns (bytes4) {
return this.onERC1155Received.selector;
}
function onERC1155BatchReceived(
address,
address,
uint256[] memory,
uint256[] memory,
bytes memory
) public virtual returns (bytes4) {
return this.onERC1155BatchReceived.selector;
}
function updateRewards() public updateRewardPerBlock {
if (block.number <= lastRewardBlock) {
return;
}
if (totalFishWeight == 0) {
lastRewardBlock = block.number;
return;
}
uint256 multiplier = block.number - (lastRewardBlock);
uint256 tokenReward = multiplier * rewardPerBlock;
accTokensPerShare =
accTokensPerShare +
((tokenReward * 1e12) / totalFishWeight);
lastRewardBlock = block.number;
}
function getRewardPerBlock() public view returns (uint256, bool) {
if (block.number < startBlock || startBlock == 0 || totalReward == 0) {
return (0, false);
}
return (rewardPerBlock, true);
}
function claim() external nonReentrant {
updateRewards();
User storage user = users[_msgSender()];
if (user.fishWeight == 0) return;
uint256 pending = (user.fishWeight * accTokensPerShare) /
1e12 -
user.rewardDebt;
if (pending > 0) {
user.rewardDebt += pending;
IERC20(rewardToken).transfer(_msgSender(), pending);
user.claimedRewards += pending;
}
emit Claim(_msgSender(), pending);
}
function depositRewards(uint256 amount_) external onlyProxy {
updateRewards();
IERC20(rewardToken).transferFrom(_msgSender(), address(this), amount_);
totalReward += amount_;
uint256 newRewardPerBlock = ((amount_ * 1e12) /
(distributionDurationDays * blocksPerDay)) / 1e12;
rewardPerBlock += newRewardPerBlock;
emit DepositRewards(amount_, newRewardPerBlock);
}
function emergencyWithdraw() public {
User storage user = users[_msgSender()];
totalFishWeight -= user.fishWeight;
user.fishWeight = 0;
user.rewardDebt = 0;
_withdrawUserNfts(user);
emit EmergencyWithdraw(_msgSender());
}
function getAPY() external view returns (uint256) {
if (totalReward == 0) return 0;
(uint256 blockReward, ) = getRewardPerBlock();
uint256 rewardForYear = blockReward * blocksPerDay * 365;
return (rewardForYear * 100) / totalFishWeight;
}
function getWPY() external view returns (uint256) {
if (totalReward == 0) return 0;
(uint256 blockReward, ) = getRewardPerBlock();
uint256 rewardForWeek = blockReward * blocksPerDay * 7;
return (rewardForWeek * 100) / totalFishWeight;
}
function pendingRewards(address user_) external view returns (uint256) {
uint256 thisAccTokensPerShare = accTokensPerShare;
if (block.number > lastRewardBlock && totalFishWeight != 0) {
uint256 multiplier = block.number - (lastRewardBlock);
(uint256 blockReward, ) = getRewardPerBlock();
uint256 tokenReward = multiplier * blockReward;
thisAccTokensPerShare =
thisAccTokensPerShare +
((tokenReward * 1e12) / totalFishWeight);
}
User memory user = users[user_];
return
(user.fishWeight * thisAccTokensPerShare) / 1e12 - user.rewardDebt;
}
function proxyStake(
address user_,
uint256 nftId_,
uint256 amount_
) external onlyProxy nonReentrant {
_stake(user_, nftId_, amount_);
emit ProxyStake(user_, nftId_, amount_);
}
function setBlocksPerDay(uint256 _blocksPerDay) external onlyOwner {
require(
_blocksPerDay >= 1000 && _blocksPerDay <= 40000,
"Value is outside of range 1000-40000"
);
blocksPerDay = _blocksPerDay;
}
function setDistributionDurationDays(uint256 _days) external onlyOwner {
require(_days >= 1 && _days <= 365, "Value is outside of range 1-365");
distributionDurationDays = _days;
}
function setStakeLockDuration(uint256 _stakeLockDays) external onlyOwner {
stakeLockPeriod = _stakeLockDays;
}
function setStartBlock(uint256 _startBlock) external onlyOwner {
if (startBlock != 0) revert CannotChangeStartBlock();
startBlock = _startBlock;
}
function stake(uint256 nftId_, uint256 amount_) external nonReentrant {
_stake(_msgSender(), nftId_, amount_);
emit Stake(_msgSender(), nftId_, amount_);
}
function stakeAll(uint256[] calldata nftIds_) external nonReentrant {
for (uint256 i; i < nftIds_.length; ++i) {
uint256 bal = IERC1155(fishdRYFTContract).balanceOf(
_msgSender(),
nftIds_[i]
);
_stake(_msgSender(), nftIds_[i], bal);
}
emit Stake(_msgSender(), 0, nftIds_.length);
}
function toggleStakingEnabled() external onlyOwner {
stakingEnabled = !stakingEnabled;
}
function transferTokens(
address tokenAddr_
) external nonZeroAddress(tokenAddr_) onlyOwner {
if (tokenAddr_ == rewardToken) revert CannotWithdrawRewardToken();
IERC20(tokenAddr_).transfer(
treasuryAddress,
IERC20(tokenAddr_).balanceOf(address(this))
);
}
function unstake() external nonReentrant {
User storage user = users[_msgSender()];
if (user.fishWeight == 0) {
return;
}
if (block.timestamp - user.lastStakeTime < stakeLockPeriod) {
revert StakeLocked();
}
updateRewards();
uint256 pending = (user.fishWeight * accTokensPerShare) /
1e12 -
user.rewardDebt;
user.rewardDebt = 0;
totalFishWeight -= user.fishWeight;
user.fishWeight = 0;
_withdrawUserNfts(user);
if (pending > 0) {
pending = pending > IERC20(rewardToken).balanceOf(address(this))
? IERC20(rewardToken).balanceOf(address(this))
: pending;
IERC20(rewardToken).transfer(_msgSender(), pending);
user.claimedRewards += pending;
}
emit Unstake(_msgSender());
}
function withdrawETH() external {
if (treasuryAddress == address(0)) revert ZeroAddress();
uint256 bal = address(this).balance;
(bool sent, ) = treasuryAddress.call{value: bal}("");
if (!sent) revert FailedSendingETH();
emit WithdrawETH(_msgSender(), bal);
}
function _stake(address user_, uint256 nftId_, uint256 amount_) private {
if (!stakingEnabled) revert StakingDisabled();
if (
IERC1155(fishdRYFTContract).balanceOf(_msgSender(), nftId_) <
amount_
) revert InsufficientBalance();
if (fishdRYFTContract == address(0)) revert ZeroAddress();
IERC1155(fishdRYFTContract).safeTransferFrom(
_msgSender(),
address(this),
nftId_,
amount_,
""
);
updateRewards();
User storage user = users[user_];
user.lastStakeTime = block.timestamp;
uint256 pending;
if (user.fishWeight > 0) {
pending =
(user.fishWeight * accTokensPerShare) /
1e12 -
user.rewardDebt;
}
for (uint256 i; i < amount_; ++i) {
user.nftIds.push(nftId_);
}
uint256 weight = IFishdRYFT(fishdRYFTContract).getTokenWrapAmount(
nftId_
) * amount_;
totalFishWeight += weight;
user.fishWeight += weight;
user.rewardDebt = (user.fishWeight * accTokensPerShare) / 1e12;
if (pending > 0) {
pending = pending > IERC20(rewardToken).balanceOf(address(this))
? IERC20(rewardToken).balanceOf(address(this))
: pending;
IERC20(rewardToken).transfer(user_, pending);
user.claimedRewards += pending;
}
}
function _withdrawUserNfts(User storage user_) private {
if (user_.nftIds.length == 0) {
return;
}
uint256[] memory values = new uint256[](user_.nftIds.length);
for (uint256 i; i < user_.nftIds.length; ++i) {
values[i] = 1;
}
IERC1155(fishdRYFTContract).safeBatchTransferFrom(
address(this),
_msgSender(),
user_.nftIds,
values,
""
);
delete user_.nftIds;
}
}
文件 3 的 10:IERC1155.sol
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
interface IERC1155 is IERC165 {
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
event URI(string value, uint256 indexed id);
function balanceOf(address account, uint256 id) external view returns (uint256);
function balanceOfBatch(
address[] calldata accounts,
uint256[] calldata ids
) external view returns (uint256[] memory);
function setApprovalForAll(address operator, bool approved) external;
function isApprovedForAll(address account, address operator) external view returns (bool);
function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external;
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external;
}
文件 4 的 10:IERC1155Receiver.sol
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
interface IERC1155Receiver is IERC165 {
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}
文件 5 的 10:IERC165.sol
pragma solidity ^0.8.20;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 6 的 10: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);
}
文件 7 的 10:IFishdRYFT.sol
pragma solidity 0.8.23;
interface IFishdRYFT {
function getTokenWrapAmount(
uint256 _fishId
) external view returns (uint256);
}
文件 8 的 10:Ownable.sol
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
error OwnableUnauthorizedAccount(address account);
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 9 的 10:Proxyable.sol
pragma solidity 0.8.23;
import "@openzeppelin/contracts/access/Ownable.sol";
abstract contract Proxyable is Ownable {
mapping(address => bool) public proxyToApproved;
modifier onlyProxy() {
require(proxyToApproved[_msgSender()], "Only proxy");
_;
}
function setProxyState(
address proxyAddress,
bool value
) public virtual onlyOwner {
proxyToApproved[proxyAddress] = value;
}
}
文件 10 的 10:ReentrancyGuard.sol
pragma solidity ^0.8.20;
abstract contract ReentrancyGuard {
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
_status = ENTERED;
}
function _nonReentrantAfter() private {
_status = NOT_ENTERED;
}
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
{
"compilationTarget": {
"contracts/FishStaking.sol": "FishStaking"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"fishdRYFTContract_","type":"address"},{"internalType":"address","name":"rewardToken_","type":"address"},{"internalType":"address","name":"treasuryAddress_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CannotChangeStartBlock","type":"error"},{"inputs":[],"name":"CannotWithdrawRewardToken","type":"error"},{"inputs":[],"name":"FailedSendingETH","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"StakeLocked","type":"error"},{"inputs":[],"name":"StakingDisabled","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newRewardPerBlock","type":"uint256"}],"name":"DepositRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"EmergencyWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"nftId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ProxyStake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"nftId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Stake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Unstake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"uint256","name":"balance","type":"uint256"}],"name":"WithdrawETH","type":"event"},{"inputs":[],"name":"blocksPerDay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"depositRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"distributionDurationDays","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fishdRYFTContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAPY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardPerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWPY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user_","type":"address"}],"name":"pendingRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user_","type":"address"},{"internalType":"uint256","name":"nftId_","type":"uint256"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"proxyStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"proxyToApproved","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardPerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_blocksPerDay","type":"uint256"}],"name":"setBlocksPerDay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_days","type":"uint256"}],"name":"setDistributionDurationDays","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"proxyAddress","type":"address"},{"internalType":"bool","name":"value","type":"bool"}],"name":"setProxyState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakeLockDays","type":"uint256"}],"name":"setStakeLockDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_startBlock","type":"uint256"}],"name":"setStartBlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nftId_","type":"uint256"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"nftIds_","type":"uint256[]"}],"name":"stakeAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakeLockPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"toggleStakingEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalFishWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddr_","type":"address"}],"name":"transferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasuryAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"users","outputs":[{"internalType":"uint256","name":"rewardDebt","type":"uint256"},{"internalType":"uint256","name":"fishWeight","type":"uint256"},{"internalType":"uint256","name":"claimedRewards","type":"uint256"},{"internalType":"uint256","name":"lastStakeTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawETH","outputs":[],"stateMutability":"nonpayable","type":"function"}]