QA: Verify Solana integration — full operator, frontend, canceler, and faucet wiring #67
Labels
No labels
agent:implement
agent:ready
backend
bug
cannot-reproduce
confirmed
desktop
docs
documentation
duplicate
enhancement
feature
frontend
good first issue
help wanted
high-risk
in-review
invalid
mobile
needs-triage
P0-critical
P1-high
P2-medium
P3-low
qa
QA
question
ready
report
responsive
security
security-escalate
smart-contract
solana
tablet
test-pass
ux
wallet-issue
wallet:keplr
wallet:metamask
wallet:station
wallet:walletconnect
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
code/cl8y-bridge-monorepo#67
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Commit
f6e0704onfeat/solana-integrationwires the full Solana integration across all services. This needs QA verification before merging.What changed
Operator (Rust)
SolanaConfigadded toConfig— loaded fromSOLANA_RPC_URL,SOLANA_PROGRAM_ID,SOLANA_PRIVATE_KEYenv varsSolanaWatchernow constructed and started when config is presentSolanaWriterspawned as a standalone task with shutdown handlingFrontend (React/TypeScript)
TransferForm(blocking guards removed,useSolanaDepositwired)fetchDepositNonce,computeTransferHash,buildWithdrawSubmitInstructionadded to transaction servicesubmitOnSolanaadded touseWithdrawSubmituseAutoWithdrawSubmitupdated with Solana branches (blockReason, triggerSubmit, startPolling)solanaTokenExistsinstead of falling through to Terra)TransferStatusPageupdated with Solana direction handlingBridgeChainConfigtype extended withprogramId,explorerTxUrl,faucetAddressFaucet
cl8y-faucetAnchor program:initialize,register_mint,claim(SPL with cooldown),claim_solsetup-test-tokens.shscript for creating test SPL mintsFaucetPanelupdated withSolanaBalanceCell,SolanaClaimButton,SolAirdropButtonCanceler (Rust)
read_pending_withdraw_fullparses all PendingWithdraw PDA fieldspoll_solana_approvalsno longer uses zeroed-placeholder dataSolanaCancelerClientaccepts configurable commitment levelQA checklist
SOLANA_RPC_URLset and logs show Solana watcher + writer initializedSOLANA_RPC_URLand Solana modules are skipped cleanlypoll_solana_approvalsreads full PDA data (check logs for populated fields)SOLANA_COMMITMENT=confirmedand verify)cl8y-faucetprogram builds withanchor buildsetup-test-tokens.shcreates mints successfully/cc @Brouie
assigned to @Brouie
Initial #67 findings: (1) anchor-cli on server is 1.0.0-rc.4 but project targets 0.32.1. Causes key mismatch on build. avm not installed so cannot downgrade without dev. (2) cl8y-faucet fails to compile (23 errors: E0277, E0432, E0599). Likely anchor version mismatch. (3) register-tokens.sh on devnet still blocked — same root cause as #62 (fresh keypairs every run). (4) anchor keys sync worked but anchor build -p cl8y_bridge then shows different keypair hash (EhetQnc vs CNWdzCX). Suspect rc.4 regenerates deploy keys. (5) Bridge .so from previous build still works — 35/35 tests pass on localnet including test fix
9b4f6b9. Pivoting to DEX #18 while devnet blockers are addressed.mentioned in commit
368e8ba99c@Brouie Fix pushed to
feat/solana-integration(368e8ba). The compile errors were not just CLI version skew —cl8y-faucet/Cargo.tomlwas missing theinit-if-neededfeature onanchor-langand theassociated_tokenfeature onanchor-spl, which its account constraints require. Both are now enabled, plusidl-buildfor IDL generation parity.Also pinned
anchor_version = "0.32.1"andsolana_version = "2.2.12"inAnchor.tomlso the CLI matches the crates (should fix the deploy-key regeneration you saw). Added faucet integration tests (faucet.test.ts) and a CI job forcontracts-solana. Please re-testanchor build -p cl8y_fauceton the server.Pulled
368e8ba. Faucet build still blocked — anchor-cli 1.0.0-rc.4 regenerates deploy keypairs on build even after keys sync. keys sync sets GDRbn9 but build sees 9P336P. avm install fails too (not properly installed). Can you install anchor-cli 0.32.1 on the server? Can't do any builds until that's resolved.@Brouie Yes, added 0.32.1, please check
@Brouie When you have a moment, please review the latest Solana QA fixes on
feat/solana-integration: faucetclaim_solnow moves lamports from the config PDA correctly (no SystemProgram CPI from a data-carrying account), Anchor/npm tooling is standardized (package-lock,.npmrc, removedyarn.lock), andanchor testshould be green including faucet. QA server: pull as your user,npm ciinpackages/contracts-solana+ frontend if needed, thenanchor build/anchor test --skip-build. Thanks.mentioned in issue #74
Final #67 verification status:
[x] Operator starts with SOLANA_RPC_URL — Solana watcher + writer initialized (verified 3/24)
[x] Operator starts without SOLANA_RPC_URL — Solana modules skipped cleanly (verified 3/24)
[x] cl8y-faucet builds with anchor build (verified 3/24)
[x] Frontend: Solana chain appears in chain list — PASS
[x] Frontend: Solana wallet connection (Phantom) — PASS
[x] Frontend: Recipient autofill with connected wallet — PASS
[x] Frontend: Solana RPC health check in Settings — green 102ms (fixed in #74, closed)
[x] Frontend: Route validation for Solana destinations — PASS
[ ] Frontend: Solana deposit execution — blocked by CSP WebSocket (#75)
[ ] Frontend: Solana withdraw execution — blocked by #75
[ ] FaucetPanel: SOL airdrop / SPL claim — no faucet configured in .env.local
[ ] Canceler: poll_solana_approvals — not tested (needs operator + canceler running together)
[ ] setup-test-tokens.sh — not tested
[ ] Cross-chain E2E — 4/6 pass, #70 open (operator keypair mismatch)
8/13 verified. Remaining 5 blocked by #70 and #75.
E2E update: 6/6 Solana E2E tests ALL PASS (make solana-test-e2e with --test-threads=1). Verified flows: evm_to_solana, solana_to_evm_deposit, cancel_flow, bridge_program_exists, admin_funded, validator_running. #70 closed. Remaining #67 items: frontend Solana deposit/withdraw flows, FaucetPanel.
Frontend #67: Solana deposit_native + withdraw_submit tx builders aligned with on-chain PDAs; TransferForm token mapping + transfer record fields; FaucetPanel shows Solana when RPC/dev; explorer + airdrop UX. Frontend build passes. Verified Settings → Faucet tab in dev server.
Pulled latest security push. New code reviewed: rate_limit.rs (24h rolling window, 8 unit tests), decimal.rs (normalize with proptest 4096 cases), nonce_used.rs (replay protection PDA), deposit_withdraw.test.ts (full flows moved from Rust E2E to anchor). 173/179 solana-test pass — 6 fail due to rate limit not configured in existing tests (#76). make solana-test-e2e broken by Bad substitution + test restructuring (#77). 3 new Playwright specs for Solana transfers (need browser). Operator migration 012 adds terra transfer_hash for Terra-to-Solana routing.
Frontend QA pass (laptop, Chrome, dark mode, v0.1.140):
VERIFIED:
ISSUES:
REMAINING:
CLI verification:
CLI items done. Remaining are end-to-end transfer flows (need EVM port forwarding + SOL balance).
QA on SSH-only VPS: local port forwarding (Solana + EVM) without breaking CSP / security
This documents the intended setup when chains run on a locked-down VPS (SSH only) and the browser runs on your laptop (e.g.
npm run devathttp://localhost:5173). It matches how the frontend is built today and avoids the issues called out in recent #67 QA (missing 8900, EVM RPC unreachable, SOL balance--).1. Why SSH
-Land not the VPS public IP in.envThe app’s Content-Security-Policy (
packages/frontend/index.html) allowsconnect-srctohttp(s)://localhost:*andhttp(s)://127.0.0.1:*andws(s)://to the same — not arbitraryhttp://<vps-ip>:…. If you put the VPS hostname or public IP inVITE_*RPC URLs, the browser will block those requests even if the network path worked.Do this instead: On the laptop, open local forwards so the browser keeps using
http://127.0.0.1:…/ws://127.0.0.1:…(orlocalhost). Traffic then goes over SSH to127.0.0.1on the VPS where validators listen.That does not weaken CORS for the app: you are not opening new public RPC ports; only your SSH session bridges them. RPC nodes still only accept connections from the VPS loopback (or your existing bind config).
2. Ports to forward (typical local stack)
8899 → 127.0.0.1:8899getBalance, txs).8900 → 127.0.0.1:8900@solana/web3.jsConnectionuses subscriptions; balance/UI often needs WS. Forwarding 8899 alone explains--balance and WS noise in the console.8545 → 127.0.0.1:8545BRIDGE_CHAINS.local.anvil/VITE_EVM_RPC_URLdefaults.8546 → 127.0.0.1:8546anvil1in the UI.1317,26657Example one SSH session (adjust user/host):
Keep this session open while testing. Use
ServerAliveIntervalif idle drops are a problem:3. Environment variables on the laptop (frontend)
Use the same logical URLs as local all-in-one dev, pointing at 127.0.0.1 after the tunnel is up:
VITE_NETWORK=localVITE_SOLANA_RPC_URL=http://127.0.0.1:8899(orhttp://localhost:8899— equivalent once forwarded)VITE_SOLANA_PROGRAM_ID, bridge/token addresses, etc. — must match what is deployed on the VPS (copy from the server’s deploy output /.env, not assumed placeholders).VITE_EVM_RPC_URL=http://127.0.0.1:8545(andVITE_EVM1_…/ second RPC if you use Anvil1 — align with8546forward).VITE_TERRA_LCD_URL/VITE_TERRA_RPC_URLif testing Terra —http://127.0.0.1:1317andhttp://127.0.0.1:26657when tunneled.Optional:
VITE_SOLANA_FAUCET_ADDRESS, mint envs — only if the faucet program is deployed and registered on that same cluster.Do not set frontend RPC URLs to
https://api.devnet.solana.comor public BSC RPCs if your goal is to hit the VPS localnet — that would test a different network than the operator/validator on the VPS.Rebuild or restart Vite after changing
VITE_*(npm run devpicks them at startup).4. CORS, rate limiting, and operator API
connect-srcand does not require exposing RPC on0.0.0.0publicly.RATE_LIMIT_PER_SECOND/RATE_LIMIT_BURST_SIZEon the operator) apply per client IP as seen by the operator. Traffic forwarded via SSH typically appears from 127.0.0.1 on the server side — normal for a single tester. This is unrelated to Solana/EVM JSON-RPC ports unless you explicitly point the frontend at the operator URL.127.0.0.1/localhost.5. If something still fails after tunnels + env
--: Confirm 8900 is forwarded and that nothing else is bound to 8900 on the laptop; check DevTools → Network / console for WebSocket errors tows://127.0.0.1:8900.VITE_SOLANA_RPC_URL.This should make laptop + SSH-only VPS QA behave like local frontend against remote validators without breaking security assumptions baked into the frontend.
QA server: DEX + bridge LocalTerra port conflict
On the shared QA host, cl8y-dex-terraclassic already binds LocalTerra on the default host ports (26657, 1317, 9090, 9091). Starting cl8y-bridge-monorepo
docker-composewith the same mappings fails with port already allocated.Mitigation: set alternate host ports for the bridge stack’s LocalTerra service via
docker-composeenv (e.g.E2E_TERRA_RPC_PORT,E2E_TERRA_LCD_PORT,E2E_TERRA_GRPC_PORT,E2E_TERRA_GRPC_WEB_PORTin a repo-root.env) so bridge and DEX can run side by side. Any bridge tooling, operator/canceler,make status, deploy scripts, and frontendVITE_TERRA_*/TERRA_*URLs must use the remapped host ports, not the defaults.Documentation: shared QA host tooling (branch
feat/solana-integration)This issue stays open as a running QA checklist; the following is reference only.
make start-qa/make stop-qamake start-qa(seescripts/qa/start-qa.sh): Before anything else, tears down an existing bridge stack (cancelerstop-all, operatorstop,docker compose down). Then brings up Docker (Anvil, LocalTerra, Solana, Postgres), runsmake operator-migrate,make deploy, writes.env.e2e.localandpackages/frontend/.env.localfrom.deploy/local.env, starts operator and canceler withQA_SHARED_HOST=1, verifies operator and canceler/health, and prints a copy-pastessh -N -L …line for the QA laptop (ports followscripts/qa/qa-host.env). Optional:QA_SSH_DEST=user@host make start-qato bake the SSH destination.make stop-qa: Stops canceler, operator, and runsdocker compose down.Shared host / DEX + bridge port separation
scripts/qa/qa-host.env: Default remapped LocalTerra host ports (26658, 1318, 9092, 9093) andOPERATOR_API_PORT=9094so Terra gRPC on 9092 does not collide with the operator API (default 9092 in code).scripts/qa/write-qa-env-e2e.sh: Merges deploy addresses with QA URLs for.env.e2e.local(bash) andpackages/frontend/.env.local(Vite).scripts/deploy-terra-local.shandsetup-bridge.shhonorTERRA_RPC_URL/TERRA_LCD_URLso deploys target the bridge LocalTerra on remapped ports, not the DEX stack on 26657/1317.scripts/operator-ctl.sh: WhenQA_SHARED_HOST=1, sourcesqa-host.envafter.envso URLs and operator port win.Docs
scripts/qa/README.md: Port conflictcat >> .envsnippet, SSH /QA_SSH_DEST, and workflow notes.Laptop QA (unchanged)
Browser + Vite still run on the laptop; SSH local forwards are required to reach 127.0.0.1 services on the QA server.
make start-qaprints the exactsshcommand at the end.Commit:
c2402fdonfeat/solana-integration.@brouie After
make start-qaon the QA server, do manual frontend QA on your laptop in this order:SSH port forwards — Run the
ssh -4 -N ...block printed at the end ofmake start-qa(keep that terminal open). Use127.0.0.1on both sides.Copy
.deploy/local.env— From the QA host into your repo clone (use the exactscpline from the script output):scp …:.deploy/local.env .deploy/local.envGenerate
packages/frontend/.env.local—./scripts/qa/write-frontend-env-local.sh(Restart Vite if it was already running so new
VITE_*load.)Install deps and run Vite —
cd packages/frontend && npm ci && npm run devOpen the URL Vite prints (e.g.
http://localhost:3000).WalletConnect: add
VITE_WC_PROJECT_IDtopackages/frontend/.env.local(get a project id from https://cloud.walletconnect.com) if you use WalletConnect; MetaMask / other injected wallets work without it.More detail:
scripts/qa/README.md→ section On your laptop.E2E testing with make start-qa (2026-03-27, v0.1.183 /
4c02b63):Setup:
Verified:
Bugs found:
Remaining:
mentioned in issue #81
FIRST FULL E2E TRANSFER COMPLETE: LocalTerra -> Anvil, 298.50 KDEC. All 4 steps passed — deposit, submit hash (auto-submit to EVM), operator approval, tokens delivered. TransferStatusPage shows 4/4 DONE correctly. Destination TX confirmed (0x96ec07...).
EVM->Terra direction (Anvil->LocalTerra) blocked by Keplr 'Failed to fetch balance' on LocalTerra — Keplr can't verify wallet balance on localnet chain config. Not a bridge code bug, QA environment issue. Will investigate Keplr chain config.
Anvil1 direction untestable due to #85 (Anvil1 0/7 registration).
Solana direction untestable due to #84 (wSOL mint missing).
Second E2E direction confirmed: Anvil->LocalTerra 99.50 TKNA, withdraw_submit succeeded on Terra (txHash D668A506). Auto-withdraw retry bug makes UI show FAILED but the on-chain submission worked — tracked in #87. Both EVM<->Terra directions now verified working at the contract/operator level.
@brouie Please prioritize sol<>anvil/anvil1 and sol<>localterra paths.
mentioned in issue #92
closing -- Solana->Anvil E2E verified via Backpack. Terra->Anvil, Terra->Anvil1, Anvil->Anvil1 all complete. Remaining paths (Anvil->Terra blocked by #89, Terra->Solana by #94) consolidated into new combined Solana Integration QA issue.
mentioned in issue #96