4.10 Twitter Dapp 01 Smart Contract

更新 發佈閱讀 28 分鐘

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




留言
avatar-img
留言分享你的想法!
avatar-img
Follow the Rainmaker 🌧️
5會員
91內容數
尋大神腳印, 亦步亦趨。
你可能也想看
Thumbnail
透過蝦皮分潤計畫,輕鬆賺取零用金!本文分享5-6月實測心得,包含數據流程、實際收入、平臺優點及注意事項,並推薦高分潤商品,教你如何運用空閒時間創造被動收入。
Thumbnail
透過蝦皮分潤計畫,輕鬆賺取零用金!本文分享5-6月實測心得,包含數據流程、實際收入、平臺優點及注意事項,並推薦高分潤商品,教你如何運用空閒時間創造被動收入。
Thumbnail
單身的人有些會養寵物,而我養植物。畢竟寵物離世會傷心,植物沒養好再接再厲就好了~(笑)
Thumbnail
單身的人有些會養寵物,而我養植物。畢竟寵物離世會傷心,植物沒養好再接再厲就好了~(笑)
Thumbnail
不知你有沒有過這種經驗?衛生紙只剩最後一包、洗衣精倒不出來,或電池突然沒電。這次一次補貨,從電池、衛生紙到洗衣精,還順便分享使用心得。更棒的是,搭配蝦皮分潤計畫,愛用品不僅自己用得安心,分享給朋友還能賺回饋。立即使用推薦碼 X5Q344E,輕鬆上手,隨時隨地賺取分潤!
Thumbnail
不知你有沒有過這種經驗?衛生紙只剩最後一包、洗衣精倒不出來,或電池突然沒電。這次一次補貨,從電池、衛生紙到洗衣精,還順便分享使用心得。更棒的是,搭配蝦皮分潤計畫,愛用品不僅自己用得安心,分享給朋友還能賺回饋。立即使用推薦碼 X5Q344E,輕鬆上手,隨時隨地賺取分潤!
Thumbnail
身為一個典型的社畜,上班時間被會議、進度、KPI 塞得滿滿,下班後只想要找一個能夠安靜喘口氣的小角落。對我來說,畫畫就是那個屬於自己的小樹洞。無論是胡亂塗鴉,還是慢慢描繪喜歡的插畫人物,那個專注在筆觸和色彩的過程,就像在幫心靈按摩一樣,讓緊繃的神經慢慢鬆開。
Thumbnail
身為一個典型的社畜,上班時間被會議、進度、KPI 塞得滿滿,下班後只想要找一個能夠安靜喘口氣的小角落。對我來說,畫畫就是那個屬於自己的小樹洞。無論是胡亂塗鴉,還是慢慢描繪喜歡的插畫人物,那個專注在筆觸和色彩的過程,就像在幫心靈按摩一樣,讓緊繃的神經慢慢鬆開。
Thumbnail
在前一篇我們已經成功地建立簽核表單及簽核節點並關聯回請假表單,而本篇會接著介紹如何管理簽核節點狀態並同步更新簽核表單狀態。
Thumbnail
在前一篇我們已經成功地建立簽核表單及簽核節點並關聯回請假表單,而本篇會接著介紹如何管理簽核節點狀態並同步更新簽核表單狀態。
Thumbnail
你好,在下最近在學習開發web,學了html css js,也得出一些心得,由於網路上已有許多教學,所以我會著重在如何開發出to do List,以及解釋我寫的程式碼。相關的教學我會直接貼網址。如果我有什麼地方出錯,或者是可以寫得更好,歡迎在下方留言,討論。 首先先介紹我的開發環境: 我用了vs
Thumbnail
你好,在下最近在學習開發web,學了html css js,也得出一些心得,由於網路上已有許多教學,所以我會著重在如何開發出to do List,以及解釋我寫的程式碼。相關的教學我會直接貼網址。如果我有什麼地方出錯,或者是可以寫得更好,歡迎在下方留言,討論。 首先先介紹我的開發環境: 我用了vs
Thumbnail
本文介紹如何使用 TG Bot 來操作 MongoDB,包括讀取所有 domain、讀取特定 domain、新增 domain、批量新增 domain、修改 domain 和刪除 domain。透過 TG Bot 的指令操作,實現了自動化管理和多環境管理。
Thumbnail
本文介紹如何使用 TG Bot 來操作 MongoDB,包括讀取所有 domain、讀取特定 domain、新增 domain、批量新增 domain、修改 domain 和刪除 domain。透過 TG Bot 的指令操作,實現了自動化管理和多環境管理。
Thumbnail
學習如何使用Python連接MongoDB進行憑證監控,包括建立MongoDB docker-compose、連接MongoDB、讀取yaml並寫入MongoDB、傳入env以及domain寫入MongoDB、讀取MongoDB、修改MongoDB、刪除MongoDB。
Thumbnail
學習如何使用Python連接MongoDB進行憑證監控,包括建立MongoDB docker-compose、連接MongoDB、讀取yaml並寫入MongoDB、傳入env以及domain寫入MongoDB、讀取MongoDB、修改MongoDB、刪除MongoDB。
Thumbnail
想了解如何製作適合自己的TG群組機器人來管理群組嗎? 以下將詳細的逐步教學。
Thumbnail
想了解如何製作適合自己的TG群組機器人來管理群組嗎? 以下將詳細的逐步教學。
Thumbnail
本文提供完成訂閱後的相關事項及安裝指引,包括填寫問卷、遠端開通Trading View帳號、指標安裝步驟等。另外也提供影片教學和紙本教學,以及解決安裝問題的方法。
Thumbnail
本文提供完成訂閱後的相關事項及安裝指引,包括填寫問卷、遠端開通Trading View帳號、指標安裝步驟等。另外也提供影片教學和紙本教學,以及解決安裝問題的方法。
Thumbnail
在 IG 上看到一位前端大大用 Google Apps Script + Line bot 替自己的球隊安排了球經,覺得很有趣,想來玩看看
Thumbnail
在 IG 上看到一位前端大大用 Google Apps Script + Line bot 替自己的球隊安排了球經,覺得很有趣,想來玩看看
Thumbnail
本文章介紹了建立網頁的整個流程,包括設置 Templates, Views, Urls 等步驟。透過這些步驟,大家便能創建一個新的網頁,並成功測試。
Thumbnail
本文章介紹了建立網頁的整個流程,包括設置 Templates, Views, Urls 等步驟。透過這些步驟,大家便能創建一個新的網頁,並成功測試。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News