parent | title | description | order | last_updated |
---|---|---|---|---|
2021-02-03_07-00-00_getting-started |
Challenge |
Translate a Solidity smart contract to Glow |
8 |
2021-02-25T09:00:00+01:00 |
In order to learn something new, we normally try to learn it refers to something we already know. That's why in this article, we are going to learn the Glow smart contract language by studying an example in Solidity and then translating it to Glow
Ballot.sol is the first program that loads when looking going to the Remix IDE
pragma solidity >=0.7.0 <0.8.0;
contract Ballot {
Declare a struct called Voter that is a complex type consisting of the weight of a vote, a Boolean voted, the address of the Voter, and an index called vote.
struct Voter {
uint weight;// Weight is accumulated by delegation
bool voted; // if true, that person already voted
address delegate;// person delegated to
uint vote; // index of the voted proposal
}
You have an address type called chairperson.
address chairperson;
You have a mapping where you map and address with a voter
mapping(address => Voter) voters;
You also create an array of proposals where each proposal is a complex type struct.
Proposal[] proposals;
struct Proposal {
// If you can limit the length to a certain number of bytes,
// always use one of bytes1 to bytes32 because they are much cheaper
bytes32 name; // short name (up to 32 bytes)
uint voteCount;// number of accumulated votes
}
In the constructor Ballot, you initialize the chairperson as the message sender with weight 1. You also create a list of proposals.
constructor(bytes32[] memory proposalNames) {
chairperson = msg.sender;
voters[chairperson].weight = 1;
for (uint i = 0; i < proposalNames.length; i++) {
// 'Proposal({...})' creates a temporary
// Proposal object and 'proposals.push(...)'
// appends it to the end of 'proposals'.
proposals.push(Proposal({
name: proposalNames[i],
voteCount: 0
}));
}
}
Give the Voter
the right to vote on this ballot.
It can only be called by the Chairperson
.
Validate that the voters have not voted yet and assign voters a weight.
function giveRightToVote(address voter) public {
require(
msg.sender == chairperson,
"Only chairperson can give right to vote."
);
require(
!voters[voter].voted,
"The voter already voted."
);
require(voters[voter].weight == 0,
"the voter already had voting rights");
voters[voter].weight = 1;
}
Then the delegate() function delegates your vote to the Voter $(to) after a couple of validations such as the message sender is not the to address has not voted.
function delegate(address to) public {
Voter storage sender = voters[msg.sender];
require(!sender.voted, "You already voted.");
require(to != msg.sender, "Self-delegation is disallowed.");
while (voters[to].delegate != address(0)) {
to = voters[to].delegate;
// We found a loop in the Delegation, not allowed.
require(to != msg.sender, "Found loop in delegation.");
}
sender.voted = true;
sender.delegate = to;
Voter storage delegate_ = voters[to];
if (delegate_.voted) {
// If the delegate already voted,
// directly add to the number of votes
proposals[delegate_.vote].voteCount += sender.weight;
} else {
// If the delegate did not vote yet,
// add to her weight.
delegate_.weight += sender.weight;
}
}
Give your vote (including votes delegated to you) to proposal
function vote(uint proposal) public {
Voter storage sender = voters[msg.sender];
require(sender.weight != 0, "Has no right to vote");
require(!sender.voted, "Already voted.");
sender.voted = true;
sender.vote = proposal;
// If 'proposal' is out of the range of the array,
// this will throw automatically and revert all
// changes.
proposals[proposal].voteCount += sender.weight;
}
Find which is the proposal with the most votes.
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;
}
}
}
Get the name of the winning proposal
function winnerName() public view
returns (bytes32 winnerName_)
{
winnerName_ = proposals[winningProposal()].name;
}
}
By reading the previous contract, we can identify the following actors and flow:
The Chairman
creates a contract with a defined number of options.
Then gives names to each option.
And grants voting rights to voters.
A voter (Bob in this diagram) can delegate his vote to another voter.
Voters vote for one of the options by its number.
Then everyone can ask who is winning by the one that has more votes.
Now it is your turn. How does the previous smart contract look in Glow?
Here are a few ideas on how you could get started with such a program:
- One known proposal, one known voter
- Multiple known proposals, One known voter
- Multiple known proposals, Three known voters
- Multiple known proposals, Three known voters, with delegation
- Multiple known proposals, unknown voters, with delegation
- Multiple known proposals, unknown voters, with delegation, with giving voting rights