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_travel_rule_metadata(): address = utils.account_address("f72589b71ff4f8d139674a3f7369c69b") metadata, sig_msg = txnmetadata.travel_rule("off chain reference id", address, 1000) assert metadata.hex() == "020001166f666620636861696e207265666572656e6365206964" assert ( sig_msg.hex() == "020001166f666620636861696e207265666572656e6365206964f72589b71ff4f8d139674a3f7369c69be803000000000000404024244449454d5f41545445535424244040" )
def test_account_address(): with pytest.raises(InvalidAccountAddressError): utils.account_address(bytes.fromhex("aaaa")) with pytest.raises(InvalidAccountAddressError): utils.account_address("aaaa") with pytest.raises(InvalidAccountAddressError): utils.account_address("0000000000000000000000000a550c1x") valid_address = "0000000000000000000000000a550c18" address = utils.account_address(valid_address) assert address assert utils.account_address(address) == address assert utils.account_address(bytes.fromhex(valid_address)) == address
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 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_intent_identifier(hrp_addresses): hrp, enocded_addr_with_none_subaddr, enocded_addr_with_subaddr = hrp_addresses account_id = identifier.encode_account(test_onchain_address, None, hrp) intent_id = identifier.encode_intent(account_id, "XUS", 123) assert intent_id == "diem://%s?c=%s&am=%d" % (enocded_addr_with_none_subaddr, "XUS", 123) intent = identifier.decode_intent(intent_id, hrp) assert intent.account_address == utils.account_address(test_onchain_address) assert intent.account_address_bytes.hex() == test_onchain_address assert intent.sub_address is None assert intent.currency_code == "XUS" assert intent.amount == 123 assert account_id == intent.account_id
def test_intent_identifier_without_params(hrp_addresses): hrp, enocded_addr_with_none_subaddr, enocded_addr_with_subaddr = hrp_addresses account_id = identifier.encode_account(test_onchain_address, None, hrp) intent_id = identifier.encode_intent(account_id) assert intent_id == "diem://%s" % enocded_addr_with_none_subaddr intent = identifier.decode_intent(intent_id, hrp) assert intent.account_address == utils.account_address(test_onchain_address) assert intent.account_address_bytes.hex() == test_onchain_address assert intent.sub_address is None assert intent.currency_code is None assert intent.amount is None assert account_id == intent.account_id
def test_intent_identifier(): account_id = identifier.encode_account(test_onchain_address, None, "lbr") intent_id = identifier.encode_intent(account_id, "Coin1", 123) assert intent_id == "diem://%s?c=%s&am=%d" % ( enocded_addr_with_none_subaddr, "Coin1", 123) intent = identifier.decode_intent(intent_id, "lbr") assert intent.account_address == utils.account_address( test_onchain_address) assert intent.account_address_bytes.hex() == test_onchain_address assert intent.sub_address is None assert intent.currency_code == "Coin1" assert intent.amount == 123 assert account_id == intent.account_id
def get_vasp_domain_map(self, batch_size: int = 100) -> typing.Dict[str, str]: domain_map = {} event_index = 0 tc_account = self.must_get_account( utils.account_address(TREASURY_ADDRESS)) event_stream_key = tc_account.role.vasp_domain_events_key while True: events = self.get_events(event_stream_key, event_index, batch_size) for event in events: if event.data.removed: del domain_map[event.data.domain] else: domain_map[event.data.domain] = event.data.address if len(events) < batch_size: break event_index += batch_size return domain_map
def test_find_refund_reference_event(): # None for no transaction given assert txnmetadata.find_refund_reference_event(None, None) is None receiver = utils.account_address("f72589b71ff4f8d139674a3f7369c69b") txn = jsonrpc.Transaction() txn.events.add(data=jsonrpc.EventData(type="unknown", receiver="f72589b71ff4f8d139674a3f7369c69b")) txn.events.add(data=jsonrpc.EventData(type="receivedpayment", receiver="unknown")) # None for not found event = txnmetadata.find_refund_reference_event(txn, receiver) assert event is None txn.events.add(data=jsonrpc.EventData(type="receivedpayment", receiver="f72589b71ff4f8d139674a3f7369c69b")) event = txnmetadata.find_refund_reference_event(txn, receiver) assert event is not None assert event.data.type == "receivedpayment" assert event.data.receiver == "f72589b71ff4f8d139674a3f7369c69b"
def test_process_incoming_travel_rule_txn() -> None: account = create_account("fake_account") sender_addr = "46db232847705e05525db0336fd9f337" receiver_addr = "lrw_vasp" sender_subaddr = generate_new_subaddress(account.id) amount = 1000 * 1_000_000 sender = account_address(sender_addr) sequence = 1 currency = DiemCurrency.XUS blockchain_version = 1 off_chain_reference_id = "off_chain_reference_id" metadata, _ = travel_rule(off_chain_reference_id, sender, amount) storage.add_transaction( amount=amount, currency=currency, payment_type=TransactionType.OFFCHAIN, status=TransactionStatus.OFF_CHAIN_READY, source_id=account.id, source_address=sender_addr, source_subaddress=sender_subaddr, destination_address=receiver_addr, reference_id=off_chain_reference_id, ) process_incoming_transaction( sender_address=sender_addr, receiver_address=receiver_addr, sequence=sequence, amount=amount, currency=currency, metadata=diem_types.Metadata__TravelRuleMetadata.bcs_deserialize( metadata), blockchain_version=blockchain_version, ) # successfully parse meta and sequence tx = storage.get_transaction_by_details(source_address=sender_addr, source_subaddress=sender_subaddr, sequence=sequence) assert tx is not None assert tx.sequence == sequence assert tx.blockchain_version == blockchain_version
def test_encode_addr_success(hrp_addresses): hrp, enocded_addr_with_none_subaddr, enocded_addr_with_subaddr = hrp_addresses # test with none sub_address enocded_addr = identifier.encode_account(test_onchain_address, None, hrp) assert enocded_addr == enocded_addr_with_none_subaddr # even with zero sub_address, expected should not change from above enocded_addr = identifier.encode_account(test_onchain_address, zero_sub_address, hrp) assert enocded_addr == enocded_addr_with_none_subaddr # test with some subaddress enocded_addr = identifier.encode_account(test_onchain_address, test_sub_address, hrp) assert enocded_addr == enocded_addr_with_subaddr # accept AccountAddress and bytes sub-address as params too enocded_addr = identifier.encode_account( utils.account_address(test_onchain_address), utils.sub_address(test_sub_address), hrp ) assert enocded_addr == enocded_addr_with_subaddr
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 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 vasp_account_address(self) -> diem_types.AccountAddress: return utils.account_address(self.vasp_address)