fix(swap): correct CACAO 10-decimal scaling in MayaChain provider#594
Conversation
CACAO (MayaChain's native asset) uses 10 decimal places, not 8 like RUNE/THORChain. The Maya /quote/swap API expects CACAO input amounts in 10-dec base units and returns CACAO output amounts in 10-dec base units. The prior code applied the same 8-decimal "thor-amount" conversion for all Maya assets, causing two systematic errors when CACAO was involved: BUG 1 (INPUT): toThorChainAmount() divided CACAO by 10^2 before sending to the API. Maya's API received 100x less CACAO than the user intended → quotes showed 100x too little swap output. BUG 2 (OUTPUT): fromThorChainAmount() multiplied the API's CACAO return value by 10^2, treating the 10-dec native value as 8-dec. → Quotes showed 100x too many CACAO as expected output for non-CACAO→CACAO swaps (e.g. BTC→CACAO, ETH→CACAO). Verified empirically 2026-06-01: querying 1000 CACAO → BTC with amount=10000000000000 (10-dec) yields 172274 sats, matching the pool ratio (1 BTC = 579289 CACAO, ~172600 sats expected). Querying with amount=1000000000000 (8-dec, bug path) yields 16554 sats — 10x low. Fix: add isMayaCACAO() helper + skip scaling for CACAO input/output. All non-CACAO assets (BTC, ETH, ZEC, DASH, …) keep the unchanged 8-dec thor-amount path. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Warning Review limit reached
More reviews will be available in 33 minutes and 32 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
@jpthor heads up - this is a 100x fund-safety bug in the recipes Go SDK affecting every Maya swap quote. CACAO uses 10 decimals (not 8 like RUNE/THORChain) but |
NeOMakinG
left a comment
There was a problem hiding this comment.
Triple-lane review — APPROVE
Verdict: APPROVE. Fix is correct, no in-band change needed.
Lane summary
| Lane | Status | Findings |
|---|---|---|
| Claude (correctness + fund-safety) | Complete | 1 nit (mayaChainDecimals constant currently inert) |
| GLM glm-4.6 | Complete | 4 findings — all false-positives after source verification |
| Codex gpt-5.4 | Unavailable (TTY non-interactive + disk transient) | Adversarial pass done inline by Claude |
Core correctness
isMayaCACAO(a Asset)usesa.Chain == "MayaChain" && a.Address == "". Internally consistent withformatAsset()which uses the sameAddress == ""guard to emitCHAIN.SYMBOLvsCHAIN.SYMBOL-ADDRESS. No asset that passesisMayaCACAOwould be routed to the API under a different format.- CACAO input path:
new(big.Int).Set(req.Amount)— clean copy passed to API. 10-dec in → 10-dec to API. Correct. - CACAO output path:
expectedOutput = expectedOutputMaya— raw API string returned as-is. No phantom multiply-by-100. Correct. - Non-CACAO paths:
toThorChainAmount/fromThorChainAmountcalled identically to pre-fix behavior. Verifiedthorchain.go:36-66— simplebig.Intdivide/multiply with no edge cases.
Adversarial sweep
- Negative
req.Amount→mayaAmount.String()emits"-N"→ Maya API rejects → fail-closed. - Nil
req.Amount→ pre-existing panic in BOTH old and new paths (no regression). {MayaChain, FOO, ""}false-positive forisMayaCACAO→formatAssetemitsMAYA.FOO→ Maya API rejects unknown asset → no fund movement.
Build / vet
go build ./sdk/swap/... exit 0. go vet ./sdk/swap/... exit 0. Test binary link fails only due to pre-existing bytedance/sonic / Go 1.26 linker incompatibility — documented in PR, unrelated to this change.
GLM triage
All 4 findings false-positive: (1) sentinel fragility — consistent with the repo's formatAsset convention; (2) zero/overflow — big.Int has no overflow, zero → API error (fail-closed); (3) unverified fromThorChainAmount — verified above; (4) no API version guard — out-of-scope.
Non-blocking nit
mayaChainDecimals = 10 at mayachain.go:36 is currently inert (declared but never referenced in arithmetic). Consider wiring it into the test arithmetic (e.g. new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(mayaChainDecimals)), nil) in CACAO_input_no_scaling) so the constant becomes load-bearing and future decimal-change regressions don't silently pass.
what
MayaChain's native asset CACAO uses 10 decimal places - unlike RUNE/THORChain which uses 8. The Maya
/quote/swapAPI expects CACAO input amounts in 10-dec base units and returns CACAO output amounts in 10-dec base units.The prior code applied the same 8-decimal "thor-amount" conversion (via
toThorChainAmount/fromThorChainAmount) for all Maya assets. This caused two systematic 100x errors when CACAO was involved:BUG 1 - INPUT: when swapping FROM CACAO, the API received 100x less CACAO than the user intended
BUG 2 - OUTPUT: when CACAO is the swap destination, the expected output was inflated 100x
evidence
Verified against live /mayachain/quote/swap 2026-06-01:
For CACAO output: API returns 57763399808087 for 0.01 BTC -> CACAO. At 10-dec = 5776 CACAO (matches pool). Prior code's fromThorChainAmount(..., 10) multiplied by 100 -> 577633 CACAO shown (100x inflated).
fix
isMayaCACAO()helper: returns true whenchain == "MayaChain"andaddress == ""(native asset)New
mayachain_test.gocovers: isMayaCACAO classification, CACAO input pass-through, ETH input still scales to 8-dec, CACAO output pass-through, ETH output still scales from 8-dec.affected swap paths
BTC->CACAO,ETH->CACAO,ARB->CACAO,ZEC->CACAO,DASH->CACAO,CACAO->BTC,CACAO->ETH, etc.receipts
no user-visible UI surface - receipt is
go build+go vetproof (sdk/swap test binary hits a pre-existing sonic/Go1.26 linker incompatibility in this repo, unrelated to this PR):CI test run covers the new
TestMayaCACAODecimalScalingcases. Live API proof above confirms the 10-dec path produces the correct 172274 sats output vs 16554 sats on the bug path.