Esempio n. 1
0
def payment(lrw1: offchain_business.LRW, lrw2: offchain_business.LRW, user1,
            user2) -> PaymentObject:
    user1address = generate_new_subaddress(account_id=user1.account_id)
    user2address = generate_new_subaddress(account_id=user2.account_id)

    return make_payment(lrw1.user_address(user1address),
                        lrw2.user_address(user2address), 1000)
Esempio n. 2
0
def send_fake_tx(amount=100, send_to_self=False) -> Tuple[int, Transaction]:
    user = OneUser.run(db_session,
                       account_amount=100_000_000_000,
                       account_currency=DiemCurrency.XUS)
    account_id = user.account_id
    amount = amount
    payment_type = types.TransactionType.EXTERNAL
    currency = diem_utils.types.currencies.DiemCurrency.XUS
    destination_address = "receiver_address"
    destination_subaddress = "receiver_subaddress"

    if send_to_self:
        destination_address = account_address_hex(
            context.get().config.vasp_address)
        destination_subaddress = generate_new_subaddress(account_id)

    send_tx = send_transaction(
        sender_id=account_id,
        amount=amount,
        currency=currency,
        payment_type=payment_type,
        destination_address=destination_address,
        destination_subaddress=destination_subaddress,
    )

    return account_id, get_transaction(send_tx.id) if send_tx else None
Esempio n. 3
0
def save_outbound_transaction(
    sender_id: int,
    destination_address: str,
    destination_subaddress: str,
    amount: int,
    currency: DiemCurrency,
) -> Transaction:
    sender_onchain_address = context.get().config.vasp_address
    sender_subaddress = account.generate_new_subaddress(account_id=sender_id)
    return commit_transaction(
        _new_payment_command_transaction(
            offchain.PaymentCommand.init(
                identifier.encode_account(
                    sender_onchain_address, sender_subaddress, _hrp()
                ),
                _user_kyc_data(sender_id),
                identifier.encode_account(
                    destination_address, destination_subaddress, _hrp()
                ),
                amount,
                currency.value,
            ),
            TransactionStatus.OFF_CHAIN_OUTBOUND,
        )
    )
Esempio n. 4
0
async def test_check_account_existence_receiver_not_exist(lrw1, lrw2, user1):
    user1address = generate_new_subaddress(account_id=user1.account_id)
    user2address = "cf64428bdeb62af2"
    payment = make_payment(lrw1.user_address(user1address),
                           lrw2.user_address(user2address), 1000)

    await lrw1.check_account_existence(payment)
    with pytest.raises(BusinessValidationFailure):
        await lrw2.check_account_existence(payment)
Esempio n. 5
0
async def test_get_extended_kyc_unknown_user_subaddress(lrw1, lrw2, user2):
    user1address = "cf64428bdeb62af2"
    user2address = generate_new_subaddress(account_id=user2.account_id)
    payment = make_payment(lrw1.user_address(user1address),
                           lrw2.user_address(user2address), 1000)

    with pytest.raises(BusinessForceAbort):
        await lrw1.get_extended_kyc(payment)
    assert await lrw2.get_extended_kyc(payment)
Esempio n. 6
0
def internal_transaction(
    sender_id: int,
    receiver_id: int,
    amount: int,
    currency: DiemCurrency,
    payment_type: TransactionType,
) -> Transaction:
    """Transfer transaction between accounts in the LRW internal ledger."""

    log_execution("Enter internal_transaction")

    if not validate_balance(sender_id, amount, currency):
        raise BalanceError(
            f"Balance {account_service.get_account_balance_by_id(account_id=sender_id).total[currency]} "
            f"is less than amount needed {amount}")

    sender_subaddress = account_service.generate_new_subaddress(sender_id)
    receiver_subaddress = account_service.generate_new_subaddress(receiver_id)
    internal_vasp_address = context.get().config.vasp_address

    transaction = add_transaction(
        amount=amount,
        currency=currency,
        payment_type=payment_type,
        status=TransactionStatus.COMPLETED,
        source_id=sender_id,
        source_address=internal_vasp_address,
        source_subaddress=sender_subaddress,
        destination_id=receiver_id,
        destination_address=internal_vasp_address,
        destination_subaddress=receiver_subaddress,
    )

    log_execution(
        f"Transfer from {sender_id} to {receiver_id} started with transaction id {transaction.id}"
    )
    add_transaction_log(transaction.id, "Transfer completed")
    return transaction
