Example #1
0
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)
Example #2
0
def token_approve(
        ctx: Context,
        value: str,
        eth_addr: str,
        eth_private_key: str,
        wait: bool,
        instance_file: str) -> None:
    """
    Approve the mixer to spend some amount of ERC20/223 tokens
    """
    approve_value = EtherValue(value)
    eth_addr = load_eth_address(eth_addr)
    eth_private_key_data = load_eth_private_key(eth_private_key)
    web3 = open_web3_from_network(get_eth_network(ctx.obj["eth_network"]))
    mixer_desc = load_mixer_description(instance_file)
    if not mixer_desc.token:
        raise ClickException("no token for mixer {mixer_desc.mixer.address}")

    token_instance = mixer_desc.token.instantiate(web3)
    approve_call = token_instance.functions.approve(
        mixer_desc.mixer.address,
        approve_value.wei)
    tx_hash = send_contract_call(
        web3, approve_call, eth_addr, eth_private_key_data)

    if wait:
        web3.eth.waitForTransactionReceipt(tx_hash)  # pylint: disable=no-member
    else:
        print(tx_hash.hex())
Example #3
0
def deploy(ctx: Context, verification_key_hash: str,
           dispatcher_instance_file: str, instance_file: str) -> None:
    """
    Deploy the contract for a dummy application.
    """

    eth_network = ctx.obj["eth_network"]

    # Load the dispatcher instance
    with open(dispatcher_instance_file, "r") as dispatcher_instance_f:
        dispatcher_desc = InstanceDescription.from_json_dict(
            json.load(dispatcher_instance_f))

    # Verification key hash as an array of evm words.
    verification_key_hash_evm = list(
        hex_to_uint256_list(verification_key_hash))
    print(f"verification_key_hash_evm = {verification_key_hash_evm}")

    web3 = open_web3_from_network(eth_network)
    eth_address = load_eth_address(ctx.obj["eth_addr"])
    eth_private_key_data = load_eth_private_key(ctx.obj["eth_private_key"])
    instance_desc = InstanceDescription.deploy(
        web3, DUMMY_APP_CONTRACT_FILE, "DummyApplication", eth_address,
        eth_private_key_data, DUMMY_APP_CONTRACT_DEPLOY_GAS,
        {"allow_paths": CONTRACTS_DIR},
        [dispatcher_desc.address, verification_key_hash_evm])

    with open(instance_file, "w") as instance_file_f:
        json.dump(instance_desc.to_json_dict(), instance_file_f)

    print(f"Instance file written to '{instance_file}'")
Example #4
0
def deploy(
        ctx: Context,
        eth_addr: Optional[str],
        eth_private_key: Optional[str],
        instance_out: str,
        token_address: str,
        deploy_gas: Optional[int]) -> None:
    """
    Deploy the zeth contracts and record the instantiation details.
    """
    eth_address = load_eth_address(eth_addr)
    eth_private_key_data = load_eth_private_key(eth_private_key)
    client_ctx = ctx.obj
    web3 = open_web3_from_ctx(client_ctx)

    print(f"deploy: eth_address={eth_address}")
    print(f"deploy: instance_out={instance_out}")
    print(f"deploy: token_address={token_address}")

    token_instance_desc = get_erc20_instance_description(token_address) \
        if token_address else None

    prover_client = create_prover_client(client_ctx)
    _zeth_client, mixer_instance_desc = MixerClient.deploy(
        web3,
        prover_client,
        eth_address,
        eth_private_key_data,
        token_address,
        deploy_gas)

    mixer_desc = MixerDescription(mixer_instance_desc, token_instance_desc)
    write_mixer_description(instance_out, mixer_desc)
