# Investment

What do you think about if stock-exchange server is running on blockchain? Can you buy codegate stock?


// SPDX-License-Identifier: MIT

pragma solidity ^0.8.11;

import "OpenZeppelin/openzeppelin-contracts@4.4.2/contracts/utils/math/SafeMath.sol";

contract Investment {
    address private implementation;
    address private owner;
    address[] public donaters;

    using SafeMath for uint;

    mapping (address => bool) private _minted;
    mapping (bytes32 => uint) private _total_stocks;
    mapping (bytes32 => uint) private _reg_stocks;
    mapping (address => mapping (bytes32 => uint)) private _stocks;
    mapping (address => uint) private _balances;

    address lastDonater;
    uint fee;
    uint denominator;
    bool inited;

    modifier isInited {
        require(inited);
        _;
    }

    function init() public {
        require(!inited);

        _reg_stocks[keccak256("apple")] = 111;
        _total_stocks[keccak256("apple")] = 99999999;
        _reg_stocks[keccak256("microsoft")] = 101;
        _total_stocks[keccak256("microsoft")] = 99999999;
        _reg_stocks[keccak256("intel")] = 97;
        _total_stocks[keccak256("intel")] = 99999999;
        _reg_stocks[keccak256("amd")] = 74;
        _total_stocks[keccak256("amd")] = 99999999;
        _reg_stocks[keccak256("codegate")] = 11111111111111111111111111111111111111;
        _total_stocks[keccak256("codegate")] = 1;
        fee = 5;
        denominator = 1e4;
        inited = true;
    }

    function buyStock(string memory _stockName, uint _amountOfStock) public isInited {
        bytes32 stockName = keccak256(abi.encodePacked(_stockName));
        require(_total_stocks[stockName] > 0 && _amountOfStock > 0);
        uint amount = _reg_stocks[stockName].mul(_amountOfStock).mul(denominator + fee).div(denominator);
        require(_balances[msg.sender] >= amount);
        
        _balances[msg.sender] -= amount;
        _stocks[msg.sender][stockName] += _amountOfStock;
        _total_stocks[stockName] -= _amountOfStock;
    }

    function sellStock(string memory _stockName, uint _amountOfStock) public isInited {
        bytes32 stockName = keccak256(abi.encodePacked(_stockName));
        require(_amountOfStock > 0);
        uint amount = _reg_stocks[stockName].mul(_amountOfStock).mul(denominator).div(denominator + fee);
        require(_stocks[msg.sender][stockName] >= _amountOfStock);
        _balances[msg.sender] += amount;
        _stocks[msg.sender][stockName] -= _amountOfStock;
        _total_stocks[stockName] += _amountOfStock;
    }

    function donateStock(address _to, string memory _stockName, uint _amountOfStock) public isInited {
        bytes32 stockName = keccak256(abi.encodePacked(_stockName));
        require(_amountOfStock > 0);
        require(isUser(msg.sender) && _stocks[msg.sender][stockName] >= _amountOfStock);
        _stocks[msg.sender][stockName] -= _amountOfStock;
        (bool success, bytes memory result) = msg.sender.call(abi.encodeWithSignature("receiveStock(address,bytes32,uint256)", _to, stockName, _amountOfStock));
        require(success);
        lastDonater = msg.sender;
        donaters.push(lastDonater);
    }

    function isInvalidDonaters(uint index) internal returns (bool) {
        require(donaters.length > index);
        if (!isUser(lastDonater)) {
            return true;
        }
        else {
            return false;
        }
    }

    function modifyDonater(uint index) public isInited {
        require(isInvalidDonaters(index));
        donaters[index] = msg.sender;
    }

    function isUser(address _user) internal returns (bool) {
        uint size;
        assembly {
            size := extcodesize(_user)
        }
        return size == 0;
    }

    function mint() public isInited {
        require(!_minted[msg.sender]);
        _balances[msg.sender] = 300;
        _minted[msg.sender] = true;
    }

    function isSolved() public isInited returns (bool) {
        return _total_stocks[keccak256("codegate")] == 0;
    }
}
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.11;


contract InvestmentProxy {
    address implementation;
    address owner;
    
    struct log {
        bytes12 time;
        address sender;
    }
    log info;
    
    constructor(address _target) {
        owner = msg.sender;
        implementation = _target;
    }

    function setImplementation(address _target) public {
        require(msg.sender == owner);
        implementation = _target;
    }

    function _delegate(address _target) internal {
        assembly {
            calldatacopy(0, 0, calldatasize())

            let result := delegatecall(gas(), _target, 0, calldatasize(), 0, 0)

            returndatacopy(0, 0, returndatasize())

            switch result
            case 0 {
                revert(0, returndatasize())
            }
            default {
                return(0, returndatasize())
            }
        }
    }

    function _implementation() internal view returns (address) {
        return implementation;
    }

    function _fallback() internal {
        _beforeFallback();
        _delegate(_implementation());
    }

    fallback() external payable {
        _fallback();
    }

    receive() external payable {
        _fallback();
    }

    function _beforeFallback() internal {
        info.time = bytes12(uint96(block.timestamp));
        info.sender = msg.sender;
    }
}