文件 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:IcyMembership.sol
pragma solidity 0.8.7;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
contract IcyMembership is ReentrancyGuard, Ownable {
using SafeMath for uint256;
event ClaimTrial(address indexed _from);
event Pay(address indexed _from, uint _value);
bool public isAcceptingNewMemberships = true;
bool public isAcceptingTrialMemberships = false;
uint256 public serviceFeePerDay = 800000000000000;
uint8 public minimumServiceDays = 30;
uint256 public numberOfTrialMembershipDays = 7;
uint256 public bonusIntervalInDays = 300;
uint256 public bonusDaysGrantedPerInterval = 60;
mapping(address => uint256) private addressPaidUpTo;
mapping(address => bool) private addressClaimedTrialMembership;
mapping(address => bool) private blocklist;
receive() external payable {
payForServices();
}
function payForServices() public payable {
require(!blocklist[msg.sender], "Sender not allowed.");
require(isAcceptingNewMemberships, "Memberships are paused.");
uint256 minimumServiceFee = serviceFeePerDay.mul(minimumServiceDays);
require(msg.value >= minimumServiceFee, "Minimum payment not met.");
uint256 secondsPerWei = serviceFeePerDay.div(86400);
uint256 secondsToAdd = msg.value.div(secondsPerWei);
uint256 daysToAdd = secondsToAdd.div(86400);
if (bonusDaysGrantedPerInterval > 0 && daysToAdd >= bonusIntervalInDays) {
secondsToAdd = secondsToAdd.add(daysToAdd.div(bonusIntervalInDays).mul(bonusDaysGrantedPerInterval).mul(86400));
}
if (addressPaidUpTo[msg.sender] == 0) {
addressPaidUpTo[msg.sender] = block.timestamp.add(secondsToAdd);
} else {
addressPaidUpTo[msg.sender] = addressPaidUpTo[msg.sender].add(secondsToAdd);
}
emit Pay(msg.sender, msg.value);
}
function hasActiveMembership(address _addr) external view returns(bool) {
return !isAddressBlocked(_addr) && addressPaidUpTo[_addr] >= block.timestamp;
}
function getAddressPaidUpTo(address _addr) public view returns(uint256) {
return !isAddressBlocked(_addr) ? addressPaidUpTo[_addr] : 0;
}
function isAddressBlocked(address _addr) public view returns(bool) {
return blocklist[_addr];
}
function claimTrialMembership() external nonReentrant {
require(isAcceptingTrialMemberships, "Trials not active.");
require(!blocklist[msg.sender], "Sender not allowed.");
require(!addressClaimedTrialMembership[msg.sender], "Trial already claimed.");
require(addressPaidUpTo[msg.sender] == 0, "Trial not allowed.");
addressPaidUpTo[msg.sender] = block.timestamp.add(numberOfTrialMembershipDays.mul(86400));
addressClaimedTrialMembership[msg.sender] = true;
emit ClaimTrial(msg.sender);
}
function addAddressToBlocklist(address _addr) external onlyOwner {
blocklist[_addr] = true;
}
function removeAddressFromBlocklist(address _addr) external onlyOwner {
delete blocklist[_addr];
}
function setBonusIntervalInDays(uint256 _bonusIntervalInDays) external onlyOwner {
bonusIntervalInDays = _bonusIntervalInDays;
}
function setBonusDaysGrantedPerInterval(uint256 _bonusDaysGrantedPerInterval) external onlyOwner {
bonusDaysGrantedPerInterval = _bonusDaysGrantedPerInterval;
}
function setAddressPaidUpTo(address _addr, uint256 _paidUpTo) external onlyOwner {
addressPaidUpTo[_addr] = _paidUpTo;
}
function setServiceFeePerDay(uint256 _serviceFeePerDay) external onlyOwner {
require(_serviceFeePerDay > 0, "serviceFeePerDay cannot be 0");
serviceFeePerDay = _serviceFeePerDay;
}
function setMinimumServiceDays(uint8 _minimumServiceDays) external onlyOwner {
require(_minimumServiceDays > 0, "minimumServiceDays cannot be 0");
minimumServiceDays = _minimumServiceDays;
}
function setNumberOfTrialMembershipDays(uint8 _numberOfTrialMembershipDays) external onlyOwner {
require(_numberOfTrialMembershipDays > 0, "numberOfTrialMembershipDays cannot be 0");
numberOfTrialMembershipDays = _numberOfTrialMembershipDays;
}
function withdraw(uint256 _amount) external nonReentrant onlyOwner {
require(_amount <= address(this).balance, "Withdraw less");
require(_amount > 0, "Withdraw more");
address owner = _msgSender();
payable(owner).transfer(_amount);
}
function toggleAcceptingNewMemberships() public onlyOwner {
isAcceptingNewMemberships = !isAcceptingNewMemberships;
}
function toggleAcceptingTrialMemberships() public onlyOwner {
isAcceptingTrialMemberships = !isAcceptingTrialMemberships;
}
function renounceOwnership() public override view onlyOwner {
revert("Not allowed");
}
}
文件 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: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;
}
}
文件 5 的 5:SafeMath.sol
pragma solidity ^0.8.0;
library SafeMath {
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}
{
"compilationTarget": {
"contracts/IcyMembership.sol": "IcyMembership"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"}],"name":"ClaimTrial","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":true,"internalType":"address","name":"_from","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Pay","type":"event"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"name":"addAddressToBlocklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bonusDaysGrantedPerInterval","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bonusIntervalInDays","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimTrialMembership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"name":"getAddressPaidUpTo","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"name":"hasActiveMembership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isAcceptingNewMemberships","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isAcceptingTrialMemberships","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"name":"isAddressBlocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumServiceDays","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numberOfTrialMembershipDays","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":"payForServices","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"name":"removeAddressFromBlocklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"serviceFeePerDay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"uint256","name":"_paidUpTo","type":"uint256"}],"name":"setAddressPaidUpTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bonusDaysGrantedPerInterval","type":"uint256"}],"name":"setBonusDaysGrantedPerInterval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bonusIntervalInDays","type":"uint256"}],"name":"setBonusIntervalInDays","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_minimumServiceDays","type":"uint8"}],"name":"setMinimumServiceDays","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_numberOfTrialMembershipDays","type":"uint8"}],"name":"setNumberOfTrialMembershipDays","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_serviceFeePerDay","type":"uint256"}],"name":"setServiceFeePerDay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleAcceptingNewMemberships","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleAcceptingTrialMemberships","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]