Skip to content

THORChain: accept remote tokens from the info server - #1117

Merged
j0ntz merged 2 commits into
masterfrom
jon/thorchain-remote-tokens
Oct 8, 2026
Merged

j0ntz merged 2 commits into
masterfrom
jon/thorchain-remote-tokens

Conversation

@j0ntz

@j0ntz j0ntz commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

CHANGELOG

Does this branch warrant an entry to the CHANGELOG?

  • Yes
  • No

Dependencies

none

Description

Asana task

thorchainrune and thorchainrunestagenet accept bank-denom tokens from the info server's infoServerTokens: RUJI, AUTO, LQDY, secured BTC/ETH/SOL, sTCY, sRUJI, bRUNE and ybRUNE. The bundled token list is unchanged; TCY is still its only entry.

Ingestion. updateBuiltinTokens takes remote tokens only from a plugin that supplies a synchronous createTokenId. THORChain had none, and every remote entry was dropped. The Cosmos denom check is a shared createCosmosTokenId helper, called by CosmosTools.getTokenId and by the THORChain outer plugins. The token id is the lowercased denom with slashes removed (x/staking-x/ruji gives xstaking-xruji). The raw denom stays in networkLocation.contractAddress, the value balance queries and MsgSend use.

A remote THORChain entry is rejected when:

  • the denom is malformed or falls outside the cosmos-sdk denom charset
  • the denom has uppercase characters (THORChain bank denoms are lowercase, and the raw string goes to the chain)
  • the denom is the native rune
  • its currency code is RUNE, or matches a bundled token with a different denom
  • its token id collides with a bundled token (the bundled token wins, as updateBuiltinTokens already does)

The generic Cosmos denom regex had no end anchor and accepted any string with a valid prefix. It is anchored to the full cosmos-sdk charset. Mixed case stays legal there, which keeps custom tokens on other Cosmos chains working.

Native denom. CosmosTools.getTokenId rejects a token whose denom is the chain's own nativeDenom, on every Cosmos plugin, with ErrorInvalidContractAddress. The comparison ignores case, as the engine's balance matching does. Before this change the token was accepted. The THORChain rune check in the list above stays, because info server ingestion calls the outer createTokenId and never reaches getTokenId.

History. Midgard names an asset differently from the bank module: THOR.RUJI in swaps and X/RUJI in sends for the denom x/ruji, THOR.AUTO for thor.auto. The shared mapping kept only the last segment of the name, which matched no token. extendedParseCoins also rejected a denom with a dot. Either one dropped the whole action from history. ThorchainEngine ports thornode's Asset.Native() for the mapping, MAYAChain keeps the previous mapping, and coin parsing takes the full cosmos-sdk charset.

Other PRs. EdgeApp/edge-currency-accountbased#1115 covers the ingestion half and has no Midgard work. EdgeApp/edge-currency-accountbased#1034 removes the outer-plugin createTokenId hook and keeps CosmosTools.getTokenId. After it lands, the createTokenId lines on the two THORChain infos are the only part of this PR to delete; the helper and the history mapping carry over.

EdgeApp/edge-react-gui#6248 adds the testID the simulator flow uses to open a custom token's edit form. Neither PR depends on the other.

Testing. Unit tests cover the ten denoms, each rejection case, and Midgard fixtures copied from live actions. The iOS simulator run used a local proxy that adds the ten tokens to the info server rollup:

  • all ten are listed in Add / Edit Tokens beside TCY
  • a RUJI balance received from a THORChain swap is detected and shown in history
  • a RUJI send reaches Transaction Success (tx 3EBA256AFAE3D177302B2F36A345247ACD0A4712AA678954B4E403A0965C6D2D)

test/cosmos/nativeDenomTokenId.test.ts checks the native denom rejection, in lowercase and uppercase, on all eight Cosmos plugins. On the simulator an Osmosis wallet refuses uosmo on the Add Token and Edit Token forms and still saves rune as a custom token (cells 11 to 14).

Not covered:

  • stagenet was not driven on the simulator
  • the Midgard names for the x/staking-* and x/brune denoms follow thornode's rule and were not observed in live actions
  • an engine already running when the info payload changes gets new tokens at its next token-list rebuild
  • the native denom rejection was driven in the app on Osmosis only, the one Cosmos chain with a custom token form; the other seven have the unit test

Test evidence

0f9a7a8
2026-10-02

1. remote tokens in wallet search

2. token list top

3. token list bottom

4. ruji balance

5. ruji send confirm

6. ruji send success

7. ruji send details

8. ruji history
0b5048c
fixup! Map Midgard asset names to THORChain denoms
2026-10-07

11. osmosis add native denom rejected

12. osmosis other denom saved

13. osmosis edit to native denom rejected

14. osmosis control token deleted

Note

Medium Risk
Changes token ingestion rules and Midgard-to-denom mapping for THORChain transaction history; incorrect mapping could mis-attribute balances or omit token txs, though coverage includes live Midgard fixtures.

Overview
THORChain mainnet and stagenet plugins now wire createTokenId via makeThorchainCreateTokenId, so infoServerTokens from the info server are ingested as bank-denom tokens (RUJI, AUTO, staking variants, etc.) while rejecting uppercase denoms, the native rune, and duplicate currency codes.

Cosmos token IDs are centralized in createCosmosTokenId (cosmos-sdk denom rules, slashes stripped for IDs). CosmosTools.getTokenId rejects adding a chain’s own nativeDenom as a custom token on all Cosmos plugins.

Midgard history for THORChain maps Midgard asset names (THOR.RUJI, X/RUJI, THOR.AUTO, …) to real bank denoms through thorchainAssetToDenom, and extendedParseCoins accepts denoms with dots and slashes so token movements are no longer dropped from history.

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

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Comment thread src/cosmos/CosmosTools.ts Outdated
j0ntz added 2 commits October 8, 2026 13:58
THORChain had no synchronous createTokenId, so infoServerTokens
entries were dropped. Share the Cosmos denom validation between the
tools and the outer plugin, anchor it to the full cosmos-sdk denom
charset, and reject remote entries that reuse the native denom or a
known currency code.
Midgard names a token by its asset (THOR.RUJI, THOR.AUTO, X/RUJI),
not by the bank denom the engine tracks (x/ruji, thor.auto). The
shared mapping cut the name down to its last part, which matched
nothing, and coin parsing rejected a denom with a dot, so the whole
action was dropped from history.

Port thornode's Asset.Native() as the THORChain mapping, keep the
existing one for MAYAChain, and parse the full cosmos-sdk denom
charset.
@j0ntz
j0ntz force-pushed the jon/thorchain-remote-tokens branch from 0b5048c to 33140f2 Compare October 8, 2026 21:03
@j0ntz
j0ntz merged commit bd66fd7 into master Oct 8, 2026
4 checks passed
@j0ntz
j0ntz deleted the jon/thorchain-remote-tokens branch October 8, 2026 21:17
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