Skip to content

feat: mayachain zcash support#11299

Merged
kaladinlight merged 32 commits intodevelopfrom
mayachain-zcash
Jan 13, 2026
Merged

feat: mayachain zcash support#11299
kaladinlight merged 32 commits intodevelopfrom
mayachain-zcash

Conversation

@kaladinlight
Copy link
Contributor

@kaladinlight kaladinlight commented Dec 5, 2025

Description

Support for zcash on mayachain

Issue (if applicable)

N/A

Risk

High Risk PRs Require 2 approvals

Low

What protocols, transaction types, wallets or contract interactions might be affected by this PR?

Testing

  • Ensure trading from zcash -> asset and asset -> zcash works on mayachain

Engineering

☝️

Operations

  • 🏁 My feature is behind a flag and doesn't require operations testing (yet)

☝️

Screenshots (if applicable)

image image image image

Summary by CodeRabbit

  • New Features

    • Added support for Zcash (ZEC) asset mapping so ZEC assets and pools are recognized.
  • Improvements

    • Swapper-aware inbound address selection and trading-status checks across Thorchain-related flows.
    • Zcash (ZIP-317) transaction sizing and fee model improved for more accurate fees, extra-output handling, and better send-max behavior.

✏️ Tip: You can customize this high-level summary in your review settings.

@kaladinlight kaladinlight requested a review from a team as a code owner December 5, 2025 16:44
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 5, 2025

📝 Walkthrough

Walkthrough

Adds swapper-specific inbound-address and trading-status handling by introducing a SwapperName parameter across selectors and callers (passed as SwapperName.Thorchain at call sites); also adds ZEC chain mapping in the asset map utility and refactors Zcash ZIP-0317 fee calculation to use total input/output sizes.

Changes

Cohort / File(s) Summary
Selectors — signatures & logic
src/react-queries/selectors/index.ts
selectInboundAddressData(inboundAddresses, assetId, swapperName) and selectIsTradingActive(..., swapperName) added; derives pool id based on swapperName (Thorchain vs Mayachain), implements swapper-specific halt checks, throws on invalid swapper.
Callers — hooks & UI using inbound-address selection
src/lib/utils/thorchain/hooks/useSendThorTx.tsx, src/pages/Lending/Pool/components/Repay/RepayConfirm.tsx, src/pages/Lending/Pool/components/Repay/RepayInput.tsx, src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx, src/pages/ThorChainLP/queries/hooks/usePools.ts, src/react-queries/hooks/useIsTradingActive.ts, src/state/apis/swapper/helpers/swapperApiHelpers.ts
Updated call sites to pass swapperName (commonly SwapperName.Thorchain) into selectInboundAddressData / selectIsTradingActive; added SwapperName imports where needed.
Asset mapping utility (ZEC)
scripts/generateTradableAssetMap/utils.ts
Adds ZEC: imports zecChainId, adds Chain.ZEC enum value and maps [Chain.ZEC]: zecChainId in chainToChainId.
UTXO fee / coinselect (Zcash)
packages/chain-adapters/src/utxo/utxoSelect/index.ts
ZIP-0317 fee calc changed to use total input/output sizes; new Zcash size constants and opReturn sizing integrated; calculateZip317Fee signature updated and coin selection updated to use total-size-based fees.
Manifest / deps
package.json
Dependency surface updated indirectly due to added SwapperName imports (reflected in manifest).

Sequence Diagram(s)

sequenceDiagram
  participant UI as UI / Hook (RepayInput, usePools, etc.)
  participant Selector as selectInboundAddressData / selectIsTradingActive
  participant InboundAPI as Thornode inboundAddresses response
  participant Mimir as mimir flags

  UI->>InboundAPI: fetch inboundAddresses
  UI->>Selector: selectInboundAddressData(inboundAddresses, assetId, SwapperName.Thorchain)
  Selector->>Selector: derive assetPoolId via swapper-specific mapping
  Selector->>InboundAPI: lookup inbound entry by assetPoolId
  Selector-->>UI: inboundAddressResponse (includes halted)
  UI->>Selector: selectIsTradingActive(assetId, mimir, inboundAddressResponse, SwapperName.Thorchain)
  Selector->>Mimir: read HALT flags
  Selector-->>UI: tradingActive boolean
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • gomesalexandre
  • NeOMakinG

Poem

🐇 I hopped through code with whiskered cheer,
I passed a SwapperName and ZEC drew near,
Thorchain routes inbound with a nimble skip,
Zcash fees sized up for a trusty trip,
Commits and carrots — a small rabbit cheer 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: mayachain zcash support' accurately reflects the main objective of adding Zcash support to MayaChain, which is evident from file changes across multiple components enabling MayaChain-specific logic alongside Thorchain support.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mayachain-zcash

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • ZIP-317: Entity not found: Issue - Could not find referenced Issue.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Base automatically changed from zcash-support to develop December 5, 2025 17:07
@kaladinlight kaladinlight marked this pull request as draft December 5, 2025 17:23
@kaladinlight
Copy link
Contributor Author

Zebra has a bug surrounding op_return data outputs being flagged as invalid preventing us from broadcasting successfully: ZcashFoundation/zebra#10143. Checking if we have another upstream node version (non zebra), or we can potentially proxy to another public node in the meantime.

@kaladinlight kaladinlight linked an issue Dec 5, 2025 that may be closed by this pull request
@kaladinlight kaladinlight marked this pull request as ready for review January 12, 2026 19:14
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/chain-adapters/src/utxo/utxoSelect/index.ts (1)

138-160: Handle zero-value remainder outputs consistently with sendMax approach.

The greedy coin selection path (lines 147–156) can create a { value: 0 } change output when remainder === 0, but the sendMax path prevents this with an early return check (if (remainder <= 0)). This inconsistency should be resolved.

When remainder === 0, the output { value: 0 } will not be identified as a change output at line 82 (because the check requires o.value to be truthy), and will remain in the final outputs array after the script filter at line 93. For consistency and correctness, add a check after line 148 to return early if remainder is zero or negative, matching the sendMax pattern.

🤖 Fix all issues with AI agents
In @packages/chain-adapters/src/utxo/utxoSelect/index.ts:
- Around line 113-115: The opReturn output size computation uses
extraOutput[0].script.length which measures string characters, risking
undercount for multi-byte UTF-8 data; update the calculation in the
opReturnOutputSize logic (referencing opReturnOutputSize, extraOutput and
TX_OUTPUT_BASE) to compute bytes instead of characters—either call
Buffer.byteLength(extraOutput[0].script, 'utf-8') or, better, keep the OP_RETURN
script as a Buffer and use its .length to get the true byte size before adding
TX_OUTPUT_BASE so fee estimates are correct.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 461f60b and 9239cb2.

📒 Files selected for processing (1)
  • packages/chain-adapters/src/utxo/utxoSelect/index.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Never assume a library is available - always check imports/package.json first
Prefer composition over inheritance
Write self-documenting code with clear variable and function names
Keep functions small and focused on a single responsibility
Avoid deep nesting - use early returns instead
Prefer procedural and easy to understand code
Never expose, log, or commit secrets, API keys, or credentials
Validate all inputs, especially user inputs
Handle errors gracefully with meaningful messages
Don't silently catch and ignore exceptions
Log errors appropriately for debugging
Provide fallback behavior when possible
Use appropriate data structures for the task
Never add code comments unless explicitly requested
When modifying code, do not add comments that reference previous implementations or explain what changed. Comments should only describe the current logic and functionality.
Use meaningful names for branches, variables, and functions
Always run yarn lint --fix and yarn type-check after making changes
Avoid let variable assignments - prefer const with inline IIFE switch statements or extract to functions for conditional logic

Files:

  • packages/chain-adapters/src/utxo/utxoSelect/index.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Avoid useEffect where practical - use it only when necessary and following best practices
Avoid 'any' types - use specific type annotations instead
For default values with user overrides, use computed values (useMemo) instead of useEffect - pattern: userSelected ?? smartDefault ?? fallback
When function parameters are unused due to interface requirements, refactor the interface or implementation to remove them rather than prefixing with underscore
Sanitize data before displaying to prevent XSS
Memoize aggressively - wrap component variables in useMemo and callbacks in useCallback where possible
For static JSX icon elements (e.g., <TbCopy />) that don't depend on state/props, define them as constants outside the component to avoid re-renders instead of using useMemo
Account for light/dark mode using useColorModeValue hook
Account for responsive mobile designs in all UI components
When applying styles, use the existing standards and conventions of the codebase
Use Chakra UI components and conventions
All copy/text must use translation keys - never hardcode strings
Use the translation hook: useTranslate() from react-polyglot
Use useFeatureFlag('FlagName') hook to access feature flag values in components
Prefer type over interface for type definitions
Use strict typing - avoid any
Use Nominal types for domain identifiers (e.g., WalletId, AccountId)
Import types from @shapeshiftoss/caip for chain/account/asset IDs
Use useAppSelector for Redux state
Use useAppDispatch for Redux actions
Memoize expensive computations with useMemo
Memoize callbacks with useCallback

**/*.{ts,tsx}: Use Result<T, E> pattern for error handling in swappers and APIs; ALWAYS use Ok() and Err() from @sniptt/monads; AVOID throwing within swapper API implementations
ALWAYS use custom error classes from @shapeshiftoss/errors with meaningful error codes for internationalization and relevant details in error objects
ALWAYS wrap async op...

Files:

  • packages/chain-adapters/src/utxo/utxoSelect/index.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/naming-conventions.mdc)

**/*.{js,jsx,ts,tsx}: Use camelCase for variables, functions, and methods with descriptive names that explain the purpose
Use verb prefixes for functions that perform actions (e.g., fetch, validate, execute, update, calculate)
Use UPPER_SNAKE_CASE for constants and configuration values with descriptive names
Use handle prefix for event handlers with descriptive names in camelCase
Use descriptive boolean variable names with is, has, can, should prefixes
Use named exports for components, functions, and utilities instead of default exports
Use descriptive import names and avoid renaming imports unless necessary
Avoid non-descriptive variable names like data, item, obj, and single-letter variable names except in loops
Avoid abbreviations in names unless they are widely understood
Avoid generic function names like fn, func, or callback

