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, Base gov_token_id, Base dao_public_x, Base dao_public_y, Base dao_bulla_blind, # votes Base win_votes, Base total_votes, Scalar win_votes_blind, Scalar total_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, gov_token_id, dao_public_x, dao_public_y, dao_bulla_blind, # @tmp-workaround 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, proposal_bulla, dao_coin_blind, ); constrain_instance(coin_1); # Create pedersen commits for win_votes, and total_votes # and make public win_votes_v = ec_mul_short(win_votes, VALUE_COMMIT_VALUE); win_votes_r = ec_mul(win_votes_blind, VALUE_COMMIT_RANDOM); win_votes_commit = ec_add(win_votes_v, win_votes_r); # get curve points and constrain win_votes_commit_x = ec_get_x(win_votes_commit); win_votes_commit_y = ec_get_y(win_votes_commit); constrain_instance(win_votes_commit_x); constrain_instance(win_votes_commit_y); total_votes_v = ec_mul_short(total_votes, VALUE_COMMIT_VALUE); total_votes_r = ec_mul(total_votes_blind, VALUE_COMMIT_RANDOM); total_votes_commit = ec_add(total_votes_v, total_votes_r); # get curve points and constrain total_votes_commit_x = ec_get_x(total_votes_commit); total_votes_commit_y = ec_get_y(total_votes_commit); constrain_instance(total_votes_commit_x); constrain_instance(total_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); # total_votes >= dao_quorum # TODO: waiting on this opcode in zkas # # greater_than_or_equal(total_votes, dao_quorum) # # win_votes / total_votes >= approval_ratio_quot / approval_ratio_base # # The above is also equivalent to this: # # win_votes * approval_ratio_base >= total_votes * approval_ratio_quot # # TODO: waiting on this opcode in zkas # # lhs = base_mul(win_votes, approval_ratio_base); # rhs = base_mul(total_votes, approval_ratio_quot); # greater_than_or_equal(lhs, rhs); # #### # 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 }