Skip to content

feat: GET /tokens endpoint with pagination#239

Open
sadiq1971 wants to merge 3 commits intofeat/user-info-v2from
feat/token-list-v2
Open

feat: GET /tokens endpoint with pagination#239
sadiq1971 wants to merge 3 commits intofeat/user-info-v2from
feat/token-list-v2

Conversation

@sadiq1971
Copy link
Copy Markdown
Member

Why this is needed

The dApp needs a supported token list to function correctly at startup and throughout the session:

  • Asset selector — when a user initiates a transfer or checks a balance, the UI must present the list of supported ERC-20 tokens (name, symbol, decimals, contract address). Without this endpoint the frontend has to hardcode tokens or ship a separate config file.
  • Decimal scaling — the dApp converts between human-readable amounts and on-chain units using the decimals field. Fetching this from the API keeps it in sync with the server config and avoids drift when tokens are added or removed.
  • Contract address resolution — MetaMask and other wallet interactions require the canonical contract address per token. The API is the single source of truth for this mapping.
  • Dynamic token support — new tokens can be enabled server-side without a frontend release; the dApp re-fetches /tokens on connect and renders whatever the server exposes.

What changed

  • pkg/token/types.go — added TokenItem and TokensPage response types.
  • pkg/token/service.go — added GetSupportedTokens(ctx, page, limit) to *Service; tokens sorted by address hex for stable pagination across requests.
  • pkg/token/http.go — new file; ListService interface, HTTP struct, RegisterRoutes, listTokens handler with parsePagination (?page, ?limit; defaults 1/50; max limit 200; 400 on invalid input).
  • pkg/token/http_test.go — new file; 6 tests covering default pagination, explicit params, invalid page/limit values, service error, and empty list.
  • pkg/token/mocks/mock_list_service.go — generated mock for ListService.
  • pkg/app/api/server.go — replaced 19-line inline closure with token.RegisterRoutes(r, tokenService, logger).

Endpoint

GET /tokens?page=1&limit=50

Response:

{
  "items": [
    { "address": "0x...", "name": "Demo Token", "symbol": "DEMO", "decimals": 18 }
  ],
  "total": 2,
  "page": 1,
  "limit": 50
}

Test plan

  • go test ./pkg/token/... — all tests green.
  • GET /tokens returns 200 with token list.
  • GET /tokens?page=2&limit=1 pages correctly.
  • GET /tokens?limit=999 returns 400.

@sadiq1971 sadiq1971 self-assigned this Apr 24, 2026
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot 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

This pull request introduces a new /tokens endpoint to provide a paginated and sorted list of supported tokens. The implementation includes the HTTP routing, service-level logic for pagination and sorting, and comprehensive unit tests. Feedback highlights a security concern regarding the default disabling of the whitelist check in the Docker configuration and a potential integer overflow in the pagination calculation that could cause a service panic.

I am having trouble creating individual review comments. Click here to see my feedback.

pkg/config/defaults/config.api-server.docker.yaml (96)

high

Disabling skip_whitelist_check by default in the Docker configuration is a security regression. This setting allows any user to register with the relayer without being on a whitelist. If this change was intended for local development or testing, it should be managed via environment variables (e.g., ${SKIP_WHITELIST_CHECK}) or a separate development-specific configuration file to ensure production-like environments remain secure by default.

pkg/token/service.go (68-72)

high

The calculation of the start index can overflow if a very large page number is provided (e.g., math.MaxInt). Since limit is at least 1, an overflow could result in a negative start value, causing a runtime panic when slicing addrs. Adding a check to ensure page is within a reasonable range relative to the total number of tokens prevents this potential Denial of Service (DoS) vulnerability.

	total := len(addrs)
	if total == 0 || page > total {
		return &TokensPage{Items: []TokenItem{}, Total: total, Page: page, Limit: limit}, nil
	}
	start := (page - 1) * limit
	if start >= total {
		return &TokensPage{Items: []TokenItem{}, Total: total, Page: page, Limit: limit}, nil
	}

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 24, 2026

Codecov Report

❌ Patch coverage is 49.12281% with 29 lines in your changes missing coverage. Please review.
✅ Project coverage is 33.15%. Comparing base (2e53f70) to head (b177499).

Files with missing lines Patch % Lines
pkg/token/service.go 0.00% 26 Missing ⚠️
pkg/token/http.go 93.33% 1 Missing and 1 partial ⚠️
pkg/app/api/server.go 0.00% 1 Missing ⚠️

❌ Your patch status has failed because the patch coverage (49.12%) is below the target coverage (50.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files

Impacted file tree graph

@@                  Coverage Diff                  @@
##           feat/user-info-v2     #239      +/-   ##
=====================================================
+ Coverage              31.51%   33.15%   +1.63%     
=====================================================
  Files                    124      124              
  Lines                  10448     8671    -1777     
=====================================================
- Hits                    3293     2875     -418     
+ Misses                  6906     5547    -1359     
  Partials                 249      249              
Flag Coverage Δ
unittests 33.15% <49.12%> (+1.63%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
pkg/app/api/server.go 0.00% <0.00%> (ø)
pkg/token/http.go 93.33% <93.33%> (ø)
pkg/token/service.go 62.62% <0.00%> (-21.29%) ⬇️

... and 108 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread pkg/token/http.go
}

func (h *HTTP) listTokens(w http.ResponseWriter, r *http.Request) error {
page, limit, err := parsePagination(r)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should use cursor approach here instead of pages for pagination. The response we can return could be.

{
  "items": [...],
  "next_cursor": "...",
  "has_more": true
}

Let me know what you think.

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.

3 participants