def get_or_create_destination_account(
        transaction: Transaction, ) -> Tuple[Account, bool]:
        """
        Returns:
            Account: The account found or created for the Transaction
            bool: True if trustline doesn't exist, False otherwise.

        If the account doesn't exist, Polaris must create the account using an account provided by the
        anchor. Polaris can use the distribution account of the anchored asset or a channel account if
        the asset's distribution account requires non-master signatures.

        If the transacted asset's distribution account does require non-master signatures,
        DepositIntegration.create_channel_account() will be called. See the function docstring for more
        info.

        On failure to create the destination account, a RuntimeError exception is raised.
        """
        try:
            account, json_resp = get_account_obj(
                Keypair.from_public_key(transaction.stellar_account))
            return account, is_pending_trust(transaction, json_resp)
        except RuntimeError:
            if MultiSigTransactions().requires_multisig(transaction):
                source_account_kp = MultiSigTransactions.get_channel_keypair(
                    transaction)
                source_account, _ = get_account_obj(source_account_kp)
            else:
                source_account_kp = Keypair.from_secret(
                    transaction.asset.distribution_seed)
                source_account, _ = get_account_obj(source_account_kp)

            builder = TransactionBuilder(
                source_account=source_account,
                network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE,
                # this transaction contains one operation so base_fee will be multiplied by 1
                base_fee=settings.MAX_TRANSACTION_FEE_STROOPS
                or settings.HORIZON_SERVER.fetch_base_fee(),
            )
            transaction_envelope = builder.append_create_account_op(
                destination=transaction.stellar_account,
                starting_balance=settings.ACCOUNT_STARTING_BALANCE,
            ).build()
            transaction_envelope.sign(source_account_kp)

            try:
                settings.HORIZON_SERVER.submit_transaction(
                    transaction_envelope)
            except BaseHorizonError as e:  # pragma: no cover
                raise RuntimeError(
                    "Horizon error when submitting create account "
                    f"to horizon: {e.message}")

            account, _ = get_account_obj(
                Keypair.from_public_key(transaction.stellar_account))
            return account, True
        except BaseHorizonError as e:
            raise RuntimeError(
                f"Horizon error when loading stellar account: {e.message}")
        except ConnectionError:
            raise RuntimeError("Failed to connect to Horizon")
 def create_deposit_envelope(transaction,
                             source_account) -> TransactionEnvelope:
     payment_amount = round(
         Decimal(transaction.amount_in) - Decimal(transaction.amount_fee),
         transaction.asset.significant_decimals,
     )
     builder = TransactionBuilder(
         source_account=source_account,
         network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE,
         # only one operation, so base_fee will be multipled by 1
         base_fee=settings.MAX_TRANSACTION_FEE_STROOPS
         or settings.HORIZON_SERVER.fetch_base_fee(),
     )
     _, json_resp = get_account_obj(
         Keypair.from_public_key(transaction.stellar_account))
     if transaction.claimable_balance_supported and is_pending_trust(
             transaction, json_resp):
         logger.debug(
             f"Crafting claimable balance operation for Transaction {transaction.id}"
         )
         claimant = Claimant(destination=transaction.stellar_account)
         asset = Asset(code=transaction.asset.code,
                       issuer=transaction.asset.issuer)
         builder.append_create_claimable_balance_op(
             claimants=[claimant],
             asset=asset,
             amount=str(payment_amount),
             source=transaction.asset.distribution_account,
         )
     else:
         builder.append_payment_op(
             destination=transaction.stellar_account,
             asset_code=transaction.asset.code,
             asset_issuer=transaction.asset.issuer,
             amount=str(payment_amount),
             source=transaction.asset.distribution_account,
         )
     if transaction.memo:
         builder.add_memo(make_memo(transaction.memo,
                                    transaction.memo_type))
     return builder.build()
def get_or_create_transaction_destination_account(
    transaction: Transaction,
) -> Tuple[Optional[Account], bool, bool]:
    """
    Returns:
        Tuple[Optional[Account]: The account(s) found or created for the Transaction
        bool: boolean, True if created, False otherwise.
        bool: boolean, True if trustline doesn't exist, False otherwise.

    If the account doesn't exist, Polaris must create the account using an account provided by the
    anchor. Polaris can use the distribution account of the anchored asset or a channel account if
    the asset's distribution account requires non-master signatures.

    If the transacted asset's distribution account does not require non-master signatures, Polaris
    can create the destination account using the distribution account.

    If the transacted asset's distribution account does require non-master signatures, the anchor
    should save a keypair of a pre-existing Stellar account to use as the channel account via
    DepositIntegration.create_channel_account(). See the function docstring for more info.

    On failure to create the destination account, a RuntimeError exception is raised.
    """
    try:
        account, json_resp = get_account_obj(
            Keypair.from_public_key(transaction.stellar_account)
        )
        return account, False, is_pending_trust(transaction, json_resp)
    except RuntimeError:
        master_signer = None
        if transaction.asset.distribution_account_master_signer:
            master_signer = transaction.asset.distribution_account_master_signer
        thresholds = transaction.asset.distribution_account_thresholds
        if master_signer and master_signer["weight"] >= thresholds["med_threshold"]:
            source_account_kp = Keypair.from_secret(transaction.asset.distribution_seed)
            source_account, _ = get_account_obj(source_account_kp)
        else:
            from polaris.integrations import registered_deposit_integration as rdi

            rdi.create_channel_account(transaction)
            source_account_kp = Keypair.from_secret(transaction.channel_seed)
            source_account, _ = get_account_obj(source_account_kp)

        builder = TransactionBuilder(
            source_account=source_account,
            network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE,
            # this transaction contains one operation so base_fee will be multiplied by 1
            base_fee=settings.MAX_TRANSACTION_FEE_STROOPS
            or settings.HORIZON_SERVER.fetch_base_fee(),
        )
        transaction_envelope = builder.append_create_account_op(
            destination=transaction.stellar_account,
            starting_balance=settings.ACCOUNT_STARTING_BALANCE,
        ).build()
        transaction_envelope.sign(source_account_kp)

        try:
            settings.HORIZON_SERVER.submit_transaction(transaction_envelope)
        except BaseHorizonError as submit_exc:  # pragma: no cover
            raise RuntimeError(
                "Horizon error when submitting create account to horizon: "
                f"{submit_exc.message}"
            )

        transaction.status = Transaction.STATUS.pending_trust
        transaction.save()
        logger.info(
            f"Transaction {transaction.id} is now pending_trust of destination account"
        )
        account, _ = get_account_obj(
            Keypair.from_public_key(transaction.stellar_account)
        )
        return account, True, True
    except BaseHorizonError as e:
        raise RuntimeError(f"Horizon error when loading stellar account: {e.message}")