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

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.

@abdolian

Copy link
Copy Markdown
Collaborator

I reviewed your #23 merge request. It works, but it’s not efficient.

Loading ergo-lib-wasm-browser on the client adds unnecessary overhead. We prefer handling this in the API and returning a simple validation result to the browser.

We’re planning to implement this on the API side, so we can continue this merge after that change.

@odiseusme

Copy link
Copy Markdown
Author

I’m happy to take the API-side implementation on as part of this PR if that’s useful — a validation endpoint returning a simple per-chain result, with the form wired to call it instead of running WASM in the browser. Or if you’d rather build the primitive internally, I’ll wait and adapt the client once it lands. Whichever fits your roadmap — just let me know.

@abdolian

abdolian commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

We will implement the API first, and then you can continue.

@odiseusme

Copy link
Copy Markdown
Author

Sounds good — I'll wait for the API-side validation to land, then refactor this PR to drop the client-side WASM and call the endpoint instead. Ping me here (or link the endpoint) once it's ready and I'll pick it back up.

@abdolian

Copy link
Copy Markdown
Collaborator

The API is already implemented here, so you can continue with this merge request.

Please use the following API to validate Ergo addresses:

/address/validate/:address

  1. Update your branch with the latest dev branch.
  2. Keep your changes minimal and focused.
  3. Commit all changes in one clean, meaningful commit.

@odiseusme

@odiseusme
odiseusme force-pushed the fix/issue-13-validate-withdrawal-address branch from 6563c2e to e73712e Compare September 13, 2026 14:02
@vercel

vercel Bot commented Sep 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
ui-guard Skipped Skipped Sep 13, 2026 2:02pm UTC

Request Review

@vercel
vercel Bot temporarily deployed to Preview – ui-guard September 13, 2026 14:02 Inactive
@odiseusme

Copy link
Copy Markdown
Author

Thanks @abdolian — rebased onto latest dev and rewritten to use the API. The client-side WASM approach is gone entirely; the branch now carries a single commit with an 8-line change to apps/watcher/src/app/actions/@form/withdraw/page.tsx.

The address field's validate rule now calls /address/validate/:address via the existing fetcher (already imported for the assets call), treating a non-200 response as an invalid address. The input is URL-encoded before being interpolated into the path.

No new files, no new dependencies. npm run build passes for the watcher app, and I verified the endpoint's behaviour against a running watcher — valid addresses return {"valid":true}, malformed base58 and bad checksums return 500 with a message, which the rule handles.

Ready for review.

@abdolian

Copy link
Copy Markdown
Collaborator

This pull request can be merged
@zargarzadehm

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

3 participants