Ejemplo n.º 1
0
def add_outgoing_transaction_to_blockchain(
    patch_blockchain,
    sender_sub_address,
    amount,
    receiver_address,
    sequence,
    version,
):
    metadata = general_metadata(
        from_subaddress=bytes.fromhex(sender_sub_address))
    transaction = mock_transaction(
        metadata=metadata.hex(),
        amount=amount,
        receiver_address=receiver_address,
        sequence_number=sequence,
        sender_address=VASP_ADDRESS,
        version=version,
    )

    event = mock_event(
        metadata=metadata.hex(),
        amount=amount,
        receiver_address=receiver_address,
        sender_address=VASP_ADDRESS,
        events_key=SENT_EVENTS_KEY,
        sequence_number=sequence,
        version=version,
    )

    patch_blockchain.add_account_transactions(addr_hex=VASP_ADDRESS,
                                              txs=[transaction])

    patch_blockchain.add_events(SENT_EVENTS_KEY, [event])
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
def add_incoming_transaction_to_blockchain(
    patch_blockchain,
    receiver_sub_address,
    amount,
    sender_address,
    sequence,
    version,
):
    metadata_1 = general_metadata(
        to_subaddress=bytes.fromhex(receiver_sub_address))
    transaction = mock_transaction(
        metadata=metadata_1.hex(),
        amount=amount,
        receiver_address=VASP_ADDRESS,
        sequence_number=sequence,
        sender_address=sender_address,
        version=version,
    )
    event = mock_event(
        metadata=metadata_1.hex(),
        amount=amount,
        receiver_address=VASP_ADDRESS,
        sender_address=sender_address,
        events_key=RECEIVED_EVENTS_KEY,
        sequence_number=sequence,
        version=version,
    )

    patch_blockchain.add_account_transactions(addr_hex=VASP_ADDRESS,
                                              txs=[transaction])

    patch_blockchain.add_events(RECEIVED_EVENTS_KEY, [event])

    return transaction
Ejemplo n.º 5
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()
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
 def p2p_by_general(
     self,
     currency: str,
     amount: int,
     receiver_vasp_address: str,
     receiver_sub_address: str,
     sender_sub_address: str,
 ) -> jsonrpc.Transaction:
     metadata = txnmetadata.general_metadata(
         from_subaddress=bytes.fromhex(sender_sub_address),
         to_subaddress=bytes.fromhex(receiver_sub_address),
     )
     return self._p2p_transfer(currency, amount, receiver_vasp_address,
                               metadata, b"")
Ejemplo n.º 8
0
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
Ejemplo n.º 9
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()
Ejemplo n.º 10
0
    def mint(
        self,
        authkey_hex: str,
        amount: int,
        identifier: str,
        session: Optional[requests.Session] = None,
        timeout: Optional[Union[float, Tuple[float, float]]] = None,
    ) -> int:
        dd_address_hex = account_address_hex(DESIGNATED_DEALER_ADDRESS)
        account = BlockchainMock.get_account_resource(dd_address_hex)
        sequence = account.sequence_number
        version = BlockchainMock.blockchain.version

        decoded_addr, decoded_subaddr = decode_account(authkey_hex)

        metadata = general_metadata(to_subaddress=decoded_subaddr)

        address_hex_bytes = account_address_bytes(decoded_addr)

        process_incoming_transaction(
            sender_address=dd_address_hex,
            receiver_address=authkey_hex,
            sequence=sequence,
            amount=amount,
            currency=DiemCurrency.Coin1,
            metadata=metadata,
        )

        BlockchainMock.blockchain.version += 1

        tx = MockSignedTransaction(
            sender=bytes.fromhex(ASSOC_AUTHKEY),
            amount=amount,
            currency=identifier,
            receiver=address_hex_bytes,
            metadata=metadata,
            sequence=account.sequence_number,
            version=version,
        )
        account.sequence_number += 1
        account.transactions[sequence] = tx
        BlockchainMock.blockchain.transactions[version] = tx

        return sequence
Ejemplo n.º 11
0
def test_refund_metadata_from_event_that_has_from_subaddress():
    from_sub_address = "8f8b82153010a1bd"
    reference_event_seq = 324

    metadata = txnmetadata.general_metadata(
        utils.sub_address(from_sub_address))
    event = jsonrpc.Event(
        data=jsonrpc.EventData(metadata=metadata.hex(), ),
        sequence_number=reference_event_seq,
    )

    ret = txnmetadata.refund_metadata_from_event(event)
    assert ret is not None

    gm = diem_types.Metadata__GeneralMetadata.bcs_deserialize(ret)
    assert gm is not None
    assert gm.value.value.from_subaddress is None
    assert gm.value.value.to_subaddress.hex() == from_sub_address
    assert int(gm.value.value.referenced_event) == reference_event_seq
