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_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_intent_identifier_with_sub_address(hrp_addresses): hrp, enocded_addr_with_none_subaddr, enocded_addr_with_subaddr = hrp_addresses account_id = identifier.encode_account(test_onchain_address, test_sub_address, hrp) intent_id = identifier.encode_intent(account_id, "XUS", 123) assert intent_id == "diem://%s?c=%s&am=%d" % (enocded_addr_with_subaddr, "XUS", 123) intent = identifier.decode_intent(intent_id, hrp) assert intent.account_address_bytes.hex() == test_onchain_address assert intent.sub_address == bytes.fromhex(test_sub_address) assert intent.currency_code == "XUS" assert intent.amount == 123
def test_intent_identifier_with_sub_address(): account_id = identifier.encode_account(test_onchain_address, test_sub_address, "lbr") intent_id = identifier.encode_intent(account_id, "Coin1", 123) assert intent_id == "diem://%s?c=%s&am=%d" % (enocded_addr_with_subaddr, "Coin1", 123) intent = identifier.decode_intent(intent_id, "lbr") assert intent.account_address_bytes.hex() == test_onchain_address assert intent.sub_address == bytes.fromhex(test_sub_address) assert intent.currency_code == "Coin1" assert intent.amount == 123
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_generate_account_payment_uri_with_currency_and_amount( account: AccountResource, currency: str, hrp: str) -> None: amount = 1123 uri = account.generate_payment_uri(currency=currency, amount=amount) assert uri.id assert uri.account_id == account.id assert uri.currency == currency assert uri.amount == amount intent = identifier.decode_intent(uri.payment_uri, hrp) assert intent.account_address assert intent.subaddress assert intent.currency_code == currency assert intent.amount == amount
def test_generate_account_payment_uri_without_currency_and_amount( account: AccountResource, hrp: str) -> None: uri = account.generate_payment_uri() assert uri.id assert uri.account_id == account.id assert uri.currency is None assert uri.amount is None assert uri.payment_uri intent = identifier.decode_intent(uri.payment_uri, hrp) assert intent.account_address assert intent.subaddress assert intent.currency_code is None assert intent.amount is None
def test_intent_identifier_decode_errors(hrp_addresses): hrp, enocded_addr_with_none_subaddr, enocded_addr_with_subaddr = hrp_addresses # amount is not int with pytest.raises(identifier.InvalidIntentIdentifierError): identifier.decode_intent("diem://%s?c=XUS&am=str" % (enocded_addr_with_none_subaddr), hrp) # too many amount with pytest.raises(identifier.InvalidIntentIdentifierError): identifier.decode_intent("diem://%s?c=XUS&am=2&am=3" % (enocded_addr_with_none_subaddr), hrp) # scheme not match with pytest.raises(identifier.InvalidIntentIdentifierError): identifier.decode_intent("hello://%s?am=2&c=XUS" % (enocded_addr_with_none_subaddr), hrp) # hrp not match with pytest.raises(identifier.InvalidIntentIdentifierError): identifier.decode_intent("diem://%s?am=2&c=XUS" % (enocded_addr_with_none_subaddr), "xdm")
def pay( self, user_name: str, intent_id: str, desc: typing.Optional[str] = None, original_payment_reference_id: typing.Optional[str] = None, ) -> str: """make payment from given user account to intent_id""" intent = identifier.decode_intent(intent_id, self.hrp) command = offchain.PaymentCommand.init( self.gen_user_account_id(user_name), self.users[user_name].kyc_data(), intent.account_id, intent.amount, intent.currency_code, original_payment_reference_id=original_payment_reference_id, description=desc, ) self.save_command(command) return command.reference_id()
def main(): # generate private key private_key = Ed25519PrivateKey.generate() # generate auth key auth_key = AuthKey.from_public_key(private_key.public_key()) # create intent identifier account_identifier = identifier.encode_account( utils.account_address_hex(auth_key.account_address()), None, identifier.TDM) encoded_intent_identifier = identifier.encode_intent( account_identifier, "XUS", 10000000) print(f"Encoded IntentIdentifier: {encoded_intent_identifier}") # 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}")
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(): 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)
def test_intent_identifier_decode_errors(): # amount is not int with pytest.raises(identifier.InvalidIntentIdentifierError): identifier.decode_intent( "diem://%s?c=Coin1&am=str" % (enocded_addr_with_none_subaddr), "lbr") # amount not exist with pytest.raises(identifier.InvalidIntentIdentifierError): identifier.decode_intent( "diem://%s?c=Coin1" % (enocded_addr_with_none_subaddr), "lbr") # too many amount with pytest.raises(identifier.InvalidIntentIdentifierError): identifier.decode_intent( "diem://%s?c=Coin1&am=2&am=3" % (enocded_addr_with_none_subaddr), "lbr") # amount is none with pytest.raises(identifier.InvalidIntentIdentifierError): identifier.decode_intent( "diem://%s?c=Coin1&am=" % (enocded_addr_with_none_subaddr), "lbr") # currency code not exist with pytest.raises(identifier.InvalidIntentIdentifierError): identifier.decode_intent( "diem://%s?am=2" % (enocded_addr_with_none_subaddr), "lbr") # scheme not match with pytest.raises(identifier.InvalidIntentIdentifierError): identifier.decode_intent( "hello://%s?am=2&c=Coin1" % (enocded_addr_with_none_subaddr), "lbr") # hrp not match with pytest.raises(identifier.InvalidIntentIdentifierError): identifier.decode_intent( "diem://%s?am=2&c=Coin1" % (enocded_addr_with_none_subaddr), "tlb")
def subaddress(uri: str) -> str: return utils.hex(identifier.decode_intent(uri, hrp).subaddress)