编译器
0.8.18+commit.87f61d96
文件 1 的 5:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 2 的 5:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
文件 3 的 5:IERC721.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC721 is IERC165 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
function safeTransferFrom(address from, address to, uint256 tokenId) external;
function transferFrom(address from, address to, uint256 tokenId) external;
function approve(address to, uint256 tokenId) external;
function setApprovalForAll(address operator, bool approved) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
文件 4 的 5:IERC721Receiver.sol
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 5 的 5:SFAStaking.sol
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
contract SFAStaking is IERC721Receiver {
struct StakingData {
uint256 tokenId;
uint256 timestamp;
}
uint256 public maxSolarPass;
uint256 public maxSolarHead;
address public solarPass;
uint8 public solarPassPayout;
address public solarHead;
uint8 public solarHeadPayout;
address public sfaToken;
uint32 public payoutPeriod;
mapping(address => uint256) public solarPassStaked;
mapping(address => uint256) public solarHeadStaked;
mapping(address => StakingData[5]) public solarPassStakedData;
mapping(address => StakingData[25]) public solarHeadStakedData;
event SolarHeadStaked(address user, uint256 amount);
event SolarPassStaked(address user, uint256 amount);
event RewardsClaimed(address user, uint256 amount);
event WithdrawalAll(address user);
event WithdrawalSolarHead(address user);
event WithdrawalSolarPass(address user);
constructor(
uint256 _maxSolarPass,
uint256 _maxSolarHead,
address _solarPass,
uint8 _solarPassPayout,
address _solarHead,
uint8 _solarHeadPayout,
address _sfaToken,
uint32 _payoutPeriod
) {
maxSolarPass = _maxSolarPass;
maxSolarHead = _maxSolarHead;
solarPass = _solarPass;
solarPassPayout = _solarPassPayout;
solarHead = _solarHead;
solarHeadPayout = _solarHeadPayout;
sfaToken = _sfaToken;
payoutPeriod = _payoutPeriod;
}
function getStakedAmounts(address _user) external view returns(uint256, uint256) {
uint256 userSolarPassesStaked = solarPassStaked[_user];
uint256 userSolarHeadsStaked = solarHeadStaked[_user];
return (userSolarPassesStaked, userSolarHeadsStaked);
}
function stakeSolarHead(uint256 _tokenId) external {
uint256 amountStaked = solarHeadStaked[msg.sender];
require(amountStaked + 1 <= maxSolarHead, "SFA Staking: staked amount exceeds limit");
IERC721(solarHead).safeTransferFrom(msg.sender, address(this), _tokenId);
solarHeadStaked[msg.sender] += 1;
solarHeadStakedData[msg.sender][amountStaked] = StakingData(_tokenId, block.timestamp);
emit SolarHeadStaked(msg.sender, 1);
}
function batchStakeSolarHead(uint256 _amount, uint256[] calldata _tokenIds) external {
uint256 amountStaked = solarHeadStaked[msg.sender];
require(amountStaked + _amount <= maxSolarHead, "SFA Staking: staked amount exceeds limit");
address _solarHead = solarHead;
uint256 i = 0;
while(i < _amount) {
IERC721(_solarHead).safeTransferFrom(msg.sender, address(this), _tokenIds[i]);
solarHeadStaked[msg.sender] += 1;
solarHeadStakedData[msg.sender][amountStaked + i] = StakingData(_tokenIds[i], block.timestamp);
unchecked {
++i;
}
}
emit SolarHeadStaked(msg.sender, _amount);
}
function stakeSolarPass(uint256 _tokenId) external {
uint256 amountStaked = solarPassStaked[msg.sender];
require(amountStaked + 1 <= maxSolarPass, "SFA Staking: staked amount exceeds limit");
IERC721(solarPass).safeTransferFrom(msg.sender, address(this), _tokenId);
solarPassStaked[msg.sender] += 1;
solarPassStakedData[msg.sender][amountStaked] = StakingData(_tokenId, block.timestamp);
emit SolarPassStaked(msg.sender, 1);
}
function batchStakeSolarPass(uint256 _amount, uint256[] calldata _tokenIds) external {
uint256 amountStaked = solarPassStaked[msg.sender];
require(amountStaked + _amount <= maxSolarPass, "SFA Staking: staked amount exceeds limit");
address _solarPass = solarPass;
uint256 i = 0;
while(i < _amount) {
IERC721(_solarPass).safeTransferFrom(msg.sender, address(this), _tokenIds[i]);
solarPassStaked[msg.sender] += 1;
solarPassStakedData[msg.sender][amountStaked + i] = StakingData(_tokenIds[i], block.timestamp);
unchecked {
++i;
}
}
emit SolarPassStaked(msg.sender, _amount);
}
function claimRewards() external {
uint256 solarHeadsStaked = solarHeadStaked[msg.sender];
uint256 solarPassesStaked = solarPassStaked[msg.sender];
uint256 tokensEarned;
uint256 currTime = block.timestamp;
uint32 _payoutPeriod = payoutPeriod;
uint256 stakedTime;
uint256 duration;
uint256 i;
while(i < solarHeadsStaked) {
stakedTime = solarHeadStakedData[msg.sender][i].timestamp;
duration = currTime - stakedTime;
tokensEarned += (duration / _payoutPeriod) * 1 ether;
solarHeadStakedData[msg.sender][i].timestamp = block.timestamp;
unchecked {
++i;
}
}
i = 0;
while(i < solarPassesStaked) {
stakedTime = solarPassStakedData[msg.sender][i].timestamp;
duration = currTime - stakedTime;
tokensEarned += (duration / _payoutPeriod) * 10 ether;
solarPassStakedData[msg.sender][i].timestamp = block.timestamp;
unchecked {
++i;
}
}
IERC20(sfaToken).transfer(msg.sender, tokensEarned);
emit RewardsClaimed(msg.sender, tokensEarned);
}
function withdraw() external {
address _solarHead = solarHead;
address _solarPass = solarPass;
uint256 solarHeadsStaked = solarHeadStaked[msg.sender];
uint256 solarPassesStaked = solarPassStaked[msg.sender];
solarHeadStaked[msg.sender] = 0;
solarPassStaked[msg.sender] = 0;
uint256 tokensEarned;
uint256 currTime = block.timestamp;
uint32 _payoutPeriod = payoutPeriod;
uint256 stakedTime;
uint256 duration;
uint256 i = 0;
while(i < solarHeadsStaked) {
stakedTime = solarHeadStakedData[msg.sender][i].timestamp;
duration = currTime - stakedTime;
tokensEarned += (duration / _payoutPeriod) * 1 ether;
solarHeadStakedData[msg.sender][i].timestamp = 0;
IERC721(_solarHead).safeTransferFrom(address(this), msg.sender, solarHeadStakedData[msg.sender][i].tokenId);
unchecked {
++i;
}
}
i = 0;
while(i < solarPassesStaked) {
stakedTime = solarPassStakedData[msg.sender][i].timestamp;
duration = currTime - stakedTime;
tokensEarned += (duration / _payoutPeriod) * 10 ether;
solarPassStakedData[msg.sender][i].timestamp = 0;
IERC721(_solarPass).safeTransferFrom(address(this), msg.sender, solarPassStakedData[msg.sender][i].tokenId);
unchecked {
++i;
}
}
IERC20(sfaToken).transfer(msg.sender, tokensEarned);
emit WithdrawalAll(msg.sender);
}
function withdrawSolarHead() external {
address _solarHead = solarHead;
uint256 solarHeadsStaked = solarHeadStaked[msg.sender];
solarHeadStaked[msg.sender] = 0;
uint256 tokensEarned;
uint256 currTime = block.timestamp;
uint32 _payoutPeriod = payoutPeriod;
uint256 stakedTime;
uint256 duration;
uint256 i = 0;
while(i < solarHeadsStaked) {
stakedTime = solarHeadStakedData[msg.sender][i].timestamp;
duration = currTime - stakedTime;
tokensEarned += (duration / _payoutPeriod) * 1 ether;
solarHeadStakedData[msg.sender][i].timestamp = 0;
IERC721(_solarHead).safeTransferFrom(address(this), msg.sender, solarHeadStakedData[msg.sender][i].tokenId);
unchecked {
++i;
}
}
IERC20(sfaToken).transfer(msg.sender, tokensEarned);
emit WithdrawalSolarHead(msg.sender);
}
function withdrawSolarPass() external {
address _solarPass = solarPass;
uint256 solarPassesStaked = solarPassStaked[msg.sender];
solarPassStaked[msg.sender] = 0;
uint256 tokensEarned;
uint256 currTime = block.timestamp;
uint32 _payoutPeriod = payoutPeriod;
uint256 stakedTime;
uint256 duration;
uint256 i = 0;
while(i < solarPassesStaked) {
stakedTime = solarPassStakedData[msg.sender][i].timestamp;
duration = currTime - stakedTime;
tokensEarned += (duration / _payoutPeriod) * 10 ether;
solarPassStakedData[msg.sender][i].timestamp = 0;
IERC721(_solarPass).safeTransferFrom(address(this), msg.sender, solarPassStakedData[msg.sender][i].tokenId);
unchecked {
++i;
}
}
IERC20(sfaToken).transfer(msg.sender, tokensEarned);
emit WithdrawalSolarPass(msg.sender);
}
function onERC721Received(
address,
address,
uint256,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC721Received.selector;
}
}
{
"compilationTarget": {
"contracts/SFAStaking.sol": "SFAStaking"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"uint256","name":"_maxSolarPass","type":"uint256"},{"internalType":"uint256","name":"_maxSolarHead","type":"uint256"},{"internalType":"address","name":"_solarPass","type":"address"},{"internalType":"uint8","name":"_solarPassPayout","type":"uint8"},{"internalType":"address","name":"_solarHead","type":"address"},{"internalType":"uint8","name":"_solarHeadPayout","type":"uint8"},{"internalType":"address","name":"_sfaToken","type":"address"},{"internalType":"uint32","name":"_payoutPeriod","type":"uint32"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardsClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"SolarHeadStaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"SolarPassStaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"}],"name":"WithdrawalAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"}],"name":"WithdrawalSolarHead","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"}],"name":"WithdrawalSolarPass","type":"event"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"batchStakeSolarHead","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"batchStakeSolarPass","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getStakedAmounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSolarHead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSolarPass","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":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"payoutPeriod","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sfaToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"solarHead","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"solarHeadPayout","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"solarHeadStaked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"solarHeadStakedData","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"solarPass","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"solarPassPayout","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"solarPassStaked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"solarPassStakedData","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"stakeSolarHead","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"stakeSolarPass","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawSolarHead","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawSolarPass","outputs":[],"stateMutability":"nonpayable","type":"function"}]