# Part One (Governance Tutorial)

In the first challenge, you will examine a simple governance contract. This smart contract allows users to create proposals. Users can stake the ERC-20 governance token into different proposals to vote for them, and if a proposal reaches a given threshold, it can be executed!

This style of governance machinery is often used by Decentralized Autonomous Organizations (DAOs) (opens new window) as well as our class! In this challenge, we will see what happens to our system when a user is able to obtain the majority of the governance tokens.

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import 'OpenZeppelin/openzeppelin-contracts@4.4.2/contracts/proxy/ERC1967/ERC1967Proxy.sol';
import 'OpenZeppelin/openzeppelin-contracts@4.4.2/contracts/token/ERC20/IERC20.sol';
import './Governance.sol';

contract PartOne {
    Governance public governance;
    IERC20 public token;
    address player;

    constructor(address _player) {
        player = _player;
        governance = new Governance(player);
        token = governance.token();
    }
    
    function solved() view external returns (bool) {
        return governance.owner() == player;
    }
}
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import 'OpenZeppelin/openzeppelin-contracts@4.4.2/contracts/proxy/ERC1967/ERC1967Proxy.sol';
import 'OpenZeppelin/openzeppelin-contracts@4.4.2/contracts/token/ERC20/IERC20.sol';
import './GovTokenLogic.sol';

contract Governance {
    address public owner;

    struct Transaction {
        address target;
        uint256 value;
        bytes data;
    }

    struct Proposal {
        bool executed;
        string description;
        Transaction transaction;
        uint256 amount;
    }

    uint256 constant public TOTAL_SUPPLY = 1e18;

    IERC20 public token;

    Proposal[] public proposals;
    mapping (uint256 => mapping (address => uint256)) public pools;

    constructor(address recipient) {
        // the GovTokenLogic contract is a logic contract
        // it is an openzeppelin upgradeable contract
        // we need to deploy it

        GovTokenLogic logic = new GovTokenLogic();
        token = IERC20(address(new ERC1967Proxy(
            address(logic),
            abi.encodeWithSelector(
                logic.initialize.selector,
                TOTAL_SUPPLY
            )
        )));

        require(token.totalSupply() == TOTAL_SUPPLY);
        require(token.balanceOf(address(this)) == TOTAL_SUPPLY);

        token.transfer(recipient, TOTAL_SUPPLY);

        owner = msg.sender;
    }

    function createProposal(
        string memory description,
        address target,
        uint256 value,
        bytes memory data
    ) public returns (uint256) {
        Proposal memory proposal = Proposal({
            executed: false,
            description: description,
            transaction: Transaction({
                target: target,
                value: value,
                data: data
            }),
            amount: 0
        });
        proposals.push(proposal);
        return proposals.length - 1;
    }

    function deposit(uint256 id, uint256 amount) public {
        require(id < proposals.length, "invalid proposal id");
        require(!proposals[id].executed, "proposal already executed");
        require(token.transferFrom(msg.sender, address(this), amount));

        proposals[id].amount += amount;
        pools[id][msg.sender] += amount;
    }

    function withdraw(uint256 id) public {
        require(id < proposals.length, "invalid proposal id");

        uint256 amount = pools[id][msg.sender];
        require(amount > 0, "no balance");

        proposals[id].amount -= amount;
        pools[id][msg.sender] = 0;

        require(token.transfer(msg.sender, amount));
    }

    function execute(uint256 id) public {
        require(id < proposals.length, "invalid proposal id");
        require(!proposals[id].executed, "proposal already executed");

        Proposal storage proposal = proposals[id];

        uint256 threshold = TOTAL_SUPPLY / 2;
        require(proposal.amount >= threshold, "insufficient votes");

         proposal.executed = true;

        (bool success,) = proposal.transaction.target.delegatecall(
            proposal.transaction.data
        );
        require(success, "transaction failed");
    }
}

Can you take control of the contract and become the owner?