def update_transaction(response: Dict, transaction: Transaction, error_msg: str = None):
    """
    Updates the transaction depending on whether or not the transaction was
    successfully executed on the Stellar network and `process_withdrawal`
    completed without raising an exception.

    If the Horizon response indicates the response was not successful or an
    exception was raised while processing the withdrawal, we mark the status
    as `error`. If the Stellar transaction succeeded, we mark it as `completed`.

    :param error_msg: a description of the error that has occurred.
    :param response: a response body returned from Horizon for the transaction
    :param transaction: a database model object representing the transaction
    """
    if error_msg or not response["successful"]:
        transaction.status = Transaction.STATUS.error
        transaction.status_message = error_msg
    else:
        transaction.completed_at = now()
        transaction.status = Transaction.STATUS.completed
        transaction.status_eta = 0
        transaction.amount_out = transaction.amount_in - transaction.amount_fee

    transaction.stellar_transaction_id = response["id"]
    transaction.save()
Example #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)
Example #3
0
    def find_matching_payment_op(
            cls, response: Dict, horizon_tx: HorizonTransaction,
            transaction: Transaction) -> Optional[Operation]:
        """
        Determines whether or not the given ``response`` represents the given
        ``transaction``. Polaris does this by checking the 'memo' field in the horizon
        response matches the `transaction.memo`, as well as ensuring the
        transaction includes a payment operation of the anchored asset.

        :param response: the JSON response from horizon for the transaction
        :param horizon_tx: the decoded Transaction object contained in the Horizon response
        :param transaction: a database model object representing the transaction
        """
        matching_payment_op = None
        for operation in horizon_tx.operations:
            if cls._check_payment_op(operation, transaction.asset):
                transaction.stellar_transaction_id = response["id"]
                transaction.from_address = operation.source
                transaction.paging_token = response["paging_token"]
                transaction.status_eta = 0
                transaction.save()
                matching_payment_op = operation
                break

        return matching_payment_op
 def _update_transaction_info(cls, transaction: Transaction,
                              stellar_txid: str, paging_token: str,
                              source: str):
     transaction.stellar_transaction_id = stellar_txid
     transaction.from_address = source
     transaction.paging_token = paging_token
     transaction.status_eta = 0
     transaction.save()
Example #5
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)
Example #6
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}")
    transaction.status = Transaction.STATUS.pending_anchor
    transaction.status_eta = 5  # Ledger close time.
    transaction.save()
    # launch the deposit Stellar transaction.
    return create_stellar_deposit(transaction.id)
    def submit(cls, transaction: Transaction) -> bool:
        valid_statuses = [
            Transaction.STATUS.pending_user_transfer_start,
            Transaction.STATUS.pending_external,
            Transaction.STATUS.pending_anchor,
            Transaction.STATUS.pending_trust,
        ]
        if transaction.status not in valid_statuses:
            raise ValueError(
                f"Unexpected transaction status: {transaction.status}, expecting "
                f"{' or '.join(valid_statuses)}."
            )

        transaction.status = Transaction.STATUS.pending_anchor
        transaction.status_eta = 5  # Ledger close time.
        transaction.save()
        logger.info(f"Initiating Stellar deposit for {transaction.id}")
        maybe_make_callback(transaction)

        if transaction.envelope_xdr:
            envelope = TransactionEnvelope.from_xdr(
                transaction.envelope_xdr, settings.STELLAR_NETWORK_PASSPHRASE
            )
        else:
            distribution_acc, _ = get_account_obj(
                Keypair.from_public_key(transaction.asset.distribution_account)
            )
            envelope = cls.create_deposit_envelope(transaction, distribution_acc)
            envelope.sign(transaction.asset.distribution_seed)

        transaction.status = Transaction.STATUS.pending_stellar
        transaction.save()
        logger.info(f"Transaction {transaction.id} now pending_stellar")
        maybe_make_callback(transaction)

        try:
            response = settings.HORIZON_SERVER.submit_transaction(envelope)
        except BaseHorizonError as e:
            cls._handle_error(transaction, f"{e.__class__.__name__}: {e.message}")
            return False

        if not response.get("successful"):
            cls._handle_error(
                transaction,
                f"Stellar transaction failed when submitted to horizon: {response['result_xdr']}",
            )
            return False
        elif transaction.claimable_balance_supported:
            transaction.claimable_balance_id = cls.get_balance_id(response)

        transaction.envelope_xdr = response["envelope_xdr"]
        transaction.paging_token = response["paging_token"]
        transaction.stellar_transaction_id = response["id"]
        transaction.status = Transaction.STATUS.completed
        transaction.completed_at = datetime.datetime.now(datetime.timezone.utc)
        transaction.status_eta = 0
        transaction.amount_out = round(
            Decimal(transaction.amount_in) - Decimal(transaction.amount_fee),
            transaction.asset.significant_decimals,
        )
        transaction.save()
        logger.info(f"Transaction {transaction.id} completed.")
        maybe_make_callback(transaction)
        return True