Skip to content

Latest commit

 

History

History
180 lines (140 loc) · 5.93 KB

2021-02-03_07-00-00_challenge-en.md

File metadata and controls

180 lines (140 loc) · 5.93 KB
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

Challenge: Translate a Solidity smart contract to Glow

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

The Ballot example

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;
     }
}

Visualization

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.

img

How does the contract look in Glow?

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