Files:

  • packages/chain-adapters/src/utxo/utxoSelect/index.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11170
File: patches/@shapeshiftoss+bitcoinjs-lib+7.0.0-shapeshift.0.patch:9-19
Timestamp: 2025-11-25T21:43:10.838Z
Learning: In shapeshift/web, gomesalexandre will not expand PR scope to fix latent bugs in unused API surface (like bitcoinjs-lib patch validation methods) when comprehensive testing proves the actual used code paths work correctly, preferring to avoid costly hdwallet/web verdaccio publish cycles and full regression testing for conceptual issues with zero runtime impact.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10171
File: src/components/MultiHopTrade/components/TradeConfirm/components/ExpandedStepperSteps.tsx:458-458
Timestamp: 2025-08-04T15:36:25.122Z
Learning: In swap transaction handling, buy transaction hashes should always use the swapper's explorer (stepSource) because they are known by the swapper immediately upon swap execution. The conditional logic for using default explorers applies primarily to sell transactions which need to be detected/indexed by external systems like Thorchain or ViewBlock.
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/src/swappers/*/*.ts : Implement filterBuyAssetsBySellAssetId method to filter assets by supported chain IDs in the buy property
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/src/swappers/*/*.ts : Implement filterAssetIdsBySellable method to filter assets by supported chain IDs in the sell property
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/src/constants.ts : Register new swappers in packages/swapper/src/constants.ts with an entry in the swappers registry mapping SwapperName enum to swapper implementation
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/**/*.ts : Use TypeScript with explicit types (e.g., SupportedChainIds) for all code in the Swapper system
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11016
File: packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts:25-38
Timestamp: 2025-11-12T13:01:06.086Z
Learning: In the swapper architecture (packages/swapper), input validation for sell amounts (e.g., checking sellAmount > 0) is handled by the application layer before reaching individual swapper implementations. Swapper methods like getTradeRate and getTradeQuote can assume inputs have already been validated upstream, so defensive guards for basic input validation (amount > 0, valid addresses, etc.) are unnecessary at the swapper layer.
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-11-24T21:20:17.804Z
Learning: Applies to **/swapper{s,}/**/*.{ts,tsx} : ALWAYS use `makeSwapErrorRight` for swapper errors with `TradeQuoteError` enum for error codes and provide detailed error information
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/src/swappers/*/endpoints.ts : Reuse checkEvmSwapStatus utility for checking EVM swap status instead of implementing custom status checks
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11281
File: packages/swapper/src/swappers/PortalsSwapper/utils/fetchSquidStatus.ts:98-106
Timestamp: 2025-12-04T11:05:01.146Z
Learning: In packages/swapper/src/swappers/PortalsSwapper/utils/fetchSquidStatus.ts, getSquidTrackingLink should return blockchain explorer links (using Asset.explorerTxLink) rather than API endpoints. For non-GMP Squid swaps: return source chain explorer link with sourceTxHash when pending/failed, and destination chain explorer link with destinationTxHash when confirmed.
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/src/swappers/*/utils/constants.ts : Define supported chain IDs for each swapper in utils/constants.ts with both 'sell' and 'buy' properties following the pattern: SupportedChainIds type
🔇 Additional comments (3)
packages/chain-adapters/src/utxo/utxoSelect/index.ts (3)

9-11: LGTM on Zcash constants.

These values align with standard P2PKH transaction sizes for Zcash (150 bytes for inputs, 34 bytes for outputs, 9 bytes for output base overhead).


117-131: LGTM on sendMax path.

The implementation correctly consumes all available UTXOs, calculates the fee based on total input/output sizes, and handles insufficient funds with an early return.


96-102: ZIP-0317 fee calculation is correctly implemented.

The formula accurately implements the transparent input/output contribution defined by ZIP-0317: fee = 5000 × max(2, max(⌈txInSize/150⌉, ⌈txOutSize/34⌉)). All constants match the specification exactly (marginal fee, grace actions, and standard sizes).

Note: This function calculates the transparent contribution component of ZIP-0317 fees. For transactions with Sapling, Orchard, or other protocol features, additional contributions would need to be summed separately.

@kaladinlight kaladinlight merged commit 04681c1 into develop Jan 13, 2026
4 checks passed
@kaladinlight kaladinlight deleted the mayachain-zcash branch January 13, 2026 17:37
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.

Zcash on Mayachain

2 participants