# Weekend Project 3
> Solidity BootCamp 2023Q1 @ encode.club
:::info
## Table of Contents
[TOC]
:::
## Tasks
* Form groups of 3 to 5 students
* Complete the contracts together
* Develop and run scripts for “TokenizedBallot.sol” within your group to give voting tokens, delegating voting power, casting votes, checking vote power and querying results
* Write a report with each function execution and the transaction hash, if successful, or the revert reason, if failed
* Share your code in a github repo in the submission form
## General Contract Information
**Contract Address:**
`` TODO
TransactionID Deployment:
https://goerli.etherscan.io/tx/0xc6ac726a083029ea8b18
Contract Code:
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
interface IMyToken{
function getPastVotes(address account, uint256 blockNumber) external view returns (uint256);
}
contract Ballot {
struct Proposal {
bytes32 name;
uint voteCount;
}
IMyToken public tokenContract;
uint256 public targetBlockNumber;
Proposal[] public proposals;
mapping (address => uint256) public votingPowerSpent;
constructor(
bytes32[] memory proposalNames,
address _tokenContract,
uint256 _targetBlockNumber
) {
tokenContract = IMyToken(_tokenContract);
targetBlockNumber = _targetBlockNumber;
for (uint i = 0; i < proposalNames.length; i++) {
proposals.push(Proposal({name: proposalNames[i], voteCount: 0}));
}
}
function vote(uint proposal, uint256 amount) external {
require(votingPower(msg.sender) >= amount);
votingPowerSpent[msg.sender] += amount;
proposals[proposal].voteCount += amount;
}
function votingPower(address account) public view returns (uint256){
return tokenContract.getPastVotes(account, targetBlockNumber) -
votingPowerSpent[account];
}
function winningProposal() public view returns (uint winningProposal_) {
uint winningVoteCount = 0;
for (uint p = 0; p < proposals.length; p++) {
if (proposals[p].voteCount > winningVoteCount) {
winningVoteCount = proposals[p].voteCount;
winningProposal_ = p;
}
}
}
function winnerName() external view returns (bytes32 winnerName_) {
winnerName_ = proposals[winningProposal()].name;
}
}
```
## Adam's Contributions
### Metamask Test Wallet
https://goerli.etherscan.io/address/0x01b5af9976658a33a9809d4261225FAc2f53a9DD
### Repository
Repository code for this project can be found here:
[Week 2 Project](https://github.com/asteinberger/encode-bootcamp-homework/tree/feature/adam-steinberger-week-2)
### State Changes
1. Deployment
2. Give Right To Vote (multiple)
3. Vote
### Edge Cases


## Dan transactions
### Metamask Wallet
Dan's Wallet: 0xEFC0D955536ed993F93177bdaCdA5d266083F573
### First Transaction
- Attempted to vote without permission granted by the chairperson, transaction reverted.
hash: 0x8626f786afa5de5d037b4a57ae1640fe324546f2c5ff396679318d7e2ff88ff9
### Second Transaction
- Chairperson grants me the right to vote.
hash: 0x4c2bf8e0e5466817aced5ce943df71b451f51d30de128b1aec5147ee90e3f6d6
- I proceed to vote for proposal 2, successful transaction.
hash: 0xca459bd9f0201a2f3545536275b5f663eb654933a5e38a11274585b20ce14124
#### State Changes:
- Voter struct with my address created, 1 weight added, vote cast = true.
### Third transaction
I attempt to give the right to vote, even though I am not the chairperson. This transaction is reverted.
- hash: 0x9c4479536e69ad7a675c4f0039a8f4a2ca807ef01a4547ee8f46fe6319ed6702
## David E. Perez Negron R. transactions
### Personal Repository
https://github.com/P1R/Tokenized_Votes
## Script Code (scripts/TokenizedBallot.ts):
The following script code performs the Weekend Project Tasks
```typescript
import { ethers } from "hardhat";
import { MyToken__factory, Ballot__factory } from "../typechain-types";
const MINT_VALUE = 100;
// I Like Pokemons which one should I pick?
const PROPOSALS = ["Bulbasaur", "Charmander", "Squirtle", "pikachu"];
// Converts convert String Array to Bytes32 Array
function convertStringArrayToBytes32(array: string[]) {
const bytes32Array = [];
for (let index = 0; index < array.length; index++) {
bytes32Array.push(ethers.utils.formatBytes32String(array[index]));
}
return bytes32Array;
}
// Converts convert Bytes32 Array to String Array
function convertBytes32ArrayToString(array: Bytes32[]) {
const stringArray = [];
for (let index = 0; index < array.length; index++) {
stringArray.push(ethers.utils.parseBytes32String(array[index]));
}
return stringArray;
}
async function main() {
// Deploy ERC20Votes Contract
const [deployer, account1, account2, account3] = await ethers.getSigners();
const contractERC20VotesFactory = new MyToken__factory(deployer);
const contractERC20Votes = await contractERC20VotesFactory.deploy();
const deployedTransactionReciptERC20 = await contractERC20Votes.deployTransaction.wait();
console.log(`The ERC20Votes contract got deployed at block number ${deployedTransactionReciptERC20.blockNumber}`);
// GIVE VOTE TOKENS
console.log("GIVE VOTE TOKENS:");
//Mint some tokens to Account 1
const mintTx = await contractERC20Votes.mint(account1.address, MINT_VALUE);
const mintRecipt = await mintTx.wait();
console.log(`Minted tokens to ${account1.address} at ${mintRecipt.blockNumber}`);
const balanceOfAccount1 = await contractERC20Votes.balanceOf(account1.address);
console.log(`Now the balance of ${account1.address} is ${balanceOfAccount1}`);
//Mint some tokens to Account 2
const mintTx2 = await contractERC20Votes.mint(account2.address, MINT_VALUE);
const mint2Recipt = await mintTx2.wait();
console.log(`Minted tokens to ${account2.address} at ${mint2Recipt.blockNumber}`);
const balanceOfAccount2 = await contractERC20Votes.balanceOf(account2.address);
console.log(`Now the balance of ${account2.address} is ${balanceOfAccount2}`);
//Mint some tokens to Account 3
const mintTx3 = await contractERC20Votes.mint(account3.address, MINT_VALUE);
const mint3Recipt = await mintTx3.wait();
console.log(`Minted tokens to ${account3.address} at ${mint3Recipt.blockNumber}`);
const balanceOfAccount3 = await contractERC20Votes.balanceOf(account3.address);
console.log(`Now the balance of ${account3.address} is ${balanceOfAccount3}`);
// DELEGATING VOTING POWER
console.log("DELEGATING VOTING POWER");
//First account1 self delegates
const delegateTx = await contractERC20Votes.connect(account1).delegate(account1.address);
const delegateTxRecipt = await delegateTx.wait();
console.log(
`tokens delegated from ${account1.address} to ${account1.address} at block ${delegateTxRecipt.blockNumber}`
);
let votingPower = await contractERC20Votes.getVotes(account1.address);
console.log(
`wallet ${account1.address} has a voting power of ${votingPower}`
);
//First account2 delegates
const delegateTx2 = await contractERC20Votes.connect(account2).delegate(account3.address);
const delegateTx2Recipt = await delegateTx2.wait();
console.log(
`tokens delegated from ${account2.address} to ${account3.address} at block ${delegateTx2Recipt.blockNumber}`
);
let votingPower2 = await contractERC20Votes.getVotes(account2.address);
console.log(
`wallet ${account2.address} has a voting power of ${votingPower2}`
);
//First account3 delegates
const delegateTx3 = await contractERC20Votes.connect(account3).delegate(account3.address);
const delegateTx3Recipt = await delegateTx3.wait();
console.log(
`tokens delegated from ${account3.address} to ${account3.address} at block ${delegateTx3Recipt.blockNumber}`
);
let votingPower3 = await contractERC20Votes.getVotes(account3.address);
console.log(
`wallet ${account3.address} has a voting power of ${votingPower3}`
);
// CASTING VOTES
console.log("CASTING VOTES");
// Deploy TokenizedBallot Contract
const contractBallotFactory = new Ballot__factory(deployer);
const contractBallot = await contractBallotFactory.deploy(
convertStringArrayToBytes32(PROPOSALS),
contractERC20Votes.address,
"7"
);
const deployedTransactionReciptBallot = await contractBallot.deployTransaction.wait();
console.log(`The ballot contract address is ${deployedTransactionReciptBallot.contractAddress}`);
console.log(`The block number is ${deployedTransactionReciptBallot.blockNumber}`);
// Account1 Votes for Bulbasaur with 49 tokens and votes 51 for Charmander
const vote1Tx = await contractBallot.connect(account1).vote( "0", "49");
const vote1Recipt = await vote1Tx.wait();
console.log(
`${account1.address} voted at block ${vote1Recipt.blockNumber} with the txID ${vote1Recipt.transactionHash}`
);
let votingPower1 = await contractBallot.votingPower(account1.address);
console.log(
`wallet ${account1.address} has a voting power of ${votingPower1}`
);
const vote2Tx = await contractBallot.connect(account1).vote( "0", "51");
const vote2Recipt = await vote2Tx.wait();
console.log(
`${account1.address} voted at block ${vote2Recipt.blockNumber} with the txID ${vote2Recipt.transactionHash}`
);
votingPower1 = await contractBallot.votingPower(account1.address);
console.log(
`wallet ${account1.address} has a voting power of ${votingPower1}`
);
// Account2 tries to give 100 to Squirtle (for testscript Gets "Transaction reverted without a reason string")
// ToDO: Add an error string to the Vote Functiont at the ballot contract (require).
//const vote3Tx = await contractBallot.connect(account2).vote( "2", "100");
//const vote3Recipt = await vote3Tx.wait();
//console.log(vote3Recipt);
// Account3 tries to give 100 to Squirtle (for testscript Gets "Transaction reverted without a reason string")
const vote3Tx = await contractBallot.connect(account3).vote( "2", "51");
const vote3Recipt = await vote3Tx.wait();
console.log(
`${account3.address} voted at block ${vote3Recipt.blockNumber} with the txID ${vote3Recipt.transactionHash}`
);
votingPower3 = await contractBallot.votingPower(account3.address);
console.log(
`wallet ${account3.address} has a voting power of ${votingPower3}`
);
const vote4Tx = await contractBallot.connect(account3).vote( "3", "101");
const vote4Recipt = await vote4Tx.wait();
console.log(
`${account3.address} voted at block ${vote4Recipt.blockNumber} with the txID ${vote4Recipt.transactionHash}`
);
votingPower3 = await contractBallot.votingPower(account3.address);
console.log(
`wallet ${account3.address} has a voting power of ${votingPower3}`
);
// CHECK VOTE POWER
console.log("CHECK VOTE POWER");
//Check Account1 voting Power
votingPower1 = await contractBallot.votingPower(account1.address);
console.log(
`wallet ${account1.address} has a voting power of ${votingPower1}`
);
//Check Account2 voting Power
votingPower2 = await contractBallot.votingPower(account2.address);
console.log(
`wallet ${account2.address} has a voting power of ${votingPower2}`
);
////Check Account3 voting Power
votingPower3 = await contractBallot.votingPower(account3.address);
console.log(
`wallet ${account3.address} has a voting power of ${votingPower3}`
);
// QUERIYING RESUTS
const winningProposal = await contractBallot.winningProposal();
const winningProposalName = convertBytes32ArrayToString([await contractBallot.winnerName()]);
console.log(` The Winner Proporsal is ${winningProposal}: ${winningProposalName} `)
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
})
```
## Output:
The following is this script output performing the Project Tasks
```shell
$ yarn hardhat run scripts/TokenizedBallot.ts
The ERC20Votes contract got deployed at block number 1
GIVE VOTE TOKENS:
Minted tokens to 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 at 2
Now the balance of 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 is 100
Minted tokens to 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC at 3
Now the balance of 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC is 100
Minted tokens to 0x90F79bf6EB2c4f870365E785982E1f101E93b906 at 4
Now the balance of 0x90F79bf6EB2c4f870365E785982E1f101E93b906 is 100
DELEGATING VOTING POWER
tokens delegated from 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 to 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 at block 5
wallet 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 has a voting power of 100
tokens delegated from 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC to 0x90F79bf6EB2c4f870365E785982E1f101E93b906 at block 6
wallet 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC has a voting power of 0
tokens delegated from 0x90F79bf6EB2c4f870365E785982E1f101E93b906 to 0x90F79bf6EB2c4f870365E785982E1f101E93b906 at block 7
wallet 0x90F79bf6EB2c4f870365E785982E1f101E93b906 has a voting power of 200
CASTING VOTES
The ballot contract address is 0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9
The block number is 8
0x70997970C51812dc3A010C7d01b50e0d17dc79C8 voted at block 9 with the txID 0xf4efd1513536cf8e1c5bb1b87e414aa09f3d1aac2fd92deb8b8b96083097c22a
wallet 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 has a voting power of 51
0x70997970C51812dc3A010C7d01b50e0d17dc79C8 voted at block 10 with the txID 0x68de52eab6d9a2902a37c2e5ee9e98472838f72e674ca5b570b451592aae5213
wallet 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 has a voting power of 0
0x90F79bf6EB2c4f870365E785982E1f101E93b906 voted at block 11 with the txID 0xcca725fc1eb115da30ccc69d1237e1a36197c645403991e613fd085716f0d45b
wallet 0x90F79bf6EB2c4f870365E785982E1f101E93b906 has a voting power of 149
0x90F79bf6EB2c4f870365E785982E1f101E93b906 voted at block 12 with the txID 0x02a6b71d2bb55cb681a234455dae6412c547792302f32f8356018e279976b300
wallet 0x90F79bf6EB2c4f870365E785982E1f101E93b906 has a voting power of 48
CHECK VOTE POWER
wallet 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 has a voting power of 0
wallet 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC has a voting power of 0
wallet 0x90F79bf6EB2c4f870365E785982E1f101E93b906 has a voting power of 48
The Winner Proporsal is 3: pikachu
```
## Conclusions
Since there where multiple errors at the Goerli network as reported issue at the Lesson - 12 [1], I was unable to
perform this test on the testnet, yet at the end I foundout mumbai network let me do the deployment correctly.
We might require to do self delegation with the team coordination to forefill the tasks at the testnet and
for new the task was forefilled successfully at the testing enviorment.
## Cesar transactions
Interacted with Contract `'0xaf5bd48C8dd8F733697e148F952c62868A701b71'`
**Call vote method:**
transactionId:
https://goerli.etherscan.io/tx/0x2e211c70bd4b008a8cad147b1543acc93bcba8238157d20de6d47f3707f0b36f
This transaction executes a call to initiate a state change and 'vote' if a user has voting delegations
## Rebecca transactions
### Successful Vote
Vote confirmation: https://goerli.etherscan.io/tx/0x458c495c2caea4585b68bf49ed7be6deeac1df971d48a8da15ae529064e25487
### Main bugs/obstacles/lessons
- goerli wallet was not properly connected
- did not confirm that my wallet was connected when sending the vote
- did not change my wallet currency to goerli before reconnecting my wallet; as a result, i almost paid my gas fee in ETH
- did not input the proper information for voting for a specific proposal
- I kept trying to input a string instead of a number defined in the script. as a result, i kept getting "out of bounds" errors
- had issues understanding how all the code connected
- like the week before, i am still facing obstables in understanding how each part of the code works together to interact with a smart contract. unlike last week, i've learned that documentation is not enough for me -- i need to reach out to my classmates, TA and programming friends for help. i will now be communicating more frequently with all of them, and setting up study sessions.
## Brent transactions
### First Transaction
https://goerli.etherscan.io/tx/0xef0443745cf85d781393ea8bc4febe85643b1831bb4d2e2d4f44ca53ec3b3961
#### State Changes
1. "Yo, whats up bro"
## Contact and Developers
- [David E. Perez Negron R.](mailto:david@neetsec.com) Github: @P1R
- [Rebecca Duke Wiesenberg](mailto:rdukewiesenb@gmail.com) Github: @rdukewiesenb
- [Adam Steinberger](mailto:adam@asteinbe.com) | Github: @asteinberger | Discord: steinz08#3291
## References
\[1\] Encode Club Solidity Bootcamp , "Lesson 8 - Scripts for Ballot.sol", https://github.com/Encode-Club-Solidity-Bootcamp/Lesson-08, 2023.
\[2\] docs.soliditylang.org , "Solidity by Example", https://docs.soliditylang.org/en/latest/solidity-by-example.html#voting, 2023.