Untitled
unknown
plain_text
2 years ago
5.0 kB
12
Indexable
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract SubscriptionService is Ownable {
struct Plan {
uint256 id;
string name;
uint256 price;
string description;
uint256 period;
}
struct Subscription {
address customerAddress; // Added customerAddress field
uint256 createdAt;
uint256 updatedAt;
}
mapping(address => Plan[]) public plans;
mapping(address => uint256) public merchantBalances;
mapping(address => uint256) public activationFees;
mapping(address => mapping(uint256 => bool)) public inactivePlans;
mapping(uint256 => Subscription[]) public subscriptions;
mapping(address => mapping(uint256 => bool)) public customerPlans;
uint256 public totalServiceFees; // Total service fees collected
event SubscriptionFailed(address indexed customer, uint256 indexed planId);
event PlanAdded(uint256 indexed planId, address indexed merchant);
event PlanRemoved(uint256 indexed planId, address indexed merchant);
event PaymentTransferred(
uint256 indexed planId,
address indexed customerAddress,
address indexed merchantAddress,
uint256 amount
);
event TransferFailed(
uint256 indexed planId,
address indexed customerAddress
);
function addPlan(
string memory name,
uint256 price,
string memory description,
uint256 period
) public {
uint256 planId = uint256(
keccak256(abi.encodePacked(name, msg.sender, block.timestamp))
);
plans[msg.sender].push(Plan(planId, name, price, description, period));
emit PlanAdded(planId, msg.sender);
}
function deactivatePlan(uint256 planId) public {
inactivePlans[msg.sender][planId] = true;
emit PlanRemoved(planId, msg.sender);
}
function subscribe(uint256 planId) public {
Subscription memory newSubscription = Subscription(
msg.sender,
block.timestamp,
0
);
subscriptions[planId].push(newSubscription);
}
function runner(address merchantAddress, IERC20 token) external {
uint256 gasStart = gasleft();
Plan[] storage merchantPlans = plans[merchantAddress];
for (uint256 i = 0; i < merchantPlans.length; i++) {
Plan storage plan = merchantPlans[i];
if (inactivePlans[merchantAddress][plan.id]) continue; // Skip if inactive
Subscription[] storage subs = subscriptions[plan.id];
for (uint256 j = 0; j < subs.length; j++) {
Subscription storage sub = subs[j];
uint64 diff = uint64(block.timestamp) -
uint64(sub.updatedAt > 0 ? sub.updatedAt : sub.createdAt);
if (diff >= plan.period) {
try
token.transferFrom(
sub.customerAddress,
address(this),
plan.price
)
{
merchantBalances[merchantAddress] += plan.price;
sub.updatedAt = uint64(block.timestamp);
emit PaymentTransferred(
plan.id,
sub.customerAddress,
merchantAddress,
plan.price
);
} catch {
emit TransferFailed(plan.id, sub.customerAddress);
}
}
}
}
uint256 gasEnd = gasleft();
uint256 gasUsed = gasStart - gasEnd;
uint256 activationFee = gasUsed * tx.gasprice;
activationFees[merchantAddress] += activationFee;
}
function claimFunds(IERC20 token) external {
uint256 merchantBalance = merchantBalances[msg.sender];
uint256 activationFee = activationFees[msg.sender];
uint256 serviceFee = (activationFee * 5) / 1000; // 0.5% of activation fee
uint256 totalAmount = merchantBalance + activationFee - serviceFee;
payable(msg.sender).transfer(activationFee - serviceFee); // Transfer activationFee in Ether
totalServiceFees += serviceFee;
require(token.transfer(msg.sender, totalAmount), "Transfer failed");
merchantBalances[msg.sender] = 0;
activationFees[msg.sender] = 0;
}
function withdrawServiceFees() external onlyOwner {
uint256 amount = totalServiceFees;
totalServiceFees = 0;
payable(owner()).transfer(amount);
}
receive() external payable {}
}
Editor is loading...