Skip to content

Commit

Permalink
Removing check for duplicate addresses. Minor fixes. (#1451)
Browse files Browse the repository at this point in the history
The duplicate addresses check exists as guardrails to prevent the
underlying wallet object from getting out of sync. This unnecessarily
prevents e.g., having one wallet interact with multiple pools. While we
haven't fixed the underlying issue (i.e., multiple agent objects has one
underlying wallet on chain can make wallet objects go out of sync), this
guardrail is too restrictive to keep, and instead we depend on
communication about syncing the wallet to solve this issue.

Other minor formatting and fixes.
  • Loading branch information
slundqui authored May 1, 2024
1 parent fd94870 commit 8bd6e9d
Show file tree
Hide file tree
Showing 7 changed files with 30 additions and 70 deletions.
2 changes: 1 addition & 1 deletion examples/interactive_hyperdrive_forking_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
# Launch a local anvil chain forked from the rpc uri.
chain = LocalChain(fork_uri=rpc_uri, fork_block_number=fork_block_number)

hyperdrive_address = Hyperdrive.get_hyperdrive_addresses_from_registry(registry_address, chain)["sdai_14_day"]
hyperdrive_address = Hyperdrive.get_hyperdrive_addresses_from_registry(chain, registry_address)["sdai_14_day"]

# Note that we use Hyperdrive here instead of LocalHyperdrive,
# as LocalHyperdrive deploys a new pool, whereas we want to connect to an existing pool
Expand Down
2 changes: 1 addition & 1 deletion examples/interactive_remote_hyperdrive_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
# This is the registry address deployed on sepolia.
registry_address = "0xba5156E697d39a03EDA824C19f375383F6b759EA"

hyperdrive_address = Hyperdrive.get_hyperdrive_addresses_from_registry(registry_address, chain)["sdai_14_day"]
hyperdrive_address = Hyperdrive.get_hyperdrive_addresses_from_registry(chain, registry_address)["sdai_14_day"]
hyperdrive_config = Hyperdrive.Config()
hyperdrive_pool = Hyperdrive(chain, hyperdrive_address, hyperdrive_config)

Expand Down
10 changes: 5 additions & 5 deletions scripts/testnet_checkpoint_bots.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,15 @@ def run_checkpoint_bot(

while True:
# Check if we've reached the block to exit
if block_to_exit is not None and chain.curr_block_number() >= block_to_exit:
if block_to_exit is not None and chain.block_number() >= block_to_exit:
logging.info("Exiting checkpoint bot...")
break

# Get the latest block time and check to see if a new checkpoint should
# be minted. This bot waits for a portion of the checkpoint to reduce
# the probability of needing a checkpoint. After the waiting period,
# the bot will attempt to mint a checkpoint.
latest_block = chain.curr_block_data()
latest_block = chain.block_data()
timestamp = latest_block.get("timestamp", None)
if timestamp is None:
raise AssertionError(f"{latest_block=} has no timestamp")
Expand Down Expand Up @@ -158,7 +158,7 @@ def run_checkpoint_bot(
if check_checkpoint:
# TODO: Add crash report
assert receipt["status"] == 1, "Checkpoint failed."
latest_block = chain.curr_block_data()
latest_block = chain.block_data()
timestamp = latest_block.get("timestamp", None)
if timestamp is None:
raise AssertionError(f"{latest_block=} has no timestamp")
Expand Down Expand Up @@ -217,7 +217,7 @@ def main(argv: Sequence[str] | None = None) -> None:
while True:
logging.info("Checking for new pools...")
# Reset hyperdrive objs
deployed_pools = Hyperdrive.get_hyperdrive_addresses_from_registry(parsed_args.registry_addr, chain)
deployed_pools = Hyperdrive.get_hyperdrive_addresses_from_registry(chain, parsed_args.registry_addr)

logging.info("Running for all pools...")

Expand All @@ -237,7 +237,7 @@ def main(argv: Sequence[str] | None = None) -> None:
funcs=partials,
chain=chain,
sender=sender,
block_to_exit=chain.curr_block_number() + pool_check_num_blocks,
block_to_exit=chain.block_number() + pool_check_num_blocks,
)
)

Expand Down
4 changes: 2 additions & 2 deletions scripts/testnet_fuzz_bot_invariant_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def main(argv: Sequence[str] | None = None) -> None:
# Run the loop forever
while True:
# Check for new pools
latest_block = chain.curr_block_data()
latest_block = chain.block_data()
latest_block_number = latest_block.get("number", None)
if latest_block_number is None:
raise AssertionError("Block has no number.")
Expand All @@ -63,7 +63,7 @@ def main(argv: Sequence[str] | None = None) -> None:
# Reset hyperdrive objs
hyperdrive_objs: dict[str, Hyperdrive] = {}
# First iteration, get list of deployed pools
deployed_pools = Hyperdrive.get_hyperdrive_addresses_from_registry(parsed_args.registry_addr, chain)
deployed_pools = Hyperdrive.get_hyperdrive_addresses_from_registry(chain, parsed_args.registry_addr)
for name, addr in deployed_pools.items():
logging.info("Adding pool %s", name)
hyperdrive_objs[name] = Hyperdrive(chain, addr)
Expand Down
31 changes: 18 additions & 13 deletions src/agent0/core/hyperdrive/interactive/chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import contextlib

from web3.types import BlockData
from web3.types import BlockData, Timestamp

from agent0.ethpy.base import initialize_web3_with_http_provider

