POA
English
English
  • Welcome to POA
  • Features
    • Known Validators
    • POADAO Consensus
    • Bridged Native Token
    • On-Chain Randomness
  • Use Cases
    • Scalability for BlockChain Games
    • Community-Based Currencies
    • Subsidized Transactions
    • Decentralized Finance (DeFi)
  • DApp Spotlights
    • Ethernal.World
  • Roadmap
  • For users
    • POA Tokens
      • POA Merger & STAKE Swap
      • POA - STAKE FAQs
      • POA Token Supply
      • POA & POA20 Exchanges
      • POA & POA20 on Binance
      • FAQ: POA20 General Questions
    • POA Token Use Cases
      • Utility Token
      • Currency Token
      • Collateral Token
      • Bridged Token
      • Staking Token
      • Stable Token
    • POA to POA20 Bridge
    • Accept POA20 Payments
      • Account Registration & Login (Merchant Setup)
      • Setup Merchant Account
      • Merchant Payment Method Setup
      • Making a Payment with POA20 (Customer Perspective)
    • Tutorials
      • Trading POA20 on DEX.AG
      • POA20 Token Swaps on 1inch.exchange
      • Getting Airdrops via Discord
    • Governance
      • Article: A Successful Year of On-Chain Governance
      • Governance Reports
        • April 2020 Report
        • December 2019 Report
      • Ballot Type, Lifecycle & Limits
    • ❌Nifty Wallet (Discontinued)
      • Getting Started
      • Import and Interact with Smart Contracts
      • Connect to a Hardware Wallet (Ledger & Trezor)
      • Connect to D'CENT Biometric Wallet
      • Connect to Pocket Decentralized Network
    • 3rd Party Wallets
      • Trust Wallet
      • MetaMask
    • POA Mania
      • News - Updates
      • Rules
      • POA Mania FAQs
      • Deposit & Withdraw
      • Winner Selection
      • Round Details
      • POA Mania vs PoolTogether
      • POA Mania on Trust Wallet
      • POA Mania Security Audit
      • POA Mania on MetaMask Mobile
    • Whitepaper
      • POADAO v1
        • Introduction
        • Proof of Authority
        • POA Network Functionality
        • Decentralized apps (DApps)
          • Initial ceremony DApp
          • Proof of Physical Address (PoPA) DApp
          • Proof of Bank Account DApp
          • Proof of Social Network DApp
          • Proof of Phone Number DApp
          • Governance DApp
        • Summary & Acknowledgements
        • References
        • Appendix A: Code Samples
          • Ballots manager
          • Validators manager
          • Deployment scripts for the mining node
  • For developers
    • Developer Resources
    • Getting Tokens For Tests
      • ERC20 Test Token Faucet
      • Sokol Testnet Faucet
    • Full Node Setup
      • Install OpenEthereum Client
      • Install Nethermind Client
    • DApp Deployment
    • TheGraph Data Indexing
    • On-Chain Random Numbers
      • RNG explainer (AuRa + RandomAura Contract)
      • Accessing a Random Seed with a Smart Contract
      • Randomness FAQs
    • API & SQL Access
    • Smart Contract Dashboard
    • Grants for Building on POA
  • For validators
    • Getting Started
      • Validator Resources
      • Becoming a Validator
    • Bootnode Setup
      • AWS Bootnode Setup
        • Prerequisites
        • Configure AWS
        • Download and Configure Playbook
        • Deploy
      • Non-AWS Bootnode Setup & Deployment
        • Local/Remote Machine System Requirements
        • Node Preparation
        • Configure node with Deployment Playbook
    • Validator Node Setup
      • Nethermind Upgrade
      • AWS VM for Validator Node Deployment
        • MoC: Master of Ceremony Key Exchange & Generation
        • Current Validators Vote in New Validators
        • Validator Node Setup Prerequisites
        • Configuring AWS
        • Download and Configure Playbook
        • Deployment
        • Upgrade Instance to a Larger Instance Type
      • Non-AWS Validator Node Setup
        • Local & Remote Machine System Requirements
        • Remote Machine Setup
        • Configure Node using Deployment Playbook
      • NetStats Dashboard
    • Hard Forks
      • Parity Upgrade Guide
      • POA Core
        • 2021-11-02 | #24090200
        • 2021-05-24 | #21364900
        • 2020-03-31 | #14350721
        • 2019-12-19 | #12598600
        • 2019-04-29 | #8582254
        • 2018-01-29 | # 772000
        • 2018-10-22 | #5329160
        • POA Core spec.json hard-fork update
      • Sokol
        • 2021-05-24 | #21050600
        • 2020-02-20 | #13391641
        • 2019-12-05 | #12095200
        • 2019-02-06 | #7026400
        • 2019-01-04 | #6464300
        • 2018-09-19 | #4622420
        • 2018-01-18 | #509355
        • 2018-01-08 | #362296
        • Sokol spec.json hard-fork update
    • Validator DApps
      • Validators MetaData DApp
      • Adding or Removing a Validator
  • Media
    • Social Media
    • Media Kit
    • Contact Us
