# Blockchain for Social Impact
## Intro
Hi Nama saya sofian hadiwijaya,
Sekarang saya sebagai CTO Alterra Group.
Sebelum ini saya 5 tahun sebagai CTO dan Co Founder Warung Pintar. Make Warung Great Again.
Buat temen temen yang bingung hubungan Alterra yang dikenal sebagai BillPayment company dan Blockchain. Mulai dari tahun lalu alterra sudah masuk ke web3 dari februari 2022.
Kita join venture sama RRQ untuk membuat RRQ Guild.
## Blockchain Benefit
Mungkin udah dibahas sebelumnya terkait sejarah web1 to web3. Dan sejarah singkat terkait lahirnya Blockchain sendiri.
Kali ini akan bahas sekilas aja, dan apa kaitannya dengan materi kita hari ini.
Ini berawal dari krisis finansial di US pada tahun 2007-2008.

Munculah ketidak percayaan terhadap institusi keuangan. Disaat yang bersamaan kelompok cryptopunk yang diprakarsai oleh satoshi nakamoto mulai mengimplemetasikan bitcoin, dimana kita bisa melakukan transaksi keuangan tanpa adanya pihak ketiga (institusi keuangan).
Blockchain masuk keranah Finance, dimana bitcoin menjadi salah satu alat pembayaran dan merambah sebagai mata uang. Enam tahun kemudian Vitalik Buterin membuat sebuah inovasi besar pada blokchain, dimana dia menyempurnakan sistem komputasi pada bitcoin, sehingga memungkinkan buat mengeksekusi kode yang lebih kompleks ketika terjadi transaksi. Yang sekarang kita kenal sebagai Smart Contract.
Hal ini yang menyebabkan blokchain digadang-gadangkan sebagai new internet dengen istilah web3.
- Dengan DeFi, secara natively blokchain akan punya sistem keuangan.
- Adanya SmartContract membuat kita bisa membuat sebuah aplikasi diatas blockchain.
- Blockchain menggunakan sistem kriptografi untuk signing sesuatu, dengan demikian akan membuat siapapun dengan gampang mempunyai identity secara aman.
Sekarang apa hubungannya dengan Social Impact?
 