Expand All @@ -22,7 +22,6 @@ def __init__(self, rpc_uri: str):
self.rpc_uri = rpc_uri
# Initialize web3 here for rpc calls
self._web3 = initialize_web3_with_http_provider(self.rpc_uri, reset_provider=False)
self._account_addrs: dict[str, bool] = {}

def cleanup(self):
"""General cleanup of resources of interactive hyperdrive."""
Expand All @@ -32,15 +31,7 @@ def __del__(self):
with contextlib.suppress(Exception):
self.cleanup()

def _ensure_no_duplicate_addrs(self, addr: str):
if addr in self._account_addrs:
raise ValueError(
f"Wallet address {addr} already in use. "
"Cannot manage a separate interactive hyperdrive agent with the same address."
)
self._account_addrs[addr] = True

def curr_block_number(self) -> int:
def block_number(self) -> int:
"""Get the current block number on the chain.
Returns
Expand All @@ -50,12 +41,26 @@ def curr_block_number(self) -> int:
"""
return self._web3.eth.get_block_number()

def curr_block_data(self) -> BlockData:
"""Get the current block number on the chain.
def block_data(self) -> BlockData:
"""Get the current block on the chain.
Returns
-------
int
The current block number
"""
return self._web3.eth.get_block("latest")

def block_time(self) -> Timestamp:
"""Get the current block time on the chain.
Returns
-------
int
The current block number
"""
block = self.block_data()
block_timestamp = block.get("timestamp", None)
if block_timestamp is None:
raise AssertionError("The provided block has no timestamp")
return block_timestamp
10 changes: 3 additions & 7 deletions src/agent0/core/hyperdrive/interactive/hyperdrive.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,17 +125,17 @@ def get_hyperdrive_addresses_from_artifacts(
@classmethod
def get_hyperdrive_addresses_from_registry(
cls,
registry_contract_addr: str,
chain: Chain,
registry_contract_addr: str,
) -> dict[str, ChecksumAddress]:
"""Gather deployed Hyperdrive pool addresses.
Arguments
---------
registry_contract_addr: str
The address of the Hyperdrive factory contract.
chain: Chain
The Chain object connected to a chain.
registry_contract_addr: str
The address of the Hyperdrive factory contract.
Returns
-------
Expand Down Expand Up @@ -244,10 +244,6 @@ def _init_agent(

agent = HyperdrivePolicyAgent(Account().from_key(private_key), initial_budget=FixedPoint(0), policy=policy_obj)

# Add the public address to the chain object to avoid multiple objects
# with the same underlying account
self.chain._ensure_no_duplicate_addrs(agent.checksum_address) # pylint: disable=protected-access

self._sync_wallet(agent)
return agent

Expand Down
41 changes: 0 additions & 41 deletions src/agent0/core/hyperdrive/interactive/hyperdrive_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,47 +204,6 @@ def test_remote_funding_and_trades(chain: LocalChain, check_remote_chain: bool):
_ensure_agent_wallet_is_correct(hyperdrive_agent0.wallet, interactive_remote_hyperdrive.interface)


@pytest.mark.anvil
@pytest.mark.parametrize("check_remote_chain", [True, False])
def test_multi_account_bookkeeping(chain: LocalChain, check_remote_chain: bool):
# Parameters for pool initialization. If empty, defaults to default values, allows for custom values if needed
# We explicitly set initial liquidity here to ensure we have withdrawal shares when trading
initial_pool_config = LocalHyperdrive.Config(
initial_liquidity=FixedPoint(1_000),
initial_fixed_apr=FixedPoint("0.05"),
position_duration=60 * 60 * 24 * 365, # 1 year
)
# Launches a local hyperdrive pool
# This deploys the pool
interactive_local_hyperdrive_0 = LocalHyperdrive(chain, initial_pool_config)
interactive_local_hyperdrive_1 = LocalHyperdrive(chain, initial_pool_config)

# Gather relevant objects from the local hyperdrive
hyperdrive_addresses_0 = interactive_local_hyperdrive_0.get_hyperdrive_address()
hyperdrive_addresses_1 = interactive_local_hyperdrive_1.get_hyperdrive_address()

# Connect to the local chain using the remote hyperdrive interface
if check_remote_chain:
remote_chain = Chain(chain.rpc_uri)
interactive_remote_hyperdrive_0 = Hyperdrive(remote_chain, hyperdrive_addresses_0)
interactive_remote_hyperdrive_1 = Hyperdrive(remote_chain, hyperdrive_addresses_1)
else:
interactive_remote_hyperdrive_0 = Hyperdrive(chain, hyperdrive_addresses_0)
interactive_remote_hyperdrive_1 = Hyperdrive(chain, hyperdrive_addresses_1)

# Generate trading agents from the interactive object
private_key = make_private_key()
_ = interactive_remote_hyperdrive_0.init_agent(private_key=private_key)

# Initializing an agent with an existing key should fail
with pytest.raises(ValueError):
_ = interactive_remote_hyperdrive_0.init_agent(private_key=private_key)

# Initializing an agent with an existing key on a separate pool should fail
with pytest.raises(ValueError):
_ = interactive_remote_hyperdrive_1.init_agent(private_key=private_key)


@pytest.mark.anvil
@pytest.mark.parametrize("check_remote_chain", [True, False])
def test_no_policy_call(chain: LocalChain, check_remote_chain: bool):
Expand Down

0 comments on commit 8bd6e9d

Please sign in to comment.