# Buildspace Testnet Guide

By [Rama.tori (💙,🧡)(📦,💫) (((🔴🤏🌍))) 🛸🦇🔊🤖🛸](https://paragraph.com/@rama-tori) · 2022-12-01

---

### 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](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](https://code.visualstudio.com/Download)
    
*   NodeJS versi 16, download disini :
    
    [http://nodejs.cn/download/](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](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.

![](https://storage.googleapis.com/papyrus_images/a2190483863bd7d981dd6da4a47e574f5f59a35c6e420792b734bb5e9200b5ff.png)

![](https://storage.googleapis.com/papyrus_images/5e9825d55f11d3efa853501687278614659c858010520b16407642cb72e5f71d.png)

*   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 :
    

![](https://storage.googleapis.com/papyrus_images/2c1453c40eaf183596324ce6103a06ba335edde31c7752b8aeeb2bc1d269cef1.png)

*   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.
    

![](https://storage.googleapis.com/papyrus_images/ccc27563f53164f0a47658f925d2b82af8ac62f43cc085f7cf1f688d00cb2144.png)

*   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”.
    

![](https://storage.googleapis.com/papyrus_images/03cc5bbaa3d79b9b07d52a2ddb860690b9c2393acd092c2e60d47a1948f2bcde.png)

### 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](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.
    

![](https://storage.googleapis.com/papyrus_images/374e91321ac18960c11459d5c7779bcb30058eb73a1e749f08a6cb72c002aa76.png)

### 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 :
    

![](https://storage.googleapis.com/papyrus_images/77e1e0aff308d0815f202e9902908168d29f3fa2d6fd8d961d14ef9699ffe380.png)

*   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.
    

![](https://storage.googleapis.com/papyrus_images/e53588fcba0f643f3385bc47e818a3fbd86d8cdc46abf42e39394cceb1e22cc6.png)

### 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](https://replit.com/@adilanchian/waveportal-starter-project?v=1&utm_source=buildspace.so&utm_medium=buildspace_project)
    

![](https://storage.googleapis.com/papyrus_images/db6672a3fe3940821079c09507b711f17296557bf92744a789836bb092a6d0dd.png)

*   Setelah berhasil, silakan tekan RUN.
    

![](https://storage.googleapis.com/papyrus_images/814d07a834d2ef5e0644c32a12282ec4a9b24fc5937535edd46f5a575952758d.png)

*   Kemudian copy link seperti yang saya tunjuk, lalu submit di website Buildspace.
    

![](https://storage.googleapis.com/papyrus_images/a5d4a3a6691c0faec8a623aabd3295cbd2c958cb9d393d812224ac66703d10c9.png)

### Tutorial (Step 7) :

*   Buat akun di website QuickNode, kemudian klik “Create endpoint” :
    
    [https://www.quicknode.com/](https://www.quicknode.com/)
    

![](https://storage.googleapis.com/papyrus_images/c86ad8da852f6b5ddb9895eecc9647fb441ab5d300ec49e1b1d27f2a62283aa4.png)

*   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!
    

![](https://storage.googleapis.com/papyrus_images/6bce48ec63dd2a7949df530549d3b1328ce1d2c82535e1814dc7f141cfc47e1e.png)

*   Setelah jadi, back-up link kamu di bagian “HTTP Provider”
    

![](https://storage.googleapis.com/papyrus_images/b26c8151ec08e46d5f3a246fc97580d69e74ec860139d40b15a9d52b7e93a5f4.png)

*   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 :
    

![](https://storage.googleapis.com/papyrus_images/5502701d93ec8004e3a97710dfd177d78ca15ef8f2a5388af9b6d88786a98eb4.png)

*   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 :
    

![](https://storage.googleapis.com/papyrus_images/fef00631fdf1d18b6f8dcc09ab49194e6db73eb13706b3f9121639c4560f9996.png)

*   Silakan buka website berikut dan ambil LINK TRANSAKSI HASH kamu disana :
    
    [https://goerli.etherscan.io/](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 :
    

![](https://storage.googleapis.com/papyrus_images/4f7b1b8d4c975902267c12eed0b6a7cf9dc707e998e570e08a33e3ced151dbb4.png)

*   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\`.
    

![](https://storage.googleapis.com/papyrus_images/c0bf9d9af2f7200a8b1b57bfe23eee4b59384023459b7a9e2ba9dda9b5425272.png)

*   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
    

![](https://storage.googleapis.com/papyrus_images/13280a861a34d76f5822ebcd302854f5f6a07e06b253b856ec4ca89c0295747c.png)

### 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.
    

![](https://storage.googleapis.com/papyrus_images/8153ea2baddd8d3e6cc52abb134df309b711ba7f0aaeddcd59a36ba839882cca.png)

*   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.
    

![](https://storage.googleapis.com/papyrus_images/c656b7e36060abb35abfb6dee94af67ebe30df688c8ca81af430368d8b27daea.png)

### 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 :
    

![](https://storage.googleapis.com/papyrus_images/fb6a5849d4b1bdf3d28373495cdf11c1f219a67748766dc08697dff300859ed5.png)

*   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](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 :
    

![](https://storage.googleapis.com/papyrus_images/7e90ec5a9bfbe47a1261745338a3162f6abc402d8d9e06b1cea4dc6a06582a68.png)

*   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 :
    

![](https://storage.googleapis.com/papyrus_images/4fc200eb03404a6f79ccb8b618d1b5f7de46b9dca223c4c9f776609230dbccb1.png)

*   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.
    

![](https://storage.googleapis.com/papyrus_images/75ec81ff27a6cb2af35d349eec8104631167f4044e71c5861c3a743313822b40.png)

*   **Done!**
    

### Catatan :

1.  Jadi kalian perlu ngebuka setidaknya 2-3 command prompt, 1 untuk yg idle atau standby, sisanya untuk ngegarap semua command yang ada.
    
2.  Pengiriman hadiah NFT dilakukan dalam 7 hari.
    
3.  Jika ada pertanyaan, silakan tanyakan di grup Telegram :
    
    [https://t.me/HappyCuanAirdrop](https://t.me/HappyCuanAirdrop)
    

Credits :

[https://mirror.xyz/0xCD0e394639B2D0b159B41F9dBe0583C33d85e874/1EJbrgGMc44-Pwoimu2DrjTiDgN4uevTMPTF2upeyTQ](https://mirror.xyz/0xCD0e394639B2D0b159B41F9dBe0583C33d85e874/1EJbrgGMc44-Pwoimu2DrjTiDgN4uevTMPTF2upeyTQ)

---

*Originally published on [Rama.tori (💙,🧡)(📦,💫) (((🔴🤏🌍))) 🛸🦇🔊🤖🛸](https://paragraph.com/@rama-tori/buildspace-testnet-guide)*
