def test_deposit_stellar_no_account(acc1_usd_deposit_transaction_factory):
    """
    `create_stellar_deposit` sets the transaction with the provided `transaction_id` to
    status `pending_trust` if the provided transaction's `stellar_account` does not
    exist yet. This condition is mocked by throwing an error when attempting to load
    information for the provided account.
    Normally, this function creates the account. We have mocked out that functionality,
    as it relies on network calls to Horizon.
    """
    deposit = acc1_usd_deposit_transaction_factory()
    deposit.status = Transaction.STATUS.pending_anchor
    deposit.asset.distribution_account_signers = json.dumps(
        mock_account.signers)
    deposit.asset.distribution_account_thresholds = json.dumps({
        "low_threshold":
        mock_account.thresholds.low_threshold,
        "med_threshold":
        mock_account.thresholds.med_threshold,
        "high_threshold":
        mock_account.thresholds.high_threshold,
    })
    deposit.asset.distribution_account_master_signer = json.dumps(
        mock_account.signers[0])
    deposit.asset.save()
    deposit.save()
    create_stellar_deposit(deposit)
    assert mock_server_no_account.submit_transaction.was_called
    # it would be pending_trust if the call to fetch the created account was not
    # mocked to raise an exception. Since the exception is raised, the transaction
    # is put in error status but the functionality works.
    assert Transaction.objects.get(
        id=deposit.id).status == Transaction.STATUS.error
    mock_server_no_account.reset_mock()
Exemplo n.º 2
0
def execute_deposit(transaction: Transaction) -> bool:
    """
    The external deposit has been completed, so the transaction
    status must now be updated to *pending_anchor*. Executes the
    transaction by calling :func:`create_stellar_deposit`.

    :param transaction: the transaction to be executed
    :returns a boolean of whether or not the transaction was
        completed successfully on the Stellar network.
    """
    if transaction.kind != transaction.KIND.deposit:
        raise ValueError("Transaction not a deposit")
    elif transaction.status != transaction.STATUS.pending_user_transfer_start:
        raise ValueError(
            f"Unexpected transaction status: {transaction.status}, expecting "
            f"{transaction.STATUS.pending_user_transfer_start}")
    elif transaction.amount_fee is None:
        if registered_fee_func == calculate_fee:
            transaction.amount_fee = calculate_fee({
                "amount":
                transaction.amount_in,
                "operation":
                settings.OPERATION_DEPOSIT,
                "asset_code":
                transaction.asset.code,
            })
        else:
            transaction.amount_fee = Decimal(0)
    transaction.status = Transaction.STATUS.pending_anchor
    transaction.status_eta = 5  # Ledger close time.
    transaction.save()
    logger.info(
        f"Transaction {transaction.id} now pending_anchor, initiating deposit")
    # launch the deposit Stellar transaction.
    return create_stellar_deposit(transaction.id)
def test_deposit_stellar_no_trustline(acc1_usd_deposit_transaction_factory):
    """
    `create_stellar_deposit` sets the transaction with the provided `transaction_id` to
    status `pending_trust` if the provided transaction's Stellar account has no trustline
    for its asset. (We assume the asset's issuer is the server Stellar account.)
    """
    deposit = acc1_usd_deposit_transaction_factory()
    deposit.status = Transaction.STATUS.pending_anchor
    deposit.asset.distribution_account_signers = json.dumps(
        mock_account.signers)
    deposit.asset.distribution_account_thresholds = json.dumps({
        "low_threshold":
        mock_account.thresholds.low_threshold,
        "med_threshold":
        mock_account.thresholds.med_threshold,
        "high_threshold":
        mock_account.thresholds.high_threshold,
    })
    deposit.asset.distribution_account_master_signer = json.dumps(
        mock_account.signers[0])
    deposit.asset.save()
    deposit.save()
    assert not create_stellar_deposit(deposit)
    assert (Transaction.objects.get(
        id=deposit.id).status == Transaction.STATUS.pending_trust)
Exemplo n.º 4
0
    def check_trustlines():
        """
        Create Stellar transaction for deposit transactions marked as pending
        trust, if a trustline has been created.
        """
        module = sys.modules[__name__]
        transactions = Transaction.objects.filter(
            kind=Transaction.KIND.deposit,
            status=Transaction.STATUS.pending_trust)
        server = settings.HORIZON_SERVER
        for transaction in transactions:
            if module.TERMINATE:
                break
            try:
                account = (server.accounts().account_id(
                    transaction.stellar_account).call())
            except BaseHorizonError:
                logger.warning(
                    f"could not load account {transaction.stellar_account} using provided horizon URL"
                )
                continue
            try:
                balances = account["balances"]
            except KeyError:
                logger.debug(
                    f"horizon account {transaction.stellar_account} response had no balances"
                )
                continue
            for balance in balances:
                if balance.get("asset_type") == "native":
                    continue
                try:
                    asset_code = balance["asset_code"]
                    asset_issuer = balance["asset_issuer"]
                except KeyError:
                    logger.debug(
                        f"horizon balance had no asset_code for account {account['id']}"
                    )
                    continue
                if (asset_code == transaction.asset.code
                        and asset_issuer == transaction.asset.issuer):
                    if check_for_multisig(transaction):
                        # Now we're waiting for signatures to be collected on real deposit transaction
                        logger.info(
                            f"Account {account['id']} has established a trustline for {asset_code}"
                        )
                        continue

                    logger.info(
                        f"Account {account['id']} has established a trustline for {asset_code}, "
                        f"initiating deposit for {transaction.id}")
                    if create_stellar_deposit(transaction,
                                              destination_exists=True):
                        transaction.refresh_from_db()
                        try:
                            rdi.after_deposit(transaction)
                        except Exception:
                            logger.exception(
                                "An unexpected error was raised from "
                                "after_deposit() in check_trustlines")
def test_deposit_stellar_success(acc1_usd_deposit_transaction_factory):
    """
    `create_stellar_deposit` succeeds if the provided transaction's `stellar_account`
    has a trustline to the issuer for its `asset`, and the Stellar transaction completes
    successfully. All of these conditions and actions are mocked in this test to avoid
    network calls.
    """
    deposit = acc1_usd_deposit_transaction_factory()
    deposit.status = Transaction.STATUS.pending_anchor
    deposit.asset.distribution_account_signers = json.dumps(
        mock_account.signers)
    deposit.asset.distribution_account_thresholds = json.dumps({
        "low_threshold":
        mock_account.thresholds.low_threshold,
        "med_threshold":
        mock_account.thresholds.med_threshold,
        "high_threshold":
        mock_account.thresholds.high_threshold,
    })
    deposit.asset.distribution_account_master_signer = json.dumps(
        mock_account.signers[0])
    deposit.asset.save()
    deposit.save()
    assert create_stellar_deposit(deposit)
    assert Transaction.objects.get(
        id=deposit.id).status == Transaction.STATUS.completed
Exemplo n.º 6
0
def test_deposit_stellar_success(acc1_usd_deposit_transaction_factory):
    """
    `create_stellar_deposit` succeeds if the provided transaction's `stellar_account`
    has a trustline to the issuer for its `asset`, and the Stellar transaction completes
    successfully. All of these conditions and actions are mocked in this test to avoid
    network calls.
    """
    deposit = acc1_usd_deposit_transaction_factory()
    deposit.status = Transaction.STATUS.pending_anchor
    deposit.save()
    assert create_stellar_deposit(deposit)
    assert Transaction.objects.get(id=deposit.id).status == Transaction.STATUS.completed
def test_deposit_stellar_no_trustline(acc1_usd_deposit_transaction_factory):
    """
    `create_stellar_deposit` sets the transaction with the provided `transaction_id` to
    status `pending_trust` if the provided transaction's Stellar account has no trustline
    for its asset. (We assume the asset's issuer is the server Stellar account.)
    """
    deposit = acc1_usd_deposit_transaction_factory()
    deposit.status = Transaction.STATUS.pending_anchor
    deposit.save()
    assert not create_stellar_deposit(deposit.id)
    assert (Transaction.objects.get(
        id=deposit.id).status == Transaction.STATUS.pending_trust)
def test_deposit_stellar_no_account(acc1_usd_deposit_transaction_factory):
    """
    `create_stellar_deposit` sets the transaction with the provided `transaction_id` to
    status `pending_trust` if the provided transaction's `stellar_account` does not
    exist yet. This condition is mocked by throwing an error when attempting to load
    information for the provided account.
    Normally, this function creates the account. We have mocked out that functionality,
    as it relies on network calls to Horizon.
    """
    deposit = acc1_usd_deposit_transaction_factory()
    deposit.status = Transaction.STATUS.pending_anchor
    deposit.save()
    assert not create_stellar_deposit(deposit.id)
    assert mock_server_no_account.submit_transaction.was_called
    assert (Transaction.objects.get(
        id=deposit.id).status == Transaction.STATUS.pending_trust)
    mock_server_no_account.reset_mock()
Exemplo n.º 9
0
def execute_deposit(transaction: Transaction) -> bool:
    valid_statuses = [
        Transaction.STATUS.pending_user_transfer_start,
        Transaction.STATUS.pending_anchor,
    ]
    if transaction.kind != transaction.KIND.deposit:
        raise ValueError("Transaction not a deposit")
    elif transaction.status not in valid_statuses:
        raise ValueError(
            f"Unexpected transaction status: {transaction.status}, expecting "
            f"{' or '.join(valid_statuses)}.")
    if transaction.status != Transaction.STATUS.pending_anchor:
        transaction.status = Transaction.STATUS.pending_anchor
    transaction.status_eta = 5  # Ledger close time.
    transaction.save()
    logger.info(f"Initiating Stellar deposit for {transaction.id}")
    # launch the deposit Stellar transaction.
    return create_stellar_deposit(transaction)
def test_deposit_stellar_no_trustline_with_claimable_bal(
    acc1_usd_deposit_transaction_factory, ):
    """
    This is the flow when a wallet/client submits a deposit and the sends
    "claimable_balance_supported=True" in their POST request body.
    Such that the deposit transaction is can continue as a
    claimable balance operation rather than a payment operation

    `execute_deposits` from `poll_pending_deposits.py`
    if the provided transaction's Stellar account has no trustline
    and sees claimable_balance_supported set to True.
    it will create_stellar_deposit()
    where it wil complete the deposit flow as a claimable balance
    """
    deposit = acc1_usd_deposit_transaction_factory()
    deposit.status = Transaction.STATUS.pending_anchor
    deposit.claimable_balance_supported = True
    deposit.save()
    assert create_stellar_deposit(deposit)
    assert Transaction.objects.get(id=deposit.id).claimable_balance_id
    assert Transaction.objects.get(
        id=deposit.id).status == Transaction.STATUS.completed
def test_bad_status(acc1_usd_deposit_transaction_factory):
    deposit = acc1_usd_deposit_transaction_factory()
    with pytest.raises(ValueError):
        create_stellar_deposit(deposit)