Skip to content

fix(accounts): provision USDF core account for fresh onboards even with a stale cache - #1158

Merged
bmc08gt merged 1 commit into
code/cashfrom
fix/core-account-onboarding-provisioning
Jul 27, 2026
Merged

fix(accounts): provision USDF core account for fresh onboards even with a stale cache#1158
bmc08gt merged 1 commit into
code/cashfrom
fix/core-account-onboarding-provisioning

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Problem

Sending a tip to a freshly-onboarded account failed on both Android and iOS with the server error:

payments to external destinations must be withdrawals

The failure was recipient-specific ("works for some users"), cross-platform, and — tellingly — killing and relaunching the receiver's app fixed it.

Root cause

The tip send path is a legitimate direct send; the OCP server auto-opens the recipient's currency destination (detectAutoOpenPrimaryAccount) only if it recognizes the recipient as an OCP user, which it does purely by the presence of a USDF core-mint PRIMARY (ocp-server owner.go).

On the client, AccountController.ensureCoreAccount (the onboarding gate that's supposed to guarantee that primary) short-circuited on the in-memory accounts cache. That cache still held the previous account's USDF primary after a logout → re-onboard in the same process, so the gate logged USDF core account already present and provisioned nothing — releasing a fresh account to the scanner with no core account server-side (getAccounts returned NOT_FOUND for the new owner). Only a process restart cleared the cache, which is why relaunch "fixed" it.

On-device logs (receiver, fresh onboard, same PID — no relaunch):

[Onboarding] : Access key seen
[Onboarding] : USDF core account already present   <- short-circuited on stale cache
[Onboarding] : releasing to scanner
[RpcLogging] : GetTokenAccountInfosResponse { result=1 }   <- NOT_FOUND for the new owner

Fix

  • ensureCoreAccount is now server-authoritative — it always confirms the current owner via getAccounts instead of trusting the local cache, and provisions the USDF primary when absent (checking account type, not just mint), tolerating a race with the reactive account bootstrap.
  • onUserLoggedIn clears the cached account list when the account changes, preventing cross-account bleed into all consumers (balances, hasAccountFor, and the onboarding gate).

Tests

AccountControllerTest (8 passing), including new regression coverage:

  • ensureCoreAccount ignores a stale cached USDF primary from a prior account
  • onUserLoggedIn clears cached accounts when the account changes
  • plus success-without-primary / empty / concurrent-open cases.

Verification

Verified on-device: a freshly-onboarded receiver now provisions its USDF core account during onboarding (Provisioning USDF core account (onboarding gate) + an OpenAccountAction for the USDF mint), and receives a direct-send tip on the first attempt with no relaunch.

…th a stale cache

ensureCoreAccount gated onboarding on the in-memory `accounts` cache, which can
still hold a prior account's USDF core-mint primary after a logout -> re-onboard
(or account switch) in the same process. The gate then reported "already present"
and released a freshly-onboarded account to the scanner with no core account
server-side, so it could not receive a direct-send tip until a process restart
cleared the cache — both Android and iOS senders saw "payments to external
destinations must be withdrawals".

- ensureCoreAccount is now server-authoritative: it always confirms the current
  owner via getAccounts and provisions the USDF primary when absent (checking
  account TYPE, not just mint), tolerating a race with the reactive bootstrap.
- onUserLoggedIn clears the cached account list when the account changes, so no
  prior account's accounts bleed into a new one.

Adds AccountControllerTest coverage for the stale-cache and account-switch cases.
@github-actions github-actions Bot added area: network gRPC, connectivity, API, exchange rates type: fix Bug fix labels Jul 27, 2026
@bmc08gt
bmc08gt merged commit cfdcd56 into code/cash Jul 27, 2026
3 checks passed
@bmc08gt
bmc08gt deleted the fix/core-account-onboarding-provisioning branch July 27, 2026 17:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: network gRPC, connectivity, API, exchange rates type: fix Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant