// SPDX-License-Identifier: Affero General Public License v3.0 pragma solidity ^0.8.0; pragma experimental ABIEncoderV2; library AmaFansLib { string constant MINIMUM_PRIVATE_BID_REQUIRED = "001009"; string constant MINIMUM_PUBLIC_BID_REQUIRED = "001010"; string constant MESSAGEID_EXISTS = "002001"; string constant INVALID_MESSAGE_OWNER = "002002"; string constant INVALID_MESSAGEID = "002003"; string constant ALREADY_ANSWERED = "002004"; string constant ALREADY_CLAIMED = "002005"; string constant MESSAGE_TIME_LIMIT_IN_EFFECT = "002006"; string constant INVALID_TIME_LOCK = "002007"; string constant MESSAGE_TIME_LIMIT_EXPIRED = "002008"; string constant MESSAGE_ACTIVE = "002009"; string constant INVALID_MESSAGE_TYPE = "002010"; string constant INVALID_MESSAGE_RESPONSE_TYPE = "002011"; string constant RESPONSE_MARKED = "002012"; string constant TIPID_EXISTS = "003001"; string constant INVALID_TIP_OWNER = "003002"; string constant INVALID_TIPID = "003003"; string constant TIP_ALREADY_CLAIMED = "003004"; string constant MINIMUM_TIP_REQUIRED = "003005"; string constant INVALID_POSTID = "004001"; string constant POSTTIP_ID_EXISTS = "004002"; string constant MINIMUM_POST_BID_REQUIRED = "004003"; string constant INSUFFICIENT_FUNDS = "009001"; string constant ADDRESS_BLOCKLISTED = "009002"; string constant INVALID_BID = "009003"; string constant DEACTIVATED = "009004"; string constant USER_EXISTS = "009005"; string constant USER_BLOCKED = "009006"; string constant INVALID_UPFRONT = "009007"; string constant INVALID_THRESHOLD = "009008"; string constant USER_WHITELISTED = "009009"; string constant USER_PARADOX = "009010"; string constant USER_NOT_BLOCKED = "009011"; bytes32 constant ZERO_BYTES32 = 0x0000000000000000000000000000000000000000000000000000000000000000; enum AccessState{ ACTIVE, BLOCKED, WHITELISTED } enum State{ACTIVE, CLAIMED, DELETED, ANSWERED} enum MessageType{ PUBLIC, PRIVATE } enum ResponseType{ DEFAULT, GOOD, BAD } // struct Session{ // uint256 minimumBid; // address createdBy; // bytes32[] messageIds; // uint256 startTime; // uint256 endTime; // uint256 createdTime; // StorageData storageData; // } // struct StorageData{ // string descriptionLink; // string titleLink; // string bannerImageLink; // } struct Message{ string messageLink; string answerLink; uint256 initialValue; uint256 totalValue; //Including the tips address createdBy; address anweredBy; bytes32[] tipIds; uint256 createdTime; uint256 expiryTime; State state; uint256 tokenId; ResponseType responseType; uint messageType; } struct Post{ string postLink; uint256 initialValue; uint256 tipsTotalValue; //Including the tips address createdBy; bytes32[] postTipIds; uint256 createdTime; uint256 tokenId; } struct Tip{ address createdBy; uint256 value; uint256 createdTime; bytes32 messageId; bool claimed; } struct PostTip{ address createdBy; uint256 value; uint256 createdTime; bytes32 postId; } struct User{ uint256 publicMinimumBid; uint256 privateMinimumBid; bytes verified; mapping(address => uint256) followersList; mapping(address => AccessState) accessList; } function createMessageId( string memory messageLink, address _createdBy) public view returns (bytes32){ // This has block.timestamp because a user can ask multiple messages on the same session return keccak256(abi.encodePacked(messageLink, _createdBy, block.timestamp)); } function createTipId( bytes32 _tipId, address _createdBy) public view returns (bytes32){ // This has block.timestamp because a user can send multiple tips to the same message return keccak256(abi.encodePacked(_tipId, _createdBy, block.timestamp)); } //CHeck if the message on which the tip is being made is in a valid state or not function messageValidityForNewTip(Message storage message ) public view { messageValidity(message); } //The changes that have to be made on message when a new tip has been made function messageChangesOnTip(Message storage message, bytes32 tipId, uint256 value ) public { message.totalValue += value; message.tipIds.push(tipId); } function postChangesOnTip(Post storage post, bytes32 postTipId, uint256 value ) public { post.tipsTotalValue += value; post.postTipIds.push(postTipId); } function newTip( mapping(bytes32 => Tip) storage tips, bytes32 messageId, address sender, uint256 value ) public returns (bytes32) { bytes32 tipId = createTipId( messageId, sender); // if (tips[_tipId].createdBy != address(0)) revert AmaFansLib.TipIdAlreadyExists(_tipId); require(tips[tipId].createdBy == address(0), TIPID_EXISTS); tips[tipId] = Tip(sender, value, block.timestamp, messageId, false); return tipId; } function newPostTip( mapping(bytes32 => PostTip) storage postTips, bytes32 postId, address sender, uint256 value ) public returns (bytes32) { bytes32 postTipId = createTipId( postId, sender); // if (tips[_tipId].createdBy != address(0)) revert AmaFansLib.TipIdAlreadyExists(_tipId); require(postTips[postTipId].createdBy == address(0), POSTTIP_ID_EXISTS); postTips[postTipId] = PostTip(sender, value, block.timestamp, postId); return postTipId; } //Whe the message has not been answered in the timeLock, The //value attached to the message can be claimed by the original sender. function claimBackMessageValue(Message storage message) public { _validClaim(message); _messageChangesOnClaimedBack(message); } function _validClaim(Message storage message) internal view{ _validMessageState(message); //uint256 _lock = message.createdTime + message.timeLock; require(block.timestamp > message.expiryTime, MESSAGE_TIME_LIMIT_IN_EFFECT); } //IN case the message value is being claimed or being answered. // The message state shouldnt be following, it shouldnt //al;ready have answered or shouldnt have already claimed function _validMessageState(Message storage message) private view{ require(message.state != State.CLAIMED, ALREADY_CLAIMED); require(message.state != State.ANSWERED, ALREADY_ANSWERED); } function _messageChangesOnClaimedBack(Message storage message) private { message.state = AmaFansLib.State.CLAIMED; } function claimBackTipValue(Tip storage tip, Message storage message ) public { // if(_message.state == AmaFansLib.State.ANSWERED) revert AmaFansLib.InValidmessageState(_tip.messageId); _validTipState(tip, message); tip.claimed = true; } function messageValidityForAnswer(Message storage message) public view { messageValidity(message); } function messageValidity(Message storage message) public view{ _validMessageState(message); // uint256 _lock = message.createdTime + message.timeLock; require(block.timestamp < message.expiryTime, MESSAGE_TIME_LIMIT_EXPIRED); } function _validTipState(Tip storage tip, Message storage message) private view{ require(message.state != State.ANSWERED, ALREADY_ANSWERED); require(message.state == State.CLAIMED, ALREADY_CLAIMED); require(tip.claimed != true, TIP_ALREADY_CLAIMED); } function messageChangesOnAnswer(Message storage message, uint256 tokenId, string memory answerLink) public { message.answerLink = answerLink; message.state = State.ANSWERED; // message.anweredBy = anweredBy; if (tokenId != 0){ message.tokenId = tokenId; } } function arrayChunk(uint256 skip_, uint256 limit_, bytes32[] storage array_) public view returns (bytes32[] memory values, uint256){ if (limit_ > array_.length - skip_) { limit_ = array_.length - skip_; } values = new bytes32[](limit_); for (uint256 i = 0; i < limit_; i++) { values[i] = array_[skip_ + i]; } return (values, skip_ + limit_); } }