Skip to content

fix(cli): resolve transfer struct via action type in sync-accounts (get_tokens missing balances)#170

Merged
igorls merged 2 commits into
devfrom
fix/sync-accounts-token-detection
May 29, 2026
Merged

fix(cli): resolve transfer struct via action type in sync-accounts (get_tokens missing balances)#170
igorls merged 2 commits into
devfrom
fix/sync-accounts-token-detection

Conversation

@igorls
Copy link
Copy Markdown
Member

@igorls igorls commented May 29, 2026

Problem

Operators report /v2/state/get_tokens returning an incomplete token list after upgrading (e.g. bu.klnk shows 13/37 tokens), with the tell-tale symptom that some symbols of the same contract show while others are missing.

Root cause

AccountSynchronizer.scanABIs() decides whether a contract is a token contract before backfilling balances. It looked up the transfer parameter struct by the hard-coded struct name "transfer":

const transferType = abi.abi?.structs?.find(s => s.name === 'transfer');

Per the ABI spec, the struct backing an action is named by the action's type field, which is frequently not the action name. Several real token contracts declare a fully standard transfer (from:name, to:name, quantity:asset, memo:string) under a differently-named struct — e.g. the paycash contracts use transfer_token. For those, the lookup returned undefined, the field validation never ran, and the contract was silently skipped → its balances were never backfilled into the MongoDB accounts collection.

The live indexer's *:accounts handler has no such requirement, so it captured whatever balances changed post-upgrade — hence "same contract, some symbols present, some missing."

Fix

Resolve the transfer struct through the transfer action's declared type, and guard against short field arrays.

Verification (against api.eosrio.io)

Applying the old vs new detection to the contracts held by bu.klnk + a sample from eosriobrazil:

  • current: accepts 12/22
  • fixed: accepts 22/22
  • recovered (current SKIP → now accept): cashescashes, token.pcash, swap.pcash, jqpua4jqkqwz, testnewswap1, testrenminbi, testrublesrb, testuralsurl, uralsuralsru, testusdbxusd

All recovered contracts have accounts+stat tables, an accounts row of balance:asset, and a transfer action whose transfer_token struct is exactly from,to,quantity,memo. Standard-transfer contracts are unaffected. tsc --noEmit passes.

Operator action after merge

Pull, rebuild, then re-run ./hyp-control sync accounts <chain> (or sync all <chain>) to backfill the previously skipped contracts.

scanABIs() looked up a contract's transfer parameter struct by the
hard-coded name "transfer". Per the ABI spec the struct backing an
action is named by the action's `type` field, which is frequently not
the action name (e.g. paycash contracts declare a standard transfer
under the struct "transfer_token"). The lookup returned undefined, so
those valid token contracts were silently skipped and never backfilled
into the MongoDB accounts collection. get_tokens then returned only the
symbols the live indexer captured, giving "same contract, some symbols
missing" on upgraded nodes.

Resolve the struct through the transfer action's declared type, and
guard against short field arrays. Verified against api.eosrio.io: the
10 previously-skipped contracts held by bu.klnk (token.pcash,
cashescashes, swap.pcash, jqpua4jqkqwz, testnewswap1, testrenminbi,
testrublesrb, testuralsurl, uralsuralsru, testusdbxusd) are now
accepted, with no change to standard-transfer contracts.
Copy link
Copy Markdown

@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 fixes an issue where token contracts were skipped during account synchronization by resolving the transfer parameter struct using the action's declared type instead of a hard-coded name. It also adds safety checks to prevent out-of-bounds errors when validating fields. The reviewer suggested a code improvement to simplify and secure the field validation check by directly comparing the field name with the expected name.

Comment thread src/cli/sync-modules/sync-accounts.ts Outdated
Comment on lines 85 to 88
if (fields[i] && (fields[i].name === "from" || fields[i].name === "to") && fields[i].type === 'account_name') {
valid = true;
continue;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The current check allows any field at index i to be accepted as valid if its name is either "from" or "to" and its type is "account_name", regardless of whether the index matches the expected field name (e.g., if from and to are swapped, or if a different field is named "from").

Since transferFields[i].name already contains the expected name ("from" at index 0, "to" at index 1), we can simplify and secure this check by verifying that fields[i].name matches transferFields[i].name directly.

Suggested change
if (fields[i] && (fields[i].name === "from" || fields[i].name === "to") && fields[i].type === 'account_name') {
valid = true;
continue;
}
if (fields[i] && fields[i].name === transferFields[i].name && fields[i].type === 'account_name') {
valid = true;
continue;
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good catch — applied in 584db2b. Matching transferFields[i].name positionally (consistent with the standard-type branch). Verified no behavior change for real contracts (still 22/22 accepted against api.eosrio.io); it only rejects malformed/swapped ABIs.

Address Gemini review on #170: the account_name legacy branch accepted
any field named from/to regardless of position. Match transferFields[i].name
positionally, consistent with the standard-type branch below it. No change
for real contracts (verified 22/22 still accepted); only tightens malformed/
swapped ABIs.
@igorls igorls merged commit b8ba9fc into dev May 29, 2026
2 checks passed
@igorls igorls deleted the fix/sync-accounts-token-detection branch May 29, 2026 06:52
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.

1 participant