Skip to content

Instantly share code, notes, and snippets.

@serapath
Created May 3, 2018 00:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save serapath/d63e247fcdc63ea681606bd5738cc58e to your computer and use it in GitHub Desktop.
Save serapath/d63e247fcdc63ea681606bd5738cc58e to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.4.23+commit.124ca40d.js&optimize=false&gist=
import "github/OpenZeppelin/zeppelin-solidity/contracts/token/ERC20/MintableToken.sol";
import "gist/Ballot.sol";
contract AwardToken is MintableToken {
uint quantity;
uint ballotPeriod = 7 hours;
Ballot public currBallot;
address[] public prevWinners;
event log (string _msg);
event winLog (address _win);
event newBallot (address _addr);
function AwardToken () {
quantity = 100;
}
function getPreviousWinners() constant returns (address[]) {
return prevWinners;
}
// either a name change or it works fine without it
// function approve(address spender, uint256 value) public returns (bool);
function startRound() onlyOwner canMint public returns (bool) {
// if this is the first minting then we should let this go immediately
if (address(currBallot) == 0x0) {
currBallot = new Ballot(ballotPeriod);
newBallot(currBallot);
} else {
return false;
}
}
function closeRound() onlyOwner {
// this can only be done by the owner of the contract
if (address(currBallot) != 0x0 && currBallot.timeOut()) {
// get winner
address winner = currBallot.winningProposal();
winLog(winner);
// send to winner - but first make sure the address is valid
if ( winner == 0x0){
log("no winner");
} else {
winLog(winner);
super.mint(winner, quantity);
prevWinners.push(winner);
}
delete currBallot;
// start new round
}else revert();
}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
revert();
}
function approve(address _spender, uint256 _value) public returns (bool) {
revert();
}
function increaseApproval(address _spender, uint _addedValue) public returns (bool) {
revert();
}
function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {
revert();
}
function transfer(address _to, uint256 _value) public returns (bool) {
revert();
}
}
pragma solidity ^0.4.0;
contract Ballot {
uint _duration;
uint _startTime;
struct Proposal {
string description;
string title;
uint voteCount;
address targetAddress;
}
event log (string _msg);
address chairperson;
mapping(address => mapping (address => uint8)) voters; // map between proposal and voter and votes
mapping(address => Proposal) public proposals;
address[] public proposalsSender;
function getProposals() constant returns (address[]) {
return proposalsSender;
}
/// Create a new ballot with $(_numProposals) different proposals.
function Ballot(uint duration) public {
chairperson = msg.sender;
_duration = duration;
_startTime = now;
}
// duration issues...
// add a new proposals
function addProposal(string desc, string title, address targetAddr) public {
if (timeOut() || targetAddr == 0x0 || proposals[msg.sender].targetAddress != 0x0){
revert();
}
proposals[msg.sender].description = desc;
proposals[msg.sender].title = title;
proposals[msg.sender].voteCount = 0;
proposals[msg.sender].targetAddress = targetAddr;
proposalsSender.push(msg.sender);
}
/// Give a single vote to proposal $(toProposal).
function vote(address proposal) public {
// is this msg.sender in vote - the voter the proposal or the owner of the contract?
// apparantly you can't vote more than once
uint8 vote = voters[proposal][msg.sender];
// the revert - takes it back to the initial state - but that blows away everyting - I suppose...
// check on revert();
if (timeOut()) revert();
if (vote != 0) {
revert(); // already voted for this proposal
} else {
voters[proposal][msg.sender] = 1;
proposals[proposal].voteCount += 1;
}
}
// timeOut vs duration in voteCount
// for use in vote(), addProposal(),
function timeOut() public constant returns ( bool timeOver) {
if (_startTime + _duration > now){
timeOver = false;
}else timeOver = true;
}
function winningProposal() public constant returns (address currLeader) {
// does this need to be run only by the contract owner? Currently I think it is not limited
uint vote = 0;
if (timeOut()){
// timeOut - mean that at least the _duration is over
// what if there is tie?
if(proposalsSender.length > 0) {
for (uint8 k = 0; k < proposalsSender.length; k++) {
Proposal proposal = proposals[proposalsSender[k]];
if (vote < proposal.voteCount) {
vote = proposal.voteCount;
currLeader = proposal.targetAddress;
}
}
if (vote > 0) {
return currLeader;
}else{
log("aint no voters!");
}
}else{
log("aint no proposals!");
}
}
}
}
remix:loadurl https://github.com/OpenZeppelin/zeppelin-solidity/contracts/token/ERC20/MintableToken.sol
remix:loadurl https://github.com/OpenZeppelin/zeppelin-solidity/contracts/ownership/Ownable.sol
remix:loadurl https://github.com/OpenZeppelin/zeppelin-solidity/contracts/token/ERC20/StandardToken.sol
remix:loadurl https://github.com/OpenZeppelin/zeppelin-solidity/contracts/token/ERC20/ERC20.sol
remix:loadurl https://github.com/OpenZeppelin/zeppelin-solidity/contracts/token/ERC20/BasicToken.sol
remix:loadurl https://github.com/OpenZeppelin/zeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol
remix:loadurl https://github.com/OpenZeppelin/zeppelin-solidity/contracts/math/SafeMath.sol

README

SETUP METAMASK

  1. open remix: go to remix.ethereum.org
  2. setup metamask: install the metamask extension in your browser and login
  3. switch to ropsten: select the Ropsten Test Network in the metamask browser extensions dropdown menu
  4. get some test ether: in developer mode new accounts get some test ethers by default
    1. open metamask settings: right-click the metamask extension and go to manage extensions
    2. turn on developer mode: in the upper menu bar switch on Developer Mode
    3. restart metamask: in the main settings pane turn off the metamask extension and switch it back on
    4. close extension settings: close the browser tab to get back to the remix tab
    5. sign into metamask: click metamask icon and if you are logged out type your password and click log in
    6. open settings dropdown: click settings in upper right corner of metamask extension overlay
    7. create accounts: click create account button, type in a name you want and click create
    8. choose account with funds: click settings in upper right corner and choose an account with funds
  5. open remix run tab: in remix on the devtools panel click on Run tab
  6. select injected web3: click the Environment dropdown and select Injected Web3

LOAD FILES

  1. load project: execute remix:loadgist 1483e5599012c3783def91ead259ece8 in terminal
  2. install dependencies: open gist/dependencies.txt from file explorer and type remix:batch into terminal

SETUP CONTRACTS

  1. open gist/AwardToken.sol click on gist/AwardToken.sol in the file explorer to show it in the editor
  2. compile: now in the devtools panel on the right, click the Compile tab and then Start to compile button
  3. choose owner: click on Run tab and Account dropdown to choose an address to become contract owner
    1. check the AwardToken.sol in the editor to see the onlyOwner tag in the mint(...) function
    2. copy owner address: click the copy button next to the account dropdown on the run tab
  4. deploy AwardToken contract: click deploy (=create) on run tab to deploy an instance to ropsten network
    1. set max gas price: in metamask popup set price (e.g. 10) (might require metamask old UI in settings)
    2. confirm transaction: click submit in metamask popup to grant the transaction and pay with test ether
    3. await confirmation: the network might take a few seconds or minutes to confirm the transaction
    4. check udapp: the auto generated user interface ("universal dapp") on the run tab
    5. check success: wait transaction to get logged in terminal to click details to check for status SUCCESS
  5. start new minting: find the mint function on the run tab represented in the contracts universal dapp
    1. first paremter: paste owners address (e.g. ctrl+v) into the input field next to the mint button
    2. second paremter: write the number of tokens to mint into the next input field
    3. check input: make sure your input looks similar to 0x1ba18b04fbfd26e426cd97f39638baeffbe36460, 7500
    4. maybe expand: if the remix version has a dropdown arrow next to the mint button to fill out a form
    5. execute mint: click the pink mint button to execute a state changing transaction which costs gas
    6. set max gas price: in metamask popup set price (e.g. 10) (might require metamask old UI in settings)
    7. confirm transaction: click submit on the confirmation dialog from metamask that will popup
    8. check success: wait transaction to get logged in terminal to click details to check for status SUCCESS
  6. start voting round: create transaction to make new Ballot contract for others to send proposal and vote
    1. execute startRound: click the pink startRound button on the awardToken udapp
    2. set max gas price: in metamask popup set price (e.g. 10) (might require metamask old UI in settings)
    3. confirm transaction: click submit on the confirmation dialog from metamask that will popup
    4. check success: wait transaction to get logged in terminal to click details to check for status SUCCESS

