diff --git a/contracts/Registry.vy b/contracts/Registry.vy index e31551df..e6dcaa12 100644 --- a/contracts/Registry.vy +++ b/contracts/Registry.vy @@ -23,6 +23,13 @@ releases: public(HashMap[uint256, address]) nextDeployment: public(HashMap[address, uint256]) vaults: public(HashMap[address, HashMap[uint256, address]]) +# Index of token added => token address +tokens: public(HashMap[uint256, address]) +# len(tokens) +numTokens: public(uint256) +# Inclusion check for token +isRegistered: public(HashMap[address, bool]) + # 2-phase commit governance: public(address) pendingGovernance: public(address) @@ -144,6 +151,12 @@ def _registerDeployment(token: address, vault: address): self.vaults[token][deployment_id] = vault self.nextDeployment[token] = deployment_id + 1 + # Register tokens for endorsed vaults + if not self.isRegistered[token]: + self.isRegistered[token] = True + self.tokens[self.numTokens] = token + self.numTokens += 1 + # Log the deployment for external listeners (e.g. Graph) log NewVault(token, deployment_id, vault, Vault(vault).apiVersion()) diff --git a/tests/functional/registry/test_deployment.py b/tests/functional/registry/test_deployment.py index d011b048..880ac1b3 100644 --- a/tests/functional/registry/test_deployment.py +++ b/tests/functional/registry/test_deployment.py @@ -1,52 +1,81 @@ import brownie +from brownie import ZERO_ADDRESS def test_deployment_management( gov, guardian, rewards, registry, Vault, create_token, create_vault, rando ): - token = create_token() + v1_token = create_token() # No deployments yet for token with brownie.reverts(): - registry.latestVault(token) + registry.latestVault(v1_token) - # Creating the first deployment makes `latestVault()` work - v1_vault = create_vault(token, version="1.0.0") + # Token tracking state variables should start off uninitialized + assert registry.tokens(0) == ZERO_ADDRESS + assert not registry.isRegistered(v1_token) + assert registry.numTokens() == 0 + + # New release does not add new token + v1_vault = create_vault(v1_token, version="1.0.0") registry.newRelease(v1_vault, {"from": gov}) + assert registry.tokens(0) == ZERO_ADDRESS + assert not registry.isRegistered(v1_token) + assert registry.numTokens() == 0 + + # Creating the first deployment makes `latestVault()` work registry.endorseVault(v1_vault, {"from": gov}) - assert registry.latestVault(token) == v1_vault + assert registry.latestVault(v1_token) == v1_vault assert registry.latestRelease() == v1_vault.apiVersion() == "1.0.0" + # Endorsing a vault with a new token registers a new token + assert registry.tokens(0) == v1_token + assert registry.isRegistered(v1_token) + assert registry.numTokens() == 1 + # Can't deploy the same vault api version twice, proxy or not with brownie.reverts(): - registry.newVault(token, guardian, rewards, "", "", {"from": gov}) + registry.newVault(v1_token, guardian, rewards, "", "", {"from": gov}) # New release overrides previous release v2_vault = create_vault(version="2.0.0") # Uses different token registry.newRelease(v2_vault, {"from": gov}) - assert registry.latestVault(token) == v1_vault + assert registry.latestVault(v1_token) == v1_vault assert registry.latestRelease() == v2_vault.apiVersion() == "2.0.0" # You can deploy proxy Vaults, linked to the latest release + assert registry.numTokens() == 1 proxy_vault = Vault.at( - registry.newVault(token, guardian, rewards, "", "", {"from": gov}).return_value + registry.newVault( + v1_token, guardian, rewards, "", "", {"from": gov} + ).return_value ) assert proxy_vault.apiVersion() == v2_vault.apiVersion() == "2.0.0" assert proxy_vault.rewards() == rewards assert proxy_vault.guardian() == guardian - assert registry.latestVault(token) == proxy_vault + assert registry.latestVault(v1_token) == proxy_vault + + # Tokens can only be registered one time (no duplicates) + assert registry.numTokens() == 1 # You can deploy proxy Vaults, linked to a previous release - token = create_token() + v2_token = create_token() proxy_vault = Vault.at( registry.newVault( - token, guardian, rewards, "", "", 1, {"from": gov} + v2_token, guardian, rewards, "", "", 1, {"from": gov} ).return_value ) assert proxy_vault.apiVersion() == v1_vault.apiVersion() == "1.0.0" assert proxy_vault.rewards() == rewards assert proxy_vault.guardian() == guardian - assert registry.latestVault(token) == proxy_vault + assert registry.latestVault(v2_token) == proxy_vault + + # Adding a new endorsed vault with `newVault()` registers a new token + assert registry.tokens(0) == v1_token + assert registry.tokens(1) == v2_token + assert registry.isRegistered(v1_token) + assert registry.isRegistered(v2_token) + assert registry.numTokens() == 2 # Not just anyone can create a new endorsed Vault, only governance can! with brownie.reverts(): @@ -81,10 +110,20 @@ def test_experimental_deployments( experimental_vault.setGovernance(gov, {"from": rando}) experimental_vault.acceptGovernance({"from": gov}) + # New experimental (unendorsed) vaults should not register tokens + assert registry.tokens(0) == ZERO_ADDRESS + assert not registry.isRegistered(token) + assert registry.numTokens() == 0 + # You can only endorse a vault if it creates an new deployment registry.endorseVault(experimental_vault, {"from": gov}) assert registry.latestVault(token) == experimental_vault + # Endorsing experimental vaults should register a token + assert registry.tokens(0) == token + assert registry.isRegistered(token) + assert registry.numTokens() == 1 + # You can't endorse a vault if it would overwrite a current deployment experimental_vault = Vault.at( registry.newExperimentalVault(