Example #5
0
def deploy(ctx: Context, eth_addr: Optional[str],
           eth_private_key: Optional[str], instance_out: str,
           token_address: Optional[str], permitted_dispatcher: Optional[str],
           vk_hash: Optional[str], deploy_gas: Optional[int]) -> None:
    """
    Deploy the zeth contracts and record the instantiation details.
    """
    eth_address = load_eth_address(eth_addr)
    eth_private_key_data = load_eth_private_key(eth_private_key)
    client_ctx = ctx.obj
    web3 = open_web3_from_ctx(client_ctx)

    if bool(permitted_dispatcher) != bool(vk_hash):
        raise ClickException(
            "Must supply BOTH --permitted-dispatch AND --vk-hash, or NEITHER")

    print(f"deploy: eth_address={eth_address}")
    print(f"deploy: instance_out={instance_out}")
    print(f"deploy: token_address={token_address}")

    if permitted_dispatcher:
        permitted_dispatcher = load_contract_address(permitted_dispatcher)
        print(f"deploy: permitted_dispatcher={permitted_dispatcher}")
        print(f"deploy: vk_hash={vk_hash}")

    token_instance_desc = get_erc20_instance_description(token_address) \
        if token_address else None

    prover_client = create_prover_client(client_ctx)
    _zeth_client, mixer_instance_desc = MixerClient.deploy(
        web3,
        prover_client,
        eth_address,
        eth_private_key_data,
        token_address,
        permitted_dispatcher=permitted_dispatcher,
        vk_hash=vk_hash,
        deploy_gas=deploy_gas)

    mixer_desc = MixerDescription(mixer=mixer_instance_desc,
                                  token=token_instance_desc,
                                  permitted_dispatcher=permitted_dispatcher,
                                  vk_hash=vk_hash)
    write_mixer_description(instance_out, mixer_desc)
Example #6
0
def deposit(
        ctx: Context,
        value: str,
        eth_addr: Optional[str],
        eth_private_key: Optional[str],
        wait: bool,
        show_parameters: bool) -> None:
    """
    Deposit function
    """

    value_pub = EtherValue(value)
    client_ctx = ctx.obj
    prover_client = create_prover_client(client_ctx)
    zklay_client, zklay_desc = create_zklay_client_and_zklay_desc(
        client_ctx, prover_client)

    zklay_address = load_zklay_address(client_ctx)
    wallet = open_zklay_wallet(
        zklay_client.mixer_instance, zklay_address.addr_sk, client_ctx)

    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 zklay_desc.token else value_pub


    # Create the MixParameters object manually so they can be displayed.
    deposit_params = zklay_client.create_deposit(prover_client, eth_address, eth_private_key_data, zklay_address, value_pub)  

    if show_parameters:
        print(f"deposit_params={deposit_params.to_json()}")

    tx_hash = zklay_client.zklay_deposit(
        deposit_params=deposit_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
Example #7
0
def deploy_test_token(eth_network: Optional[str], eth_addr: Optional[str],
                      eth_private_key: Optional[str], mint_amount: int,
                      recipient_address: str) -> None:
    """
    Deploy a simple ERC20 token for testing, and mint some for a specific
    address. Print the token address.
    """
    eth_addr = load_eth_address(eth_addr)
    eth_private_key_data = load_eth_private_key(eth_private_key)
    recipient_address = load_eth_address(recipient_address)
    web3 = open_web3_from_network(get_eth_network(eth_network))
    token_instance = deploy_token(
        web3, eth_addr, eth_private_key_data, 4000000) \
        # pylint: disable=no-member

    mint_tx_hash = mint_token(web3, token_instance, recipient_address,
                              eth_addr, eth_private_key_data,
                              EtherValue(mint_amount, 'ether'))
    web3.eth.waitForTransactionReceipt(mint_tx_hash)
    print(token_instance.address)
Example #8
0
def eth_send(
        ctx: Context,
        dest_addr: str,
        eth_private_key: Optional[str],
        eth_addr: Optional[str],
        amount: str) -> None:
    """
    Send Ether from the local eth-addr to a destination address.
    """
    dest_addr = load_eth_address(dest_addr)
    eth_private_key_data = load_eth_private_key(eth_private_key)
    eth_addr = load_eth_address(eth_addr)
    eth_network = get_eth_network(ctx.obj["eth_network"])
    web3 = open_web3_from_network(eth_network)

    if eth_private_key_data is None:
        raise ClickException("hosted accounts are not supported")

    print(f"eth_addr = {eth_addr}")
    print(f"dest_addr = {dest_addr}")
    print(f"amount = {amount}")

    # pylint: disable=no-member
    send_tx_desc = {
        "from": eth_addr,
        "to": dest_addr,
        "value": EtherValue(amount).wei,
        "gasPrice": web3.eth.gasPrice,
        "nonce": web3.eth.getTransactionCount(eth_addr)
    }
    send_tx_desc["gas"] = web3.eth.estimateGas(send_tx_desc)

    signed_tx = web3.eth.account.signTransaction(
        send_tx_desc, eth_private_key_data)

    tx_hash = web3.eth.sendRawTransaction(signed_tx.rawTransaction)
    # pylint: enable=no-member

    print(tx_hash.hex())
Example #9
0
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)
Example #10
0
 def get_eth_key_and_address(self) -> Tuple[str, Optional[bytes]]:
     return (load_eth_address(self.eth_addr),
             load_eth_private_key(self.eth_private_key))