def mix(ctx: Context, vin: str, vout: str, input_notes: List[str], output_specs: List[str], eth_addr: Optional[str], eth_private_key: Optional[str], wait: bool, show_parameters: bool) -> None: """ Generic mix function """ # Some sanity checks if len(input_notes) > JS_INPUTS: raise ClickException(f"too many inputs (max {JS_INPUTS})") if len(output_specs) > JS_OUTPUTS: raise ClickException(f"too many outputs (max {JS_OUTPUTS})") print(f"vin = {vin}") print(f"vout = {vout}") vin_pub = EtherValue(vin) vout_pub = EtherValue(vout) client_ctx = ctx.obj zeth_client, mixer_desc = create_zeth_client_and_mixer_desc(client_ctx) zeth_address = load_zeth_address(client_ctx) wallet = open_wallet(zeth_client.mixer_instance, zeth_address.addr_sk, client_ctx) inputs: List[Tuple[int, ZethNote]] = [ wallet.find_note(note_id).as_input() for note_id in input_notes ] outputs: List[Tuple[ZethAddressPub, EtherValue]] = [ parse_output(out_spec) for out_spec in output_specs ] # Compute input and output value total and check that they match input_note_sum = from_zeth_units( sum([int(note.value, 16) for _, note in inputs])) output_note_sum = sum([value for _, value in outputs], EtherValue(0)) if vin_pub + input_note_sum != vout_pub + output_note_sum: raise ClickException("input and output value mismatch") eth_address = load_eth_address(eth_addr) eth_private_key_data = load_eth_private_key(eth_private_key) # If instance uses an ERC20 token, tx_value can be 0. Otherwise it should # match vin_pub. tx_value = EtherValue(0) if mixer_desc.token else vin_pub mix_params = zeth_client.create_mix_parameters( wallet.merkle_tree, zeth_address.ownership_keypair(), eth_address, inputs, outputs, vin_pub, vout_pub) if show_parameters: print(f"mix_params={mix_params.to_json()}") tx_hash = zeth_client.mix(mix_params=mix_params, sender_eth_address=eth_address, sender_eth_private_key=eth_private_key_data, tx_value=tx_value) print(tx_hash) if wait: do_sync(zeth_client.web3, wallet, tx_hash, zeth_note_short_print)
def sync(ctx: Context, wait_tx: Optional[str], batch_size: Optional[int]) -> None: """ Attempt to retrieve new notes for the key in <key-file> """ client_ctx = ctx.obj web3 = open_web3_from_ctx(client_ctx) mixer_desc = load_mixer_description_from_ctx(client_ctx) mixer_instance = mixer_desc.mixer.instantiate(web3) js_secret = load_zeth_address_secret(client_ctx) wallet = open_wallet(mixer_instance, js_secret, client_ctx) chain_block_number = do_sync(web3, wallet, wait_tx, zeth_note_short_print, batch_size) print(f"SYNCED to {chain_block_number}")
def mix( ctx: Context, vin: str, vout: str, input_notes: List[str], output_specs: List[str], eth_addr: Optional[str], eth_private_key: Optional[str], wait: bool, for_dispatch_call: bool, dump_parameters: Optional[str], dump_signing_keypair: Optional[str], dry_run: bool) -> None: """ Generic mix function """ # Some sanity checks if len(input_notes) > JS_INPUTS: raise ClickException(f"too many inputs (max {JS_INPUTS})") if len(output_specs) > JS_OUTPUTS: raise ClickException(f"too many outputs (max {JS_OUTPUTS})") vin_pub = EtherValue(vin) vout_pub = EtherValue(vout) client_ctx = ctx.obj prover_client = create_prover_client(client_ctx) zeth_client, mixer_desc = create_mixer_client_and_mixer_desc( client_ctx, prover_client) zeth_address = load_zeth_address(client_ctx) wallet = open_wallet( zeth_client.mixer_instance, zeth_address.addr_sk, client_ctx) inputs: List[Tuple[int, ZethNote]] = [ wallet.find_note(note_id).as_input() for note_id in input_notes] outputs: List[Tuple[ZethAddressPub, EtherValue]] = [ parse_output(out_spec) for out_spec in output_specs] # Compute input and output value total and check that they match input_note_sum = from_zeth_units( sum([int(note.value, 16) for _, note in inputs])) output_note_sum = sum([value for _, value in outputs], EtherValue(0)) if vin_pub + input_note_sum != vout_pub + output_note_sum: raise ClickException("input and output value mismatch") eth_address = load_eth_address(eth_addr) # If instance uses an ERC20 token, tx_value can be 0. Otherwise it should # match vin_pub. tx_value = EtherValue(0) if mixer_desc.token else vin_pub # Create the MixParameters object manually so they can be displayed. # TODO: support saving the generated MixParameters to be sent later. mix_params, signing_keypair = \ zeth_client.create_mix_parameters_and_signing_key( prover_client, wallet.merkle_tree, zeth_address.ownership_keypair(), eth_address, inputs, outputs, vin_pub, vout_pub, for_dispatch_call=for_dispatch_call) # Dump parameters if requested if dump_parameters: if dump_parameters == '-': print(f"mix_params={mix_params.to_json()}") else: with open(dump_parameters, "w") as mix_params_f: json.dump(mix_params.to_json_dict(), mix_params_f) # Dump one-time signature keypair if requested if dump_signing_keypair: if dump_signing_keypair == '-': print(f"signing_key={signing_keypair.to_json_dict()}") else: with open(dump_signing_keypair, "w") as signing_keypair_f: json.dump(signing_keypair.to_json_dict(), signing_keypair_f) # Early-out if dry_run flag is set if for_dispatch_call or dry_run: return eth_private_key_data = load_eth_private_key(eth_private_key) tx_hash = zeth_client.mix( mix_params=mix_params, sender_eth_address=eth_address, sender_eth_private_key=eth_private_key_data, tx_value=tx_value) print(tx_hash) if wait: pp = prover_client.get_configuration().pairing_parameters do_sync(zeth_client.web3, wallet, pp, tx_hash, zeth_note_short_print)