USER INTERACTION

  1. find ballot address: click the blue currBallot button to execute a free of cost read only call

  2. grab ballot address: select and copy (e.g. ctrl+c) ballot address from udapp or terminal

  3. connect to ballot: click contract dropdown on run tab to select ballot

    1. paste ballot address (ctrl+v) into input field next to At address and click that blue button
  4. add new proposal: scroll down the run tab to check the ballot udapp and it's addProposal button

    1. grab local address: scroll up and click copy button on run tab next to Account dropdown
    2. goto ballot udapp: scroll down on run tab to the ballot udap with the pink addProposal button
    3. fill description param: write a "description text" wrapped in quotations and a comma (,) afterwards
    4. fill title param: write a "short title" wrapped in quotations and a comma (,) afterwards
    5. fill address param: paste (ctrl+v) your address as the proposals sender WITHOUT quotation marks
      • every wallet address can only create one proposal
      • e.g
      "description", "title", "0xca35b7d915458ef540ade6068dfe2f44e8fa733c"
      
    6. submit proposal: click the pink addProposal button to submit the new proposal and pay gas fee
    7. set max gas price: in metamask popup set price (e.g. 100) (might require metamask old UI in settings)
    8. confirm transaction: click submit on the confirmation dialog from metamask that will popup
    9. check success: wait transaction to get logged in terminal to click details to check for status SUCCESS
  5. copy proposal address: first wait until the addProposal transaction gets confirmed in a terminal log 2. copy address: scroll down with mousewheel in transaction details to to field and click copy icon

  6. vote on proposal: every wallet address can only vote once per proposal

    1. choose proposal: paste address (ctrl+v) into vote input field and click that pink button
    2. maybe gas estimation fail: if so, use mousewheel to scroll down on popup and click send transaction
    3. set max gas price: in metamask popup set price (e.g. 1) (might require metamask old UI in settings)
    4. confirm transaction: click submit on the confirmation dialog from metamask that will popup
  7. check proposals: click the blue getProposals button to execute a free of cost read only call

  8. grab proposal address: select and copy (e.g. ctrl+c) proposal address to vote on from udapp or terminal

FINISH MINTING

  1. close round: when the time is over, awardToken owner needs to closeRound to retrieve winningProposal
    1. switch to owner: switch back to owner address and click on finish minting on AwardToken instance
    2. execute closeRound: owner clicks the pink closeRound button on the awardToken udapp
    3. set max gas price: in metamask popup set price (e.g. 10) (might require metamask old UI in settings)
    4. confirm transaction: click submit on the confirmation dialog from metamask that will popup
    5. check success: wait transaction to get logged in terminal to click details to check for status SUCCESS
  2. finish minting 0
    1. execute closeRound: owner clicks the pink closeRound button on the awardToken udapp
    2. set max gas price: in metamask popup set price (e.g. 10) (might require metamask old UI in settings)
    3. confirm transaction: click submit on the confirmation dialog from metamask that will popup
    4. check success: wait transaction to get logged in terminal to click details to check for status SUCCESS
    5. winner gets award: mints the tokens and gives it to the winning proposal. The log looks something like:
      "args": [
          "4b0897b0513fdc7c541b6d9d7e929c4e5364d2db",
          "14723a09acff6d2a60dcdf7aa4aff308fddc160c",
          "100"
      ]
      
  3. whats next: It is then possible to start a another round of voting.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment