QA: Test Solana Bridge Integration on Devnet #60

Closed
opened 2026-03-18 13:45:00 +00:00 by PlasticDigits · 6 comments
PlasticDigits commented 2026-03-18 13:45:00 +00:00 (Migrated from gitlab.com)

Overview

The feat/solana-integration branch adds full Solana chain support to the CL8Y bridge. This needs thorough QA testing on Solana devnet before merging to main, so that our live production mainnet (EVM + Terra) is not affected.

Branch: feat/solana-integration


Prerequisites

  1. Solana CLI — Install via sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)"
  2. Anchor CLI — Install via cargo install --git https://github.com/coral-xyz/anchor anchor-cli
  3. A devnet wallet — solana-keygen new -o ~/.config/solana/devnet-deployer.json
  4. Devnet SOL — solana airdrop 5 --url devnet
  5. Node.js 18+ and Rust 1.75+

Step 1: Deploy the Solana Program to Devnet

# From repo root
git checkout feat/solana-integration

# Deploy to devnet
./scripts/solana/deploy.sh devnet

Note the Program ID printed at the end. You'll need it for all subsequent steps.


Step 2: Initialize the Bridge

# Set env vars for scripts
export SOLANA_RPC_URL=https://api.devnet.solana.com
export SOLANA_PROGRAM_ID=<program-id-from-step-1>
export SOLANA_KEYPAIR_PATH=~/.config/solana/devnet-deployer.json

# Initialize bridge config (sets admin, fee, withdraw delay)
npx ts-node scripts/solana/initialize-bridge.ts

Step 3: Register Chains & Tokens

# Register EVM chain on Solana bridge
npx ts-node scripts/solana/register-chain-evm.ts

# Register token mappings (native SOL + any SPL tokens)
npx ts-node scripts/solana/register-tokens.ts

Step 4: Run Anchor Tests (On-chain Logic)

cd packages/contracts-solana

# Run all Anchor tests against localnet validator
anchor test

# Key test suites to check:
# - tests/deposit_withdraw.test.ts  → full deposit + withdraw lifecycle
# - tests/cancel_flow.test.ts       → canceler flow
# - tests/hash_parity.test.ts       → cross-chain hash compatibility

What to verify:

  • All tests pass with zero failures
  • Hash parity test confirms Solana hashes match EVM keccak256 output
  • Close-reinit replay protection test passes (ExecutedHash PDA prevents double-spend)
  • Fee edge cases (0 fee, 100% fee) are handled correctly

Step 5: Test Operator + Canceler with Solana

Start the operator and canceler with Solana enabled:

# Operator env vars (add to existing .env)
SOLANA_ENABLED=true
SOLANA_RPC_URL=https://api.devnet.solana.com
SOLANA_PROGRAM_ID=<program-id>
SOLANA_KEYPAIR_PATH=~/.config/solana/devnet-deployer.json
SOLANA_V2_CHAIN_ID=<bytes4-chain-id>
SOLANA_POLL_INTERVAL_MS=5000

# Start operator
cd packages/operator && cargo run

# In another terminal, start canceler with same SOLANA_* env vars
cd packages/canceler && cargo run

What to verify:

  • Operator watcher picks up Solana deposit events and inserts into solana_deposits table
  • Operator writer submits withdraw_approve transactions successfully
  • Canceler polls WithdrawApprove events from Solana
  • Canceler reads PendingWithdraw PDA to get src_chain_id
  • If a fraudulent approval is detected, canceler submits withdraw_cancel

Step 6: Test Frontend Solana Integration

cd packages/frontend
npm install
npm run dev

What to verify:

  • Solana chain appears in the chain list with correct "Solana" label (not "Cosmos")
  • Solana RPC health check works (green dot in Settings > ChainCard)
  • Bridge config panel shows correct data for Solana (admin, feeBps, withdrawDelay)
  • Phantom / Solflare wallet connection works
  • Native SOL deposit flow completes (on devnet)
  • SPL token deposit flow completes (mint a test SPL token first)
  • Faucet panel shows Solana option when VITE_SOLANA_FAUCET_ADDRESS is set

Step 7: Cross-Chain E2E Flow (Manual)

Test a full round-trip:

  1. Solana → EVM deposit: Deposit SOL on devnet, verify operator picks up event, submits approval on EVM testnet
  2. EVM → Solana withdraw: Submit withdraw on Solana devnet, verify operator approves, wait for delay, execute withdraw
  3. Cancel flow: Submit a withdraw, have the canceler cancel it before execution, verify re-enable works

Step 8: Run E2E Tests

cd packages/e2e

# These require a running Solana devnet validator + deployed program
SOLANA_RPC_URL=https://api.devnet.solana.com \
SOLANA_PROGRAM_ID=<program-id> \
cargo test test_solana -- --nocapture

Security Checklist

  • Replay protection: Confirm ExecutedHash PDA prevents re-execution of the same transfer hash
  • Close-reinit attack: After a withdraw is executed, try to withdraw_submit with the same hash — should fail with AlreadyExecutedHash
  • MintBurn fee handling: For MintBurn tokens, verify fee goes to the bridge fee collector token account (not burned)
  • Access control: Only admin can call set_config, add_canceler, register_chain, register_token
  • Only cancelers can cancel: withdraw_cancel requires a valid CancelerEntry PDA

Environment Variables Reference

Variable Description Example
SOLANA_ENABLED Enable Solana support true
SOLANA_RPC_URL Solana RPC endpoint https://api.devnet.solana.com
SOLANA_PROGRAM_ID Deployed program address CL8Y...
SOLANA_KEYPAIR_PATH Path to signer keypair ~/.config/solana/id.json
SOLANA_V2_CHAIN_ID 4-byte chain ID (hex) 0x736f6c00
SOLANA_POLL_INTERVAL_MS Watcher poll interval 5000
SOLANA_COMMITMENT RPC commitment level finalized
VITE_SOLANA_RPC_URL Frontend RPC URL https://api.devnet.solana.com
VITE_SOLANA_FAUCET_ADDRESS Faucet for devnet testing (optional)

Notes

  • Do NOT merge to main until all checklist items above pass. Main branch serves live EVM + Terra production.
  • If you hit rate limits on devnet RPC, use a dedicated RPC provider (e.g., Helius, Alchemy).
  • The Anchor.toml uses a placeholder program ID for localnet. After deploying to devnet, update it with the real program ID.
  • Refer to docs/SOLANA_INTEGRATION_PLAN.md for architectural details.
## Overview The **feat/solana-integration** branch adds full Solana chain support to the CL8Y bridge. This needs thorough QA testing on **Solana devnet** before merging to main, so that our live production mainnet (EVM + Terra) is not affected. **Branch:** `feat/solana-integration` --- ## Prerequisites 1. **Solana CLI** — Install via `sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)"` 2. **Anchor CLI** — Install via `cargo install --git https://github.com/coral-xyz/anchor anchor-cli` 3. **A devnet wallet** — `solana-keygen new -o ~/.config/solana/devnet-deployer.json` 4. **Devnet SOL** — `solana airdrop 5 --url devnet` 5. **Node.js 18+** and **Rust 1.75+** --- ## Step 1: Deploy the Solana Program to Devnet ```bash # From repo root git checkout feat/solana-integration # Deploy to devnet ./scripts/solana/deploy.sh devnet ``` Note the **Program ID** printed at the end. You'll need it for all subsequent steps. --- ## Step 2: Initialize the Bridge ```bash # Set env vars for scripts export SOLANA_RPC_URL=https://api.devnet.solana.com export SOLANA_PROGRAM_ID=<program-id-from-step-1> export SOLANA_KEYPAIR_PATH=~/.config/solana/devnet-deployer.json # Initialize bridge config (sets admin, fee, withdraw delay) npx ts-node scripts/solana/initialize-bridge.ts ``` --- ## Step 3: Register Chains & Tokens ```bash # Register EVM chain on Solana bridge npx ts-node scripts/solana/register-chain-evm.ts # Register token mappings (native SOL + any SPL tokens) npx ts-node scripts/solana/register-tokens.ts ``` --- ## Step 4: Run Anchor Tests (On-chain Logic) ```bash cd packages/contracts-solana # Run all Anchor tests against localnet validator anchor test # Key test suites to check: # - tests/deposit_withdraw.test.ts → full deposit + withdraw lifecycle # - tests/cancel_flow.test.ts → canceler flow # - tests/hash_parity.test.ts → cross-chain hash compatibility ``` ### What to verify: - [ ] All tests pass with zero failures - [ ] Hash parity test confirms Solana hashes match EVM keccak256 output - [ ] Close-reinit replay protection test passes (ExecutedHash PDA prevents double-spend) - [ ] Fee edge cases (0 fee, 100% fee) are handled correctly --- ## Step 5: Test Operator + Canceler with Solana Start the operator and canceler with Solana enabled: ```bash # Operator env vars (add to existing .env) SOLANA_ENABLED=true SOLANA_RPC_URL=https://api.devnet.solana.com SOLANA_PROGRAM_ID=<program-id> SOLANA_KEYPAIR_PATH=~/.config/solana/devnet-deployer.json SOLANA_V2_CHAIN_ID=<bytes4-chain-id> SOLANA_POLL_INTERVAL_MS=5000 # Start operator cd packages/operator && cargo run # In another terminal, start canceler with same SOLANA_* env vars cd packages/canceler && cargo run ``` ### What to verify: - [ ] Operator watcher picks up Solana deposit events and inserts into `solana_deposits` table - [ ] Operator writer submits `withdraw_approve` transactions successfully - [ ] Canceler polls `WithdrawApprove` events from Solana - [ ] Canceler reads `PendingWithdraw` PDA to get `src_chain_id` - [ ] If a fraudulent approval is detected, canceler submits `withdraw_cancel` --- ## Step 6: Test Frontend Solana Integration ```bash cd packages/frontend npm install npm run dev ``` ### What to verify: - [ ] Solana chain appears in the chain list with correct "Solana" label (not "Cosmos") - [ ] Solana RPC health check works (green dot in Settings > ChainCard) - [ ] Bridge config panel shows correct data for Solana (admin, feeBps, withdrawDelay) - [ ] Phantom / Solflare wallet connection works - [ ] Native SOL deposit flow completes (on devnet) - [ ] SPL token deposit flow completes (mint a test SPL token first) - [ ] Faucet panel shows Solana option when `VITE_SOLANA_FAUCET_ADDRESS` is set --- ## Step 7: Cross-Chain E2E Flow (Manual) Test a full round-trip: 1. **Solana → EVM deposit**: Deposit SOL on devnet, verify operator picks up event, submits approval on EVM testnet 2. **EVM → Solana withdraw**: Submit withdraw on Solana devnet, verify operator approves, wait for delay, execute withdraw 3. **Cancel flow**: Submit a withdraw, have the canceler cancel it before execution, verify re-enable works --- ## Step 8: Run E2E Tests ```bash cd packages/e2e # These require a running Solana devnet validator + deployed program SOLANA_RPC_URL=https://api.devnet.solana.com \ SOLANA_PROGRAM_ID=<program-id> \ cargo test test_solana -- --nocapture ``` --- ## Security Checklist - [ ] **Replay protection**: Confirm `ExecutedHash` PDA prevents re-execution of the same transfer hash - [ ] **Close-reinit attack**: After a withdraw is executed, try to `withdraw_submit` with the same hash — should fail with `AlreadyExecutedHash` - [ ] **MintBurn fee handling**: For MintBurn tokens, verify fee goes to the bridge fee collector token account (not burned) - [ ] **Access control**: Only admin can call `set_config`, `add_canceler`, `register_chain`, `register_token` - [ ] **Only cancelers can cancel**: `withdraw_cancel` requires a valid `CancelerEntry` PDA --- ## Environment Variables Reference | Variable | Description | Example | |---|---|---| | `SOLANA_ENABLED` | Enable Solana support | `true` | | `SOLANA_RPC_URL` | Solana RPC endpoint | `https://api.devnet.solana.com` | | `SOLANA_PROGRAM_ID` | Deployed program address | `CL8Y...` | | `SOLANA_KEYPAIR_PATH` | Path to signer keypair | `~/.config/solana/id.json` | | `SOLANA_V2_CHAIN_ID` | 4-byte chain ID (hex) | `0x736f6c00` | | `SOLANA_POLL_INTERVAL_MS` | Watcher poll interval | `5000` | | `SOLANA_COMMITMENT` | RPC commitment level | `finalized` | | `VITE_SOLANA_RPC_URL` | Frontend RPC URL | `https://api.devnet.solana.com` | | `VITE_SOLANA_FAUCET_ADDRESS` | Faucet for devnet testing | (optional) | --- ## Notes - **Do NOT merge to main** until all checklist items above pass. Main branch serves live EVM + Terra production. - If you hit rate limits on devnet RPC, use a dedicated RPC provider (e.g., Helius, Alchemy). - The `Anchor.toml` uses a placeholder program ID for localnet. After deploying to devnet, update it with the real program ID. - Refer to `docs/SOLANA_INTEGRATION_PLAN.md` for architectural details.
PlasticDigits commented 2026-03-18 13:45:01 +00:00 (Migrated from gitlab.com)

assigned to @Brouie

assigned to @Brouie
PlasticDigits commented 2026-03-18 14:27:01 +00:00 (Migrated from gitlab.com)

Local Dev Setup Guide & Current Status

Branch: feat/solana-integration (latest: 1f01c90)


Quick Start (Local Environment)

git checkout feat/solana-integration

# 1. Start infrastructure (Anvil, LocalTerra, Solana validator, Postgres)
make start

# 2. Wait for all containers to be healthy, then deploy contracts
make deploy

# 3. Set up cross-chain bridge registration
export EVM_BRIDGE_ADDRESS=0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0
export EVM_CHAIN_REGISTRY=$(grep CHAIN_REGISTRY packages/contracts-evm/broadcast/DeployLocal.s.sol/31337/run-latest.json 2>/dev/null | head -1 || echo "check broadcast logs")
export TERRA_BRIDGE_ADDRESS=terra17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9jfksztgw5uh69wac2pgsydrqk7
./scripts/setup-bridge.sh

Frontend Setup

cd packages/frontend
npm install

Create packages/frontend/.env.local:

VITE_NETWORK=local
VITE_TERRA_BRIDGE_ADDRESS=terra17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9jfksztgw5uh69wac2pgsydrqk7
VITE_EVM_BRIDGE_ADDRESS=0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0
VITE_EVM_ROUTER_ADDRESS=
VITE_BRIDGE_TOKEN_ADDRESS=
VITE_LOCK_UNLOCK_ADDRESS=0x0165878A594ca255338adfa4d48449f69242Eb8F
VITE_EVM_RPC_URL=http://localhost:8545
VITE_TERRA_LCD_URL=http://localhost:1317
VITE_TERRA_RPC_URL=http://localhost:26657
VITE_DEV_MODE=true

Then start the dev server:

npm run dev
# Frontend available at http://localhost:3000

Infrastructure Fixes Applied (commit 1f01c90)

The following issues were discovered and fixed during local setup:

Issue Fix
docker-compose command not found Replaced with docker compose (v2 syntax) throughout Makefile
solanalabs/solana:v2.2 image doesn't exist Changed to solanalabs/solana:v1.18.26 in docker-compose.yml
Solana validator crash: UnableToSetOpenFileDescriptorLimit Added ulimits.nofile: 1000000 to solana service
forge script fails with "default sender" error Added --sender and --private-key to Makefile deploy-evm target
Browser console: Module "buffer" has been externalized Added buffer to Vite resolve.alias and optimizeDeps.include
Solana chains not appearing in frontend dropdowns Fixed useDiscoveredChains.ts to pass solana type through filter

Frontend Integration Status

Working:

  • CONNECT SOL button in navbar (alongside TC and EVM)
  • SolanaWalletModal renders for Phantom/Solflare connection
  • Solana wallet status row in WalletStatusBar (purple accent)
  • Solana Localnet appears in FROM/TO chain selectors (local tier)
  • Solana and Solana Devnet appear in chain selectors (mainnet/testnet tiers)
  • Chain icons display correctly (localsolana-icon.png, solana-icon.png)
  • Transfer direction logic handles all 4 Solana routes (solana-to-evm, evm-to-solana, solana-to-terra, terra-to-solana)
  • Swap button correctly disables for solana-to-solana
  • Recipient autofill works with connected Solana wallet
  • No console errors (Buffer polyfill fixed)

Pending (requires deployed Solana program):

  • Actual Solana deposit execution (currently shows placeholder: "Solana deposits are not yet available")
  • Actual Solana withdraw execution (same placeholder)
  • useSolanaDeposit hook wired into handleSubmit (needs program ID)
  • Solana withdraw flow in useWithdrawSubmit
  • Solana RPC health check in Settings > ChainCard
  • Bridge config panel for Solana (admin, feeBps, withdrawDelay)

Solana-specific Frontend Env Vars (for devnet/mainnet)

When testing against devnet, add these to .env.local:

VITE_SOLANA_RPC_URL=https://api.devnet.solana.com
VITE_SOLANA_PROGRAM_ID=<program-id-after-deploy>
VITE_SOLANA_FAUCET_ADDRESS=<optional-faucet>

For local testing, the Solana test validator runs at http://localhost:8899 (started by docker compose).

## Local Dev Setup Guide & Current Status **Branch:** `feat/solana-integration` (latest: `1f01c90`) --- ### Quick Start (Local Environment) ```bash git checkout feat/solana-integration # 1. Start infrastructure (Anvil, LocalTerra, Solana validator, Postgres) make start # 2. Wait for all containers to be healthy, then deploy contracts make deploy # 3. Set up cross-chain bridge registration export EVM_BRIDGE_ADDRESS=0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0 export EVM_CHAIN_REGISTRY=$(grep CHAIN_REGISTRY packages/contracts-evm/broadcast/DeployLocal.s.sol/31337/run-latest.json 2>/dev/null | head -1 || echo "check broadcast logs") export TERRA_BRIDGE_ADDRESS=terra17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9jfksztgw5uh69wac2pgsydrqk7 ./scripts/setup-bridge.sh ``` ### Frontend Setup ```bash cd packages/frontend npm install ``` Create `packages/frontend/.env.local`: ```env VITE_NETWORK=local VITE_TERRA_BRIDGE_ADDRESS=terra17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9jfksztgw5uh69wac2pgsydrqk7 VITE_EVM_BRIDGE_ADDRESS=0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0 VITE_EVM_ROUTER_ADDRESS= VITE_BRIDGE_TOKEN_ADDRESS= VITE_LOCK_UNLOCK_ADDRESS=0x0165878A594ca255338adfa4d48449f69242Eb8F VITE_EVM_RPC_URL=http://localhost:8545 VITE_TERRA_LCD_URL=http://localhost:1317 VITE_TERRA_RPC_URL=http://localhost:26657 VITE_DEV_MODE=true ``` Then start the dev server: ```bash npm run dev # Frontend available at http://localhost:3000 ``` --- ### Infrastructure Fixes Applied (commit 1f01c90) The following issues were discovered and fixed during local setup: | Issue | Fix | |---|---| | `docker-compose` command not found | Replaced with `docker compose` (v2 syntax) throughout Makefile | | `solanalabs/solana:v2.2` image doesn't exist | Changed to `solanalabs/solana:v1.18.26` in docker-compose.yml | | Solana validator crash: `UnableToSetOpenFileDescriptorLimit` | Added `ulimits.nofile: 1000000` to solana service | | `forge script` fails with "default sender" error | Added `--sender` and `--private-key` to Makefile `deploy-evm` target | | Browser console: `Module "buffer" has been externalized` | Added `buffer` to Vite `resolve.alias` and `optimizeDeps.include` | | Solana chains not appearing in frontend dropdowns | Fixed `useDiscoveredChains.ts` to pass `solana` type through filter | --- ### Frontend Integration Status **Working:** - [x] CONNECT SOL button in navbar (alongside TC and EVM) - [x] SolanaWalletModal renders for Phantom/Solflare connection - [x] Solana wallet status row in WalletStatusBar (purple accent) - [x] Solana Localnet appears in FROM/TO chain selectors (local tier) - [x] Solana and Solana Devnet appear in chain selectors (mainnet/testnet tiers) - [x] Chain icons display correctly (localsolana-icon.png, solana-icon.png) - [x] Transfer direction logic handles all 4 Solana routes (solana-to-evm, evm-to-solana, solana-to-terra, terra-to-solana) - [x] Swap button correctly disables for solana-to-solana - [x] Recipient autofill works with connected Solana wallet - [x] No console errors (Buffer polyfill fixed) **Pending (requires deployed Solana program):** - [ ] Actual Solana deposit execution (currently shows placeholder: "Solana deposits are not yet available") - [ ] Actual Solana withdraw execution (same placeholder) - [ ] `useSolanaDeposit` hook wired into handleSubmit (needs program ID) - [ ] Solana withdraw flow in `useWithdrawSubmit` - [ ] Solana RPC health check in Settings > ChainCard - [ ] Bridge config panel for Solana (admin, feeBps, withdrawDelay) --- ### Solana-specific Frontend Env Vars (for devnet/mainnet) When testing against devnet, add these to `.env.local`: ```env VITE_SOLANA_RPC_URL=https://api.devnet.solana.com VITE_SOLANA_PROGRAM_ID=<program-id-after-deploy> VITE_SOLANA_FAUCET_ADDRESS=<optional-faucet> ``` For local testing, the Solana test validator runs at `http://localhost:8899` (started by `docker compose`).
Brouie commented 2026-03-19 06:22:45 +00:00 (Migrated from gitlab.com)

mentioned in issue #61

mentioned in issue #61
Brouie commented 2026-03-19 06:23:26 +00:00 (Migrated from gitlab.com)

mentioned in issue #62

mentioned in issue #62
Brouie commented 2026-04-01 04:55:00 +00:00 (Migrated from gitlab.com)

closing -- consolidating into new combined Solana Integration QA issue per dev request.

closing -- consolidating into new combined Solana Integration QA issue per dev request.
Brouie (Migrated from gitlab.com) closed this issue 2026-04-01 04:55:04 +00:00
Brouie commented 2026-04-01 04:55:40 +00:00 (Migrated from gitlab.com)

mentioned in issue #96

mentioned in issue #96
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-bridge-monorepo#60
No description provided.