编译器
0.8.15+commit.e14f2714
文件 1 的 9:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 2 的 9:HookableStakingPool.sol
pragma solidity ^0.8.0;
import './StakingPool.sol';
contract HookableStakingPool is StakingPool {
address public hookAddress;
constructor(address tokenAddress) StakingPool(tokenAddress) {}
function setHookAddress(address hookAddress_) external onlyOwner {
hookAddress = hookAddress_;
}
function _beforeStake(uint256 tokenId, address owner)
internal
virtual
override
{
if (hookAddress != address(0)) {
StakingHook(hookAddress).onStake(tokenId, owner);
}
}
function _beforeUnstake(uint256 tokenId, address owner)
internal
virtual
override
{
if (hookAddress != address(0)) {
StakingHook(hookAddress).onUnstake(tokenId, owner);
}
}
}
interface StakingHook {
function onStake(uint256 tokenId, address owner) external;
function onUnstake(uint256 tokenId, address owner) external;
}
文件 3 的 9:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 4 的 9: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
) external;
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
function approve(address to, uint256 tokenId) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function setApprovalForAll(address operator, bool _approved) external;
function isApprovedForAll(address owner, address operator) external view returns (bool);
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
}
文件 5 的 9:IERC721Receiver.sol
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 6 的 9:NoundleStakingPools.sol
pragma solidity ^0.8.0;
import './HookableStakingPool.sol';
contract NoundleStakingPool is HookableStakingPool {
constructor(address tokenAddress) HookableStakingPool(tokenAddress) {}
}
contract CompanionStakingPool is HookableStakingPool {
constructor(address tokenAddress) HookableStakingPool(tokenAddress) {}
}
contract EvilNoundleStakingPool is HookableStakingPool {
constructor(address tokenAddress) HookableStakingPool(tokenAddress) {}
}
文件 7 的 9:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 8 的 9:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 9 的 9:StakingPool.sol
pragma solidity ^0.8.0;
import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol';
import '@openzeppelin/contracts/token/ERC721/IERC721.sol';
import '@openzeppelin/contracts/security/ReentrancyGuard.sol';
contract StakingPool is Ownable, IERC721Receiver, ReentrancyGuard {
event Stake(address indexed owner, uint256 indexed tokenId);
event Unstake(address indexed owner, uint256 indexed tokenId);
IERC721 public tokenContract;
mapping(address => uint16[]) private _staked;
constructor(address tokenAddress) {
tokenContract = IERC721(tokenAddress);
}
function stakedTokens(address owner)
external
view
returns (uint256[] memory)
{
uint16[] memory staked = _staked[owner];
uint256 numTokens = staked.length;
uint256[] memory tokenIds = new uint256[](numTokens);
for (uint256 i; i < numTokens; ++i) {
tokenIds[i] = staked[i];
}
return tokenIds;
}
function stake(uint256 tokenId) external nonReentrant {
tokenContract.safeTransferFrom(_msgSender(), address(this), tokenId);
}
function batchStake(uint256[] calldata tokenIds) external nonReentrant {
uint256 numTokens = tokenIds.length;
for (uint256 i; i < numTokens; ++i) {
tokenContract.safeTransferFrom(_msgSender(), address(this), tokenIds[i]);
}
}
function _stake(uint256 tokenId, address owner) internal {
_beforeStake(tokenId, owner);
_staked[owner].push(uint16(tokenId));
emit Stake(owner, tokenId);
}
function _beforeStake(uint256 tokenId, address owner) internal virtual {}
function unstake(uint256 tokenId) external nonReentrant {
_unstake(tokenId, _msgSender());
}
function batchUnstake(uint256[] calldata tokenIds) external nonReentrant {
uint256 numTokens = tokenIds.length;
for (uint256 i; i < numTokens; ++i) {
_unstake(tokenIds[i], _msgSender());
}
}
function unstakeAll() external nonReentrant {
_unstakeAll(_msgSender());
}
function _unstakeAll(address owner) internal {
uint256 stakedCount = _staked[owner].length;
for (uint256 i = stakedCount; i > 0; --i) {
_unstakeIndex(i - 1, owner);
}
}
function _unstake(uint256 tokenId, address owner) internal {
uint256 stakedCount = _staked[owner].length;
for (uint256 i; i < stakedCount; ++i) {
if (_staked[owner][i] == tokenId) {
_unstakeIndex(i, owner);
break;
}
}
}
function unstakeIndex(uint256 index) external nonReentrant {
_unstakeIndex(index, _msgSender());
}
function batchUnstakeIndex(uint256[] memory indices) external nonReentrant {
_sort(indices, _staked[_msgSender()].length);
for (uint256 i = indices.length; i > 0; --i) {
_unstakeIndex(indices[i - 1], _msgSender());
}
}
function batchUnstakeIndexSorted(uint256[] memory indices)
external
nonReentrant
{
uint256 lastIndex = type(uint256).max;
for (uint256 i = indices.length; i > 0; --i) {
uint256 index = indices[i - 1];
if (index < lastIndex) {
lastIndex = index;
_unstakeIndex(index, _msgSender());
}
}
}
function _unstakeIndex(uint256 index, address owner) internal {
uint16 tokenId = _staked[owner][index];
_beforeUnstake(tokenId, owner);
uint256 lastIndex = _staked[owner].length - 1;
if (index != lastIndex) {
_staked[owner][index] = _staked[owner][lastIndex];
}
_staked[owner].pop();
tokenContract.safeTransferFrom(address(this), owner, tokenId);
emit Unstake(owner, tokenId);
}
function _beforeUnstake(uint256 tokenId, address owner) internal virtual {}
function forceUnstake(address owner) external onlyOwner {
_unstakeAll(owner);
}
function _sort(uint256[] memory data, uint256 setSize) internal pure {
uint256 length = data.length;
bool[] memory set = new bool[](setSize);
for (uint256 i = 0; i < length; ++i) {
set[data[i]] = true;
}
uint256 n = 0;
for (uint256 i = 0; i < setSize; ++i) {
if (set[i]) {
data[n] = i;
if (++n >= length) break;
}
}
}
function balanceOf(address owner) public view returns (uint256) {
return _staked[owner].length;
}
function onERC721Received(
address,
address from,
uint256 tokenId,
bytes memory data
) public virtual override returns (bytes4) {
require(_msgSender() == address(tokenContract), 'Unknown token contract');
address owner = data.length > 0 ? abi.decode(data, (address)) : from;
_stake(tokenId, owner);
return this.onERC721Received.selector;
}
}
{
"compilationTarget": {
"contracts/NoundleStakingPools.sol": "EvilNoundleStakingPool"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 800
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"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":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Stake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Unstake","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"batchStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"batchUnstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"indices","type":"uint256[]"}],"name":"batchUnstakeIndex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"indices","type":"uint256[]"}],"name":"batchUnstakeIndexSorted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"forceUnstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"hookAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"hookAddress_","type":"address"}],"name":"setHookAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"stakedTokens","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenContract","outputs":[{"internalType":"contract IERC721","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unstakeAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"unstakeIndex","outputs":[],"stateMutability":"nonpayable","type":"function"}]