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()
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 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()
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 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