Untitled
unknown
plain_text
2 years ago
5.0 kB
6
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...