# Buildspace Testnet Guide **Published by:** [Rama.tori (💙,🧡)(📦,💫) (((🔴🤏🌍))) 🛸🦇🔊🤖🛸](https://paragraph.com/@rama-tori/) **Published on:** 2022-12-01 **URL:** https://paragraph.com/@rama-tori/buildspace-testnet-guide ## Content Note : This tutorial using Bahasa Indonesia, if you still wanna know, just translate it and good luck! Bahan-bahan : PC / Laptop / Komputer dengan OS Windows Discord Buildspace : https://discord.gg/buildspace Kopi dan ayang, kalo ada Aplikasi : Command prompt (sudah ada di komputer kalian) Visual Studio Code, download disini : https://code.visualstudio.com/Download NodeJS versi 16, download disini : http://nodejs.cn/download/ Tutorial (Step 1) : Buka website ini kemudian klik “Start Build” dan login pakai akun Google-mu. https://buildspace.so/builds/solidity Klik “Add to Calendar” dan hubungkan akun Discord-mu, lalu klik “Lets go!” Pada fase “Welcome, let's get you the details!”, isi alasan atau motivasi kamu dalam mengikuti event ini. Gunakan bahasa inggris ya. Siapkan command prompt (CMD) kamu, lalu lanjut ke fase “Get your local Ethereum networking running - 1” dan pastikan sudah menginstall NodeJS versi 16. Ketik : node -v di CMD, apabila sudah versi 16 maka lanjut ke step berikutnya. ketik ini : mkdir my-wave-portal cd my-wave-portal npm init -y npm install --save-dev hardhat@latest Kalo hasilnya seperti berikut, maka lanjut ke step berikutnya ya. Ketik npx hardhat lalu pilih “Create javascript”, untuk folder biarkan default saja, kemudian tekan y dan enter. setelah selesai, jalankan code berikut : npm install --save-dev "hardhat@^2.12.2" "@nomicfoundation/hardhat-toolbox@^2.0.0" maka hasilnya akan kurang lebih seperti ini : Buka aplikasi VS Code > File > Open Folder > Pilih folder “my-wave-portal” yang udah kamu install sebelumnya. Buat/edit file hardhat.config.js dan isi code berikut : require("@nomicfoundation/hardhat-toolbox"); // This is a sample Hardhat task. To learn how to create your own go to // https://hardhat.org/guides/create-task.html task("accounts", "Prints the list of accounts", async (taskArgs, hre) => { const accounts = await hre.ethers.getSigners(); for (const account of accounts) { console.log(account.address); } }); // You need to export an object to set up your config // Go to https://hardhat.org/config/ to learn more /** * @type import('hardhat/config').HardhatUserConfig */ module.exports = { solidity: "0.8.17", }; Save, lalu run npx hardhat node di CMD kamu. Nanti disana akan muncul 15 address, TOLONG JANGAN DI CLOSE. Buka CMD baru, lalu ketik code berikut : cd my-wave-portal npx hardhat compile npx hardhat test hasilnya akan seperti ini, kalo iya silakan lanjut. Kemudian kembali ke aplikasi VS Code dan silakan hapus file lock.js di folder test, deploy.js di folder scripts, dan lock.sol di folder contracts. Setelah itu, submit screenshot dari CMD kamu yang berisi 15 alamat di step sebelumnya ke Discord official Buildspace di channel #progress (link Discord ada diatas ya) Submit juga screenshot tersebut di website Buildspace dengan cara klik “Submit Requirement”. Tutorial (Step 2) : Buka aplikasi VS Code, buat file WavePortal.sol di dalam folder contracts isi dengan code berikut : // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.17; import "hardhat/console.sol"; contract WavePortal { constructor() { console.log("Yo yo, I am a contract and I am smart"); } } Download extension Solidity di link berikut : https://marketplace.visualstudio.com/items?itemName=JuanBlanco.solidity&utm_source=buildspace.so&utm_medium=buildspace_project Screenshot code kamu di WavePortal.sol dan upload di website + Discord Buildspace. Tutorial (Step 3) : Kembali ke aplikasi VS Code, buat file dengan nama run.js dan taruh didalam folder scripts kemudian isi dengan code berikut : const main = async () => { const waveContractFactory = await hre.ethers.getContractFactory("WavePortal"); const waveContract = await waveContractFactory.deploy(); await waveContract.deployed(); console.log("Contract deployed to:", waveContract.address); }; const runMain = async () => { try { await main(); process.exit(0); // exit Node process without error } catch (error) { console.log(error); process.exit(1); // exit Node process while indicating 'Uncaught Fatal Exception' error } // Read more about Node exit ('process.exit(num)') status codes here: https://stackoverflow.com/a/47163396/7974948 }; runMain(); Buka CMD kamu yang ke-2 (yang sedang nganggur), kemudian tulis command ini npx hardhat run scripts/run.js dan screenshot + submit hasil dari command tersebut di Discord + website Buildspace. Tutorial (Step 4) : Edit file WavePortal.sol yang ada didalam folder contracts dan isi dengan code berikut : // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.17; import "hardhat/console.sol"; contract WavePortal { uint256 totalWaves; constructor() { console.log("Yo yo, I am a contract and I am smart"); } function wave() public { totalWaves += 1; console.log("%s has waved!", msg.sender); } function getTotalWaves() public view returns (uint256) { console.log("We have %d total waves!", totalWaves); return totalWaves; } } Edit file run.js dan isi dengan code berikut : const main = async () => { const [owner, randomPerson] = await hre.ethers.getSigners(); const waveContractFactory = await hre.ethers.getContractFactory("WavePortal"); const waveContract = await waveContractFactory.deploy(); await waveContract.deployed(); console.log("Contract deployed to:", waveContract.address); console.log("Contract deployed by:", owner.address); await waveContract.getTotalWaves(); const waveTxn = await waveContract.wave(); await waveTxn.wait(); await waveContract.getTotalWaves(); }; const runMain = async () => { try { await main(); process.exit(0); } catch (error) { console.log(error); process.exit(1); } }; runMain(); Kemudian buka CMD kamu lagi, dan run command ini npx hardhat run scripts/run.js dan hasilnya sebagai berikut : Setelah selesai, buka website Buildspace dan submit kembali. Untuk kata-katanya, isi dengan Create my first eth contract. Tutorial (Step 5) : Kembali ke aplikasi VS Code kemudian tambahkan/edit file deploy.js didalam folder scripts dengan code berikut : const main = async () => { const [deployer] = await hre.ethers.getSigners(); const accountBalance = await deployer.getBalance(); console.log("Deploying contracts with account: ", deployer.address); console.log("Account balance: ", accountBalance.toString()); const waveContractFactory = await hre.ethers.getContractFactory("WavePortal"); const waveContract = await waveContractFactory.deploy(); await waveContract.deployed(); console.log("WavePortal address: ", waveContract.address); }; const runMain = async () => { try { await main(); process.exit(0); } catch (error) { console.log(error); process.exit(1); } }; runMain(); kemudian run command berikut (dengan catatan, posisi folder di CMD kamu sekarang berada didalam folder my-wave-portal) : npx hardhat run scripts/deploy.js --network localhost Copy WavePortal address, dan simpan di tempat terbaik. Screenshot hasilnya, dan submit di website Buildspace. Tutorial (Step 6) : Buat akun di Replit, kemudian buka link berikut dan klik “Fork Repl” dan langsung tekan enter saja (nama proyek tidak usah dirubah) : https://replit.com/@adilanchian/waveportal-starter-project?v=1&utm_source=buildspace.so&utm_medium=buildspace_project Setelah berhasil, silakan tekan RUN. Kemudian copy link seperti yang saya tunjuk, lalu submit di website Buildspace. Tutorial (Step 7) : Buat akun di website QuickNode, kemudian klik “Create endpoint” : https://www.quicknode.com/ Step 1 > Pilih Ethereum Step 2 > Pilih Goerli Step 3 > Tidak usah di edit, langsung tekan “Continue” saja. Pada bagian “Plan”, pilih yang “Discover” Create! Setelah jadi, back-up link kamu di bagian “HTTP Provider” Kembali ke CMD kamu yang nganggur, ketik npm install --save dotenv Kembali ke aplikasi VS Code, edit file hardhat.config.js dan isi dengan code berikut : require("@nomicfoundation/hardhat-toolbox"); // Import and configure dotenv require("dotenv").config(); module.exports = { solidity: "0.8.17", networks: { goerli: { // This value will be replaced on runtime url: process.env.STAGING_QUICKNODE_KEY, accounts: [process.env.PRIVATE_KEY], }, }, }; Setelah itu, kembali ke CMD dan ketik echo test>.env, hasilnya seperti berikut : Kemudian cek di aplikasi VS Code, nanti akan ada muncul file baru dengan nama .env, edit file tersebut dan isi ini : STAGING_QUICKNODE_KEY=isi_dengan_https_dari_QuickNode_tadi PRIVATE_KEY=isi_dengan_private_key_metamask_kamu Save, kemudian run command npx hardhat run scripts/deploy.js --network goerli di CMD dan hasilnya seperti : Silakan buka website berikut dan ambil LINK TRANSAKSI HASH kamu disana : https://goerli.etherscan.io/ Submit link tersebut di website Buildspace Tutorial (Step 8) : Kembali buka akun Replit kamu, buka folder src dan edit file App.jsx dan replace code tersebut dengan ini ya ges ya : import React, { useEffect, useState } from "react"; import "./App.css"; const getEthereumObject = () => window.ethereum; /* * This function returns the first linked account found. * If there is no account linked, it will return null. */ const findMetaMaskAccount = async () => { try { const ethereum = getEthereumObject(); /* * First make sure we have access to the Ethereum object. */ if (!ethereum) { console.error("Make sure you have Metamask!"); return null; } console.log("We have the Ethereum object", ethereum); const accounts = await ethereum.request({ method: "eth_accounts" }); if (accounts.length !== 0) { const account = accounts[0]; console.log("Found an authorized account:", account); return account; } else { console.error("No authorized account found"); return null; } } catch (error) { console.error(error); return null; } }; const App = () => { const [currentAccount, setCurrentAccount] = useState(""); const connectWallet = async () => { try { const ethereum = getEthereumObject(); if (!ethereum) { alert("Get MetaMask!"); return; } const accounts = await ethereum.request({ method: "eth_requestAccounts", }); console.log("Connected", accounts[0]); setCurrentAccount(accounts[0]); } catch (error) { console.error(error); } }; /* * This runs our function when the page loads. * More technically, when the App component "mounts". */ useEffect(async () => { const account = await findMetaMaskAccount(); if (account !== null) { setCurrentAccount(account); } }, []); return ( <div className="mainContainer"> <div className="dataContainer"> <div className="header"> 👋 Hey there! </div> <div className="bio"> I am Farza and I worked on self-driving cars so that's pretty cool right? Connect your Ethereum wallet and wave at me! </div> <button className="waveButton" onClick={null}> Wave at Me </button> {/* * If there is no currentAccount render this button */} {!currentAccount && ( <button className="waveButton" onClick={connectWallet}> Connect Wallet </button> )} </div> </div> ); }; export default App; Tekan “RUN” kembali, seperti di step sebelumnya. Nanti hasilnya seperti ini : Silakan koneksikan wallet yang private-key nya sudah kamu submit tadi di website tersebut. Buka website Buildspace kembali, klik “Submit Requirement” dan isi form tersebut dengan kalimat indahmu ;) Tutorial (Step 9) : Kembali ke Replit lagi, kita edit file App.jsx lagi dan isi dengan code berikut : import React, { useEffect, useState } from "react"; import { ethers } from "ethers"; import './App.css'; import abi from './utils/WavePortal.json'; const App = () => { const [currentAccount, setCurrentAccount] = useState(""); /** * Create a varaible here that holds the contract address after you deploy! */ const contractAddress = "0xd5f08a0ae197482FA808cE84E00E97d940dBD26E"; const contractABI = abi.abi; const checkIfWalletIsConnected = async () => { try { const { ethereum } = window; if (!ethereum) { console.log("Make sure you have metamask!"); return; } else { console.log("We have the ethereum object", ethereum); } const accounts = await ethereum.request({ method: 'eth_accounts' }); if (accounts.length !== 0) { const account = accounts[0]; console.log("Found an authorized account:", account); setCurrentAccount(account) } else { console.log("No authorized account found") } } catch (error) { console.log(error); } } const connectWallet = async () => { try { const { ethereum } = window; if (!ethereum) { alert("Get MetaMask!"); return; } const accounts = await ethereum.request({ method: "eth_requestAccounts" }); console.log("Connected", accounts[0]); setCurrentAccount(accounts[0]); } catch (error) { console.log(error) } } const wave = async () => { try { const { ethereum } = window; if (ethereum) { const provider = new ethers.providers.Web3Provider(ethereum); const signer = provider.getSigner(); const wavePortalContract = new ethers.Contract(contractAddress, contractABI, signer); let count = await wavePortalContract.getTotalWaves(); console.log("Retrieved total wave count...", count.toNumber()); const waveTxn = await wavePortalContract.wave(); console.log("Mining...", waveTxn.hash); await waveTxn.wait(); console.log("Mined -- ", waveTxn.hash); count = await wavePortalContract.getTotalWaves(); console.log("Retrieved total wave count...", count.toNumber()); } else { console.log("Ethereum object doesn't exist!"); } } catch (error) { console.log(error) } } useEffect(() => { checkIfWalletIsConnected(); }, []) return ( <div className="mainContainer"> <div className="dataContainer"> <div className="header"> 👋 Hey there! </div> <div className="bio"> I am farza and I worked on self-driving cars so that's pretty cool right? Connect your Ethereum wallet and wave at me! </div> <button className="waveButton" onClick={wave}> Wave at Me </button> {!currentAccount && ( <button className="waveButton" onClick={connectWallet}> Connect Wallet </button> )} </div> </div> ); } export default App Pada bagian const contractAddress, silakan ganti 0xblablabla dengan address WavePortal yang kita dapat dari step tutorial 5. Kembali ke Replit lagi, silakan buat folder dengan nama src didalam folder utils, dan buat file dengan nama `WavePortal.json`. Kembali ke VS Code lalu buka file ini artifacts/contracts/WavePortal.sol/WavePortal.json, kemudian ambil isinya dan paste ke file di Replit yang baru kita buat tadi. Setelah itu, buka website yang kamu generate di Replit, klik “Connect”, dan klik “Wave at Me”. Terima approval yang muncul di Metamask jaringan GOERLI. Screenshot website kamu, dan upload di website Buildspace <3 Tutorial (Step 10) : Kembali ke VS Code, dan edit file WavePortal.sol yang kita buat diawal tadi. // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.17; import "hardhat/console.sol"; contract WavePortal { uint256 totalWaves; /* * A little magic, Google what events are in Solidity! */ event NewWave(address indexed from, uint256 timestamp, string message); /* * I created a struct here named Wave. * A struct is basically a custom datatype where we can customize what we want to hold inside it. */ struct Wave { address waver; // The address of the user who waved. string message; // The message the user sent. uint256 timestamp; // The timestamp when the user waved. } /* * I declare a variable waves that lets me store an array of structs. * This is what lets me hold all the waves anyone ever sends to me! */ Wave[] waves; constructor() { console.log("I AM SMART CONTRACT. POG."); } /* * You'll notice I changed the wave function a little here as well and * now it requires a string called _message. This is the message our user * sends us from the frontend! */ function wave(string memory _message) public { totalWaves += 1; console.log("%s waved w/ message %s", msg.sender, _message); /* * This is where I actually store the wave data in the array. */ waves.push(Wave(msg.sender, _message, block.timestamp)); /* * I added some fanciness here, Google it and try to figure out what it is! * Let me know what you learn in #general-chill-chat */ emit NewWave(msg.sender, block.timestamp, _message); } /* * I added a function getAllWaves which will return the struct array, waves, to us. * This will make it easy to retrieve the waves from our website! */ function getAllWaves() public view returns (Wave[] memory) { return waves; } function getTotalWaves() public view returns (uint256) { // Optional: Add this line if you want to see the contract print the value! // We'll also print it over in run.js as well. console.log("We have %d total waves!", totalWaves); return totalWaves; } } Edit file run.js dengan ini : const main = async () => { const waveContractFactory = await hre.ethers.getContractFactory("WavePortal"); const waveContract = await waveContractFactory.deploy(); await waveContract.deployed(); console.log("Contract addy:", waveContract.address); let waveCount; waveCount = await waveContract.getTotalWaves(); console.log(waveCount.toNumber()); /** * Let's send a few waves! */ let waveTxn = await waveContract.wave("A message!"); await waveTxn.wait(); // Wait for the transaction to be mined const [_, randomPerson] = await hre.ethers.getSigners(); waveTxn = await waveContract.connect(randomPerson).wave("Another message!"); await waveTxn.wait(); // Wait for the transaction to be mined let allWaves = await waveContract.getAllWaves(); console.log(allWaves); }; const runMain = async () => { try { await main(); process.exit(0); } catch (error) { console.log(error); process.exit(1); } }; runMain(); Buka CMD kamu yang nganggur, dan ketik command ini npx hardhat run scripts/run.js dan liat hasilnya. Kita run ulang command berikut dan SAVE WavePortal address kamu : npx hardhat run scripts/deploy.js --network goerli Buka Replit lagi, dan edit contractAddress di file App.js dan replace dengan WavePortal yang baru kamu generate. (OPSIONAL) kamu bisa pakai code lain di App.js, semisal ingin membuat tampilannya lebih baik ~ Berikut codenya (INGAT, INI OPSIONAL) : import React,{useEffect,useState} from "react"; import { ethers } from "ethers"; import './App.css'; import abi from './utils/WavePortal.json'; export default function App() { const [currentAccount,setCurrentAccount]=useState(""); const [totalWaves,setTotalWaves]=useState(); const [allwaves,setAllwaves]=useState([]); const [inputValue,setInputValue]= useState(''); const contractAddress = "0xD014C8260bbF382D2ecCf0eb832c20A38c070F3b"; const contractABI = abi.abi; const chainId = `0x5`; const rpcURL = 'https://rpc.ankr.com/eth_goerli'; const networkName = 'Goerli Network'; const currencyName = 'ETH'; const currencySymbol = 'ETH'; const explorerURL = 'https://goerli.etherscan.io/'; const addNetwork = async () => { await window.ethereum.request({ method: 'wallet_addEthereumChain', params: [ { chainId: chainId, chainName: networkName, rpcUrls: [rpcURL], blockExplorerUrls: [explorerURL], nativeCurrency: { name: currencyName, symbol: currencySymbol, // 2-6 characters long decimals: 18, }, }, ], }); // refresh window.location.reload(); }; const checkIfWalletIsConnected = async ()=>{ try { const {ethereum} = window; if(!ethereum){ console.log("make sure you have metamask"); return; }else{ console.log("we have the etherum object") } const accounts = await ethereum.request({method: "eth_accounts"}) if(accounts.length!==0){ const account = accounts[0]; await getAllWaves(); setCurrentAccount(account); }else{ console.log("No authorized account found") } } catch (error) { console.log(error); } } const wave = async () => { try { const {ethereum} = window; if(ethereum){ const provider = new ethers.providers.Web3Provider(ethereum); const signer = provider.getSigner(); const wavePortalContract = new ethers.Contract(contractAddress, contractABI, signer); let count = await wavePortalContract.getTotalWaves(); console.log("Retrieved total wave count...", count.toNumber()); const waveTxn = await wavePortalContract.wave(inputValue,{gasLimit: 300000}); console.log("Mining...", waveTxn.hash); await waveTxn.wait(); console.log("Mined -- ", waveTxn.hash); count = await wavePortalContract.getTotalWaves(); // await getAllWaves(); setTotalWaves(count.toNumber()); console.log("Retrieved total wave count...", count.toNumber()); }else{ console.log("ethereum object doesn't exist") } } catch (error) { console.log(error); } } const connectWallet = async () => { try { const { ethereum } = window; if (!ethereum) { alert("Get MetaMask!"); return; } const accounts = await ethereum.request({ method: "eth_requestAccounts" }); console.log("Connected", accounts[0]); setCurrentAccount(accounts[0]); } catch (error) { console.log(error) } } useEffect(()=>{ checkIfWalletIsConnected(); },[currentAccount]) const fetchTotal = async ()=>{ const {ethereum} = window; if(ethereum){ const provider = new ethers.providers.Web3Provider(ethereum); const signer = provider.getSigner(); const wavePortalContract = new ethers.Contract(contractAddress, contractABI, signer); let count = await wavePortalContract.getTotalWaves(); setTotalWaves(count.toNumber()); console.log("Retrieved total wave count...", count.toNumber()); }else{ console.log("ethereum object doesn't exist") } } useEffect(async ()=>{ await fetchTotal(); },[totalWaves]) const getAllWaves=async ()=>{ try { if(ethereum){ const provider = new ethers.providers.Web3Provider(ethereum); const signer = provider.getSigner(); const wavePortalContract = new ethers.Contract(contractAddress, contractABI, signer); const waves = await wavePortalContract.getAllWaves(); console.log(waves); let wavesArr = []; waves.forEach(wave => { wavesArr.push({ address: wave.waver, timestamp: new Date(wave.timestamp * 1000), message: wave.message }); }); setAllwaves(wavesArr); } } catch (error) { console.log(error); } } useEffect(()=>{ let wavePortalContract; const onNewWave = (from, timestamp, message) => { console.log('NewWave', from, timestamp, message); setAllwaves(prevState => [ ...prevState, { address: from, timestamp: new Date(timestamp * 1000), message: message, }, ]); }; if (window.ethereum) { const provider = new ethers.providers.Web3Provider(window.ethereum); const signer = provider.getSigner(); wavePortalContract = new ethers.Contract(contractAddress, contractABI, signer); wavePortalContract.on('NewWave', onNewWave); } return () => { if (wavePortalContract) { wavePortalContract.off('NewWave', onNewWave); } }; },[]) return ( <div className="mainContainer"> <div className="dataContainer"> <div className="header"> <div>👋 Hey there!</div> <div className="add" onClick={addNetwork}>Add Goerli to Wallet</div> </div> <div className="bio"> I am farza and I worked on self-driving cars so that's pretty cool right? Connect your Ethereum wallet and wave at me! </div> <div className="inputWrapper"> <input className="messageBox" placeholder="Please input wave message" onChange={(e)=>{ setInputValue(e.target.value); }}></input> <button className="waveButton" onClick={wave}> Wave at Me </button> </div> {!currentAccount&&( <button className="connectButton" onClick={connectWallet}>Connect Wallet</button> )} <div> TotalWaves: {totalWaves} </div> {allwaves.map((wave,index)=>{ return ( <div key={index} className="messageCard"> <div>Address: {wave.address}</div> <div>Timestamp: {wave.timestamp.toString()}</div> <div>Message: {wave.message}</div> </div> ) })} </div> </div> ); } Buka website hasil generate di Replit, dan liat tampilannya sekarang. Silakan screenshot dan submit di Discord dan website Buildspace. Tutorial (Step 11) : Kembali ke Replit, edit file App.js dengan code berikut : import React, { useEffect, useState } from "react"; import { ethers } from "ethers"; import './App.css'; import wavePortal from './utils/WavePortal.json'; const App = () => { const [currentAccount, setCurrentAccount] = useState(""); const [allWaves, setAllWaves] = useState([]); const contractAddress = "0xd5f08a0ae197482FA808cE84E00E97d940dBD26E"; const getAllWaves = async () => { try { if (window.ethereum) { const provider = new ethers.providers.Web3Provider const signer = provider.getSigner(); const wavePortalContract = new ethers.Contract(contractAddress, wavePortal.abi, signer); const waves = await wavePortalContract.getAllWaves(); let wavesCleaned = []; waves.forEach(wave => { wavesCleaned.push({ address: wave.waver, timestamp: new Date(wave.timestamp * 1000), message: wave.message }); }); setAllWaves(wavesCleaned); } else { console.log("Ethereum object doesn't exist!") } } catch (error) { console.log(error); } } const checkIfWalletIsConnected = async () => { try { const { ethereum } = window; if (!ethereum) { console.log("Make sure you have metamask!"); return; } else { console.log("We have the ethereum object", ethereum); } const accounts = await ethereum.request({ method: 'eth_accounts' }); if (accounts.length !== 0) { const account = accounts[0]; console.log("Found an authorized account:", account); setCurrentAccount(account) } else { console.log("No authorized account found") } } catch (error) { console.log(error); } } const connectWallet = async () => { try { const { ethereum } = window; if (!ethereum) { alert("Get MetaMask!"); return; } const accounts = await ethereum.request({ method: "eth_requestAccounts" }); console.log("Connected", accounts[0]); setCurrentAccount(accounts[0]); } catch (error) { console.log(error) } } const wave = async () => { try { const { ethereum } = window; if (ethereum) { const provider = new ethers.providers.Web3Provider(ethereum); const signer = provider.getSigner(); const wavePortalContract = new ethers.Contract(contractAddress, wavePortal.abi, signer); let count = await wavePortalContract.getTotalWaves(); console.log("Retrieved total wave count...", count.toNumber()); const waveTxn = await wavePortalContract.wave(); console.log("Mining...", waveTxn.hash); await waveTxn.wait(); console.log("Mined -- ", waveTxn.hash); count = await wavePortalContract.getTotalWaves(); console.log("Retrieved total wave count...", count.toNumber()); } else { console.log("Ethereum object doesn't exist!"); } } catch (error) { console.log(error) } } useEffect(() => { checkIfWalletIsConnected(); }, []) return ( <div className="mainContainer"> <div className="dataContainer"> <div className="header"> 👋 Hey there! </div> <div className="bio"> I am farza and I worked on self-driving cars so that's pretty cool right? Connect your Ethereum wallet and wave at me! </div> <button className="waveButton" onClick={wave}> Wave at Me </button> {!currentAccount && ( <button className="waveButton" onClick={connectWallet}> Connect Wallet </button> )} {allWaves.map((wave, index) => { return ( <div style={{ backgroundColor: "OldLace", marginTop: "16px", padding: "8px" }}> <div>Address: {wave.address}</div> <div>Time: {wave.timestamp.toString()}</div> <div>Message: {wave.message}</div> </div>) })} </div> </div> ); } export default App Buka aplikasi VS Code di komputermu, dan edit deploy.js jadi begini : const main = async () => { const waveContractFactory = await hre.ethers.getContractFactory('WavePortal'); const waveContract = await waveContractFactory.deploy({ value: hre.ethers.utils.parseEther('0.001'), }); await waveContract.deployed(); console.log('WavePortal address: ', waveContract.address); }; const runMain = async () => { try { await main(); process.exit(0); } catch (error) { console.error(error); process.exit(1); } }; runMain(); Masih di VS Code, edit file run.js jadi begini : const main = async () => { const waveContractFactory = await hre.ethers.getContractFactory('WavePortal'); const waveContract = await waveContractFactory.deploy({ value: hre.ethers.utils.parseEther('0.01'), }); await waveContract.deployed(); console.log('Contract addy:', waveContract.address); let contractBalance = await hre.ethers.provider.getBalance( waveContract.address ); console.log( 'Contract balance:', hre.ethers.utils.formatEther(contractBalance) ); let waveTxn = await waveContract.wave('A message!'); await waveTxn.wait(); contractBalance = await hre.ethers.provider.getBalance(waveContract.address); console.log( 'Contract balance:', hre.ethers.utils.formatEther(contractBalance) ); let allWaves = await waveContract.getAllWaves(); console.log(allWaves); }; const runMain = async () => { try { await main(); process.exit(0); } catch (error) { console.log(error); process.exit(1); } }; runMain(); Masih di VS Code ya ges ya, edit file WavePortal.sol dengan code : // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "hardhat/console.sol"; contract WavePortal { uint256 totalWaves; event NewWave(address indexed from, uint256 timestamp, string message); struct Wave { address waver; string message; uint256 timestamp; } Wave[] waves; constructor() payable { console.log("We have been constructed!"); } function wave(string memory _message) public { totalWaves += 1; console.log("%s has waved!", msg.sender); waves.push(Wave(msg.sender, _message, block.timestamp)); emit NewWave(msg.sender, block.timestamp, _message); uint256 prizeAmount = 0.0001 ether; require( prizeAmount <= address(this).balance, "Trying to withdraw more money than they contract has." ); (bool success, ) = (msg.sender).call{value: prizeAmount}(""); require(success, "Failed to withdraw money from contract."); } function getAllWaves() public view returns (Wave[] memory) { return waves; } function getTotalWaves() public view returns (uint256) { return totalWaves; } } Run command berikut di CMD, untuk ngecek hasil dari code-code diatas : npx hardhat run scripts/run.js Hasilnya seperti ini : Kemudian, kita coba deploy kontrak baru dengan cara npx hardhat run scripts/deploy.js --network goerli di CMD kamu. Setelah itu, cek hasilnya di : https://goerli.etherscan.io/?utm_source=buildspace.so&utm_medium=buildspace_project Submit hasilnya di website Buildspace. Tutorial (Step 12) : Kembali ke VSC, edit file WavePortal.sol dengan ini : // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "hardhat/console.sol"; contract WavePortal { uint256 totalWaves; /* * We will be using this below to help generate a random number */ uint256 private seed; event NewWave(address indexed from, uint256 timestamp, string message); struct Wave { address waver; string message; uint256 timestamp; } Wave[] waves; constructor() payable { console.log("We have been constructed!"); /* * Set the initial seed */ seed = (block.timestamp + block.difficulty) % 100; } function wave(string memory _message) public { totalWaves += 1; console.log("%s has waved!", msg.sender); waves.push(Wave(msg.sender, _message, block.timestamp)); /* * Generate a new seed for the next user that sends a wave */ seed = (block.difficulty + block.timestamp + seed) % 100; console.log("Random # generated: %d", seed); /* * Give a 50% chance that the user wins the prize. */ if (seed < 50) { console.log("%s won!", msg.sender); /* * The same code we had before to send the prize. */ uint256 prizeAmount = 0.0001 ether; require( prizeAmount <= address(this).balance, "Trying to withdraw more money than the contract has." ); (bool success, ) = (msg.sender).call{value: prizeAmount}(""); require(success, "Failed to withdraw money from contract."); } emit NewWave(msg.sender, block.timestamp, _message); } function getAllWaves() public view returns (Wave[] memory) { return waves; } function getTotalWaves() public view returns (uint256) { return totalWaves; } } Edit run.js dengan ini : const main = async () => { const waveContractFactory = await hre.ethers.getContractFactory("WavePortal"); const waveContract = await waveContractFactory.deploy({ value: hre.ethers.utils.parseEther("0.1"), }); await waveContract.deployed(); console.log("Contract addy:", waveContract.address); let contractBalance = await hre.ethers.provider.getBalance( waveContract.address ); console.log( "Contract balance:", hre.ethers.utils.formatEther(contractBalance) ); /* * Let's try two waves now */ const waveTxn = await waveContract.wave("This is wave #1"); await waveTxn.wait(); const waveTxn2 = await waveContract.wave("This is wave #2"); await waveTxn2.wait(); contractBalance = await hre.ethers.provider.getBalance(waveContract.address); console.log( "Contract balance:", hre.ethers.utils.formatEther(contractBalance) ); let allWaves = await waveContract.getAllWaves(); console.log(allWaves); }; const runMain = async () => { try { await main(); process.exit(0); } catch (error) { console.log(error); process.exit(1); } }; runMain(); Kemudian run command berikut di CMD kamu yang nganggur : npx hardhat run scripts/run.js Hasilnya : Kita edit kembali file WavePortal.sol dan isi dengan ini : // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.17; import "hardhat/console.sol"; contract WavePortal { uint256 totalWaves; uint256 private seed; event NewWave(address indexed from, uint256 timestamp, string message); struct Wave { address waver; string message; uint256 timestamp; } Wave[] waves; /* * This is an address => uint mapping, meaning I can associate an address with a number! * In this case, I'll be storing the address with the last time the user waved at us. */ mapping(address => uint256) public lastWavedAt; constructor() payable { console.log("We have been constructed!"); /* * Set the initial seed */ seed = (block.timestamp + block.difficulty) % 100; } function wave(string memory _message) public { /* * We need to make sure the current timestamp is at least 15-minutes bigger than the last timestamp we stored */ require( lastWavedAt[msg.sender] + 15 minutes < block.timestamp, "Wait 15m" ); /* * Update the current timestamp we have for the user */ lastWavedAt[msg.sender] = block.timestamp; totalWaves += 1; console.log("%s has waved!", msg.sender); waves.push(Wave(msg.sender, _message, block.timestamp)); /* * Generate a new seed for the next user that sends a wave */ seed = (block.difficulty + block.timestamp + seed) % 100; if (seed <= 50) { console.log("%s won!", msg.sender); uint256 prizeAmount = 0.0001 ether; require( prizeAmount <= address(this).balance, "Trying to withdraw more money than they contract has." ); (bool success, ) = (msg.sender).call{value: prizeAmount}(""); require(success, "Failed to withdraw money from contract."); } emit NewWave(msg.sender, block.timestamp, _message); } function getAllWaves() public view returns (Wave[] memory) { return waves; } function getTotalWaves() public view returns (uint256) { return totalWaves; } } Setelah itu, buka CMD dan run ini : npx hardhat run scripts/run.js Nanti disana akan ada error, silakan tunggu 15 menit kemudian RUN lagi. Contoh bisa diliat sebagai berikut : Setelah kamu run lagi dan hash-nya muncul, silakan ke explorer Goerli dan copy link-nya. Kemudian, submit di website Buildspace. Tutorial (Step 13 - Terakhir) : Buka website hasil generate di Replit, kemudian edit sesuka hati. Screenshot, submit di website Buildspace. Done! Catatan : Jadi kalian perlu ngebuka setidaknya 2-3 command prompt, 1 untuk yg idle atau standby, sisanya untuk ngegarap semua command yang ada. Pengiriman hadiah NFT dilakukan dalam 7 hari. Jika ada pertanyaan, silakan tanyakan di grup Telegram : https://t.me/HappyCuanAirdrop Credits : https://mirror.xyz/0xCD0e394639B2D0b159B41F9dBe0583C33d85e874/1EJbrgGMc44-Pwoimu2DrjTiDgN4uevTMPTF2upeyTQ ## Publication Information - [Rama.tori (💙,🧡)(📦,💫) (((🔴🤏🌍))) 🛸🦇🔊🤖🛸](https://paragraph.com/@rama-tori/): Publication homepage - [All Posts](https://paragraph.com/@rama-tori/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@rama-tori): Subscribe to updates - [Twitter](https://twitter.com/0xkindasus): Follow on Twitter