def test_refund_transaction_of_custodial_to_custodial_under_threshold(): client = testnet.create_client() faucet = testnet.Faucet(client) sender_custodial = CustodialApp.create(faucet.gen_account(), client) receiver_custodial = CustodialApp.create(faucet.gen_account(), client) # create a payment transaction intent_id = receiver_custodial.payment(user_id=0, amount=1_000_000) intent = identifier.decode_intent(intent_id, identifier.TDM) receiver_address = utils.account_address(intent.account_address) script = stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(intent.currency_code), payee=receiver_address, amount=intent.amount, metadata=txnmetadata.general_metadata( sender_custodial.find_user_sub_address_by_id(0), intent.sub_address), metadata_signature=b"", # only travel rule metadata requires signature ) sender = sender_custodial.available_child_vasp() txn = sender_custodial.create_transaction(sender, script, intent.currency_code) signed_txn = sender.sign(txn) client.submit(signed_txn) executed_txn = client.wait_for_transaction(signed_txn) # start to refund the transaction # find the event for the receiver, a p2p transaction may contains multiple receivers # in the future. event = txnmetadata.find_refund_reference_event(executed_txn, receiver_address) assert event is not None amount = event.data.amount.amount currency_code = event.data.amount.currency refund_receiver_address = utils.account_address(event.data.sender) metadata = txnmetadata.refund_metadata_from_event(event) refund_txn_script = stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(currency_code), payee=refund_receiver_address, amount=amount, metadata=metadata, metadata_signature=b"", # only travel rule metadata requires signature ) # receiver is sender of refund txn sender = receiver_custodial.available_child_vasp() txn = receiver_custodial.create_transaction(sender, refund_txn_script, currency_code) refund_executed_txn = receiver_custodial.submit_and_wait(sender.sign(txn)) assert refund_executed_txn is not None
def test_custodial_to_non_custodial(): client = testnet.create_client() faucet = testnet.Faucet(client) sender_custodial = CustodialApp.create(faucet.gen_account()) receiver = faucet.gen_account() amount = 1_000_000 currency_code = testnet.TEST_CURRENCY_CODE script = stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(currency_code), payee=utils.account_address(receiver.account_address), amount=amount, metadata=txnmetadata.general_metadata( sender_custodial.find_user_sub_address_by_id(0), None), metadata_signature=b"", # only travel rule metadata requires signature ) sender = sender_custodial.available_child_vasp() seq_num = client.get_account_sequence(sender.account_address) txn = create_transaction(sender, seq_num, script, currency_code) signed_txn = sender.sign(txn) client.submit(signed_txn) executed_txn = client.wait_for_transaction(signed_txn) assert executed_txn is not None
def test_custodial_to_custodial_under_threshold(): client = testnet.create_client() faucet = testnet.Faucet(client) sender_custodial = CustodialApp.create(faucet.gen_account()) receiver_custodial = CustodialApp.create(faucet.gen_account()) intent_id = receiver_custodial.payment(user_id=0, amount=1_000_000) intent = identifier.decode_intent(intent_id, identifier.TDM) script = stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(intent.currency_code), payee=utils.account_address(intent.account_address), amount=intent.amount, metadata=txnmetadata.general_metadata( sender_custodial.find_user_sub_address_by_id(0), intent.sub_address), metadata_signature=b"", # only travel rule metadata requires signature ) sender = sender_custodial.available_child_vasp() seq_num = client.get_account_sequence(sender.account_address) txn = create_transaction(sender, seq_num, script, intent.currency_code) signed_txn = sender.sign(txn) client.submit(signed_txn) executed_txn = client.wait_for_transaction(signed_txn) assert executed_txn is not None
def test_receive_payment_with_travel_rule_metadata_and_invalid_reference_id( sender_account: AccountResource, receiver_account: AccountResource, currency: str, hrp: str, stub_config: AppConfig, diem_client: jsonrpc.Client, pending_income_account: AccountResource, invalid_ref_id: Optional[str], ) -> None: """ There is no way to create travel rule metadata with invalid reference id when the payment amount meets travel rule threshold, because the metadata signature is verified by transaction script. Also, if metadata signature is provided, transaction script will also verify it regardless whether the amount meets travel rule threshold, thus no need to test invalid metadata signature case. This test bypasses the transaction script validation by sending payment amount under the travel rule threshold without metadata signature, and receiver should handle it properly and refund. Test Plan: 1. Generate a valid account identifier from receiver account as payee. 2. Submit payment under travel rule threshold transaction from sender to receiver on-chain account. 3. Wait for the transaction executed successfully. 4. Assert the payment is refund eventually. Note: the refund payment will be received by pending income account of the MiniWallet Stub, because no account owns the original invalid payment transaction which is sent by test. """ receiver_account_identifier = receiver_account.generate_account_identifier( ) receiver_account_address = identifier.decode_account_address( receiver_account_identifier, hrp) sender_account_identifier = sender_account.generate_account_identifier() sender_address = identifier.decode_account_address( sender_account_identifier, hrp) metadata, _ = txnmetadata.travel_rule(invalid_ref_id, sender_address, amount) # pyre-ignore original_payment_txn: jsonrpc.Transaction = stub_config.account.submit_and_wait_for_txn( diem_client, stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(currency), amount=amount, payee=receiver_account_address, metadata=metadata, metadata_signature=b"", ), ) pending_income_account.wait_for_event( "created_transaction", status=Transaction.Status.completed, refund_diem_txn_version=original_payment_txn.version, ) assert receiver_account.balance(currency) == 0
def test_receive_payment_with_general_metadata_and_invalid_to_subaddress( stub_client: RestClient, target_client: RestClient, currency: str, hrp: str, stub_config: AppConfig, diem_client: jsonrpc.Client, invalid_to_subaddress: Optional[bytes], ) -> None: """When received a payment with general metadata and invalid to subaddress, receiver should refund the payment by using RefundMetadata with reason `invalid subaddress`. Test Plan: 1. Generate a valid account identifier from receiver account as payee. 2. Create a general metadata with valid from subaddress and invalid to subaddress. 3. Send payment transaction from sender to receiver on-chain account. 4. Wait for the transaction executed successfully. 5. Assert sender account received a payment transaction with refund metadata. 6. Assert receiver account does not receive funds. """ amount = 1_000_000 sender_account = stub_client.create_account(balances={currency: amount}) receiver_account = target_client.create_account() try: receiver_account_identifier = receiver_account.generate_account_identifier( ) receiver_account_address: diem_types.AccountAddress = identifier.decode_account_address( receiver_account_identifier, hrp) sender_account_identifier = sender_account.generate_account_identifier( ) valid_from_subaddress = identifier.decode_account_subaddress( sender_account_identifier, hrp) invalid_metadata = txnmetadata.general_metadata( valid_from_subaddress, invalid_to_subaddress) original_payment_txn: jsonrpc.Transaction = stub_config.account.submit_and_wait_for_txn( diem_client, stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(currency), amount=amount, payee=receiver_account_address, metadata=invalid_metadata, metadata_signature=b"", ), ) sender_account.wait_for_event( "created_transaction", status=Transaction.Status.completed, refund_diem_txn_version=original_payment_txn.version, refund_reason=RefundReason.invalid_subaddress, ) assert receiver_account.balance(currency) == 0 finally: receiver_account.log_events() sender_account.log_events()
def test_receive_payment_with_refund_metadata_and_invalid_transaction_version( stub_client: RestClient, target_client: RestClient, currency: str, hrp: str, stub_config: AppConfig, diem_client: jsonrpc.Client, invalid_refund_txn_version: int, ) -> None: """ When received a payment transaction with invalid refund metadata, it's up to wallet application to decide how to handle, this test makes sure the wallet application should be able to continue to receive following up valid payment transactions. Test Plan: 1. Generate a valid account identifier from receiver account as payee. 2. Submit payment transaction with refund metadata and invalid txn version. 3. Wait for the transaction executed successfully. 4. Send a valid payment to the account identifier. 5. Assert receiver account received the valid payment. """ amount = 120_000 sender_account = stub_client.create_account(balances={currency: amount}) receiver_account = target_client.create_account() try: receiver_account_identifier = receiver_account.generate_account_identifier( ) receiver_account_address = identifier.decode_account_address( receiver_account_identifier, hrp) reason = diem_types.RefundReason__OtherReason() metadata = txnmetadata.refund_metadata(invalid_refund_txn_version, reason) stub_config.account.submit_and_wait_for_txn( diem_client, stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(currency), amount=amount * 2, payee=receiver_account_address, metadata=metadata, metadata_signature=b"", ), ) assert receiver_account.balance(currency) == 0 pay = sender_account.send_payment(currency, amount, payee=receiver_account_identifier) wait_for_payment_transaction_complete(sender_account, pay.id) receiver_account.wait_for_balance(currency, amount) finally: receiver_account.log_events() sender_account.log_events()
def _p2p_transfer(self, currency, amount, receiver_vasp_address, metadata, signature) -> jsonrpc.Transaction: script = stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(currency), payee=utils.account_address(receiver_vasp_address), amount=diem_types.st.uint64(amount), metadata=metadata, metadata_signature=signature, ) txn = self.create_transaction(script) return self._submit_and_wait(txn)
def test_receive_payment_with_general_metadata_and_invalid_subaddresses( sender_account: AccountResource, receiver_account: AccountResource, currency: str, hrp: str, stub_config: AppConfig, diem_client: jsonrpc.Client, invalid_to_subaddress: Optional[bytes], invalid_from_subaddress: Optional[bytes], pending_income_account: AccountResource, ) -> None: """When received a payment with general metadata and invalid subaddresses, it is considered same with the case received invalid to subaddress, and receiver should refund the payment. Test Plan: 1. Generate a valid account identifier from receiver account as payee. 2. Create a general metadata with invalid from subaddress and invalid to subaddress. 3. Send payment transaction from sender to receiver on-chain account. 4. Wait for the transaction executed successfully. 5. Assert sender account received a payment transaction with refund metadata. 6. Assert receiver account does not receive funds. """ receiver_account_identifier = receiver_account.generate_account_identifier( ) receiver_account_address = identifier.decode_account_address( receiver_account_identifier, hrp) invalid_metadata = txnmetadata.general_metadata(invalid_from_subaddress, invalid_to_subaddress) original_payment_txn: jsonrpc.Transaction = stub_config.account.submit_and_wait_for_txn( diem_client, stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(currency), amount=amount, payee=receiver_account_address, metadata=invalid_metadata, metadata_signature=b"", ), ) pending_income_account.wait_for_event( "created_transaction", status=Transaction.Status.completed, refund_diem_txn_version=original_payment_txn.version, refund_reason=RefundReason.invalid_subaddress, ) assert receiver_account.balance(currency) == 0
def test_receive_payment_with_general_metadata_and_invalid_from_subaddress( stub_client: RestClient, target_client: RestClient, currency: str, hrp: str, stub_config: AppConfig, diem_client: jsonrpc.Client, invalid_from_subaddress: Optional[bytes], ) -> None: """When received a payment with general metadata and invalid from subaddress, receiver is not required to take any action on it as long as to subaddress is valid. Test Plan: 1. Generate a valid account identifier from receiver account as payee. 2. Create a general metadata with invalid from subaddress and valid to subaddress. 3. Send payment transaction from sender to receiver on-chain account. 4. Wait for the transaction executed successfully. 5. Assert receiver account received funds eventually. """ amount = 1_000_000 sender_account = stub_client.create_account(balances={currency: amount}) receiver_account = target_client.create_account() try: receiver_account_identifier = receiver_account.generate_account_identifier( ) receiver_account_address = identifier.decode_account_address( receiver_account_identifier, hrp) valid_to_subaddress = identifier.decode_account_subaddress( receiver_account_identifier, hrp) invalid_metadata = txnmetadata.general_metadata( invalid_from_subaddress, valid_to_subaddress) stub_config.account.submit_and_wait_for_txn( diem_client, stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(currency), amount=amount, payee=receiver_account_address, metadata=invalid_metadata, metadata_signature=b"", ), ) receiver_account.wait_for_balance(currency, amount) finally: receiver_account.log_events() sender_account.log_events()
def test_receive_payment_with_invalid_metadata( stub_client: RestClient, target_client: RestClient, currency: str, hrp: str, stub_config: AppConfig, diem_client: jsonrpc.Client, invalid_metadata: bytes, ) -> None: """When received a payment with invalid metadata, it is up to the wallet application how to handle it. This test makes sure target wallet application should continue to process valid transactions after received such an on-chain transaction. Test Plan: 1. Generate a valid account identifier from receiver account as payee. 2. Submit a p2p transaction with invalid metadata, and wait for it is executed. 3. Send a valid payment to the valid account identifier. 4. Assert receiver account received the valid payment. """ amount = 1_000_000 sender_account = stub_client.create_account(balances={currency: amount}) receiver_account = target_client.create_account() try: account_identifier = receiver_account.generate_account_identifier() receiver_account_address = identifier.decode_account_address( account_identifier, hrp) stub_config.account.submit_and_wait_for_txn( diem_client, stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(currency), amount=amount * 2, payee=receiver_account_address, metadata=invalid_metadata, metadata_signature=b"", ), ) assert receiver_account.balance(currency) == 0 pay = sender_account.send_payment(currency=currency, amount=amount, payee=account_identifier) wait_for_payment_transaction_complete(sender_account, pay.id) receiver_account.wait_for_balance(currency, amount) finally: receiver_account.log_events() sender_account.log_events()
def transferFunds(receiver, sender, amount): script = stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(testnet.TEST_CURRENCY_CODE), payee=receiver.account_address, amount=amount, metadata=b"", # no requirement for metadata and metadata signature metadata_signature=b"", ) seq_num = client.get_account_sequence(sender.account_address) txn = create_transaction(sender, seq_num, script, testnet.TEST_CURRENCY_CODE) signed_txn = sender.sign(txn) client.submit(signed_txn) executed_txn = client.wait_for_transaction(signed_txn) return executed_txn
def test_receive_payment_with_refund_metadata_and_invalid_transaction_version( sender_account: AccountResource, receiver_account: AccountResource, currency: str, hrp: str, stub_config: AppConfig, diem_client: jsonrpc.Client, pending_income_account: AccountResource, invalid_refund_txn_version: int, ) -> None: """ When received a payment transaction with invalid refund metadata, it's up to wallet application to decide how to handle, this test makes sure the wallet application should be able to continue to receive following up valid payment transactions. Test Plan: 1. Generate a valid payment URI from receiver account. 2. Submit payment transaction with refund metadata and invalid txn version. 3. Wait for the transaction executed successfully. 4. Send a valid payment to the payment URI. 5. Assert receiver account received the valid payment. """ receiver_uri = receiver_account.generate_payment_uri() receiver_account_address: diem_types.AccountAddress = receiver_uri.intent( hrp).account_address reason = diem_types.RefundReason__OtherReason() metadata = txnmetadata.refund_metadata(invalid_refund_txn_version, reason) stub_config.account.submit_and_wait_for_txn( diem_client, stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(currency), amount=amount * 2, payee=receiver_account_address, metadata=metadata, metadata_signature=b"", ), ) assert receiver_account.balance(currency) == 0 pay = sender_account.send_payment( currency, amount, payee=receiver_uri.intent(hrp).account_id) wait_for_payment_transaction_complete(sender_account, pay.id) receiver_account.wait_for_balance(currency, amount)
def _submit_travel_rule_txn( self, command: offchain.Command, ) -> ActionResultType: command = typing.cast(offchain.PaymentCommand, command) child_vasp = self._find_child_vasp(command.sender_account_address(self.hrp)) assert command.payment.recipient_signature child_vasp.submit_and_wait_for_txn( self.jsonrpc_client, stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(command.payment.action.currency), payee=command.receiver_account_address(self.hrp), amount=command.payment.action.amount, metadata=command.travel_rule_metadata(self.hrp), metadata_signature=bytes.fromhex(command.payment.recipient_signature), ), ) return ActionResult.TXN_EXECUTED
def test_receive_payment_with_invalid_metadata( sender_account: AccountResource, receiver_account: AccountResource, currency: str, hrp: str, stub_config: AppConfig, diem_client: jsonrpc.Client, invalid_metadata: bytes, ) -> None: """When received a payment with invalid metadata, it is up to the wallet application how to handle it. This test makes sure target wallet application should continue to process valid transactions after received such an on-chain transaction. Test Plan: 1. Generate a valid payment URI from receiver account. 2. Submit a p2p transaction with invalid metadata, and wait for it is executed. 3. Send a valid payment to the payment URI. 4. Assert receiver account received the valid payment. """ uri = receiver_account.generate_payment_uri() receiver_account_address = uri.intent(hrp).account_address stub_config.account.submit_and_wait_for_txn( diem_client, stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(currency), amount=amount * 2, payee=receiver_account_address, metadata=invalid_metadata, metadata_signature=b"", ), ) assert receiver_account.balance(currency) == 0 pay = sender_account.send_payment(currency=currency, amount=amount, payee=uri.intent(hrp).account_id) wait_for_payment_transaction_complete(sender_account, pay.id) receiver_account.wait_for_balance(currency, amount)
def test_receive_payment_with_general_metadata_and_invalid_from_subaddress( sender_account: AccountResource, receiver_account: AccountResource, currency: str, hrp: str, stub_config: AppConfig, diem_client: jsonrpc.Client, invalid_from_subaddress: Optional[bytes], ) -> None: """When received a payment with general metadata and invalid from subaddress, receiver is not required to take any action on it as long as to subaddress is valid. Test Plan: 1. Generate a valid payment URI from the receiver account. 2. Create a general metadata with invalid from subaddress and valid to subaddress. 3. Send payment transaction from sender to receiver on-chain account. 4. Wait for the transaction executed successfully. 5. Assert receiver account received funds eventually. """ receiver_uri = receiver_account.generate_payment_uri() receiver_account_address: diem_types.AccountAddress = receiver_uri.intent( hrp).account_address valid_to_subaddress = receiver_uri.intent(hrp).subaddress invalid_metadata = txnmetadata.general_metadata(invalid_from_subaddress, valid_to_subaddress) stub_config.account.submit_and_wait_for_txn( diem_client, stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(currency), amount=amount, payee=receiver_account_address, metadata=invalid_metadata, metadata_signature=b"", ), ) receiver_account.wait_for_balance(currency, amount)
def send_transaction( self, currency: DiemCurrency, amount: int, dest_vasp_address: str, dest_sub_address: str, source_sub_address: str = None, ) -> Tuple[int, int]: account_info = self.fetch_account_info() if not account_info: raise RuntimeError(f"Could not find account {self.address_str}") if source_sub_address is None: source_sub_address = secrets.token_hex( identifier.DIEM_SUBADDRESS_SIZE) meta = txnmetadata.general_metadata( from_subaddress=bytes.fromhex(source_sub_address), to_subaddress=bytes.fromhex(dest_sub_address), ) script = stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(currency.value), payee=utils.account_address(dest_vasp_address), amount=amount, metadata=meta, metadata_signature=b"", ) tx = self._custody.create_transaction( self._custody_account_name, account_info.sequence_number, script, currency.value, ) self._diem_client.submit(tx) onchain_tx = self._diem_client.wait_for_transaction(tx, 30) return onchain_tx.version, account_info.sequence_number
def send_transaction_travel_rule( self, currency: DiemCurrency, amount: int, source_sub_address: str, dest_vasp_address: str, dest_sub_address: str, off_chain_reference_id: str, metadata_signature: bytes, ) -> Tuple[int, int]: account_info = self.fetch_account_info() if not account_info: raise RuntimeError(f"Could not find account {self.address_str}") sender = utils.account_address(self.address_str) metadata, metadata_sig = txnmetadata.travel_rule( off_chain_reference_id, sender, amount ) # sender constructs transaction after off chain communication script = stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(currency.value), payee=utils.account_address(dest_vasp_address), amount=amount, metadata=metadata, metadata_signature=metadata_signature, ) tx = self._custody.create_transaction( self._custody_account_name, account_info.sequence_number, script, currency.value, ) self._diem_client.submit(tx) onchain_tx = self._diem_client.wait_for_transaction(tx, 30) return onchain_tx.version, account_info.sequence_number
def test_non_custodial_to_non_custodial(): client = testnet.create_client() faucet = testnet.Faucet(client) sender = faucet.gen_account() receiver = faucet.gen_account() amount = 1_000_000 script = stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(testnet.TEST_CURRENCY_CODE), payee=receiver.account_address, amount=amount, metadata=b"", # no requirement for metadata and metadata signature metadata_signature=b"", ) seq_num = client.get_account_sequence(sender.account_address) txn = create_transaction(sender, seq_num, script, testnet.TEST_CURRENCY_CODE) signed_txn = sender.sign(txn) client.submit(signed_txn) executed_txn = client.wait_for_transaction(signed_txn) assert executed_txn is not None
def test_custodial_to_custodial_above_threshold(): client = testnet.create_client() faucet = testnet.Faucet(client) sender_custodial = CustodialApp.create(faucet.gen_account()) receiver_custodial = CustodialApp.create(faucet.gen_account()) receiver_custodial.init_compliance_keys() intent_id = receiver_custodial.payment(user_id=0, amount=2_000_000_000) intent = identifier.decode_intent(intent_id, identifier.TDM) sender = sender_custodial.available_child_vasp() # sender & receiver communicate by off chain APIs off_chain_reference_id = "32323abc" metadata, metadata_signing_msg = txnmetadata.travel_rule( off_chain_reference_id, sender.account_address, intent.amount) metadata_signature = receiver_custodial.compliance_key.sign( metadata_signing_msg) # sender constructs transaction after off chain communication script = stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(intent.currency_code), payee=utils.account_address(intent.account_address), amount=intent.amount, metadata=metadata, metadata_signature=metadata_signature, ) seq_num = client.get_account_sequence(sender.account_address) txn = create_transaction(sender, seq_num, script, intent.currency_code) signed_txn = sender.sign(txn) client.submit(signed_txn) executed_txn = client.wait_for_transaction(signed_txn) assert executed_txn is not None
def main(): # connect to testnet client = testnet.create_client() # generate private key for sender account sender_private_key = Ed25519PrivateKey.generate() # generate auth key for sender account sender_auth_key = AuthKey.from_public_key(sender_private_key.public_key()) print( f"Generated sender address: {utils.account_address_hex(sender_auth_key.account_address())}" ) # create sender account faucet = testnet.Faucet(client) testnet.Faucet.mint(faucet, sender_auth_key.hex(), 100000000, "XUS") # get sender account sender_account = client.get_account(sender_auth_key.account_address()) # generate private key for receiver account receiver_private_key = Ed25519PrivateKey.generate() # generate auth key for receiver account receiver_auth_key = AuthKey.from_public_key( receiver_private_key.public_key()) print( f"Generated receiver address: {utils.account_address_hex(receiver_auth_key.account_address())}" ) # create receiver account faucet = testnet.Faucet(client) testnet.Faucet.mint(faucet, receiver_auth_key.hex(), 10000000, CURRENCY) # create script script = stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(CURRENCY), payee=receiver_auth_key.account_address(), amount=10000000, metadata=b'', # no requirement for metadata and metadata signature metadata_signature=b'', ) # create transaction raw_transaction = diem_types.RawTransaction( sender=sender_auth_key.account_address(), sequence_number=sender_account.sequence_number, payload=diem_types.TransactionPayload__Script(script), max_gas_amount=1_000_000, gas_unit_price=0, gas_currency_code=CURRENCY, expiration_timestamp_secs=int(time.time()) + 30, chain_id=testnet.CHAIN_ID, ) # sign transaction signature = sender_private_key.sign( utils.raw_transaction_signing_msg(raw_transaction)) public_key_bytes = utils.public_key_bytes(sender_private_key.public_key()) signed_txn = utils.create_signed_transaction(raw_transaction, public_key_bytes, signature) # submit transaction client.submit(signed_txn) # wait for transaction client.wait_for_transaction(signed_txn)
else: # use DD private key to send P2P transaction to the watched account sender_account = LocalAccount( Ed25519PrivateKey.from_private_bytes( bytes.fromhex(private_key))) sender_account_info = diem_client.get_account( sender_account.account_address) sender_account_addr_hex = utils.account_address_hex( sender_account.account_address) script = stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(currency), payee=watched_account_addr, amount=refill_amount, metadata=txnmetadata.general_metadata( from_subaddress=utils.account_address_bytes( sender_account.account_address), to_subaddress=utils.account_address_bytes( watched_account_addr), ), metadata_signature=b"", ) raw_tx = diem_types.RawTransaction( sender=sender_account.account_address, sequence_number=sender_account_info.sequence_number, payload=diem_types.TransactionPayload__Script(script), max_gas_amount=1_000_000, gas_unit_price=0, gas_currency_code=currency, expiration_timestamp_secs=int(time()) + 30, chain_id=diem_types.ChainId.from_int(network_chainid), )
def main(): print("#1 connect to testnet") client = testnet.create_client() print("#2 Generate Keys") # generate private key for sender account sender_private_key = Ed25519PrivateKey.generate() # generate auth key for sender account sender_auth_key = AuthKey.from_public_key(sender_private_key.public_key()) print( f"Generated sender address: {utils.account_address_hex(sender_auth_key.account_address())}" ) print("#3 Create account") faucet = testnet.Faucet(client) testnet.Faucet.mint(faucet, sender_auth_key.hex(), 100000000, CURRENCY) print("#4 Get account information") sender_account = client.get_account(sender_auth_key.account_address()) events_key = sender_account.received_events_key print("#5 Start event listener") get_events_example.subscribe(client, events_key) print("#6 Add money to account") faucet = testnet.Faucet(client) testnet.Faucet.mint(faucet, sender_auth_key.hex(), 10000000, CURRENCY) print("#7 Generate Keys") # generate private key for receiver account receiver_private_key = Ed25519PrivateKey.generate() # generate auth key for receiver account receiver_auth_key = AuthKey.from_public_key( receiver_private_key.public_key()) print( f"Generated receiver address: {utils.account_address_hex(receiver_auth_key.account_address())}" ) print("#8 Create second account") faucet = testnet.Faucet(client) testnet.Faucet.mint(faucet, receiver_auth_key.hex(), 1000000, CURRENCY) print("#9 Generate IntentIdentifier") account_identifier = identifier.encode_account( utils.account_address_hex(receiver_auth_key.account_address()), None, identifier.TDM) encoded_intent_identifier = identifier.encode_intent( account_identifier, CURRENCY, 10000000) print(f"Encoded IntentIdentifier: {encoded_intent_identifier}") print("#10 Deserialize IntentIdentifier") intent_identifier = identifier.decode_intent(encoded_intent_identifier, identifier.TDM) print( f"Account (HEX) from intent: {utils.account_address_hex(intent_identifier.account_address)}" ) print(f"Amount from intent: {intent_identifier.amount}") print(f"Currency from intent: {intent_identifier.currency_code}") print("#11 Peer 2 peer transaction") # create script script = stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(intent_identifier.currency_code), payee=intent_identifier.account_address, amount=intent_identifier.amount, metadata=b'', # no requirement for metadata and metadata signature metadata_signature=b'', ) # create transaction raw_transaction = diem_types.RawTransaction( sender=sender_auth_key.account_address(), sequence_number=sender_account.sequence_number, payload=diem_types.TransactionPayload__Script(script), max_gas_amount=1_000_000, gas_unit_price=0, gas_currency_code=CURRENCY, expiration_timestamp_secs=int(time.time()) + 30, chain_id=testnet.CHAIN_ID, ) # sign transaction signature = sender_private_key.sign( utils.raw_transaction_signing_msg(raw_transaction)) public_key_bytes = utils.public_key_bytes(sender_private_key.public_key()) signed_txn = utils.create_signed_transaction(raw_transaction, public_key_bytes, signature) # submit transaction client.submit(signed_txn) # wait for transaction client.wait_for_transaction(signed_txn)