文件 1 的 5: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 的 5:HarvestArt.sol
pragma solidity >=0.8.0 <0.9.0;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
interface ERCBase {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
function isApprovedForAll(address account, address operator) external view returns (bool);
}
interface ERC721Partial is ERCBase {
function transferFrom(address from, address to, uint256 tokenId) external;
}
interface ERC1155Partial is ERCBase {
function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata) external;
}
contract HarvestArt is ReentrancyGuard, Pausable, Ownable {
bytes4 _ERC721 = 0x80ac58cd;
bytes4 _ERC1155 = 0xd9b67a26;
address public barn = address(0);
uint256 public defaultPrice = 1 gwei;
uint256 public maxTokensPerTx = 100;
mapping (address => uint256) private _contractPrices;
function setBarn(address _barn) onlyOwner public {
barn = _barn;
}
function setDefaultPrice(uint256 _defaultPrice) onlyOwner public {
defaultPrice = _defaultPrice;
}
function setMaxTokensPerTx(uint256 _maxTokensPerTx) onlyOwner public {
maxTokensPerTx = _maxTokensPerTx;
}
function setPriceByContract(address contractAddress, uint256 price) onlyOwner public {
_contractPrices[contractAddress] = price;
}
function pause() onlyOwner public {
_pause();
}
function unpause() onlyOwner public {
_unpause();
}
function _getPrice(address contractAddress) internal view returns (uint256) {
if (_contractPrices[contractAddress] > 0)
return _contractPrices[contractAddress];
else
return defaultPrice;
}
function batchTransfer(address[] calldata tokenContracts, uint256[] calldata tokenIds, uint256[] calldata counts) external whenNotPaused {
require(barn != address(0), "Barn cannot be the 0x0 address");
require(tokenContracts.length > 0, "Must have 1 or more token contracts");
require(tokenContracts.length == tokenIds.length && tokenIds.length == counts.length, "All params must have equal length");
ERCBase tokenContract;
uint256 totalTokens = 0;
uint256 totalPrice = 0;
for (uint256 i = 0; i < tokenContracts.length; i++) {
require(counts[i] > 0, "Token count must be greater than zero.");
tokenContract = ERCBase(tokenContracts[i]);
if (tokenContract.supportsInterface(_ERC721)) {
totalTokens += 1;
totalPrice += _getPrice(tokenContracts[i]);
}
else if (tokenContract.supportsInterface(_ERC1155)) {
totalTokens += counts[i];
totalPrice += _getPrice(tokenContracts[i]) * counts[i];
}
else {
continue;
}
require(totalTokens < maxTokensPerTx, "Maximum token count reached.");
require(address(this).balance > totalPrice, "Not enough ether in contract.");
require(tokenContract.isApprovedForAll(msg.sender, address(this)), "Token not yet approved for all transfers");
if (tokenContract.supportsInterface(_ERC721)) {
ERC721Partial(tokenContracts[i]).transferFrom(msg.sender, barn, tokenIds[i]);
}
else {
ERC1155Partial(tokenContracts[i]).safeTransferFrom(msg.sender, barn, tokenIds[i], counts[i], "");
}
}
(bool sent, ) = payable(msg.sender).call{ value: totalPrice }("");
require(sent, "Failed to send ether.");
}
receive () external payable { }
function withdrawBalance() external onlyOwner {
payable(msg.sender).transfer(address(this).balance);
}
}
文件 3 的 5: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() {
_setOwner(_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 {
_setOwner(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_setOwner(newOwner);
}
function _setOwner(address newOwner) private {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 4 的 5:Pausable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Pausable is Context {
event Paused(address account);
event Unpaused(address account);
bool private _paused;
constructor() {
_paused = false;
}
function paused() public view virtual returns (bool) {
return _paused;
}
modifier whenNotPaused() {
require(!paused(), "Pausable: paused");
_;
}
modifier whenPaused() {
require(paused(), "Pausable: not paused");
_;
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
文件 5 的 5: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;
}
}
{
"compilationTarget": {
"contracts/HarvestArt.sol": "HarvestArt"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"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":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"barn","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokenContracts","type":"address[]"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint256[]","name":"counts","type":"uint256[]"}],"name":"batchTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTokensPerTx","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"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":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_barn","type":"address"}],"name":"setBarn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_defaultPrice","type":"uint256"}],"name":"setDefaultPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTokensPerTx","type":"uint256"}],"name":"setMaxTokensPerTx","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"}],"name":"setPriceByContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]