diff --git a/node/pkg/governor/mainnet_tokens_test.go b/node/pkg/governor/mainnet_tokens_test.go index 4ea21aafe9..6f89a8bab8 100644 --- a/node/pkg/governor/mainnet_tokens_test.go +++ b/node/pkg/governor/mainnet_tokens_test.go @@ -2,6 +2,7 @@ package governor import ( "fmt" + "sort" "strings" "testing" @@ -118,3 +119,84 @@ func TestTokenListEmptyCoinGeckoId(t *testing.T) { assert.Greater(t, len(tokenConfigEntry.coinGeckoId), 0) } } + +// If not true, then there exists some chain that Wormhole governs yet has no governed tokens. That means assets +// native to the chain are not actually governed and can be transferred across all other supported chains without +// increasing their Governor limit. We don't want this. +func TestAllGovernedChainsHaveGovernedAssets(t *testing.T) { + + // Build a list of chains that are not governed we will filter these out. Compare with `mainnet_chains.go` + ignoredChains := map[vaa.ChainID]bool{ + // Pyth is special + vaa.ChainIDPythNet: true, + // BTC is special + vaa.ChainIDBtc: true, + // Wormchain is a Wormhole abstraction over IBC type networks + vaa.ChainIDWormchain: true, + // From the perspective of the Governor, all of these are "Wormchain" because they use IBC. + vaa.ChainIDCosmoshub: true, + vaa.ChainIDEvmos: true, + vaa.ChainIDKujira: true, + vaa.ChainIDNeutron: true, + vaa.ChainIDCelestia: true, + vaa.ChainIDStargaze: true, + vaa.ChainIDSeda: true, + vaa.ChainIDDymension: true, + vaa.ChainIDProvenance: true, + // ID reserved but mainnet hasn't launched + vaa.ChainIDBerachain: true, + // Testnets + vaa.ChainIDHolesky: true, + vaa.ChainIDSepolia: true, + vaa.ChainIDArbitrumSepolia: true, + vaa.ChainIDBaseSepolia: true, + vaa.ChainIDOptimismSepolia: true, + vaa.ChainIDPolygonSepolia: true, + // Otherwise Archived/inactive + vaa.ChainIDRootstock: true, + vaa.ChainIDLinea: true, + vaa.ChainIDGnosis: true, + vaa.ChainIDOsmosis: true, + } + + chainsWithNoGovernedAssets := []vaa.ChainID{} + + // Scan all governed tokens and build a set of all chain IDs found in the "Origin" field of the tokens. + originChains := make(map[uint16]bool) + for _, token := range tokenList() { + _, ok := originChains[token.chain] + if !ok { + originChains[token.chain] = true + } + } + + // For all governed chains, make sure that they showed up when we scanned all the Origins of the governed tokens. + // If not, add them to the list of chains that should be governed yet have no assets configured for them. + for _, id := range vaa.GetAllNetworkIDs() { + if _, ok := originChains[uint16(id)]; !ok { + if _, artificial := ignoredChains[id]; !artificial { + chainsWithNoGovernedAssets = append(chainsWithNoGovernedAssets, id) + } + } + } + + if len(chainsWithNoGovernedAssets) > 0 { + output := []string{} + for _, id := range chainsWithNoGovernedAssets { + output = append(output, id.String()) + + } + sort.Strings(output) + t.Logf("Governed chains without governed assets: %s\n", strings.Join(output, "\n")) + } + + if len(ignoredChains) > 0 { + ignoredOutput := []string{} + for id, _ := range ignoredChains { + ignoredOutput = append(ignoredOutput, id.String()) + } + + t.Logf("This test ignored the following chains because they are not governed: %s\n", strings.Join(ignoredOutput, "\n")) + } + assert.Zero(t, len(chainsWithNoGovernedAssets)) +}