contract CryptoShares {

    using SafeMath for uint256;

    /*
    * ID of the contract
    */
    uint public contractNumberInTheLedger;

    /*
    * description of the organization or project, can be short text or a link to website, white paper, github/gitlab repo
    */
    string public description;

    /* ---- Identity verification for shareholders */

    CryptonomicaVerification public cryptonomicaVerification;

    /*
    * @param _address Address to check
    * keyCertificateValidUntil:  if 0, no key certificate registered for this address.
    * If key certificate not expired and not revoked, identity verification is valid.
    */
    function addressIsVerifiedByCryptonomica(address _address) public view returns (bool){
        return cryptonomicaVerification.keyCertificateValidUntil(_address) > now && cryptonomicaVerification.revokedOn(_address) == 0;
    }

    /* ---- xEUR contract */

    /*
    * We will pay dividends in xEUR as well as in Ether
    * see: https://xeuro.online
    */
    XEuro public xEuro;

    /* --- ERC-20 variables */

    string public name;

    string public symbol;

    uint8 public constant decimals = 0;

    uint public totalSupply;

    mapping(address => uint) public balanceOf;

    mapping(address => mapping(address => uint)) public allowance;

    /**
    * stored address that deployed this smart contract to blockchain
    * it used only in 'init' function (only creator can set initial values for the contract)
    */
    address public creator;

    /**
    * Constructor
    * no args constructor make possible to create contracts with code pre-verified on etherscan.io
    * (once we verify one contract, all next contracts with the same code and constructor args will be verified on etherscan)
    */
    constructor() public {
        // if deployed via factory contract, creator is the factory contract
        creator = msg.sender;
    }

    /* --- ERC-20 events */

    /*
    * We use Transfer as in ERC20, not as in ERC223 (https://github.com/ethereum/EIPs/issues/223)
    * because wallets and etherscan used to detect tokens transfers using ERC20 Transfer event
    */
    event Transfer(address indexed from, address indexed to, uint value);

    event Approval(address indexed _owner, address indexed spender, uint value);

    /* --- Events for interaction with other smart contracts */

    /**
    * @param from Address that sent transaction
    * @param toContract Receiver (smart contract)
    * @param extraData Data sent
    */
    event DataSentToAnotherContract(
        address indexed from,
        address indexed toContract,
        bytes indexed extraData
    );

    /* ===== Arbitration (Dispute Resolution) =======*/

    // * Every shareholder to be registered has to sign dispute resolution agreement.

    /**
    * Arbitration clause (dispute resolution agreement) text
    * see: https://en.wikipedia.org/wiki/Arbitration_clause
    * https://en.wikipedia.org/wiki/Arbitration#Arbitration_agreement
    */
    string public disputeResolutionAgreement;

    /**
    * Number of signatures under disputeResolution agreement
    */
    uint256 public disputeResolutionAgreementSignaturesCounter;

    /**
    * dev: This struct represent a signature under dispute resolution agreement.
    *
    * @param signatureNumber Signature id. Corresponds to disputeResolutionAgreementSignaturesCounter value.
    * @param shareholderId Id of the shareholder that made this signature (signatory).
    * @param signatoryRepresentedBy Ethereum address of the person, that signed the agreement
    * @param signatoryName Legal name of the person that signed agreement. This can be a name of a legal or physical person
    * @param signatoryRegistrationNumber Registration number of legal entity, or ID number of physical person
    * @param signatoryAddress Address of the signatory (country/State, ZIP/postal code, city, street, house/building number,
    * apartment/office number)
    * @param signedOnUnixTime Timestamp of the signature
    */
    struct Signature {
        uint signatureNumber;
        uint shareholderId;
        address signatoryRepresentedBy;
        string signatoryName;
        string signatoryRegistrationNumber;
        string signatoryAddress;
        uint signedOnUnixTime;
    }

    // signature number => signature data (struct)
    mapping(uint256 => Signature) public disputeResolutionAgreementSignaturesByNumber;

    // shareholder address => number of signatures made from this address
    mapping(address => uint) public addressSignaturesCounter;

    // shareholder address => ( signature number for this shareholder => signature data)
    mapping(address => mapping(uint => Signature)) public signaturesByAddress;

    /**
    * dev: Event to be emitted when Dispute Resolution agreement was signed by a new person (we call this person 'signatory')
    *
    * @param signatureNumber Number of the signature (see 'disputeResolutionAgreementSignaturesCounter')
    * @param signatoryRepresentedBy Ethereum address of the person who signed disputeResolution agreement
    * @param signatoryName Name of the person who signed disputeResolution agreement
    * @param signatoryShareholderId Id of the shareholder that made this signature
    * @param signatoryRegistrationNumber Registration number of legal entity, or ID number of physical person (string)
    * @param signatoryAddress Address of the signatory (country/State, ZIP/postal code, city, street, house/building number, apartment/office number)
    * @param signedOnUnixTime Signature timestamp
    */
    event disputeResolutionAgreementSigned(
        uint256 indexed signatureNumber,
        address indexed signatoryRepresentedBy,
        string signatoryName,
        uint indexed signatoryShareholderId,
        string signatoryRegistrationNumber,
        string signatoryAddress,
        uint signedOnUnixTime
    );

    /**
    * @dev This is the function to make a signature of the shareholder under arbitration agreement.
    * The identity of a person (ETH address) who make a signature has to be verified via Cryptonomica.net verification.
    * This verification identifies the physical person who owns the key of ETH address. It this physical person is
    * a representative of a legal person or an other physical person, it's a responsibility of a person who makes transaction
    * (i.e. verified person) to provide correct data of a person he/she represents, if not he/she considered as acting
    * in his/her own name and not as representative.
    *
    * @param _shareholderId Id of the shareholder
    * @param _signatoryName Name of the person who signed disputeResolution agreement
    * @param _signatoryRegistrationNumber Registration number of legal entity, or ID number of physical person
    * @param _signatoryAddress Address of the signatory (country/State, ZIP/postal code, city, street, house/building number, apartment/office number)
    */
    function signDisputeResolutionAgreement(
        uint _shareholderId,
        string memory _signatoryName,
        string memory _signatoryRegistrationNumber,
        string memory _signatoryAddress
    ) private {

        require(
            addressIsVerifiedByCryptonomica(msg.sender),
            "Signer has to be verified on Cryptonomica.net"
        );

        disputeResolutionAgreementSignaturesCounter++;
        addressSignaturesCounter[msg.sender] = addressSignaturesCounter[msg.sender] + 1;

        disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signatureNumber = disputeResolutionAgreementSignaturesCounter;
        disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].shareholderId = _shareholderId;
        disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signatoryRepresentedBy = msg.sender;
        disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signatoryName = _signatoryName;
        disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signatoryRegistrationNumber = _signatoryRegistrationNumber;
        disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signatoryAddress = _signatoryAddress;
        disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signedOnUnixTime = now;

        signaturesByAddress[msg.sender][addressSignaturesCounter[msg.sender]] = disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter];

        emit disputeResolutionAgreementSigned(
            disputeResolutionAgreementSignaturesCounter,
            disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signatoryRepresentedBy,
            disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signatoryName,
            disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].shareholderId,
            disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signatoryRegistrationNumber,
            disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signatoryAddress,
            disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signedOnUnixTime
        );

    }

    /* ===== Shareholders management =============== */

    /**
    * dev: counts all shareholders in smart contract history
    */
    uint public shareholdersCounter;

    /*
    * Shares hold by registered shareholders, i.e. not "in transfer"
    * like 'totalSupply' but counts tokens of registered shareholders only
    */
    uint public registeredShares;

    /**
    * dev: keeps address for each shareholder ID/number (according to shareholdersCounter)
    * if zero -> not a registered shareholder
    */
    mapping(address => uint) public shareholderID;

    /*
    * @param shareholderID The same as in shareholderID mapping
    * @param shareholderEthereumAddress Ethereum address of the shareholder
    * @param shareholderName Legal name of the shareholder, it can be name of the legal person, or fist and last name
    * for the physical person
    * @param shareholderRegistrationNumber Registration number of the legal person or personal ID of the physical person
    * @param shareholderAddress Shareholder's legal address (house number, street, city, zip, country)
    * @param  shareholderIsLegalPerson True if shareholder is a legal person, false if shareholder is a physical person
    * @param linkToSignersAuthorityToRepresentTheShareholder Link to ledger/register record or to document that
    * contains information about person's that manages ETH address  authority to represent the shareholder. If shareholder
    * is a physical person that represents himself/herself can contain "no representation" string
    * @param balanceOf This is the same as balanceOf(shareholderEthereumAddress), stored here for convenience
    * (to get all shareholder's data in one request)
    */
    struct Shareholder {
        uint shareholderID;                                     // 1
        address payable shareholderEthereumAddress;             // 2
        string shareholderName;                                 // 3
        string shareholderRegistrationNumber;                   // 4
        string shareholderAddress;                              // 5
        bool shareholderIsLegalPerson;                          // 6
        string linkToSignersAuthorityToRepresentTheShareholder; // 7
        uint balanceOf;                                         // 8
    }

    mapping(uint => Shareholder) public shareholdersLedgerByIdNumber;

    mapping(address => Shareholder) public shareholdersLedgerByEthAddress;

    event shareholderAddedOrUpdated(
        uint indexed shareholderID,
        address shareholderEthereumAddress,
        bool indexed isLegalPerson,
        string shareholderName,
        string shareholderRegistrationNumber,
        string shareholderAddress,
        uint shares,
        bool indexed newRegistration
    );

    /*
    * @notice Using this function a token holder can register himself as shareholder.
    * Any share (token) not owned of registered shareholder is considered 'in transfer'.
    * Shares 'in transfer' can not vote and does not receive dividends.
    * In the ledger (variables: 'shareholderID', 'shareholderEthereumAddress' and so on ) we store data of all
    * historical shareholders,
    * and they persist even if a shareholder transferred all his shares and his 'balanceOf' is zero.
    * @param _isLegalPerson This indicates if new shareholder is a legal person or physical person.
    * @param _shareholderName Legal name of the shareholder. If this is different from name registered in Cryptonomica
    * verification smart contract, we consider a person registered in Cryptonomica smart contract representative of the
    * shareholder.
    * @param _shareholderRegistrationNumber Registration number of a legal person or personal ID number for physical person.
    * @param  _shareholderAddress Shareholder's legal address (country/state, street, building/house number, apartment/office number)
    *
    * we allow allow change/update shareholder data (if entered incorrectly or some data changed) by calling
    * this function again by existing shareholder
    */
    function registerAsShareholderAndSignArbitrationAgreement(
        bool _isLegalPerson,
        string calldata _shareholderName,
        string calldata _shareholderRegistrationNumber,
        string calldata _shareholderAddress,
        string calldata _linkToSignersAuthorityToRepresentTheShareholder
    ) external returns (bool success){

        require(
            balanceOf[msg.sender] > 0,
            "To be registered address has to hold at least one token/share"
        );

        require(
            addressIsVerifiedByCryptonomica(msg.sender),
            "Shareholder address has to be verified on Cryptonomica"
        );

        bool newShareholder;
        uint id;

        if (shareholderID[msg.sender] == 0) {
            shareholdersCounter++;
            id = shareholdersCounter;
            shareholderID[msg.sender] = id;
            newShareholder = true;
            /* add these shares to shares of registered shareholders (i.e. not "in transfer"*/
            registeredShares = registeredShares.add(balanceOf[msg.sender]);
        } else {
            id = shareholderID[msg.sender];
            newShareholder = false;
        }

        // 1
        shareholdersLedgerByIdNumber[id].shareholderID = id;
        // 2
        shareholdersLedgerByIdNumber[id].shareholderEthereumAddress = msg.sender;
        // 3
        shareholdersLedgerByIdNumber[id].shareholderName = _shareholderName;
        // 4
        shareholdersLedgerByIdNumber[id].shareholderRegistrationNumber = _shareholderRegistrationNumber;
        // 5
        shareholdersLedgerByIdNumber[id].shareholderAddress = _shareholderAddress;
        // 6
        shareholdersLedgerByIdNumber[id].shareholderIsLegalPerson = _isLegalPerson;
        // 7
        shareholdersLedgerByIdNumber[id].linkToSignersAuthorityToRepresentTheShareholder = _linkToSignersAuthorityToRepresentTheShareholder;
        // 8
        shareholdersLedgerByIdNumber[id].balanceOf = balanceOf[msg.sender];

        /* copy struct  */
        shareholdersLedgerByEthAddress[msg.sender] = shareholdersLedgerByIdNumber[id];

        emit shareholderAddedOrUpdated(
            shareholdersLedgerByIdNumber[id].shareholderID,
            shareholdersLedgerByIdNumber[id].shareholderEthereumAddress,
            shareholdersLedgerByIdNumber[id].shareholderIsLegalPerson,
            shareholdersLedgerByIdNumber[id].shareholderName,
            shareholdersLedgerByIdNumber[id].shareholderRegistrationNumber,
            shareholdersLedgerByIdNumber[id].shareholderAddress,
            shareholdersLedgerByIdNumber[id].balanceOf,
            newShareholder
        );

        /*
        * even if shareholder updates data he makes new signature under dispute resolution agreement
        */
        signDisputeResolutionAgreement(
            id,
            shareholdersLedgerByIdNumber[id].shareholderName,
            shareholdersLedgerByIdNumber[id].shareholderRegistrationNumber,
            shareholdersLedgerByIdNumber[id].shareholderAddress
        );

        return true;
    }

    /* ---------------- Dividends --------------- */

    /**
    * Time in seconds between dividends distribution rounds.
    * Next round can be started only if the specified number of seconds has elapsed since the end of the previous round.
    * See: https://en.wikipedia.org/wiki/Dividend#Dividend_frequency
    */
    uint public dividendsPeriod;

    /*
    * @param roundIsRunning Shows if this dividends payouts round is running.
    * @param sumWeiToPayForOneToken Sum in wei to pay for one token in this round.
    * @param sumXEurToPayForOneToken Sum in xEUR to pay for one token in this round.
    * @param allRegisteredShareholders Number of all shareholder registered in whole smart contract.
    * history, at the moment this round was started.
    * @shareholdersCounter Number (id) of shareholder to whom last payment was made.
    * On the start it will be 0, and on the end of the round shareholdersCounter == allRegisteredShareholders.
    * @registeredShares Number of shares that will receive dividends in this round, i.e. number of shares,
    * hold by registered shareholder (that's all shares minus shares 'in transfer')
    * @param roundStartedOnUnixTime Timestamp.
    * @param roundFinishedOnUnixTime Timestamp.
    * @param weiForTxFees Amount in wei deposited for this round to reward those who make transactions to distribute
    * dividends.
    */
    struct DividendsRound {
        bool roundIsRunning; //............0
        uint sumWeiToPayForOneToken; //....1
        uint sumXEurToPayForOneToken; //...2
        uint allRegisteredShareholders; //.3
        uint shareholdersCounter; //.......4
        uint registeredShares; //..........5
        uint roundStartedOnUnixTime; //....6
        uint roundFinishedOnUnixTime; //...7
        uint weiForTxFees; //..............8
    }

    /**
    * 'dividendsRoundsCounter' holds the sequence number of the last (or current) round of dividends payout
    * We record all historical dividends payouts data
    */
    uint public dividendsRoundsCounter;
    mapping(uint => DividendsRound) public dividendsRound;

    /*
    * @param dividendsRound Number of dividends distribution round.
    * @param startedBy ETH address that started round (if time to pay dividends, can be started by any ETH address)
    * @param totalWei Sum in wei that has to be distributed in this round.
    * @param totalXEur Sum in xEUR that has to be distributed in this round.
    * @param sharesToPayDividendsTo The same as 'registeredShares' in struct DividendsRound.
    * @param sumWeiToPayForOneShare Sum in wei to pay for one token in this round.
    * @param sumXEurToPayForOneShare Sum in xEUR to pay for one token in this round.
    */
    event DividendsPaymentsStarted(
        uint indexed dividendsRound, //..0
        address indexed startedBy, //...1
        uint totalWei, //................2
        uint totalXEur, //...............3
        uint sharesToPayDividendsTo, //..4
        uint sumWeiToPayForOneShare, //..5
        uint sumXEurToPayForOneShare //..6
    );

    /**
    * @param dividendsRound Number of dividends distribution round
    */
    event DividendsPaymentsFinished(
        uint indexed dividendsRound
    );

    /**
    * dev: Info about the payment in ETH made to next shareholder
    */
    event DividendsPaymentEther (
        bool indexed success,
        address indexed to,
        uint shareholderID,
        uint shares,
        uint sumWei,
        uint indexed dividendsRound
    );

    /**
    * dev: Info about the payment in xEUR made to next shareholder
    */
    event DividendsPaymentXEuro (
        bool indexed success,
        address indexed to,
        uint shareholderID,
        uint shares,
        uint sumXEuro,
        uint indexed dividendsRound
    );

    /*
    * @notice This function starts dividend payout round, and can be started from ANY address if the time has come.
    */
    function startDividendsPayments() public returns (bool success) {

        require(
            dividendsRound[dividendsRoundsCounter].roundIsRunning == false,
            "Already running"
        );

        // dividendsRound[dividendsRoundsCounter].roundFinishedOnUnixTime is zero for first round
        // so it can be started right after contract deploy
        require(now.sub(dividendsRound[dividendsRoundsCounter].roundFinishedOnUnixTime) > dividendsPeriod,
            "To early to start"
        );

        require(registeredShares > 0,
            "No registered shares to distribute dividends to"
        );

        uint sumWeiToPayForOneToken = address(this).balance / registeredShares;
        uint sumXEurToPayForOneToken = xEuro.balanceOf(address(this)) / registeredShares;

        require(
            sumWeiToPayForOneToken > 0 || sumXEurToPayForOneToken > 0,
            "Nothing to pay"
        );

        // here we start the next dividends payout round:
        dividendsRoundsCounter++;

        dividendsRound[dividendsRoundsCounter].roundIsRunning = true;
        dividendsRound[dividendsRoundsCounter].roundStartedOnUnixTime = now;
        dividendsRound[dividendsRoundsCounter].registeredShares = registeredShares;
        dividendsRound[dividendsRoundsCounter].allRegisteredShareholders = shareholdersCounter;

        dividendsRound[dividendsRoundsCounter].sumWeiToPayForOneToken = sumWeiToPayForOneToken;
        dividendsRound[dividendsRoundsCounter].sumXEurToPayForOneToken = sumXEurToPayForOneToken;

        emit DividendsPaymentsStarted(
            dividendsRoundsCounter,
            msg.sender,
            address(this).balance,
            xEuro.balanceOf(address(this)),
            registeredShares,
            sumWeiToPayForOneToken,
            sumXEurToPayForOneToken
        );

        return true;
    }

    /*
    * @dev Reward for tx distributing dividends was paid
    * @dividendsRoundNumber Number (Id) of dividends round.
    * @dividendsToShareholderNumber Shareholder ID, to whom payment was made by the transaction
    * @dividendsToShareholderAddress Shareholder ETH address, to whom payment was made by the transaction
    * @feePaidTo Address (ETH), who received the reward (this is the address who send tx to pay dividends to above
    * stated shareholder
    * @feeInWei Amount of the reward paid.
    * @paymentSuccesful Shows if fee payment was successful (msg.sender.send == true)
    */
    event FeeForDividendsDistributionTxPaid(
        uint indexed dividendsRoundNumber,
        uint dividendsToShareholderNumber,
        address dividendsToShareholderAddress,
        address indexed feePaidTo,
        uint feeInWei,
        bool feePaymentSuccesful
    );

    /*
    * @notice This function pays dividends due to the next shareholder.
    * dev: This functions is intended to be called by external script (bot), but can be also called manually.
    * External script can be run by any person interested in distributing dividends.
    * Script code is open source and published on smart contract's web site and/or on Github.
    * Technically this functions can be run also manually (acceptable option for small number of shareholders)
    */
    function payDividendsToNext() external returns (bool success) {

        require(
            dividendsRound[dividendsRoundsCounter].roundIsRunning,
            "Dividends payments round is not open"
        );

        dividendsRound[dividendsRoundsCounter].shareholdersCounter = dividendsRound[dividendsRoundsCounter].shareholdersCounter + 1;

        uint nextShareholderToPayDividends = dividendsRound[dividendsRoundsCounter].shareholdersCounter;

        uint sumWeiToPayForOneToken = dividendsRound[dividendsRoundsCounter].sumWeiToPayForOneToken;
        uint sumXEurToPayForOneToken = dividendsRound[dividendsRoundsCounter].sumXEurToPayForOneToken;

        address payable to = shareholdersLedgerByIdNumber[nextShareholderToPayDividends].shareholderEthereumAddress;

        if (balanceOf[to] > 0) {

            if (sumWeiToPayForOneToken > 0) {

                uint sumWeiToPay = sumWeiToPayForOneToken * balanceOf[to];

                // 'send' is the low-level counterpart of 'transfer'.
                // If the execution fails, the current contract will not stop with an exception, but 'send' will return false.
                // https://solidity.readthedocs.io/en/v0.5.10/types.html?highlight=send#members-of-addresses
                // So we use 'send' and not 'transfer' to ensure that execution continues even if sending ether fails.
                bool result = to.send(sumWeiToPay);
                emit DividendsPaymentEther(
                    result,
                    to,
                    nextShareholderToPayDividends,
                    balanceOf[to],
                    sumWeiToPay,
                    dividendsRoundsCounter
                );
            }

            if (sumXEurToPayForOneToken > 0) {
                uint sumXEuroToPay = sumXEurToPayForOneToken * balanceOf[to];
                //  if (sumXEuroToPay <= xEuro.balanceOf(address(this))) {
                bool result = xEuro.transfer(to, sumXEuroToPay);
                emit DividendsPaymentXEuro(
                    result,
                    to,
                    nextShareholderToPayDividends,
                    sumXEuroToPay,
                    nextShareholderToPayDividends,
                    dividendsRoundsCounter
                );
                //  }
            }

        }

        // if the round started shareholdersCounter can not be zero
        // because to start the round we need at least one registered share and thus at least one registered shareholder

        uint feeForTxCaller = dividendsRound[dividendsRoundsCounter].weiForTxFees / shareholdersCounter;

        if (
            feeForTxCaller > 0
            && msg.sender == tx.origin // < msg.sender is not a contract (to prevent reentrancy)
        ) {

            // we use send not transfer (returns false, not fail)
            bool feePaymentSuccessful = msg.sender.send(feeForTxCaller);
            emit FeeForDividendsDistributionTxPaid(
                dividendsRoundsCounter,
                nextShareholderToPayDividends,
                to,
                msg.sender,
                feeForTxCaller,
                feePaymentSuccessful
            );
        }

        // if this is the last registered shareholder for this round
        // then FINISH the round:
        if (nextShareholderToPayDividends == shareholdersCounter) {

            dividendsRound[dividendsRoundsCounter].roundIsRunning = false;
            dividendsRound[dividendsRoundsCounter].roundFinishedOnUnixTime = now;

            emit DividendsPaymentsFinished(
                dividendsRoundsCounter
            );
        }

        return true;
    }

    /*
    * Interested party can provide funds to pay for dividends distribution.
    * @param forDividendsRound Number (Id) of dividends payout round.
    * @param sumInWei Sum in wei received.
    * @param from Address from which sum was received.
    * @param currentSum Current sum of wei to reward accounts sending dividends distributing transactions.
    */
    event FundsToPayForDividendsDistributionReceived(
        uint indexed forDividendsRound,
        uint sumInWei,
        address indexed from,
        uint currentSum
    );

    /*
    * Function to add funds to reward transactions distributing dividends in this round/
    */
    function fundDividendsPayout() public payable returns (bool success){

        /* We allow this only for running round */
        require(
            dividendsRound[dividendsRoundsCounter].roundIsRunning,
            "Dividends payout is not running"
        );

        dividendsRound[dividendsRoundsCounter].weiForTxFees = dividendsRound[dividendsRoundsCounter].weiForTxFees + msg.value;

        emit FundsToPayForDividendsDistributionReceived(
            dividendsRoundsCounter,
            msg.value,
            msg.sender,
            dividendsRound[dividendsRoundsCounter].weiForTxFees // totalSum
        );

        return true;
    }

    /*
    * @dev startDividendsPayments() and fundDividendsPayout() combined for convenience
    */
    function startDividendsPaymentsAndFundDividendsPayout() external payable returns (bool success) {
        startDividendsPayments();
        return fundDividendsPayout();
    }

    /* ============= ERC20 functions ============ */

    /**
    * dev:
    * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md#approve
    * there is an attack:
    * https://github.com/CORIONplatform/solidity/issues/6,
    * https://drive.google.com/file/d/0ByMtMw2hul0EN3NCaVFHSFdxRzA/view
    * but this function is required by ERC-20:
    * To prevent attack vectors like the one described on https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/
    * and discussed on https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 ,
    * clients SHOULD make sure to create user interfaces in such a way that they set the allowance first to 0 before
    * setting it to another value for the same spender.
    * THOUGH The contract itself shouldn't enforce it, to allow backwards compatibility with contracts deployed before
    *
    * @param _spender The address which will spend the funds.
    * @param _value The amount of tokens to be spent.
    */
    function approve(address _spender, uint _value) public returns (bool success){
        allowance[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);
        return true;
    }

    /**
    * @notice Approve another address to spend tokens from the tokenholder account
    * dev: Overloaded approve function
    *      See https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/
    * @param _spender The address which will spend the funds.
    * @param _currentValue The current value of allowance for spender
    * @param _value The amount of tokens to be spent.
    */
    function approve(address _spender, uint _currentValue, uint _value) external returns (bool success){
        require(
            allowance[msg.sender][_spender] == _currentValue,
            "Current value in contract is different than provided current value"
        );
        return approve(_spender, _value);
    }

    /**
    * dev: private function that checks and changes balances and allowances for transfer functions
    */
    function _transferFrom(address _from, address _to, uint _value) private returns (bool success) {

        require(
            _to != address(0),
            "_to was 0x0 address"
        );

        require(
            !dividendsRound[dividendsRoundsCounter].roundIsRunning,
            "Transfers blocked while dividends are distributed"
        );

        require(
            _from == msg.sender || _value <= allowance[_from][msg.sender],
            "Sender not authorized"
        );

        // check if _from account has the required amount, if not, throw an exception
        require(
            _value <= balanceOf[_from],
            "Account doesn't have required amount"
        );

        balanceOf[_from] = balanceOf[_from].sub(_value);
        balanceOf[_to] = balanceOf[_to].add(_value);

        uint fromId = shareholderID[_from];
        uint toId = shareholderID[_to];

        if (fromId > 0) {
            shareholdersLedgerByEthAddress[_from].balanceOf = balanceOf[_from];
            shareholdersLedgerByIdNumber[fromId].balanceOf = balanceOf[_from];
        }

        if (toId > 0) {
            shareholdersLedgerByEthAddress[_to].balanceOf = balanceOf[_to];
            shareholdersLedgerByIdNumber[toId].balanceOf = balanceOf[_to];
        }

        if (fromId > 0 && toId == 0) {
            // shares goes from registered address to unregistered address
            // subtract from 'registeredShares'
            registeredShares = registeredShares.sub(_value);
        } else if (fromId == 0 && toId > 0) {
            // shares goes from unregistered address to registered address
            // add to 'registeredShares'
            registeredShares = registeredShares.add(_value);
        }

        // If allowance used, change allowances correspondingly
        if (_from != msg.sender) {
            allowance[_from][msg.sender] = allowance[_from][msg.sender].sub(_value);
        }

        emit Transfer(_from, _to, _value);

        return true;
    }

    /*
    * dev: Private function, that calls 'tokenFallback' function if token receiver is a contract.
    */
    function _erc223Call(address _to, uint _value, bytes memory _data) private returns (bool success) {

        uint codeLength;

        assembly {
        // Retrieve the size of the code on target address, this needs assembly .
            codeLength := extcodesize(_to)
        }

        if (codeLength > 0) {
            ERC223ReceivingContract receiver = ERC223ReceivingContract(_to);
            receiver.tokenFallback(msg.sender, _value, _data);
            emit DataSentToAnotherContract(msg.sender, _to, _data);
        }

        return true;
    }

    /**
     * @notice Transfers tokens from one address to another.
     *         Sender can send own tokens or or those tokens that he is allowed to transfer.
     * dev: Transfer the specified amount of tokens to the specified address.
     *      Invokes the `tokenFallback` function if the recipient is a contract.
     *      The token transfer fails if the recipient is a contract
     *      but does not implement the `tokenFallback` function
     *      or the fallback function to receive funds.
     * @param _to  Receiver address.
     * @param _value Amount of tokens that will be transferred.
     */
    function transferFrom(address _from, address _to, uint _value) public returns (bool success){

        _transferFrom(_from, _to, _value);

        // see:
        // https://github.com/Dexaran/ERC223-token-standard/pull/54
        // https://github.com/Dexaran/ERC223-token-standard/issues/53
        bytes memory empty = hex"00000000";

        return _erc223Call(_to, _value, empty);

    } // end of transferFrom

    /*
    * @notice Transfer tokens from tx sender address to another address.
    *         The rest is similar to the 'transferFrom' function.
    */
    function transfer(address _to, uint _value) public returns (bool success){
        return transferFrom(msg.sender, _to, _value);
    }

    /**
    * @notice (ERC223) Transfers tokens to another address with additional info.
    * dev: Overloaded 'transfer' function (ERC223 standard)
    *      See: https://github.com/ethereum/EIPs/issues/223
    *      https://github.com/Dexaran/ERC223-token-standard/blob/Recommended/ERC223_Token.sol
    * @param _to    Receiver address.
    * @param _value Amount of tokens that will be transferred.
    * @param _data  Transaction metadata.
    */
    function transfer(address _to, uint _value, bytes calldata _data) external returns (bool success){

        _transferFrom(msg.sender, _to, _value);

        return _erc223Call(_to, _value, _data);
    }


    /* ============= VOTING ================ */

    /*
    * This smart contract implements voting for shareholders of ERC20 tokens based on the principle
    * "one share - one vote"
    * It requires external script to count votes.
    *
    * Rules:
    * To start a voting an address have to own at lest one share.
    * To start a voting, voting creator must provide:
    * 1) text of the proposal,
    * 2) number of the block on which voting will be finished and results have to be calculated.
    *
    * Every proposal for a contract receives a sequence number that serves as a proposal ID.
    * To vote 'for' or 'against' voter has to provide proposal ID.
    *
    * In most scenarios only votes 'for' can be used, who did not voted 'for' can be considered as voted 'against'.
    * But our dApp also supports votes 'against'
    *
    * To calculate results we collect all voted addresses by an external script, which is also open sourced.
    * Than we check their balances in tokens on resulting block, and and sum up the voices.
    * Thus, for the results, the number of tokens of the voter at the moment of voting does not matter
    * (it should just has at least one).
    * What matters is the number of tokens on the voter's address on the block where the results should calculated.
    *
    * It's like https://www.cryptonomica.net/eth-vote/, but:
    * 1) for this contract only
    * 2) to start voting or to vote an address has to be registered as a shareholder, not just to have tokens
    *
    */

    // Counts all voting created in this smart contract
    uint public votingCounterForContract;

    // proposal id => text of the proposal
    mapping(uint => string) public proposalText;

    // proposal id => number of voters
    mapping(uint => uint256) public numberOfVotersFor;
    mapping(uint => uint256) public numberOfVotersAgainst;

    // proposal id => (voter id => voter address)
    mapping(uint => mapping(uint256 => address)) public votedFor;
    mapping(uint => mapping(uint256 => address)) public votedAgainst;

    // proposal id => (voter address => voter has voted already)
    mapping(uint => mapping(address => bool)) public boolVotedFor;
    mapping(uint => mapping(address => bool)) public boolVotedAgainst;

    // proposal ID => block number
    mapping(uint => uint) public resultsInBlock;

    /*
    * @param proposalId Number of this voting, according to 'votingCounterForContract'
    * @param by Address that created proposal
    * @param proposalText Text of the proposal
    * @param resultsInBlock Block to calculate results of voting.
    */
    event Proposal(
        uint indexed proposalID,
        address indexed by,
        string proposalText,
        uint indexed resultsInBlock
    );

    // to run function an address has to be registered as a shareholder and own at least one share
    modifier onlyShareholder() {
        require(
            shareholdersLedgerByEthAddress[msg.sender].shareholderID != 0 && balanceOf[msg.sender] > 0,
            "Only shareholder can do that"
        );
        _;
    }

    /*
    * @notice Creates proposal for voting.
    * @param _proposalText Text of the proposal.
    * @param _resultsInBlock Number of block on which results will be counted.
    */
    function createVoting(
        string calldata _proposalText,
        uint _resultsInBlock
    ) onlyShareholder external returns (bool success){

        require(
            _resultsInBlock > block.number,
            "Block for results should be later than current block"
        );

        votingCounterForContract++;

        proposalText[votingCounterForContract] = _proposalText;
        resultsInBlock[votingCounterForContract] = _resultsInBlock;

        emit Proposal(votingCounterForContract, msg.sender, proposalText[votingCounterForContract], resultsInBlock[votingCounterForContract]);

        return true;
    }

    // Vote 'for' received
    event VoteFor(
        uint indexed proposalID,
        address indexed by
    );

    // Vote 'against' received
    event VoteAgainst(
        uint indexed proposalID,
        address indexed by
    );

    /*
    * @notice Vote for the proposal
    * @param _proposalId Id (number) of the proposal
    */
    function voteFor(uint256 _proposalId) onlyShareholder external returns (bool success){

        require(
            resultsInBlock[_proposalId] > block.number,
            "Voting already finished"
        );

        require(
            !boolVotedFor[_proposalId][msg.sender] && !boolVotedAgainst[_proposalId][msg.sender],
            "Already voted"
        );

        numberOfVotersFor[_proposalId] = numberOfVotersFor[_proposalId] + 1;

        uint voterId = numberOfVotersFor[_proposalId];

        votedFor[_proposalId][voterId] = msg.sender;

        boolVotedFor[_proposalId][msg.sender] = true;

        emit VoteFor(_proposalId, msg.sender);

        return true;
    }

    /*
    * @notice Vote against the proposal
    * @param _proposalId Id (number) of the proposal
    */
    function voteAgainst(uint256 _proposalId) onlyShareholder external returns (bool success){

        require(
            resultsInBlock[_proposalId] > block.number,
            "Voting finished"
        );

        require(
            !boolVotedFor[_proposalId][msg.sender] && !boolVotedAgainst[_proposalId][msg.sender],
            "Already voted"
        );

        numberOfVotersAgainst[_proposalId] = numberOfVotersAgainst[_proposalId] + 1;

        uint voterId = numberOfVotersAgainst[_proposalId];

        votedAgainst[_proposalId][voterId] = msg.sender;

        boolVotedAgainst[_proposalId][msg.sender] = true;

        emit VoteAgainst(_proposalId, msg.sender);

        return true;
    }

    /*
    * This contract can receive Ether from any address.
    * Received Ether will be distributed as dividends to shareholders.
    */

    function addEtherToContract() external payable {
        // gas: 21482
    }

    function() external payable {
        // gas: 21040
    }

    /* ============= Contract initialization
    * dev: initializes token: set initial values for erc20 variables
    *      assigns all tokens ('totalSupply') to one address ('tokenOwner')
    * @param _contractNumberInTheLedger Contract Id.
    * @param _description Description of the project of organization (short text or just a link)
    * @param _name Name of the token
    * @param _symbol Symbol of the token
    * @param _tokenOwner Address that will initially hold all created tokens
    * @param _dividendsPeriod Period in seconds between finish of the previous dividends round and start of the next.
    *        On test net can be small.
    * @param _xEurContractAddress Address of contract with xEUR tokens
    *        (can be different for test net, where we use mock up contract)
    * @param _cryptonomicaVerificationContractAddress Address of the Cryptonomica verification smart contract
    *        (can be different for test net, where we use mock up contract)
    * @param _disputeResolutionAgreement Text of the arbitration agreement.
    */
    function initToken(
        uint _contractNumberInTheLedger,
        string calldata _description,
        string calldata _name,
        string calldata _symbol,
        uint _dividendsPeriod,
        address _xEurContractAddress,
        address _cryptonomicaVerificationContractAddress,
        string calldata _disputeResolutionAgreement
    ) external returns (bool success) {

        require(
            msg.sender == creator,
            "Only creator can initialize token contract"
        );

        require(
            totalSupply == 0,
            "Contract already initialized"
        );

        contractNumberInTheLedger = _contractNumberInTheLedger;
        description = _description;
        name = _name;
        symbol = _symbol;
        xEuro = XEuro(_xEurContractAddress);
        cryptonomicaVerification = CryptonomicaVerification(_cryptonomicaVerificationContractAddress);
        disputeResolutionAgreement = _disputeResolutionAgreement;
        dividendsPeriod = _dividendsPeriod;

        return true;
    }

    /*
    * @dev initToken and issueTokens are separate functions because of
    * 'Stack too deep' exception from compiler
    * @param _tokenOwner Address that will get all new created tokens.
    * @param _totalSupply Amount of tokens to create.
    */
    function issueTokens(
        uint _totalSupply,
        address _tokenOwner
    ) external returns (bool success){

        require(
            msg.sender == creator,
            "Only creator can initialize token contract"
        );

        require(
            totalSupply == 0,
            "Contract already initialized"
        );

        require(
            _totalSupply > 0,
            "Number of tokens can not be zero"
        );


        totalSupply = _totalSupply;

        balanceOf[_tokenOwner] = totalSupply;

        emit Transfer(address(0), _tokenOwner, _totalSupply);

        return true;
    }

}
/*
 * @title Cryptoshares smart contract
 * @notice Contract to manage shares of a corporation on the blockchain
 *         Shares are implemented as ERC20/ERC223 tokens.
 *         Contract also implements dividends distribution, shareholders voting, dispute resolution agreement
 */
function transferFrom(address _from, address _to, uint _value) public returns (bool success){

    _transferFrom(_from, _to, _value);

    // see:
    // https://github.com/Dexaran/ERC223-token-standard/pull/54
    // https://github.com/Dexaran/ERC223-token-standard/issues/53
    bytes memory empty = hex"00000000";

    return _erc223Call(_to, _value, empty);

} // end of transferFrom

/**
 * @notice Transfers tokens from one address to another.
 *         Sender can send own tokens or or those tokens that he is allowed to transfer.
 * dev: Transfer the specified amount of tokens to the specified address.
 *      Invokes the `tokenFallback` function if the recipient is a contract.
 *      The token transfer fails if the recipient is a contract
 *      but does not implement the `tokenFallback` function
 *      or the fallback function to receive funds.
 * @param _to  Receiver address.
 * @param _value Amount of tokens that will be transferred.
 */