Esempio n. 7
0
def handle_outgoing_transaction(sender_sub_address):
    if sender_sub_address:
        sender_sub_record = SubAddress.query.filter_by(
            address=sender_sub_address
        ).first()

        if sender_sub_record:
            source_id = sender_sub_record.account_id
        else:
            source_id = Account.query.filter_by(name=INVENTORY_ACCOUNT_NAME).first().id
    else:
        source_id = Account.query.filter_by(name=INVENTORY_ACCOUNT_NAME).first().id
        sender_sub_address = generate_new_subaddress(source_id)

    return sender_sub_address, source_id
Esempio n. 8
0
def test_process_inbound_command(monkeypatch):
    hrp = context.get().config.diem_address_hrp()
    user = OneUser.run(db_session,
                       account_amount=100_000_000_000,
                       account_currency=currency)
    amount = 10_000_000_000
    sender = LocalAccount.generate()
    sender_subaddress = identifier.gen_subaddress()
    receiver_subaddress = generate_new_subaddress(user.account_id)
    cmd = offchain.PaymentCommand.init(
        identifier.encode_account(sender.account_address, sender_subaddress,
                                  hrp),
        _user_kyc_data(user.account_id),
        identifier.encode_account(context.get().config.vasp_address,
                                  receiver_subaddress, hrp),
        amount,
        currency.value,
    )

    with monkeypatch.context() as m:
        client = context.get().offchain_client
        m.setattr(
            client,
            "process_inbound_request",
            lambda _, cmd: client.create_inbound_payment_command(
                cmd.cid, cmd.payment),
        )
        code, resp = process_inbound_command(cmd.payment.sender.address, cmd)
        assert code == 200
        assert resp

    txn = get_transaction_by_reference_id(cmd.reference_id())
    assert txn
    assert txn.status == TransactionStatus.OFF_CHAIN_INBOUND

    cmd = _txn_payment_command(txn)
    assert cmd.is_inbound(), str(cmd)

    with monkeypatch.context() as m:
        m.setattr(
            context.get().offchain_client,
            "send_command",
            lambda cmd, _: offchain.reply_request(cmd.cid),
        )
        process_offchain_tasks()

        db_session.refresh(txn)
        assert txn.status == TransactionStatus.OFF_CHAIN_OUTBOUND
Esempio n. 9
0
def handle_incoming_transaction(receiver_sub_address):
    if receiver_sub_address:
        sub_address_record = SubAddress.query.filter_by(
            address=receiver_sub_address).first()

        if sub_address_record:
            destination_id = sub_address_record.account_id
        else:
            destination_id = (Account.query.filter_by(
                name=INVENTORY_ACCOUNT_NAME).first().id)
    else:
        destination_id = Account.query.filter_by(
            name=INVENTORY_ACCOUNT_NAME).first().id
        receiver_sub_address = generate_new_subaddress(destination_id)

    return destination_id, receiver_sub_address
