Community Investment Pool

What it does:
A smart contract that allows a community to pool funds together and collectively invest, manage, and share profits according to predefined contribution-based rules.

Why it matters:
Small investors often lack access to high-quality opportunities. By pooling capital and enforcing transparent governance, this contract enables collective investing without centralized fund managers.

How it works:

  • Members deposit funds into a shared investment pool.

  • Each member’s ownership share is calculated proportionally to contributions.

  • Profits (or losses) are reflected in the pool’s total value.

  • Members can withdraw their share based on current pool valuation.

  • All balances and ownership ratios are tracked transparently on-chain.

      // SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title CommunityInvestmentPool
 * @author Nam
 * @notice Collective investment pool with proportional ownership
 */
contract CommunityInvestmentPool {

    // -------------------- DATA STRUCTURES --------------------

    struct Member {
        uint256 shares;      // Ownership shares
        bool active;
    }

    mapping(address => Member) public members;
    address[] public memberList;

    address public manager;
    uint256 public totalShares;
    uint256 public totalPoolValue;

    // -------------------- EVENTS --------------------

    event Joined(address indexed member, uint256 amount, uint256 shares);
    event PoolValueUpdated(uint256 newValue);
    event Withdrawn(address indexed member, uint256 amount);

    // -------------------- MODIFIERS --------------------

    modifier onlyManager() {
        require(msg.sender == manager, "Not manager");
        _;
    }

    modifier onlyMember() {
        require(members[msg.sender].active, "Not member");
        _;
    }

    // -------------------- CONSTRUCTOR --------------------

    constructor() {
        manager = msg.sender;
    }

    // -------------------- CORE LOGIC --------------------

    /**
     * @notice Join the investment pool
     */
    function joinPool() external payable {
        require(msg.value > 0, "Zero contribution");

        uint256 newShares;
        if (totalShares == 0) {
            newShares = msg.value;
        } else {
            newShares =
                (msg.value * totalShares) / totalPoolValue;
        }

        if (!members[msg.sender].active) {
            members[msg.sender] = Member({
                shares: newShares,
                active: true
            });
            memberList.push(msg.sender);
        } else {
            members[msg.sender].shares += newShares;
        }

        totalShares += newShares;
        totalPoolValue += msg.value;

        emit Joined(msg.sender, msg.value, newShares);
    }

    /**
     * @notice Manager updates pool value (profits/losses)
     * @dev In real systems, this reflects external investments
     */
    function updatePoolValue(uint256 _newValue)
        external
        onlyManager
    {
        require(_newValue > 0, "Invalid value");

        totalPoolValue = _newValue;
        emit PoolValueUpdated(_newValue);
    }

    /**
     * @notice Withdraw proportional share from pool
     */
    function withdraw() external onlyMember {
        Member storage member = members[msg.sender];

        uint256 amount =
            (member.shares * totalPoolValue) / totalShares;

        totalShares -= member.shares;
        totalPoolValue -= amount;

        member.shares = 0;
        member.active = false;

        payable(msg.sender).transfer(amount);

        emit Withdrawn(msg.sender, amount);
    }

    // -------------------- VIEW FUNCTIONS --------------------

    /**
     * @notice Get member info
     */
    function getMember(address _member)
        external
        view
        returns (
            uint256 shares,
            bool active
        )
    {
        Member memory m = members[_member];
        return (
            m.shares,
            m.active
        );
    }

    /**
     * @notice Get pool overview
     */
    function getPoolStats()
        external
        view
        returns (
            uint256 _totalPoolValue,
            uint256 _totalShares,
            uint256 _memberCount
        )
    {
        return (
            totalPoolValue,
            totalShares,
            memberList.length
        );
    }
}