diff --git a/aeternity/__main__.py b/aeternity/__main__.py index f9b41811..719a7542 100644 --- a/aeternity/__main__.py +++ b/aeternity/__main__.py @@ -351,7 +351,7 @@ def account_balance(keystore_name, password, height, force, wait, json_): _print_error(e, exit_code=1) -@account.command('spend', help="Create a transaction to another account") +@account.command('spend', help="Create a transaction to another account or AENS Name") @click.argument('keystore_name', required=True) @click.argument('recipient_id', required=True) @click.argument('amount', required=True, type=int) @@ -361,12 +361,16 @@ def account_balance(keystore_name, password, height, force, wait, json_): @online_options @transaction_options def account_spend(keystore_name, recipient_id, amount, payload, fee, ttl, nonce, password, force, wait, json_): + """ + KEYSTORE_NAME is the name of the keystore file of the sender account + RECIPIENT_ID can be address of the recipient account or an AENS Name + AMOUNT is the amount to transfer + """ try: set_global_options(json_, force, wait) account, _ = _account(keystore_name, password=password) account.nonce = nonce - if not utils.is_valid_hash(recipient_id, prefix="ak"): - raise ValueError("Invalid recipient address") + tx = None tx = _node_cli().spend(account, recipient_id, amount, tx_ttl=ttl, fee=fee, payload=payload) _print_object(tx, title='spend transaction') except Exception as e: @@ -388,8 +392,7 @@ def account_transfer_amount(keystore_name, recipient_id, transfer_amount, includ set_global_options(json_, force, wait) account, _ = _account(keystore_name, password=password) account.nonce = nonce - if not utils.is_valid_hash(recipient_id, prefix="ak"): - raise ValueError("Invalid recipient address") + tx = None tx = _node_cli().transfer_funds(account, recipient_id, transfer_amount, tx_ttl=ttl, payload=payload, include_fee=include_fee) _print_object(tx, title='spend transaction') except Exception as e: @@ -589,7 +592,7 @@ def name_update(keystore_name, domain, address, name_ttl, ttl, fee, nonce, passw if name.status != name.Status.CLAIMED: print(f"Domain is {name.status} and cannot be transferred") exit(0) - tx = name.update(account, target=address, name_ttl=name_ttl, tx_ttl=ttl) + tx = name.update(account, address, name_ttl=name_ttl, tx_ttl=ttl) _print_object(tx, title=f"Name {domain} status update") except Exception as e: _print_error(e, exit_code=1) diff --git a/aeternity/node.py b/aeternity/node.py index bd4fcfcf..c5e95a4d 100644 --- a/aeternity/node.py +++ b/aeternity/node.py @@ -239,6 +239,10 @@ def spend(self, account: Account, """ Create and execute a spend transaction """ + if utils.is_valid_aens_name(recipient_id): + recipient_id = hashing.name_id(recipient_id) + elif not utils.is_valid_hash(recipient_id, prefix="ak"): + raise TypeError("Invalid recipient_id. Please provide a valid AENS name or account pub_key.") # retrieve the nonce account.nonce = self.get_next_nonce(account.get_address()) if account.nonce == 0 else account.nonce + 1 # retrieve ttl @@ -251,20 +255,6 @@ def spend(self, account: Account, self.broadcast_transaction(tx) return tx - def spend_by_name(self, account: Account, - recipient_name: str, - amount: int, - payload: str = "", - fee: int = defaults.FEE, - tx_ttl: int = defaults.TX_TTL): - """ - Create and execute a spend to name_id transaction - """ - if utils.is_valid_aens_name(recipient_name): - name_id = hashing.name_id(recipient_name) - return self.spend(account, name_id, amount, payload, fee, tx_ttl) - raise TypeError("Invalid AENS name. Please provide a valid AENS name.") - def wait_for_transaction(self, tx_hash, max_retries=None, polling_interval=None): """ Wait for a transaction to be mined for an account @@ -362,6 +352,10 @@ def transfer_funds(self, account: Account, """ Create and execute a spend transaction """ + if utils.is_valid_aens_name(recipient_id): + recipient_id = hashing.name_id(recipient_id) + elif not utils.is_valid_hash(recipient_id, prefix="ak"): + raise TypeError("Invalid recipient_id. Please provide a valid AENS name or account pub_key.") if percentage < 0 or percentage > 1: raise ValueError(f"Percentage should be a number between 0 and 1, got {percentage}") account_on_chain = self.get_account_by_pubkey(pubkey=account.get_address()) diff --git a/tests/test_aens.py b/tests/test_aens.py index fef078cb..5ffebe2e 100644 --- a/tests/test_aens.py +++ b/tests/test_aens.py @@ -136,7 +136,7 @@ def test_spend_by_name(chain_fixture): name.update_status() print(f"domain is {name.domain} name_id {name.name_id}") print("pointers", name.pointers) - tx = chain_fixture.NODE_CLI.spend_by_name(chain_fixture.ALICE, domain, 100) + tx = chain_fixture.NODE_CLI.spend(chain_fixture.ALICE, domain, 100) print("DATA ", tx) recipient_account = chain_fixture.NODE_CLI.get_account_by_pubkey(pubkey=target_address) print(f"recipient address {target_address}, balance {recipient_account.balance}") diff --git a/tests/test_cli.py b/tests/test_cli.py index a54f6e92..0ad31e99 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -93,6 +93,29 @@ def test_cli_spend(chain_fixture, tempdir): print(f"recipient address {recipient_address}, balance {recipient_account.balance}") assert recipient_account.balance == 90 +def test_cli_spend_by_name(chain_fixture, tempdir): + account_alice_path = _account_path(tempdir, chain_fixture.ALICE) + # generate a new address + recipient_address = Account.generate().get_address() + domain = __fullclaim_domain(chain_fixture, tempdir, recipient_address) + call_aecli('account', 'spend', account_alice_path, domain, "90", '--password', 'aeternity_bc', '--wait') + # test that the recipient account has the requested amount + print(f"recipient domain is {domain}") + recipient_account = chain_fixture.NODE_CLI.get_account_by_pubkey(pubkey=recipient_address) + print(f"recipient address {recipient_address}, balance {recipient_account.balance}") + assert recipient_account.balance == 90 + +def test_cli_transfer_by_name(chain_fixture, tempdir): + account_alice_path = _account_path(tempdir, chain_fixture.ALICE) + # generate a new address + recipient_address = Account.generate().get_address() + domain = __fullclaim_domain(chain_fixture, tempdir, recipient_address) + val = call_aecli('account', 'transfer', account_alice_path, domain, "0.01", '--password', 'aeternity_bc', '--wait') + # test that the recipient account has the requested amount + print(f"recipient domain is {domain}") + recipient_account = chain_fixture.NODE_CLI.get_account_by_pubkey(pubkey=recipient_address) + print(f"recipient address {recipient_address}, balance {recipient_account.balance}") + assert recipient_account.balance == val['data']['tx']['data']['amount'] def test_cli_spend_invalid_amount(chain_fixture, tempdir): with pytest.raises(subprocess.CalledProcessError): @@ -265,3 +288,18 @@ def test_cli_contract_deploy_call(chain_fixture, compiler_fixture, tempdir): th = j.get("hash") assert utils.is_valid_hash(th, prefix=identifiers.TRANSACTION_HASH) +def __fullclaim_domain(chain_fixture, tempdir, recipient_address): + account_path = _account_path(tempdir, chain_fixture.ALICE) + domain = random_domain(length=13 ,tld='chain' if chain_fixture.NODE_CLI.get_consensus_protocol_version() >= identifiers.PROTOCOL_LIMA else 'test') + # let alice preclaim a name + j = call_aecli('name', 'pre-claim', '--password', 'aeternity_bc', account_path, domain, '--wait') + # retrieve the salt and the transaction hash + salt = j.get("metadata",{}).get("salt") + preclaim_hash = j.get("hash") + # wait for confirmation + chain_fixture.NODE_CLI.wait_for_confirmation(preclaim_hash) + # now run the claim + j = call_aecli('name', 'claim', account_path, domain, '--password', 'aeternity_bc', '--name-salt', f"{salt}", '--preclaim-tx-hash', preclaim_hash, '--wait') + # now run the name update + j = call_aecli('name', 'update', '--password', 'aeternity_bc', account_path, domain, recipient_address) + return domain \ No newline at end of file