constant "DaoExec" {
	EcFixedPointShort VALUE_COMMIT_VALUE,
	EcFixedPoint VALUE_COMMIT_RANDOM,
}

contract "DaoExec" {
    # proposal params
    Base proposal_dest_x,
    Base proposal_dest_y,
    Base proposal_amount,
    Base proposal_serial,
    Base proposal_token_id,
    Base proposal_blind,

    # DAO params
    Base dao_proposer_limit,
    Base dao_quorum,
    Base dao_approval_ratio_quot,
    Base dao_approval_ratio_base,
    Base gov_token_id,
    Base dao_public_x,
    Base dao_public_y,
    Base dao_bulla_blind,

    # votes
    Base yes_votes_value,
    Base all_votes_value,
    Scalar yes_votes_blind,
    Scalar all_votes_blind,
    
    # outputs + inputs
    Base user_serial,
    Base user_coin_blind,
    Base dao_serial,
    Base dao_coin_blind,
    Base input_value,
    Scalar input_value_blind,

    # misc
    Base dao_spend_hook,
    Base user_spend_hook,
    Base user_data,
}

circuit "DaoExec" {
    dao_bulla = poseidon_hash(
        dao_proposer_limit,
        dao_quorum,
        dao_approval_ratio_quot,
        dao_approval_ratio_base,
        gov_token_id,
        dao_public_x,
        dao_public_y,
        dao_bulla_blind,
    );
    # Proposal bulla is valid means DAO bulla is also valid
    # because of dao-propose-main.zk, already checks that when
    # we first create the proposal. So it is redundant here.

    proposal_bulla = poseidon_hash(
        proposal_dest_x,
        proposal_dest_y,
        proposal_amount,
        proposal_serial,
        proposal_token_id,
        dao_bulla,
        proposal_blind,
        # @tmp-workaround
        proposal_blind,
    );
    constrain_instance(proposal_bulla);

    coin_0 = poseidon_hash(
       proposal_dest_x,
       proposal_dest_y,
       proposal_amount,
       proposal_token_id,
       proposal_serial,
       user_spend_hook,
       user_data,
       proposal_blind,
    );
    constrain_instance(coin_0);

    change = base_sub(input_value, proposal_amount);

    coin_1 = poseidon_hash(
       dao_public_x,
       dao_public_y,
       change,
       proposal_token_id,
       dao_serial,
       dao_spend_hook,
       dao_bulla,
       dao_coin_blind,
    );
    constrain_instance(coin_1);

    # Create pedersen commits for win_votes, and total_votes
    # and make public
    yes_votes_value_c = ec_mul_short(yes_votes_value, VALUE_COMMIT_VALUE);
    yes_votes_blind_c = ec_mul(yes_votes_blind, VALUE_COMMIT_RANDOM);
    yes_votes_commit = ec_add(yes_votes_value_c, yes_votes_blind_c);

    # get curve points and constrain
	yes_votes_commit_x = ec_get_x(yes_votes_commit);
	yes_votes_commit_y = ec_get_y(yes_votes_commit);
	constrain_instance(yes_votes_commit_x);
	constrain_instance(yes_votes_commit_y);

    all_votes_c = ec_mul_short(all_votes_value, VALUE_COMMIT_VALUE);
    all_votes_blind_c = ec_mul(all_votes_blind, VALUE_COMMIT_RANDOM);
    all_votes_commit = ec_add(all_votes_c, all_votes_blind_c);

    # get curve points and constrain
	all_votes_commit_x = ec_get_x(all_votes_commit);
	all_votes_commit_y = ec_get_y(all_votes_commit);
	constrain_instance(all_votes_commit_x);
	constrain_instance(all_votes_commit_y);

    # Create pedersen commit for input_value and make public
    
    input_value_v = ec_mul_short(input_value, VALUE_COMMIT_VALUE);
    input_value_r = ec_mul(input_value_blind, VALUE_COMMIT_RANDOM);
    input_value_commit = ec_add(input_value_v, input_value_r);

    # get curve points and constrain
	input_value_x = ec_get_x(input_value_commit);
	input_value_y = ec_get_y(input_value_commit);
	constrain_instance(input_value_x);
	constrain_instance(input_value_y);

    constrain_instance(dao_spend_hook);
    constrain_instance(user_spend_hook);
    constrain_instance(user_data);

    # Check that dao_quorum is less than or equal to all_votes_value
    one = witness_base(1);
    all_votes_value_1 = base_add(all_votes_value, one);
    less_than(dao_quorum, all_votes_value_1);

    # approval_ratio_quot / approval_ratio_base <= yes_votes / all_votes
    #
    # The above is also equivalent to this:
    #
    # all_votes * approval_ratio_quot <= yes_votes * approval_ratio_base

    rhs = base_mul(all_votes_value, dao_approval_ratio_quot);
    lhs = base_mul(yes_votes_value, dao_approval_ratio_base);

    lhs_1 = base_add(lhs, one);
    less_than(rhs, lhs_1);
    
    ####

    # Create coin 0
    # Create coin 1
    # Check values of coin 0 + coin 1 == input value
    # Check value of coin 0 == proposal_amount
    # Check public key matches too
    # Create the input value commit
    # Create the value commits

    # NOTE: there is a vulnerability here where someone can create the exec
    # transaction with a bad note so it cannot be decrypted by the receiver
    # TODO: research verifiable encryption inside ZK
}

