Search code examples
solidityipfs

Function to mint ERC-token with every nth-number of like


I need help with a function to reward user with erc777-token as soon as his content (Ipfs-Hash, see the program below) hit n-number of likes (lets say every 100th like), i.e., whenever the 'netLike' counter hits 100, it automatically mints one token to the respective user's address.

And because there's a dislike function as well, the user should not be rewarded the token every time the likeCounter hits 100, (for example - if a user hits 100th like for the first time, its rewarded with one erc token, and once it hits that milestone, in order to earn 2nd token, it must hit the milestone of 200 likes, and likewise every multiple of 100 can only generate one token 'one-time')

I've added nonce for this purpose, but couldn't really figure out the exact logic!! (brainfog 😊) The logic and the _mint() fn is inside the like function.

Thanks!!

  Content[] public contents;
    
    // A mapping of Content Hashes to their respective Owners
    mapping(bytes32 => address) public contentHashToAuthor;
    
  
    //Contains all the indices of content uploaded by the author
    mapping(address => uint256[]) public authorToContentIndices;
    
    
    //A mapping of contentHash to contentIndex
    mapping(bytes32 => uint256) contentIndex;
    
    
 
    //the struct that contains the content-Info
    struct Content{
        bytes32 hash;
        string[] tags;
        address author;
        uint256 likes;
        uint256 dislikes;
        int256 netLikes;
        uint256 nonce;
        uint64 timeStamp;
    }
    
  
function addContent(bytes32[] memory _hash, string[][] memory _tags) public {
    
    for(uint256 i = 0; i < _hash.length; i++ ){
        
        if(contentHashToAuthor[_hash[i]] == 0) {
            
            Content memory _content = new Content({
                hash: _hash[i],
                tags: _tags[i][],
                author: msg.sender
                like: 0,
                dislikes: 0,
                netLikes: 0,
                nonce: 0,
                mapping(address => bool) usersLiked;
                mapping(address => bool) usersDisliked;
                timeStamp: uint64(now)
            });
            
            uint256 contentIndex = contents.push(_content) - 1;
            authorToContentIndices[msg.sender].push(contentIndex);
            contentHashToAuthor[_hash[i]] = msg.sender;
            contentIndices[_hash[i]] = contentIndex;
        
        } else {
            revert("Content already Exist!")
        }
        
    }

    
}



function like(bytes32 _hash) public {
            uint256 cId = contentIndex[_hash];
            Content storage c = contents[cId];
            if(c.usersLiked[msg.sender] != true){
                c.usersLiked[msg.sender] = true;
                if(c.usersDisliked[msg.sender] == true){
                    c.usersDisliked[msg.sender] == false;
                    c.dislikes--;
                }
                c.likes++;
                c.netLikes++;
                //logic for rewarding ERC777 for every 100th netLike. 
                //todo
                if(c.netLikes == 100){
                      //mint function to hit with every 100th netLike
                     _mint(c.author, 1, "", "");
                }
                
            } else {
                revert("Already liked!")
            }
            
    }

  function dislike(bytes32 _hash) public {
            uint256 cId = contentIndex[_hash];
            Content storage c = contents[cId];
            if(c.usersDisliked[msg.sender] != true){
                c.usersDisliked[msg.sender] = true;
                if(c.usersLiked == true){
                    c.usersLiked == false;
                    c.likes--;
                    c.netLikes--;
                }
                c.dislikes++;
                c.netLikes--;
            } else {
                revert("Already disliked!")
            }
            
    }
    

Solution

  • You can add a counter of rewards to the struct Content.

    struct Content{
        // ... rest of your code
        uint8 rewards; // Max value of uint8 is 255, which represents 25.5k netLikes. If that's not sufficient, use uint16.
    }
    
    if(c.netLikes % 100 == 0 && c.netLikes / 100 == c.rewards + 1){
          //mint function to hit with every 100th netLike
         _mint(c.author, 1, "", "")
         c.rewards++;
    }
    

    Your original code if(c.netLikes == 100) only works for the 1st reward (100th netLike).

    The updated code:

    • c.netLikes % 100 == 0 Checks whether netLikes is divisible by 100
    • c.netLikes / 100 == c.rewards + 1 Validates that the reward hasn't been given for this 100.

    Example with values:

    1. netLikes 99, likes 99, dislikes 0, rewards 0, one new like:
      • likes becomes 100, netLikes becomes 100
      • c.netLikes % 100 == 0 => 100 % 100 == 0 => true
      • c.netLikes / 100 == c.rewards + 1 => 100 / 100 == 0 + 1 => true
      • _mint() is called and rewards becomes 1
    2. netLikes 100, likes 100, dislikes 0, rewards 1, one new dislike:
      • dislikes becomes 1, netLikes becomes 99
    3. netLikes 99, likes 100, dislikes 1, rewards 1, one new like:
      • likes becomes 101, netLikes becomes 100
      • c.netLikes % 100 == 0 => 100 % 100 == 0 => true
      • c.netLikes / 100 == c.rewards + 1 => 100 / 100 == 1 + 1 => false
      • the "mint" snippet is not called