Ejemplo n.º 12
0
def test_process_incoming_general_txn() -> None:
    account = create_account("fake_account")
    sender_addr = "46db232847705e05525db0336fd9f337"
    subaddr = generate_new_subaddress(account.id)

    meta = general_metadata(to_subaddress=sub_address(subaddr))
    process_incoming_transaction(
        sender_address=sender_addr,
        receiver_address="lrw_vasp",
        sequence=1,
        amount=100,
        currency=DiemCurrency.XUS,
        metadata=diem_types.Metadata__GeneralMetadata.bcs_deserialize(meta),
        blockchain_version=1,
    )

    # successfully parse meta and sequence
    tx = storage.get_transaction_by_details(source_address=sender_addr,
                                            source_subaddress=None,
                                            sequence=1)
    assert tx is not None
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)
Ejemplo n.º 14
0
    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
Ejemplo n.º 15
0
async def test_p2p_under_threshold_by_subaddress():
    client = create_client()
    faucet = Faucet(client)

    sender = await faucet.gen_account()
    sender_subaddress = identifier.gen_subaddress()
    receiver = await faucet.gen_account()
    receiver_subaddress = identifier.gen_subaddress()

    amount = 2_000_000

    payload = stdlib.encode_peer_to_peer_with_metadata_script_function(
        currency=utils.currency_code(XUS),
        payee=receiver.account_address,
        amount=amount,
        metadata=txnmetadata.general_metadata(sender_subaddress,
                                              receiver_subaddress),
        metadata_signature=b"",  # only travel rule metadata requires signature
    )

    seq_num = await client.get_account_sequence(sender.account_address)
    txn = diem_types.RawTransaction(
        sender=sender.account_address,
        sequence_number=seq_num,
        payload=payload,
        max_gas_amount=1_000_000,
        gas_unit_price=0,
        gas_currency_code=XUS,
        expiration_timestamp_secs=int(time.time()) + 30,
        chain_id=chain_ids.TESTNET,
    )

    signed_txn = sender.sign(txn)
    await client.submit(signed_txn)
    executed_txn = await client.wait_for_transaction(signed_txn)
    assert executed_txn is not None
Ejemplo n.º 16
0
    def trade_and_execute(
        self,
        quote_id: QuoteId,
        direction: Direction,
        diem_deposit_address: Optional[str] = None,
        tx_version: Optional[int] = None,
    ) -> TradeId:
        quote = LpClientMock.QUOTES[quote_id]
        trade_id = TradeId(uuid4())
        metadata = diem_types.Metadata__Undefined()
        if diem_deposit_address is not None:
            addr, subaddr = identifier.decode_account(diem_deposit_address,
                                                      "tdm")
            metadata = general_metadata(to_subaddress=subaddr)
        if direction == Direction.Buy:
            process_incoming_transaction(
                sender_address="",
                receiver_address=diem_deposit_address,
                sequence=1,
                amount=quote.amount,
                currency=quote.rate.pair.base.value,
                metadata=metadata,
                blockchain_version=1,
            )

        trade_data = TradeData(
            trade_id=trade_id,
            direction=direction,
            pair=quote.rate.pair,
            amount=quote.amount,
            status=TradeStatus.Complete,
            quote=quote,
            tx_version=1,
        )
        LpClientMock.TRADES[trade_id] = trade_data
        return trade_id
Ejemplo n.º 17
0
def test_new_general_metadata_from_to_sub_address():
    from_sub_address = utils.sub_address("8f8b82153010a1bd")
    to_sub_address = utils.sub_address("111111153010a111")

    ret = txnmetadata.general_metadata(from_sub_address, to_sub_address)
    assert ret.hex() == "01000108111111153010a11101088f8b82153010a1bd00"
Ejemplo n.º 18
0
def test_new_general_metadata_to_sub_address():
    sub_address = utils.sub_address("8f8b82153010a1bd")
    ret = txnmetadata.general_metadata(None, sub_address)
    assert ret.hex() == "010001088f8b82153010a1bd0000"
Ejemplo n.º 19
0
def test_new_general_metadata_for_nones():
    ret = txnmetadata.general_metadata(None, None)
    assert ret == b""
                # 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),
                )
                tx = sender_account.sign(raw_tx)
Ejemplo n.º 21
0
 def general_metadata(self, from_subaddress: bytes,
                      payee: str) -> Tuple[bytes, bytes]:
     to_account, to_subaddress = identifier.decode_account(payee, self.hrp)
     return (txnmetadata.general_metadata(from_subaddress,
                                          to_subaddress), b"")
def test_new_general_metadata_for_nones():
    ret = txnmetadata.general_metadata(None, None)
    assert ret.hex() == "0100000000"