// here is my contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
uint256 c = a / b;
return c;
}
}
contract ThetaVibes {
using SafeMath for uint256; // Import SafeMath library
mapping(address => uint256) public balances;
struct Video {
uint256 price;
uint256 price48Hours;
uint256 priceLifetime;
mapping(address => bool) lifetimeAccess;
}
struct Channel {
address payable owner;
mapping(string => Video) videos;
uint256 channelBalance;
uint256 subscriptionPrice;
mapping(address => bool) subscribers;
}
struct Subscription {
bool isActive;
}
address payable contractOwnerAddress;
constructor() {
contractOwnerAddress = payable(msg.sender);
}
modifier onlyOwner() {
require(msg.sender == contractOwnerAddress, "Only the contract owner can call this function.");
_;
}
mapping(string => Channel) public channels;
mapping(string => mapping(address => Subscription)) public subscriptions;
event SubscriptionPurchased(string indexed channelId, address indexed subscriber);
event VideoPurchased(string indexed channelId, string indexed videoId, address indexed purchaser, bool isLifetime);
event ChannelOwnerWithdrawn(string indexed channelId, address indexed owner, uint256 amount);
event ContractOwnerWithdrawn(address indexed owner, uint256 amount);
event DepositMade(address indexed depositor, uint256 amount);
event SubscriptionRemoved(string indexed channelId, address indexed subscriber);
function createChannel(string memory channelId, uint256 subscriptionPriceTFuel) public {
require(channels[channelId].owner == address(0), "Channel already exists");
Channel storage newChannel = channels[channelId];
newChannel.owner = payable(msg.sender);
newChannel.subscriptionPrice = subscriptionPriceTFuel;
}
function deposit() public payable {
require(msg.value > 0, "Amount must be greater than zero");
// Deduct gas fees from the deposited amount
uint256 gasCost = gasleft() * tx.gasprice;
uint256 depositedAmount = msg.value.sub(gasCost);
balances[msg.sender] = balances[msg.sender].add(depositedAmount);
emit DepositMade(msg.sender, depositedAmount);
}
function purchaseSubscriptionWithBalance(string memory channelId, address subscriber) public {
Channel storage channel = channels[channelId];
require(channel.owner != address(0), "Channel does not exist");
require(!channel.subscribers[subscriber], "Already subscribed to the channel");
uint256 gasCost = gasleft() * tx.gasprice;
uint256 totalCost = channel.subscriptionPrice.add(gasCost); // Calculate total cost
require(balances[subscriber] >= totalCost, "Insufficient balance to cover subscription and gas fees");
channel.subscribers[subscriber] = true;
emit SubscriptionPurchased(channelId, subscriber);
uint256 contractOwnerShare = (channel.subscriptionPrice * 20) / 100;
uint256 channelOwnerShare = channel.subscriptionPrice - contractOwnerShare;
channel.channelBalance += channelOwnerShare;
balances[subscriber] = balances[subscriber].sub(channel.subscriptionPrice); // Deduct subscription price from user's balance
// Call a separate function for gas-heavy operations
processGas(subscriber, gasCost);
}
function processGas(address subscriber, uint256 gasCost) internal {
balances[subscriber] = balances[subscriber].sub(gasCost); // Deduct gas cost from user's balance
// Additional gas-heavy operations can be performed here
}
function renewSubscriptionWithBalance(string memory channelId, address subscriber) public onlyOwner {
Channel storage channel = channels[channelId];
require(channel.owner != address(0), "Channel does not exist");
require(channel.subscribers[subscriber], "Subscriber is not subscribed to the channel");
require(balances[subscriber] >= channel.subscriptionPrice, "Insufficient balance");
channel.channelBalance += channel.subscriptionPrice; // Add subscription price to channel balance
balances[subscriber] -= channel.subscriptionPrice; // Deduct subscription price from user's balance
}
function removeSubscription(string memory channelId, address subscriber) public onlyOwner {
Channel storage channel = channels[channelId];
require(channel.owner != address(0), "Channel does not exist");
require(channel.subscribers[subscriber], "Subscriber is not subscribed to the channel");
channel.subscribers[subscriber] = false; // Set subscriber status to false to remove subscription
emit SubscriptionRemoved(channelId, subscriber);
}
function updateSubscriptionPrice(string memory channelId, uint256 newPrice) public {
Channel storage channel = channels[channelId];
require(channel.owner == msg.sender, "Only the channel owner can update the subscription price");
channel.subscriptionPrice = newPrice;
}
modifier onlyChannelOwner(string memory channelId) {
require(channels[channelId].owner == msg.sender, "Only the channel owner can call this function.");
_;
}
function createVideo(string memory channelId, string memory videoId, uint256 price48Hours, uint256 priceLifetime) public onlyChannelOwner(channelId) {
Channel storage channel = channels[channelId];
require(channel.videos[videoId].price48Hours == 0, "Video already exists");
Video storage newVideo = channel.videos[videoId];
newVideo.price48Hours = price48Hours * 1e18;
newVideo.priceLifetime = priceLifetime * 1e18;
}
function purchaseVideoWithBalance(string memory channelId, string memory videoId, bool lifetimeAccess) public {
Channel storage channel = channels[channelId];
require(channel.owner != address(0), "Channel does not exist");
require(channel.videos[videoId].price48Hours > 0, "Video does not exist");
require(!channel.subscribers[msg.sender], "Subscribers cannot purchase videos from this channel");
require(!channel.videos[videoId].lifetimeAccess[msg.sender], "Already purchased lifetime access to the video");
uint256 videoPrice = (lifetimeAccess ? channel.videos[videoId].priceLifetime : channel.videos[videoId].price48Hours) / 1e18;
require(balances[msg.sender] >= videoPrice, "Insufficient balance");
if (lifetimeAccess) {
channel.videos[videoId].lifetimeAccess[msg.sender] = true;
}
uint256 contractOwnerShare = (videoPrice * 20) / 100;
uint256 channelOwnerShare = videoPrice - contractOwnerShare;
channel.channelBalance += channelOwnerShare;
balances[msg.sender] -= videoPrice;
contractOwnerAddress.transfer(contractOwnerShare); // Transfer 20% to the contract owner
emit VideoPurchased(channelId, videoId, msg.sender, lifetimeAccess);
}
function channelOwnerWithdraw(string memory channelId) public {
Channel storage channel = channels[channelId];
require(channel.owner == msg.sender, "Only the channel owner can call this function");
uint256 amount = channel.channelBalance;
require(amount > 0, "No balance available for withdrawal");
channel.channelBalance = 0;
channel.owner.transfer(amount);
emit ChannelOwnerWithdrawn(channelId, msg.sender, amount);
}
function isSubscriber(string memory channelId, address account) public view returns (bool) {
return channels[channelId].subscribers[account];
}
}