Powered by GitBook
On this page

Was this helpful?

  1. For users
  2. Whitepaper
  3. POADAO v1
  4. Appendix A: Code Samples

Ballots manager

Code Sample

pragma solidity ^0.4.14;

import "./Utility.sol";
import "./ValidatorsManager.sol";

contract BallotsManager is ValidatorsManager {
    /**
    @notice Adds new Ballot
    @param ballotID Ballot unique ID
    @param owner Voting key of notary, who creates ballot
    @param miningKey Mining key of notary, which is proposed to add or remove
    @param affectedKey Mining/payout/voting key of notary, which is proposed to add or remove
    @param affectedKeyType Type of affectedKey: 0 = mining key, 1 = voting key, 2 = payout key
    @param addAction Flag: adding is true, removing is false
    @param memo Ballot's memo
    */
    function addBallot(
        uint ballotID,
        address owner,
        address miningKey,
        address affectedKey,
        uint affectedKeyType,
        bool addAction,
        string memo
    ) {
        assert(checkVotingKeyValidity(msg.sender));
        assert(!(licensesIssued == licensesLimit && addAction));
        assert(ballotsMapping[ballotID].createdAt <= 0);
        if (affectedKeyType == 0) {//mining key
            bool validatorIsAdded = false;
            for (uint i = 0; i < validators.length; i++) {
                assert(!(validators[i] == affectedKey && addAction)); //validator is already added before
                if (validators[i] == affectedKey) {
                    validatorIsAdded = true;
                    break;
                }
            }
            for (uint j = 0; j < disabledValidators.length; j++) {
                assert(disabledValidators[j] != affectedKey); //validator is already removed before
            }
            assert(!(!validatorIsAdded && !addAction)); // no such validator in validators array to remove it
        } else if (affectedKeyType == 1) {//voting key
            assert(!(checkVotingKeyValidity(affectedKey) && addAction)); //voting key is already added before
            assert(!(!checkVotingKeyValidity(affectedKey) && !addAction)); //no such voting key to remove it
        } else if (affectedKeyType == 2) {//payout key
            assert(!(checkPayoutKeyValidity(affectedKey) && addAction)); //payout key is already added before
            assert(!(!checkPayoutKeyValidity(affectedKey) && !addAction)); //no such payout key to remove it
        }
        uint votingStart = now;
        ballotsMapping[ballotID] = Ballot({
            owner: owner,
            miningKey: miningKey,
            affectedKey: affectedKey,
            memo: memo, 
            affectedKeyType: affectedKeyType,
            createdAt: now,
            votingStart: votingStart,
            votingDeadline: votingStart + 48 * 60 minutes,
            votesAmmount: 0,
            result: 0,
            addAction: addAction,
            active: true
        });
        ballots.push(ballotID);
        checkBallotsActivity();
    }

    /**
    @notice Gets active ballots' ids
    @return { "value" : "Array of active ballots ids" }
    */
    function getBallots() constant returns (uint[] value) {
        return ballots;
    }

    /**
    @notice Gets ballot's memo
    @param ballotID Ballot unique ID
    @return { "value" : "Ballot's memo" }
    */
    function getBallotMemo(uint ballotID) constant returns (string value) {
        return ballotsMapping[ballotID].memo;
    }

    /**
    @notice Gets ballot's action
    @param ballotID Ballot unique ID
    @return { "value" : "Ballot's action: adding is true, removing is false" }
    */
    function getBallotAction(uint ballotID) constant returns (bool value) {
        return ballotsMapping[ballotID].addAction;
    }

    /**
    @notice Gets mining key of notary
    @param ballotID Ballot unique ID
    @return { "value" : "Notary's mining key" }
    */
    function getBallotMiningKey(uint ballotID) constant returns (address value) {
        return ballotsMapping[ballotID].miningKey;
    }

    /**
    @notice Gets affected key of ballot
    @param ballotID Ballot unique ID
    @return { "value" : "Ballot's affected key" }
    */
    function getBallotAffectedKey(uint ballotID) constant returns (address value) {
        return ballotsMapping[ballotID].affectedKey;
    }

    /**
    @notice Gets affected key type of ballot
    @param ballotID Ballot unique ID
    @return { "value" : "Ballot's affected key type" }
    */
    function getBallotAffectedKeyType(uint ballotID) constant returns (uint value) {
        return ballotsMapping[ballotID].affectedKeyType;
    }

    function toString(address x) internal returns (string) {
        bytes memory b = new bytes(20);
        for (uint i = 0; i < 20; i++)
            b[i] = byte(uint8(uint(x) / (2**(8*(19 - i)))));
        return string(b);
    }

    /**
    @notice Gets ballot's owner full name
    @param ballotID Ballot unique ID
    @return { "value" : "Ballot's owner full name" }
    */
    function getBallotOwner(uint ballotID) constant returns (string value) {
        address ballotOwnerVotingKey = ballotsMapping[ballotID].owner;
        address ballotOwnerMiningKey = votingMiningKeysPair[ballotOwnerVotingKey];
        string storage validatorFullName = validator[ballotOwnerMiningKey].fullName;
        bytes memory ownerName = bytes(validatorFullName);
        if (ownerName.length == 0)
            return toString(ballotOwnerMiningKey);
        else
            return validatorFullName;
    }

    /**
    @notice Gets ballot's creation time
    @param ballotID Ballot unique ID
    @return { "value" : "Ballot's creation time" }
    */
    function ballotCreatedAt(uint ballotID) constant returns (uint value) {
        return ballotsMapping[ballotID].createdAt;
    }

    /**
    @notice Gets ballot's voting start date
    @param ballotID Ballot unique ID
    @return { "value" : "Ballot's voting start date" }
    */
    function getBallotVotingStart(uint ballotID) constant returns (uint value) {
        return ballotsMapping[ballotID].votingStart;
    }

    /**
    @notice Gets ballot's voting end date
    @param ballotID Ballot unique ID
    @return { "value" : "Ballot's voting end date" }
    */
    function getBallotVotingEnd(uint ballotID) constant returns (uint value) {
        return ballotsMapping[ballotID].votingDeadline;
    }

    /**
    @notice Gets ballot's amount of votes for
    @param ballotID Ballot unique ID
    @return { "value" : "Ballot's amount of votes for" }
    */
    function getVotesFor(uint ballotID) constant returns (int value) {
        return (ballotsMapping[ballotID].votesAmmount + ballotsMapping[ballotID].result)/2;
    }

    /**
    @notice Gets ballot's amount of votes against
    @param ballotID Ballot unique ID
    @return { "value" : "Ballot's amount of votes against" }
    */
    function getVotesAgainst(uint ballotID) constant returns (int value) {
        return (ballotsMapping[ballotID].votesAmmount - ballotsMapping[ballotID].result)/2;
    }

    /**
    @notice Checks, if ballot is active
    @param ballotID Ballot unique ID
    @return { "value" : "Ballot's activity: active or not" }
    */
    function ballotIsActive(uint ballotID) constant returns (bool value) {
        return ballotsMapping[ballotID].active;
    }

    /**
    @notice Checks, if ballot is already voted by signer of current transaction
    @param ballotID Ballot unique ID
    @return { "value" : "Ballot is already voted by signer of current transaction: yes or no" }
    */
    function ballotIsVoted(uint ballotID) constant returns (bool value) {
        return ballotsMapping[ballotID].voted[msg.sender];
    }

    /**
    @notice Votes
    @param ballotID Ballot unique ID
    @param accept Vote for is true, vote against is false
    */
    function vote(uint ballotID, bool accept) {
        assert(checkVotingKeyValidity(msg.sender));
        Ballot storage v =  ballotsMapping[ballotID];
        assert(v.votingDeadline >= now);
        assert(!v.voted[msg.sender]);
        v.voted[msg.sender] = true;
        v.votesAmmount++;
        if (accept) v.result++;
        else v.result--;
        checkBallotsActivity();
    }

    /**
    @notice Removes element by index from validators array and shift elements in array
    @param index Element's index to remove
    @return { "value" : "Updated validators array with removed element at index" }
    */
    function removeValidator(uint index) internal returns(address[]) {
        if (index >= validators.length) return;

        for (uint i = index; i<validators.length-1; i++){
            validators[i] = validators[i+1];
        }
        delete validators[validators.length-1];
        validators.length--;
    }

    /**
    @notice Checks ballots' activity
    @dev Deactivate ballots, if ballot's time is finished and implement action: add or remove notary, if votes for are greater votes against, and total votes are greater than 3
    */
    function checkBallotsActivity() internal {
        for (uint ijk = 0; ijk < ballots.length; ijk++) {
            Ballot storage b = ballotsMapping[ballots[ijk]];
            if (b.votingDeadline < now && b.active) {
                if ((int(b.votesAmmount) >= int(votingLowerLimit)) && b.result > 0) {
                    if (b.addAction) { //add key
                        if (b.affectedKeyType == 0) {//mining key
                            if (licensesIssued < licensesLimit) {
                                licensesIssued++;
                                validators.push(b.affectedKey);
                                InitiateChange(Utility.getLastBlockHash(), validators);
                            }
                        } else if (b.affectedKeyType == 1) {//voting key
                            votingKeys[b.affectedKey] = VotingKey({isActive: true});
                            votingMiningKeysPair[b.affectedKey] = b.miningKey;
                        } else if (b.affectedKeyType == 2) {//payout key
                            payoutKeys[b.affectedKey] = PayoutKey({isActive: true});
                            miningPayoutKeysPair[b.miningKey] = b.affectedKey;
                        }
                    } else { //invalidate key
                        if (b.affectedKeyType == 0) {//mining key
                            for (uint jj = 0; jj < validators.length; jj++) {
                                if (validators[jj] == b.affectedKey) {
                                    removeValidator(jj); 
                                    return;
                                }
                            }
                            disabledValidators.push(b.affectedKey);
                            validator[b.affectedKey].disablingDate = now;
                        } else if (b.affectedKeyType == 1) {//voting key
                            votingKeys[b.affectedKey] = VotingKey({isActive: false});
                        } else if (b.affectedKeyType == 2) {//payout key
                            payoutKeys[b.affectedKey] = PayoutKey({isActive: false});
                        }
                    }
                }
                b.active = false;
            }
        }
    }
}
PreviousAppendix A: Code SamplesNextValidators manager

Last updated 5 years ago

Was this helpful?