From 23789234a9d268928aa946f420447e7abf9e863f Mon Sep 17 00:00:00 2001 From: Hendrik Schicke Date: Fri, 15 Oct 2021 12:34:23 +0800 Subject: [PATCH] v1.1.0 --- B_Config.py.sample | 59 +- C_Main.py | 1253 ++++++++++++++++++++++++----------- assets/Contact_addresses.py | 22 +- assets/Logging.py | 1 + assets/Notifications.py | 7 +- assets/Other.py | 48 +- assets/Queries.py | 489 +++++++------- assets/Terra.py | 123 ++-- assets/Transactions.py | 543 +++++++++++---- readme.md | 87 +-- 10 files changed, 1726 insertions(+), 906 deletions(-) diff --git a/B_Config.py.sample b/B_Config.py.sample index cee367c..bc8aa3a 100644 --- a/B_Config.py.sample +++ b/B_Config.py.sample @@ -7,27 +7,41 @@ NETWORK = 'TESTNET' # TESTNET or MAINNET mnemonic = os.environ.get('MNEMONIC', '') # Read me: When to claim, sell, unstake? - What is the right min_total_value? -# Check the Excel file attached in this repository +# Check this link: https://docs.google.com/spreadsheets/d/1U9jd5rarvWwbeuGLzkuG7Hyx4B71Pkdrmoj894SGr3M +# Don't know which mAsset to pick, check this link: https://docs.google.com/spreadsheets/d/19WyuPtGz1SGJsCKZGskD7JAGAT9THUFy9b2GtbMR7JI -# Anchor Earn roundtrip break-even for 1 day is about 9000 UST. - -# CLAIM & SELL MIR, SPEC. ANC REWARDS +# MIN PRICES AND VALUES FOR FUTHER FUNCTIONS TO WORK WITH # Important: min_price AND min_total_value must both be fulfilled for your token to be sold. -MIR_claim_and_sell_token = False -MIR_min_price = 4 # Min price acceptable to sell in UST -MIR_min_total_value = 193 # Min amount (qty * price in UST) to sell MIR tokens. -SPEC_claim_and_sell_token = False -SPEC_min_price = 9 -SPEC_min_total_value = 224 +MIR_min_price = 3 # Minimum price acceptable to sell in UST https://coinhall.org/charts/terra/terra1amv303y8kzxuegvurh0gug2xe9wkgj65enq2ux +MIR_min_total_value = 96 # Minimum amount (qty * price in UST) to claim and sell/deposit MIR tokens. + +SPEC_min_price = 7 # https://coinhall.org/charts/terra/terra1tn8ejzw8kpuc87nu42f6qeyen4c7qy35tl8t20 +SPEC_min_total_value = 138 +ANC_min_price = 4 # https://coinhall.org/charts/terra/terra1gm5p3ner9x9xpwugn9sp6gvhd0lwrtkyrecdn3 +ANC_min_total_value = 111 + +# WITHDRAWAL MIR, SPEC, ANC, UST FROM LIQUIDITY POOLS AND THEN SELL +MIR_withdraw_and_sell_if_min_price_is_reached = False +SPEC_withdraw_and_sell_if_min_price_is_reached = False +ANC_withdraw_and_sell_if_min_price_is_reached = False + +# CLAIM MIR, SPEC, ANC REWARDS AND SELL THEM IMMEDIATELY +MIR_claim_and_sell_token = False +SPEC_claim_and_sell_token = False ANC_claim_and_sell_token = False -ANC_min_price = 4 -ANC_min_total_value = 278 + +# DEPOSIT MIR, SPEC, ANC REWARDS INTO LIQUIDITY POOLS +# min_price as well as min_total_value from the previous section will be both considered. +MIR_claim_and_deposit_in_LP = False +SPEC_claim_and_deposit_in_LP = False +ANC_claim_and_deposit_in_LP = False +Anchor_enable_withdraw_from_Anchor_Earn_to_deposit_in_LP = False # MIRROR: CLAIMING UNLOCKED UST Mirror_claim_unlocked_UST = False -Mirror_min_amount_UST_to_claim = 193 +Mirror_min_amount_UST_to_claim = 96 # ANCHOR BORROW: MAINTAIN LTV RATIO / REPAY BORROWED UST IF REQUIRED # READ the example carefully, as Anchor works opposite for Mirror's liquidation ratio's logic. @@ -50,8 +64,9 @@ Anchor_min_borrow_limit = 295 # Set a minimum limit; otherwise the script may bo Anchor_borrow_cooldown = 1 # Cooldown in days after collateral has been withdrawn. Example: 3 means it happens only once every 3 days. # ANCHOR EARN: DEPOSIT UST FROM SELLING ANC, MIR, SPEC -Anchor_enable_deposit_borrowed_UST = False -Anchor_min_deposit_amount = 148 +Anchor_Earn_enable_deposit_UST = False +Anchor_Earn_min_deposit_amount = 148 +Anchor_Earn_min_balance_to_keep_in_wallet = 150 # This this bot also deposits token in LP, you should have a UST balance in your wallet. # MIRROR: MAINTAIN COLLATERAL RATIO / DEPOSIT COLLATERAL IF REQUIRED # Example: Let's say the minimum ratio for the given mAsset on Mirror is 150% or 1.5. @@ -78,13 +93,12 @@ Send_me_a_report = True # Logs summary of what has happened, if something has ha Notify_Slack = False Notify_Telegram = False Notify_Gmail = False -Send_me_a_status_update = False # Even if nothing is done by the script, you can receive a status update with your key infos your Anchor / Positions. +Send_me_a_status_update = True # Even if nothing is done by the script, you can receive a status update with your key infos your Anchor / Positions. Status_update_frequency = 24 # In hours. 24 means once per 24h. Status_update_time = '14:00' # Time to send you the status_update based on server time -# OTHER +# SCHEDULER Run_interval_for_Scheduler = 5 # in minutes. 5 means every 5 minutes -Safety_multiple_on_transaction_fees = 1 # Multiplier for Anchor Borrow, Repay, Deposit. So you will have a bit of UST in your wallet left for future transactions. # DEBUGGING Debug_mode = True # If False, default.log will include almost everything. If False only WARNINGs and ERRORs will be logged. @@ -94,6 +108,9 @@ Return_failed_tx = False # If Disable_all_transaction_def is False, you can retu # LOGGING Logging_detail = 'simple' # detailed, moderate, simple. Recommended: simple. +# OTHER +Safety_multiple_on_transaction_fees = 3 # Multiplier for Anchor Borrow, Repay, Deposit. So you will have a bit of UST in your wallet left for future transactions. + # NOTIFICATION SETUP TELEGRAM_TOKEN = os.environ.get('TELEGRAM_TOKEN', 'Your Bot Token here') # See readme.md how to get this. TELEGRAM_CHAT_ID = os.environ.get('TELEGRAM_CHAT_ID', 'Your Chat ID here') # See readme.md how to get this. @@ -103,8 +120,4 @@ GMAIL_APP_PASSWORD = 'Your app password here' # See readme.md how to get this. GMAIL_ACCOUNT = 'Your full Gmail address here' # Your Gmail address you use for logging into your account. EMAIL_SUBJECT = 'Terra One-Stop-Bot' EMAIL_FROM = GMAIL_ACCOUNT # Normally the same as your main Gmail address. -EMAIL_TO = GMAIL_ACCOUNT # Normally the same as your main Gmail address. - - - - +EMAIL_TO = GMAIL_ACCOUNT # Normally the same as your main Gmail address. \ No newline at end of file diff --git a/C_Main.py b/C_Main.py index 2dd1349..ee1b2be 100644 --- a/C_Main.py +++ b/C_Main.py @@ -13,18 +13,24 @@ # https://terra-money.github.io/terra-sdk-python/ # https://docs.anchorprotocol.com/ # https://api.extraterrestrial.money/v1/api/prices +# https://assets.terra.money/cw20/tokens.json +# https://assets.terra.money/cw20/contracts.json + +# Terra SDK +from terra_sdk.core.numeric import Dec +from terra_sdk.client.lcd import wallet # Other assets from assets.Notifications import Notifications from assets.Queries import Queries +from assets.Terra import Terra from assets.Transactions import Transaction -from assets.Other import Cooldown +from assets.Other import Cooldown, Prettify from assets.Logging import Logger import B_Config as config # Other imports from datetime import datetime, timedelta -from decimal import Decimal import time #------------------------------ @@ -35,6 +41,8 @@ Queries_class = Queries() Cooldown_class = Cooldown() Logger_class = Logger() +Terra_class = Terra +Prettify_class = Prettify() default_logger = Logger_class.default_logger report_logger = Logger_class.report_logger @@ -44,233 +52,702 @@ #------------------------------- #---------- MAIN DEF ----------- #------------------------------- -def keep_safe(): +def keep_safe(): + if config.Debug_mode: print(f'keep_safe() started.') + begin_time = time.time() + wallet_balance = Queries_class.get_wallet_balances() + general_estimated_tx_fee = Dec(Queries_class.get_fee_estimation()) + + if wallet_balance['UST'] < general_estimated_tx_fee: + default_logger.warning(f'[Script] YOU NEED TO ACT! Your wallet balance of {(wallet_balance["UST"].__float__() / 1000000):.2f} UST is too low to execute any transaction.') + return False datetime_now = datetime.now() - aUST_rate = Queries_class.get_aUST_rate() - general_estimated_tx_fee = Decimal(Queries_class.get_fee_estimation()) / 1000000 - begin_time = time.time() - try: - Mirror_position_info = Queries_class.Mirror_get_position_info() - Anchor_borrow_info = Queries_class.Anchor_get_borrow_info() - cooldowns = Cooldown_class.read_cooldown() - current_UST_wallet_balance = Queries_class.get_native_balance('uusd') # is return in humen decimals - UST_balance_to_be_deposited_at_Anchor_Earn = 0 - status_update = False - - if current_UST_wallet_balance < general_estimated_tx_fee: - default_logger.warning(f'[Script] YOU NEED TO ACT! Your wallet balance of {current_UST_wallet_balance:.0f} UST is too low to execute any transaction.') + cooldowns = Cooldown_class.read_cooldown() + status_update = False + + Mirror_position_info = Queries_class.Mirror_get_position_info() + Anchor_borrow_info = Queries_class.Anchor_get_borrow_info() + wallet_balance = Queries_class.get_wallet_balances() + all_rates = Queries_class.get_all_rates() + + action_dict = { + 'MIR' : 'none', + 'SPEC' : 'none', + 'ANC' : 'none', + } + + wallet_balance_before = Queries_class.get_wallet_balances() + default_logger.debug(f'Wallet_balance_before: {Prettify_class.dict_value_convert_dec_to_float(wallet_balance_before, False)}') + + # default_logger.debug(f'------------------------------------------\n' + # f'-------- WITHDRAW FROM LP SECTION --------\n' + # f'------------------------------------------\n') + + # Check if the this section for the token is enabled + if config.MIR_claim_and_deposit_in_LP: + # Check if there is enough UST balance in the wallet to pay the transaction fees + if wallet_balance['UST'] > general_estimated_tx_fee: + # Check if the min_price for the token has been matched + if (all_rates['MIR']/1000000) > config.MIR_min_price: + # Check if there are any LP for that token available + available_MIR_LP_token_for_withdrawal = Queries_class.get_available_LP_token_for_withdrawal(Terra_class.mirrorFarm, Terra_class.MIR_token) + if available_MIR_LP_token_for_withdrawal > 0: + # Check if the min_withdrawal_limit is exceeded + value_of_MIR_LP_token = Queries_class.get_UST_amount_for_LP_deposit(available_MIR_LP_token_for_withdrawal, Terra_class.Mirror_MIR_UST_Pair) + if (value_of_MIR_LP_token/1000000) > config.MIR_min_total_value: + # Unstake / withdrawn LP + withdraw_MIR_from_pool_tx = Transaction_class.withdraw_MIR_from_pool(available_MIR_LP_token_for_withdrawal) + withdraw_MIR_from_pool_tx_status = Queries_class.get_status_of_tx(withdraw_MIR_from_pool_tx) + if withdraw_MIR_from_pool_tx_status == True: + default_logger.debug(f'[MIR LP Withdrawal] Success TX: {withdraw_MIR_from_pool_tx}') + report_logger.info(f'[MIR LP Withdrawal] MIR & UST have been withdrawn from the LP.') + # Mark for sell + action_dict['MIR'] = 'sell' + # Update UST balance in wallet + wallet_balance['UST'] = Dec(Queries_class.get_native_balance('uusd')) + else: + default_logger.warning(f'[MIR LP Withdrawal] Failed TX: {withdraw_MIR_from_pool_tx}.\n' + f'[MIR LP Withdrawal] Reason: {withdraw_MIR_from_pool_tx_status}') + else: + default_logger.debug(f'[MIR LP Withdrawal] Skipped because withdrawable LP token value ({(value_of_MIR_LP_token.__float__()/1000000):.2f}) below limit ({config.MIR_min_total_value}).') + else: + default_logger.debug(f'[MIR LP Withdrawal] Skipped because no withdrawable LP token ({(available_MIR_LP_token_for_withdrawal.__float__()/1000000):.0f}).') + else: + default_logger.debug(f'[MIR LP Withdrawal] Skipped because minimum price of MIR ({config.MIR_min_price}) not exceeded ({(all_rates["MIR"].__float__()/1000000):.2f}).') + else: + default_logger.warning(f'[MIR LP Withdrawal] Skipped because insufficent funds ({(wallet_balance["UST"].__float__() / 1000000):.2f}).') + return False + else: + default_logger.debug(f'[MIR LP Withdrawal] Skipped because disabled by config ({config.MIR_claim_and_deposit_in_LP}).') + + # Check if the this section for the token is enabled + if config.SPEC_claim_and_deposit_in_LP: + # Check if there is enough UST balance in the wallet to pay the transaction fees + if wallet_balance['UST'] > general_estimated_tx_fee: + # Check if the min_price for the token has been matched + if (all_rates['SPEC']/1000000) > config.SPEC_min_price: + # Check if there are any LP for that token available + available_SPEC_LP_token_for_withdrawal = Queries_class.get_available_LP_token_for_withdrawal(Terra_class.specFarm, Terra_class.SPEC_token) + if available_SPEC_LP_token_for_withdrawal > 0: + # Check if the min_withdrawal_limit is exceeded + value_of_SPEC_LP_token = Queries_class.get_UST_amount_for_LP_deposit(available_SPEC_LP_token_for_withdrawal, Terra_class.Spectrum_SPEC_UST_Pair) + if (value_of_SPEC_LP_token/1000000) > config.SPEC_min_total_value: + # Unstake / withdrawn LP + withdraw_SPEC_from_pool_tx = Transaction_class.withdraw_SPEC_from_pool(available_SPEC_LP_token_for_withdrawal) + withdraw_SPEC_from_pool_tx_status = Queries_class.get_status_of_tx(withdraw_SPEC_from_pool_tx) + if withdraw_SPEC_from_pool_tx_status == True: + default_logger.debug(f'[SPEC LP Withdrawal] Success TX: {withdraw_SPEC_from_pool_tx}') + report_logger.info(f'[SPEC LP Withdrawal] SPEC & UST have been withdrawn from the LP.') + # Mark for sell + action_dict['SPEC'] = 'sell' + # Update UST balance in wallet + wallet_balance['UST'] = Dec(Queries_class.get_native_balance('uusd')) + else: + default_logger.warning(f'[SPEC LP Withdrawal] Failed TX: {withdraw_SPEC_from_pool_tx}.\n' + f'[SPEC LP Withdrawal] Reason: {withdraw_SPEC_from_pool_tx_status}') + else: + default_logger.debug(f'[SPEC LP Withdrawal] Skipped because withdrawable LP token value ({(value_of_SPEC_LP_token.__float__()/1000000):.2f}) below limit ({config.SPEC_min_total_value}).') + else: + default_logger.debug(f'[SPEC LP Withdrawal] Skipped because no withdrawable LP token ({(available_SPEC_LP_token_for_withdrawal.__float__()/1000000):.0f}).') + else: + default_logger.debug(f'[SPEC LP Withdrawal] Skipped because minimum price of SPEC ({config.SPEC_min_price}) not exceeded ({(all_rates["SPEC"].__float__()/1000000):.2f}).') + else: + default_logger.warning(f'[SPEC LP Withdrawal] Skipped because insufficent funds ({(wallet_balance["UST"].__float__() / 1000000):.2f}).') return False + else: + default_logger.debug(f'[SPEC LP Withdrawal] Skipped because disabled by config ({config.SPEC_claim_and_deposit_in_LP}).') - # default_logger.debug(f'------------------------------------------\n' - # f'---------- CLAIM & SELL SECTION ----------\n' - # f'------------------------------------------\n') - # Mirror: Claim & sell MIR + # Check if the this section for the token is enabled + if config.ANC_claim_and_deposit_in_LP: + # Check if there is enough UST balance in the wallet to pay the transaction fees + if wallet_balance['UST'] > general_estimated_tx_fee: + # Check if the min_price for the token has been matched + if (all_rates['ANC']/1000000) > config.ANC_min_price: + # Check if there are any LP for that token available + available_ANC_LP_token_for_withdrawal = Queries_class.get_available_LP_token_for_withdrawal(Terra_class.anchorFarm, Terra_class.ANC_token) + if available_ANC_LP_token_for_withdrawal > 0: + # Check if the min_withdrawal_limit is exceeded + value_of_ANC_LP_token = Queries_class.get_UST_amount_for_LP_deposit(available_ANC_LP_token_for_withdrawal, Terra_class.Terraswap_ANC_UST_Pair) + if (value_of_ANC_LP_token/1000000) > config.ANC_min_total_value: + # Unstake / withdrawn LP + withdraw_ANC_from_pool_tx = Transaction_class.withdraw_ANC_from_pool(available_ANC_LP_token_for_withdrawal) + withdraw_ANC_from_pool_tx_status = Queries_class.get_status_of_tx(withdraw_ANC_from_pool_tx) + if withdraw_ANC_from_pool_tx_status == True: + default_logger.debug(f'[ANC LP Withdrawal] Success TX: {withdraw_ANC_from_pool_tx}') + report_logger.info(f'[ANC LP Withdrawal] ANC & UST have been withdrawn from the LP.') + # Mark for sell + action_dict['ANC'] = 'sell' + # Update UST balance in wallet + wallet_balance['UST'] = Dec(Queries_class.get_native_balance('uusd')) + else: + default_logger.warning(f'[ANC LP Withdrawal] Failed TX: {withdraw_ANC_from_pool_tx}.\n' + f'[ANC LP Withdrawal] Reason: {withdraw_ANC_from_pool_tx_status}') + else: + default_logger.debug(f'[ANC LP Withdrawal] Skipped because withdrawable LP token value ({(value_of_ANC_LP_token.__float__()/1000000):.2f}) below limit ({config.ANC_min_total_value}).') + else: + default_logger.debug(f'[ANC LP Withdrawal] Skipped because no withdrawable LP token ({(available_ANC_LP_token_for_withdrawal.__float__()/1000000):.0f}).') + else: + default_logger.debug(f'[ANC LP Withdrawal] Skipped because minimum price of ANC ({config.ANC_min_price}) not exceeded ({(all_rates["ANC"].__float__()/1000000):.2f}).') + else: + default_logger.warning(f'[ANC LP Withdrawal] Skipped because insufficent funds ({(wallet_balance["UST"].__float__() / 1000000):.2f}).') + return False + else: + default_logger.debug(f'[ANC LP Withdrawal] Skipped because disabled by config ({config.ANC_claim_and_deposit_in_LP}).') + + + # default_logger.debug(f'------------------------------------------\n' + # f'------------- CLAIM SECTION --------------\n' + # f'------------------------------------------\n') - if config.MIR_claim_and_sell_token \ - and current_UST_wallet_balance > general_estimated_tx_fee: + # Mirror: Claim MIR + # Check if this section is enabled + if config.MIR_claim_and_sell_token or config.MIR_claim_and_deposit_in_LP: + # Check if there is enough UST balance in the wallet to pay the transaction fees + if wallet_balance['UST'] > general_estimated_tx_fee: claimable_MIR = Queries_class.get_claimable_MIR() + # Check if there is any token claimable if claimable_MIR > 0: - value_of_MIR_claim = Queries_class.simulate_MIR_Swap(claimable_MIR) - # ! Balance will not be checked again, if enough UST are available for tx fees - if value_of_MIR_claim >= config.MIR_min_total_value \ - and (value_of_MIR_claim/claimable_MIR) >= config.MIR_min_price: - claim_MIR_tx = Transaction_class.claim_MIR() - claim_MIR_tx_status = Queries_class.get_status_of_tx(claim_MIR_tx) - - if claim_MIR_tx_status == True: - default_logger.debug(f'[MIR Claim] Success TX: {claim_MIR_tx}') - sell_MIR_tx = Transaction_class.sell_MIR(claimable_MIR) - sell_MIR_tx_status = Queries_class.get_status_of_tx(sell_MIR_tx) - if sell_MIR_tx_status == True: - default_logger.debug(f'[MIR Sell] Success TX: {sell_MIR_tx}') - report_logger.info( - f'[MIR Claim & Sell] {claimable_MIR:.2f} MIR have been claimed and sold for {value_of_MIR_claim:.2f} UST total.') - UST_balance_to_be_deposited_at_Anchor_Earn += value_of_MIR_claim - default_logger.debug( - f'[MIR Claim & Sell] UST balance to be despoited at Anchor Earn: {UST_balance_to_be_deposited_at_Anchor_Earn:.0f} UST.') + value_of_MIR_claim = Queries_class.simulate_Token_Swap(claimable_MIR, Terra_class.Mirror_MIR_UST_Pair, Terra_class.MIR_token) + # Check if the amount claimable is bigger than the min_amount + if (value_of_MIR_claim/1000000) >= config.MIR_min_total_value: + # Check if the min_price for a sale has been matched + if config.MIR_claim_and_sell_token and (all_rates['MIR']/1000000) >= config.MIR_min_price: + # Claim MIR + claim_MIR_tx = Transaction_class.claim_MIR() + claim_MIR_tx_status = Queries_class.get_status_of_tx(claim_MIR_tx) + if claim_MIR_tx_status == True: + default_logger.debug(f'[MIR Claim] Success TX: {claim_MIR_tx}') + report_logger.info(f'[MIR Claim] {(claimable_MIR.__float__()/1000000):.2f} MIR have been claimed to be sold.') + # Mark for sale + action_dict['MIR'] = 'sell' + # Update UST balance in wallet + wallet_balance['UST'] = Dec(Queries_class.get_native_balance('uusd')) else: - default_logger.warning(f'[MIR Sell] Failed TX: {sell_MIR_tx}.\n' - f'[MIR Sell] Reason: {sell_MIR_tx_status}') + default_logger.warning(f'[MIR Claim] Failed TX: {claim_MIR_tx}.\n' + f'[MIR Claim] Reason: {claim_MIR_tx_status}') + # Check if deposit is enabled + elif config.MIR_claim_and_deposit_in_LP: + # Check if enough UST is available to actually deposit it later + UST_to_be_deposited_with_MIR = Queries_class.get_UST_amount_for_LP_deposit(claimable_MIR, Terra_class.Mirror_MIR_UST_Pair) + if wallet_balance['UST'] > UST_to_be_deposited_with_MIR: + # Claim and mark for deposit + claim_MIR_tx = Transaction_class.claim_MIR() + claim_MIR_tx_status = Queries_class.get_status_of_tx(claim_MIR_tx) + if claim_MIR_tx_status == True: + default_logger.debug(f'[MIR Claim] Success TX: {claim_MIR_tx}') + # Mark for deposit + action_dict['MIR'] = 'deposit' + report_logger.info(f'[MIR Claim] {(claimable_MIR.__float__()/1000000):.2f} MIR have been claimed to be deposited.') + # Update UST balance in wallet + wallet_balance['UST'] = Dec(Queries_class.get_native_balance('uusd')) + else: + default_logger.warning(f'[MIR Claim] Failed TX: {claim_MIR_tx}.\n' + f'[MIR Claim] Reason: {claim_MIR_tx_status}') + # Not enough UST in the wallet to deposit later. Check if allowed to take from Anchor Earn. + elif config.Anchor_enable_withdraw_from_Anchor_Earn_to_deposit_in_LP: + # Check if enough in Anchor Earn to withdraw + if (wallet_balance['aUST'] * all_rates['aUST'] + wallet_balance['UST']) > UST_to_be_deposited_with_MIR: + # Withdraw from Anchor Earn + claim_Anchor_withdraw_UST_from_Earn_tx = Transaction_class.Anchor_withdraw_UST_from_Earn(UST_to_be_deposited_with_MIR - wallet_balance['UST'], 'UST') + claim_Anchor_withdraw_UST_from_Earn_tx_status = Queries_class.get_status_of_tx(claim_Anchor_withdraw_UST_from_Earn_tx) + if claim_Anchor_withdraw_UST_from_Earn_tx_status: + # ! This can result in a withdraw from Anchor Earn three times (MIR, SPEC, ANC) if you balance is not enough. There is no cumulated withdraw. + report_logger.info(f'[MIR Claim] No enought UST balance to depoit later with MIR, so {(UST_to_be_deposited_with_MIR.__float__() - wallet_balance["UST"].__float__()/1000000):.2f} UST have been withdrawn to be deposited later with.') + # Claim and mark for deposit + claim_MIR_tx = Transaction_class.claim_MIR() + claim_MIR_tx_status = Queries_class.get_status_of_tx(claim_MIR_tx) + if claim_MIR_tx_status == True: + default_logger.debug(f'[MIR Claim] Success TX: {claim_MIR_tx}') + # Mark for deposit + action_dict['MIR'] = 'deposit' + report_logger.info(f'[MIR Claim] {(claimable_MIR.__float__()/1000000):.2f} MIR have been claimed to be deposited.') + # Update UST balance in wallet + wallet_balance['UST'] = Dec(Queries_class.get_native_balance('uusd')) + else: + default_logger.warning(f'[MIR Claim] Failed TX: {claim_MIR_tx}.\n' + f'[MIR Claim] Reason: {claim_MIR_tx_status}') + else: + default_logger.warning(f'[MIR Claim] Failed TX: {claim_Anchor_withdraw_UST_from_Earn_tx}.\n' + f'[MIR Claim] Reason: {claim_Anchor_withdraw_UST_from_Earn_tx_status}') + else: + default_logger.warning(f'[MIR Claim] Skipped because not enough UST/aUST ({(wallet_balance["UST"].__float__() / 1000000):.2f})/({(wallet_balance["aUST"].__float__() / 1000000):.2f} in wallet to be deposited with MIR later.') + else: + default_logger.warning(f'[MIR Claim] Skipped because not enough UST ({(wallet_balance["UST"].__float__() / 1000000):.2f}) in wallet to be deposited with MIR later and not enabled to withdraw from Anchor Earn ({config.Anchor_enable_withdraw_from_Anchor_Earn_to_deposit_in_LP}).') else: - default_logger.warning(f'[MIR Claim] Failed TX: {claim_MIR_tx}.\n' - f'[MIR Claim] Reason: {claim_MIR_tx_status}') + default_logger.debug(f'[MIR Claim] Minimum price ({config.MIR_min_price}) not exceeded for sale ({(all_rates["MIR"].__float__()/1000000):.2f}) and a deposit is not enabled ({config.MIR_claim_and_deposit_in_LP}).') else: - default_logger.debug( - f'[MIR Claim & Sell] Skipped because claimable MIR value ({value_of_MIR_claim:.2f}) below limit ({config.MIR_min_total_value:.0f}) or current MIR price ({Queries_class.get_MIR_rate():.2f}) below limit ({config.MIR_min_price:.2f}).') + default_logger.debug(f'[MIR Claim] Skipped because claimable MIR value ({(value_of_MIR_claim.__float__()/1000000):.2f}) below limit ({config.MIR_min_total_value}).') else: - default_logger.debug(f'[MIR Claim & Sell] Skipped because no claimable MIR ({claimable_MIR:.0f}).') + default_logger.debug(f'[MIR Claim] Skipped because no claimable MIR ({(claimable_MIR.__float__()/1000000):.0f}).') else: - default_logger.debug( - f'[MIR Claim & Sell] Skipped because disabled by config ({config.MIR_claim_and_sell_token}) or insufficent funds ({(current_UST_wallet_balance - general_estimated_tx_fee):.2f}).') + default_logger.warning(f'[MIR Claim] Skipped because insufficent funds ({(wallet_balance["UST"].__float__() / 1000000):.2f}).') + return False + else: + default_logger.debug(f'[MIR Claim] Skipped because disabled by config ({config.MIR_claim_and_sell_token}).') + - # Spectrum: Claim & sell SPEC - if config.SPEC_claim_and_sell_token \ - and current_UST_wallet_balance > general_estimated_tx_fee: + # Spectrum: Claim SPEC + # Check if this section is enabled + if config.SPEC_claim_and_sell_token or config.SPEC_claim_and_deposit_in_LP: + # Check if there is enough UST balance in the wallet to pay the transaction fees + if wallet_balance['UST'] > general_estimated_tx_fee: claimable_SPEC_list = Queries_class.get_claimable_SPEC() claimable_SPEC = claimable_SPEC_list[0] + # Check if there is any token claimable if claimable_SPEC > 0: - value_of_SPEC_claim = Queries_class.simulate_SPEC_Swap(claimable_SPEC) - # ! Balance will not be checked again, if enough UST are available for tx fees - if value_of_SPEC_claim >= config.SPEC_min_total_value \ - and (value_of_SPEC_claim/claimable_SPEC) >= config.SPEC_min_price: - claim_SPEC_tx = Transaction_class.claim_SPEC(claimable_SPEC_list) - claim_SPEC_tx_status = Queries_class.get_status_of_tx(claim_SPEC_tx) - - if claim_SPEC_tx_status == True: - default_logger.debug(f'[SPEC Claim] Success TX: {claim_SPEC_tx}') - sell_SPEC_tx = Transaction_class.sell_SPEC(claimable_SPEC) - sell_SPEC_tx_status = Queries_class.get_status_of_tx(sell_SPEC_tx) - if sell_SPEC_tx_status == True: - default_logger.debug(f'[SPEC Sell] Success TX: {sell_SPEC_tx}') - report_logger.info( - f'[SPEC Claim & Sell] {claimable_SPEC:.2f} SPEC have been claimed and sold for {value_of_SPEC_claim:.2f} UST total.') - UST_balance_to_be_deposited_at_Anchor_Earn += value_of_SPEC_claim - default_logger.debug( - f'[SPEC Claim & Sell] UST balance to be despoited at Anchor Earn: {UST_balance_to_be_deposited_at_Anchor_Earn:.0f} UST.') + value_of_SPEC_claim = Queries_class.simulate_Token_Swap(claimable_SPEC, Terra_class.Spectrum_SPEC_UST_Pair, Terra_class.SPEC_token) + # Check if the amount claimable is bigger than the min_amount + if (value_of_SPEC_claim/1000000) >= config.SPEC_min_total_value: + # Check if the min_price for a sale has been matched + if config.SPEC_claim_and_sell_token and (all_rates['SPEC']/1000000) >= config.SPEC_min_price: + # Claim SPEC + claim_SPEC_tx = Transaction_class.claim_SPEC(claimable_SPEC_list) + claim_SPEC_tx_status = Queries_class.get_status_of_tx(claim_SPEC_tx) + if claim_SPEC_tx_status == True: + default_logger.debug(f'[SPEC Claim] Success TX: {claim_SPEC_tx}') + report_logger.info(f'[SPEC Claim] {(claimable_SPEC.__float__()/1000000):.2f} SPEC have been claimed to be sold.') + # Mark for sale + action_dict['SPEC'] = 'sell' + # Update UST balance in wallet + wallet_balance['UST'] = Dec(Queries_class.get_native_balance('uusd')) else: - default_logger.warning(f'[SPEC Sell] Failed TX: {sell_SPEC_tx}.\n' - f'[SPEC Sell] Reason: {sell_SPEC_tx_status}') + default_logger.warning(f'[SPEC Claim] Failed TX: {claim_SPEC_tx}.\n' + f'[SPEC Claim] Reason: {claim_SPEC_tx_status}') + # Check if deposit is enabled + elif config.SPEC_claim_and_deposit_in_LP: + # Check if enough UST is available to actually deposit it later + UST_to_be_deposited_with_SPEC = Queries_class.get_UST_amount_for_LP_deposit(claimable_SPEC, Terra_class.Spectrum_SPEC_UST_Pair) + if wallet_balance['UST'] > UST_to_be_deposited_with_SPEC: + # Claim and mark for deposit + claim_SPEC_tx = Transaction_class.claim_SPEC(claimable_SPEC_list) + claim_SPEC_tx_status = Queries_class.get_status_of_tx(claim_SPEC_tx) + if claim_SPEC_tx_status == True: + default_logger.debug(f'[SPEC Claim] Success TX: {claim_SPEC_tx}') + # Mark for deposit + action_dict['SPEC'] = 'deposit' + report_logger.info(f'[SPEC Claim] {(claimable_SPEC.__float__()/1000000):.2f} SPEC have been claimed to be deposited.') + # Update UST balance in wallet + wallet_balance['UST'] = Dec(Queries_class.get_native_balance('uusd')) + else: + default_logger.warning(f'[SPEC Claim] Failed TX: {claim_SPEC_tx}.\n' + f'[SPEC Claim] Reason: {claim_SPEC_tx_status}') + # Not enough UST in the wallet to deposit later. Check if allowed to take from Anchor Earn. + elif config.Anchor_enable_withdraw_from_Anchor_Earn_to_deposit_in_LP: + # Check if enough in Anchor Earn to withdraw + if (wallet_balance['aUST'] * all_rates['aUST'] + wallet_balance['UST'])> UST_to_be_deposited_with_SPEC: + # Withdraw from Anchor Earn + claim_Anchor_withdraw_UST_from_Earn_tx = Transaction_class.Anchor_withdraw_UST_from_Earn(UST_to_be_deposited_with_SPEC - wallet_balance['UST'], 'UST') + claim_Anchor_withdraw_UST_from_Earn_tx_status = Queries_class.get_status_of_tx(claim_Anchor_withdraw_UST_from_Earn_tx) + if claim_Anchor_withdraw_UST_from_Earn_tx_status: + # ! This can result in a withdraw from Anchor Earn three times (MIR, SPEC, ANC) if you balance is not enough. There is no cumulated withdraw. + report_logger.info(f'[SPEC Claim] No enought UST balance to depoit later with SPEC, so {(UST_to_be_deposited_with_SPEC.__float__() - wallet_balance["UST"].__float__()/1000000):.2f} UST have been withdrawn to be deposited later with.') + # Claim and mark for deposit + claim_SPEC_tx = Transaction_class.claim_SPEC(claimable_SPEC_list) + claim_SPEC_tx_status = Queries_class.get_status_of_tx(claim_SPEC_tx) + if claim_SPEC_tx_status == True: + default_logger.debug(f'[SPEC Claim] Success TX: {claim_SPEC_tx}') + # Mark for deposit + action_dict['SPEC'] = 'deposit' + report_logger.info(f'[SPEC Claim] {(claimable_SPEC.__float__()/1000000):.2f} SPEC have been claimed to be deposited.') + # Update UST balance in wallet + wallet_balance['UST'] = Dec(Queries_class.get_native_balance('uusd')) + else: + default_logger.warning(f'[SPEC Claim] Failed TX: {claim_SPEC_tx}.\n' + f'[SPEC Claim] Reason: {claim_SPEC_tx_status}') + else: + default_logger.warning(f'[SPEC Claim] Failed TX: {claim_Anchor_withdraw_UST_from_Earn_tx}.\n' + f'[SPEC Claim] Reason: {claim_Anchor_withdraw_UST_from_Earn_tx_status}') + else: + default_logger.warning(f'[SPEC Claim] Skipped because not enough UST/aUST ({(wallet_balance["UST"].__float__() / 1000000):.2f})/({(wallet_balance["aUST"].__float__() / 1000000):.2f} in wallet to be deposited with SPEC later.') + else: + default_logger.warning(f'[SPEC Claim] Skipped because not enough UST ({(wallet_balance["UST"].__float__() / 1000000):.2f}) in wallet to be deposited with SPEC later and not enabled to withdraw from Anchor Earn ({config.Anchor_enable_withdraw_from_Anchor_Earn_to_deposit_in_LP}).') else: - default_logger.warning(f'[SPEC Claim] Failed TX: {claim_SPEC_tx}.\n' - f'[SPEC Claim] Reason: {claim_SPEC_tx_status}') + default_logger.debug(f'[SPEC Claim] Minimum price ({config.SPEC_min_price}) not exceeded for sale ({(all_rates["SPEC"].__float__()/1000000):.2f}) and a deposit is not enabled ({config.SPEC_claim_and_deposit_in_LP}).') else: - default_logger.debug( - f'[SPEC Claim & Sell] Skipped because claimable SPEC value ({value_of_SPEC_claim:.2f}) below limit ({config.SPEC_min_total_value:.0f}) or current SPEC price ({Queries_class.get_SPEC_rate():.2f}) below limit ({config.SPEC_min_price:.2f}).') + default_logger.debug(f'[SPEC Claim] Skipped because claimable SPEC value ({(value_of_SPEC_claim.__float__()/1000000):.2f}) below limit ({config.SPEC_min_total_value}).') else: - default_logger.debug(f'[SPEC Claim & Sell] Skipped because no claimable SPEC ({claimable_SPEC:.0f}).') + default_logger.debug(f'[SPEC Claim] Skipped because no claimable SPEC ({(claimable_SPEC.__float__()/1000000):.0f}).') else: - default_logger.debug( - f'[SPEC Claim & Sell] Skipped because disabled by config ({config.SPEC_claim_and_sell_token}) or insufficent funds ({(current_UST_wallet_balance - general_estimated_tx_fee):.2f}).') + default_logger.warning(f'[SPEC Claim] Skipped because insufficent funds ({(wallet_balance["UST"].__float__() / 1000000):.2f}).') + return False + else: + default_logger.debug(f'[SPEC Claim] Skipped because disabled by config ({config.SPEC_claim_and_sell_token}).') - # Anchor: Claim & sell ANC - if config.ANC_claim_and_sell_token \ - and current_UST_wallet_balance > general_estimated_tx_fee: + # Anchor: Claim ANC + # Check if this section is enabled + if config.ANC_claim_and_sell_token or config.ANC_claim_and_deposit_in_LP: + # Check if there is enough UST balance in the wallet to pay the transaction fees + if wallet_balance['UST'] > general_estimated_tx_fee: claimable_ANC = Queries_class.get_claimable_ANC() + # Check if there is any token claimable if claimable_ANC > 0: - value_of_ANC_claim = Queries_class.simulate_ANC_Swap(claimable_ANC) - # ! Balance will not be checked again, if enough UST are available for tx fees - if value_of_ANC_claim >= config.ANC_min_total_value \ - and (value_of_ANC_claim/claimable_ANC) >= config.ANC_min_price: - claim_ANC_tx = Transaction_class.claim_ANC() - claim_ANC_tx_status = Queries_class.get_status_of_tx(claim_ANC_tx) - - if claim_ANC_tx_status == True: - default_logger.debug(f'[ANC Claim] Success TX: {claim_ANC_tx}') - sell_ANC_tx = Transaction_class.sell_ANC(claimable_ANC) - sell_ANC_tx_status = Queries_class.get_status_of_tx(sell_ANC_tx) - if sell_ANC_tx_status == True: - default_logger.debug(f'[ANC Sell] Success TX: {sell_ANC_tx}') - report_logger.info( - f'[ANC Claim & Sell] {claimable_ANC:.2f} ANC have been claimed and sold for {value_of_ANC_claim:.2f} UST total.') - UST_balance_to_be_deposited_at_Anchor_Earn += value_of_ANC_claim - default_logger.debug( - f'[ANC Claim & Sell] UST balance to be despoited at Anchor Earn: {UST_balance_to_be_deposited_at_Anchor_Earn:.0f} UST.') + value_of_ANC_claim = Queries_class.simulate_Token_Swap(claimable_ANC, Terra_class.Terraswap_ANC_UST_Pair, Terra_class.ANC_token) + # Check if the amount claimable is bigger than the min_amount + if (value_of_ANC_claim/1000000) >= config.ANC_min_total_value: + # Check if the min_price for a sale has been matched + if config.ANC_claim_and_sell_token and (all_rates['ANC']/1000000) >= config.ANC_min_price: + # Claim ANC + claim_ANC_tx = Transaction_class.claim_ANC() + claim_ANC_tx_status = Queries_class.get_status_of_tx(claim_ANC_tx) + if claim_ANC_tx_status == True: + default_logger.debug(f'[ANC Claim] Success TX: {claim_ANC_tx}') + report_logger.info(f'[ANC Claim] {(claimable_ANC.__float__()/1000000):.2f} ANC have been claimed to be sold.') + # Mark for sale + action_dict['ANC'] = 'sell' + # Update UST balance in wallet + wallet_balance['UST'] = Dec(Queries_class.get_native_balance('uusd')) else: - default_logger.warning(f'[ANC Sell] Failed TX: {sell_ANC_tx}.\n' - f'[ANC Sell] Reason: {sell_ANC_tx_status}') + default_logger.warning(f'[ANC Claim] Failed TX: {claim_ANC_tx}.\n' + f'[ANC Claim] Reason: {claim_ANC_tx_status}') + # Check if deposit is enabled + elif config.ANC_claim_and_deposit_in_LP: + # Check if enough UST is available to actually deposit it later + UST_to_be_deposited_with_ANC = Queries_class.get_UST_amount_for_LP_deposit(claimable_ANC, Terra_class.Terraswap_ANC_UST_Pair) + if wallet_balance['UST'] > UST_to_be_deposited_with_ANC: + # Claim and mark for deposit + claim_ANC_tx = Transaction_class.claim_ANC() + claim_ANC_tx_status = Queries_class.get_status_of_tx(claim_ANC_tx) + if claim_ANC_tx_status == True: + default_logger.debug(f'[ANC Claim] Success TX: {claim_ANC_tx}') + # Mark for deposit + action_dict['ANC'] = 'deposit' + report_logger.info(f'[ANC Claim] {(claimable_ANC.__float__()/1000000):.2f} ANC have been claimed to be deposited.') + # Update UST balance in wallet + wallet_balance['UST'] = Dec(Queries_class.get_native_balance('uusd')) + else: + default_logger.warning(f'[ANC Claim] Failed TX: {claim_ANC_tx}.\n' + f'[ANC Claim] Reason: {claim_ANC_tx_status}') + # Not enough UST in the wallet to deposit later. Check if allowed to take from Anchor Earn. + elif config.Anchor_enable_withdraw_from_Anchor_Earn_to_deposit_in_LP: + # Check if enough in Anchor Earn to withdraw + if (wallet_balance['aUST'] * all_rates['aUST'] + wallet_balance['UST']) > UST_to_be_deposited_with_ANC: + # Withdraw from Anchor Earn + claim_Anchor_withdraw_UST_from_Earn_tx = Transaction_class.Anchor_withdraw_UST_from_Earn(UST_to_be_deposited_with_ANC - wallet_balance['UST'], 'UST') + claim_Anchor_withdraw_UST_from_Earn_tx_status = Queries_class.get_status_of_tx(claim_Anchor_withdraw_UST_from_Earn_tx) + if claim_Anchor_withdraw_UST_from_Earn_tx_status: + # ! This can result in a withdraw from Anchor Earn three times (MIR, SPEC, ANC) if you balance is not enough. There is no cumulated withdraw. + report_logger.info(f'[ANC Claim] No enought UST balance to depoit later with ANC, so {(UST_to_be_deposited_with_ANC.__float__() - wallet_balance["UST"].__float__()/1000000):.2f} UST have been withdrawn to be deposited later with.') + # Claim and mark for deposit + claim_ANC_tx = Transaction_class.claim_ANC() + claim_ANC_tx_status = Queries_class.get_status_of_tx(claim_ANC_tx) + if claim_ANC_tx_status == True: + default_logger.debug(f'[ANC Claim] Success TX: {claim_ANC_tx}') + # Mark for deposit + action_dict['ANC'] = 'deposit' + report_logger.info(f'[ANC Claim] {(claimable_ANC.__float__()/1000000):.2f} ANC have been claimed to be deposited.') + # Update UST balance in wallet + wallet_balance['UST'] = Dec(Queries_class.get_native_balance('uusd')) + else: + default_logger.warning(f'[ANC Claim] Failed TX: {claim_ANC_tx}.\n' + f'[ANC Claim] Reason: {claim_ANC_tx_status}') + else: + default_logger.warning(f'[ANC Claim] Failed TX: {claim_Anchor_withdraw_UST_from_Earn_tx}.\n' + f'[ANC Claim] Reason: {claim_Anchor_withdraw_UST_from_Earn_tx_status}') + else: + default_logger.warning(f'[ANC Claim] Skipped because not enough UST/aUST ({(wallet_balance["UST"].__float__() / 1000000):.2f})/({(wallet_balance["aUST"].__float__() / 1000000):.2f} in wallet to be deposited with ANC later.') + else: + default_logger.warning(f'[ANC Claim] Skipped because not enough UST ({(wallet_balance["UST"].__float__() / 1000000):.2f}) in wallet to be deposited with ANC later and not enabled to withdraw from Anchor Earn ({config.Anchor_enable_withdraw_from_Anchor_Earn_to_deposit_in_LP}).') else: - default_logger.warning(f'[ANC Claim] Failed TX: {claim_ANC_tx}.\n' - f'[ANC Claim] Reason: {claim_ANC_tx_status}') + default_logger.debug(f'[ANC Claim] Minimum price ({config.ANC_min_price}) not exceeded for sale ({(all_rates["ANC"].__float__()/1000000):.2f}) and a deposit is not enabled ({config.ANC_claim_and_deposit_in_LP}).') else: - default_logger.debug( - f'[ANC Claim & Sell] Skipped because claimable ANC value ({value_of_ANC_claim:.2f}) below limit ({config.ANC_min_total_value:.0f}) or current ANC price ({Queries_class.get_ANC_rate():.2f}) below limit ({config.ANC_min_price:.2f}).') + default_logger.debug(f'[ANC Claim] Skipped because claimable ANC value ({(value_of_ANC_claim.__float__()/1000000):.2f}) below limit ({config.ANC_min_total_value}).') else: - default_logger.debug(f'[ANC Claim & Sell] Skipped because no claimable ANC ({claimable_ANC:.2f}).') + default_logger.debug(f'[ANC Claim] Skipped because no claimable ANC ({(claimable_ANC.__float__()/1000000):.0f}).') else: - default_logger.debug( - f'[ANC Claim & Sell] Skipped because disabled by config ({config.ANC_claim_and_sell_token}) or insufficent funds ({(current_UST_wallet_balance - general_estimated_tx_fee):.2f}).') + default_logger.warning(f'[ANC Claim] Skipped because insufficent funds ({(wallet_balance["UST"].__float__() / 1000000):.2f}).') + return False + else: + default_logger.debug(f'[ANC Claim] Skipped because disabled by config ({config.ANC_claim_and_sell_token}).') - # Mirror: Claim un-locked UST - if config.Mirror_claim_unlocked_UST \ - and current_UST_wallet_balance > general_estimated_tx_fee: + + + # Mirror: Claim un-locked UST + # Check if this section is enabled + if config.Mirror_claim_unlocked_UST: + # Check if there is enough UST balance in the wallet to pay the transaction fees + if wallet_balance['UST'] > general_estimated_tx_fee: claimable_UST = Queries_class.Mirror_get_claimable_UST(Mirror_position_info) - # ! Balance will not be checked again, if enough UST are available for tx fees - if claimable_UST > config.Mirror_min_amount_UST_to_claim \ - and claimable_UST > 0: - Mirror_claim_unlocked_UST_tx = Transaction_class.Mirror_claim_unlocked_UST( - Mirror_position_info) - Mirror_claim_unlocked_UST_tx_status = Queries_class.get_status_of_tx( - Mirror_claim_unlocked_UST_tx) - if Mirror_claim_unlocked_UST_tx_status == True: - default_logger.debug( - f'[Mirror Claim UST] Success TX: {Mirror_claim_unlocked_UST_tx}') - report_logger.info( - f'[Mirror Claim UST] {claimable_UST:.2f} UST have been claimed from your shorts on Mirror.') - UST_balance_to_be_deposited_at_Anchor_Earn += claimable_UST - default_logger.debug( - f'[Mirror Claim UST] UST balance to be despoited at Anchor Earn: {UST_balance_to_be_deposited_at_Anchor_Earn:.0f} UST.') + # Check if there is any token claimable + if claimable_UST > 0: + # Check if the amount claimable is bigger than the min_amount + if (claimable_UST/1000000) > config.Mirror_min_amount_UST_to_claim: + # Claim UST + Mirror_claim_unlocked_UST_tx = Transaction_class.Mirror_claim_unlocked_UST(Mirror_position_info) + Mirror_claim_unlocked_UST_tx_status = Queries_class.get_status_of_tx(Mirror_claim_unlocked_UST_tx) + if Mirror_claim_unlocked_UST_tx_status == True: + default_logger.debug(f'[Mirror Claim UST] Success TX: {Mirror_claim_unlocked_UST_tx}') + report_logger.info(f'[Mirror Claim UST] {(claimable_UST.__float__()/1000000):.2f} UST have been claimed from your Mirror Shorts.') + # Update UST balance in wallet + wallet_balance['UST'] = Dec(Queries_class.get_native_balance('uusd')) + else: + default_logger.warning(f'[Mirror Claim UST] Failed TX: {Mirror_claim_unlocked_UST_tx}.\n' + f'[Mirror Claim UST] Reason: {Mirror_claim_unlocked_UST_tx_status}') else: - default_logger.warning(f'[Mirror Claim UST] Failed TX: {Mirror_claim_unlocked_UST_tx}.\n' - f'[Mirror Claim UST] Reason: {Mirror_claim_unlocked_UST_tx_status}') + default_logger.debug(f'[Mirror Claim UST] Skipped because claimable UST amount ({(claimable_UST.__float__()/1000000):.0f}) below limit ({config.Mirror_min_amount_UST_to_claim}).') else: - default_logger.debug( - f'[Mirror Claim UST] Skipped because claimable UST amount ({claimable_UST:.0f}) below limit ({config.Mirror_min_amount_UST_to_claim:.0f}).') + default_logger.debug(f'[Mirror Claim UST] Skipped because no UST to claim ({(claimable_UST.__float__()/1000000):.0f}).') else: - default_logger.debug( - f'[Mirror Claim UST] Skipped because disabled by config ({config.Mirror_claim_unlocked_UST}) or insufficent funds ({(current_UST_wallet_balance - general_estimated_tx_fee):.2f}).') + default_logger.warning(f'[Mirror Claim UST] Skipped because insufficent funds ({(wallet_balance["UST"].__float__() / 1000000):.2f}).') + return False + else: + default_logger.debug( + f'[Mirror Claim UST] Skipped because disabled by config ({config.Mirror_claim_unlocked_UST}) or insufficent funds ({(wallet_balance["UST"].__float__() - general_estimated_tx_fee.__float__()):.2f}).') - # default_logger.debug(f'\n-----------------------------------------------------------\n' - # f'---------- ANCHOR REPAY, BORROW, DEPOSIT SECTION ----------\n' - # f'-----------------------------------------------------------\n') + # default_logger.debug(f'---------------------------------------\n' + # f'------------ SELL SECTION -------------\n' + # f'---------------------------------------\n') - default_logger.debug(f'[Anchor] Anchor_borrow_info: {Anchor_borrow_info}') + # Check if section is enabled + if config.MIR_claim_and_sell_token: + if action_dict['MIR'] == 'sell': + # Check if there is enough UST balance in the wallet to pay the transaction fees + if wallet_balance['UST'] > general_estimated_tx_fee: + # Check if there is any token to sell + wallet_balance['MIR'] = Queries_class.get_non_native_balance(Terra_class.MIR_token) + default_logger.debug(f'[MIR Sell] Updated MIR balance {(wallet_balance["MIR"].__float__()/1000000)}') + MIR_to_be_sold = wallet_balance['MIR'] - wallet_balance_before['MIR'] + if MIR_to_be_sold > 0: + # Price and min_value has been checked before therefore sell + sell_MIR_tx = Transaction_class.sell_MIR(MIR_to_be_sold) + sell_MIR_tx_status = Queries_class.get_status_of_tx(sell_MIR_tx) + if sell_MIR_tx_status == True: + default_logger.debug(f'[MIR Sell] Success TX: {sell_MIR_tx}') + report_logger.info(f'[MIR Sell] {(MIR_to_be_sold.__float__()/1000000):.2f} MIR have been sold for {(MIR_to_be_sold.__float__()/1000000 * all_rates["MIR"].__float__()/1000000):.2f} UST total.') + # Update UST balance in wallet + wallet_balance['UST'] = Dec(Queries_class.get_native_balance('uusd')) + else: + default_logger.warning(f'[MIR Sell] Failed TX: {sell_MIR_tx}.\n' + f'[MIR Sell] Reason: {sell_MIR_tx_status}') + else: + default_logger.debug(f'[MIR Sell] Skipped because no MIR ({(MIR_to_be_sold.__float__()/1000000):.0f}) to sell.') + else: + default_logger.warning(f'[MIR Sell] Skipped because insufficent funds ({(wallet_balance["UST"].__float__() / 1000000):.2f}).') + return False + else: + default_logger.debug(f'[MIR Sell] Skipped because no MIR marked to be sold ({action_dict["MIR"]}).') + + else: + default_logger.debug(f'[MIR Sell] Skipped because disabled by config ({config.MIR_claim_and_sell_token}).') + + + # Check if section is enabled + if config.SPEC_claim_and_sell_token: + if action_dict['SPEC'] == 'sell': + # Check if there is enough UST balance in the wallet to pay the transaction fees + if wallet_balance['UST'] > general_estimated_tx_fee: + # Check if there is any token to sell + wallet_balance['SPEC'] = Queries_class.get_non_native_balance(Terra_class.SPEC_token) + default_logger.debug(f'[SPEC Sell] Updated SPEC balance {(wallet_balance["SPEC"].__float__()/1000000)}') + SPEC_to_be_sold = wallet_balance['SPEC'] - wallet_balance_before['SPEC'] + if SPEC_to_be_sold > 0: + # Price and min_value has been checked before therefore sell + sell_SPEC_tx = Transaction_class.sell_SPEC(SPEC_to_be_sold) + sell_SPEC_tx_status = Queries_class.get_status_of_tx(sell_SPEC_tx) + if sell_SPEC_tx_status == True: + default_logger.debug(f'[SPEC Sell] Success TX: {sell_SPEC_tx}') + report_logger.info(f'[SPEC Sell] {(SPEC_to_be_sold.__float__()/1000000):.2f} SPEC have been sold for {(SPEC_to_be_sold.__float__() / 1000000 * all_rates["SPEC"].__float__()/1000000):.2f} UST total.') + # Update UST balance in wallet + wallet_balance['UST'] = Dec(Queries_class.get_native_balance('uusd')) + else: + default_logger.warning(f'[SPEC Sell] Failed TX: {sell_SPEC_tx}.\n' + f'[SPEC Sell] Reason: {sell_SPEC_tx_status}') + else: + default_logger.debug(f'[SPEC Sell] Skipped because no SPEC ({(SPEC_to_be_sold.__float__()/1000000):.0f}) to sell.') + else: + default_logger.warning(f'[SPEC Sell] Skipped because insufficent funds ({(wallet_balance["UST"].__float__() / 1000000):.2f}).') + return False + else: + default_logger.debug(f'[SPEC Sell] Skipped because no SPEC marked to be sold ({action_dict["SPEC"]}).') + + else: + default_logger.debug(f'[SPEC Sell] Skipped because disabled by config ({config.SPEC_claim_and_sell_token}).') + + # Check if section is enabled + if config.ANC_claim_and_sell_token: + if action_dict['ANC'] == 'sell': + # Check if there is enough UST balance in the wallet to pay the transaction fees + if wallet_balance['UST'] > general_estimated_tx_fee: + # Check if there is any token to sell + wallet_balance['ANC'] = Queries_class.get_non_native_balance(Terra_class.ANC_token) + default_logger.debug(f'[ANC Sell] Updated ANC balance {(wallet_balance["ANC"].__float__()/1000000)}') + ANC_to_be_sold = wallet_balance['ANC'] - wallet_balance_before['ANC'] + if ANC_to_be_sold > 0: + # Price and min_value has been checked before therefore sell + sell_ANC_tx = Transaction_class.sell_ANC(ANC_to_be_sold) + sell_ANC_tx_status = Queries_class.get_status_of_tx(sell_ANC_tx) + if sell_ANC_tx_status == True: + default_logger.debug(f'[ANC Sell] Success TX: {sell_ANC_tx}') + report_logger.info(f'[ANC Sell] {(ANC_to_be_sold.__float__()/1000000):.2f} ANC have been sold for {(ANC_to_be_sold.__float__()/1000000 * all_rates["ANC"].__float__()/1000000):.2f} UST total.') + # Update UST balance in wallet + wallet_balance['UST'] = Dec(Queries_class.get_native_balance('uusd')) + else: + default_logger.warning(f'[ANC Sell] Failed TX: {sell_ANC_tx}.\n' + f'[ANC Sell] Reason: {sell_ANC_tx_status}') + else: + default_logger.debug(f'[ANC Sell] Skipped because no ANC ({(ANC_to_be_sold.__float__()/1000000):.0f}) to sell.') + else: + default_logger.warning(f'[ANC Sell] Skipped because insufficent funds ({(wallet_balance["UST"].__float__() / 1000000):.2f}).') + return False + else: + default_logger.debug(f'[ANC Sell] Skipped because no ANC marked to be sold ({action_dict["ANC"]}).') + + else: + default_logger.debug(f'[ANC Sell] Skipped because disabled by config ({config.ANC_claim_and_sell_token}).') + + + # default_logger.debug(f'------------------------------------------\n' + # f'------------ DEPOSIT SECTION -------------\n' + # f'------------------------------------------\n') + + # Check if this section is enabled + if config.MIR_claim_and_deposit_in_LP: + if action_dict['MIR'] == 'deposit': + # Check if there is enough UST balance in the wallet to pay the transaction fees + if wallet_balance['UST'] > general_estimated_tx_fee: + # Check if there is any token to deposit + wallet_balance['MIR'] = Queries_class.get_non_native_balance(Terra_class.MIR_token) + MIR_to_be_deposited = wallet_balance['MIR'] - wallet_balance_before['MIR'] + if MIR_to_be_deposited > 0: + # Price and min_value has been checked before therefore deposit + UST_to_be_deposited_with_MIR = Queries_class.get_UST_amount_for_LP_deposit(MIR_to_be_deposited,Terra_class.Mirror_MIR_UST_Pair) + deposit_MIR_tx = Transaction_class.deposit_MIR_in_pool(MIR_to_be_deposited, UST_to_be_deposited_with_MIR) + deposit_MIR_tx_status = Queries_class.get_status_of_tx(deposit_MIR_tx) + if deposit_MIR_tx_status == True: + default_logger.debug(f'[MIR LP Deposit] Success TX: {deposit_MIR_tx}') + report_logger.info(f'[MIR LP Deposit] {(MIR_to_be_deposited.__float__()/1000000):.2f} MIR and {(UST_to_be_deposited_with_MIR.__float__()/1000000):.2f} UST have been deposited to LP.') + # Update UST balance in wallet + wallet_balance['UST'] = Dec(Queries_class.get_native_balance('uusd')) + else: + default_logger.warning(f'[MIR LP Deposit] Failed TX: {deposit_MIR_tx}.\n' + f'[MIR LP Deposit] Reason: {deposit_MIR_tx_status}') + else: + default_logger.debug(f'[MIR LP Deposit] Skipped because no MIR ({(MIR_to_be_deposited.__float__()/1000000):.0f}) to deposit.') + else: + default_logger.warning(f'[MIR LP Deposit] YOU NEED TO ACT! Skipped because insufficent funds ({(wallet_balance["UST"].__float__() / 1000000):.2f}).') + return False + else: + default_logger.debug(f'[MIR LP Deposit] Skipped because no MIR marked to deposited ({action_dict["MIR"]}).') + else: + default_logger.debug(f'[MIR LP Deposit] Skipped because disabled by config ({config.MIR_claim_and_deposit_in_LP}).') + + # Check if this section is enabled + if config.SPEC_claim_and_deposit_in_LP: + if action_dict['SPEC'] == 'deposit': + # Check if there is enough UST balance in the wallet to pay the transaction fees + if wallet_balance['UST'] > general_estimated_tx_fee: + # Check if there is any token to deposit + wallet_balance['SPEC'] = Queries_class.get_non_native_balance(Terra_class.SPEC_token) + SPEC_to_be_deposited = wallet_balance['SPEC'] - wallet_balance_before['SPEC'] + if SPEC_to_be_deposited > 0: + # Price and min_value has been checked before therefore deposit + UST_to_be_deposited_with_SPEC = Queries_class.get_UST_amount_for_LP_deposit(SPEC_to_be_deposited,Terra_class.Spectrum_SPEC_UST_Pair) + deposit_SPEC_tx = Transaction_class.deposit_SPEC_in_pool(SPEC_to_be_deposited, UST_to_be_deposited_with_SPEC) + deposit_SPEC_tx_status = Queries_class.get_status_of_tx(deposit_SPEC_tx) + if deposit_SPEC_tx_status == True: + default_logger.debug(f'[SPEC LP Deposit] Success TX: {deposit_SPEC_tx}') + report_logger.info(f'[SPEC LP Deposit] {(SPEC_to_be_deposited.__float__()/1000000):.2f} SPEC and {(UST_to_be_deposited_with_SPEC.__float__()/1000000):.2f} UST have been deposited to LP.') + # Update UST balance in wallet + wallet_balance['UST'] = Dec(Queries_class.get_native_balance('uusd')) + else: + default_logger.warning(f'[SPEC LP Deposit] Failed TX: {deposit_SPEC_tx}.\n' + f'[SPEC LP Deposit] Reason: {deposit_SPEC_tx_status}') + else: + default_logger.debug(f'[SPEC LP Deposit] Skipped because no SPEC ({(SPEC_to_be_deposited.__float__()/1000000):.0f}) to deposit.') + else: + default_logger.warning(f'[SPEC LP Deposit] YOU NEED TO ACT! Skipped because insufficent funds ({(wallet_balance["UST"].__float__() / 1000000):.2f}).') + return False + else: + default_logger.debug(f'[SPEC LP Deposit] Skipped because no SPEC marked to deposited ({action_dict["SPEC"]}).') + else: + default_logger.debug(f'[SPEC LP Deposit] Skipped because disabled by config ({config.SPEC_claim_and_deposit_in_LP}).') + + # Check if this section is enabled + if config.ANC_claim_and_deposit_in_LP: + if action_dict['ANC'] == 'deposit': + # Check if there is enough UST balance in the wallet to pay the transaction fees + if wallet_balance['UST'] > general_estimated_tx_fee: + # Check if there is any token to deposit + wallet_balance['ANC'] = Queries_class.get_non_native_balance(Terra_class.ANC_token) + ANC_to_be_deposited = wallet_balance['ANC'] - wallet_balance_before['ANC'] + if ANC_to_be_deposited > 0: + # Price and min_value has been checked before therefore deposit + UST_to_be_deposited_with_ANC = Queries_class.get_UST_amount_for_LP_deposit(ANC_to_be_deposited,Terra_class.Terraswap_ANC_UST_Pair) + deposit_ANC_tx = Transaction_class.deposit_ANC_in_pool(ANC_to_be_deposited, UST_to_be_deposited_with_ANC) + deposit_ANC_tx_status = Queries_class.get_status_of_tx(deposit_ANC_tx) + if deposit_ANC_tx_status == True: + default_logger.debug(f'[ANC LP Deposit] Success TX: {deposit_ANC_tx}') + report_logger.info(f'[ANC LP Deposit] {(ANC_to_be_deposited.__float__()/1000000):.2f} ANC and {(UST_to_be_deposited_with_ANC.__float__()/1000000):.2f} UST have been deposited to LP.') + # Update UST balance in wallet + wallet_balance['UST'] = Dec(Queries_class.get_native_balance('uusd')) + else: + default_logger.warning(f'[ANC LP Deposit] Failed TX: {deposit_ANC_tx}.\n' + f'[ANC LP Deposit] Reason: {deposit_ANC_tx_status}') + else: + default_logger.debug(f'[ANC LP Deposit] Skipped because no ANC ({(ANC_to_be_deposited.__float__()/1000000):.0f}) to deposit.') + else: + default_logger.warning(f'[ANC LP Deposit] YOU NEED TO ACT! Skipped because insufficent funds ({(wallet_balance["UST"].__float__() / 1000000):.2f}).') + return False + else: + default_logger.debug(f'[ANC LP Deposit] Skipped because no ANC marked to deposited ({action_dict["ANC"]}).') + else: + default_logger.debug(f'[ANC LP Deposit] Skipped because disabled by config ({config.ANC_claim_and_deposit_in_LP}).') + + # default_logger.debug(f'\n-----------------------------------------------------------\n' + # f'---------- ANCHOR REPAY, BORROW, DEPOSIT SECTION ----------\n' + # f'-----------------------------------------------------------\n') + + if Anchor_borrow_info['borrow_limit'] > 0: + + default_logger.debug(f'[Anchor] Anchor_borrow_info: {Prettify_class.dict_value_convert_dec_to_float(Anchor_borrow_info, True)}') # Anchor: Repay loan if necesarry and repayment amount bigger than Anchor_min_repay_limit Anchor_amount_to_execute_in_ust = Anchor_borrow_info['amount_to_execute_in_ust'] Anchor_action_to_be_executed = Anchor_borrow_info['action_to_be_executed'] + + if Anchor_action_to_be_executed == 'none': - # Update the wallet's balance, in case some token have been sold for UST - current_UST_wallet_balance = Queries_class.get_native_balance('uusd') - current_aUST_wallet_balance = Queries_class.get_aUST_balance() - - if Anchor_borrow_info['borrow_limit'] > 0: + if wallet_balance['UST'] < general_estimated_tx_fee: + default_logger.warning(f'[Anchor] YOU NEED TO ACT! Skipped because insufficent funds ({(wallet_balance["UST"].__float__() / 1000000):.2f}).') + return False + default_logger.debug(f'[Anchor] Anchor is healthy. Current LTV at {(Anchor_borrow_info["cur_col_ratio"].__float__()*100):.2f} %.') - if Anchor_action_to_be_executed == 'none' \ - and Anchor_borrow_info['borrow_limit'] > 0: - default_logger.debug(f'[Anchor] Current LTV at {(Anchor_borrow_info["cur_col_ratio"]*100):.0f} %.') - - if Anchor_action_to_be_executed == 'repay' \ - and Anchor_amount_to_execute_in_ust > config.Anchor_min_repay_limit: + if not config.Anchor_enable_auto_repay_of_debt: + default_logger.debug(f'[Anchor Repay] Skipped because disabled by config ({config.Anchor_enable_auto_repay_of_debt}).') + if not config.Anchor_enable_auto_borrow_UST: + default_logger.debug(f'[Anchor Borrow] Skipped because disabled by config ({config.AAnchor_enable_auto_borrow_UST}).') + + elif Anchor_action_to_be_executed == 'repay': + if Anchor_amount_to_execute_in_ust > config.Anchor_min_repay_limit: # Check if the wallet has enough UST to repay and for tx fees - if Anchor_amount_to_execute_in_ust < (current_UST_wallet_balance - general_estimated_tx_fee): - Anchor_repay_debt_UST_tx = Transaction_class.Anchor_repay_debt_UST( - Anchor_amount_to_execute_in_ust) - Anchor_repay_debt_UST_tx_status = Queries_class.get_status_of_tx( - Anchor_repay_debt_UST_tx) + if Anchor_amount_to_execute_in_ust < (wallet_balance['UST'] - general_estimated_tx_fee): + Anchor_repay_debt_UST_tx = Transaction_class.Anchor_repay_debt_UST(Anchor_amount_to_execute_in_ust) + Anchor_repay_debt_UST_tx_status = Queries_class.get_status_of_tx(Anchor_repay_debt_UST_tx) if Anchor_repay_debt_UST_tx_status == True: - default_logger.debug( - f'[Anchor Repay] Success TX: {Anchor_repay_debt_UST_tx}') - report_logger.info( - f'[Anchor Repay] {Anchor_amount_to_execute_in_ust:.2f} UST have been repaid to Anchor Borrow from your wallet.') + default_logger.debug(f'[Anchor Repay] Success TX: {Anchor_repay_debt_UST_tx}') + report_logger.info(f'[Anchor Repay] {(Anchor_amount_to_execute_in_ust.__float__()/1000000):.2f} UST have been repaid to Anchor Borrow from your wallet.') else: default_logger.warning(f'[Anchor Repay] Failed TX: {Anchor_repay_debt_UST_tx}.\n' f'[Anchor Repay] Reason: {Anchor_repay_debt_UST_tx_status}') # Otherwise check if the balance in the wallet + a withdrawl of UST from Anchor Earn would be enough, and withdraw what is needed elif config.Anchor_enable_withdraw_of_deposited_UST \ - and (current_aUST_wallet_balance * aUST_rate + current_UST_wallet_balance - general_estimated_tx_fee) >= Anchor_amount_to_execute_in_ust: + and (wallet_balance['aUST'] * Queries_class.get_aUST_rate() + wallet_balance['UST'] - general_estimated_tx_fee) >= Anchor_amount_to_execute_in_ust: - Amount_to_be_withdrawn = Anchor_amount_to_execute_in_ust - \ - current_UST_wallet_balance + general_estimated_tx_fee - Anchor_withdraw_UST_from_Earn_tx = Transaction_class.Anchor_withdraw_UST_from_Earn( - Amount_to_be_withdrawn, 'UST') - Anchor_withdraw_UST_from_Earn_tx_status = Queries_class.get_status_of_tx( - Anchor_withdraw_UST_from_Earn_tx) + Amount_to_be_withdrawn = Anchor_amount_to_execute_in_ust - wallet_balance['UST'] + general_estimated_tx_fee + Anchor_withdraw_UST_from_Earn_tx = Transaction_class.Anchor_withdraw_UST_from_Earn(Amount_to_be_withdrawn, 'UST') + Anchor_withdraw_UST_from_Earn_tx_status = Queries_class.get_status_of_tx(Anchor_withdraw_UST_from_Earn_tx) if Anchor_withdraw_UST_from_Earn_tx_status == True: - default_logger.debug( - f'[Anchor Withdraw] Success TX: {Anchor_withdraw_UST_from_Earn_tx}') - Anchor_repay_debt_UST_tx = Transaction_class.Anchor_repay_debt_UST( - Anchor_amount_to_execute_in_ust) - Anchor_repay_debt_UST_tx_status = Queries_class.get_status_of_tx( - Anchor_repay_debt_UST_tx) + default_logger.debug(f'[Anchor Withdraw] Success TX: {Anchor_withdraw_UST_from_Earn_tx}') + Anchor_repay_debt_UST_tx = Transaction_class.Anchor_repay_debt_UST(Anchor_amount_to_execute_in_ust) + Anchor_repay_debt_UST_tx_status = Queries_class.get_status_of_tx(Anchor_repay_debt_UST_tx) if Anchor_repay_debt_UST_tx_status == True: default_logger.debug(f'[Anchor Withdraw] Success TX: {Anchor_repay_debt_UST_tx}') - report_logger.info(f'[Anchor Withdraw] {Amount_to_be_withdrawn:.2f} UST have been withdrawn from your Anchor Earn and {Anchor_repay_debt_UST_tx} (incl. UST from your wallet) have been repaid to Anchor Borrow.') + report_logger.info(f'[Anchor Withdraw] {(Amount_to_be_withdrawn.__float__()/1000000):.2f} UST have been withdrawn from your Anchor Earn and {(Anchor_amount_to_execute_in_ust.__float__()/1000000):.0f} (incl. UST from your wallet) have been repaid to Anchor Borrow.') else: default_logger.warning(f'[Anchor Withdraw] Failed TX: {Anchor_repay_debt_UST_tx}.\n' f'[Anchor Withdraw] Reason: {Anchor_repay_debt_UST_tx_status}') @@ -280,26 +757,21 @@ def keep_safe(): # Otherwise (if allowed) withdraw what is available and repay what is possible if enough tx fees are available elif config.Anchor_enable_partially_repay_if_not_enough_UST_in_wallet \ - and current_UST_wallet_balance > general_estimated_tx_fee: + and wallet_balance['UST'] > general_estimated_tx_fee: - Anchor_withdraw_UST_from_Earn_tx = Transaction_class.Anchor_withdraw_UST_from_Earn( - current_aUST_wallet_balance, 'aUST') - Anchor_withdraw_UST_from_Earn_tx_status = Queries_class.get_status_of_tx( - Anchor_withdraw_UST_from_Earn_tx) + Anchor_withdraw_UST_from_Earn_tx = Transaction_class.Anchor_withdraw_UST_from_Earn(wallet_balance['aUST'], 'aUST') + Anchor_withdraw_UST_from_Earn_tx_status = Queries_class.get_status_of_tx(Anchor_withdraw_UST_from_Earn_tx) if Anchor_withdraw_UST_from_Earn_tx_status == True: - default_logger.debug( - f'[Anchor Withdraw] Success TX: {Anchor_withdraw_UST_from_Earn_tx}') - - Anchor_repay_debt_UST_tx = Transaction_class.Anchor_repay_debt_UST(Queries_class.get_native_balance('uusd') - general_estimated_tx_fee) - Anchor_repay_debt_UST_tx_status = Queries_class.get_status_of_tx( - Anchor_repay_debt_UST_tx) + default_logger.debug(f'[Anchor Withdraw] Success TX: {Anchor_withdraw_UST_from_Earn_tx}') + Anchor_repay_amount = Queries_class.get_native_balance('uusd') - general_estimated_tx_fee + Anchor_repay_debt_UST_tx = Transaction_class.Anchor_repay_debt_UST(Anchor_repay_amount) + Anchor_repay_debt_UST_tx_status = Queries_class.get_status_of_tx(Anchor_repay_debt_UST_tx) if Anchor_repay_debt_UST_tx_status == True: - default_logger.debug( - f'[Anchor Repay] Success TX: {Anchor_repay_debt_UST_tx}') + default_logger.debug(f'[Anchor Repay] Success TX: {Anchor_repay_debt_UST_tx}') report_logger.warning(f'[Anchor Repay] YOU NEED TO ACT! There was not enough availabe aUST to withdraw and not enough UST in your wallet to repay your Anchor Borrow.\n' - f'{current_aUST_wallet_balance:.2f} aUST has been withdrawn, and combined with your availabe UST in your wallet, {Anchor_repay_debt_UST_tx:.2f} UST have been repaid to Anchor Borrow.') + f'{(wallet_balance["aUST"].__float__()/1000000):.2f} aUST has been withdrawn, and combined with your availabe UST in your wallet, {(Anchor_repay_amount.__float__()/1000000):.2f} UST have been repaid to Anchor Borrow.') else: default_logger.warning(f'[Anchor Repay] Failed TX: {Anchor_repay_debt_UST_tx}.\n' f'[Anchor Repay] Reason: {Anchor_repay_debt_UST_tx_status}') @@ -308,251 +780,240 @@ def keep_safe(): default_logger.warning(f'[Anchor Withdraw] Failed TX: {Anchor_withdraw_UST_from_Earn_tx}.\n' f'[Anchor Withdraw] Reason: {Anchor_withdraw_UST_from_Earn_tx_status}') else: - default_logger.debug( - f'[Anchor Repay] Skipped because disabled by config Anchor_enable_withdraw_of_deposited_UST({config.Anchor_enable_withdraw_of_deposited_UST}) or\nAnchor_enable_partially_repay_if_not_enough_UST_in_wallet ({config.Anchor_enable_partially_repay_if_not_enough_UST_in_wallet}).') + default_logger.debug(f'[Anchor Repay] Skipped because disabled by config Anchor_enable_withdraw_of_deposited_UST({config.Anchor_enable_withdraw_of_deposited_UST}) or\nAnchor_enable_partially_repay_if_not_enough_UST_in_wallet ({config.Anchor_enable_partially_repay_if_not_enough_UST_in_wallet}).') else: - default_logger.debug(f'[Anchor Repay] Skipped because disabled by config ({config.Anchor_enable_auto_repay_of_debt}), nothing to repay ({Anchor_action_to_be_executed}) or repay amount ({Anchor_amount_to_execute_in_ust:.0f}) below repay limit ({config.Anchor_min_repay_limit:.0f}).') - - - # Anchor: Borrow more UST if possible, allowed, big enough and enough balance for tx fees is available - if Anchor_action_to_be_executed == 'borrow' \ - and Anchor_amount_to_execute_in_ust > config.Anchor_min_borrow_limit \ - and current_UST_wallet_balance > general_estimated_tx_fee: - - # Check if we are in a cooldown period or if the key actually exists - if cooldowns.get('Anchor_borrow_cooldown') is None or cooldowns['Anchor_borrow_cooldown'] <= datetime_now: - - Anchor_borrow_more_UST_tx = Transaction_class.Anchor_borrow_more_UST( - Anchor_amount_to_execute_in_ust) - Anchor_borrow_more_UST_tx_status = Queries_class.get_status_of_tx( - Anchor_borrow_more_UST_tx) - - if Anchor_borrow_more_UST_tx_status == True: - default_logger.debug( - f'[Anchor Borrow] Success TX: {Anchor_borrow_more_UST_tx}') - report_logger.info( - f'[Anchor Borrow] {Anchor_amount_to_execute_in_ust:.2f} UST more has been borrowed from Anchor Borrow.') - UST_balance_to_be_deposited_at_Anchor_Earn += Anchor_amount_to_execute_in_ust - default_logger.debug( - f'[Anchor Borrow] UST balance to be despoited at Anchor Earn: {UST_balance_to_be_deposited_at_Anchor_Earn:.0f} UST.') - - # Cooldown: Write date of today into cooldown dictionary - cooldowns['Anchor_borrow_cooldown'] = datetime_now + timedelta(days=config.Anchor_borrow_cooldown) - if config.Anchor_borrow_cooldown > 0: - report_logger.info( - f'[Anchor Borrow] Cooldown limit has been activated. Next Anchor deposit will be possible on {(datetime_now + timedelta(days=config.Anchor_borrow_cooldown)):%Y-%m-%d}.') - else: - default_logger.warning(f'[Anchor Borrow] Failed TX: {Anchor_borrow_more_UST_tx}.\n' - f'[Anchor Borrow] Reason: {Anchor_borrow_more_UST_tx_status}') - else: - try: - default_logger.debug(f'[Anchor Borrow] Skipped because in cooldown period until ({cooldowns["Anchor_borrow_cooldown"]}).') - except: - default_logger.debug(f'[Anchor Borrow] Something is wrong with the cooldowns["Anchor_borrow_cooldown"].') + default_logger.debug(f'[Anchor Repay] Skipped because repay amount ({(Anchor_amount_to_execute_in_ust.__float__()/1000000):.0f}) below repay limit ({config.Anchor_min_repay_limit}).') + + # Anchor: Borrow more UST if possible, allowed, big enough and enough balance for tx fees is available + elif Anchor_action_to_be_executed == 'borrow' \ + and Anchor_amount_to_execute_in_ust > config.Anchor_min_borrow_limit \ + and wallet_balance['UST'] > general_estimated_tx_fee: + + # Check if we are in a cooldown period or if the key actually exists + if cooldowns.get('Anchor_borrow_cooldown') is None or cooldowns['Anchor_borrow_cooldown'] <= datetime_now: + + Anchor_borrow_more_UST_tx = Transaction_class.Anchor_borrow_more_UST(Anchor_amount_to_execute_in_ust) + Anchor_borrow_more_UST_tx_status = Queries_class.get_status_of_tx(Anchor_borrow_more_UST_tx) + + if Anchor_borrow_more_UST_tx_status == True: + default_logger.debug(f'[Anchor Borrow] Success TX: {Anchor_borrow_more_UST_tx}') + report_logger.info(f'[Anchor Borrow] {Anchor_amount_to_execute_in_ust.__float__():.2f} UST more has been borrowed from Anchor Borrow.') + # Cooldown: Write date of today into cooldown dictionary + cooldowns['Anchor_borrow_cooldown'] = datetime_now + timedelta(days=config.Anchor_borrow_cooldown) + if config.Anchor_borrow_cooldown > 0: + report_logger.info(f'[Anchor Borrow] Cooldown limit has been activated. Next Anchor deposit will be possible on {(datetime_now + timedelta(days=config.Anchor_borrow_cooldown)):%Y-%m-%d}.') + else: + default_logger.warning(f'[Anchor Borrow] Failed TX: {Anchor_borrow_more_UST_tx}.\n' + f'[Anchor Borrow] Reason: {Anchor_borrow_more_UST_tx_status}') else: - default_logger.debug( - f'[Anchor Borrow] Skipped because disabled by config ({config.Anchor_enable_auto_borrow_UST}), nothing to borrow ({Anchor_action_to_be_executed}), borrow amount ({Anchor_amount_to_execute_in_ust:.0f}) below repay limit ({config.Anchor_min_borrow_limit:.0f}) or not enough funds for the transaction ({(current_UST_wallet_balance - general_estimated_tx_fee):.0f}).') + try: + default_logger.debug(f'[Anchor Borrow] Skipped because in cooldown period until ({cooldowns["Anchor_borrow_cooldown"]}).') + except: + default_logger.warning(f'[Anchor Borrow] Something is wrong with the cooldowns["Anchor_borrow_cooldown"].') + else: - default_logger.debug(f'[Anchor] You do not have any collateral deposited in Anchor. You borrow limit is 0.') + default_logger.warning(f'[Anchor] Something went wrong while processing the action to execute on Anchor ({Anchor_action_to_be_executed}).') + else: + default_logger.debug(f'[Anchor] You do not have any collateral deposited in Anchor. You borrow limit is 0.') - # Anchor: Deposit UST from previous claim/sale of reward tokens into Anchor to get more aUST - if config.Anchor_enable_deposit_borrowed_UST \ - and UST_balance_to_be_deposited_at_Anchor_Earn >= config.Anchor_min_deposit_amount: + # Update wallet balances to find out what the delta is + wallet_balance['UST'] = Dec(Queries_class.get_native_balance('uusd')) - Anchor_deposit_UST_for_Earn_tx = Transaction_class.Anchor_deposit_UST_for_Earn(UST_balance_to_be_deposited_at_Anchor_Earn) + # Anchor: Deposit UST from previous claim/sale of reward tokens into Anchor to get more aUST + if config.Anchor_Earn_enable_deposit_UST: + UST_to_be_deposited_at_Anchor_Earn = wallet_balance['UST'] - wallet_balance_before['UST'] - (config.Anchor_Earn_min_balance_to_keep_in_wallet * 1000000) + default_logger.debug(f'[Anchor Deposit] Updated UST balance {(wallet_balance["UST"].__float__()/1000000):.2f}') + if UST_to_be_deposited_at_Anchor_Earn >= config.Anchor_Earn_min_deposit_amount: + Anchor_deposit_UST_for_Earn_tx = Transaction_class.Anchor_deposit_UST_for_Earn(UST_to_be_deposited_at_Anchor_Earn) Anchor_deposit_UST_for_Earn_tx_status = Queries_class.get_status_of_tx(Anchor_deposit_UST_for_Earn_tx) if Anchor_deposit_UST_for_Earn_tx_status == True: - default_logger.debug( - f'[Anchor Deposit] Success TX: {Anchor_deposit_UST_for_Earn_tx}') - report_logger.info( - f'[Anchor Deposit] {UST_balance_to_be_deposited_at_Anchor_Earn:.2f} UST have been deposited to Anchor Earn.') + default_logger.debug(f'[Anchor Deposit] Success TX: {Anchor_deposit_UST_for_Earn_tx}') + report_logger.info(f'[Anchor Deposit] {(UST_to_be_deposited_at_Anchor_Earn.__float__()/1000000):.2f} UST have been deposited to Anchor Earn.') else: default_logger.warning(f'[Anchor Deposit] Failed TX: {Anchor_deposit_UST_for_Earn_tx}.\n' f'[Anchor Deposit] Reason: {Anchor_deposit_UST_for_Earn_tx_status}') else: - default_logger.debug( - f'[Anchor Deposit] Skipped because disabled by config ({config.Anchor_enable_deposit_borrowed_UST}) or deposit amount ({UST_balance_to_be_deposited_at_Anchor_Earn:.0f}) below deposit limit ({config.Anchor_min_deposit_amount:.0f})') - - # default_logger.debug(f'\n-------------------------------------------\n' - # f'---------- MIRROR SHORTS SECTION ----------\n' - # f'-------------------------------------------\n') - - default_logger.debug(f'[Mirror] Mirror_position_info: {Mirror_position_info}') - - for position in Mirror_position_info: - position_idx = position['position_idx'] - action_to_be_executed = position['action_to_be_executed'] - - amount_to_execute_in_ust = position["amount_to_execute_in_ust"] - amount_to_execute_in_kind = position['amount_to_execute_in_kind'] - collateral_token_denom = position['collateral_token_denom'] - within_market_hours = Queries_class.market_hours() - # Check if position is marked for a withdraw - if action_to_be_executed == 'withdraw': - if within_market_hours: - if amount_to_execute_in_ust > config.Mirror_min_withdraw_limit_in_UST: - - # Check if we are in a cooldown period or if the key actually exists - if cooldowns.get(position_idx) is None or cooldowns[position_idx] <= datetime_now: - - Mirror_withdraw_collateral_for_position_tx = Transaction_class.Mirror_withdraw_collateral_for_position( - position_idx, amount_to_execute_in_kind, collateral_token_denom) - Mirror_withdraw_collateral_for_position_tx_status = Queries_class.get_status_of_tx( - Mirror_withdraw_collateral_for_position_tx) - - if Mirror_withdraw_collateral_for_position_tx_status == True: - default_logger.debug( - f'[Mirror Shorts Withdraw] Success TX: {Mirror_withdraw_collateral_for_position_tx}') - report_logger.info( - f'[Mirror Shorts] {amount_to_execute_in_kind:.2f} {collateral_token_denom} with a value of {amount_to_execute_in_ust:.0f} UST of collateral have been withdrawn from your short position idx {position["position_idx"]}.') - - # Cooldown: Write date of today into cooldown dictionary - cooldowns[position_idx] = datetime_now + timedelta(days=config.Mirror_withdraw_cooldown) - if config.Mirror_withdraw_cooldown > 0: - report_logger.info( - f'[Mirror Shorts] Cooldown limit has been activated. Next withdraw for short position idx {position["position_idx"]} will be possible on {(datetime_now + timedelta(days=config.Mirror_withdraw_cooldown)):%Y-%m-%d}') - else: - default_logger.warning(f'[Mirror Shorts Withdraw] Failed TX: {Mirror_withdraw_collateral_for_position_tx}.\n' - f'[Mirror Shorts Withdraw] Reason: {Mirror_withdraw_collateral_for_position_tx_status}') - else: - try: - default_logger.debug(f'[Mirror Shorts] Skipped because in cooldown period until ({cooldowns[position_idx]}) for position ({position_idx}).') - except: - default_logger.debug(f'[Mirror Shorts] Something is wrong with the cooldowns[position_idx] for position ({position_idx}).') - - else: - default_logger.debug( - f'[Mirror Shorts] For position {position_idx} amount to be withdrawn ({amount_to_execute_in_ust:.0f}) is below limit ({config.Mirror_min_withdraw_limit_in_UST:.0f}).') - else: - default_logger.warning(f'[Mirror Shorts] Withdraw was planned, but NYSE market is not open ({within_market_hours}).') - - # Check if position has a deposit pending and if the deposit amount if big enough - elif action_to_be_executed == 'deposit': - if amount_to_execute_in_ust > config.Mirror_min_deposit_limit_in_ust: - - # Depending on the collateral token required, check if enough balance of the in-kind token is in your wallet - # and enough UST for the transaction fee - current_UST_wallet_balance = Queries_class.get_native_balance('uusd') - if collateral_token_denom == 'aUST': - available_balance = Queries_class.get_aUST_balance() - enough_balance = available_balance >= amount_to_execute_in_kind and current_UST_wallet_balance > general_estimated_tx_fee - elif collateral_token_denom == 'uluna': - available_balance = Queries_class.get_native_balance( - collateral_token_denom) - enough_balance = available_balance >= amount_to_execute_in_kind and current_UST_wallet_balance > general_estimated_tx_fee - elif collateral_token_denom == 'uusd': - available_balance = current_UST_wallet_balance - enough_balance = available_balance >= amount_to_execute_in_kind + general_estimated_tx_fee - else: - default_logger.debug( - f'[Mirror Shorts] You discovered a new collateral_token_denom. Congratulations! Please post this as an issue on my Github, so I can fix it. Thank you!') - - if enough_balance: - # If you have enough balance then deposit collateral - Mirror_deposit_collateral_for_position_tx = Transaction_class.Mirror_deposit_collateral_for_position( + default_logger.debug(f'[Anchor Deposit] Skipped because deposit amount ({(UST_to_be_deposited_at_Anchor_Earn.__float__()/1000000):.0f}) below deposit limit ({config.Anchor_Earn_min_deposit_amount}) with considered Anchor_Earn_min_balance_to_keep_in_wallet ({config.Anchor_Earn_min_balance_to_keep_in_wallet}).') + + else: + default_logger.debug(f'[Anchor Deposit] Skipped because disabled by config ({config.Anchor_Earn_enable_deposit_UST}).') + + # default_logger.debug(f'\n-------------------------------------------\n' + # f'---------- MIRROR SHORTS SECTION ----------\n' + # f'-------------------------------------------\n') + + default_logger.debug(f'[Mirror] Mirror_position_info: {Prettify_class.dict_value_convert_dec_to_float(Mirror_position_info, True)}') + + for position in Mirror_position_info: + position_idx = position['position_idx'] + action_to_be_executed = position['action_to_be_executed'] + + amount_to_execute_in_ust = position["amount_to_execute_in_ust"] + amount_to_execute_in_kind = position['amount_to_execute_in_kind'] + collateral_token_denom = position['collateral_token_denom'] + within_market_hours = Queries_class.market_hours() + # Check if position is marked for a withdraw + if action_to_be_executed == 'withdraw': + if within_market_hours: + if amount_to_execute_in_ust > config.Mirror_min_withdraw_limit_in_UST: + + # Check if we are in a cooldown period or if the key actually exists + if cooldowns.get(position_idx) is None or cooldowns[position_idx] <= datetime_now: + + Mirror_withdraw_collateral_for_position_tx = Transaction_class.Mirror_withdraw_collateral_for_position( position_idx, amount_to_execute_in_kind, collateral_token_denom) - Mirror_deposit_collateral_for_position_tx_status = Queries_class.get_status_of_tx(Mirror_deposit_collateral_for_position_tx) + Mirror_withdraw_collateral_for_position_tx_status = Queries_class.get_status_of_tx( + Mirror_withdraw_collateral_for_position_tx) - if Mirror_deposit_collateral_for_position_tx_status == True: + if Mirror_withdraw_collateral_for_position_tx_status == True: default_logger.debug( - f'[Mirror Shorts Deposit] Success TX: {Mirror_deposit_collateral_for_position_tx}') + f'[Mirror Shorts Withdraw] Success TX: {Mirror_withdraw_collateral_for_position_tx}') report_logger.info( - f'[Mirror Shorts] {amount_to_execute_in_kind:.2f} {collateral_token_denom:.2f} with a value of {amount_to_execute_in_ust:.2f} UST of collateral have been deposited to your short position idx {position["position_idx"]}.') + f'[Mirror Shorts] {(amount_to_execute_in_kind.__float__()/1000000):.2f} {collateral_token_denom} with a value of {(amount_to_execute_in_ust.__float__()/1000000):.0f} UST of collateral have been withdrawn from your short position idx {position["position_idx"]}.') + + # Cooldown: Write date of today into cooldown dictionary + cooldowns[position_idx] = datetime_now + timedelta(days=config.Mirror_withdraw_cooldown) + if config.Mirror_withdraw_cooldown > 0: + report_logger.info(f'[Mirror Shorts] Cooldown limit has been activated. Next withdraw for short position idx {position["position_idx"]} will be possible on {(datetime_now + timedelta(days=config.Mirror_withdraw_cooldown)):%Y-%m-%d}') else: - default_logger.warning(f'[Mirror Shorts Deposit] Failed TX: {Mirror_deposit_collateral_for_position_tx}.\n' - f'[Mirror Shorts Deposit] Reason: {Mirror_deposit_collateral_for_position_tx_status}') + default_logger.warning(f'[Mirror Shorts Withdraw] Failed TX: {Mirror_withdraw_collateral_for_position_tx}.\n' + f'[Mirror Shorts Withdraw] Reason: {Mirror_withdraw_collateral_for_position_tx_status}') else: - # If you have NOT enough balance then deposit what is possible - Mirror_deposit_collateral_for_position_tx = Transaction_class.Mirror_deposit_collateral_for_position( - position_idx, available_balance, collateral_token_denom) - Mirror_deposit_collateral_for_position_tx_status = Queries_class.get_status_of_tx( - Mirror_deposit_collateral_for_position_tx) + try: + default_logger.debug(f'[Mirror Shorts] Skipped because in cooldown period until ({cooldowns[position_idx]}) for position ({position_idx}).') + except: + default_logger.warning(f'[Mirror Shorts] Something is wrong with the cooldowns[position_idx] for position ({position_idx}).') + + else: + default_logger.debug( + f'[Mirror Shorts] For position {position_idx} amount to be withdrawn ({(amount_to_execute_in_ust.__float__()/1000000):.0f}) is below limit ({config.Mirror_min_withdraw_limit_in_UST}).') + else: + default_logger.warning(f'[Mirror Shorts] Withdraw was planned, but NYSE market is not open ({within_market_hours}).') - if Mirror_deposit_collateral_for_position_tx_status == True: - default_logger.debug( - f'[Mirror Shorts Deposit] Success TX: {Mirror_deposit_collateral_for_position_tx}') - report_logger.warning(f'[Mirror Shorts Deposit] YOU NEED TO ACT! There was not enough availabe {collateral_token_denom:.2f} in your wallet to deposit your short position {position_idx} on Mirror.\n' - f'{available_balance:.2f} {collateral_token_denom:.2f} from your wallet, has been deposited in your short position {position_idx} on Mirror.') - else: - default_logger.warning(f'[Mirror Shorts Deposit] Failed TX: {Mirror_deposit_collateral_for_position_tx}.\n' - f'[Mirror Shorts Deposit] Reason: {Mirror_deposit_collateral_for_position_tx_status}') + # Check if position has a deposit pending and if the deposit amount if big enough + elif action_to_be_executed == 'deposit': + if amount_to_execute_in_ust > config.Mirror_min_deposit_limit_in_ust: + + # Depending on the collateral token required, check if enough balance of the in-kind token is in your wallet + # and enough UST for the transaction fee + wallet_balance['UST'] = Queries_class.get_native_balance('uusd') + if collateral_token_denom == 'aUST': + available_balance = Queries_class.get_non_native_balance(Terra_class.aUST_token) / 1000000 + enough_balance = available_balance >= amount_to_execute_in_kind and wallet_balance['UST'] > general_estimated_tx_fee + elif collateral_token_denom == 'uluna': + available_balance = Queries_class.get_native_balance('uluna') / 1000000 + enough_balance = available_balance >= amount_to_execute_in_kind and wallet_balance['UST'] > general_estimated_tx_fee + elif collateral_token_denom == 'uusd': + available_balance = wallet_balance['UST'] + enough_balance = available_balance >= amount_to_execute_in_kind + general_estimated_tx_fee else: - default_logger.debug(f'[Mirror Shorts] For position {position_idx} amount to be deposited ({amount_to_execute_in_ust:.0f}) is below limit ({config.Mirror_min_deposit_limit_in_ust:.0f}).') + default_logger.debug(f'[Mirror Shorts] You discovered a new collateral_token_denom. Congratulations! Please post this as an issue on my Github, so I can fix it. Thank you!') - elif action_to_be_executed == 'none': - default_logger.debug( - f'[Mirror Shorts] Position {position_idx} is healthy. Current ratio is {position["cur_col_ratio"]:.2f}.') + if enough_balance: + # If you have enough balance then deposit collateral + Mirror_deposit_collateral_for_position_tx = Transaction_class.Mirror_deposit_collateral_for_position( + position_idx, amount_to_execute_in_kind, collateral_token_denom) + Mirror_deposit_collateral_for_position_tx_status = Queries_class.get_status_of_tx(Mirror_deposit_collateral_for_position_tx) + + if Mirror_deposit_collateral_for_position_tx_status == True: + default_logger.debug(f'[Mirror Shorts Deposit] Success TX: {Mirror_deposit_collateral_for_position_tx}') + report_logger.info(f'[Mirror Shorts] {(amount_to_execute_in_kind.__float__()/1000000):.2f} {collateral_token_denom} with a value of {amount_to_execute_in_ust.__float__():.2f} UST of collateral have been deposited to your short position idx {position["position_idx"]}.') + else: + default_logger.warning(f'[Mirror Shorts Deposit] Failed TX: {Mirror_deposit_collateral_for_position_tx}.\n' + f'[Mirror Shorts Deposit] Reason: {Mirror_deposit_collateral_for_position_tx_status}') + else: + # If you have NOT enough balance then deposit what is possible + Mirror_deposit_collateral_for_position_tx = Transaction_class.Mirror_deposit_collateral_for_position( + position_idx, available_balance, collateral_token_denom) + Mirror_deposit_collateral_for_position_tx_status = Queries_class.get_status_of_tx( + Mirror_deposit_collateral_for_position_tx) + + if Mirror_deposit_collateral_for_position_tx_status == True: + default_logger.debug(f'[Mirror Shorts Deposit] Success TX: {Mirror_deposit_collateral_for_position_tx}') + report_logger.warning(f'[Mirror Shorts Deposit] YOU NEED TO ACT! There was not enough availabe {collateral_token_denom} in your wallet to deposit your short position {position_idx} on Mirror.\n' + f'{(available_balance.__float__()/1000000):.2f} {collateral_token_denom} from your wallet, has been deposited in your short position {position_idx} on Mirror.') + else: + default_logger.warning(f'[Mirror Shorts Deposit] Failed TX: {Mirror_deposit_collateral_for_position_tx}.\n' + f'[Mirror Shorts Deposit] Reason: {Mirror_deposit_collateral_for_position_tx_status}') else: - default_logger.warning(f'[Mirror Shorts] Something went wrong with position {position_idx} and action {action_to_be_executed}.') + default_logger.debug(f'[Mirror Shorts] For position {position_idx} amount to be deposited ({(amount_to_execute_in_ust.__float__()/1000000):.0f}) is below limit ({config.Mirror_min_deposit_limit_in_ust}).') - # default_logger.debug( f'\n[CONFIG] Mirror_enable_deposit_collateral is set to ({config.Mirror_enable_deposit_collateral})\n' - # f'[CONFIG] Mirror_enable_withdraw_collateral is set to ({config.Mirror_enable_withdraw_collateral})') - - # default_logger.debug(f'\n-----------------------------------------\n' - # f'---------- BUREAUCRACY SECTION ----------\n' - # f'-----------------------------------------\n') - - if config.Send_me_a_status_update: - if cooldowns.get('Staus_Report_cooldown') is None or cooldowns['Staus_Report_cooldown'] <= datetime_now: - if datetime.strptime(f'{datetime_now:%H:%M}', '%H:%M') > datetime.strptime(config.Status_update_time, '%H:%M'): - - status_update = "" - - if Anchor_borrow_info["loan_amount"] > 0: - status_update += f'-----------------------------------\n' \ - f'------------- ANCHOR --------------\n' \ - f'-----------------------------------\n' \ - f'bETH collateral: {Anchor_borrow_info["amount_bETH_collateral"]:.3f} bETH\n' \ - f'bLuna collateral: {Anchor_borrow_info["amount_bLuna_collateral"]:.0f} bLuna\n' \ - f'Total collateral: {Anchor_borrow_info["total_collateral_value"]:.0f} UST\n' \ - f'Loan amount: {Anchor_borrow_info["loan_amount"]:.0f} UST\n' \ - f'Borrow limit: {Anchor_borrow_info["borrow_limit"]:.0f} UST\n' \ - f'Current LTV: {Anchor_borrow_info["cur_col_ratio"]*100:.0f} %\n' \ - f'If all your collateral loses {Anchor_borrow_info["collateral_loss_to_liq"]*100:.0f}% you would get liquidated.\n' \ - - if len(Mirror_position_info) > 0: - - status_update += f'-----------------------------------\n' \ - f'------------- MIRROR --------------\n' \ - f'-----------------------------------\n' \ + elif action_to_be_executed == 'none': + default_logger.debug( + f'[Mirror Shorts] Position {position_idx} is healthy. Current ratio is {position["cur_col_ratio"].__float__()*100:.0f} %.') + else: + default_logger.warning(f'[Mirror Shorts] Something went wrong with position {position_idx} and action {action_to_be_executed}.') + + # default_logger.debug( f'\n[CONFIG] Mirror_enable_deposit_collateral is set to ({config.Mirror_enable_deposit_collateral})\n' + # f'[CONFIG] Mirror_enable_withdraw_collateral is set to ({config.Mirror_enable_withdraw_collateral})') + + # default_logger.debug(f'\n-----------------------------------------\n' + # f'---------- BUREAUCRACY SECTION ----------\n' + # f'-----------------------------------------\n') + + if config.Send_me_a_status_update: + if cooldowns.get('Staus_Report_cooldown') is None or cooldowns['Staus_Report_cooldown'] <= datetime_now: + if datetime.strptime(f'{datetime_now:%H:%M}', '%H:%M') > datetime.strptime(config.Status_update_time, '%H:%M'): + + status_update = "" + + if Anchor_borrow_info["loan_amount"] > 0: + status_update += f'-----------------------------------\n' + status_update += f'------------- ANCHOR --------------\n' + status_update += f'-----------------------------------\n' + status_update += f'bETH collateral: {(Anchor_borrow_info["amount_bETH_collateral"].__float__()/1000000):.3f} bETH\n' + status_update += f'bLuna collateral: {(Anchor_borrow_info["amount_bLuna_collateral"].__float__()/1000000):.0f} bLuna\n' + status_update += f'Total collateral: {(Anchor_borrow_info["total_collateral_value"].__float__()/1000000):.0f} UST\n' + status_update += f'Loan amount: {(Anchor_borrow_info["loan_amount"].__float__()/1000000):.0f} UST\n' + status_update += f'Borrow limit: {(Anchor_borrow_info["borrow_limit"].__float__()/1000000):.0f} UST\n' + status_update += f'Current LTV: {Anchor_borrow_info["cur_col_ratio"].__float__()*100:.0f} %\n' + status_update += f'If all your collateral loses {Anchor_borrow_info["collateral_loss_to_liq"].__float__()*100:.0f}% you would get liquidated.\n' + + if len(Mirror_position_info) > 0: + + status_update += f'-----------------------------------\n' + status_update += f'------------- MIRROR --------------\n' + status_update += f'-----------------------------------\n' + + for position in Mirror_position_info: - for position in Mirror_position_info: - - status_update += f'Position: {position["position_idx"]} - {position["mAsset_symbol"]}\n' \ - f'Collateral value: {position["collateral_amount_in_kind"]:.0f} {position["collateral_token_denom"]}\n' \ - f'Collateral value: {position["collateral_amount_in_ust"]:.0f} UST\n' \ - f'Shorted Value in UST: {position["shorted_asset_amount"]:.0f} UST\n' \ - f'Current LTV: {position["cur_col_ratio"]:.0f}00 %\n' \ - f'If all your collateral loses {(position["collateral_loss_to_liq"]*100):.0f}%\n' \ - f'or if {position["mAsset_symbol"]} raises by {(position["shorted_mAsset_gain_to_liq"]*100):.0f}% you would get liquidated.\n' \ - f'\n' + status_update += f'Position: {position["position_idx"]} - {position["mAsset_symbol"]}\n' + status_update += f'Collateral value: {(position["collateral_amount_in_kind"].__float__()/1000000):.0f} {position["collateral_token_denom"]}\n' + status_update += f'Collateral value: {(position["collateral_amount_in_ust"].__float__()/1000000):.0f} UST\n' + status_update += f'Shorted Value in UST: {(position["shorted_asset_amount"].__float__()/1000000):.0f} UST\n' + status_update += f'Current LTV: {position["cur_col_ratio"].__float__():.0f}00 %\n' + status_update += f'If all your collateral loses {(position["collateral_loss_to_liq"].__float__()*100):.0f}%\n' + status_update += f'or if {position["mAsset_symbol"]} raises by {(position["shorted_mAsset_gain_to_liq"].__float__()*100):.0f}% you would get liquidated.\n' + status_update += f'\n' - # Cooldown: Write date of today into cooldown dictionary - cooldowns['Staus_Report_cooldown'] = datetime_now + timedelta(hours=config.Status_update_frequency) - report_logger.info(f'[Status Update] Cooldown limit has been activated. Next Status Report will be send on {(datetime_now + timedelta(hours=config.Status_update_frequency)):%Y-%m-%d %H:%M}') - else: - default_logger.debug(f'[Status Update] Not sent as we are before your desired time ({config.Status_update_time}).') + # Cooldown: Write date of today into cooldown dictionary + cooldowns['Staus_Report_cooldown'] = datetime_now + timedelta(hours=config.Status_update_frequency) + report_logger.info(f'[Status Update] Cooldown limit has been activated. Next Status Report will be send on {(datetime_now + timedelta(hours=config.Status_update_frequency)):%Y-%m-%d %H:%M}') else: - try: - default_logger.debug(f'[Status Update] Skipped because in cooldown period until ({cooldowns["Staus_Report_cooldown"]}) or before defined time({config.Status_update_time}).') - except: - default_logger.debug(f'[Status Update] Something is wrong with the cooldowns["Staus_Report_cooldown"].') + default_logger.debug(f'[Status Update] Not sent as we are before your desired time ({config.Status_update_time}).') else: - default_logger.debug(f'[Status Update] Skipped because disabled by config ({config.Send_me_a_status_update}) or Debug Mode is on ({config.Debug_mode}).') + try: + default_logger.debug(f'[Status Update] Skipped because in cooldown period until ({cooldowns["Staus_Report_cooldown"]}) or before defined time({config.Status_update_time}).') + except: + default_logger.warning(f'[Status Update] Something is wrong with the cooldowns["Staus_Report_cooldown"].') + else: + default_logger.debug(f'[Status Update] Skipped because disabled by config ({config.Send_me_a_status_update}) or Debug Mode is on ({config.Debug_mode}).') - except Exception as err: - print(err) - default_logger.warning(err) + # except: + # raise Exception + # except Exception as err: + # default_logger.warning(err) + + # else: # Write cooldowns to file Cooldown_class.write_cooldown(cooldowns) - + # Write all from current report_logger to array report_content = report_array.getvalue() - print(report_content) # Notify user about something that has been done if config.Send_me_a_report \ @@ -573,7 +1034,7 @@ def keep_safe(): if config.Notify_Gmail: Notifications.gmail_notification(f'{config.EMAIL_SUBJECT} Status:', status_update) - default_logger.debug(f'{datetime.now():%H:%M} [Script] Run successful. Runtime: {(time.time() - begin_time):.0f}s') + default_logger.debug(f'{datetime.now():%H:%M} [Script] Ran successful. Runtime: {(time.time() - begin_time):.0f}s') print(f'[Script] At {datetime.now():%H:%M}, ran successfully. Runtime: {(time.time() - begin_time):.0f}s') return True diff --git a/assets/Contact_addresses.py b/assets/Contact_addresses.py index 5033596..283898f 100644 --- a/assets/Contact_addresses.py +++ b/assets/Contact_addresses.py @@ -1,5 +1,8 @@ #!/usr/bin/python3 +# https://assets.terra.money/cw20/tokens.json +# https://assets.terra.money/cw20/contracts.json + class Contract_addresses: def contact_addresses(network): if network == 'MAINNET': @@ -12,12 +15,14 @@ def contact_addresses(network): 'Gov': 'terra1wh39swv7nq36pnefnupttm2nr96kz7jjddyt2x', 'Mint': 'terra1wfz7h3aqf4cjmjcvc6s8lxdhh7k30nkczyf0mj', 'Oracle': 'terra1t6xe0txzywdg85n6k8c960cuwgh6l8esw6lau9', - 'Staking': 'terra17f7zu97865jmknk7p2glqvxzhduk78772ezac5', + 'MirrorStaking': 'terra17f7zu97865jmknk7p2glqvxzhduk78772ezac5', 'Airdrop': 'terra1kalp2knjm4cs3f59ukr4hdhuuncp648eqrgshw', 'Limit Order': 'terra1zpr8tq3ts96mthcdkukmqq4y9lhw0ycevsnw89', 'Collateral Oracle': 'terra1pmlh0j5gpzh2wsmyd3cuk39cgh2gfwk6h5wy9j', 'Lock': 'terra169urmlm8wcltyjsrn7gedheh7dker69ujmerv2', 'Short Reward': 'terra16mlzdwqq5qs6a23250lq0fftke8v80sapc5kye', + 'Mirror MIR-UST Pair': 'terra1amv303y8kzxuegvurh0gug2xe9wkgj65enq2ux', + 'Mirror MIR-UST LP': 'terra17gjf2zehfvnyjtdgua9p9ygquk6gukxe7ucgwh', # mAssets https://docs.mirror.finance/networks#terra 'ANC' : 'terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76', 'aUST' : 'terra1hzh9vpxhsk8253se0vv5jj6etdvxu3nv8z07zu', @@ -64,9 +69,9 @@ def contact_addresses(network): 'specFarm': 'terra17hjvrkcwn3jk2qf69s5ldxx5rjccchu35assga', 'pylonFarm': 'terra1r3675psl7s2fe0sfh0vut5z4hrywgyyfdrzg95', 'specgov': 'terra1dpe4fmcz2jqk6t50plw0gqa2q3he2tj6wex5cl', - # TerraSwap + 'SpectrumStaking' : 'terra1fxwelge6mf5l6z0rjpylzcfq9w9tw2q7tewaf5', 'Spectrum SPEC-UST Pair': 'terra1tn8ejzw8kpuc87nu42f6qeyen4c7qy35tl8t20', - 'Terraswap MIR-UST Pair': 'terra1amv303y8kzxuegvurh0gug2xe9wkgj65enq2ux', + 'Spectrum SPEC-UST LP' : 'terra1y9kxxm97vu4ex3uy0rgdr5h2vt7aze5sqx7jyl', # Anchor 'bLunaHub': 'terra1mtwph2juhj0rvjz7dy92gvl6xvukaxu8rfv8ts', 'bLunaReward': 'terra17yap3mhph35pcwvhza38c2lkj7gzywzy05h7l0', @@ -105,17 +110,20 @@ def contact_addresses(network): 'Gov': 'terra12r5ghc6ppewcdcs3hkewrz24ey6xl7mmpk478s', 'Mint': 'terra1s9ehcjv0dqj2gsl72xrpp0ga5fql7fj7y3kq3w', 'Oracle': 'terra1uvxhec74deupp47enh7z5pk55f3cvcz8nj4ww9', - 'Staking': 'terra1a06dgl27rhujjphsn4drl242ufws267qxypptx', + 'MirrorStaking': 'terra1a06dgl27rhujjphsn4drl242ufws267qxypptx', 'Airdrop': 'terra1p6nvyw7vz3fgpy4nyh3q3vc09e65sr97ejxn2p', 'Limit Order': 'terra1vc4ch0z3n6c23f9uywzy5yqaj2gmpnam8qgge7', 'Collateral Oracle': 'terra1q3ls6u2glsazdeu7dxggk8d04elnvmsg0ung6n', 'Lock': 'terra1pcxghd4dyf950mcs0kmlp7lvnrjsnl6qlfldwj', + 'Mirror MIR-UST Pair': 'terra1cz6qp8lfwht83fh9xm9n94kj04qc35ulga5dl0', + 'Mirror MIR-UST LP': 'terra1zrryfhlrpg49quz37u90ck6f396l4xdjs5s08j', # mAssets https://docs.mirror.finance/networks#terra 'SPEC': 'terra1kvsxd94ue6f4rtchv2l6me5k07uh26s7637cza', 'MIR': 'terra10llyp6v3j3her8u3ce66ragytu45kcmd9asj3u', 'ANC': 'terra1747mad58h0w4y589y3sk84r5efqdev9q4r02pc', + 'aUST' : 'terra1ajt556dpzvjwl0kl5tzku3fc3p3knkg9mkv8jl', 'bETH': 'terra19mkj9nec6e3y5754tlnuz4vem7lzh4n0lc2s3l', - 'bLuna': 'terra1u0t35drzyy0mujj8rkdyzhe264uls4ug3wdp3x', + 'bLUNA': 'terra1u0t35drzyy0mujj8rkdyzhe264uls4ug3wdp3x', 'mAAPL': 'terra16vfxm98rxlc8erj4g0sj5932dvylgmdufnugk0', 'mDOT': 'terra1fs6c6y65c65kkjanjwvmnrfvnm2s58ph88t9ky', 'mGOOGL': 'terra1qg9ugndl25567u03jrr79xur2yk9d632fke3h2', @@ -141,9 +149,9 @@ def contact_addresses(network): 'specFarm': 'terra1cedx8gpvu7c4vzfadwmf3pewg2030fqgw4q3dl', 'pylonFarm': 'terra1hgjp2yjqe7ngzsx283tm7ch8xcsvk5c8mdj2tw', 'specgov': 'terra1x3l2tkkwzzr0qsnrpy3lf2cm005zxv7pun26x4', - # TerraSwap + 'SpectrumStaking' : 'terra15nwqmmmza9y643apneg0ddwt0ekk38qdevnnjt', 'Spectrum SPEC-UST Pair': 'terra15cjce08zcmempedxwtce2y44y2ayup8gww3txr', - 'Terraswap MIR-UST Pair': 'terra1cz6qp8lfwht83fh9xm9n94kj04qc35ulga5dl0', + 'Spectrum SPEC-UST LP' : 'terra1ntt4mdhr9lukayenntgltqppw4yy6hts7wr67d', # Anchor "bLunaHub": "terra1fflas6wv4snv8lsda9knvq2w0cyt493r8puh2e", "bLunaToken": "terra1u0t35drzyy0mujj8rkdyzhe264uls4ug3wdp3x", diff --git a/assets/Logging.py b/assets/Logging.py index 13db023..620205a 100644 --- a/assets/Logging.py +++ b/assets/Logging.py @@ -64,6 +64,7 @@ } class Logger: + if config.Debug_mode: print(f'Logger Class loaded.') def __init__(self): if not os.path.exists('./logs'): os.makedirs('logs') diff --git a/assets/Notifications.py b/assets/Notifications.py index 6505841..b4bf367 100644 --- a/assets/Notifications.py +++ b/assets/Notifications.py @@ -7,6 +7,7 @@ # from email.mime.text import MIMEText class Notifications: + if config.Debug_mode: print(f'Notifications Class loaded.') def slack_webhook(msg): slack_data = { "blocks": [ @@ -30,7 +31,7 @@ def slack_webhook(msg): 'Request to slack returned an error %s, the response is:\n%s' % (response.status_code, response.text) ) - except Exception: + except Exception: # Todo pass @@ -47,7 +48,7 @@ def telegram_notification(msg): 'Request to slack returned an error %s, the response is:\n%s' % (response.status_code, response.text) ) - except Exception: + except Exception: # Todo pass @@ -58,7 +59,7 @@ def email_notification(msg): txt_file.write(msg) os.system('cat One-stop-bot-email-temp-body.txt | mail -s "' + config.Email_subject + config.Email_address) - except Exception: + except Exception: # Todo pass def gmail_notification(subject, message): diff --git a/assets/Other.py b/assets/Other.py index f87903b..e69b1e6 100644 --- a/assets/Other.py +++ b/assets/Other.py @@ -1,7 +1,12 @@ #!/usr/bin/python3 +# Terra SKD +from terra_sdk.core.numeric import Dec + + # Other assets from assets.Logging import Logger +import B_Config as config # Other imports import json @@ -9,8 +14,8 @@ from datetime import datetime class Cooldown: - def __init__(self): - self.default_logger = Logger().default_logger + if config.Debug_mode: print(f'Cooldown Class loaded.') + default_logger = Logger().default_logger def write_cooldown(self, cooldowns): with open('X_Cooldowns.json', 'w') as fp: @@ -34,7 +39,7 @@ def read_cooldown(self): try: f = open('X_Cooldowns.json') cooldowns = json.load(f) - self.default_logger.debug(f'[Script] X_Cooldowns.json has been read: {cooldowns}') + self.default_logger.debug(f'[Script] X_Cooldowns.json existed and has been read: {cooldowns}') f.close for index in cooldowns: @@ -43,4 +48,39 @@ def read_cooldown(self): return cooldowns except: # If there is anything wrong with the X_Cooldowns.json, it will just give an empty dict. - return {} + return {} + +class Prettify: + if config.Debug_mode: print(f'Prettify Class loaded.') + def email_text_to_html(self): + # Todo + pass + + def value_convert_dec_to_float(self, input_value, human): + + if type(input_value) == Dec: + # If you need a bigger number than 1000000, then you are way too rich lol + if input_value > 1000000: + if human: + output_value = f'{float(input_value / 1000000):.2f}' + else: + output_value = input_value.__int__() + else: + output_value = f'{input_value.__float__():.2f}' + + return output_value + else: + return input_value + + def dict_value_convert_dec_to_float(self, input_value, human=False): + + # Maybe its a list of dict + if type(input_value) is list: + output_value = [] + for item in input_value: + output_value.append(dict((k, self.value_convert_dec_to_float(v, human)) for k, v in item.items())) + return output_value + + # If it is just a plain dict + elif type(input_value) is dict: + return dict((k, self.value_convert_dec_to_float(v, human)) for k, v in input_value.items()) \ No newline at end of file diff --git a/assets/Queries.py b/assets/Queries.py index 378a7c9..9c70310 100644 --- a/assets/Queries.py +++ b/assets/Queries.py @@ -1,11 +1,14 @@ #!/usr/bin/python3 # Terra SDK +import re from terra_sdk.core.coins import Coin from terra_sdk.core.numeric import Dec +from terra_sdk.exceptions import LCDResponseError # Other assets from assets.Terra import Terra +from assets.Logging import Logger import B_Config as config # Other imports @@ -13,74 +16,79 @@ from time import mktime import time import requests -from decimal import Decimal +import re -Terra_class = Terra() -account_address = Terra_class.account_address +account_address = Terra.account_address class Queries: - def __init__(self): + if config.Debug_mode: print(f'Queries Class loaded.') + default_logger = Logger().default_logger + def __init__(self): self.all_rates = self.get_all_rates() - def get_all_rates(self): - - all_rates = requests.get('https://api.extraterrestrial.money/v1/api/prices').json() - all_rates = {**all_rates.pop('prices'), **all_rates} - - return all_rates - def get_fee_estimation(self): - estimation = Terra_class.terra.treasury.tax_cap('uusd') - fee = int(estimation.to_data().get('amount')) - return int(fee) # returns the gas price in satoshis - means 1490000 for 1.49 UST - def get_ANC_rate(self): + estimation = Terra.terra.treasury.tax_cap('uusd') + fee = estimation.to_data().get('amount') + return Dec(fee) - if config.NETWORK == 'MAINNET': - SPEC_rate = self.all_rates['ANC']['price'] - else: - SPEC_rate = 1 - return SPEC_rate + def get_swap_price(self, token_UST_pair_address:str): - def get_MIR_rate(self): + # Get the terra swap price from the pool + # https://bombay-lcd.terra.dev/wasm/contracts/terra15cjce08zcmempedxwtce2y44y2ayup8gww3txr/store?query_msg={"pool":{}} - if config.NETWORK == 'MAINNET': - MIR_rate = self.all_rates['MIR']['price'] - else: - MIR_rate = 1 - return MIR_rate + query = { + "pool": {} + } - def get_SPEC_rate(self): + query_result = Terra.terra.wasm.contract_query(token_UST_pair_address, query) - if config.NETWORK == 'MAINNET': - SPEC_rate = self.all_rates['SPEC']['price'] - else: - SPEC_rate = 1 - return SPEC_rate + for asset in query_result['assets']: + + # If ['info']['token'] does not exists, the current asset is uusd + if asset['info'].get('token') is None: + UST_in_pool = Dec(asset['amount']) - def get_aUST_rate(self): + # Otherwise it is the token + else: + token_in_pool = Dec(asset['amount']) - if config.NETWORK == 'MAINNET': - aUST_rate = self.all_rates['aUST']['price'] - else: - query = { - "epoch_state": {}, - } - query_result = Terra_class.terra.wasm.contract_query(Terra_class.mmMarket, query) + Swap_price = UST_in_pool / token_in_pool - aUST_rate = Decimal(query_result['exchange_rate']) - return aUST_rate + return Dec(Swap_price) + def get_all_rates(self): - def get_uluna_rate(self): + all_rates:dict + all_rates = {} if config.NETWORK == 'MAINNET': - uluna_rate = self.all_rates['LUNA']['price'] + extraterrestrial_response = requests.get('https://api.extraterrestrial.money/v1/api/prices').json() + extraterrestrial_response = {**extraterrestrial_response.pop('prices'), **extraterrestrial_response} + # Those prices may be a bit out-dated 8.8451392 vs 8.79209 Delta of 0.6% + # Therefore this on is only for information. No swaps are evaluated based on this rates. + + # Rewrite dictionary, for example all_rates['ANC']['price'] to just all_rates['ANC'] + for k, v in extraterrestrial_response.items(): + all_rates[k] = Dec(v['price'] * 1000000) + else: - uluna_rate = Decimal(str(Terra_class.terra.market.swap_rate(Coin('uluna', 1000000), 'uusd')).replace('uusd', '')) / 1000000 + # The rates above are not availabe for the TESTNET, therefore + all_rates['LUNA'] = Dec(str(Terra.terra.market.swap_rate(Coin('uluna', 1000000), 'uusd')).replace('uusd', '')) - return uluna_rate + query = { + "epoch_state": {}, + } + query_result = Terra.terra.wasm.contract_query(Terra.mmMarket, query) + + all_rates['aUST'] = Dec(query_result['exchange_rate']) * 1000000 + + # Update ANC, MIR, SPEC as those prices are critical to be up-to-date + all_rates['MIR'] = Dec(self.get_swap_price(Terra.Mirror_MIR_UST_Pair) * 1000000) + all_rates['SPEC'] = Dec(self.get_swap_price(Terra.Spectrum_SPEC_UST_Pair) * 1000000) + all_rates['ANC'] = Dec(self.get_swap_price(Terra.Terraswap_ANC_UST_Pair) * 1000000) + return all_rates def get_luna_col_multiplier(self): @@ -90,118 +98,81 @@ def get_luna_col_multiplier(self): "asset": "uluna" } } - query_result = Terra_class.terra.wasm.contract_query(Terra_class.Collateral_Oracle, query) + query_result = Terra.terra.wasm.contract_query(Terra.Collateral_Oracle, query) - get_luna_col_multiplier = Decimal(query_result['multiplier']) + get_luna_col_multiplier = query_result['multiplier'] - return get_luna_col_multiplier + return Dec(get_luna_col_multiplier) def get_latest_block(self): - result = Terra_class.terra.tendermint.block_info() + result = Terra.terra.tendermint.block_info() height = result['block']['header']['height'] return int(height) - - def get_native_balance(self, denom): - native_balance = 0 - balance_native = Terra_class.terra.bank.balance(address=account_address) - try: - native_balance = str(balance_native[denom]).replace(denom, '') - except: - native_balance = 0 - - return Decimal(native_balance) / 1000000 - - - def get_aUST_balance(self): - - query = { - "balance": { - "address": account_address - }, - } - query_result = Terra_class.terra.wasm.contract_query(Terra_class.aTerra, query) - balance = query_result['balance'] - - return Decimal(balance) / 1000000 - - - def get_oracle_price_and_min_col_ratio(self, mAsset): - # Input: mAssets as List - # Outputs: Prices for mAssets as List - - # for mAsset in mAssets: - # Oracle Price - # https://tequila-fcd.terra.dev/wasm/contracts/terra1q3ls6u2glsazdeu7dxggk8d04elnvmsg0ung6n/store?query_msg={%22collateral_price%22:{%22asset%22:%22terra104tgj4gc3pp5s240a0mzqkhd3jzkn8v0u07hlf%22}} + def get_oracle_price_and_min_col_ratio(self, mAsset:str): + oracle_price_and_min_col_ratio:list query_oracle_price = { "collateral_price": { "asset": mAsset }, } - position_ids_result = Terra_class.terra.wasm.contract_query(Terra_class.Collateral_Oracle, query_oracle_price) - - # Minimal collateral ratio - # mBABA - # https://tequila-fcd.terra.dev/wasm/contracts/terra1s9ehcjv0dqj2gsl72xrpp0ga5fql7fj7y3kq3w/store?query_msg={"asset_config":{"asset_token":"terra15dr4ah3kha68kam7a907pje9w6z2lpjpnrkd06"}} + position_ids_result = Terra.terra.wasm.contract_query(Terra.Collateral_Oracle, query_oracle_price) query_oracle_price = { "asset_config": { "asset_token": mAsset }, } - min_col_ratio_result = Terra_class.terra.wasm.contract_query(Terra_class.Mint, query_oracle_price) + min_col_ratio_result = Terra.terra.wasm.contract_query(Terra.Mint, query_oracle_price) - oracle_price_and_min_col_ratio = [Decimal(position_ids_result['rate']), Decimal(min_col_ratio_result['min_collateral_ratio'])] + oracle_price_and_min_col_ratio = [Dec(position_ids_result['rate']), Dec(min_col_ratio_result['min_collateral_ratio'])] return oracle_price_and_min_col_ratio def Mirror_get_position_info(self): - # Input: - - # Output: List of all short positions incl. - # [[position_idx, collateral_amount_in_ust, shorted_asset_qty, mAsset_address, oracle_price, min_col_ratio, cur_col_ratio], [....]] + Mirror_position_info:list + Mirror_position_info= [] - # [position_idx, collateral_price, mAsset, - # https://tequila-fcd.terra.dev/wasm/contracts/terra1s9ehcjv0dqj2gsl72xrpp0ga5fql7fj7y3kq3w/store?query_msg={%22positions%22:{%22owner_addr%22:%20%22terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma%22}} - Mirror_position_info = [] query_position_ids = { "positions": { "owner_addr": account_address }, } - position_ids_result = Terra_class.terra.wasm.contract_query(Terra_class.Mint, query_position_ids) + position_ids_result = Terra.terra.wasm.contract_query(Terra.Mint, query_position_ids) for position in position_ids_result['positions']: # There are currently three tokens that can be used as collateral Luna, UST, aUST, so we need to find out which one is used for each position_idx. position_idx = position['idx'] - try: - # for aUST = terra1hzh9vpxhsk8253se0vv5jj6etdvxu3nv8z07zu/terra1ajt556dpzvjwl0kl5tzku3fc3p3knkg9mkv8jl - if position['collateral']['info']['token']['contract_addr'] == Terra_class.aTerra: - collateral_token_denom = 'aUST' - except: - # for uluna / uusd - # If this throws an exception it is because your collaterial is not in UST or Luna. Ignore that exception. + + # if denom exists, its means the collateral_token is either uusd or uluna + if 'native_token' in position['collateral']['info']: collateral_token_denom = position['collateral']['info']['native_token']['denom'] - + else: + if position['collateral']['info']['token']['contract_addr'] == Terra.aTerra: + collateral_token_denom = 'aUST' + else: + self.default_logger.warning(f'[Script] The collateral you have here is none of those: UST, aUST, LUNA. The bot cannot handle that.') + # This value is returned from the blockchain in-kind. - collateral_amount_in_kind = Decimal(position['collateral']['amount']) / 1000000 + collateral_amount_in_kind = Dec(position['collateral']['amount']) # As the mAsset is valued in UST, we convert the colateral_amount also into UST here. if collateral_token_denom == 'aUST': - collateral_amount_in_ust = collateral_amount_in_kind * Decimal(self.get_aUST_rate()) + collateral_amount_in_ust = collateral_amount_in_kind * self.all_rates['aUST'] / 1000000 elif collateral_token_denom == 'uluna': - collateral_amount_in_ust = collateral_amount_in_kind * Decimal(self.get_uluna_rate()) + collateral_amount_in_ust = collateral_amount_in_kind * self.all_rates['LUNAs'] / 1000000 elif collateral_token_denom == 'uusd': collateral_amount_in_ust = collateral_amount_in_kind - shorted_asset_qty = Decimal(position['asset']['amount']) / 1000000 + shorted_asset_qty = Dec(position['asset']['amount']) mAsset_address = position['asset']['info']['token']['contract_addr'] - try: - mAsset_symbol = Terra_class.rev_Contract_addresses[mAsset_address] - except: + if mAsset_address in Terra.rev_Contract_addresses.keys(): + mAsset_symbol = Terra.rev_Contract_addresses[mAsset_address] + else: mAsset_symbol = 'Not in assets.Contact_addresses.py' oracle_price_and_min_col_ratio = self.get_oracle_price_and_min_col_ratio(mAsset_address) @@ -211,14 +182,14 @@ def Mirror_get_position_info(self): # If the collateral is provided in UST or aUST the min_col_ratio is as received form the query. # if the colalteral is Luna it is luna_col_multiplier (4/3) of the min_col_ratio if collateral_token_denom == 'uluna': - min_col_ratio = oracle_price_and_min_col_ratio[1] * Decimal(self.get_luna_col_multiplier()) + min_col_ratio = oracle_price_and_min_col_ratio[1] * Dec(self.get_luna_col_multiplier()) else: min_col_ratio = oracle_price_and_min_col_ratio[1] cur_col_ratio = collateral_amount_in_ust / (oracle_price * shorted_asset_qty) - lower_trigger_ratio = min_col_ratio + Decimal(config.Mirror_lower_distance) - target_ratio = min_col_ratio + Decimal(config.Mirror_target_distance) - upper_trigger_ratio = min_col_ratio + Decimal(config.Mirror_upper_distance) + lower_trigger_ratio = min_col_ratio + Dec(config.Mirror_lower_distance) + target_ratio = min_col_ratio + Dec(config.Mirror_target_distance) + upper_trigger_ratio = min_col_ratio + Dec(config.Mirror_upper_distance) collateral_loss_to_liq = -(shorted_asset_amount * min_col_ratio / collateral_amount_in_ust) + 1 shorted_mAsset_gain_to_liq = (collateral_amount_in_ust / min_col_ratio / shorted_asset_amount) - 1 @@ -278,7 +249,7 @@ def Mirror_get_position_info(self): def sort_by_distance(elem): return elem['distance_to_min_col'] - # Sort positions by action (withdrawls first) + # Sort positions by action (withdrawals first) def sort_by_action(elem): return elem['action_to_be_executed'] @@ -289,8 +260,6 @@ def sort_by_action(elem): def get_claimable_MIR(self): - # Input: - - # Output: Returns the quantity of MIR that can be claimed claimable = 0 query = { @@ -299,21 +268,20 @@ def get_claimable_MIR(self): }, } - query_result = Terra_class.terra.wasm.contract_query(Terra_class.Staking, query) + query_result = Terra.terra.wasm.contract_query(Terra.MirrorStaking, query) # Sum up all claimable rewards for this account_address for reward in query_result['reward_infos']: - claimable += int(reward['pending_reward']) + claimable += Dec(reward['pending_reward']) - return Decimal(claimable) / 1000000 + return Dec(claimable) def get_claimable_SPEC(self): - # Input: - - # Output: Returns the quantity of SPEC that can be claimed - claimable_mirrorFarm = \ - claimable_anchorFarm = \ - claimable_specFarm = \ + claimable_SPEC_list:list + claimable_mirrorFarm = 0 + claimable_anchorFarm = 0 + claimable_specFarm = 0 claimable_pylonFarm = 0 latest_block = self.get_latest_block() @@ -325,11 +293,11 @@ def get_claimable_SPEC(self): "height": latest_block }, } - query_result_mirrorFarm = Terra_class.terra.wasm.contract_query(Terra_class.mirrorFarm, query) + query_result_mirrorFarm = Terra.terra.wasm.contract_query(Terra.mirrorFarm, query) # print(f'mirrorFarm: {query_result_mirrorFarm}') # Sum up all claimable rewards for this account_address for reward in query_result_mirrorFarm['reward_infos']: - claimable_mirrorFarm += int(reward['pending_spec_reward']) + claimable_mirrorFarm += Dec(reward['pending_spec_reward']) # Query for the Anchor related claimable SPEC query = { @@ -338,11 +306,11 @@ def get_claimable_SPEC(self): "height": latest_block }, } - query_result_anchorFarm = Terra_class.terra.wasm.contract_query(Terra_class.anchorFarm, query) + query_result_anchorFarm = Terra.terra.wasm.contract_query(Terra.anchorFarm, query) # print(f'anchorFarm: {query_result_anchorFarm}') # Sum up all claimable rewards for this account_address for reward in query_result_anchorFarm['reward_infos']: - claimable_anchorFarm += int(reward['pending_spec_reward']) + claimable_anchorFarm += Dec(reward['pending_spec_reward']) # Query for the Spec related claimable SPEC query = { @@ -351,11 +319,11 @@ def get_claimable_SPEC(self): "height": latest_block }, } - query_result_specFarm = Terra_class.terra.wasm.contract_query(Terra_class.specFarm, query) + query_result_specFarm = Terra.terra.wasm.contract_query(Terra.specFarm, query) # print(f'specFarm: {query_result_specFarm}') # Sum up all claimable rewards for this account_address for reward in query_result_specFarm['reward_infos']: - claimable_specFarm += int(reward['pending_spec_reward']) + claimable_specFarm += Dec(reward['pending_spec_reward']) # Query for the Pylon related claimable SPEC query = { @@ -364,26 +332,24 @@ def get_claimable_SPEC(self): "height": latest_block }, } - query_result_pylonFarm = Terra_class.terra.wasm.contract_query(Terra_class.pylonFarm, query) + query_result_pylonFarm = Terra.terra.wasm.contract_query(Terra.pylonFarm, query) # print(f'pylonFarm: {query_result_pylonFarm}') # Sum up all claimable rewards for this account_address for reward in query_result_pylonFarm['reward_infos']: - claimable_pylonFarm += int(reward['pending_spec_reward']) + claimable_pylonFarm += Dec(reward['pending_spec_reward']) # claimable_SPEC_dict = { - # "claimable_mirrorFarm": Decimal(claimable_mirrorFarm)/1000000, - # "claimable_anchorFarm": Decimal(claimable_anchorFarm)/1000000, - # "claimable_specFarm": Decimal(claimable_specFarm)/1000000, - # "claimable_pylonFarm": Decimal(claimable_pylonFarm)/1000000, + # "claimable_mirrorFarm": Dec(claimable_mirrorFarm)/1000000, + # "claimable_anchorFarm": Dec(claimable_anchorFarm)/1000000, + # "claimable_specFarm": Dec(claimable_specFarm)/1000000, + # "claimable_pylonFarm": Dec(claimable_pylonFarm)/1000000, # } claimable_SPEC_list = [ - Decimal( - +claimable_mirrorFarm \ - +claimable_anchorFarm\ - +claimable_specFarm \ - +claimable_pylonFarm - ) / 1000000, + +Dec(claimable_mirrorFarm) \ + +Dec(claimable_anchorFarm) \ + +Dec(claimable_specFarm) \ + +Dec(claimable_pylonFarm), claimable_mirrorFarm >0, claimable_anchorFarm >0, claimable_specFarm >0, @@ -394,9 +360,7 @@ def get_claimable_SPEC(self): def get_claimable_ANC(self): - # Input: - - # Output: Returns the quantity of ANC that can be claimed - claimable = 0 + latest_block = self.get_latest_block() query = { @@ -406,20 +370,19 @@ def get_claimable_ANC(self): } } - query_result = Terra_class.terra.wasm.contract_query(Terra_class.mmMarket, query) + query_result = Terra.terra.wasm.contract_query(Terra.mmMarket, query) - claimable = Decimal(query_result['pending_rewards']) / 1000000 + claimable = query_result['pending_rewards'] - return claimable + return Dec(claimable) - def Mirror_get_claimable_UST(self, Mirror_position_info): + def Mirror_get_claimable_UST(self, Mirror_position_info:list): + # Input: Mirror_position_info # Output: Returns the quantity of UST that can be claimed # https://docs.mirror.finance/contracts/lock#positionlockinfo - claimable = 0 - for position in Mirror_position_info: query = { @@ -428,119 +391,98 @@ def Mirror_get_claimable_UST(self, Mirror_position_info): } } - try: - - # Status code 500 means, that there is no unclaimed UST. If so, this exception can be ignored. - query_result = Terra_class.terra.wasm.contract_query(Terra_class.Lock, query) - - locked_amount = Decimal(query_result['locked_amount']) - unlock_time = Decimal(query_result['unlock_time']) - if unlock_time < int(datetime.utcnow().timestamp()): + try: + query_result = Terra.terra.wasm.contract_query(Terra.Lock, query) + locked_amount = Dec(query_result['locked_amount']) + unlock_time = Dec(query_result['unlock_time']) + if unlock_time < Dec(datetime.utcnow().timestamp()): claimable += locked_amount - - except: - # If a short position has already been claimed, this query will result in an error. We catch it here. - claimable = 0 + + except LCDResponseError as err: + # Status code 500 means, that there is no unclaimed UST. If so, this exception can be ignored + if err.response.status == 500: + claimable = 0 + else: + raise err - return Decimal(claimable) / 1000000 + return Dec(claimable) - def simulate_MIR_Swap(self, amount): - # Input: Amount of MIR - # Output: Value of input-MIR at current market price in UST - # https://fcd.terra.dev/wasm/contracts/terra1tn8ejzw8kpuc87nu42f6qeyen4c7qy35tl8t20/store?query_msg={"simulation":{"offer_asset":{"amount":"1000000","info":{"token":{"contract_addr":"terra1s5eczhe0h0jutf46re52x5z4r03c8hupacxmdr"}}}}} + def simulate_Token_Swap(self, token_amount:Dec, token_UST_pair_address:str, token_address:str): query = { "simulation": { "offer_asset": { - "amount": str(int(amount * 1000000)), + "amount": str(int(token_amount)), "info": { "token": { - "contract_addr": Terra_class.MIR_token + "contract_addr": token_address } } } } } - query_result = Terra_class.terra.wasm.contract_query(Terra_class.Terraswap_MIR_UST_Pair, query) - MIR_return = Decimal(query_result['return_amount']) / 1000000 - - return MIR_return + query_result = Terra.terra.wasm.contract_query(token_UST_pair_address, query) + UST_return = query_result['return_amount'] + return Dec(UST_return) - def simulate_SPEC_Swap(self, amount): - # Input: Amount of SPEC - # Output: Value of input-SPEC at current market price in UST - # https://fcd.terra.dev/wasm/contracts/terra1tn8ejzw8kpuc87nu42f6qeyen4c7qy35tl8t20/store?query_msg={"simulation":{"offer_asset":{"amount":"1000000","info":{"token":{"contract_addr":"terra1s5eczhe0h0jutf46re52x5z4r03c8hupacxmdr"}}}}} + def get_available_LP_token_for_withdrawal(self, token_farm_address:str, token_address:str): + + LP_token_available = 0 query = { - "simulation": { - "offer_asset": { - "amount": str(int(amount * 1000000)), - "info": { - "token": { - "contract_addr": Terra_class.SPEC_token - } - } - } + "reward_info": { + "staker_addr": account_address, } } - query_result = Terra_class.terra.wasm.contract_query(Terra_class.Spectrum_SPEC_UST_Pair, query) - SPEC_return = Decimal(query_result['return_amount']) / 1000000 + query_result = Terra.terra.wasm.contract_query(token_farm_address, query) - return SPEC_return + if not query_result == []: + for reward_info in query_result['reward_infos']: + if reward_info['asset_token'] == token_address: + LP_token_available = reward_info['bond_amount'] + return Dec(LP_token_available) - def simulate_ANC_Swap(self, amount): - # Input: Amount of ANC - # Output: Value of input-ANC at current market price in UST - query = { - "simulation": { - "offer_asset": { - "amount": str(int(amount * 1000000)), - "info": { - "token": { - "contract_addr": Terra_class.ANC_token - } - } - } - } - } - query_result = Terra_class.terra.wasm.contract_query(Terra_class.Terraswap_ANC_UST_Pair, query) - ANC_return = Decimal(query_result['return_amount']) / 1000000 + def get_UST_amount_for_LP_deposit(self, token_amount:Dec, token_UST_pair_address:str): - return ANC_return + Swap_price = self.get_swap_price(token_UST_pair_address) + tax_rate = Terra.terra.treasury.tax_rate() + UST_amount = token_amount * (Swap_price + tax_rate) + return Dec(UST_amount) - def Anchor_get_max_ltv_ratio(self): + def Anchor_get_max_ltv_ratio(self): + + max_ltv_ratio:dict max_ltv_ratio = {} query = { "whitelist": {}, } - query_result = Terra_class.terra.wasm.contract_query(Terra_class.mmOverseer, query) + query_result = Terra.terra.wasm.contract_query(Terra.mmOverseer, query) for elem in query_result['elems']: - max_ltv_ratio[elem['symbol']] = Decimal(elem['max_ltv']) + max_ltv_ratio[elem['symbol']] = Dec(elem['max_ltv']) return max_ltv_ratio def Anchor_get_borrow_info(self): - # Input: - - # Output: Collects, calculated all there is required to know for your Anchor debt + Anchor_debt_info:dict - max_ltv_ratio = Decimal(self.Anchor_get_max_ltv_ratio()['BETH']) + max_ltv_ratio = self.Anchor_get_max_ltv_ratio()['BETH'] query_msg_borrow_limit = { "borrow_limit": { "borrower": account_address }, } - borrow_limit_result = Terra_class.terra.wasm.contract_query(Terra_class.mmOverseer, query_msg_borrow_limit) + borrow_limit_result = Terra.terra.wasm.contract_query(Terra.mmOverseer, query_msg_borrow_limit) - borrow_limit = Decimal(borrow_limit_result['borrow_limit']) / 1000000 + borrow_limit = Dec(borrow_limit_result['borrow_limit']) # Check if you actually have some collateral in Anchor if borrow_limit > 0: @@ -550,58 +492,52 @@ def Anchor_get_borrow_info(self): "borrower": account_address }, } - query_msg_collateral_result = Terra_class.terra.wasm.contract_query(Terra_class.mmOverseer, query_msg_collateral) + query_msg_collateral_result = Terra.terra.wasm.contract_query(Terra.mmOverseer, query_msg_collateral) query_msg_loan = { "borrower_info": { - "borrower": account_address, - "block_height": self.get_latest_block() + "borrower": account_address }, } - loan_amount_result = Terra_class.terra.wasm.contract_query(Terra_class.mmMarket, query_msg_loan) + loan_amount_result = Terra.terra.wasm.contract_query(Terra.mmMarket, query_msg_loan) - loan_amount = Decimal(loan_amount_result['loan_amount']) / 1000000 + loan_amount = Dec(loan_amount_result['loan_amount']) collateral_dict = {} for collateral in query_msg_collateral_result['collaterals']: - collateral_dict[collateral[0]] = collateral[1] + collateral_dict[collateral[0]] = Dec(collateral[1]) - if collateral_dict.get(Terra_class.bETH_token) is not None: - amount_bETH_collateral = Decimal(collateral_dict[Terra_class.bETH_token]) / 1000000 + if collateral_dict.get(Terra.bETH_token) is not None: + amount_bETH_collateral = collateral_dict[Terra.bETH_token] else: amount_bETH_collateral = 0 - if collateral_dict.get(Terra_class.bLuna_token) is not None: - amount_bLuna_collateral = Decimal(collateral_dict[Terra_class.bLuna_token]) / 1000000 + if collateral_dict.get(Terra.bLuna_token) is not None: + amount_bLuna_collateral = collateral_dict[Terra.bLuna_token] else: amount_bLuna_collateral = 0 total_collateral_value = borrow_limit / max_ltv_ratio cur_col_ratio = loan_amount / borrow_limit * max_ltv_ratio - lower_trigger_ratio = max_ltv_ratio + Decimal(config.Anchor_lower_distance) - upper_trigger_ratio = max_ltv_ratio + Decimal(config.Anchor_upper_distance) + lower_trigger_ratio = max_ltv_ratio + Dec(config.Anchor_lower_distance) + upper_trigger_ratio = max_ltv_ratio + Dec(config.Anchor_upper_distance) distance_to_max_ltv = cur_col_ratio - max_ltv_ratio collateral_loss_to_liq = -(loan_amount / max_ltv_ratio / total_collateral_value) + 1 - if cur_col_ratio > lower_trigger_ratio and \ - config.Anchor_enable_auto_repay_of_debt: + if cur_col_ratio > lower_trigger_ratio and config.Anchor_enable_auto_repay_of_debt: action_to_be_executed = 'repay' # Calculate how much aUST to deposite to return to the desired ratio - amount_to_execute_in_ust = loan_amount - \ - (borrow_limit * (max_ltv_ratio + - config.Anchor_target_distance) / max_ltv_ratio) - elif cur_col_ratio < upper_trigger_ratio and \ - config.Anchor_enable_auto_borrow_UST: + amount_to_execute_in_ust = loan_amount - (borrow_limit * (max_ltv_ratio + Dec(config.Anchor_target_distance)) / max_ltv_ratio) + elif cur_col_ratio < upper_trigger_ratio and config.Anchor_enable_auto_borrow_UST: action_to_be_executed = 'borrow' # Calculate how much aUST to withdraw to return to the desired ratio - amount_to_execute_in_ust = ( - borrow_limit * (max_ltv_ratio + config.Anchor_target_distance) / max_ltv_ratio) - loan_amount + amount_to_execute_in_ust = (borrow_limit * (max_ltv_ratio + Dec(config.Anchor_target_distance)) / max_ltv_ratio) - loan_amount else: action_to_be_executed = 'none' amount_to_execute_in_ust = 0 - Anchor_debt_info = { + Anchor_debt_info = { 'loan_amount': loan_amount, 'amount_bETH_collateral': amount_bETH_collateral, 'amount_bLuna_collateral': amount_bLuna_collateral, @@ -634,28 +570,33 @@ def Anchor_get_borrow_info(self): return Anchor_debt_info - def get_status_of_tx(self, tx_hash): - # Input: Transaction hash - # Output: If the Transaction was successful returns True, otherwise the reason why it failed - + def get_status_of_tx(self, tx_hash, retry=0): + + if re.search("[A-F0-9]{64}", tx_hash) is None: + return tx_hash + if config.Disable_all_transaction_defs: if config.Return_failed_tx: return "Dummy reason for failed tx" else: return True - # Since we need to wait a bit for the transaction we add a delay here. That way we make sure that the transaction before had time to go through. - time.sleep(15) + time.sleep(5) try: - status = Terra_class.terra.tx.tx_info(tx_hash).code - if not status: + status = Terra.terra.tx.tx_info(tx_hash) + if status.code is None: + # Transaction successful return True else: - # If status 404 cannot be found, most likely the gas fee for the transaction before was too low. So it was never executed on Terra. - return Terra_class.terra.tx.tx_info(tx_hash).rawlog - except: - return 'Status query of tx failed!' + # Transaction failed + return status.rawlog + except LCDResponseError as err: + if err.response.status == 404 and retry < 3: + retry +=1 + self.get_status_of_tx(tx_hash, retry) + else: + return f'Transaction hash could not be found even after multiple retries.' def market_hours(self): @@ -670,11 +611,11 @@ def market_hours(self): query = { "price": { - "base_asset": Terra_class.mAAPL_token, + "base_asset": Terra.mAAPL_token, "quote_asset":"uusd" } } - query_result = Terra_class.terra.wasm.contract_query(Terra_class.Oracle, query) + query_result = Terra.terra.wasm.contract_query(Terra.Oracle, query) unix_last_price_update = query_result['last_updated_base'] unix_now = mktime(datetime.now().timetuple()) @@ -684,4 +625,42 @@ def market_hours(self): if time_difference < 120: # 2 min = 60*2 = 120 seconds return True else: - return False \ No newline at end of file + return False + + def get_native_balance(self, denom:str): + # Todo: Return a dict with all natives to be incl in the wallet_balance dict provided + + balance_native = Terra.terra.bank.balance(address=account_address).to_data() + for item in balance_native: + if item['denom'] == denom: + return Dec(item['amount']) + return 0 + + def get_non_native_balance(self, token_address): + # Todo: Return a dict with all natives to be incl in the wallet_balance dict provided + # curl 'https://bombay-mantle.terra.dev/' -H 'Accept-Encoding: gzip, deflate, br' -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Connection: keep-alive' -H 'DNT: 1' -H 'Origin: https://bombay-mantle.terra.dev' --data-binary '{"query":"# Write your query or mutation here\n{\n terra1v000amr8a59r88p33ec2kk9xqe047g7zzqqaf4: WasmContractsContractAddressStore(\n ContractAddress: \"terra1v000amr8a59r88p33ec2kk9xqe047g7zzqqaf4\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1u0t35drzyy0mujj8rkdyzhe264uls4ug3wdp3x: WasmContractsContractAddressStore(\n ContractAddress: \"terra1u0t35drzyy0mujj8rkdyzhe264uls4ug3wdp3x\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra19mkj9nec6e3y5754tlnuz4vem7lzh4n0lc2s3l: WasmContractsContractAddressStore(\n ContractAddress: \"terra19mkj9nec6e3y5754tlnuz4vem7lzh4n0lc2s3l\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1ajt556dpzvjwl0kl5tzku3fc3p3knkg9mkv8jl: WasmContractsContractAddressStore(\n ContractAddress: \"terra1ajt556dpzvjwl0kl5tzku3fc3p3knkg9mkv8jl\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1747mad58h0w4y589y3sk84r5efqdev9q4r02pc: WasmContractsContractAddressStore(\n ContractAddress: \"terra1747mad58h0w4y589y3sk84r5efqdev9q4r02pc\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra10llyp6v3j3her8u3ce66ragytu45kcmd9asj3u: WasmContractsContractAddressStore(\n ContractAddress: \"terra10llyp6v3j3her8u3ce66ragytu45kcmd9asj3u\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra16vfxm98rxlc8erj4g0sj5932dvylgmdufnugk0: WasmContractsContractAddressStore(\n ContractAddress: \"terra16vfxm98rxlc8erj4g0sj5932dvylgmdufnugk0\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1avryzxnsn2denq7p2d7ukm6nkck9s0rz2llgnc: WasmContractsContractAddressStore(\n ContractAddress: \"terra1avryzxnsn2denq7p2d7ukm6nkck9s0rz2llgnc\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1zeyfhurlrun6sgytqfue555e6vw2ndxt2j7jhd: WasmContractsContractAddressStore(\n ContractAddress: \"terra1zeyfhurlrun6sgytqfue555e6vw2ndxt2j7jhd\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra12saaecsqwxj04fn0jsv4jmdyp6gylptf5tksge: WasmContractsContractAddressStore(\n ContractAddress: \"terra12saaecsqwxj04fn0jsv4jmdyp6gylptf5tksge\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1qk0cd8576fqf33paf40xy3rt82p7yluwtxz7qx: WasmContractsContractAddressStore(\n ContractAddress: \"terra1qk0cd8576fqf33paf40xy3rt82p7yluwtxz7qx\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra15dr4ah3kha68kam7a907pje9w6z2lpjpnrkd06: WasmContractsContractAddressStore(\n ContractAddress: \"terra15dr4ah3kha68kam7a907pje9w6z2lpjpnrkd06\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1csr22xvxs6r3gkjsl7pmjkmpt39mwjsrm0e2r8: WasmContractsContractAddressStore(\n ContractAddress: \"terra1csr22xvxs6r3gkjsl7pmjkmpt39mwjsrm0e2r8\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1qre9crlfnulcg0m68qqywqqstplgvrzywsg3am: WasmContractsContractAddressStore(\n ContractAddress: \"terra1qre9crlfnulcg0m68qqywqqstplgvrzywsg3am\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1ys4dwwzaenjg2gy02mslmc96f267xvpsjat7gx: WasmContractsContractAddressStore(\n ContractAddress: \"terra1ys4dwwzaenjg2gy02mslmc96f267xvpsjat7gx\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra14gq9wj0tt6vu0m4ec2tkkv4ln3qrtl58lgdl2c: WasmContractsContractAddressStore(\n ContractAddress: \"terra14gq9wj0tt6vu0m4ec2tkkv4ln3qrtl58lgdl2c\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra104tgj4gc3pp5s240a0mzqkhd3jzkn8v0u07hlf: WasmContractsContractAddressStore(\n ContractAddress: \"terra104tgj4gc3pp5s240a0mzqkhd3jzkn8v0u07hlf\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1qg9ugndl25567u03jrr79xur2yk9d632fke3h2: WasmContractsContractAddressStore(\n ContractAddress: \"terra1qg9ugndl25567u03jrr79xur2yk9d632fke3h2\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra13myzfjdmvqkama2tt3v5f7quh75rv78w8kq6u6: WasmContractsContractAddressStore(\n ContractAddress: \"terra13myzfjdmvqkama2tt3v5f7quh75rv78w8kq6u6\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra19dl29dpykvzej8rg86mjqg8h63s9cqvkknpclr: WasmContractsContractAddressStore(\n ContractAddress: \"terra19dl29dpykvzej8rg86mjqg8h63s9cqvkknpclr\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1p50j2k5vyw3q2tgywqvxyz59z8csh9p7x8dk5m: WasmContractsContractAddressStore(\n ContractAddress: \"terra1p50j2k5vyw3q2tgywqvxyz59z8csh9p7x8dk5m\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1qhkjjlqq2lyf2evzserdaqx55nugksjqdpxvru: WasmContractsContractAddressStore(\n ContractAddress: \"terra1qhkjjlqq2lyf2evzserdaqx55nugksjqdpxvru\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1374w7fkm7tqhd9dt2r5shjk8ly2kum443uennt: WasmContractsContractAddressStore(\n ContractAddress: \"terra1374w7fkm7tqhd9dt2r5shjk8ly2kum443uennt\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1anw5z9u5l35vxhhqljuygmkupwmafcv0m86kum: WasmContractsContractAddressStore(\n ContractAddress: \"terra1anw5z9u5l35vxhhqljuygmkupwmafcv0m86kum\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra19jdmle3zl99gugmptx8auckc9c2xw7nspyxjvx: WasmContractsContractAddressStore(\n ContractAddress: \"terra19jdmle3zl99gugmptx8auckc9c2xw7nspyxjvx\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra12s2h8vlztjwu440khpc0063p34vm7nhu25w4p9: WasmContractsContractAddressStore(\n ContractAddress: \"terra12s2h8vlztjwu440khpc0063p34vm7nhu25w4p9\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1djnlav60utj06kk9dl7defsv8xql5qpryzvm3h: WasmContractsContractAddressStore(\n ContractAddress: \"terra1djnlav60utj06kk9dl7defsv8xql5qpryzvm3h\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra18yx7ff8knc98p07pdkhm3u36wufaeacv47fuha: WasmContractsContractAddressStore(\n ContractAddress: \"terra18yx7ff8knc98p07pdkhm3u36wufaeacv47fuha\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra14vmf4tzg23fxnt9q5wavlp4wtvzzap82hdq402: WasmContractsContractAddressStore(\n ContractAddress: \"terra14vmf4tzg23fxnt9q5wavlp4wtvzzap82hdq402\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1hvmzhnhxnyhjfnctntnn49a35w6hvygmxvjt7q: WasmContractsContractAddressStore(\n ContractAddress: \"terra1hvmzhnhxnyhjfnctntnn49a35w6hvygmxvjt7q\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1fdkfhgk433tar72t4edh6p6y9rmjulzc83ljuw: WasmContractsContractAddressStore(\n ContractAddress: \"terra1fdkfhgk433tar72t4edh6p6y9rmjulzc83ljuw\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra15t9afkpj0wnh8m74n8n2f8tspkn7r65vnru45s: WasmContractsContractAddressStore(\n ContractAddress: \"terra15t9afkpj0wnh8m74n8n2f8tspkn7r65vnru45s\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1nslem9lgwx53rvgqwd8hgq7pepsry6yr3wsen4: WasmContractsContractAddressStore(\n ContractAddress: \"terra1nslem9lgwx53rvgqwd8hgq7pepsry6yr3wsen4\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1ax7mhqahj6vcqnnl675nqq2g9wghzuecy923vy: WasmContractsContractAddressStore(\n ContractAddress: \"terra1ax7mhqahj6vcqnnl675nqq2g9wghzuecy923vy\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1fucmfp8x4mpzsydjaxyv26hrkdg4vpdzdvf647: WasmContractsContractAddressStore(\n ContractAddress: \"terra1fucmfp8x4mpzsydjaxyv26hrkdg4vpdzdvf647\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1z0k7nx0vl85hwpv3e3hu2cyfkwq07fl7nqchvd: WasmContractsContractAddressStore(\n ContractAddress: \"terra1z0k7nx0vl85hwpv3e3hu2cyfkwq07fl7nqchvd\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra18gphn8r437p2xmjpw7a79hgsglf5y4t0x7s5ee: WasmContractsContractAddressStore(\n ContractAddress: \"terra18gphn8r437p2xmjpw7a79hgsglf5y4t0x7s5ee\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra18py95akdje8q8aaukhx65dplh9342m0j884wt4: WasmContractsContractAddressStore(\n ContractAddress: \"terra18py95akdje8q8aaukhx65dplh9342m0j884wt4\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1090l5p5v794dpyzr07da72cyexhuc4zag5cuer: WasmContractsContractAddressStore(\n ContractAddress: \"terra1090l5p5v794dpyzr07da72cyexhuc4zag5cuer\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1jr9s6cx4j637fctkvglrclvrr824vu3r2rrvj7: WasmContractsContractAddressStore(\n ContractAddress: \"terra1jr9s6cx4j637fctkvglrclvrr824vu3r2rrvj7\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1jyunclt6juv6g7rw0dltlr0kgaqtpq4quvyvu3: WasmContractsContractAddressStore(\n ContractAddress: \"terra1jyunclt6juv6g7rw0dltlr0kgaqtpq4quvyvu3\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1lqm5tutr5xcw9d5vc4457exa3ghd4sr9mzwdex: WasmContractsContractAddressStore(\n ContractAddress: \"terra1lqm5tutr5xcw9d5vc4457exa3ghd4sr9mzwdex\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1kvsxd94ue6f4rtchv2l6me5k07uh26s7637cza: WasmContractsContractAddressStore(\n ContractAddress: \"terra1kvsxd94ue6f4rtchv2l6me5k07uh26s7637cza\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1s8s39cnse493rzkmyr95esa44chc6vgztdm7gh: WasmContractsContractAddressStore(\n ContractAddress: \"terra1s8s39cnse493rzkmyr95esa44chc6vgztdm7gh\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1ykagvyzdmj3jcxkhavy7l84qs66haf7akqfrkc: WasmContractsContractAddressStore(\n ContractAddress: \"terra1ykagvyzdmj3jcxkhavy7l84qs66haf7akqfrkc\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1juwtwk5qymhz7s3hn0vx6tkqst54ud6wfjknvp: WasmContractsContractAddressStore(\n ContractAddress: \"terra1juwtwk5qymhz7s3hn0vx6tkqst54ud6wfjknvp\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra18xfqhtfaz2su55zmurmh02ng9lnhw0xnyplvln: WasmContractsContractAddressStore(\n ContractAddress: \"terra18xfqhtfaz2su55zmurmh02ng9lnhw0xnyplvln\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1eq0xqc88ceuvw2ztz2a08200he8lrgvnplrcst: WasmContractsContractAddressStore(\n ContractAddress: \"terra1eq0xqc88ceuvw2ztz2a08200he8lrgvnplrcst\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n terra1dy9kmlm4anr92e42mrkjwzyvfqwz66un00rwr5: WasmContractsContractAddressStore(\n ContractAddress: \"terra1dy9kmlm4anr92e42mrkjwzyvfqwz66un00rwr5\"\n QueryMsg: \"{\\\"balance\\\":{\\\"address\\\":\\\"terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma\\\"}}\"\n ) {\n Height\n Result\n __typename\n }\n}\n"}' --compressed + # https://bombay-fcd.terra.dev/wasm/contracts/terra10llyp6v3j3her8u3ce66ragytu45kcmd9asj3u/store?query_msg={%22balance%22:{%22address%22:%22terra1h0ujhwfx9wxt9lgpk5vrzutctt3k2cue9z3qma%22}} + + query = { + "balance": { + "address": account_address + } + } + query_result = Terra.terra.wasm.contract_query(token_address, query) + non_native_balance = Dec(query_result['balance']) + + return non_native_balance + + + def get_wallet_balances(self): + wallet_balances:dict + wallet_balances = { + 'UST' : Dec(self.get_native_balance('uusd')), + 'aUST' : Dec(self.get_non_native_balance(Terra.aUST_token)), + 'LUNA' : Dec(self.get_native_balance('uluna')), + 'MIR' : Dec(self.get_non_native_balance(Terra.MIR_token)), + 'SPEC' : Dec(self.get_non_native_balance(Terra.SPEC_token)), + 'ANC' : Dec(self.get_non_native_balance(Terra.ANC_token)), + } + + return wallet_balances \ No newline at end of file diff --git a/assets/Terra.py b/assets/Terra.py index 6bfbdb5..aa7d7ba 100644 --- a/assets/Terra.py +++ b/assets/Terra.py @@ -3,6 +3,7 @@ # Terra SDK from terra_sdk.client.lcd import LCDClient from terra_sdk.key.mnemonic import MnemonicKey +from terra_sdk.exceptions import LCDResponseError # Other assets from assets.Contact_addresses import Contract_addresses @@ -13,73 +14,85 @@ def get_terra_gas_prices(retry=0): - if retry > 2: - raise Exception(f'Maximum retries on fetching gas prices from https://fcd.terra.dev/v1/txs/gas_prices reached.') - try: r = requests.get("https://fcd.terra.dev/v1/txs/gas_prices") r.raise_for_status() if r.status_code == 200: return r.json() - except: - retry = retry + 1 - print(retry) - return get_terra_gas_prices(retry) - + + except requests.ConnectionError as err: + if retry < 1: + retry +=1 + get_terra_gas_prices(retry) + else: + raise err + except requests.ConnectTimeout as err: + if retry < 1: + retry +=1 + get_terra_gas_prices(retry) + else: + raise err + terra_gas_prices = get_terra_gas_prices() -# https://terra-money.github.io/terra-sdk-python/core_modules/wasm.html class Terra: - def __init__(self): - if config.NETWORK == 'MAINNET': - self.chain_id = 'columbus-5' - self.public_node_url = 'https://lcd.terra.dev' - self.tx_look_up = f'https://finder.terra.money/{self.chain_id}/tx/' - self.contact_addresses = Contract_addresses.contact_addresses(network='MAINNET') - self.rev_Contract_addresses = Contract_addresses.rev_contact_addresses(self.contact_addresses) + if config.Debug_mode: print(f'Terra Class loaded.') + if config.NETWORK == 'MAINNET': + chain_id = 'columbus-5' + public_node_url = 'https://lcd.terra.dev' + tx_look_up = f'https://finder.terra.money/{chain_id}/tx/' + contact_addresses = Contract_addresses.contact_addresses(network='MAINNET') + rev_Contract_addresses = Contract_addresses.rev_contact_addresses(contact_addresses) - else: - self.chain_id = 'bombay-12' - self.public_node_url = 'https://bombay-lcd.terra.dev' - self.tx_look_up = f'https://finder.terra.money/{self.chain_id}/tx/' - self.contact_addresses = Contract_addresses.contact_addresses(network='bombay-12') - self.rev_Contract_addresses = Contract_addresses.rev_contact_addresses(self.contact_addresses) + else: + chain_id = 'bombay-12' + public_node_url = 'https://bombay-lcd.terra.dev' + tx_look_up = f'https://finder.terra.money/{chain_id}/tx/' + contact_addresses = Contract_addresses.contact_addresses(network='bombay-12') + rev_Contract_addresses = Contract_addresses.rev_contact_addresses(contact_addresses) + + + # Contracts required + mmMarket = contact_addresses['mmMarket'] + mmOverseer = contact_addresses['mmOverseer'] + aTerra = contact_addresses['aTerra'] + Mint = contact_addresses['Mint'] + Collateral_Oracle = contact_addresses['Collateral Oracle'] + MirrorStaking = contact_addresses['MirrorStaking'] + Lock = contact_addresses['Lock'] + Oracle = contact_addresses['Oracle'] - # Contracts required - self.mmMarket = self.contact_addresses['mmMarket'] - self.mmOverseer = self.contact_addresses['mmOverseer'] - self.aTerra = self.contact_addresses['aTerra'] - self.Mint = self.contact_addresses['Mint'] - self.Collateral_Oracle = self.contact_addresses['Collateral Oracle'] - self.Staking = self.contact_addresses['Staking'] - self.Lock = self.contact_addresses['Lock'] - self.Oracle = self.contact_addresses['Oracle'] + mirrorFarm = contact_addresses['mirrorFarm'] + anchorFarm = contact_addresses['anchorFarm'] + specFarm = contact_addresses['specFarm'] + pylonFarm = contact_addresses['pylonFarm'] + specgov = contact_addresses['specgov'] - self.mirrorFarm = self.contact_addresses['mirrorFarm'] - self.anchorFarm = self.contact_addresses['anchorFarm'] - self.specFarm = self.contact_addresses['specFarm'] - self.pylonFarm = self.contact_addresses['pylonFarm'] - self.specgov = self.contact_addresses['specgov'] + Mirror_MIR_UST_Pair = contact_addresses['Mirror MIR-UST Pair'] + Mirror_MIR_UST_LP = contact_addresses['Mirror MIR-UST LP'] + Spectrum_SPEC_UST_Pair = contact_addresses['Spectrum SPEC-UST Pair'] + Spectrum_SPEC_UST_LP = contact_addresses['Spectrum SPEC-UST LP'] + Terraswap_ANC_UST_Pair = contact_addresses['terraswapAncUstPair'] + Terraswap_ANC_UST_LP = contact_addresses['terraswapAncUstLPToken'] + SpectrumStaking = contact_addresses['SpectrumStaking'] - self.Terraswap_MIR_UST_Pair = self.contact_addresses['Terraswap MIR-UST Pair'] - self.Spectrum_SPEC_UST_Pair = self.contact_addresses['Spectrum SPEC-UST Pair'] - self.Terraswap_ANC_UST_Pair = self.contact_addresses['terraswapAncUstPair'] + SPEC_token = contact_addresses['SPEC'] + MIR_token = contact_addresses['MIR'] + ANC_token = contact_addresses['ANC'] + bETH_token = contact_addresses['bETH'] + bLuna_token = contact_addresses['bLUNA'] + mAAPL_token = contact_addresses['mAAPL'] + aUST_token = contact_addresses['aUST'] - self.SPEC_token = self.contact_addresses['SPEC'] - self.MIR_token = self.contact_addresses['MIR'] - self.ANC_token = self.contact_addresses['ANC'] - self.bETH_token = self.contact_addresses['bETH'] - self.bLuna_token = self.contact_addresses['bLUNA'] - self.mAAPL_token = self.contact_addresses['mAAPL'] + failed_tx_hash = contact_addresses['failed_tx_hash'] + success_tx_hash = contact_addresses['success_tx_hash'] - self.failed_tx_hash = self.contact_addresses['failed_tx_hash'] - self.success_tx_hash = self.contact_addresses['success_tx_hash'] + terra = LCDClient( + chain_id=chain_id, + url=public_node_url, + gas_prices=terra_gas_prices['uusd']+"uusd", + gas_adjustment=1.6) - self.terra = LCDClient( - chain_id=self.chain_id, - url=self.public_node_url, - gas_prices=terra_gas_prices['uusd']+"uusd", - gas_adjustment=1.6) - self.mk = MnemonicKey(mnemonic=config.mnemonic) # Desire wallet via passphrase - self.wallet = self.terra.wallet(self.mk) # Define what wallet to use - self.account_address = self.wallet.key.acc_address # Account Add \ No newline at end of file + mk = MnemonicKey(mnemonic=config.mnemonic) # Desire wallet via passphrase + wallet = terra.wallet(mk) # Define what wallet to use + account_address = wallet.key.acc_address # Account Add \ No newline at end of file diff --git a/assets/Transactions.py b/assets/Transactions.py index 94bf864..2daf29c 100644 --- a/assets/Transactions.py +++ b/assets/Transactions.py @@ -4,78 +4,88 @@ from terra_sdk.core.coins import Coins from terra_sdk.core.coins import Coin from terra_sdk.core.wasm import MsgExecuteContract +from terra_sdk.core.numeric import Dec +from terra_sdk.exceptions import LCDResponseError # Other assets from assets.Terra import Terra from assets.Queries import Queries -import B_Config as config from assets.Logging import Logger -from decimal import Decimal +import B_Config as config -Terra_class = Terra() Queries_class = Queries() -account_address = Terra_class.account_address -fee_estimation = Queries_class.get_fee_estimation() +account_address = Terra.account_address +fee_estimation = Dec(Queries_class.get_fee_estimation()) class Transaction: - - def __init__(self): - self.default_logger = Logger().default_logger + if config.Debug_mode: print(f'Transactions Class loaded.') + default_logger = Logger().default_logger # For debugging only if config.Disable_all_transaction_defs: if config.Return_failed_tx: - def Mirror_deposit_collateral_for_position(self, idx, collateral_amount_in_kind, denom): return Terra_class.failed_tx_hash - def Anchor_borrow_more_UST(self, amount): return Terra_class.failed_tx_hash - def Anchor_deposit_UST_for_Earn(self, amount): return Terra_class.failed_tx_hash - def Anchor_repay_debt_UST(self, amount): return Terra_class.failed_tx_hash - def Anchor_withdraw_UST_from_Earn(self, amount, denom): return Terra_class.failed_tx_hash - def claim_ANC(self): return Terra_class.failed_tx_hash - def claim_MIR(self): return Terra_class.failed_tx_hash - def claim_SPEC(self, claimable_SPEC): return Terra_class.failed_tx_hash - def Mirror_claim_unlocked_UST(self, Mirror_position_info): return Terra_class.failed_tx_hash - def Mirror_withdraw_collateral_for_position(self, idx, collateral_amount_in_kind, denom): return Terra_class.failed_tx_hash - def sell_ANC(self, amount): return Terra_class.failed_tx_hash - def sell_MIR(self, amount): return Terra_class.failed_tx_hash - def sell_SPEC(self, amount): return Terra_class.failed_tx_hash - def Mirror_deposit_collateral_for_position(self, idx, collateral_amount_in_kind, denom): return Terra_class.failed_tx_hash + def Mirror_deposit_collateral_for_position(self, idx, collateral_amount_in_kind, denom): return Terra.failed_tx_hash + def Anchor_borrow_more_UST(self, amount): return Terra.failed_tx_hash + def Anchor_deposit_UST_for_Earn(self, amount): return Terra.failed_tx_hash + def Anchor_repay_debt_UST(self, amount): return Terra.failed_tx_hash + def Anchor_withdraw_UST_from_Earn(self, amount, denom): return Terra.failed_tx_hash + def claim_ANC(self): return Terra.failed_tx_hash + def claim_MIR(self): return Terra.failed_tx_hash + def claim_SPEC(self, claimable_SPEC_list): return Terra.failed_tx_hash + def Mirror_claim_unlocked_UST(self, Mirror_position_info): return Terra.failed_tx_hash + def Mirror_withdraw_collateral_for_position(self, idx, collateral_amount_in_kind, denom): return Terra.failed_tx_hash + def sell_ANC(self, amount): return Terra.failed_tx_hash + def sell_MIR(self, amount): return Terra.failed_tx_hash + def sell_SPEC(self, amount): return Terra.failed_tx_hash + def Mirror_deposit_collateral_for_position(self, idx, collateral_amount_in_kind, denom): return Terra.failed_tx_hash + def deposit_ANC_in_pool(self, amount_token, amount_UST): return Terra.failed_tx_hash + def deposit_MIR_in_pool(self, amount_token, amount_UST): return Terra.failed_tx_hash + def deposit_SPEC_in_pool(self, amount_token, amount_UST): return Terra.failed_tx_hash + def withdraw_MIR_from_pool(self, amount_lp_token): return Terra.failed_tx_hash + def withdraw_SPEC_from_pool(self, amount_lp_token): return Terra.failed_tx_hash + def withdraw_ANC_from_pool(self, amount_lp_token): return Terra.failed_tx_hash + else: - def Mirror_deposit_collateral_for_position(self, idx, collateral_amount_in_kind, denom): return Terra_class.success_tx_hash - def Anchor_borrow_more_UST(self, amount): return Terra_class.success_tx_hash - def Anchor_deposit_UST_for_Earn(self, amount): return Terra_class.success_tx_hash - def Anchor_repay_debt_UST(self, amount): return Terra_class.success_tx_hash - def Anchor_withdraw_UST_from_Earn(self, amount, denom): return Terra_class.success_tx_hash - def claim_ANC(self): return Terra_class.success_tx_hash - def claim_MIR(self): return Terra_class.success_tx_hash - def claim_SPEC(self, claimable_SPEC): return Terra_class.success_tx_hash - def Mirror_claim_unlocked_UST(self, Mirror_position_info): return Terra_class.success_tx_hash - def Mirror_withdraw_collateral_for_position(self, idx, collateral_amount_in_kind, denom): return Terra_class.success_tx_hash - def sell_ANC(self, amount): return Terra_class.success_tx_hash - def sell_MIR(self, amount): return Terra_class.success_tx_hash - def sell_SPEC(self, amount): return Terra_class.success_tx_hash - def Mirror_deposit_collateral_for_position(self, idx, collateral_amount_in_kind, denom): return Terra_class.success_tx_hash + def Mirror_deposit_collateral_for_position(self, idx, collateral_amount_in_kind, denom): return Terra.success_tx_hash + def Anchor_borrow_more_UST(self, amount): return Terra.success_tx_hash + def Anchor_deposit_UST_for_Earn(self, amount): return Terra.success_tx_hash + def Anchor_repay_debt_UST(self, amount): return Terra.success_tx_hash + def Anchor_withdraw_UST_from_Earn(self, amount, denom): return Terra.success_tx_hash + def claim_ANC(self): return Terra.success_tx_hash + def claim_MIR(self): return Terra.success_tx_hash + def claim_SPEC(self, claimable_SPEC_list): return Terra.success_tx_hash + def Mirror_claim_unlocked_UST(self, Mirror_position_info): return Terra.success_tx_hash + def Mirror_withdraw_collateral_for_position(self, idx, collateral_amount_in_kind, denom): return Terra.success_tx_hash + def sell_ANC(self, amount): return Terra.success_tx_hash + def sell_MIR(self, amount): return Terra.success_tx_hash + def sell_SPEC(self, amount): return Terra.success_tx_hash + def Mirror_deposit_collateral_for_position(self, idx, collateral_amount_in_kind, denom): return Terra.success_tx_hash + def deposit_ANC_in_pool(self, amount_token, amount_UST): return Terra.success_tx_hash + def deposit_MIR_in_pool(self, amount_token, amount_UST): return Terra.success_tx_hash + def deposit_SPEC_in_pool(self, amount_token, amount_UST): return Terra.success_tx_hash + def withdraw_MIR_from_pool(self, amount_lp_token): return Terra.success_tx_hash + def withdraw_SPEC_from_pool(self, amount_lp_token): return Terra.success_tx_hash + def withdraw_ANC_from_pool(self, amount_lp_token): return Terra.success_tx_hash else: - def Mirror_deposit_collateral_for_position(self, idx, collateral_amount_in_kind, denom): - - amount = int(collateral_amount_in_kind * 1000000) - + def Mirror_deposit_collateral_for_position(self, idx:str, collateral_amount_in_kind:Dec, denom:str): + collateral_amount_in_kind = int(collateral_amount_in_kind) # Depending on the denom, hence the token that was used for the collateral we need to change this tx's details if denom == 'aUST': - contract=Terra_class.aTerra + contract=Terra.aTerra execute_msg={ "send": { - "amount": str(amount), - "contract": Terra_class.Mint, + "amount": str(collateral_amount_in_kind), + "contract": Terra.Mint, "msg": { "deposit": { "position_idx": idx, "collateral": { - "amount": str(amount), + "amount": str(collateral_amount_in_kind), "info": { "token": { - "contract_addr": Terra_class.aTerra, + "contract_addr": Terra.aTerra, } } } @@ -87,15 +97,15 @@ def Mirror_deposit_collateral_for_position(self, idx, collateral_amount_in_kind, else: # Luna and UST are natively supported - coin = Coin(denom, int(collateral_amount_in_kind * 1000000)).to_data() + coin = Coin(denom, collateral_amount_in_kind).to_data() coins = Coins.from_data([coin]) - contract = Terra_class.Mint + contract = Terra.Mint execute_msg={ "deposit": { "position_idx": idx, "collateral": { - "amount": str(amount), + "amount": str(collateral_amount_in_kind), "info": { "native_token": { "denom": denom @@ -109,23 +119,21 @@ def Mirror_deposit_collateral_for_position(self, idx, collateral_amount_in_kind, return txhash - def Mirror_withdraw_collateral_for_position(self, idx, collateral_amount_in_kind, denom): - - amount = int(collateral_amount_in_kind * 1000000) - + def Mirror_withdraw_collateral_for_position(self, idx:str, collateral_amount_in_kind:Dec, denom:str): + collateral_amount_in_kind = int(collateral_amount_in_kind) # Depending on the denom, hence the token that was used for the collateral we need to change this tx's details if denom == 'aUST': # https://finder.terra.money/tequila-0004/tx/10C1B6310DA5B16F5EE96F3535B99C9CD7DC5D696054D547C32A54F2317E930B - contract=Terra_class.aTerra + contract=Terra.aTerra execute_msg={ "withdraw": { "position_idx": idx, "collateral": { - "amount": str(amount), + "amount": str(collateral_amount_in_kind), "info": { "token": { - "contract_addr": Terra_class.aTerra + "contract_addr": Terra.aTerra } } } @@ -134,15 +142,15 @@ def Mirror_withdraw_collateral_for_position(self, idx, collateral_amount_in_kind coins=Coins() else: - coin = Coin('uusd', int(collateral_amount_in_kind * 1000000)).to_data() + coin = Coin('uusd', collateral_amount_in_kind).to_data() coins = Coins.from_data([coin]) - contract=Terra_class.Mint + contract=Terra.Mint execute_msg={ "withdraw": { "position_idx": idx, "collateral": { - "amount": str(amount), + "amount": str(collateral_amount_in_kind), "info": { "native_token": { "denom": "uusd" @@ -156,7 +164,7 @@ def Mirror_withdraw_collateral_for_position(self, idx, collateral_amount_in_kind return txhash - def Mirror_claim_unlocked_UST(self, Mirror_position_info): + def Mirror_claim_unlocked_UST(self, Mirror_position_info:dict): def position_idxs_to_be_claimed(): position_idxs_to_be_claimed = [] @@ -164,7 +172,7 @@ def position_idxs_to_be_claimed(): position_idxs_to_be_claimed.append(position['position_idx']) return position_idxs_to_be_claimed - contract=Terra_class.Lock + contract=Terra.Lock execute_msg={ "unlock_position_funds": { "positions_idx": position_idxs_to_be_claimed() @@ -178,7 +186,7 @@ def position_idxs_to_be_claimed(): def claim_MIR(self): - contract=Terra_class.Staking + contract=Terra.MirrorStaking execute_msg={ "withdraw": {} } @@ -188,73 +196,73 @@ def claim_MIR(self): return txhash - def claim_SPEC(self, claimable_SPEC): + def claim_SPEC(self, claimable_SPEC_list:list): - # claimable_SPEC contains from index 1 True/False if there is any Spec to claim: + # claimable_SPEC_list contains from index 1 True/False if there is any Spec to claim: # claimable_mirrorFarm # claimable_anchorFarm - # claimable_specFarm + # claimable_SPEC_listFarm # claimable_pylonFarm - send = [] + message = [] - send.append( + message.append( MsgExecuteContract( sender=account_address, - contract=Terra_class.specgov, + contract=Terra.specgov, execute_msg={ "mint": {} } )) - if claimable_SPEC[1] == True: - send.append( + if claimable_SPEC_list[1] == True: + message.append( MsgExecuteContract( # Withdraw SPEC from your mirrorFarm sender=account_address, - contract=Terra_class.mirrorFarm, + contract=Terra.mirrorFarm, execute_msg={ "withdraw": {} } )) - if claimable_SPEC[2] == True: - send.append( + if claimable_SPEC_list[2] == True: + message.append( MsgExecuteContract( # Withdraw SPEC from your anchorFarm sender=account_address, - contract=Terra_class.anchorFarm, + contract=Terra.anchorFarm, execute_msg={ "withdraw": {} } )) - if claimable_SPEC[3] == True: - send.append( + if claimable_SPEC_list[3] == True: + message.append( MsgExecuteContract( # Withdraw SPEC from your specFarm sender=account_address, - contract=Terra_class.specFarm, + contract=Terra.specFarm, execute_msg={ "withdraw": {} } )) - if claimable_SPEC[4] == True: - send.append( + if claimable_SPEC_list[4] == True: + message.append( MsgExecuteContract( # Withdraw SPEC from your pylonfarm sender=account_address, - contract=Terra_class.pylonFarm, + contract=Terra.pylonFarm, execute_msg={ "withdraw": {} } )) - sendtx = Terra_class.wallet.create_and_sign_tx(send) - result = Terra_class.terra.tx.broadcast(sendtx) + sendtx = Terra.wallet.create_and_sign_tx(message, memo='Terra One-Stop-Bot by realKibou') + result = Terra.terra.tx.broadcast(sendtx) return result.txhash def claim_ANC(self): - contract=Terra_class.mmMarket + contract=Terra.mmMarket execute_msg={ "claim_rewards": {} } @@ -264,15 +272,14 @@ def claim_ANC(self): return txhash - def sell_MIR(self, amount): + def sell_MIR(self, amount:Dec): + amount = int(amount) - # https://docs.terraswap.io/docs/howto/swap/ - - contract=Terra_class.MIR_token + contract=Terra.MIR_token execute_msg={ "send": { - "contract": Terra_class.Terraswap_MIR_UST_Pair, - "amount": str(int(amount * 1000000)), + "contract": Terra.Mirror_MIR_UST_Pair, + "amount": str(amount), "msg": "eyJzd2FwIjp7fX0=" } } @@ -282,14 +289,14 @@ def sell_MIR(self, amount): return txhash - def sell_SPEC(self, amount): - # https://docs.terraswap.io/docs/howto/swap/ + def sell_SPEC(self, amount:Dec): + amount = int(amount) - contract=Terra_class.SPEC_token + contract=Terra.SPEC_token execute_msg={ "send": { - "contract": Terra_class.Spectrum_SPEC_UST_Pair, - "amount": str(int(amount * 1000000)), + "contract": Terra.Spectrum_SPEC_UST_Pair, + "amount": str(amount), "msg": "eyJzd2FwIjp7fX0=" } } @@ -300,14 +307,14 @@ def sell_SPEC(self, amount): return txhash - def sell_ANC(self, amount): - # https://docs.terraswap.io/docs/howto/swap/ + def sell_ANC(self, amount:Dec): + amount = int(amount) - contract=Terra_class.ANC_token + contract=Terra.ANC_token execute_msg={ "send": { - "contract": Terra_class.Terraswap_ANC_UST_Pair, - "amount": str(int(amount * 1000000)), + "contract": Terra.Terraswap_ANC_UST_Pair, + "amount": str(amount), "msg": "eyJzd2FwIjp7fX0=" } } @@ -318,17 +325,17 @@ def sell_ANC(self, amount): return txhash - def Anchor_deposit_UST_for_Earn(self, amount): + def Anchor_deposit_UST_for_Earn(self, amount:Dec): # Depoit a bit less, to have some UST for tx feess - amount = int(amount * 1000000 - fee_estimation * config.Safety_multiple_on_transaction_fees) + amount = int(amount - fee_estimation * config.Safety_multiple_on_transaction_fees) if amount > 0: coin = Coin('uusd', amount).to_data() coins = Coins.from_data([coin]) - contract=Terra_class.mmMarket + contract=Terra.mmMarket execute_msg={ "deposit_stable": {} } @@ -337,21 +344,21 @@ def Anchor_deposit_UST_for_Earn(self, amount): return txhash else: - self.default_logger.warning(f'[Anchor Deposit] YOU NEED TO ACT! Amount to deposit is lower than the gas fees ({amount}). Check your settings in B_Config.py') - return Terra_class.failed_tx_hash # ! I return a random but failed transaction here. It is not yours, it is just so the bot continues + self.default_logger.warning(f'[Anchor Deposit] YOU NEED TO ACT! Amount to deposit is lower than the gas fees ({(amount.__float__()/1000000):.2f}). Check your settings in B_Config.py') + return Terra.failed_tx_hash # * I return a random but failed transaction here. It is not your transaction, it is just so the bot continues + + def Anchor_withdraw_UST_from_Earn(self, amount:Dec, denom:str): - def Anchor_withdraw_UST_from_Earn(self, amount, denom): + amount = int(amount + config.Safety_multiple_on_transaction_fees * fee_estimation) # Convert amount UST into aUST for withdrawl and add a bit more for fees if denom == 'UST': - amount = amount / Queries_class.get_aUST_rate() + amount = int(amount / Queries_class.all_rates['aUST']) - amount = int(amount * 1000000) - - contract=Terra_class.aTerra + contract=Terra.aTerra execute_msg={ "send": { - "contract": Terra_class.mmMarket, + "contract": Terra.mmMarket, "amount": str(amount), "msg": "eyJyZWRlZW1fc3RhYmxlIjp7fX0="} } @@ -361,17 +368,17 @@ def Anchor_withdraw_UST_from_Earn(self, amount, denom): return txhash - def Anchor_repay_debt_UST(self, amount): + def Anchor_repay_debt_UST(self, amount:Dec): # Deduct the fee incl safety so there is still some UST left - amount = int(amount * 1000000 - fee_estimation * config.Safety_multiple_on_transaction_fees) + amount = int(amount - fee_estimation * config.Safety_multiple_on_transaction_fees) if amount > 0: coin = Coin('uusd', amount).to_data() coins = Coins.from_data([coin]) - contract=Terra_class.mmMarket + contract=Terra.mmMarket execute_msg={ "repay_stable": {} } @@ -380,17 +387,17 @@ def Anchor_repay_debt_UST(self, amount): return txhash else: - self.default_logger.warning(f'[Anchor Repay] YOU NEED TO ACT! Amount to deposit is lower than the gas fees ({amount}). Check your settings in B_Config.py') - return Terra_class.failed_tx_hash # ! I return a random but failed transaction here. It is not yours, it is just so the bot continues + self.default_logger.warning(f'[Anchor Repay] YOU NEED TO ACT! Amount to deposit is lower than the gas fees ({(amount/1000000):.2f}). Check your settings in B_Config.py') + return Terra.failed_tx_hash # * I return a random but failed transaction here. It is not yours, it is just so the bot continues - def Anchor_borrow_more_UST(self, amount): + def Anchor_borrow_more_UST(self, amount:Dec): - amount = int(amount * 1000000 + fee_estimation * config.Safety_multiple_on_transaction_fees) + amount = int(amount + fee_estimation * config.Safety_multiple_on_transaction_fees) - contract=Terra_class.mmMarket + contract=Terra.mmMarket execute_msg={ "borrow_stable": { - "borrow_amount": f'{amount}' + "borrow_amount": str(amount) } } @@ -399,10 +406,290 @@ def Anchor_borrow_more_UST(self, amount): txhash = self.execute_transaction(contract, execute_msg, coins) return txhash - def execute_transaction(self, contract, execute_msg, coins): + def deposit_MIR_in_pool(self, amount_token:Dec, amount_UST:Dec): + + amount_token = int(amount_token) + amount_UST = int(amount_UST) + message = [] + + message.append( + MsgExecuteContract( + sender=account_address, + contract=Terra.MIR_token, + execute_msg={ + "increase_allowance": { + "amount": str(amount_token), # Amount of MIR to be deposited + "spender": Terra.SpectrumStaking # SPEC Staking-Contract + } + } + )) + + + coin = Coin('uusd', amount_UST).to_data() + coins = Coins.from_data([coin]) + + message.append( + MsgExecuteContract( + sender=account_address, + contract=Terra.SpectrumStaking, + execute_msg={ + "bond": { + "assets": [ + { + "info": { + "token": { + "contract_addr": Terra.MIR_token + } + }, + # Amount of MIR to be deposited + "amount": str(amount_token) + }, + { + "info": { + "native_token": { + "denom": "uusd" + } + }, + "amount": str(amount_UST) # Amount of UST to be deposited + } + ], + "contract": Terra.mirrorFarm, + "compound_rate": "1", # 1 means Auto compounding + "slippage_tolerance": "0.1" + } + }, + coins=coins + )) + + sendtx = Terra.wallet.create_and_sign_tx(message, memo='Terra One-Stop-Bot by realKibou') + result = Terra.terra.tx.broadcast(sendtx) + + return result.txhash + + def deposit_SPEC_in_pool(self, amount_token:Dec, amount_UST:Dec): + + amount_UST = int(amount_UST) + amount_token = int(amount_token) + message = [] + + message.append( + MsgExecuteContract( + sender=account_address, + contract=Terra.SPEC_token, + execute_msg={ + "increase_allowance": { + "amount": str(amount_token), # Amount of SPEC to be deposited + "spender": Terra.SpectrumStaking #SPEC Staking-Contract + } + } + )) + + coin = Coin('uusd', amount_UST).to_data() + coins = Coins.from_data([coin]) + + message.append( + MsgExecuteContract( + sender=account_address, + contract=Terra.SpectrumStaking, + execute_msg={ + "bond": { + "assets": [ + { + "info": { + "token": { + "contract_addr": Terra.SPEC_token + } + }, + "amount": str(amount_token) # Amount of ANC to be deposited + }, + { + "info": { + "native_token": { + "denom": "uusd" + } + }, + "amount": str(amount_UST) # Amount of UST to be deposited + } + ], + "contract": Terra.specFarm, + "compound_rate": "1", # 1 means Auto compounding + "slippage_tolerance": "0.1" + } + }, + coins=coins + )) + + sendtx = Terra.wallet.create_and_sign_tx(message, memo='Terra One-Stop-Bot by realKibou') + result = Terra.terra.tx.broadcast(sendtx) + + return result.txhash + + def deposit_ANC_in_pool(self, amount_token:Dec, amount_UST:Dec): + amount_UST = int(amount_UST) + amount_token = int(amount_token) + message = [] + + message.append( + MsgExecuteContract( + sender=account_address, + contract=Terra.ANC_token, + execute_msg={ + "increase_allowance": { + "amount": str(amount_token), # Amount of ANC to be deposited + "spender": Terra.SpectrumStaking #SPEC Staking-Contract + } + } + )) + + coin = Coin('uusd', amount_UST).to_data() + coins = Coins.from_data([coin]) + + message.append( + MsgExecuteContract( + sender=account_address, + contract=Terra.SpectrumStaking, + execute_msg={ + "bond": { + "assets": [ + { + "info": { + "token": { + "contract_addr": Terra.ANC_token + } + }, + "amount": str(amount_token) # Amount of ANC to be deposited + }, + { + "info": { + "native_token": { + "denom": "uusd" + } + }, + "amount": str(amount_UST) # Amount of UST to be deposited + } + ], + "contract": Terra.anchorFarm, + "compound_rate": "1", # 1 means Auto compounding + "slippage_tolerance": "0.1" + } + }, + coins=coins + )) + + sendtx = Terra.wallet.create_and_sign_tx(message, memo='Terra One-Stop-Bot by realKibou') + result = Terra.terra.tx.broadcast(sendtx) + + return result.txhash + + def withdraw_MIR_from_pool(self, amount_lp_token:Dec): + + amount_lp_token = str(int(amount_lp_token)) + message = [] + + message.append( + MsgExecuteContract( + sender=account_address, + contract=Terra.mirrorFarm, + execute_msg={ + "unbond": { + "amount": amount_lp_token, + "asset_token": Terra.MIR_token + } + }, + coins=Coins() + )) + + message.append( + MsgExecuteContract( + sender=account_address, + contract=Terra.Mirror_MIR_UST_LP, + execute_msg={ + "send": { + "msg": "eyJ3aXRoZHJhd19saXF1aWRpdHkiOnt9fQ==", + "amount": amount_lp_token, + "contract": Terra.Mirror_MIR_UST_Pair + } + }, + coins=Coins() + )) + + sendtx = Terra.wallet.create_and_sign_tx(message, memo='Terra One-Stop-Bot by realKibou') + result = Terra.terra.tx.broadcast(sendtx) + + return result.txhash - # Todo: If error 504 (timeout), try again. + def withdraw_SPEC_from_pool(self, amount_lp_token:Dec): + amount_lp_token = str(int(amount_lp_token)) + message = [] + + message.append( + MsgExecuteContract( + sender=account_address, + contract=Terra.specFarm, + execute_msg={ + "unbond": { + "amount": amount_lp_token, + "asset_token": Terra.SPEC_token + } + } + )) + + message.append( + MsgExecuteContract( + sender=account_address, + contract=Terra.Spectrum_SPEC_UST_LP, + execute_msg={ + "send": { + "msg": "eyJ3aXRoZHJhd19saXF1aWRpdHkiOnt9fQ==", + "amount": amount_lp_token, + "contract": Terra.Spectrum_SPEC_UST_Pair + } + }, + )) + + sendtx = Terra.wallet.create_and_sign_tx(message, memo='Terra One-Stop-Bot by realKibou') + result = Terra.terra.tx.broadcast(sendtx) + + return result.txhash + + def withdraw_ANC_from_pool(self, amount_lp_token:Dec): + + amount_lp_token = str(int(amount_lp_token)) + + message = [] + + message.append( + MsgExecuteContract( + sender=account_address, + contract=Terra.anchorFarm, + execute_msg={ + "unbond": { + "amount": amount_lp_token, + "asset_token": Terra.ANC_token + } + } + )) + + message.append( + MsgExecuteContract( + sender=account_address, + contract=Terra.Terraswap_ANC_UST_LP, + execute_msg={ + "send": { + "msg": "eyJ3aXRoZHJhd19saXF1aWRpdHkiOnt9fQ==", + "amount": amount_lp_token, + "contract": Terra.Terraswap_ANC_UST_Pair + } + }, + )) + + sendtx = Terra.wallet.create_and_sign_tx(message, memo='Terra One-Stop-Bot by realKibou') + result = Terra.terra.tx.broadcast(sendtx) + + return result.txhash + + def execute_transaction(self, contract:str, execute_msg:list, coins:Coins): try: message = MsgExecuteContract( sender=account_address, @@ -411,13 +698,19 @@ def execute_transaction(self, contract, execute_msg, coins): coins=coins, ) - transaction = Terra_class.wallet.create_and_sign_tx( + transaction = Terra.wallet.create_and_sign_tx( msgs=[message], memo='Terra One-Stop-Bot by realKibou', ) - result = Terra_class.terra.tx.broadcast(transaction) + result = Terra.terra.tx.broadcast(transaction) + # print(result) + # if result.code is None: + # # Transaction was successful + # return result.txhash + # else: + # # Well, what else? + # pass return result.txhash - - except Exception as err: - self.default_logger.warning(err) \ No newline at end of file + except LCDResponseError as err: + return f'Execution of tx failed with: {err}' \ No newline at end of file diff --git a/readme.md b/readme.md index 29bc272..c85a597 100644 --- a/readme.md +++ b/readme.md @@ -10,7 +10,7 @@ If this bot is helpful to you and helps maximize your gainz, feel free to donate *Special thanks to unl1k3ly as his bot taught me what I needed to know. Thanks Terra, Mirror, Spectrum, Anchor team and the Terra Community!* -## How to pick the right mAsset for your strategy! +## How to pick the right mAsset for your strategy!? I found there are many calculations out there. But most are just wrong. They do not consider volatility or the most important factor hodl time. So I made 2x overly detailed calculation that I base my decisions on. I consider this valuable for you, even if you do not run the Terra-One-Stop-Bot. @@ -24,56 +24,68 @@ Decision Help Min Values: https://docs.google.com/spreadsheets/d/1U9jd5rarvWwbeu - Gives you a basis to make your decision what minimum deposits, withdraws, sell quantities, etc. to set for the Terra-One-Stop-Bot. ## What this One-Stop-Bot does -1. Claims and sells your unclaimed MIR, SPEC, ANC tokens -2. Claims unlocked UST on Mirror -3. Repays debt at Anchor if your LTV requires it -4. Borrows more UST from Anchor if you LTV allows it -5. Deposits UST (from sale of MIR, SPEC, ANC and Borrow) in Anchor Earn to get more aUST -6. Checks each of your shorted positions whether they are below or above your defined limits. - * If above: It will withdraw aUST to return to your defined ratio - * If below: It will deposit more aUST to return to your defined ratio -7. Sends you an update via Slack, Telegram or Email -8. Runs the bot at your defined intervals -9. Runs in debug mode -10. Logs information for you -11. Other stuff +1. Withdraws your MIR, SPEC, ANC from your LP tokens +2. Claims your unclaimed MIR, SPEC, ANC tokens +3. Claims unlocked UST on Mirror +4. Sells your MIR, SPEC, ANC tokens +5. Deposits your MIR, SPEC, ANC tokens into corresponding LP +6. Repays debt at Anchor if your LTV requires it +7. Borrows more UST from Anchor if you LTV allows it +8. Deposits UST (from sale of MIR, SPEC, ANC and Borrow) in Anchor Earn to get more aUST +9. Deposits collateral in your short positions +10. Withdraws collateral from your short positions +11. Sends you an update via Slack, Telegram or Email +12. Runs at your defined intervals +13. Runs in debug mode +14. Logs information for you +15. Other stuff *Due to the order of which the functions are executed, the priority is on a repayment of debt to Anchor rather than depositing more aUST into your shorts on Mirror, as crypto is more volatile than the legacy stock market.* ## What can be configured -*Almost* **everything** can be configured in the `B_config.py`. -1. Sells your unclaimed MIR, SPEC tokens - * `XXX_claim_and_sell_token` True/False sale of SPEC, MIR, ANC (SPEC gets claimed from all your farms Mirror, Anchor, Pylon and Spectrum) - * `XXX_min_price` Define a minimum price for SPEC, MIR, ANC - * `XXX_min_total_value` Define a minimum sales value (= price of token * amount to sell) for SPEC, MIR, ANC -2. Claims unlocked UST on Mirror +I made the One-Stop-Bot as much configureable as possible. You can configure what you like in the `B_config.py`. This order here is also the logical flow of the bot. +0. Setup + * `XXX_min_price` Define a minimum prices for SPEC, MIR, ANC to trigger a sale + * `XXX_min_total_value` Define a minimum value (= price of token * amount to sell) for SPEC, MIR, ANC to be acted on (sale or deposit) +1. Withdraws your MIR, SPEC, ANC from your LP tokens + * `XXX_withdraw_and_sell_if_min_price_is_reached` True/False withdraw of your token and UST from LP to sell if **BOTH** `XXX_min_price` **AND** `XXX_min_total_value` is exceeded +2. Claims your unclaimed MIR, SPEC, ANC tokens + * `XXX_claim_and_sell_token` True/False sale of SPEC, MIR, ANC (SPEC gets claimed from all your farms Mirror, Anchor, Pylon and Spectrum) if **BOTH** `XXX_min_price` **AND** `XXX_min_total_value` is exceeded + * `XXX_claim_and_deposit_in_LP`True/False deposit of SPEC, MIR, ANC to the corresponding LP if **ONLY** `XXX_min_total_value` is exceeded +3. Claims unlocked UST on Mirror * `Mirror_claim_unlocked_UST` True/False claim of unlocked UST * `Mirror_min_amount_UST_to_claim` Define a minimum of unlocked UST to be claimed -3. Repays debt at Anchor if your LTV requires it +4. Sells your MIR, SPEC, ANC tokens + * For each token there can be only a sell or deposit allowed. +5. Deposits your MIR, SPEC, ANC tokens into corresponding LP + * For each token there can be only a sell or deposit allowed. +6. Repays debt at Anchor if your LTV requires it * `Anchor_enable_auto_repay_of_debt` True/False auto repayment of debt * `Anchor_enable_withdraw_of_deposited_UST` True/False allowance to withdraw UST from Anchor Earn to repay debt * `Anchor_enable_partially_repay_if_not_enough_UST_in_wallet` True/False of partial debt repayment (withdraw all deposited UST on Anchor Earn + all UST available in wallet) * `Anchor_lower_distance` Define lower_distance from maximal ltv ratio below a repayment will be executed * `Anchor_target_distance`Define target_distance from maximal ltv ratio that is restored when repay debt/borrow more UST * `Anchor_min_repay_limit` Define minimum debt repayment limit -4. Borrows more UST from Anchor if you LTV allows it - * `Anchor_enable_deposit_borrowed_UST` True/False auto borrow of more UST +7. Borrows more UST from Anchor if you LTV allows it + * `Anchor_enable_auto_borrow_UST` True/False auto borrow of more UST * `Anchor_upper_distance`Define upper_distance from maximal ltv ratio above more UST will be borrowed * `Anchor_min_borrow_limit` Define minimum borrow limit -5. Deposits UST (from sale of MIR, SPEC, ANC and Borrow) in Anchor Earn to get more aUST - * `Anchor_enable_deposit_borrowed_UST` True/False enable deposit of freshly gained UST (from the sale of SPEC, MIR & Mirror claim) into Anchor Earn - * `Anchor_min_deposit_amount` Define minimum UST amount to deposit -6. Checks each of your shorted positions + * `Anchor_borrow_cooldown` Define cooldown period in days for the auto borrow function +8. Deposits UST (from sale of MIR, SPEC, ANC and Borrow) in Anchor Earn to get more aUST + * `Anchor_Earn_enable_deposit_UST` True/False enable deposit of freshly gained UST (from the sale of SPEC, MIR & Mirror claim) into Anchor Earn + * `Anchor_Earn_min_deposit_amount` Define minimum UST amount to deposit + * `Anchor_Earn_min_balance_to_keep_in_wallet` This this bot also deposits token in LP, you should have a UST balance in your wallet. +9. Deposits collateral in your short positions * `Mirror_enable_deposit_collateral` True/False deposit of collateral (Luna, UST, aUST supported) * `Mirror_lower_distance` Define lower_distance from minimal ratio below collateral will be deposited * `Mirror_target_distance` Define target_distance from minimal ratio that is restored when depoit/withdraw collateral * `Mirror_min_deposit_limit_in_UST` Define minimum deposit limit in UST +10. Withdraws collateral from your short positions * `Mirror_enable_withdraw_collateral` True/False withdraw of collateral * `Mirror_upper_distance` Define upper_distance from minimal ratio above collateral will be withdrawn - * `Anchor_borrow_cooldown` Define cooldown period in days for the auto borrow function * `Mirror_min_withdraw_limit_in_UST` Define minimum withdraw limit in UST * `Mirror_withdraw_cooldown` Define cooldown period in days for the auto withdraw function -7. Sends you a report on Telegram, Slack and/or Email if something has been done. Also writes logs into ./logs and sends you a status update if you want. +11. Sends you a report on Telegram, Slack and/or Email if something has been done. Also writes logs into ./logs and sends you a status update if you want. * `Send_me_a_report` True/False prepares a summary of what has happened, if something has happened. Always includes WARNINGs and ERRORs. * `Notify_Slack` True/False notifications to be received on Slack * `Notify_Telegram` True/False notifications to be received on Telegram @@ -81,28 +93,28 @@ Decision Help Min Values: https://docs.google.com/spreadsheets/d/1U9jd5rarvWwbeu * `Send_me_a_status_update` True/False if you want to receive a status update anyway depending on your `Status_update_frequency` * `Status_update_frequency` Define in what intervals (hours) you want to receive a status update * `Status_update_time` Define at what time you want to receive the status update -8. Runs the bot at your defined intervals +12. Runs the bot at your defined intervals * `Run_interval_for_Scheduler` Define the frequency how often the scheduler should run the bot -9. Debug +13. Debug * `Debug_mode` True/False debug mode for default.log * `Disable_all_transaction_defs` True/False disables all transaction functions, by returning a fake transaction hash * `Return_failed_tx` True/False if you want that transaction to be a failed transaction hash -10. Logging +14. Logging * `Logging_detail` Define what level of detail each log shall show -11. Other stuff +15. Other stuff * `Safety_multiple_on_transaction_fees` Safety multiple on transaction fees - * I also added an Excel sheet for you, to help you decide what minimum values you want to set for your claim & sell strategy as well as for the (not yet implemented) deposit SPEC, MIR, ANC into pools strategy. ## What the One-Stop-Bot does NOT do: - Withdraws any UST from Anchor Borrow to deposit that new UST collateral on Mirror. - Deposits any UST to Anchor Earn to deposit that new aUST as collateral on Mirror. - Sells, buys, swaps any Luna to deposit it as collateral on Mirror. - Uses withdrawn aUST or UST from Mirror to repay your Anchor Borrow debt (if you run the One-Stop-Bot often enough of course it will loop and eventually repay that debt). -- If you withdraw pool rewards, sell them, claim UST etc. and it is still not enough UST to exceed the `config.Anchor_min_deposit_amount` that UST will just remain in your wallet. They will NOT be "remembered" for the next run of the One-Stop-Bot. +- If you withdraw pool rewards, sell them, claim UST etc. and it is still not enough UST to exceed the `config.Anchor_Earn_min_deposit_amount` that UST will just remain in your wallet. They will NOT be "remembered" for the next run of the One-Stop-Bot. - The bot currently only supports UST, aUST and Luna as collateral on Mirror (you really should only use aUST anyway). -## Very important remarks! -- This bot is quite heavy, so do not run it too short intervals. It currently has a runtime of around 1 min. Depending on your internet connection. +## ⚠️ Very important remarks! +- This bot is quite heavy, so do not run it too short intervals. It currently has a runtime of around 1-2 min. Depending on your internet connection and how often you run it (more often, means less to do in one run, so less runtime). +- Watch your UST balance, as this bot is doing transactions, hence drains your UST balance. - Use this bot at your own risk. I have done my best to check it, but program bugs & human bugs happen and I am not financial advisor. - This bot can be used with the Testnet. I strongly recommend playing on the Testnet or with `Disable_all_transaction_defs` set to True first, before letting it manage your funds for real. Here you can get free UST, LUNA etc: https://faucet.terra.money/. - Since the LTV/min ratios on Mirror and Anchor are defined exactly opposite each other, it may gets confusing to set the `lower_distance`, `target_distance`, `upper_distance`. I wrote some explanations, but make sure you take time to understand it. @@ -150,7 +162,6 @@ To send emails from your Google account you need to get a `GMAIL_APP_PASSWORD`. 5. Copy the app password, it will be in a yellow box and looks like: "cjut fanq prdo diby". ## Under development (in desc priority) -- Deposit in SPEC-UST and MIR-UST Pool instead of selling until min price of SPEC, MIR, ANC is reached and then sell it (I think it gets to complicated...). - HTML Status Report (function is there, just not formatted properly). - Run Mirror withdrawals before repay of Anchor Borrow to make use of that available aUST - Build a front end.