编译器
0.8.28+commit.7893614a
文件 1 的 3: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);
}
文件 2 的 3: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;
}
}
文件 3 的 3:Stanker.sol
pragma solidity ^0.8.13;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
contract Stanker is ReentrancyGuard {
struct Stake {
uint256 unlockTimestamp;
uint256 amount;
address erc20;
address recipient;
bool distributed;
}
mapping(uint256 => Stake) public stakes;
uint256[] allStakeIds;
mapping(address => uint256[]) public userStakesToReceive;
mapping(address => uint256[]) public userStakesToSend;
function getAllStakes() public view returns (Stake[] memory, uint256[] memory) {
Stake[] memory allStakes = new Stake[](allStakeIds.length);
for (uint256 i = 0; i < allStakeIds.length; i++) {
allStakes[i] = stakes[allStakeIds[i]];
}
return (allStakes, allStakeIds);
}
function getReceivingStakes(address user) public view returns (Stake[] memory, uint256[] memory) {
Stake[] memory userStakesToReturn = new Stake[](userStakesToReceive[user].length);
uint256[] memory userStakeIdsToReturn = new uint256[](userStakesToReceive[user].length);
for (uint256 i = 0; i < userStakesToReceive[user].length; i++) {
userStakesToReturn[i] = stakes[userStakesToReceive[user][i]];
userStakeIdsToReturn[i] = userStakesToReceive[user][i];
}
return (userStakesToReturn, userStakeIdsToReturn);
}
function getSendingStakes(address user) public view returns (Stake[] memory, uint256[] memory) {
Stake[] memory userStakesToReturn = new Stake[](userStakesToSend[user].length);
uint256[] memory userStakeIdsToReturn = new uint256[](userStakesToSend[user].length);
for (uint256 i = 0; i < userStakesToSend[user].length; i++) {
userStakesToReturn[i] = stakes[userStakesToSend[user][i]];
userStakeIdsToReturn[i] = userStakesToSend[user][i];
}
return (userStakesToReturn, userStakeIdsToReturn);
}
function withdrawStake(uint256 id) public nonReentrant {
Stake memory stake = stakes[id];
require(block.timestamp >= stake.unlockTimestamp, "Stake not yet unlocked");
require(msg.sender == stake.recipient, "You are not the recipient of this stake");
require(!stake.distributed, "Stake already distributed");
IERC20(stake.erc20).transfer(stake.recipient, stake.amount);
stakes[id].distributed = true;
}
function createStake(uint256 id, uint256 unlockTimestamp, uint256 amount, address erc20, address recipient) public nonReentrant {
require(stakes[id].unlockTimestamp == 0, "Stake already exists");
require(unlockTimestamp != 0, "Cannot have no unlockTimestamp");
IERC20(erc20).transferFrom(msg.sender, address(this), amount);
Stake memory stake = Stake(unlockTimestamp, amount, erc20, recipient, false);
stakes[id] = stake;
userStakesToReceive[recipient].push(id);
userStakesToSend[msg.sender].push(id);
allStakeIds.push(id);
}
}
{
"compilationTarget": {
"src/Stanker.sol": "Stanker"
},
"evmVersion": "cancun",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": [
":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
":@uniswap/v3-core/=lib/v3-core/",
":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/",
":v3-core/=lib/v3-core/"
]
}
[{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"unlockTimestamp","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"erc20","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"createStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllStakes","outputs":[{"components":[{"internalType":"uint256","name":"unlockTimestamp","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"erc20","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bool","name":"distributed","type":"bool"}],"internalType":"struct Stanker.Stake[]","name":"","type":"tuple[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getReceivingStakes","outputs":[{"components":[{"internalType":"uint256","name":"unlockTimestamp","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"erc20","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bool","name":"distributed","type":"bool"}],"internalType":"struct Stanker.Stake[]","name":"","type":"tuple[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getSendingStakes","outputs":[{"components":[{"internalType":"uint256","name":"unlockTimestamp","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"erc20","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bool","name":"distributed","type":"bool"}],"internalType":"struct Stanker.Stake[]","name":"","type":"tuple[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakes","outputs":[{"internalType":"uint256","name":"unlockTimestamp","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"erc20","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bool","name":"distributed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userStakesToReceive","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userStakesToSend","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"withdrawStake","outputs":[],"stateMutability":"nonpayable","type":"function"}]