0. Todo List
- Create a Twitter Contract (ep.7)
- Creat a mapping between user and tweet
- Add function to creat a tweet and save it in mapping
- Create a function to get Tweet (ep.13)
- Define a Tweet STruct with Author, content, timestamp, likes
- Add the struct to array Test tweets
- Use require to limit the length of the tweet to be only 280 characters (ep.15)
- Add a function called change TweetLength to change max tweet length ( Hint: use newTweetLength as input for function) (ep.17)
- Create a constructor function to set an owner of contract
- Create a modifier called onlyOwner
- Use onlyOwner on the changeTweetLength function
- Add id to Tweet Struct to make every Tweet Unique (ep.18)
- Set the id to be the Tweet [ ] length (Hint: you do it in the creatTweet function)
- Add a function to like the tweet (Hint: there should be 2 paramenters, id and author
- Add a function to unlike the tweet (make sure you can unlike only if likes count is greater than 0)
- Mark both functions external
- Create Event for creating the tweet, called TweetCreated (Use parameters like id, author, content, timestamp) (ep.21)
- Emit the event in the createTweet() function below
- Create Event for liking the tweet, called TweetLiked (Use parameters like liker, tweetAuthor, tweetId, newLikeCount
- Emit the event in the likeTweet() function below
- Create a function, getTotalLikes, get total Tweet likes for the user ( User parameters of author)
- Loop over all the tweets
- sum up totalLikes
- Return totalLikes
1. Basic Twitter Contract (ep.7)
- msg.sender - comes directly from blockchain
2. Complete Basic Twitter Contract (ep.9)
pragma solidity ^0.8.24;
contract Twitter {
mapping(address => string) public tweets;
function createTweet(string memory _tweet) public {
tweets[msg.sender] = _tweet;
}
function getTweet(address _owner) public view returns (string memory) {
return tweets[_owner];
}
}
3. Get an Arrays of Tweets (ep.11)
4. Add struct to Twitter (ep.13)
5. Limit tweet length with require (ep.15)
- please generate 400 character of lorem ipsum
6. Add Custom Modifier to Twitter (ep.17)
7. Add Likes to Twitter Contract (ep.18)
8. Add Event to Twitter Contract (ep.21)
9. Implement Twitter contract into a twitter Dapp (ep.22)
ToDoList
- Request Wallet Connection from Metamask get account function
- Set your smart contract address
- connect to the contract using web3
- call the contract createTweet method in order to crete the actual TWEET
- call the function getAllTweets from smart contract to get all the tweets
- Call the displayTweets function with address as input
- Uncomment the displayTweets function! PRETTY EASY 🔥
- call the likeTweet function from smart contract
import contractABI from "./abi.json";
const contractAddress = "0xB74e4287C0776A43163eE9f041e410506056D084";
let web3 = new Web3(window.ethereum);
let contract = new web3.eth.Contract(contractABI, contractAddress);
async function connectWallet() {
if (window.ethereum) {
const accounts = await window.ethereum
.request({ method: "eth_requestAccounts" })
.catch((err) => {
if (err.code === 4001) {
console.log("Please connect to MetaMask.");
} else {
console.error(err);
}
});
setConnected(accounts[0]);
} else {
console.error("No web3 provider detected");
document.getElementById("connectMessage").innerText =
"No web3 provider detected. Please install MetaMask.";
}
}
async function createTweet(content) {
const accounts = await web3.eth.getAccounts();
try {
await contract.methods.createTweet(content).send({ from: accounts[0] });
displayTweets(accounts[0]);
} catch (error) {
console.error("User rejected request:", error);
}
}
async function displayTweets(userAddress) {
const tweetsContainer = document.getElementById("tweetsContainer");
const tempTweets = [];
tweetsContainer.innerHTML = "";
tempTweets = await contract.methods.getAllTweets(userAddress).call();
const tweets = [...tempTweets];
tweets.sort((a, b) => b.timestamp - a.timestamp);
for (let i = 0; i < tweets.length; i++) {
const tweetElement = document.createElement("div");
tweetElement.className = "tweet";
const userIcon = document.createElement("img");
userIcon.className = "user-icon";
userIcon.src = `https://avatars.dicebear.com/api/human/${tweets[i].author}.svg`;
userIcon.alt = "User Icon";
tweetElement.appendChild(userIcon);
const tweetInner = document.createElement("div");
tweetInner.className = "tweet-inner";
tweetInner.innerHTML += `
<div class="author">${shortAddress(tweets[i].author)}</div>
<div class="content">${tweets[i].content}</div>
`;
const likeButton = document.createElement("button");
likeButton.className = "like-button";
likeButton.innerHTML = `
<i class="far fa-heart"></i>
<span class="likes-count">${tweets[i].likes}</span>
`;
likeButton.setAttribute("data-id", tweets[i].id);
likeButton.setAttribute("data-author", tweets[i].author);
addLikeButtonListener(
likeButton,
userAddress,
tweets[i].id,
tweets[i].author
);
tweetInner.appendChild(likeButton);
tweetElement.appendChild(tweetInner);
tweetsContainer.appendChild(tweetElement);
}
}
function addLikeButtonListener(likeButton, address, id, author) {
likeButton.addEventListener("click", async (e) => {
e.preventDefault();
e.currentTarget.innerHTML = '<div class="spinner"></div>';
e.currentTarget.disabled = true;
try {
await likeTweet(author, id);
displayTweets(address);
} catch (error) {
console.error("Error liking tweet:", error);
}
});
}
function shortAddress(address, startLength = 6, endLength = 4) {
return `${address.slice(0, startLength)}...${address.slice(-endLength)}`;
}
async function likeTweet(author, id) {
try {
await contract.methods.like(author, id).send({ from: accounts[0] });
} catch (error) {
console.error("User rejected request:", error);
}
}
function setConnected(address) {
document.getElementById("userAddress").innerText =
"Connected: " + shortAddress(address);
document.getElementById("connectMessage").style.display = "none";
document.getElementById("tweetForm").style.display = "block";
displayTweets(address);
}
document
.getElementById("connectWalletBtn")
.addEventListener("click", connectWallet);
document.getElementById("tweetForm").addEventListener("submit", async (e) => {
e.preventDefault();
const content = document.getElementById("tweetContent").value;
const tweetSubmitButton = document.getElementById("tweetSubmitBtn");
tweetSubmitButton.innerHTML = '<div class="spinner"></div>';
tweetSubmitButton.disabled = true;
try {
await createTweet(content);
} catch (error) {
console.error("Error sending tweet:", error);
} finally {
tweetSubmitButton.innerHTML = "Tweet";
tweetSubmitButton.disabled = false;
}
});
10. Get Total Likes in Twitter Contract (ep.24)
11. Add User Profile To Twitter Contract