Skip to content

feat: Isolated Adapter Cross-Chain Tests#775

Merged
wischli merged 73 commits intomainfrom
multi-chain-tests-v3
Feb 17, 2026
Merged

feat: Isolated Adapter Cross-Chain Tests#775
wischli merged 73 commits intomainfrom
multi-chain-tests-v3

Conversation

@wischli
Copy link
Contributor

@wischli wischli commented Feb 10, 2026

Updated port from https://github.com/centrifuge/protocol-internal/pull/119

Extends (and supersedes) #767 and replaces cross-chain tests created there with isolated pool adapter tests. In #767, the main goal was first to ensure cross-chain messages were working. However, the setup there involved an unhappy UX because

  1. the unbatched messages often failed due to race-condition (i.e. NotifyShareClass before NotifyPool)
  2. the setup theoretically prepared for an invest flow but in practice was too cumbersome to get anything out of it other succeeded messages from hub to spoke and vice versa (ref)

Please note the changelog description includes also changes from #767 done by @gpmayorga

Per @gpmayorga 's request, no deployment changes from his branch were touched:

  ┌───────────────────────────────┬───────────────────────────────┬───────────────────────────┐
  │             File              │             PR #767           │        This PR            │
  ├───────────────────────────────┼───────────────────────────────┼───────────────────────────┤
  │ env/*.json contracts          │ null blockNumber/txHash       │ Actual values ✅          │
  ├───────────────────────────────┼───────────────────────────────┼───────────────────────────┤
  │ env/*.json adapters.threshold │ Missing (outdated)            │ 2 ✅                      │
  ├───────────────────────────────┼───────────────────────────────┼───────────────────────────┤
  │ verifier.py                   │ Simple receipts-only parsing  │ CREATE3/factory-aware ✅  │
  ├───────────────────────────────┼───────────────────────────────┼───────────────────────────┤
  │ load_config.py                │ Direct private key assignment │ Mainnet/testnet safety ✅ │
  ├───────────────────────────────┼───────────────────────────────┼───────────────────────────┤
  │ deploy.py                     │ Identical                     │ Identical                 │
  ├───────────────────────────────┼───────────────────────────────┼───────────────────────────┤
  │ runner.py                     │ Identical                     │ Identical                 │
  └───────────────────────────────┴───────────────────────────────┴───────────────────────────┘

Product requirements

  • Consolidate testnet cross-chain adapter testing into a single script (TestAdapterIsolation.s.sol) that supports all four adapters (Axelar, LayerZero, Wormhole, Chainlink) with a cost-efficient three-phase workflow
  • Replace the old two-script approach (TestCrossChainHub + TestCrossChainSpoke) with a unified script that separates pool creation, adapter configuration, and repeatable share class testing
  • Improve deployment automation: deploy all testnets in a single CI run, support dry-run for PRs, add automatic contract verification for factory-deployed contracts
  • Disable Wormhole adapter deployment on testnets (sepolia) and mainnet chains (Avalanche, BNB) as part of deprecation
  • Update adapter wiring to handle asymmetric configurations where not all adapters are deployed on every chain

Design notes

  • TestAdapterIsolation.s.sol uses a three-phase design: Phase 1 creates pools (hub-only, no XC), Phase 2 configures isolated adapters (2 XC messages each), Phase 3 sends NotifyShareClass (repeatable without re-running setup). This replaces the previous approach that required full re-setup for each test round
  • BaseTestData.s.sol was refactored to load adapter contract references (Axelar, LayerZero, Wormhole, Chainlink) from config JSON, enabling per-pool adapter isolation via hub.setAdapters()
  • WireAdapters.s.sol now checks the deploy flag in destination network config before wiring, preventing InvalidAdapter errors from asymmetric adapter configurations
  • The deploy CI workflow (deploy.yml) was simplified from per-network manual dispatch to a single deploy:testnets command that handles all testnet deployments sequentially with optional dry-run
  • deploy.py gained deploy:testnets and crosschaintest:hub/crosschaintest:spoke steps, plus automatic factory contract verification via verify:contracts
  • Wormhole deploy flag set to false in sepolia.json, avalanche.json, and bnb-smart-chain.json. Wormhole is being deprecated. Scanner URLs updated with direct filtered links
  • Pool index scheme: one pool per adapter at GAS_TEST_BASE + adapterIndex (default 91000). Chainlink support added (index 3) with single-message phases to stay under CCIP's per-message gas limit

gpmayorga and others added 30 commits October 17, 2025 19:07
- Updated argument validation to support new deployment steps and improved error handling.
- Enhanced wiring logic for adapters, including support for multiple connected networks.
…nventions

- Changed backward compatibility check in deploy.py from "release:sepolia" to "deploy:testnets".
- Updated contract names in crosschain.py to use lowercase for consistency.
- Added logic in WireAdapters.s.sol to skip deployment if the deploy flag is set to false.
- Updated deployment step names from "deploy:testnets" to "deploy:all" for consistency.
- Changed references from "deploy:protocol" to "deploy:full" to align with new deployment structure.
- Adjusted user prompts and validation messages to reflect the updated command usage.
- Ensured backward compatibility for the new deployment step naming.
- Updated deployment step from "deploy:all" to "deploy:testnets" for clarity and consistency.
- Implemented dry-run mode to skip verification and state saving during test deployments.
- Added early network validation in load_config.py to prevent loading .env values if a network mismatch is detected.
- Updated deploy.py to normalize the step for the special case of deploying to testnets.
- Improved runner.py to skip verification in dry-run mode with appropriate messaging.
* base implementation

impl almost complete

add BRM and split in two spells

protect calls

migrate PoolEscrow

organize spell

draft next steps

add script and test structure

more correct setup

minor changes

minor changes

more dubugging process

move validationf files to validation folder

fix

fixes

fix version

deployment changes

working preview address

remove check

parameterize deployer address in Deployer contract

use registerPool

remove manual process to ensure no outstanding orders

test passing but without indexing data

retrieve the hubPools from indexer

more indexer data and fixes

* fix subsidizing issue

* correct refunding

* correct refunding assuming no escrow used in spoke side

* fixes and more support

* onOfframp indexer requests

* link vaults correctly and fix bs managers

* filtered assets and centrifugeIds

* fix imports

* correclty process for unexisting poolIds in that chain

* fix asset treatment

* fix import

* tested for all chains working

* add spell lock post-check

* discard all spell test from CI

* fix spelling

* minor changes from review

* fix spelling

* fix coverage

* fix anvil
* testnet support

* Add patch to suppor the non-existence of freelyTransferibleHook in testnets

* migration fixes

* custom pools by input

* add pool for testnet

Signed-off-by: lemunozm <lemunozm@gmail.com>

* fix spelling

---------

Signed-off-by: lemunozm <lemunozm@gmail.com>
* rely steps for root in migration

* add deployer for the migration

* deploy with blocked registerAsset and fix it in the spell

* simplify migration script

* unify migration spells into just one

* disable spell

* fix imports

* apply comments
@wischli
Copy link
Contributor Author

wischli commented Feb 10, 2026

@gpmayorga When you have the time, please take a look if I truly included all of your desired changes from #767 and didn't flush them, especially in 9beffab where I removed any changed to env files because I believe these were outdated at this point.

Also @lemunozm please take a look at all deployment related changes. I am not fully synced on the details from the recent changes in the last weeks. All I wanted to achieve here is better cross chain adapter tests on top of #767.

Copy link
Contributor

@lemunozm lemunozm left a comment

Choose a reason for hiding this comment

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

Well done with the AdapterIsolation script! Nice to have it. Just some minor comments.

Also @lemunozm please take a look at all deployment related changes. I am not fully synced on the details from the recent changes in the last weeks. All I wanted to achieve here is better cross chain adapter tests on top of #767.

I think everything is good. You probably will have a small git conflict in anvil.py when rebasing. Now the generated evn json file must have a baseRpcUrl

Comment on lines 147 to 160
### Contract Addresses (Same on All Chains via CREATE3)

```bash
export ROOT=0x8a7c1D479Cc77a5458F74C480B9b306BB29b953e
export MULTI_ADAPTER=0x2C61BC7C5aF7f0Af2888dE9343C3ce4b2fBf5933
export HUB=0xE5e49CEdB5D3DCD24b25e2886a0c5E27e2e9CBe9
export HUB_REGISTRY=0x92e78c7680303b04e4CE9d1736c000288e2339E5
export VAULT_REGISTRY=0x22dB7862f9D903F49CF179C7079E72739f5a3c1D
export SPOKE=0x7Ac5B65764A8b1A19E832FdE942ce618EeF823aF

# Adapters
export AXELAR_ADAPTER=0xb324e55F8332748142274FC76De0A8D95d453Ada
export LAYERZERO_ADAPTER=0x24f3192d46869609F8F6605e662b8146CA4240d3
export WORMHOLE_ADAPTER=0x5940ad8841C50a57F0464f36BaF488964E86655e
Copy link
Contributor

Choose a reason for hiding this comment

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

These are no longer valid because we redeployed in testnet with fresh addreses


---

## Step 0: Register Asset (One-Time Setup)
Copy link
Contributor

@lemunozm lemunozm Feb 12, 2026

Choose a reason for hiding this comment

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

NIT (and maybe not for now). Wondering if all these steps can be added to a .sh file instead 🤔

@lemunozm lemunozm mentioned this pull request Feb 12, 2026
2 tasks
@gpmayorga
Copy link
Collaborator

The deployment is broken for some reason (see CI checks). I will be able to take a look at this tomorrow (Friday 13th)

@lemunozm
Copy link
Contributor

Yeah, it seems like crosschain.py is missing in this PR

Adds CrossChainTestManager used by deploy.py for crosschaintest:hub
and crosschaintest:spoke steps. Was missing from the branch despite
deploy.py already importing it.
@gpmayorga gpmayorga force-pushed the multi-chain-tests-v3 branch from 5646dd9 to 664d8cb Compare February 13, 2026 14:51
@gpmayorga
Copy link
Collaborator

crosschain.py added

Modified the AnvilManager class to pass additional parameters (network_name, port, dst_cfg, chain_id) to the AnvilEnv constructor, enhancing its configuration capabilities.
@gpmayorga
Copy link
Collaborator

gpmayorga commented Feb 13, 2026

Fixed the anvil deployments and updated the branch from main. IMO this is ready to go

gpmayorga and others added 5 commits February 13, 2026 16:15
Updated the CrossChainTestManager to support a full 4-step cross-chain test sequence, including asset registration, hub setup, relay waiting, and share class testing. Added new command options for streamlined execution and improved documentation in README.md for clarity on usage. Adjusted argument parsing to include new test phases.
Consolidated the creation of environment files for Sepolia and Arbitrum Sepolia in the AnvilManager class. This change ensures both environment files are created upfront
- Override protocolAdmin/opsAdmin in anvil env with anvil account
  addresses so OpsGuardian/ProtocolGuardian accept calls from the
  deployer (fixes NotTheAuthorizedSafe)
- Remove stray undefined `verifier` reference (would crash with
  NameError)
- Use --disable-block-gas-limit for anvil forks (Arbitrum gas model
  inflates estimates beyond any fixed limit)
- Remove redundant WireAdapters step (FullDeployer already wires
  adapters during deploy:full)
- Fix verification to extract address from contract entry dict
  (was passing the full {address, blockNumber, txHash} object)
Copy link
Contributor

@lemunozm lemunozm left a comment

Choose a reason for hiding this comment

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

Good job here to both @wischli and @gpmayorga! LGTM!!

@wischli
Copy link
Contributor Author

wischli commented Feb 17, 2026

Thanks for cleaning up after my slight mess @gpmayorga 🫶

@wischli wischli merged commit 7893125 into main Feb 17, 2026
13 of 14 checks passed
@wischli wischli deleted the multi-chain-tests-v3 branch February 17, 2026 08:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants