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}")