Esempio n. 10
0
def external_transaction(
    sender_id: int,
    receiver_address: str,
    receiver_subaddress: str,
    amount: int,
    currency: DiemCurrency,
    payment_type: TransactionType,
    original_txn_id: int,
) -> Transaction:
    logger.info(
        f"external_transaction {sender_id} to receiver {receiver_address}, "
        f"receiver subaddress {receiver_subaddress}, amount {amount}")
    if not validate_balance(sender_id, amount, currency):
        raise BalanceError(
            f"Balance {account_service.get_account_balance_by_id(account_id=sender_id).total[currency]} "
            f"is less than amount needed {amount}")

    sender_onchain_address = context.get().config.vasp_address

    sender_subaddress = None
    if (payment_type == TransactionType.EXTERNAL
            or payment_type == TransactionType.REFUND):
        sender_subaddress = account_service.generate_new_subaddress(
            account_id=sender_id)

    transaction = add_transaction(
        amount=amount,
        currency=currency,
        payment_type=payment_type,
        status=TransactionStatus.PENDING,
        source_id=sender_id,
        source_address=sender_onchain_address,
        source_subaddress=sender_subaddress,
        destination_id=None,
        destination_address=receiver_address,
        destination_subaddress=receiver_subaddress,
        original_txn_id=original_txn_id,
    )

    if services.run_bg_tasks():
        from ..background_tasks.background import async_external_transaction

        async_external_transaction.send(transaction.id)
    else:
        submit_onchain(transaction_id=transaction.id)

    return transaction
Esempio n. 11
0
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
Esempio n. 12
0
def test_process_incoming_refund_txn() -> None:
    initial_sender_account = create_account("fake_account")
    initial_sender_subaddr = generate_new_subaddress(initial_sender_account.id)
    initial_sender_addr = "lrw_vasp"
    initial_receiver_addr = "46db232847705e05525db0336fd9f337"

    meta = refund_metadata(
        original_transaction_version=1,
        reason=diem_types.RefundReason__InvalidSubaddress(),
    )

    initial_tx = storage.add_transaction(
        amount=500,
        currency=DiemCurrency.XUS,
        payment_type=TransactionType.EXTERNAL,
        status=TransactionStatus.COMPLETED,
        source_id=initial_sender_account.id,
        source_address=initial_sender_addr,
        source_subaddress=initial_sender_subaddr,
        destination_address=initial_receiver_addr,
        blockchain_version=1,
    )

    assert initial_tx is not None
    assert initial_tx.blockchain_version == 1
    assert storage.get_transaction_by_blockchain_version(1) is not None

    process_incoming_transaction(
        sender_address=initial_receiver_addr,
        receiver_address=initial_sender_addr,
        sequence=1,
        amount=500,
        currency=DiemCurrency.XUS,
        metadata=diem_types.Metadata__RefundMetadata.bcs_deserialize(meta),
        blockchain_version=2,
    )

    tx = storage.get_transaction_by_blockchain_version(2)
    assert tx is not None
    assert tx.type == TransactionType.REFUND
    assert tx.original_txn_id == initial_tx.id
Esempio n. 13
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
Esempio n. 14
0
def test_send_payment_between_vasps(lrw1, lrw2, vasp1, vasp2, user1, user2):
    sender_address = lrw1.context.config.vasp_diem_address()
    receiver_address = lrw2.context.config.vasp_diem_address()
    receiver_subaddress = generate_new_subaddress(account_id=user2.account_id)

    # setup global environment as lrw1 app
    context.set(lrw1.context)
    client.set(vasp1)

    txn = send_transaction(
        sender_id=user1.account_id,
        amount=2_000_000_000,
        currency=DiemCurrency.Coin1,
        destination_address=receiver_address.get_onchain_address_hex(),
        destination_subaddress=receiver_subaddress,
    )

    assert txn
    assert txn.off_chain
    assert len(txn.off_chain) == 1
    assert txn.off_chain[0].reference_id

    reference_id = txn.off_chain[0].reference_id

    num_tries = 20
    while num_tries > 1:
        txn = get_single_transaction(txn.id)
        if txn.status == TransactionStatus.COMPLETED:
            break
        num_tries -= 1
        time.sleep(1)

    payment = vasp1.get_payment_by_ref(reference_id)
    assert payment.sender.status.as_status() == Status.ready_for_settlement
    assert payment.receiver.status.as_status() == Status.ready_for_settlement

    payment = vasp2.get_payment_by_ref(reference_id)
    assert payment.sender.status.as_status() == Status.ready_for_settlement
    assert payment.receiver.status.as_status() == Status.ready_for_settlement
