Skip to content

sdk(DistributorClient): getUserStats/getTokenStats compute actualUser/actualToken but never use them; JSDoc claims an unsupported wrapper-object input #256

@pragmaticAweds

Description

@pragmaticAweds

Summary

DistributorClient.getUserStats and getTokenStats extract actualUser/actualToken from the parameter, then discard the extracted value and pass the raw parameter to addressToString. The JSDoc on both methods promises an { user: ... } / { token: ... } wrapper-object input form that the type signature (AddressParam = string | Address) does not support and that the body would not handle correctly even if it did.

Where

packages/sdk/src/DistributorClient.ts:106-137

/**
 * Get stats for a specific user.
 * @param user The address of the user, or an object containing the user address.
 */
public async getUserStats(
  user: AddressParam
): Promise<AssembledTransaction<UserStats | undefined>> {
  const actualUser = typeof user === "object" ? user.user : user;   // ← computed and never used

  return executeWithErrorHandling(
    () =>
      this.client.get_user_stats({ user: addressToString(user) }) as Promise< // ← uses raw `user`
        AssembledTransaction<UserStats | undefined>
      >,
    "Get user statistics"
  );
}

getTokenStats (lines 125-137) has the same dead-code shape with actualToken.

Why this is a real bug, not just lint noise

  1. The JSDoc lies. Consumers who pass { user: 'G...' } (per the docstring) will see TypeScript reject it; if they cast around the type, runtime hits addressToString({ user: 'G...' }), which throws or returns garbage.
  2. typeof user === 'object' is true for Address instances, so actualUser becomes (addressInstance as any).user (undefined) — a footgun if the unused variable is ever wired up later.
  3. The dead destructure suggests this was supposed to be the parameter unwrapping logic and was abandoned mid-refactor — easy to misread on next-touch.

The other Distributor methods (distributeEqual, distributeWeighted, setAdmin, etc., lines 50-83 / 200+) accept AddressParam and call addressToString(...) directly with no destructure. That's the correct shape; getUserStats/getTokenStats should match.

Fix

Pick one of:

Option A — drop the dead code (recommended, minimal change):

public async getUserStats(user: AddressParam) {
  return executeWithErrorHandling(
    () => this.client.get_user_stats({ user: addressToString(user) }) as Promise<...>,
    "Get user statistics"
  );
}

Update the JSDoc to remove the "or an object containing the user address" claim. Apply the same to getTokenStats.

Option B — actually support the wrapper form by widening AddressParam to string | Address | { user: AddressParam } (and likewise for token). Adds API surface; only worth it if there's a real caller asking for it.

Acceptance criteria

  • No unused actualUser / actualToken locals.
  • JSDoc matches the type signature.
  • Behaviour against the existing test suite is unchanged for the string | Address input form.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Stellar WaveIssues in the Stellar wave programbugSomething isn't workingdifficulty: easySmall, bounded changessdkIssues related to the SDK package

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions