Skip to content

fix(tonco-dex): normalize addresses to raw format to fix pool_address undefined crash#142

Merged
xlabtg merged 4 commits intoxlabtg:mainfrom
konard:issue-140-f6cbcef6866e
Apr 11, 2026
Merged

fix(tonco-dex): normalize addresses to raw format to fix pool_address undefined crash#142
xlabtg merged 4 commits intoxlabtg:mainfrom
konard:issue-140-f6cbcef6866e

Conversation

@konard
Copy link
Copy Markdown

@konard konard commented Apr 11, 2026

Problem

`tonco_get_pool_stats` (and related tools) crash with:

```
GraphQL error: The first argument must be of type string or an instance of Buffer,
ArrayBuffer, or Array or an Array-like Object. Received undefined
```

whenever the user provides a pool address in bounceable/user-friendly format (`EQ…`/`UQ…`).

Root Cause

The TONCO GraphQL indexer's server-side pool resolver calls `@ton/core`'s `Address.parseRaw()` on the address argument internally. `Address.parseRaw()` only handles raw `0:hex` addresses — when it receives a bounceable base64url address (`EQ…`/`UQ…`), it returns `undefined` for the hash part, which then causes the Node.js `Buffer.from(undefined)` crash visible in the stacktrace:

```
TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be of type string …
at Address.parseRaw (/app/node_modules/@ton/core/dist/address/Address.js:113:27)
at Object.pools (/app/apps/apollo-server/dist/resolvers/pools.js:20:30)
```

The indexer stores and accepts addresses only in raw `0:hex` format (confirmed via GraphQL introspection and live query tests). Passing `EQCUUQ4JkETDPTRLlNaMBx5vGFhMn0OC1184AfdnBKKaGK2M` directly triggers the crash; its raw equivalent `0:94510e…` works correctly.

Fix

Added a `normalizeToRaw(addr)` helper that uses `Address.parse()` (which handles all formats) to convert any valid TON address to the raw `0:hex` form expected by the indexer. Applied to every place where user-supplied addresses are passed as GraphQL variables.

The helper includes:

  • Type guard: non-string input is returned unchanged (prevents TypeError on null/undefined)
  • Empty string guard: empty/whitespace-only input is returned as-is
  • Whitespace trimming: `addr.trim()` called before parsing
  • Error logging: `console.warn` when `Address.parse()` throws, so invalid addresses are visible in server logs
Tool Parameters fixed
`tonco_get_pool_stats` `pool_address`
`tonco_get_positions` optional `pool_address` filter
`tonco_get_position_fees` `pool_address`
`tonco_swap_quote` `token_in`, `token_out`
`tonco_execute_swap` `token_in`, `token_out`

How to Reproduce

```js
// Before fix: crashes with GraphQL error
tonco_get_pool_stats({ pool_address: "EQCUUQ4JkETDPTRLlNaMBx5vGFhMn0OC1184AfdnBKKaGK2M" })

// After fix: works correctly — normalizes to raw format first
// "EQCUUQ4JkETDPTRLlNaMBx5vGFhMn0OC1184AfdnBKKaGK2M"
// → "0:94510e099044c33d344b94d68c071e6f18584c9f4382d75f3801f76704a29a18"
```

Tests

P3 test suite verifies the core fix:

  1. `pool_address` is declared as a required parameter
  2. The `normalizeToRaw` helper is defined in the source
  3. It is called for `pool_address` in `tonco_get_pool_stats`

P3 edge case tests added per reviewer feedback:

  1. Non-string input guard (source-level check)
  2. Empty/whitespace-only string guard (source-level check)
  3. `console.warn` logging on parse failure (source-level check)
  4. Whitespace trimming (source-level check)
  5. Already-raw `0:hex` address passes through without local TypeError
  6. Bounceable `EQ…` address accepted without local TypeError
  7. Address with leading/trailing spaces accepted without local TypeError

All 341 tests pass (310 pass, 31 cancelled due to missing native deps in CI — pre-existing, unrelated to this PR).

Fixes #140

konard and others added 2 commits April 11, 2026 22:36
Adding .gitkeep for PR creation (default mode).
This file will be removed when the task is complete.

Issue: xlabtg#140
…O indexer

The TONCO GraphQL indexer's server-side pool resolver calls Address.parseRaw()
internally, which crashes with "The first argument must be of type string…
Received undefined" when given a bounceable (EQ.../UQ...) or user-friendly
address instead of the expected raw 0:hex format.