Jika kita lihat tingkat literasi dan inklusi keugangan meningkat beberapa tahun terakhir, berkat adanya teknologi, Bahkan selama periode pelaksnaaan BIK (Bulan Inklusi Keuangan) tahun 2022, tercatat telah diselenggarakan sebanyak 2.538 kegiatan dengan total peserta sebanyak 1.599.860. Hingga saat ini capaian BIK tahun 2022 adalah sebesar:
- Industri Perbankan: pembukaan rekening baru sebanyak 2.037.105 rekening;
- Industri Pasar Modal sebanyak 64.228 rekening efek baru;
- Industri Perasuransian adalah sebanyak 69.091 polis;
- Industri Pembiayaan adalah sebanyak 451.638 debitur;
- Industri Pergadaian adalah sebanyak 2.878.570 rekening;
- Industri fintech adalah sebanyak 1.501.709 akun.
Tentunya jika masyarakat semakin mudah untuk mendapatkan akses ke keuangan, maka perputaran ekonomi akan semakin kuat. Dan menciptakan Financial Inclusion.
Beberapa hal yang bisa dilakukan teknologi web3 untuk Financial Inclusion.
- Digital Identity: Akan menjadi no rekening dan wallet mereka untuk kemudian melakukan transaksi keuangan.
- Microfinance: Dengan teknologi blockchain dan smart contractnya akan membuat lebih mudah dan murah bagi orang untuk mendapatkan pinjaman.
- Remittance: Melalui CryptoCurrency memudahkan para TKI dan juga traveller untuk melakukan aktifitas mereka.
- Access to Capital: Sekarang bisa juga melakukan fundraising dengan mudah.
- Digital Marketplace: Petani bisa saja menjual dalam partai besar, namun yang beli secara group buying.
## Challange and Limitations
Namun tentu nya Web3 sendiri saat ini masih terdapat banyak limitasi terutama di Indonesia.
- Accessibility : Wallet
- User Experience : Wallet
- Education :
- Exchange :
- Regulation :
- Adoption from Industri :
## Workshop
### Overview
Salah satu Platform social yang terkenal di indonesia adalah kitabisa.com. Platform dimana kita bisa membuat sebuah campaign untuk kebaikan, dan orang baik serta kita bisa berdonasi. Yang mana uang hasil donasi akan disalurkan kepada yang membutuhkan.
Namun ada beberapa kasus dimana uang hasil penggalangan dana, disalah gunakan oleh pelaku kejahatan.
Nah pada proyek hari ini kita mencoba membuat sistem crowdfunding ini menggunakan smart contract. Kemudian kita buatkan tampilan sederhana untuk berinteraksi dengan smart contract tersebut.
Pada platform sederhana ini, setidaknya orang baik bisa membuat kampanye atau proyek, melihat daftar proyek yang ada, berapa uang yang sudah terkumpul, donasi ke kampanye, vote ke kampanye, memberikan autorisasi ke pemilik kampanye untuk mengambil uangnya.
### Tools
- Code Editor
- Metamask
- Remix
- Git
- Browser ( Brave or Chrome)
- Testnet ETH
- Ganache ( Optional )
### Install Metamask on Browser
### Install Ganache
### Configure Metamask Network
### Integrasi Metamask ke Remix
### Membuat Smart Contract
Untuk kebutuhan pada proyek kita, kita akan membagi menjadi beberapa Kontrak, diantaranya :
- CrowdSaleToken.sol - Token untuk donasi ke platform
- LoveToken.sol - Setiap kali melakukan donasi atau project sukses, orang baik akan dapat LoveToken. LoveToken nantinya bisa digunakan untuk meng-upvote kampanye.
- TokenSwap.sol - Untuk menukarkan Native token ke CrowdsaleToken dan sebaliknya.
- Approval.sol - Policy ketika apa uang yang sudah terkumpul dapat di transfer ke owner proyek, yang kemudian bisa di withdraw.
- ProjectFundraise.sol - Ini merupakan core kontrak kita. Fungsinya untuk memanage Kampanye.
Oke mari kita mulai dengan CrowdsaleToken. Implementasi sederhana dari ERC20.
```solidity=
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract CrowdsaleToken is ERC20 {
constructor() ERC20("CrowdsaleToken", "CST") {}
function mint(address _to, uint256 _amount) public {
_mint(_to, _amount);
}
}
```
Jadi kita bisa import dari standar yang udah ada di Openzeppelin. Pada konstruktor kita set Nama dan Kode dari Token kita.
Berikutnya LoveToken.sol.
```solidity=
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract LoveToken is ERC20 {
constructor() ERC20("LoveToken", "LT") {}
function mint(address _to, uint256 _amount) public {
_mint(_to, _amount);
}
function burn(address from, uint256 amount) public {
require(balanceOf(from) >= amount, "Insufficient balance");
_burn(from, amount);
}
}
```
Kurang lebih mirip dengan CrowdsaleToken. Namun kita tambahkan burn, agar nanti ketika LoveToken digunakan untuk meng-upvote kampanye, kita bisa burn Tokennya.
Setelah itu untuk swap dari Native Token ke Crowdsale, kita akan butuh TokenSwap.sol
```solidity=
pragma solidity ^0.8.0;
import "./CrowdsaleToken.sol";
contract TokenSwap {
CrowdsaleToken public crowdsaleToken;
uint256 public rate; // number of CrowdsaleToken tokens per wei
constructor(CrowdsaleToken _crowdsaleToken, uint256 _rate) {
crowdsaleToken = _crowdsaleToken;
rate = _rate;
}
function swap() public payable {
require(msg.value > 0, "Need to send some ETH");
uint256 tokens = msg.value * rate * 1 ether;
crowdsaleToken.mint(msg.sender, tokens);
}
// Allows contract owner to withdraw any ETH that's been sent here
function withdraw() public {
payable(msg.sender).transfer(address(this).balance);
}
}
```
Pada konstruktor kita bisa set berapa rate dari Native Token ke CrowdsaleToken. Pada contoh hari ini saya coba buat 1 ETH = 100 CST.
Berikutnya Approval.sol
```solidity=
pragma solidity ^0.8.0;
contract Approval {
mapping(uint256 => bool) private approvals;
function approve(uint256 _projectId) public {
approvals[_projectId] = true;
}
function isApproved(uint256 _projectId) public view returns(bool) {
return approvals[_projectId];
}
}
```
Sangat sederhana, mungkin dikemudian hari kita ingin menambahkan sesuatu disini.
Dan terakhir kita punya ProjectFundraise.sol
```solidity=
pragma solidity ^0.8.0;
import "./CrowdsaleToken.sol";
import "./LoveToken.sol";
import "./Approval.sol";
contract ProjectFundraise {
struct Donation {
address donor;
uint256 amount;
}
struct Voter {
address voter;
}
struct Project {
address payable owner;
string description;
uint256 goal;
uint256 amountRaised;
mapping(uint => Donation) donations;
uint256 numDonations;
string imageUrl;
uint256 deadline;
uint256 votes;
mapping(uint => Voter) voters;
uint256 numVoters;
bool isWithdraw;
}
Project[] public projects;
CrowdsaleToken public crowdsaleToken;
LoveToken public loveToken;
Approval public approval;
constructor(CrowdsaleToken _crowdsaleToken, LoveToken _loveToken, Approval _approval) {
crowdsaleToken = _crowdsaleToken;
loveToken = _loveToken;
approval = _approval;
}
function createProject(string memory _description, uint256 _goal, string memory _imageUrl, uint256 _deadline) public {
require(_deadline > block.timestamp, "Deadline should be in the future");
Project storage newProject = projects.push();
newProject.owner = payable(msg.sender);
newProject.description = _description;
newProject.goal = _goal;
newProject.amountRaised = 0;
newProject.imageUrl = _imageUrl;
newProject.deadline = _deadline;
newProject.votes = 0;
newProject.numDonations = 0;
newProject.numVoters = 0;
newProject.isWithdraw = false;
}
function donate(uint256 _projectId, uint256 _amount) public {
Project storage project = projects[_projectId];
require(block.timestamp < project.deadline, "Project has reached its deadline");
require(crowdsaleToken.transferFrom(msg.sender, address(this), _amount), "Transfer failed");
project.amountRaised += _amount;
project.donations[project.numDonations++] = Donation({donor: msg.sender, amount: _amount});
loveToken.mint(msg.sender, _amount);
}
function approveTransfer(uint256 _projectId) public {
Project storage project = projects[_projectId];
require(project.amountRaised >= project.goal, "Project has not reached its goal");
require(block.timestamp < project.deadline, "Project has reached its deadline");
require(donorExists(_projectId, msg.sender), "Only donors can approve transfers");
approval.approve(_projectId);
}
function transfer(uint256 _projectId) public {
Project storage project = projects[_projectId];
require(project.isWithdraw == false, "Already withdraw");
require(project.owner == msg.sender, "Only project owner can transfer");
require(project.amountRaised >= project.goal, "Project has not reached its goal");
require(approval.isApproved(_projectId), "Transfer not approved");
require(crowdsaleToken.transfer(project.owner, project.amountRaised), "Transfer failed");
if (project.amountRaised >= project.goal) {
loveToken.mint(project.owner, project.votes);
}
project.amountRaised = 0;
project.isWithdraw = true;
}
function vote(uint256 _projectId) public {
Project storage project = projects[_projectId];
require(loveToken.balanceOf(msg.sender) > 0, "Must have LoveTokens to vote");
require(!hasVoted(_projectId, msg.sender), "You have already voted for this project");
loveToken.burn(msg.sender, 1);
project.votes++;
project.voters[project.numVoters++] = Voter({voter: msg.sender});
}
function hasVoted(uint256 _projectId, address _voter) private view returns(bool) {
Project storage project = projects[_projectId];
for(uint i = 0; i < project.numVoters; i++) {
if(project.voters[i].voter == _voter) {
return true;
}
}
return false;
}
function donorExists(uint256 _projectId, address _donor) private view returns(bool) {
Project storage project = projects[_projectId];
for(uint i = 0; i < project.numDonations; i++) {
if(project.donations[i].donor == _donor) {
return true;
}
}
return false;
}
function getProjectCount() public view returns(uint) {
return projects.length;
}
function getProject(uint _projectId) public view returns(address owner, string memory description, uint256 goal, uint256 amountRaised, string memory imageUrl, uint256 deadline, uint256 votes) {
Project storage project = projects[_projectId];
return (project.owner, project.description, project.goal, project.amountRaised, project.imageUrl, project.deadline, project.votes);
}
function getDonations(uint _projectId) public view returns(address[] memory, uint256[] memory) {
Project storage project = projects[_projectId];
address[] memory donorAddresses = new address[](project.numDonations);
uint256[] memory amounts = new uint256[](project.numDonations);
for (uint i = 0; i < project.numDonations; i++) {
donorAddresses[i] = project.donations[i].donor;
amounts[i] = project.donations[i].amount;
}
return (donorAddresses, amounts);
}
function getVoters(uint _projectId) public view returns(address[] memory) {
Project storage project = projects[_projectId];
address[] memory voterAddresses = new address[](project.numVoters);
for (uint i = 0; i < project.numVoters; i++) {
voterAddresses[i] = project.voters[i].voter;
}
return voterAddresses;
}
}
```
Fungsi utamanya adalah membuat sebuah kampanye, donasi dan voting. Namun disamping itu juga tersedia beberapa fungsi untuk melihat daftar kampanye dan detailnya.
Setelah selasai semua kita akan masuk ke tahap berikutnya.
### Deploy SmartContract
Untuk dapat mendeploy SmartContract ke Blockchain, kita harus mengompile dulu solidity kita ke ByteCode. Hal tersebut dapat kita lakukan dengan pertama memilih dulu smart contract mana yang mau di compile. Lalu kemudian navigasikan ke menu Solidy Compiler. Kita bisa tekan tombol "Compile NamaFile.sol"

