diff --git a/requirements-dev.txt b/requirements-dev.txt index 61ef6907..536dfa43 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,2 +1,2 @@ black==19.10b0 -eth-brownie>=1.11.12,<2.0.0 +eth-brownie>=1.12.1,<2.0.0 diff --git a/scripts/keep.py b/scripts/keep.py index 13c6f1c9..9417bf8e 100644 --- a/scripts/keep.py +++ b/scripts/keep.py @@ -1,10 +1,16 @@ -from brownie import accounts, network, interface, Vault +from brownie import accounts, network, interface, Vault, Token +from brownie.network.gas.strategies import GasNowScalingStrategy from decimal import Decimal from eth_utils import is_checksum_address import requests from time import sleep +GAS_BUFFER = 1.2 + +gas_strategy = GasNowScalingStrategy() + + def get_address(msg: str) -> str: while True: addr = input(msg) @@ -13,13 +19,6 @@ def get_address(msg: str) -> str: print(f"I'm sorry, but '{addr}' is not a checksummed address") -def get_gas_price(confirmation_speed: str = "fast"): - if "mainnet" not in network.show_active(): - return 10 ** 9 # 1 gwei - data = requests.get("https://www.gasnow.org/api/v3/gas/price").json() - return data["data"][confirmation_speed] - - def main(): print(f"You are using the '{network.show_active()}' network") bot = accounts.load("bot") @@ -30,45 +29,80 @@ def main(): strategies.append(interface.StrategyAPI(get_address("Strategy to farm: "))) vault = Vault.at(strategies[0].vault()) + want = Token.at(vault.token()) for strategy in strategies: assert ( strategy.keeper() == bot.address ), "Bot is not set as keeper! [{strategy.address}]" - assert strategy.vault() == vault.address, "Vault mismatch! [{strategy.address}]" + assert ( + strategy.vault() == vault.address + ), f"Vault mismatch! [{strategy.address}]" while True: - gas_price = get_gas_price() starting_balance = bot.balance() - no_action = True + calls_made = 0 + total_gas_estimate = 0 for strategy in strategies: # Display some relevant statistics - symbol = vault.symbol()[1:] + symbol = want.symbol() credit = vault.creditAvailable(strategy) / 10 ** vault.decimals() print(f"[{strategy.address}] Credit Available: {credit:0.3f} {symbol}") debt = vault.debtOutstanding(strategy) / 10 ** vault.decimals() print(f"[{strategy.address}] Debt Outstanding: {debt:0.3f} {symbol}") - # TODO: Actually estimate gas - if strategy.tendTrigger(40000 * gas_price): + starting_gas_price = next(gas_strategy.get_gas_price()) + + try: + tend_gas_estimate = int( + GAS_BUFFER * strategy.tend.estimate_gas({"from": bot}) + ) + total_gas_estimate += tend_gas_estimate + except ValueError: + print(f"[{strategy.address}] `tend` estimate fails") + tend_gas_estimate = None + + try: + harvest_gas_estimate = int( + GAS_BUFFER * strategy.harvest.estimate_gas({"from": bot}) + ) + total_gas_estimate += harvest_gas_estimate + except ValueError: + print(f"[{strategy.address}] `harvest` estimate fails") + harvest_gas_estimate = None + + if harvest_gas_estimate and strategy.harvestTrigger( + harvest_gas_estimate * starting_gas_price + ): try: - strategy.tend({"from": bot, "gas_price": gas_price}) - no_action = False + strategy.harvest({"from": bot, "gas_price": gas_strategy}) + calls_made += 1 except: - print("Call failed") + print(f"[{strategy.address}] `harvest` call fails") - elif strategy.harvestTrigger(180000 * gas_price): + elif tend_gas_estimate and strategy.tendTrigger( + tend_gas_estimate * starting_gas_price + ): try: - strategy.harvest({"from": bot, "gas_price": gas_price}) - no_action = False + strategy.tend({"from": bot, "gas_price": gas_strategy}) + calls_made += 1 except: - print("Call failed") + print(f"[{strategy.address}] `tend` call fails") + + # Check running 10 `tend`s & `harvest`s per strategy at estimated gas price + # would empty the balance of the bot account + if bot.balance() < 10 * total_gas_estimate * starting_gas_price: + print(f"Need more ether please! {bot.address}") - if no_action: + # Wait a minute if we didn't make any calls + if calls_made > 0: + gas_cost = (starting_balance - bot.balance()) / 10 ** 18 + num_harvests = bot.balance() // (starting_balance - bot.balance()) + print(f"Made {calls_made} calls, spent {gas_cost} ETH on gas.") + print( + f"At this rate, it'll take {num_harvests} harvests to run out of gas." + ) + else: print("Sleeping for 60 seconds...") sleep(60) - - if bot.balance() < 10 ** 8 * gas_price: - # Less than 100m gas left to spend - print(f"Need more ether please! {bot.address}")