Skip to content

fix: validate withdrawal address in watcher (#13)#23

Open
odiseusme wants to merge 1 commit into
rosen-bridge:devfrom
odiseusme:fix/issue-13-validate-withdrawal-address
Open

fix: validate withdrawal address in watcher (#13)#23
odiseusme wants to merge 1 commit into
rosen-bridge:devfrom
odiseusme:fix/issue-13-validate-withdrawal-address

Conversation

@odiseusme

Copy link
Copy Markdown

Fixes #13.

Changes

  • Adds ergo-lib-wasm-browser (^0.24.1) to apps/watcher dependencies
  • Adds webpack/WASM configuration to apps/watcher/next.config.js (mirrors the experiments block from apps/rosen/next.config.js, plus output.webassemblyModuleFilename needed for output: 'export')
  • Adds apps/watcher/src/utils/validateErgoAddress.ts — a browser-side Ergo address validator that lazy-loads the WASM module on first use
  • Refactors the address field in apps/watcher/src/app/actions/@form/withdraw/page.tsx from register('address', { required }) to useController with an async validate rule, mirroring the pattern in apps/rosen/src/hooks/useBridgeForm.ts

Validation behavior

The validator uses Address.from_base58() from ergo-lib-wasm-browser, which accepts both mainnet and testnet Ergo addresses. The issue specifies "an Ergo address" (not "a mainnet Ergo address"), and a Watcher operator may be running a testnet deployment — restricting to mainnet would break testnet operators.

Error messages mirror the Rosen app's useBridgeForm exactly:

  • Empty input: "Address cannot be empty" (intentional change from the previous "Address is required" to match Rosen)
  • Invalid address: "Invalid Address"
  • Unexpected error during validation: "Something went wrong! please try again"

Verification

  • npm run build for apps/watcher succeeds; the .wasm chunk is emitted to out/_next/static/wasm/
  • The WASM file is served with Content-Type: application/wasm and HTTP 200 from a static-server smoke test
  • No new TypeScript errors introduced (verified by comparing npm run type-check output against the pre-PR baseline)

Notes for reviewers

@vercel

vercel Bot commented May 7, 2026

Copy link
Copy Markdown

@odiseusme is attempting to deploy a commit to the rosen-bridge Team on Vercel.

A member of the Team first needs to authorize it.

@odiseusme

Copy link
Copy Markdown
Author

Verification of acceptance conditions (done locally via source inspection):

  1. Error display: Uses react-hook-form's formState.errors.address.message rendered through the shared TextField's helperText prop (same @rosen-bridge/ui-kit component as Rosen). Visual parity follows from the shared component.

  2. Validation logic: Equivalent to Rosen's by construction. Rosen's chain runs server-side: useBridgeForm → Server Action → @rosen-network/base.validateAddress@rosen-bridge/address-codec → for ERGO_CHAIN: ergoLib.Address.from_base58(address). Our PR runs Address.from_base58(address) directly in the browser via ergo-lib-wasm-browser. Same Rust source, same accept/reject behavior. The Watcher's output: 'export' precludes Server Actions, which is why we go direct-to-WASM.

  3. react-hook-form API: useController with async validate rule, mirroring apps/rosen/src/hooks/useBridgeForm.ts. Empty check ("Address cannot be empty"), validation call, fallback ("Invalid Address"), catch-all ("Something went wrong! please try again") — all identical strings to Rosen's flow.

One small UX delta: we trim whitespace on the input's onBlur before validation. Rosen's ErgoNetwork.toSafeAddress is a no-op pass-through (return address), so where Rosen would reject " 9fuoH... ", our form accepts it. We've kept this small UX improvement intentionally — happy to discuss if there's a reason to revert.

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.

Validate withdrawal address in Watcher

1 participant