Setelah compile sukses, harusnya terbentuk artifacts pada proyek kalian. Yang didalamnya terdapat hasil dari kompilasi.

Oke kita lanjut untuk deploy ke Blockchain, kita ke menu Deploy and Run Transaction. Jadi pada menu ini selain bisa deploy juga bisa berinteraksi langsung dengan smart contract kita.
Pastikan sudah memilih Environment yang tepat dan Account yang benar. Ada banyak opsi yang ditawarkan Remix

Jika mau menggunakan local ganache dapan memilih dev ganache. Untuk saat ini agar bisa diakses melalui internet saya menggunakan chain/network yang kami pakai, dengan menggunakan injected provider - Metamask.

Pastikan juga kontrak nya juga benar yang mau kita deploy. Kemudian pencet Deploy.
Jika sukses dibagian bawah "Deploy Contracts", akan muncul Kontrak yang sudah kita deploy berikut bersama alamat address dari kontraknya, beserta field dan button untuk kita berintaksi dengan smart contract yang sudah kita deploy, selayaknya SwaggerHub.

Mari sejenak kita coba untuk melakukan beberapa hal.
- Create Project
- Swap Token
- Donasi
- Voting
- Approve
- Transfer
- Withdraw
Jika tidak ada kendala, kita bisa lanjut membuat antarmukanya agar bisa diakses melalui website.
### Frontend
Kali ini saya tidak akan menggunakan framework ataupun library yang fancy, kita cukup menggunakan vanilla js :)
Boleh dibuka Code Editor kesayangannya. Kebetulan saya pake VSCode.

