bug(operator): MegaETH/LCD rate-limit gaps stall getDeposit and Terra writer approval #164
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#164
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?
Reporter observed a stuck bridge transfer for xchain hash
0xd2350e21e090a91260457cfd6e697a5acfde2b2d1d32d958a8d3f9ba323f1951. Likely cause: LCD/RPC throttling while verifying source deposits and polling Terra withdrawals, especially under MegaETH public RPC quality pressure. On-chain withdraw rate limits must stay.Formatted engineering report (current codebase, constraints, direction, acceptance, and test plans) is in the comment below.
Summary
A reporter observed a stuck bridge transfer for xchain hash
0xd2350e21e090a91260457cfd6e697a5acfde2b2d1d32d958a8d3f9ba323f1951(valid V2 32-byte id; Terra encoding0jUOIeCQqRJgRXz9bml6Ws/eKy0dMtlYqNP5ujI/GVE=). Operator triage points at LCD/RPC throttling while verifying source deposits and polling Terra withdrawals, especially on MegaETH, whose public RPC quality is known-poor.This is a client/operator resilience gap, not a request to weaken on-chain withdraw rate limits. EVM
eth_getLogsalready has method-level fallback and retry classification for HTTP 429. SourcegetDepositverification and the Terra writer poll path do not: they use a single RPC/LCD URL, and Terra writer does not apply the EVM negative-verify backoff. FrontendLCD_CONFIGthrottle knobs exist but are unused, while Transfer Status polls every chain in parallel.Treat the reported hash as a diagnostic example (confirm its current stage if still pending). The implementation is the systemic rate-limit-aware fallback/backoff for source verification and Terra LCD polling.
Current codebase
Transfer and approval flow
xchain_hash_id.WithdrawSubmiton dest; pending withdraw uses the same hash.getPendingWithdrawHashes+ events; Terra: LCDactive_withdrawals/ legacypending_withdrawals).getDeposit/ Terra deposit query / Solana PDA). Fail closed: never approve without a verified deposit.WithdrawApprove; after the cancel window, execute (unlock/mint).POLLING_INTERVAL(default 10s).Two different “rate limits” must not be conflated:
RATE_LIMITS, EVMTokenRateLimit, SolanaWithdrawRateLimit. These must stay.What is already resilient
eth_getLogs: method-level URL fallback + chain-id confirm (rpc_fallback.rs, INV-OP-W1–W3 / issue #138).multichain_rs::is_retryable_evm_rpc_error_message).NegativeVerifySchedule(INV-OP-W4).Gaps that match this stuck-transfer class
source_chain_endpointsstores one RPC URL per chain (writers/mod.rs). Comma-separatedEVM_RPC_URL/EVM_CHAIN_N_RPC_URLfallbacks are not used forgetDeposit.verify_evm_deposit_on_chaininwriters/evm.rsandwriters/terra.rscallsgetDepositon that single URL.TerraWriter::poll_and_approveuses a singleTERRA_LCD_URL. On LCD failure it logs and skips the cycle (Ok); there is no LCD URL fallback and noNegativeVerifySchedule.fetchLcd/queryContracttry sequential URL fallbacks but ignoreLCD_CONFIG.minRequestIntervalandendpointCooldown. Transfer Status (useMultiChainLookup) fans out parallel EVM + Terra + Solana queries every 10s.no_evm_deposit/evm_errors, EVM negative-retry suppression, or Transfer Status stalling after cancel-window expiry.Why a new implementation is needed
MegaETH public RPC is intentionally treated as poor-quality. Client-side throttling and failover are required, not optional debt. Today a 429 or flaky
getDepositon the primary MegaETH URL can leave a real deposit unverified every Terra poll cycle, so destWithdrawSubmitsits unapproved and the transfer looks stuck.Changing only the frontend poll interval cannot fix operator source verification. Relaxing on-chain withdraw caps would increase drain on key compromise and does not address HTTP 429. The missing work is to reuse the existing EVM log-fallback and negative-retry designs for
getDepositand Terra LCD list/verify polls, and to actually apply the frontend LCD throttle constants.Constraints and guardrails
TokenRateLimit; Solana INV-W4). Fix UX/ops if a transfer is delayed by those caps (INV-UX2).Relevant files
getDepositpackages/operator/src/writers/terra.rs,terra_list.rspackages/operator/src/writers/evm.rs,negative_retry.rs,poll_cursor.rs,retry.rspackages/operator/src/writers/mod.rspackages/operator/src/poll_config.rspackages/operator/src/rpc_fallback.rspackages/operator/src/watchers/terra.rspackages/operator/src/config.rspackages/multichain-rs/src/evm/rpc_fallback.rspackages/frontend/src/services/lcdClient.ts,src/utils/constants.tspackages/frontend/src/hooks/useMultiChainLookup.ts,src/pages/TransferStatusPage.tsxpackages/frontend/src/services/terraBridgeQueries.ts,hashMonitor.ts,hashVerification.tspackages/frontend/src/utils/bridgeChains.ts,src/lib/megaethMainnet.tsdocs/OPERATOR_WRITER_INVARIANTS.md,docs/FRONTEND_BRIDGE_INVARIANTS.md,docs/deployment-megaeth.mdRecommended direction
getDeposit(and othereth_callverifies) using the full comma-separated URL lists from config, not primary-onlysource_chain_endpoints. Confirm chain id on each fallback (INV-OP-W3).NegativeVerifySchedule(or a shared cycle verify budget) toTerraWriterso MegaETH/getDepositfailures do not re-hit every unapproved row every poll interval.LCD_CONFIG.minRequestInterval/endpointCooldown; avoid parallel multi-chain blasts on Transfer Status when a lookup is already in flight.rpc_throttledvsno_depositvslcd_failurein logs/metrics (no secrets, no user ids). Surface “source RPC throttled — retrying” in Transfer Status rather than an indefinite unknown stall.Acceptance criteria
getDeposit/ source verify uses the same fallback URL list aseth_getLogsand confirms chain id on each URL.minRequestInterval/endpointCooldown; Transfer Status does not amplify 429s via unbounded parallel polls.xchain_hash_id(Transfer Status + operator log grep) without requiring a new public hash-oracle API.Test plan: all paths
getDepositsucceeds on primary RPC, approve + execute.getDepositfails on URL[0] with 429; URL[1] returns the deposit; approve proceeds; chain-id mismatch on a fallback is rejected.getDeposit; never approve.LCD_CONFIGknobs are actually enforced (unit + integration).Test plan: attack, hack, and abuse vectors
WithdrawSubmitwith random hashes/pendingVerification criteria
getDepositfallback order, 429 classification, chain-id confirm, and TerraNegativeVerifySchedule(or equivalent) bounds.fetchLcdhonorsminRequestInterval/endpointCooldownand Transfer Status does not issue overlapping multi-chain lookups.getDepositsuccess without raising on-chain caps.OPERATOR_WRITER_INVARIANTS.md, MegaETH deployment notes) mention source-verify fallback and Terra writer backoff.Check bridge monorepo, lcd call, likely its rate limiting (which we need due toto bug(operator): MegaETH/LCD rate-limit gaps stall getDeposit and Terra writer approval