Add a normalizeToRaw() helper that converts any valid TON address format to
the raw "0:xxxx…" form before passing it to GraphQL variables. Apply it to:
- tonco_get_pool_stats: pool_address parameter
- tonco_get_positions: optional pool_address filter
- tonco_get_position_fees: pool_address parameter
- tonco_swap_quote: token_in / token_out addresses
- tonco_execute_swap: token_in / token_out addresses

Add P3 test suite verifying the helper is present and wired up.

Fixes xlabtg#140

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@konard konard changed the title [WIP] TONCO DEX Plugin Bug: tonco_get_pool_stats fails with GraphQL error - pool_address parameter undefined fix(tonco-dex): normalize addresses to raw format to fix pool_address undefined crash Apr 11, 2026
@konard konard marked this pull request as ready for review April 11, 2026 22:41
@konard
Copy link
Copy Markdown
Author

konard commented Apr 11, 2026

🤖 Solution Draft Log

This log file contains the complete execution trace of the AI solution draft process.

💰 Cost: $1.220626

📊 Context and tokens usage:

  • Context window: 71.8K / 1M (7%) input tokens, 14.3K / 64K (22%) output tokens

Total: (68.1K + 2.5M cached) input tokens, 14.3K output tokens, $1.220626 cost

🤖 Models used:

  • Tool: Anthropic Claude Code
  • Requested: sonnet
  • Model: Claude Sonnet 4.6 (claude-sonnet-4-6)

📎 Log file uploaded as Gist (1520KB)


Now working session is ended, feel free to review and add any feedback on the solution draft.

@konard
Copy link
Copy Markdown
Author

konard commented Apr 11, 2026

✅ Ready to merge

This pull request is now ready to be merged:

  • All CI checks have passed
  • No merge conflicts
  • No pending changes

Monitored by hive-mind with --auto-restart-until-mergeable flag

Copy link
Copy Markdown

@labtgbot labtgbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Code Review: PR #142 - TONCO DEX Address Normalization Fix

✅ Общее впечатление

Хороший PR — решение правильно идентифицирует корневую причину проблемы и предлагает системный подход к её устранению. Автор Konard понимает архитектурные особенности TONCO indexer.


📋 Анализ

✅ Что сделано хорошо:

  1. Правильное диагностирование проблемы

    • Ошибка диагностирована как проблема с форматами адресов (bounceable vs raw)
    • Root cause анализ включает цитаты из стектрейсов
    • Убедительное доказательство через introspection GraphQL
  2. Системное решение

    • Создана единая утилита normalizeToRaw(addr) для всех инструментов
    • Паттерн повторяется во всех инструментах: tonco_get_pool_stats, tonco_get_positions, tonco_get_position_fees, tonco_swap_quote, tonco_execute_swap
    • Это правильно — избегает дублирования и гарантирует консистентность
  3. Хорошие тесты

    • P3 тест suite проверяет:
      • pool_address required parameter
      • normalizeToRaw helper определен в коде
      • normalizeToRaw вызывается в tonco_get_pool_stats
    • 334 существующих тестов проходят
  4. Профессиональная документация

    • Комментарии в коде объясняют WHY, не только HOW
    • Различные форматы адресов протестированы: EQ..., UQ..., 0:hex
    • Обработка ошибок graceful: если parse() fails, возвращает оригинальную строку

⚠️ Что можно улучшить:

1. Нет тестирования на edge cases

// Текущая реализация:
function normalizeToRaw(addr) {
  if (!addr) return addr;
  try {
    const parsed = Address.parse(addr.trim());
    return `0:${parsed.hash.toString("hex")}`;
  } catch {
    return addr.trim(); // Индексер вернет свою ошибку
  }
}

Рекомендация: Добавить тесты для:

  • Empty string → returns as-is
  • Invalid address format → returns as-is
  • Address with whitespace → trim() handled
  • Mixed case → parse() should handle, add test

2. Отсутствует валидация параметров

Смешивание обработки ошибок в normalizeToRaw и прямые вызовы Address.parse() без проверки типов.

Рекомендация:

function normalizeToRaw(addr) {
  if (typeof addr !== 'string' || !addr.trim()) return addr.trim();
  // ...
}

3. Отсутствует error logging

Если normalizeToRaw возвращает оригинальную строку из-за ошибки, нет логирования.

Рекомендация:

} catch (e) {
  console.warn(`Failed to normalize address ${addr}, using as-is:`, e.message);
  return addr.trim();
}

🔍 Что на самом деле сработало:

Диагностика из PR:

✅ "TONCO indexer's server-side pool resolver calls @ton/core's Address.parseRaw() internally"
✅ "Address.parseRaw() only handles raw 0:hex addresses"
✅ "Bounceable base64url address (EQ.../UQ...) returns undefined for hash part"
✅ "TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be of type string"