Berikut kurang lebih struktur kita. Ada folder abi yang diambil dari folder artifact pada Remix. Cukup ambil "abi" nya saja.

kita perlu inisiati paket manager kita.
npm init
tambahkan beberapa dependencies
```bash
npm install --save browserify
npm install --save web3
npm install --save-dev babelify
npm install --save-dev http-serve
```
tambahkan script berikut pada file package.json
```
...
"scripts": {
"build": "browserify index.js --standalone bundle -o ./dist/bundle.js",
"start": "http-server"
},
...
```
Untuk index.html sangat sederhana hanya button dan input text :D
```javascript=
<!DOCTYPE html>
<html>
<head>
<title>Vote Dapp</title>
</head>
<body>
<div id="Metamask">
<span id="status">Status</span>
<br />
<button id="connectButton" onclick="bundle.connect()">Connect</button>
</div>
<div id="Data">
<hr>
<br />
<button id="getProjectsTotalBtn" onclick="bundle.getProjectCount()">Get Total Projects</button>
<br />
<span id="totalProject">Total Projects</span>
<hr>
<br />
<button id="getProjectsBtn" onclick="bundle.getProjects()">Get Projects</button>
<br />
<table>
<tbody id="project"></tbody>
</table>
<hr>
<br />
Description : <input id="inputDescription">
<br />
Goal : <input id="inputGoal">
<br />
Image Url : <input id="inputImageUrl">
<br />
Deadline : <input id="inputDeadline">
<br />
<button id="addProject" onclick="bundle.addProject()">Add Project</button>
<br />
<hr>
Project id : <input id="inputProjectIdDonate">
<br />
Amount : <input id="inputAmount">
<br />
<button id="donateBtn" onclick="bundle.Donate()">Donate</button>
<br />
<hr>
Project id : <input id="inputProjectIdApprove">
<br />
<button id="approveBtn" onclick="bundle.Approve()">Approve</button>
<br />
<hr>
Project id : <input id="inputProjectIdVote">
<br />
<button id="voteBtn" onclick="bundle.Vote()">Vote</button>
<br />
<hr>
Project id : <input id="inputProjectIdTransfer">
<br />
<button id="approveBtn" onclick="bundle.Transfer()">Transfer</button>
<br />
<hr>
CrowdSale Token
<br />
<button id="getCrowdSaleToken" onclick="bundle.getCrowdSaleToken()">Get CT Balance</button>
<br />
<span id="CTBalance">Total Balance</span>
<br />
<hr>
Love Token
<br />
<button id="getLoveToken" onclick="bundle.getLoveToken()">Get CT Balance</button>
<br />
<span id="LTBalance">Total Balance</span>
<br />
<hr>
Swap Token
<br />
<button id="RateBtn" onclick="bundle.Rate()">Get Rate</button>
<br />
<span id="rateValue">Rate Balance</span>
<br />
Swap Amount : <input id="swapAmount">
<br />
<button id="SwapBtn" onclick="bundle.Swap()">Swap</button>
<br />
<span id="swapBalance">Swap Balance</span>
<br />
<button id="WithdrawBtn" onclick="bundle.Withdraw()">Withdraw</button>
<br />
</div>
</body>
<script src="./dist/bundle.js" type="text/javascript"></script>
</html>
```
Harusnya pakai jQuery bisa lebih cepet, kita kembali ke zaman purba dulu untuk manually define element. Berikut index.js
```javascript=
const Web3js = require("web3");
const IFundraise = require("./abi/Fundraise.json");
const F_CONTRACT_ABI = IFundraise.abi;
const F_CONTRACT_ADDRESS = '0xe05F67FA4Aa8Dd3Ba2F9f7ba4b7c36f8C7286C41';
const ICrowdToken = require("./abi/CrowdToken.json");
const CT_CONTRACT_ABI = ICrowdToken.abi;
const CT_CONTRACT_ADDRESS = '0xc87a916B4337Cc29C96bb12B2961bFCc5000F941';
const ILoveToken = require("./abi/LoveToken.json");
const LT_CONTRACT_ABI = ILoveToken.abi;
const LT_CONTRACT_ADDRESS = '0xb3a2a927000bc403952a169011330C9139Ce5EE0';
const ITokenSwap = require("./abi/TokenSwap.json");
const TS_CONTRACT_ABI = ITokenSwap.abi;
const TS_CONTRACT_ADDRESS = '0x95E5A887FDBf9d43412581e6fa62Ed518c9482cF';
let web3js, Fundraise, CrowdToken, LoveToken, TokenSwap, OwnerAddress;
const dataBox = document.getElementById('Data');
const statusBox = document.getElementById('status');
const connectButton = document.getElementById("connectButton");
const totalProjectBox = document.getElementById('totalProject');
const description = document.getElementById('inputDescription');
const goal = document.getElementById('inputGoal');
const imageUrl = document.getElementById('inputImageUrl');
const deadline = document.getElementById('inputDeadline');
const projectBox = document.getElementById('project');
const projectIdDonate = document.getElementById('inputProjectIdDonate');
const amountDonate = document.getElementById('inputAmount');
const projectIdVote = document.getElementById('inputProjectIdVote');
const projectIdApprove = document.getElementById('inputProjectIdApprove');
const projectIdTransfer = document.getElementById('inputProjectIdTransfer');
const CTBox = document.getElementById('CTBalance');
const LTBox = document.getElementById('LTBalance');
const swapAmount = document.getElementById('swapAmount');
const swapBalance = document.getElementById('swapBalance');
const rateValue = document.getElementById('rateValue');
(async () => {
dataBox.hidden = true;
if (typeof window.ethereum !== "undefined") {
const accounts = await ethereum.request({ method: "eth_accounts" });
if(accounts.length > 0){
statusBox.innerHTML = "Your Address " + accounts[0];
OwnerAddress = accounts[0];
initiateContract(accounts[0]);
connectButton.disabled = true;
dataBox.hidden = false;
} else {
statusBox.innerHTML = "Please Connect";
connectButton.hidden = false;
}
} else {
statusBox.innerHTML = "Please install Metamask Pluggin";
connectButton.hidden = true;
}
})();
async function connect() {
if (window.ethereum.isConnected()) {
try {
await ethereum.request({ method: "eth_requestAccounts" });
} catch (error) {
console.log(error);
}
statusBox.innerHTML = "Connected"
let accounts = await ethereum.request({ method: "eth_accounts" });
connectButton.innerHTML = accounts[0];
initiateContract(accounts[0]);
dataBox.hidden = false;
connectButton.disabled = true;
}
}
async function initiateContract(account) {
web3js = await new Web3js(Web3js.givenProvider);
web3js.eth.defaultAccount = account;
Fundraise = new web3js.eth.Contract(F_CONTRACT_ABI, F_CONTRACT_ADDRESS);
CrowdToken = new web3js.eth.Contract(CT_CONTRACT_ABI, CT_CONTRACT_ADDRESS);
LoveToken = new web3js.eth.Contract(LT_CONTRACT_ABI, LT_CONTRACT_ADDRESS);
TokenSwap = new web3js.eth.Contract(TS_CONTRACT_ABI, TS_CONTRACT_ADDRESS);
}
// Get Project Counts
async function getProjectCount() {
const projectCount = await Fundraise.methods.getProjectCount().call();
totalProjectBox.innerHTML = "Total Project : "+projectCount;
}
// Add Project
async function addProject() {
const candidate = await Fundraise.methods.createProject(description.value, BigInt(goal.value), imageUrl.value, BigInt(deadline.value)).send({from: web3js.eth.defaultAccount});
statusBox.innerHTML = "Project added!";
getProjects();
}
// Get Projects
async function getProjects() {
const totalProjects = await Fundraise.methods.getProjectCount().call();
projectBox.innerHTML = "<tr><th>ID</th><th>Description</th><th>Goal</th><th>Image Url</th><th>Deadline</th><th>Vote Total</th><th>Amount Raise</th></tr>";
let projectList = "";
for( i=0 ; i<totalProjects ; i++){
const project = await getProject(i);
console.log(project);
projectList += "<tr><td>"
+ i + "</td>" + "<td>"
+ project.description + "</td>" + "<td>"
+ project.goal + "</td>" + "<td>"
+ project.imageUrl + "</td>" + "<td>"
+ project.deadline + "</td>" + "<td>"
+ project.votes + "</td>" + "<td>"
+ project.amountRaised + "</td></tr>";
}
projectBox.innerHTML += projectList;
}
// Get Project
async function getProject(projectId) {
const project = await Fundraise.methods.getProject(projectId).call();
return project;
}
// Donate
async function Donate() {
const allowance = await CrowdToken.methods.approve(F_CONTRACT_ADDRESS,BigInt(amountDonate.value)).send({from: web3js.eth.defaultAccount});
const donate = await Fundraise.methods.donate(BigInt(projectIdDonate.value), BigInt(amountDonate.value)).send({from: web3js.eth.defaultAccount});
statusBox.innerHTML = "Donation added!";
getProjects();
}
// Vote
async function Vote() {
const vote = await Fundraise.methods.vote(BigInt(projectIdVote.value)).send({from: web3js.eth.defaultAccount});
statusBox.innerHTML = "Vote added!";
getProjects();
}
// Approve
async function Approve() {
const vote = await Fundraise.methods.approveTransfer(BigInt(projectIdApprove.value)).send({from: web3js.eth.defaultAccount});
statusBox.innerHTML = "Approve added!";
getProjects();
}
// Transfer
async function Transfer() {
const vote = await Fundraise.methods.transfer(BigInt(projectIdTransfer.value)).send({from: web3js.eth.defaultAccount});
statusBox.innerHTML = "Transfer!";
getProjects();
}
// CT
async function getCrowdSaleToken() {
const balance = await CrowdToken.methods.balanceOf(OwnerAddress).call();
CTBox.innerHTML = "Total Balance : "+balance;
}
// LT
async function getLoveToken() {
const balance = await LoveToken.methods.balanceOf(OwnerAddress).call();
LTBox.innerHTML = "Total Balance : "+balance;
}
// Token Swap
async function Rate() {
const rate = await TokenSwap.methods.rate().call();
rateValue.innerHTML = "Rate 1 ETH : "+rate+" CST";
}
async function Swap() {
const swap = await TokenSwap.methods.swap().send({from: web3js.eth.defaultAccount, value: parseInt(swapAmount.value)});
swapBalance.innerHTML = "Total Swap : "+swapAmount.value+" CST";
}
async function Withdraw() {
const swap = await TokenSwap.methods.withdraw().send({from: web3js.eth.defaultAccount});
}
module.exports = {
connect,
getProjectCount,
addProject,
getProjects,
getProject,
Donate,
Vote,
getCrowdSaleToken,
getLoveToken,
Rate,
Swap,
Withdraw,
Approve,
Transfer
};
```
Cool!
Let's run the frontend!
```bash
npm run build && npm run start
```

Lets test