Maya Protocol (MAYAChain) — execution dossier
Status in this phase: price discovery only (executability: quote_only, atomic: false). Adapter:
packages/swap/src/providers/maya.ts (configuration) on the engine of thorchain.ts. MAYAChain is a fork of THORChain:
same quote endpoint shape, same 1e8 fixed point, same memo grammar, same vault model. Read thorchain.md first; this
file states what was verified for Maya on 2026-11-10 (2026-11-11 UTC), MAYANode 1.135.4, and what differs.
1. Sources
Endpoints: the docs list https://mayanode.mayachain.info/mayachain (pinned by the adapter), Midgard
https://midgard.mayachain.info/v2, Tendermint https://tendermint.mayachain.info. A second, independently hosted MAYANode
answers at https://api-maya.liquify.com/mayachain (same version, same routers; not in the docs). No key. No published rate
limit, only "Careful querying this too much - you could overload the public nodes". No terms-of-use page found in the docs.
Measured: 150–620 ms per quote, no failure in about 60 calls.
2. What is served
Chain → wallet network: BTC bitcoin, ETH ethereum, ARB arbitrum. (Maya's other chains — DASH, ZEC, ADA, THOR
(RUNE), MAYA (CACAO) — have no wallet network. Mimir still carries keys for chains it does not run pools for.)
GET /mayachain/pools: 25 pools, 18 Available. In the wallet registry by chain + contract: BTC, ETH, Arbitrum ETH,
Ethereum USDC and USDT, Arbitrum USDC (6 assets). ARB.USDT and ARB.WBTC are Available but not in the registry;
ETH.PEPE, ARB.ARB, ARB.DAI are Staged (refused: pool(ETH.PEPE-…) is not available).
No DOGE, LTC, BCH, SOL, XRP, TRX, ATOM: for those pairs the adapter says "unsupported" without any network call.
Halts: GET /mayachain/inbound_addresses has halted per chain only (no trading-pause flags). Same handling as THORChain:
read with each quote, 15 s cache, fail closed. Nothing was halted on the day.
3. The quote — differences from THORChain
GET /mayachain/quote/swap?from_asset&to_asset&amount&destination&liquidity_tolerance_bps=<slippageBps>&streaming_interval=3&streaming_quantity=0
- Errors are HTTP 200 with
{"error": "…"}(THORNode: HTTP 400{code, message}). Handled; e.g.amount less than dust threshold,fail to add outbound tx … not enough asset to pay for fees→ no route. - Streaming must be asked for. Maya has no advanced swap queue: without
streaming_intervala large swap is quoted as a single swap. Measured for 2 BTC → ETH: about 39 ETH single (slippage_bps≈ 2800) against about 71.6 ETH streamed (29 bps). The adapter therefore always sendsstreaming_interval=3&streaming_quantity=0(the network picks the count, minimum 5 bps of slip per sub-swap). For small amountsmax_streaming_quantityis 1 and the swap is single; the memo still ends in/3/0. The interval is a free choice (3 blocks ≈ 18 s between sub-swaps); the docs give no recommendation. Streaming is reported insteps[0].via[2]andraw.streaming; 2 BTC → ETH: 193 sub-swaps, 58 min of streaming, 68 min in total. - The limit is enforced before the outbound fee. The quote computes
LIM = floor(expected_amount_out × (10000 − bps) / 10000)from the amount net of the outbound fee (querier_quotes.go), but execution compares the gross swap output with it (swap_current.go:if !swapTarget.IsZero() && assetAmount.LT(swapTarget)), and the outbound fee is deducted afterwards. So what the recipient is guaranteed isLIM − outbound fee, notLIM. The adapter reportsminAmountOut = LIM − fees.outbound(both from the quote; the outbound fee is dynamic, so this floor is itself an estimate) and no route when that is not positive. On a 40 USD BTC → ETH quote: expected 0.01971008 ETH, limit 0.01961152, real floor 0.01956260. A signer that wants an exact floor must write its own, higherLIMin the memo. expiry= node wall clock + 15 min.total_swap_secondsis omitted when zero (Arbitrum → BTC):estimatedSeconds: null.- Short codes in memos:
b= BTC.BTC,e= ETH.ETH,a= ARB.ETH; tokens asETH.USDC,ARB.USDC.
Everything else (units, fee mapping, minimums, refusals, validation of memo recipient / asset / limit / router) is as in
thorchain.md §3.
4. Transaction shape
| Source | Shape | Memo carrier |
|---|---|---|
| BTC | vault output first, OP_RETURN with the memo, change back to the address of input 0. Maya's docs page lists the outputs as vault / memo / change, the quote notes say vault, change, then OP_RETURN: follow the quote notes. "BTC Taproot is not supported. Funds sent to or from a Taproot address will be lost." Segwit bech32 preferred. |
OP_RETURN, 80 bytes |
| ETH, Arbitrum ETH | router.depositWithExpiry(vault, 0x0000000000000000000000000000000000000000, amount, memo, expiry) with value = amount (or, per the quote notes, a plain transfer with the memo hex-encoded in data) |
string argument |
| ERC-20 (USDC, USDT) | token.approve(router, amount), then router.depositWithExpiry(vault, token, amount, memo, expiry); expiry = now + 60 min recommended. USDT on Ethereum needs its allowance reset to 0 before a new non-zero approval. |
string argument |
Routers named by the network (router in /mayachain/inbound_addresses, identical on both hosts): Ethereum
0xe3985E6b61b814F7Cdb188766562ba71b446B46d, Arbitrum 0x700E97ef07219440487840Dc472E7120A7FF11F4. Pinned by the adapter,
which rejects any other router (including THORChain's). Not yet checked against verified explorer source.
Dust thresholds on the day (1e8 units): BTC 10 000; ETH and ARB 0. An =:e:0x…:1961152/3/0 memo is 58 bytes.
5. Refunds
Same rules as THORChain (thorchain.md §5): refund to the sender less the source-chain outbound fee; nothing back when the
amount is at or below dust, cannot pay the refund's outbound fee, is sent to a vault that is no longer active, or (BTC)
involves Taproot or a change output away from input 0. Streaming: "If the first attempt fails, the entire streaming swap is
refunded"; otherwise the swapped part is paid out and the rest of the input refunded (partial fill). refundable: true for
every quote returned (all are at or above recommended_min_amount_in).
6. What the isolated signer could and could not verify
Identical to thorchain.md §6, with two Maya specifics:
- the minimum-output check must use
LIM − outbound fee(point 3 above), or the signer must setLIMitself; - two independently hosted public nodes exist, so a two-source check of the vault is possible today — as set membership
in
GET /mayachain/vaults/asgard, not equality: the two hosts named different active vaults at the same moment (0xa2b7…ed2cand0x7df8…4f04; BTCbc1qhrha…andbc1q0ys0…). Two hosts are still not a trust-minimised proof.
The vault address remains unverifiable by the signer on its own; Maya's node set is also much smaller than THORChain's
(DESIREDVALIDATORSET 55, shallow pools), which weighs on the same risk.
7. Tracking
GET /mayachain/tx/status/{hash} (checked live), GET /mayachain/tx/{hash},
GET https://midgard.mayachain.info/v2/actions?txid={hash}.
8. Execution: not enabled (v6, 2026-11-11)
THORChain swaps are now executed by the wallet (thorchain.md §9–§13). The same code would cover Maya — same memo grammar,
same vault model — but the defence it rests on does not exist for Maya today: the signer signs only when at least three
independently operated nodes confirm the vault, and on 2026-11-11 only two keyless public MAYANode operators answered
(mayanode.mayachain.info, also the only entry of the Cosmos chain registry, and api-maya.liquify.com;
midgard.mayachain.info proxies the first one and is not independent; gateway.liquify.com/chain/maya_api answers
"Chain not publicly accessible"; no THORWallet, Rorcual, IBS or Keplr node for Maya was found). With two operators a single
compromise plus one outage, or one actor behind both, is enough to name a false vault. Lowering the quorum for Maya would be
a weaker design than the one THORChain swaps ship with, so Maya stays quote_only.
What enabling it would take: a third and preferably fourth independent MAYANode (or a self-hosted one), then a Maya table
in packages/core/src/thorchain.ts (pools, short codes, routers with bytecode hashes after reading their sources, the
mayapub key prefix), and two differences handled explicitly: the memo limit is enforced before the outbound fee on
Maya (§3 above), so the approved minimum must be limit − outbound fee; and Maya streams only when asked.