convert_tokens_multi

Function

def convert_tokens_multi(account, multi_address, token0_address, token1_address, iterations, attempts=18):
    # check if conversion route exists or is disabled
    routes_functions = json.load(open('./data/routes.json'))
    if token0_address not in routes_functions[multi_address]['functions'].keys():
        raise Exception("Route not available for {} to {} in {}".format(token0_address, token1_address, multi_address))
    elif routes_functions[multi_address]['functions'][token0_address][0] == '#':
        raise Exception("Route is disabled for {} to {} in {}".format(token0_address, token1_address, multi_address))

    # get the cost required to convert tokens
    cost = routes_functions[multi_address]['costs'][token0_address]
    tokens_cost = cost * iterations * routes_functions[multi_address]['mints']
    # python is so stupid sometimes
    try:
        decimal_places = len(str(cost).split('.')[1])
        decimal_places = decimal_places if decimal_places <= 15 else 15
    except (AttributeError, IndexError):
        tokens_required = tokens_cost
    else:
        tokens_required = float(round(tokens_cost, decimal_places))

    # check if the wallet has enough tokens to convert
    if tokens_required > (tokens_balance := get_token_balance(token0_address, account.address)):
        logging.error("Need {} more tokens".format(tokens_required - tokens_balance))
        return False
    # approve the tokens required to convert and determine how many loops
    approve_token_spending(account, token0_address, multi_address, get_token_supply(token0_address, True))
    loops = math.floor(iterations / routes_functions[multi_address]['max_iterations'])
    if iterations % routes_functions[multi_address]['max_iterations'] != 0:
        loops += 1
    # start calling multi mints
    for i in list(range(0, loops)):
        # cancel the rest of this loop if the gas price is too damn high
        if get_beacon_gas_prices('rapid', beacon_gasnow_cache_seconds) > rapid_gas_fee_limit:
            logging.warning("Gas fees are too high")
            return None
        if i + 1 < loops or iterations == routes_functions[multi_address]['max_iterations']:
            # do max iterations during loop
            call_iterations = routes_functions[multi_address]['max_iterations']
        else:
            # on final loop run the remaining iterations
            call_iterations = iterations % routes_functions[multi_address]['max_iterations']
        # call the multi mint function with iterations based on tokens minted
        call_function = routes_functions[multi_address]['functions'][token0_address]
        multi_contract = load_contract(multi_address, load_contract_abi(multi_address))
        try:
            tx = getattr(multi_contract.functions, call_function)(call_iterations).build_transaction({
                "from": account.address,
                "nonce": get_nonce(account.address)
            })
            success = broadcast_transaction(account, tx, True, attempts)
        except Exception as e:
            if error := interpret_exception_message(e):
                logging.error("{}. Failed to convert using {}".format(error, routes_functions[multi_address]['label']))
        else:
            if success:
                logging.info("Called {}({}) from {}".format(
                    call_function,
                    call_iterations,
                    routes_functions[multi_address]['label']
                ))
            else:
                logging.warning("Failed to call {}({}) from {}".format(
                    call_function,
                    call_iterations,
                    routes_functions[multi_address]['label']
                ))
                return False
    return True

Description

  • Load a list of routes

  • Check if the source token has a route to the desired token

  • Check if the route is disabled

  • Check how many tokens are minted in one call

  • Fix float/decimal amounts

  • Check if the wallet has enough tokens required to convert

  • Approve the source token contract with spender as the multi contract address

  • Determine how many loops and iterations are needed to complete minting

  • Start the loop

  • Check if gas prices are reasonable

  • Get the function to call for the multi contract

  • Load the multi contract

  • Create a transaction and call the multi function with the desired amount

  • Broadcast and restart the loop

  • Return True/False