Skip to content

fix: handle null tokens in balance extraction after transaction#569

Merged
fengtality merged 3 commits intodevelopmentfrom
fix/null-token-balance-extraction
Dec 9, 2025
Merged

fix: handle null tokens in balance extraction after transaction#569
fengtality merged 3 commits intodevelopmentfrom
fix/null-token-balance-extraction

Conversation

@fengtality
Copy link
Contributor

@fengtality fengtality commented Dec 8, 2025

Summary

Fixes a bug where Gateway returns HTTP 500 errors after transactions are successfully confirmed on-chain when pool tokens are not in Gateway's token list.

Root Cause: When getToken() returns null for unknown tokens, the code crashes trying to access .address on null objects during balance extraction.

Fix: Use pool token addresses directly as fallback when getToken() returns null:

// Before (crashes if tokenX is null)
extractBalanceChangesAndFee(signature, wallet, [tokenX.address, tokenY.address])

// After (uses pool address as fallback)
extractBalanceChangesAndFee(signature, wallet, [
  tokenX?.address || dlmmPool.tokenX.publicKey.toBase58(),
  tokenY?.address || dlmmPool.tokenY.publicKey.toBase58(),
])

Affected Connectors

  • Meteora CLMM: openPosition
  • Raydium AMM: addLiquidity, removeLiquidity
  • Raydium CLMM: addLiquidity, removeLiquidity
  • Orca CLMM: addLiquidity, removeLiquidity, closePosition, collectFees

Manual QA Test Plan

Test using pools containing the Franklin token (CSrwNk6B1DwWCHRMsaoDVUfD5bBMQCJPY72ZG3Nnpump) or another token that is NOT in your Gateway's token list.

Prerequisites

  • Do NOT add Franklin token to Gateway's token list (the bug only occurs with unknown tokens)
  • Ensure you have SOL and USDC for test transactions

Test Cases

1. Meteora CLMM - Open Position

curl -X POST http://localhost:15888/connectors/meteora/clmm/open-position \
  -H "Content-Type: application/json" \
  -d '{
    "network": "mainnet-beta",
    "walletAddress": "<YOUR_WALLET>",
    "poolAddress": "<FRANKLIN_USDC_POOL>",
    "lowerPrice": 0.01,
    "upperPrice": 0.02,
    "quoteTokenAmount": 10
  }'

Expected: Returns 200 with signature and position details (not 500 error)

2. Meteora CLMM - Close Position

curl -X POST http://localhost:15888/connectors/meteora/clmm/close-position \
  -H "Content-Type: application/json" \
  -d '{
    "network": "mainnet-beta",
    "walletAddress": "<YOUR_WALLET>",
    "positionAddress": "<POSITION_FROM_STEP_1>"
  }'

Expected: Returns 200 with signature and removed amounts

3. Orca CLMM - Open Position

curl -X POST http://localhost:15888/connectors/orca/clmm/open-position \
  -H "Content-Type: application/json" \
  -d '{
    "network": "mainnet-beta",
    "walletAddress": "<YOUR_WALLET>",
    "poolAddress": "<FRANKLIN_USDC_WHIRLPOOL>",
    "lowerPrice": 0.01,
    "upperPrice": 0.02,
    "quoteTokenAmount": 10
  }'

Expected: Returns 200 with signature and position details

4. Orca CLMM - Close Position

curl -X POST http://localhost:15888/connectors/orca/clmm/close-position \
  -H "Content-Type: application/json" \
  -d '{
    "network": "mainnet-beta",
    "walletAddress": "<YOUR_WALLET>",
    "positionAddress": "<POSITION_FROM_STEP_3>"
  }'

Expected: Returns 200 with signature and removed amounts

5. Raydium CLMM - Open Position

curl -X POST http://localhost:15888/connectors/raydium/clmm/open-position \
  -H "Content-Type: application/json" \
  -d '{
    "network": "mainnet-beta",
    "walletAddress": "<YOUR_WALLET>",
    "poolAddress": "<FRANKLIN_USDC_RAYDIUM_CLMM>",
    "lowerPrice": 0.01,
    "upperPrice": 0.02,
    "quoteTokenAmount": 10
  }'

Expected: Returns 200 with signature and position details

6. Raydium CLMM - Close Position

