def fund_eth_address(eth_network: Optional[str], eth_addr: Optional[str], source_addr: Optional[str], amount: int) -> None: """ Fund an address. If no source address is given, the first hosted account on the RPC host is used. """ eth_addr = load_eth_address(eth_addr) network = get_eth_network(eth_network) web3 = open_web3_from_network(network) if not source_addr: # Use the first hosted address. source_addr = web3.eth.accounts[0] # pylint: disable=no-member if network.name == "autonity-helloworld": # The Autonity helloworld network supplies hosted accounts, secured # with the password 'test'. Attempt to unlock it. # pylint: disable=import-outside-toplevel, no-member from web3.middleware import geth_poa_middleware # type: ignore web3.middleware_stack.inject(geth_poa_middleware, layer=0) web3.personal.unlockAccount(source_addr, "test") print(f"eth_addr = {eth_addr}") print(f"source_addr = {source_addr}") print(f"amount = {amount}") web3.eth.sendTransaction({ # pylint: disable=no-member "from": source_addr, "to": eth_addr, "value": EtherValue(amount).wei })
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 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())
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}'")
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)
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)
def eth_get_balance(ctx: Any, eth_addr: Optional[str], wei: bool) -> None: """ Command to get the balance of specific addresses. Support multiple queries per invocation (outputs one per line), for efficiency. """ eth_addr = load_eth_address(eth_addr) web3 = open_web3_from_network(get_eth_network(ctx.obj["eth_network"])) balance_wei = web3.eth.getBalance(eth_addr) # pylint: disable=no-member if wei: print(balance_wei) else: print(EtherValue(balance_wei, "wei").ether())
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())
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)
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
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)
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))