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
Follow the Rainmaker 🌧️
5會員
91內容數
尋大神腳印, 亦步亦趨。
你可能也想看
Thumbnail
本文章介紹了建立網頁的整個流程,包括設置 Templates, Views, Urls 等步驟。透過這些步驟,大家便能創建一個新的網頁,並成功測試。
Thumbnail
本文章介紹了建立網頁的整個流程,包括設置 Templates, Views, Urls 等步驟。透過這些步驟,大家便能創建一個新的網頁,並成功測試。
Thumbnail
在前一篇我們已經成功地建立簽核表單及簽核節點並關聯回請假表單,而本篇會接著介紹如何管理簽核節點狀態並同步更新簽核表單狀態。
Thumbnail
在前一篇我們已經成功地建立簽核表單及簽核節點並關聯回請假表單,而本篇會接著介紹如何管理簽核節點狀態並同步更新簽核表單狀態。
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
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
在 IG 上看到一位前端大大用 Google Apps Script + Line bot 替自己的球隊安排了球經,覺得很有趣,想來玩看看
Thumbnail
在 IG 上看到一位前端大大用 Google Apps Script + Line bot 替自己的球隊安排了球經,覺得很有趣,想來玩看看
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
你好,在下最近在學習開發web,學了html css js,也得出一些心得,由於網路上已有許多教學,所以我會著重在如何開發出to do List,以及解釋我寫的程式碼。相關的教學我會直接貼網址。如果我有什麼地方出錯,或者是可以寫得更好,歡迎在下方留言,討論。 首先先介紹我的開發環境: 我用了vs
Thumbnail
你好,在下最近在學習開發web,學了html css js,也得出一些心得,由於網路上已有許多教學,所以我會著重在如何開發出to do List,以及解釋我寫的程式碼。相關的教學我會直接貼網址。如果我有什麼地方出錯,或者是可以寫得更好,歡迎在下方留言,討論。 首先先介紹我的開發環境: 我用了vs
Thumbnail
本文提供完成訂閱後的相關事項及安裝指引,包括填寫問卷、遠端開通Trading View帳號、指標安裝步驟等。另外也提供影片教學和紙本教學,以及解決安裝問題的方法。
Thumbnail
本文提供完成訂閱後的相關事項及安裝指引,包括填寫問卷、遠端開通Trading View帳號、指標安裝步驟等。另外也提供影片教學和紙本教學,以及解決安裝問題的方法。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
想了解如何製作適合自己的TG群組機器人來管理群組嗎? 以下將詳細的逐步教學。
Thumbnail
想了解如何製作適合自己的TG群組機器人來管理群組嗎? 以下將詳細的逐步教學。
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News