109 Twitter Contract

2024/02/01閱讀時間約 21 分鐘

0. Todo List

  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.13)
  5. Define a Tweet STruct with Author, content, timestamp, likes
  6. Add the struct to array Test tweets
  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
  10. Create a modifier called onlyOwner
  11. Use onlyOwner on the changeTweetLength function
  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)
  14. Add a function to like the tweet (Hint: there should be 2 paramenters, id and author
  15. Add a function to unlike the tweet (make sure you can unlike only if likes count is greater than 0)
  16. Mark both functions external
  17. Create Event for creating the tweet, called TweetCreated (Use parameters like id, author, content, timestamp) (ep.21)
  18. Emit the event in the createTweet() function below
  19. Create Event for liking the tweet, called TweetLiked (Use parameters like liker, tweetAuthor, tweetId, newLikeCount
  20. Emit the event in the likeTweet() function below
  21. Create a function, getTotalLikes, get total Tweet likes for the user ( User parameters of author)
  22. Loop over all the tweets
  23. sum up totalLikes
  24. Return totalLikes


1. Basic Twitter Contract (ep.7)

  • msg.sender - comes directly from blockchain

2. Complete Basic Twitter Contract (ep.9)

  • temporary value
// SPDX-License-Identifier: MIT
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)

raw-image


9. Implement Twitter contract into a twitter Dapp (ep.22)

ToDoList

  1. Request Wallet Connection from Metamask get account function
  2. Set your smart contract address
  3. connect to the contract using web3
  4. call the contract createTweet method in order to crete the actual TWEET
  5. call the function getAllTweets from smart contract to get all the tweets
  6. Call the displayTweets function with address as input
  7. Uncomment the displayTweets function! PRETTY EASY 🔥
  8. call the likeTweet function from smart contract


// index.js

import contractABI from "./abi.json";

// 2️⃣ Set your smart contract address 👇
const contractAddress = "0xB74e4287C0776A43163eE9f041e410506056D084";

let web3 = new Web3(window.ethereum);
// 3️⃣ connect to the contract using web3
// HINT: https://web3js.readthedocs.io/en/v1.2.11/web3-eth-contract.html#new-contract
// let contract = YOUR CODE
let contract = new web3.eth.Contract(contractABI, contractAddress);

async function connectWallet() {
if (window.ethereum) {
// 1️⃣ Request Wallet Connection from Metamask
// ANSWER can be found here: https://docs.metamask.io/wallet/get-started/set-up-dev-environment/
// const accounts = YOUR CODE
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 {
// 4️⃣ call the contract createTweet method in order to crete the actual TWEET
// HINT: https://web3js.readthedocs.io/en/v1.2.11/web3-eth-contract.html#methods-mymethod-send
// use the "await" feature to wait for the function to finish execution
// what is await? https://javascript.info/async-await
await contract.methods.createTweet(content).send({ from: accounts[0] });

// 7️⃣ Uncomment the displayTweets function! PRETTY EASY 🔥
// GOAL: reload tweets after creating a new tweet
displayTweets(accounts[0]);
} catch (error) {
console.error("User rejected request:", error);
}
}

async function displayTweets(userAddress) {
const tweetsContainer = document.getElementById("tweetsContainer");
const tempTweets = [];
tweetsContainer.innerHTML = "";
// 5️⃣ call the function getAllTweets from smart contract to get all the tweets
// HINT: https://web3js.readthedocs.io/en/v1.2.11/web3-eth-contract.html#methods-mymethod-call
// tempTweets = await YOUR CODE
tempTweets = await contract.methods.getAllTweets(userAddress).call();

// we do this so we can sort the tweets by timestamp
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 {
// 8️⃣ call the likeTweet function from smart contract
// INPUT: author and id
// GOAL: Save the like in the smart contract
// HINT: don't forget to use await 😉 👇

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";

// 6️⃣ Call the displayTweets function with address as input
// This is the function in the javascript code, not smart contract 😉
// GOAL: display all tweets after connecting to metamask
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 {
// Restore the original button text
tweetSubmitButton.innerHTML = "Tweet";
tweetSubmitButton.disabled = false;
}
});


10. Get Total Likes in Twitter Contract (ep.24)


11. Add User Profile To Twitter Contract






尋大神腳印, 亦步亦趨。
留言0
查看全部
發表第一個留言支持創作者!