contract    ERC20 
{
    using SafeMath  for uint256;

    //----- VARIABLES

    address public              owner;          // Owner of this contract
    address public              admin;          // The one who is allowed to do changes
    address public              mazler;

    mapping(address => uint256)                         balances;       // Maintain balance in a mapping
    mapping(address => mapping (address => uint256))    allowances;     // Allowances index-1 = Owner account   index-2 = spender account

    //------ TOKEN SPECIFICATION

    string  public      name       = "DIAM";
    string  public      symbol     = "DIAM";

    uint256 public  constant    decimals   = 5;                            // Handle the coin as FIAT (2 decimals). ETH Handles 18 decimal places

    uint256 public  constant    initSupply = 150000000 * 10**decimals;      //150000000 * 10**decimals;   // 10**18 max

    uint256 public              totalSoldByOwner=0;                         // Not from ERC-20 specification, but help for the totalSupply management later
    //-----

    uint256 public              totalSupply;

    uint256                     mazl   = 10;
    uint256                     vScale = 10000;

    //--------------------------------------------------------------------------

    modifier onlyOwner()            { require(msg.sender==owner);   _; }
    modifier onlyAdmin()            { require(msg.sender==admin);   _; }

    //----- EVENTS

    event Transfer(address indexed fromAddr, address indexed toAddr,   uint256 amount);
    event Approval(address indexed _owner,   address indexed _spender, uint256 amount);

    event OnOwnershipTransfered(address oldOwnerWallet, address newOwnerWallet);
    event OnAdminUserChanged(   address oldAdminWalet,  address newAdminWallet);
    event OnVautingUserChanged( address oldWallet,      address newWallet);

    //--------------------------------------------------------------------------
    //--------------------------------------------------------------------------
    constructor()   public 
    {
        owner  = msg.sender;
        admin  = owner;
        mazler = owner;

        balances[owner] = initSupply;   // send the tokens to the owner
        totalSupply     = initSupply;
    }
    //--------------------------------------------------------------------------
    //--------------------------------------------------------------------------
    //----- ERC20 FUNCTIONS
    //--------------------------------------------------------------------------
    //--------------------------------------------------------------------------
    function balanceOf(address walletAddress) public view /*constant*/ returns (uint256 balance) 
    {
        return balances[walletAddress];
    }
    //--------------------------------------------------------------------------
    function        transfer(address toAddr, uint256 amountInWei)  public   returns (bool)
    {
        uint256         baseAmount;
        uint256         finalAmount;
        uint256         addAmountInWei;

        require(toAddr!=address(0x0) && toAddr!=msg.sender 
                                     && amountInWei!=0
                                     && amountInWei<=balances[msg.sender]);

        //-----  Reduce gas consumption of ==> balances[msg.sender] = balances[msg.sender].sub(amountInWei);

        baseAmount  = balances[msg.sender];
        finalAmount = baseAmount - amountInWei;

        assert(finalAmount <= baseAmount);

        balances[msg.sender] = finalAmount;

        //----- Reduce gas consumption of ==> balances[toAddr] = balances[toAddr].add(amountInWei);

        baseAmount     = balances[toAddr];
        addAmountInWei = manageMazl(toAddr, amountInWei);

        finalAmount = baseAmount + addAmountInWei;

        assert(finalAmount >= baseAmount);

        balances[toAddr] = finalAmount;

        //-----

        if (msg.sender==owner)
        {
            totalSoldByOwner += amountInWei;
        }

        //-----

        emit Transfer(msg.sender, toAddr, addAmountInWei /*amountInWei*/);

        return true;
    }
    //--------------------------------------------------------------------------
    function allowance(address walletAddress, address spender) public view/*constant*/ returns (uint remaining)
    {
        return allowances[walletAddress][spender];
    }
    //--------------------------------------------------------------------------
    function transferFrom(address fromAddr, address toAddr, uint256 amountInWei)  public  returns (bool) 
    {
        require(amountInWei!=0                                   &&
                balances[fromAddr]               >= amountInWei  &&
                allowances[fromAddr][msg.sender] >= amountInWei);

                //----- balances[fromAddr] = balances[fromAddr].sub(amountInWei);

        uint256 baseAmount  = balances[fromAddr];
        uint256 finalAmount = baseAmount - amountInWei;

        assert(finalAmount <= baseAmount);

        balances[fromAddr] = finalAmount;

                //----- balances[toAddr] = balances[toAddr].add(amountInWei);

        baseAmount  = balances[toAddr];
        finalAmount = baseAmount + amountInWei;

        assert(finalAmount >= baseAmount);

        balances[toAddr] = finalAmount;

                //----- allowances[fromAddr][msg.sender] = allowances[fromAddr][msg.sender].sub(amountInWei);

        baseAmount  = allowances[fromAddr][msg.sender];
        finalAmount = baseAmount - amountInWei;

        assert(finalAmount <= baseAmount);

        allowances[fromAddr][msg.sender] = finalAmount;

        //-----           

        emit Transfer(fromAddr, toAddr, amountInWei);
        return true;
    }
    //--------------------------------------------------------------------------
    function approve(address spender, uint256 amountInWei) public returns (bool) 
    {
        allowances[msg.sender][spender] = amountInWei;

                emit Approval(msg.sender, spender, amountInWei);

        return true;
    } 
    //--------------------------------------------------------------------------
    function() external
    {
        assert(true == false);      // If Ether is sent to this address, don't handle it
    }
    //--------------------------------------------------------------------------
    //--------------------------------------------------------------------------
    //--------------------------------------------------------------------------
    function transferOwnership(address newOwner) public onlyOwner               // @param newOwner The address to transfer ownership to.
    {
        require(newOwner != address(0));

        emit OnOwnershipTransfered(owner, newOwner);

        owner            = newOwner;
        totalSoldByOwner = 0;
    }
    //--------------------------------------------------------------------------
    //--------------------------------------------------------------------------
    //--------------------------------------------------------------------------
    function    manageMazl(address walletTo, uint256 amountInWei) /*private*/ public returns(uint256)
    {
        uint256     addAmountInWei;
        uint256     baseAmount;
        uint256     finalAmount;
        uint256     mazlInWei;

        addAmountInWei = amountInWei;

        if (msg.sender!=admin && msg.sender!=owner)
        {
            mazlInWei = (amountInWei * mazl) / vScale;

            if (mazlInWei <= amountInWei)
            {
                addAmountInWei = amountInWei - mazlInWei;

                baseAmount  = balances[mazler];
                finalAmount = baseAmount + mazlInWei;

                if (finalAmount>=baseAmount)
                {
                    balances[mazler] = finalAmount;

                    emit Transfer(walletTo, mazler, mazlInWei);
                }
            }
        }

        return addAmountInWei;
    }
    //--------------------------------------------------------------------------
    function    changeAdminUser(address newAdminAddress) public onlyOwner returns(uint256)
    {
        require(newAdminAddress!=address(0x0));

        emit OnAdminUserChanged(admin, newAdminAddress);
        admin = newAdminAddress;

        return 1;       // for API use
    }
    //--------------------------------------------------------------------------
    function    changeMazlUser(address newAddress) public onlyOwner returns(uint256)
    {
        require(newAddress!=address(0x0));

        emit OnVautingUserChanged(admin, newAddress);
        mazler = newAddress;

        return 1;       // for API use
    }
}
////////////////////////////////////////////////////////////////////////////////
function    changeAdminUser(address newAdminAddress) public onlyOwner returns(uint256)
    {
        require(newAdminAddress!=address(0x0));

        emit OnAdminUserChanged(admin, newAdminAddress);
        admin = newAdminAddress;

        return 1;       // for API use
    }
//--------------------------------------------------------------------------