Skip to content

Add EVM bridge contracts to SystemContracts#8358

Open
turbolent wants to merge 1 commit intomasterfrom
bastian/add-evm-bridge-contracts-to-system-contracts
Open

Add EVM bridge contracts to SystemContracts#8358
turbolent wants to merge 1 commit intomasterfrom
bastian/add-evm-bridge-contracts-to-system-contracts

Conversation

@turbolent
Copy link
Member

@turbolent turbolent commented Jan 21, 2026

The Emulator lists all system contracts on startup. Include the EVM bridge contracts in that list for informational purposes. Also add a helper to return bridge.Environment and don't duplicate it in tests.

Summary by CodeRabbit

  • New Features

    • Added support for multiple EVM bridge system contracts, including NFT and token bridge contracts, utilities, and related interfaces.
    • Introduced a simplified method to retrieve bridge environment configuration.
  • Refactor

    • Expanded system contract registry with complete set of bridge-related contracts.

✏️ Tip: You can customize this high-level summary in your review settings.

@turbolent turbolent requested a review from a team January 21, 2026 21:25
@turbolent turbolent self-assigned this Jan 21, 2026
@turbolent turbolent requested a review from a team as a code owner January 21, 2026 21:25
@turbolent turbolent requested a review from j1010001 January 21, 2026 21:25
@github-actions
Copy link
Contributor

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 21, 2026

📝 Walkthrough

Walkthrough

This change expands the SystemContracts struct by introducing 22 new public system contract fields for EVM bridge-related contracts and utilities, adds an AsBridgeEnv() helper method to derive bridge environment configuration, and updates initialization functions to populate these new fields. A test is simplified to use the new helper method instead of manual struct construction.

Changes

