Repository navigation
fix(solana): native SOL by mint, balances keys and errors, Meteora add/open fixes, wallet activity route - #724
Closed
fengtality wants to merge 8 commits into
Closed
fengtality wants to merge 8 commits into
fengtality wants to merge 8 commits into
Conversation
The Meteora DLMM open, add, remove and close routes, Raydium CLMM add, and Solana.extractClmmBalanceChanges treated a token as native SOL when its symbol was 'SOL'. Any mint's metadata can claim that symbol. Such a token was then measured on the native balance, or had a fee or rent correction applied to it. Compare the mint with NATIVE_MINT instead.
/chains/solana/balances turned every error except a 429 into a 500. A 4xx now passes through as it is. getBalances answers 400 for a malformed wallet address, which used to surface as a 500.
[Medium impact] The PR appears safe to merge; the numbered balance-key finding is fixed, and no new blocking issue was established. SummaryThis PR switches native SOL checks to mint addresses, makes requested balance keys consistent, supports unlisted mints, and adds cleanup for empty Meteora positions.
Review checks were static; no tests were run during this review.
|
fengtality
force-pushed
the
fix/solana-fork-fixes
branch
from
October 20, 2026 02:40
1b216c7 to
5e122db
Compare
fengtality
force-pushed
the
fix/solana-fork-fixes
branch
from
October 20, 2026 02:50
5e122db to
3e4e74d
Compare
…ts symbol getBalances reported a listed token under its symbol when asked for by symbol, but under its mint when asked for by mint, so the caller could not name or price it. Both now report the symbol. A wallet with no token accounts goes through the same steps instead of its own shortcut, so the keys no longer depend on whether the wallet holds the token.
…s mints The DLMM add-liquidity route asked getBalances for the tokens' symbols. A token outside the token list has no symbol getBalances knows (getToken names it DUMMY_..., or the route falls back to UNKNOWN), so its balance read as 0 and a funded wallet was refused with 'Insufficient balance'. Ask by mint, read each side under the key getBalances reports it by, and treat the native side by its mint for the transaction buffer.
… fails A wide DLMM open creates the position in one transaction and funds it over several. When the first deposit chunk failed, the route left an empty position behind, still holding its rent. It now reads the position and, if it holds nothing, closes it with closePositionIfEmpty and says so in the error. A send can fail after its chunk was broadcast and still land, so a position that holds tokens is left open and the error says what it holds. If the read or the close fails, the error names the position.
… activity
Each of a wallet's recent transactions is named as what it did: swap,
open_position, add_liquidity, remove_liquidity, collect_fees,
close_position, deposit or withdraw. It covers the Solana venues Gateway
trades on: Meteora DLMM and DAMM v2, Raydium CLMM, CPMM and AMM v4, Orca
Whirlpools, PancakeSwap's Solana CLMM, and Jupiter.
Two readings are joined per transaction. The venue instruction is matched by
program id and discriminator on the outer instructions and the inner CPIs,
with Anchor discriminators derived from instruction names
(sha256("global:<name>")) and pinned in a test against published bytes.
What moved is read from the wallet's own pre and post balances, SOL included
and the fee kept out. With no venue, the tokens that moved decide deposit or
withdraw (the SOL a new token account costs is not a withdrawal), and a wrap
or unwrap is neither.
Transactions are read five at a time rather than in one JSON-RPC batch,
which not every RPC honours. The venue tables hold mainnet program ids, so
another cluster answers 400. A malformed address answers 400, and Ethereum
answers 501. The spec test for the signing gate lists GETs that return
signatures separately and exactly, since a GET signs nothing.
Base and quote resolve in the venue's own order, and the venues disagree: Meteora usually puts SOL on the quote side, Orca and Raydium on the base side. Requiring one orientation empties most of Orca's and Raydium's SOL pools, and a caller that always puts its SOL budget in one amount field sends it to the wrong token on half of them. Orca returns tradeEnableTimestamp as the unix epoch on every pool, so every Orca pool looks decades old and pool-age filters silently pass or drop the whole venue. Also notes that the yield figures Gateway passes through are each venue's own quantity, not normalised.
fetchTokenAccounts dropped every token account whose mint is not in the token list, so getBalances reported 0 for an unlisted mint the wallet holds, and Meteora add-liquidity still refused a funded wallet for one. Keep those accounts; the balance uses the decimals read from the mint through the token program that owns the account. A mint that cannot be read is now an error instead of a balance computed with a guessed 9 decimals after a 1 s timeout. The default list-only view is unchanged. The Meteora add-liquidity test now runs the real fetchTokenAccounts over encoded token accounts instead of a stub.
fengtality
force-pushed
the
fix/solana-fork-fixes
branch
from
October 20, 2026 03:06
3e4e74d to
6786f59
Compare
Contributor
Author
|
Bundled into #735 with the other fix PRs. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Small Solana fixes found while running Gateway forks against mainnet, ported to
development. One commit per fix, each with a test that fails without it (except the docs commit). Review feedback from Greptile is folded into the commits; fix 8 was added for its first finding.Fixes
eaaff1c18; sourced8c4870a). The Meteora DLMM open, add, remove and close routes, Raydium CLMM add, andSolana.extractClmmBalanceChangestreated a token as native SOL when its symbol was'SOL'. Any mint's metadata can claim that symbol. They now compare the mint withNATIVE_MINT.c59f3ed24; sourced8c4870a).POST /chains/solana/balancesturned every error except 429 into a 500. A 4xx now passes through. Added here:getBalancesanswers 400 for a malformed wallet address, which used to be a 500.d6a41a004, completed by fix 8; sourced8c4870a).developmenthas the same fault: the route askedgetBalancesfor symbols, and a token outside the token list (namedDUMMY_…orUNKNOWN) read as 0, so a funded wallet got "Insufficient balance". It now asks by the pool's mints. Changed from the source: it reads each side under the keygetBalancesreports (the list symbol for a listed mint, the mint otherwise,SOLfor native) and throws a clear error if that key is missing. This depends on fix 4, and on fix 8 for unlisted tokens.1bf6e95b1; sourcef82e207e). A listed token asked for by its mint is reported under its symbol, the same as when asked for by symbol. Added here: the shortcut for a wallet with no token accounts is removed, so it goes through the same steps and the keys no longer depend on whether the wallet holds the token. A token-list entry of another mint with the symbolSOLis refused with a clear error, because its balance would overwrite the nativeSOLkey.9b5a5712c; sourceb7684ba6,openPosition.tspart only). When the first deposit chunk of a wide Meteora open fails, the route reads the position. If it holds nothing, the route closes it withclosePositionIfEmptyand returns its rent. Added here: a send can fail after its chunk was broadcast and still land, so a position that holds tokens is left open and the error says what it holds. If the read or the close fails, the error names the position.a496d80b8; source67677eb5).GET /chains/:chain/transactionslists a wallet's recent Solana transactions, each named as what it did (swap, open_position, add_liquidity, remove_liquidity, collect_fees, close_position, deposit, withdraw), with the wallet's own balance changes. Ethereum answers 501. Changed from the source: covers only venuesdevelopmenthas connectors and SDKs for (Meteora DLMM and DAMM v2, Raydium CLMM, CPMM and AMM v4, Orca, PancakeSwap Solana CLMM, Jupiter). The launchpad venues are left for feat: launchpad connectors (pump.fun, Meteora DBC, Raydium LaunchLab) #721. A malformed address answers 400 and other 4xx pass through. The venue tables hold mainnet program ids, so another cluster answers 400 instead of misreading every venue call as a transfer. With no venue, the tokens that moved decide deposit or withdraw (the SOL a new token account costs is not a withdrawal), a wrap or unwrap is neither, and balances are read per side with that side's owner, so an account handed to another owner counts. It reads the wallet address's own signature history, so a transfer into an existing token account that does not name the wallet is not listed; the route description says so. Adds anoperationIdand regeneratesopenapi.json.afd1ffdec; source738b1821,11f8ba5c).docs/cross-venue-pool-normalisation.md: base/quote orientation differs by venue, and Orca'stradeEnableTimestampis always the epoch. Changed from the source: three corrections. The source said a pool with SOL on the unexpected side cannot take a quote-denominated deposit; it can, with the amount in the other field. The source said a minimum-age filter excludes all of Orca; an epoch timestamp makes every pool look old, so it passes them all. The source said Gateway surfaces no yield fields, but ondevelopmentOrcapool-inforeturnsyieldOverTvlandfetch-poolsreturnsapr.6786f5969; source: the generic part of a later fork commit).fetchTokenAccountsdropped every token account whose mint is not in the token list, sogetBalancesreported 0 for an unlisted mint the wallet holds, and fix 3 still refused a funded wallet for one. Those accounts are now kept, and the balance uses the decimals read from the mint through the token program that owns the account. A mint that cannot be read is now an error, instead of a balance computed with a guessed 9 decimals after a 1 s timeout. A rate limit on the mint read stays a 429. The default list-only view is unchanged. The fix 3 test now runs the realfetchTokenAccountsover encoded token accounts.Change to the signing-gate spec test
test/spec/signing-routes-are-gated.test.tstreats any operation whose response has asignatureit was not given as a signing route that must be gated. The new GET route lists past signatures and signs nothing, so the test now puts GET operations in ahistoryRouteslist. That list is asserted exactly (['/chains/ethereum/transactions']), so any new GET that returns asignaturestill fails the test until someone looks at it. This is the same shape #721 uses for its launch-history route, so the two only conflict on the contents of that list.Overlap
Checked against #721 and #723. Neither has these changes. #721 touches
chain.routes.ts,chain-schema.ts,operation-ids.tsand the same spec test, so expect small textual conflicts there.Tests
pnpm build,pnpm lint(0 errors) andGATEWAY_TEST_MODE=dev pnpm testwith a freshconf/copied fromsrc/templates: 177 suites, 1540 tests passed.pnpm generate:openapileavesopenapi.jsonunchanged.🤖 Generated with Claude Code