curl -X POST http://localhost:15888/connectors/raydium/clmm/close-position \
  -H "Content-Type: application/json" \
  -d '{
    "network": "mainnet-beta",
    "walletAddress": "<YOUR_WALLET>",
    "positionAddress": "<POSITION_FROM_STEP_5>"
  }'

Expected: Returns 200 with signature and removed amounts

Verification

  • All 6 test cases return HTTP 200 (not 500)
  • Transaction signatures are valid and confirmed on Solscan
  • Position addresses are returned correctly
  • No "Cannot read properties of null (reading 'address')" errors in logs

Automated Tests

Added regression tests in test/connectors/null-token-handling.test.ts (12 tests) to prevent this bug from recurring.

🤖 Generated with Claude Code

When a pool contains tokens not in Gateway's token list, getToken()
returns null. Previously, this caused "Cannot read properties of null
(reading 'address')" errors AFTER transactions were confirmed on-chain,
causing users to lose track of their positions.

Fix: Use pool's token addresses directly as fallback when getToken()
returns null.

Affected connectors:
- Meteora CLMM: openPosition
- Raydium AMM: addLiquidity, removeLiquidity
- Raydium CLMM: addLiquidity, removeLiquidity
- Orca CLMM: addLiquidity, removeLiquidity, closePosition, collectFees

Also adds regression tests to prevent this bug from recurring.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@fengtality fengtality requested a review from rapcmia December 8, 2025 22:39
@fengtality fengtality added this to the v2.11 milestone Dec 8, 2025
@fengtality fengtality changed the title fix: handle null tokens in balance extraction after transaction fix: improve HTTP error handling and null token handling Dec 8, 2025
@fengtality fengtality changed the title fix: improve HTTP error handling and null token handling fix: handle null tokens in balance extraction after transaction Dec 8, 2025
@rapcmia rapcmia moved this to Under Review in Pull Request Board Dec 9, 2025
@rapcmia
Copy link
Contributor

rapcmia commented Dec 9, 2025

Commit 488d9ff

  • Able to reproduce the error on gateway development branch
    curl -X POST http://localhost:15888/trading/clmm/open \
        -H 'Content-Type: application/json' \
        -d '{
          "connector": "orca",
          "chainNetwork": "solana-mainnet-beta",
          "poolAddress": "6nD6d8gG17wakW6Wu5URktBZQp3uxp5orgPa576QXigJ",
          "lowerPrice": 5.3,
          "upperPrice": 5.9,
          "baseTokenAmount": 0.52689894,
          "quoteTokenAmount": 3,
          "walletAddress": "GiooMWkHziPuXhfRar2ChBxU6VhQSrAh7xJTG2zHcxWV"
        }' | jq
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100   425  100    91  100   334  32887   117k --:--:-- --:--:-- --:--:--  207k
    
    {
      "statusCode": 500,
      "error": "Internal Server Error",
      "message": "An unexpected error occurred"
    }
    
  • Test using helius as nodeURL
  • Test with TRUMP pools 9d9mb8kooFfaD3SctgZtkxQypkshx6ezhbKio89ixyy2
    • TRUMP not added to token list
  • Open and close position for the following connectors:
    • Meteora: SgHTEmZ75MBziraYADfbxx8n9uZYFNWCSELj34wYeaU ✅
    • Orca: Da4aScebNggUxhKWN1Nqogati63pZkFfs97tD1iHTS4E ✅
    • Raydium: 9srQg3FQSSCHPEatJn1PrWFpZPpudRKvfyvouWDhu6mW ✅
    • All connector run position-owned and compare the dataset received between gateway endpoint and exchange
    • Confirmed on txns correct
  • No Error found on every endpoint to open, position-info and closed used :

Added test and gateway logs 12092025a.zip

Base automatically changed from refactor/http-errors to development December 9, 2025 12:55
@fengtality fengtality merged commit a9af2e5 into development Dec 9, 2025
4 checks passed
@fengtality fengtality deleted the fix/null-token-balance-extraction branch December 9, 2025 12:55
@rapcmia rapcmia moved this from Under Review to Development v2.11.0 in Pull Request Board Dec 9, 2025
@rapcmia rapcmia moved this from Development v2.11.0 to Release v2.10.0 in Pull Request Board Dec 17, 2025
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