Cohort / File(s) Summary
System contracts expansion
fvm/systemcontracts/system_contracts.go
Added 22 new public system contract fields (CrossVMNFT, CrossVMToken, FlowEVMBridge\\*, IBridgePermissions, ICrossVM\\*, IEVMBridge\\*, IFlowEVM\\*, utility contracts like ArrayUtils, StringUtils, etc.), new AsBridgeEnv() method to construct bridge environment, updated All() to include new fields, and expanded contract initialization in init() and getSystemContractsForChain()
Test simplification
fvm/fvm_test.go
Replaced manual bridge environment struct construction with call to AsBridgeEnv() helper method

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Hop-hop, new contracts bloom,
Bridge them swift across the room,
EVM bound with tokens, NFTs in tow,
Helper methods make the config flow,
Twenty-two new friends now play! 🌈

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add EVM bridge contracts to SystemContracts' directly and accurately describes the main change: introducing EVM bridge contract fields to the SystemContracts struct and adding a helper method.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov-commenter
Copy link

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@fvm/systemcontracts/system_contracts.go`:
- Around line 355-380: All() currently lists bridge contracts (CrossVMNFT,
CrossVMToken, FlowEVMBridge*, FlowEVMBridgeUtils, etc.) even though
setupVMBridge() only deploys them on transient networks; update the registry so
All() only includes those bridge-related contracts for transient chains (or when
setupVMBridge() indicates they were deployed) — locate the All() function in
system_contracts.go and either filter out the bridge symbols for non-transient
chains (e.g., check the chain type or call the same transient check used by
setupVMBridge()) or move the bridge entries into the transient-only registration
path so that contract existence checks reflect actual deployments.
🧹 Nitpick comments (1)
fvm/systemcontracts/system_contracts.go (1)

294-321: Prefer deriving bridge env from the concrete SystemContracts fields.

Using the service account address for every entry can drift if any bridge contracts move to different accounts. Pulling from the actual SystemContracts fields keeps this consistent with contractAddressFunc.

♻️ Proposed refactor
 func (c SystemContracts) AsBridgeEnv() bridge.Environment {
-	serviceAccountAddress := c.FlowServiceAccount.Address.Hex()
 	return bridge.Environment{
-		CrossVMNFTAddress:                     serviceAccountAddress,
-		CrossVMTokenAddress:                   serviceAccountAddress,
-		FlowEVMBridgeHandlerInterfacesAddress: serviceAccountAddress,
-		IBridgePermissionsAddress:             serviceAccountAddress,
-		ICrossVMAddress:                       serviceAccountAddress,
-		ICrossVMAssetAddress:                  serviceAccountAddress,
-		IEVMBridgeNFTMinterAddress:            serviceAccountAddress,
-		IEVMBridgeTokenMinterAddress:          serviceAccountAddress,
-		IFlowEVMNFTBridgeAddress:              serviceAccountAddress,
-		IFlowEVMTokenBridgeAddress:            serviceAccountAddress,
-		FlowEVMBridgeAddress:                  serviceAccountAddress,
-		FlowEVMBridgeAccessorAddress:          serviceAccountAddress,
-		FlowEVMBridgeConfigAddress:            serviceAccountAddress,
-		FlowEVMBridgeHandlersAddress:          serviceAccountAddress,
-		FlowEVMBridgeNFTEscrowAddress:         serviceAccountAddress,
-		FlowEVMBridgeResolverAddress:          serviceAccountAddress,
-		FlowEVMBridgeTemplatesAddress:         serviceAccountAddress,
-		FlowEVMBridgeTokenEscrowAddress:       serviceAccountAddress,
-		FlowEVMBridgeUtilsAddress:             serviceAccountAddress,
-		ArrayUtilsAddress:                     serviceAccountAddress,
-		ScopedFTProvidersAddress:              serviceAccountAddress,
-		SerializeAddress:                      serviceAccountAddress,
-		SerializeMetadataAddress:              serviceAccountAddress,
-		StringUtilsAddress:                    serviceAccountAddress,
+		CrossVMNFTAddress:                     c.CrossVMNFT.Address.Hex(),
+		CrossVMTokenAddress:                   c.CrossVMToken.Address.Hex(),
+		FlowEVMBridgeHandlerInterfacesAddress: c.FlowEVMBridgeHandlerInterfaces.Address.Hex(),
+		IBridgePermissionsAddress:             c.IBridgePermissions.Address.Hex(),
+		ICrossVMAddress:                       c.ICrossVM.Address.Hex(),
+		ICrossVMAssetAddress:                  c.ICrossVMAsset.Address.Hex(),
+		IEVMBridgeNFTMinterAddress:            c.IEVMBridgeNFTMinter.Address.Hex(),
+		IEVMBridgeTokenMinterAddress:          c.IEVMBridgeTokenMinter.Address.Hex(),
+		IFlowEVMNFTBridgeAddress:              c.IFlowEVMNFTBridge.Address.Hex(),
+		IFlowEVMTokenBridgeAddress:            c.IFlowEVMTokenBridge.Address.Hex(),
+		FlowEVMBridgeAddress:                  c.FlowEVMBridge.Address.Hex(),
+		FlowEVMBridgeAccessorAddress:          c.FlowEVMBridgeAccessor.Address.Hex(),
+		FlowEVMBridgeConfigAddress:            c.FlowEVMBridgeConfig.Address.Hex(),
+		FlowEVMBridgeHandlersAddress:          c.FlowEVMBridgeHandlers.Address.Hex(),
+		FlowEVMBridgeNFTEscrowAddress:         c.FlowEVMBridgeNFTEscrow.Address.Hex(),
+		FlowEVMBridgeResolverAddress:          c.FlowEVMBridgeResolver.Address.Hex(),
+		FlowEVMBridgeTemplatesAddress:         c.FlowEVMBridgeTemplates.Address.Hex(),
+		FlowEVMBridgeTokenEscrowAddress:       c.FlowEVMBridgeTokenEscrow.Address.Hex(),
+		FlowEVMBridgeUtilsAddress:             c.FlowEVMBridgeUtils.Address.Hex(),
+		ArrayUtilsAddress:                     c.ArrayUtils.Address.Hex(),
+		ScopedFTProvidersAddress:              c.ScopedFTProviders.Address.Hex(),
+		SerializeAddress:                      c.Serialize.Address.Hex(),
+		SerializeMetadataAddress:              c.SerializeMetadata.Address.Hex(),
+		StringUtilsAddress:                    c.StringUtils.Address.Hex(),
 	}
 }

Comment on lines 355 to +380
c.Migration,

c.CrossVMNFT,
c.CrossVMToken,
c.FlowEVMBridgeHandlerInterfaces,
c.IBridgePermissions,
c.ICrossVM,
c.ICrossVMAsset,
c.IEVMBridgeNFTMinter,
c.IEVMBridgeTokenMinter,
c.IFlowEVMNFTBridge,
c.IFlowEVMTokenBridge,
c.FlowEVMBridge,
c.FlowEVMBridgeAccessor,
c.FlowEVMBridgeConfig,
c.FlowEVMBridgeHandlers,
c.FlowEVMBridgeNFTEscrow,
c.FlowEVMBridgeResolver,
c.FlowEVMBridgeTemplates,
c.FlowEVMBridgeTokenEscrow,
c.FlowEVMBridgeUtils,
c.ArrayUtils,
c.ScopedFTProviders,
c.Serialize,
c.SerializeMetadata,
c.StringUtils,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the system_contracts.go file to see the context
cd fvm/systemcontracts && wc -l system_contracts.go && head -50 system_contracts.go

Repository: onflow/flow-go

Length of output: 2458


🏁 Script executed:

# Find the All() function definition and usage
rg -n "func.*All\(\)|\.All\(\)" --type=go fvm/systemcontracts/

Repository: onflow/flow-go

Length of output: 312


🏁 Script executed:

# Search for bootstrap and deployment code
rg -n "bootstrap|deploy" --type=go -i fvm/systemcontracts/

Repository: onflow/flow-go

Length of output: 710


🏁 Script executed:

# Check for where these new bridge contracts are defined
rg -n "CrossVMNFT|FlowEVMBridge" --type=go fvm/ | head -30

Repository: onflow/flow-go

Length of output: 3155


🏁 Script executed:

# Read the All() function implementation
sed -n '325,380p' fvm/systemcontracts/system_contracts.go

Repository: onflow/flow-go

Length of output: 1226


🏁 Script executed:

# Check how All() is tested
cat -n fvm/systemcontracts/system_contracts_test.go | head -80

Repository: onflow/flow-go

Length of output: 3060


🏁 Script executed:

# Search for where system contracts are deployed/bootstrapped
rg -n "NewSystemContracts|bootstrap" --type=go fvm/ | grep -v test | head -20

Repository: onflow/flow-go

Length of output: 1621


🏁 Script executed:

# Look for init or setup functions that deploy contracts
rg -n "func init|SetupSystemContracts|DeploySystemContracts" --type=go -i | head -20

Repository: onflow/flow-go

Length of output: 1436


🏁 Script executed:

# Look at the bootstrap.go file to see how contracts are deployed
sed -n '224,300p' fvm/bootstrap.go

Repository: onflow/flow-go

Length of output: 2473


🏁 Script executed:

# Check if there's specific code for deploying bridge contracts
rg -n "WithFlowEVMBridge|DeployBridge" --type=go | head -20

Repository: onflow/flow-go

Length of output: 40


🏁 Script executed:

# Look for where SystemContracts are actually deployed in bootstrapping
rg -n "setupSystemContracts|deployContracts" --type=go -i | head -20

Repository: onflow/flow-go

Length of output: 1166


🏁 Script executed:

# Search for how chain-specific system contracts are configured
rg -n "SystemContractsForChain|mainnet|testnet" --type=go fvm/systemcontracts/ | head -30

Repository: onflow/flow-go

Length of output: 987


🏁 Script executed:

# Look at the SystemContractsForChain function implementation
sed -n '404,500p' fvm/systemcontracts/system_contracts.go

Repository: onflow/flow-go

Length of output: 3016


🏁 Script executed:

# Check for chain-specific contract configurations
rg -n "Mainnet|Testnet|Canarynet|Previewnet" --type=go fvm/systemcontracts/system_contracts.go | head -30

Repository: onflow/flow-go

Length of output: 2165


🏁 Script executed:

# Look for where bridge contracts are conditionally included or excluded
rg -n "CrossVMNFT|FlowEVMBridge" --type=go fvm/systemcontracts/system_contracts.go -B 2 -A 2 | head -60

Repository: onflow/flow-go

Length of output: 3390


🏁 Script executed:

# Check if there's any migration or rollout status for these contracts
rg -n "Migration|rollout|enabled|disabled" --type=go fvm/systemcontracts/system_contracts.go -i | head -20

Repository: onflow/flow-go

Length of output: 304


🏁 Script executed:

# Look at the full init() function to see which contracts are registered
sed -n '428,700p' fvm/systemcontracts/system_contracts.go

Repository: onflow/flow-go

Length of output: 11580


🏁 Script executed:

# Search for where contractAddressFunc is populated for the bridge contracts
rg -n "contractAddressFunc\[" --type=go fvm/systemcontracts/system_contracts.go | tail -50

Repository: onflow/flow-go

Length of output: 221


🏁 Script executed:

# Check the complete list of what's registered in contractAddressFunc
rg -n "registerContractAddress|contractAddressFunc\[ContractName" --type=go fvm/systemcontracts/system_contracts.go | wc -l

Repository: onflow/flow-go

Length of output: 59


🏁 Script executed:

# Count how many contracts are in All()
sed -n '325,390p' fvm/systemcontracts/system_contracts.go | grep "c\." | wc -l

Repository: onflow/flow-go

Length of output: 60


🏁 Script executed:

# Look for the registerContractAddress or similar registration pattern
rg -n "registerContractAddress" --type=go fvm/systemcontracts/system_contracts.go -A 3 | head -30

Repository: onflow/flow-go

Length of output: 40


🏁 Script executed:

# Search for bootstrap code that actually deploys contracts
rg -n "setupVM|DeployContracts|BridgeContract" --type=go fvm/ | grep -i bootstrap | head -20

Repository: onflow/flow-go

Length of output: 547


🏁 Script executed:

# Look for Cadence contract deployment in bootstrap
rg -n "setupVMBridge|bridge" --type=go fvm/bootstrap.go -i -A 3 | head -40

Repository: onflow/flow-go

Length of output: 1584


🏁 Script executed:

# Check if there's a deployment manifest or list
rg -n "manifest|deployment.*list|contract.*list" --type=go fvm/ -i | head -20

Repository: onflow/flow-go

Length of output: 1119


🏁 Script executed:

# Look at what happens in transient network setup vs mainnet/testnet
rg -n "transient|mainnet|testnet" --type=go fvm/systemcontracts/system_contracts.go -B 1 -A 1 | head -40

Repository: onflow/flow-go

Length of output: 383


🏁 Script executed:

# Look at the test that was mentioned - transient network contract existence checks
cat -n fvm/systemcontracts/system_contracts_test.go | head -100

Repository: onflow/flow-go

Length of output: 4043


🏁 Script executed:

# Search for tests that check contract existence
rg -n "All\(\)" --type=go fvm/systemcontracts/ -A 5 -B 5

Repository: onflow/flow-go

Length of output: 2394


🏁 Script executed:

# Check if there's documentation about deployment on mainnet/testnet
rg -n "mainnet|testnet" --type=go fvm/bootstrap.go -B 2 -A 2 | grep -i "bridge\|deploy"

Repository: onflow/flow-go

Length of output: 258


🏁 Script executed:

# Look for where bridge contracts are actually deployed on mainnet/testnet
rg -n "CrossVMNFT|FlowEVMBridge" --type=go --type=go -l | xargs grep -l "mainnet\|testnet" | head -10

Repository: onflow/flow-go

Length of output: 114


🏁 Script executed:

# Check the blueprints to see what contracts are deployed
rg -n "BridgeContracts" --type=go fvm/blueprints/ -A 10 -B 5

Repository: onflow/flow-go

Length of output: 1321


🏁 Script executed:

# Check all chain types
rg -n "type ChainID|func AllChainIDs" --type=go model/flow/

Repository: onflow/flow-go

Length of output: 206


🏁 Script executed:

# See what AllChainIDs returns
rg -n "func AllChainIDs" --type=go -A 10 model/flow/

Repository: onflow/flow-go

Length of output: 485


🏁 Script executed:

# Check if there's chain-specific logic for bridge deployment on mainnet/testnet
sed -n '1042,1200p' fvm/bootstrap.go

Repository: onflow/flow-go

Length of output: 7193


🏁 Script executed:

# Look for where bridge contracts might be deployed on mainnet/testnet separately
rg -n "migration|deploy.*bridge|bridge.*deploy" --type=go -i fvm/ | grep -v test | head -20

Repository: onflow/flow-go

Length of output: 1827


🏁 Script executed:

# Double-check: does SystemContractsForChain return different contracts for different chains?
# Look for any filtering or chain-specific logic in the SystemContracts construction
sed -n '575,700p' fvm/systemcontracts/system_contracts.go | grep -A 100 "getSystemContractsForChain"

Repository: onflow/flow-go

Length of output: 5179


🏁 Script executed:

# Check if Mainnet and Testnet are transient
rg -n "func.*Transient|func.*IsTransient" --type=go model/flow/chain.go -A 5

Repository: onflow/flow-go

Length of output: 349


🏁 Script executed:

# Look for any documented notes about bridge contract availability on mainnet/testnet
rg -n "bridge.*mainnet|bridge.*testnet|bridge.*availability" --type=go -i | head -20

Repository: onflow/flow-go

Length of output: 378


🏁 Script executed:

# Final confirmation: check if there's any migration plan or deployment roadmap for bridge contracts on mainnet/testnet
rg -n "bridge.*migration|rollout.*bridge|deploy.*bridge" --type=go -i | grep -v "test" | head -15

Repository: onflow/flow-go

Length of output: 2084


🏁 Script executed:

# Check if the test actually validates this concern
rg -n "TestSystemContracts|checkSystemContracts" --type=go -A 20 fvm/systemcontracts/system_contracts_test.go | head -50

Repository: onflow/flow-go

Length of output: 1955


Bridge contracts are only deployed on transient networks, but All() returns them for all chains including Mainnet and Testnet.

The bridge contracts (CrossVMNFT, CrossVMToken, FlowEVMBridge*, BridgeUtils, etc.) are only deployed during bootstrap on transient networks (Emulator, Previewnet, etc.) via the setupVMBridge() function which returns early for non-transient chains. However, All() includes these contracts for all chains (Mainnet, Testnet, Sandboxnet, etc.), which means tests checking contract existence will report valid addresses but the contracts won't actually be deployed on long-lived networks. Verify whether this is intentional (e.g., planned for future rollout) or if All() and the system contracts registry should only include contracts that are actually deployed on each target chain.

🤖 Prompt for AI Agents
In `@fvm/systemcontracts/system_contracts.go` around lines 355 - 380, All()
currently lists bridge contracts (CrossVMNFT, CrossVMToken, FlowEVMBridge*,
FlowEVMBridgeUtils, etc.) even though setupVMBridge() only deploys them on
transient networks; update the registry so All() only includes those
bridge-related contracts for transient chains (or when setupVMBridge() indicates
they were deployed) — locate the All() function in system_contracts.go and
either filter out the bridge symbols for non-transient chains (e.g., check the
chain type or call the same transient check used by setupVMBridge()) or move the
bridge entries into the transient-only registration path so that contract
existence checks reflect actual deployments.

@janezpodhostnik
Copy link
Contributor

This adds a lot of contracts to the default bootstrapping, is this something we need for flow-go or do we just need it downstream?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Comments