2024-02-01|閱讀時間 ‧ 約 48 分鐘

4.10 Twitter Dapp 01 Smart Contract

Overview

  1. Create a Twitter Contract (ep.7) 🌳
  2. Creat a mapping between user and tweet 🌳
  3. Add function to creat a tweet and save it in mapping 🌳
  4. Create a function to get Tweet (ep.11) 🌳
  5. Define a Tweet Struct with Author, content, timestamp, likes (ep.13) 🌳
  6. Add the struct to array Test tweets (ep.13) 🌳
  7. Use require to limit the length of the tweet to be only 280 characters (ep.15) 🌳
  8. Add a function called change TweetLength to change max tweet length ( Hint: use newTweetLength as input for function) (ep.17) 🌳
  9. Create a constructor function to set an owner of contract (ep.17) 🌳
  10. Create a modifier called onlyOwner (ep.17) 🌳
  11. Use onlyOwner on the changeTweetLength function (ep.17) 🌳
  12. Add id to Tweet Struct to make every Tweet Unique (ep.18)🌳
  13. Set the id to be the Tweet [ ] length (Hint: you do it in the creatTweet function) ep.18)🌳
  14. Add a function to like the tweet (Hint: there should be 2 paramenters, id and author ep.18) 🌳
  15. Add a function to unlike the tweet (make sure you can unlike only if likes count is greater than 0 (ep.18) 🌳
  16. Mark both functions external (ep.18) 🌳
  17. Deploy Smart Contract to Sepolia (ep.19) 🌳
  18. Create Event for creating the tweet, called TweetCreated (Use parameters like id, author, content, timestamp) (ep.21)🌳
  19. Emit the event in the createTweet() function below(ep.21)🌳
  20. Create Event for liking the tweet, called TweetLiked (Use parameters like liker, tweetAuthor, tweetId, newLikeCount(ep.21)🌳
  21. Emit the event in the likeTweet() function below(ep.21)🌳
  22. Create a function, getTotalLikes, get total Tweet likes for the user ( User parameters of author) (ep.24) 🌳
  23. Loop over all the tweets (ep.24) 🌳
  24. sum up totalLikes (ep.24) 🌳
  25. Return totalLike (ep.24) 🌳
  26. Save UserProfile to the mapping in the setProfile() function// HINT: don't forget to set the _displayName and _bio (ep.28)
  27. // 2️⃣ Add a getProfile() function to the interface ✅//
  28. 3️⃣ Initialize the IProfile in the contructor ✅// HINT: don't forget to include the _profileContract address as a input//
  29. 4️⃣ Create a modifier called onlyRegistered that require the msg.sender to have a profile ✅// HINT: use the getProfile() to get the user// HINT: check if displayName.length > 0 to make sure the user exists//
  30. 5️⃣ ADD the onlyRegistered modified to createTweet, likeTweet, and unlikeTweet function ✅




// SPDX-License-Identifier: MIT
pragma solidity ^ 0.8.24;

contract Twitter { // 1️⃣ Create a Twitter Contract
// 定義不可改變的數字
uint16 public MAX_TWEET_LENGTH = 280;

// 5️⃣ Define a Tweet Struct with Author, content, timestamp, likes
// Struct: define a tweet wtih multiple data
// 1️⃣1️⃣ Add id to Tweet Struct to make every Tweet Unique
struct Tweet {
uint256 id;
address author;
string content;
uint256 timestamp;
uint256 likes;
}

// 2️⃣ Create a mappping between user and tweet
mapping(address => Tweet[] ) public tweets;
address public owner; // define the owner of this contract

// 1️⃣5️⃣ Create Event for creating the tweet, called TweetCreated
// Use parameters like id, author, content, timestamp
// 1️⃣7️⃣ Create Event for liking the tweet, called TweetLiked (Use parameters like liker, tweetAuthor, tweetId, newLikeCount
event TweetCreated(uint256 id, address author, string content, uint256 timestamp);
event TweetLiked(address liker, address tweetAuthor, uint256 tweetId, uint256newLikedCount);
event TweetUnliked(address unliker, address tweetAuthor, uint256 tweetId, newLikeCount);

// 8️⃣ create the constructor under all the variables
// Create a constructor function to set an owner of contract
constructor(){
owner = msg.sender;
}

// 9️⃣ Create a modifier called onlyOwner: to check if the owner is calling the function
modifier onlyowner() { // use modifier to check onlyowner
require(msg.sender == owner, "You Are Not The Owner");
_;
}

// 7️⃣ Add a function called change TweetLength to change max tweet length
// ( Hint: use newTweetLength as input for function)
// 🔟 Use onlyOwner on the changeTweetLength function
function changeTweetLength(uint16 newTweetLength) public onlyOwner {
MAX_TWEET_LENGTH = newTweetLength;
}

// 3️⃣ Add function to create a tweet and save it in mapping
// store the tweets above in temporary memory
// key is the address (the msg.sender)
// msg.sender: whoever is using the blockchain interacting with your code
// Add the struct to array Test tweets
function createTweet(string memory _tweet) public {

// 6️⃣ Use require to limit the length of the tweet to be only 280 characters (ep.15)
// conditional
// if tweet length <= 280 then we are good, otherwise we revert
function createTweet(string memory _tweet) public {
require(bytes(_tweet).length <= MAX_TWEET_LENGTH, "Tweet is too long bro");

// 1️⃣2️⃣ Set the id to be the Tweet [ ] length (Hint: you do it in the creatTweet function)
Tweet memory newTweet = Tweet({
id: tweets[msg.sender].length,
author: msg.sender,
content: _tweet,
timestamp: block.timestamp,
likes: 0
});
// not only 1 tweet, so use array
// push the tweet into the array
tweets[msg.sender].push(newTweet);

// 1️⃣6️⃣ Emit the event in the createTweet() function below
emit TweetCreated(newTweet, id, newTweet.author, newTweet.content, newTweet.timestamp);
}

// 1️⃣3️⃣ Add a function to like the tweet (Hint: there should be 2 paramenters, id and author
// 1️⃣5️⃣ Mark both functions external
require tweets[author][id].id == id, "TWEET DOES NOT EXISTS";
function likeTweet(address author, uint256 id) external {
tweets[author][id].likes++; //likes = likes + 1;

// 1️⃣8️⃣ Emit the event in the likeTweet() function below
emit TweetLiked(msg.sender, author, id, tweets[author][id].likes);
}

// 1️⃣4️⃣ Add a function to unlike the tweet (make sure you can unlike only if likes count is greater than 0)
// 1️⃣5️⃣ Mark both functions external
function unlikeTweet(address author, uint256 id) external {
require(tweets[author][id].id == id, "TWEET DOES NOT EXISTS");
require(tweets[author][id].likes > 0, "TWEET HAS NO LIKES");
tweets[author][id].likes--;

emit TweetUnLiked(msg.sender, author, id, tweets[author][id].likes);
// you cannnot decrement the count if the tweet does not exist
// also the count cannot be negative
}

// 4️⃣ Create a function to get tweet
// not only 1 tweet, so use index to specify the tweet
function getTweet(uint _i) public view returns (Tweet memory) {
return tweets[msg.sender][_i]; //only check for information
}

function getAllTweets(address _owner) public view returns (Tweet[] memory){
return tweets[_owner];
}
}


create a twitter contract and a user profile contract (exercise user)

// SPDX-License-Identifier: MIT

// 1️⃣ Save UserProfile to the mapping in the setProfile() function
// HINT: don't forget to set the _displayName and _bio

pragma solidity ^0.8.0;

contract Profile {
struct UserProfile {
string displayName;
string bio;
}
string maxSupply = 50;
mapping(address => UserProfile) public profiles;

function setProfile(string memory _displayName, string memory _bio) public {
// CODE HERE 👇
profiles[msg.sender] = UserProfile(_displayName, _bio);
}

function getProfile(address _user) public view returns (UserProfile memory) {
return profiles[_user];
}
}


exercise(main)

// SPDX-License-Identifier: MIT

import "@openzeppelin/contracts/access/Ownable.sol";

pragma solidity ^0.8.0;

interface IProfile {
struct UserProfile {
string displayName;
string bio;
}

// 2️⃣ Add a getProfile() function to the interface ✅
// CODE HERE
function getProfile (address _user) external view returns (UserProfile memory)
}

contract Twitter is Ownable {

uint16 public MAX_TWEET_LENGTH = 280;

struct Tweet {
uint256 id;
address author;
string content;
uint256 timestamp;
uint256 likes;
}
mapping(address => Tweet[] ) public tweets;
// profile contract defined here
IProfile profileContract;

// Define the events
event TweetCreated(uint256 id, address author, string content, uint256 timestamp);
event TweetLiked(address liker, address tweetAuthor, uint256 tweetId, uint256 newLikeCount);
event TweetUnliked(address unliker, address tweetAuthor, uint256 tweetId, uint256 newLikeCount);

// 4️⃣ Create a modifier called onlyRegistered that require the msg.sender to have a profile ✅
// HINT: use the getProfile() to get the user
// HINT: check if displayName.length > 0 to make sure the user exists
modifier onlyRegistered(){
IProfile.UserProfile memory userProfileTemp = profileContract.getProfile(
require(bytes(userProfileTemp.displayName).length > 0, "USER NOT REGISTERED");
_);
}

// 3️⃣ Initialize the IProfile in the contructor ✅
// HINT: don't forget to include the _profileContract address as a input
constructor(address _profileContract) {
profileContract = IProfile(_profileContract);
}

function changeTweetLength(uint16 newTweetLength) public onlyOwner {
MAX_TWEET_LENGTH = newTweetLength;
}

function getTotalLikes(address _author) external view returns(uint) {
uint totalLikes;

for( uint i = 0; i < tweets[_author].length; i++){
totalLikes += tweets[_author][i].likes;
}

return totalLikes;
}

function createTweet(string memory _tweet) public {
require(bytes(_tweet).length <= MAX_TWEET_LENGTH, "Tweet is too long bro!" );

Tweet memory newTweet = Tweet({
id: tweets[msg.sender].length,
author: msg.sender,
content: _tweet,
timestamp: block.timestamp,
likes: 0
});

tweets[msg.sender].push(newTweet);

// Emit the TweetCreated event
emit TweetCreated(newTweet.id, newTweet.author, newTweet.content, newTweet.timestamp);
}

// 5️⃣ ADD the onlyRegistered modified to createTweet, likeTweet, and unlikeTweet function ✅
function likeTweet(address author, uint256 id) external onlyRegistered {
require(tweets[author][id].id == id, "TWEET DOES NOT EXIST");

tweets[author][id].likes++;

// Emit the TweetLiked event
emit TweetLiked(msg.sender, author, id, tweets[author][id].likes);
}

// 5️⃣ ADD the onlyRegistered modified to createTweet, likeTweet, and unlikeTweet function ✅
function unlikeTweet(address author, uint256 id) external onlyRegistered {
require(tweets[author][id].id == id, "TWEET DOES NOT EXIST");
require(tweets[author][id].likes > 0, "TWEET HAS NO LIKES");

tweets[author][id].likes--;

emit TweetUnliked(msg.sender, author, id, tweets[author][id].likes );
}

function getTweet( uint _i) public view returns (Tweet memory) {
return tweets[msg.sender][_i];
}

function getAllTweets(address _owner) public view returns (Tweet[] memory ){
return tweets[_owner];
}

}


Add Account create to Twitter Dapp

useStateVariables

app.js


Ultimate Solidity Smart Contract Course - For Complete Beginners




分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.