def get_yieldwatch_balances( # noqa: C901 my_address: Optional[str] = None, return_raw_data: bool = False): config = read_config() if my_address is None: my_address = config["bsc"]["address"] platforms = { "BeefyFinance": "beefy", "PancakeSwap": "pancake", "HyperJump": "hyperjump", "Blizzard": "blizzard", "bDollar": "bdollar", "Jetfuel": "jetfuel", "Autofarm": "auto", "bunny": "bunny", "Acryptos": "acryptos", "MDex": "mdex", "Alpha": "alpha", "Venus": "venus", "CreamFinance": "cream", } platforms_str = ",".join(platforms.values()) url = f"https://www.yieldwatch.net/api/all/{my_address}?platforms={platforms_str}" for i in range(3): req = requests.get(url) response = req.json() if "result" in response: raw_data = response["result"] break elif i == 2: raise RuntimeError("Tried trice and failed getting YieldWatch") time.sleep(2) balances = defaultdict(lambda: defaultdict(float)) for k, v in raw_data.items(): if k in ("watchBalance", "currencies", "walletBalance"): continue if k not in platforms: print( f"the '{k}' platform was not requested in the yieldwatch url!") if "vaults" in v: for vault in v["vaults"]["vaults"]: if (deposit_token := vault.get("depositToken")) is not None: balances[deposit_token]["amount"] += vault["currentTokens"] balances[deposit_token]["price"] = ( vault["priceInUSDDepositToken"] * euro_per_dollar()) if (reward_token := vault.get("rewardToken")) is not None: balances[reward_token]["amount"] += vault["pendingRewards"] balances[reward_token]["price"] = ( vault["priceInUSDRewardToken"] * euro_per_dollar())
def get_bep20_balances(my_address: Optional[str] = None, api_key: Optional[str] = None): config = read_config() if my_address is None: my_address = config["bsc"]["address"] if api_key is None: api_key = config["bscscan"]["api_key"] bsc = BscScan(api_key) my_address = my_address.lower() txs = bsc.get_bep20_token_transfer_events_by_address(address=my_address, startblock=0, endblock=999999999, sort="asc") balances = defaultdict(float) for d in txs: symbol = d["tokenSymbol"] if symbol in IGNORE_TOKENS: continue if d["to"].lower() == my_address: # Incoming tokens sign = +1 else: sign = -1 factor = 10**int(d["tokenDecimal"]) balances[symbol] += sign * float(d["value"]) / factor # Get BNB balance balances["BNB"] += float(bsc.get_bnb_balance(address=my_address)) / 1e18 # Remove 0 or negative balances # TODO: why can it become negative? balances = {k: v for k, v in balances.items() if v > 0} renames = {"Belt.fi bDAI/bUSDC/bUSDT/bBUSD": "BUSD"} for old, new in renames.items(): if old in balances: balances[new] = balances.pop(old) return {k: dict(amount=v) for k, v in balances.items()}
def scrape_yieldwatch(my_address: Optional[str] = None, headless=True, timeout: int = 30): config = read_config() if my_address is None: my_address = config["bsc"]["address"] chrome_options = Options() if headless: chrome_options.add_argument("--headless") with webdriver.Chrome(options=chrome_options) as driver: WebDriverWait(driver, timeout) driver.get("https://www.yieldwatch.net/") for letter in my_address: address_bar = driver.find_element_by_id("addressInputField") address_bar.send_keys(letter) icon_bar = driver.find_element_by_class_name( "centered.bottom.aligned.row") buttons = icon_bar.find_elements_by_class_name("center.aligned.column") for button in buttons: grayscale = button.find_element_by_class_name( "ui.centered.image").value_of_css_property("filter") if grayscale == "grayscale(1)": button.click() button = driver.find_element_by_class_name("binoculars") button.click() # Wait until the next page is loaded element_present = presence_of_element_located( (By.CLASS_NAME, "content.active")) WebDriverWait(driver, timeout).until(element_present) infos = defaultdict(dict) segments = driver.find_elements_by_class_name("ui.segment") for segment in segments: # Many elements have the "ui segment" class, only pick the ones with # the "accordion ui" style. for defi in segment.find_elements_by_class_name("accordion.ui"): boxes = defi.find_elements_by_class_name("ui.equal.width.grid") if not boxes: continue which = defi.text.split("\n")[0] for box in boxes: header, content = box.find_elements_by_class_name("row") header_text = header.text.split("\n") box_name = header_text[0] dollar_value = header_text[1] assert "$" in dollar_value dollar_value = float( dollar_value.replace(",", "").replace("$", "")) # Get the columns in the box, only the first two are relevant columns = content.find_elements_by_class_name( "collapsing.right.aligned") names = columns[0].text.split("\n") amounts = columns[1].text.split("\n") d = defaultdict(list) for i, amount in enumerate(amounts): amount, coin = amount.split(" ", 1) name = names[min(i, len(names) - 1)] amount = (float(amount[:-1]) * 1000 if "k" in amount else float(amount)) d[name].append((amount, coin)) d = dict(d) d["dollar_value"] = dollar_value infos[which][box_name] = dict(d) return dict(infos)