Esempio n. 15
0
def test_subaddr_map() -> None:
    account = create_account(account_name="fake_account")

    subaddr = generate_new_subaddress(account.id)

    assert get_account_id_from_subaddr(subaddr) == account.id
Esempio n. 16
0
def external_offchain_transaction(
    sender_id: int,
    receiver_address: str,
    receiver_subaddress: str,
    amount: int,
    currency: DiemCurrency,
    payment_type: TransactionType,
    original_payment_reference_id: Optional[str] = None,
    description: Optional[str] = None,
) -> Transaction:

    sender_onchain_address = context.get().config.vasp_address
    logger.info(
        f"=================Start external_offchain_transaction "
        f"{sender_onchain_address}, {sender_id}, {receiver_address}, {receiver_subaddress}, "
        f"{amount}, {currency}, {payment_type}")
    if not validate_balance(sender_id, amount, currency):
        raise BalanceError(
            f"Balance {account_service.get_account_balance_by_id(account_id=sender_id).total[currency]} "
            f"is less than amount needed {amount}")

    sender_subaddress = account_service.generate_new_subaddress(
        account_id=sender_id)
    logger.info(f"======sender_subaddress: {sender_subaddress}")
    ref_id = get_new_offchain_reference_id(sender_onchain_address)
    transaction = add_transaction(
        amount=amount,
        currency=currency,
        payment_type=payment_type,
        status=TransactionStatus.PENDING,
        source_id=sender_id,
        source_address=sender_onchain_address,
        source_subaddress=sender_subaddress,
        destination_id=None,
        destination_address=receiver_address,
        destination_subaddress=receiver_subaddress,
        reference_id=ref_id,
    )

    # off-chain logic
    sender_address = LibraAddress.from_bytes(
        context.get().config.diem_address_hrp(),
        bytes.fromhex(sender_onchain_address),
        bytes.fromhex(sender_subaddress),
    )
    logger.info(
        f"sender address: {sender_onchain_address}, {sender_address.as_str()}, {sender_address.get_onchain().as_str()}"
    )
    receiver_address = LibraAddress.from_bytes(
        context.get().config.diem_address_hrp(),
        bytes.fromhex(receiver_address),
        bytes.fromhex(receiver_subaddress),
    )
    logger.info(
        f"receiver address: {receiver_address.as_str()}, {receiver_address.get_onchain().as_str()}",
    )
    sender = PaymentActor(
        sender_address.as_str(),
        StatusObject(Status.needs_kyc_data),
        [],
    )
    receiver = PaymentActor(receiver_address.as_str(),
                            StatusObject(Status.none), [])
    action = PaymentAction(amount, currency, "charge", int(time()))
    reference_id = get_reference_id_from_transaction_id(transaction.id)
    payment = PaymentObject(
        sender=sender,
        receiver=receiver,
        reference_id=reference_id,
        original_payment_reference_id=original_payment_reference_id,
        description=description,
        action=action,
    )
    cmd = PaymentCommand(payment)

    if not get_transaction_status(transaction.id) == TransactionStatus.PENDING:
        logger.info(
            "In external_offchain_transaction, payment status is not PENDING, abort"
        )
        return

    update_transaction(transaction.id, TransactionStatus.OFF_CHAIN_STARTED)
    logger.info(
        "In external_offchain_transaction: Updated status to OFF_CHAIN_STARTED"
    )

    result = (offchain_client.get().new_command(receiver_address.get_onchain(),
                                                cmd).result(timeout=300))
    logger.info(f"Offchain Result: {result}")

    return transaction