Skip to content

Add transparent refund address for shielded Zcash Maya swaps - #459

Open
j0ntz wants to merge 2 commits into
masterfrom
jon/zec-shielded-refund-address
Open

Add transparent refund address for shielded Zcash Maya swaps#459
j0ntz wants to merge 2 commits into
masterfrom
jon/zec-shielded-refund-address

Conversation

@j0ntz

@j0ntz j0ntz commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

CHANGELOG

Does this branch warrant an entry to the CHANGELOG?

  • Yes
  • No

Dependencies

none

Description

Asana: https://app.asana.com/0/1215088146871429/1214541361005860

Problem. When Edge sends a shielded-Zcash swap to Maya, the swap memo carries no refund address. Maya cannot refund a shielded source and rejects the refund:

can't refund ZEC from shielded source without a refund address
fail to refund for halted trading

For every chain except Zcash, Maya defaults the refund to the sending address, which is correct. A shielded ZEC source has no transparent sending address to refund to, so the integrator must supply a transparent (t-address) refund address in the swap memo.

Fix. In the shared Thorchain/Maya common code, when the source wallet is Zcash, fetch the wallet's transparent address (getAddress(fromWallet, 'transparentAddress'), the same helper already used for the ZEC receive side) and append it to the swap memo's destination field as DESTADDR/REFUNDADDR per the Maya memo spec, via the new documented helper appendMayaRefundAddress (which replaces the destination address in the memo with DESTADDR/REFUNDADDR). Since this is the Zcash-only path, the code throws SwapCurrencyError if the transparent refund address is missing.

The refund address is deliberately NOT passed to the quote/swap endpoint. Given a refund_address, Maya builds that same DESTADDR/REFUNDADDR memo and then rejects the quote because the result overflows the source chain's memo limit (e.g. ZEC to DASH is 86/80). The shielded ZEC send instead carries the memo in the encrypted note (512 bytes), which is not bound by the 80-char transparent-memo limit that the quote endpoint pre-validates against, so the refund is injected client-side after the quote is fetched without it. Non-Zcash sources are untouched and keep defaulting to the sending address (their quote requests and memos are unchanged).

The change lives entirely in the dependency; no gui-side wiring is required.

Verification.

  • tsc --noEmit, eslint, and the mocha suite all pass (via verify-repo.sh, which also runs the webpack build).
  • New unit tests in test/thorchain.test.ts pin appendMayaRefundAddress's output to the exact memo shape (=:d:DEST/REFUND:0/1/1:ej:75) and cover the destination-not-present edge case.
  • Live Maya node (mayanode.mayachain.info) confirms why the endpoint cannot build the memo: BTC to ETH with refund_address returns generated memo too long for source chain: ...(96/80); the same request without it returns a valid 53-char memo.
  • In-app ZEC to asset swap-to-success was driven to the success scene in the prior run (with the byte-identical memo). It could not be re-driven this pass: Maya ZEC trading is halted again (HALTZECTRADING=1, trading is halted, can't process swap) at the protocol level, and a swap during the halt fails at the quote before the refund injection runs, so it would not exercise this code anyway. Re-run the in-app smoke once Maya resumes ZEC trading.

Note

Medium Risk
Changes Maya Zcash swap memo construction and refund routing for a subset of swaps; wrong address formatting could misroute refunds, but scope is limited to ZEC source via the existing ZIP-321 path.

Overview
Shielded Zcash → Maya swaps now embed a transparent (t-address) refund in the swap memo as DESTADDR/REFUNDADDR, so Maya can refund when trading is halted or the swap fails—shielded sources cannot default to the sender like other chains.

Quotes still call quote/swap without refund_address, because Maya would build the same long memo and reject quotes that exceed the 80-character transparent memo limit; the shielded ZIP-321 path carries the memo in the encrypted note (512 bytes), so appendMayaRefundAddress patches the memo after quoting. Missing transparent refund address fails the swap with SwapCurrencyError.

Unit tests lock the memo shape; CHANGELOG notes the Maya behavior.

Reviewed by Cursor Bugbot for commit 80f0430. Bugbot is set up for automated code reviews on this repo. Configure here.

@j0ntz
j0ntz force-pushed the jon/zec-shielded-refund-address branch 2 times, most recently from d550dc3 to 67bbce0 Compare June 16, 2026 01:08

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 67bbce0. Configure here.

Comment thread src/swap/defi/thorchain/thorchainCommon.ts Outdated
@j0ntz
j0ntz force-pushed the jon/zec-shielded-refund-address branch from 67bbce0 to dfd5a7a Compare June 16, 2026 01:17
@j0ntz

j0ntz commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

📸 Test evidence (in-app, after fix)

agent proof 1214541361005860 04 zec dash fixed order

agent proof 1214541361005860 04 zec dash fixed order

agent proof 1214541361005860 05 zec dash swap success

agent proof 1214541361005860 05 zec dash swap success

agent proof 1214541361005860 06 btc eth unaffected order

agent proof 1214541361005860 06 btc eth unaffected order

Captured by the agent's in-app test run (build-and-test).

Comment thread src/swap/defi/thorchain/thorchainCommon.ts Outdated
@j0ntz
j0ntz force-pushed the jon/zec-shielded-refund-address branch from dfd5a7a to 4a473d9 Compare July 28, 2026 22:27

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Automated security triage completed on the current PR head. One net-new finding met this workflow's reporting threshold after deduplication and false-positive filtering.

Open in Web View Automation 

Sent by Cursor Security Agent: Security Reviewer

Comment thread src/swap/defi/thorchain/thorchainCommon.ts Outdated
@j0ntz
j0ntz force-pushed the jon/zec-shielded-refund-address branch from 4a473d9 to b55835f Compare July 28, 2026 22:39
Comment thread src/swap/defi/thorchain/thorchainCommon.ts Outdated
Maya cannot refund a shielded Zcash source and rejects the refund with
"can't refund ZEC from shielded source without a refund address". Add the
wallet's transparent (t-address) refund address to the Maya swap memo as
DESTADDR/REFUNDADDR so Maya can process refunds.

The refund is injected into the memo client-side rather than passed to the
quote endpoint. Appending it to the quote request overflows Zcash's 80-char
transparent-memo limit and the quote endpoint rejects the swap. The ZEC swap
carries its memo in the shielded note, which is not bound by that limit, so
the refund is added after the quote is fetched. Non-Zcash sources are
unchanged and continue to default to the sending address.
@j0ntz
j0ntz force-pushed the jon/zec-shielded-refund-address branch from b55835f to 73c3394 Compare July 29, 2026 23:08
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.

2 participants