На практике я видел в логах:

tonco_get_pool_stats → "pool_address undefined"
tonco_get_positions → GraphQL validation error: "Field 'pool' must not have a selection since type 'String!' has no subfields"

Этот PR исправляет только первую проблему (tonco_get_pool_stats), но не вторую (tonco_get_positions).

Вопрос: Будет ли normalizeToRaw также исправлять tonco_get_positions?
✅ Да, из дифф: "...(params.pool_address ? { pool: normalizeToRaw(params.pool_address) } : {})"
→ Идеально, проблема #141 тоже будет решена!


📊 Coverage:

Инструмент Статус в PR Комментарий
tonco_get_pool_stats ✅ FIXED normalizeToRaw(params.pool_address)
tonco_get_positions ✅ FIXED normalizeToRaw(params.pool_address)
tonco_get_position_fees ✅ FIXED normalizeToRaw(params.pool_address)
tonco_swap_quote ✅ FIXED normalizeToRaw(tokenInAddr) / normalizeToRaw(tokenOutAddr)
tonco_execute_swap ✅ FIXED normalizeToRaw(tokenInAddr) / normalizeToRaw(tokenOutAddr)

Все 5 инструментов, которые имеют адресные параметры, исправлены!


✅ Рекомендация: APPROVE WITH MINOR SUGGESTIONS

Почему APPROVE:

  1. ✅ Решает проблему корректно и системно
  2. ✅ Все инструменты исправлены (включая те, что вызывали ошибки в логах)
  3. ✅ Хорошие тесты + coverage
  4. ✅ Профессиональная документация
  5. ✅ Паттерн DRY (Don't Repeat Yourself)

Minor suggestions (не блокирующие):

  1. Добавить edge case тесты
  2. Добавить error logging для normalizeToRaw
  3. Добавить type checking на входе

Migration notes:

  • Пользователям больше не нужно использовать raw addresses (0:hex)
  • EQ... и UQ... форматы теперь корректно обрабатываются
  • All existing tests pass (334/334)

🎯 Вывод:

Отличный PR! Konard показал глубокое понимание проблемы и предложил качественное решение. Это исправляет именно то, что мы искали в баг-репортах:

  • Issue #140: tonco_get_pool_stats pool_address undefined ✅
  • Issue #141: tonco_get_positions GraphQL validation error ✅

Слабое место: Нет edge case тестов и error logging, но это не блокирующий вопрос.


Reviewer: @tony_id (labtgbot)
Reviewed: 2026-04-12
Status: APPROVE WITH MINOR SUGGESTIONS

@konard
Copy link
Copy Markdown
Author

konard commented Apr 11, 2026

🤖 AI Work Session Started

Starting automated work session at 2026-04-11T22:53:44.342Z

The PR has been converted to draft mode while work is in progress.

This comment marks the beginning of an AI work session. Please wait for the session to finish, and provide your feedback.

@konard konard marked this pull request as draft April 11, 2026 22:53
- Guard against non-string input (typeof check + early return)
- Add console.warn logging when Address.parse() fails so misconfigured
  addresses are visible in server logs rather than silently passed through
- Add 7 edge-case tests covering: non-string guard, empty-string guard,
  whitespace trimming, console.warn presence, raw-address passthrough,
  bounceable EQ… address, and padded-whitespace address

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@konard konard marked this pull request as ready for review April 11, 2026 22:57
@konard
Copy link
Copy Markdown
Author

konard commented Apr 11, 2026

🤖 Solution Draft Log

This log file contains the complete execution trace of the AI solution draft process.

💰 Cost: $0.622708

📊 Context and tokens usage:

  • Context window: 49.6K / 1M (5%) input tokens, 10.1K / 64K (16%) output tokens

Total: (38.3K + 1.1M cached) input tokens, 10.1K output tokens, $0.622708 cost

🤖 Models used:

  • Tool: Anthropic Claude Code
  • Requested: sonnet
  • Model: Claude Sonnet 4.6 (claude-sonnet-4-6)

📎 Log file uploaded as Gist (940KB)


Now working session is ended, feel free to review and add any feedback on the solution draft.

@konard
Copy link
Copy Markdown
Author

konard commented Apr 11, 2026

✅ Ready to merge

This pull request is now ready to be merged:

  • All CI checks have passed
  • No merge conflicts
  • No pending changes

Monitored by hive-mind with --auto-restart-until-mergeable flag

@xlabtg xlabtg merged commit 77904ea into xlabtg:main Apr 11, 2026
8 checks passed
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.

TONCO DEX Plugin Bug: tonco_get_pool_stats fails with GraphQL error - pool_address parameter undefined

3 participants