feat(userflags): surface the username minimum balance flag - #1322
Merged
Conversation
Adds UserFlags.username_min_balance, the USDF amount in quarks a user must hold across all currencies before setting a username. Vendored from flipcash2-protobuf-api at HEAD; opencode was already current.
Maps UserFlags.username_min_balance through to the domain model and the debug flag editor as a read-only entry. It gates the username claim flow added in #1320, which has no UI yet, so nothing reads it so far. The default is Fiat.Zero rather than Fiat.MAX_VALUE. This is a minimum balance to hold, like minimumHolderValue, not a price to pay like newCurrencyPurchaseAmount. An absent flag should leave the gate open and let the server answer with INSUFFICIENT_BALANCE, not hard-block a claim the server would have allowed. CachedFlags also carries the field, since its toDomain() reconstructs the whole UserFlags. It defaults to zero quarks so payloads cached before this change still decode -- UserFlagsCoordinator drops the entire cached flag set when decodeFromString fails, so an undefaulted field would blank the flags on the first launch after upgrade. ReadOnlyEntry holds a Boolean, so the amount goes in readOnlyTextEntries formatted with Fiat.FormattingRule.Truncated, matching WithdrawalFeeAmount.
bmc08gt
added a commit
that referenced
this pull request
Aug 25, 2026
) `usernameMinBalance` landed on UserFlags in #1322 without a default, so the test fixture no longer compiles and every PR against code/cash fails: ResolvedUserFlagsTest.kt:140:5 No value passed for parameter 'usernameMinBalance' The flag resolves with FieldOverride.None, so it needs no OverrideCase — only the fixture value and the assertion the first test's name already promises.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
UserFlagsgainedusername_min_balanceupstream — the USDF amount, in quarks, a user must hold across all currencies before setting a username. This vendors the proto change and maps the field through to the domain model and the debug flag editor.It gates the username claim flow whose service layer landed in #1320. That flow has no UI yet, so nothing reads this value so far.
Read-only, not overridable
Every other
Fiatflag is overridable in the debug editor; this one isn't. The practical cost: exercising the claim gate locally means having the server send a non-zero value, since you can't force one from the editor.ReadOnlyEntryholds aBoolean, so the amount goes inreadOnlyTextEntriesnext totipPresets, formatted withFiat.FormattingRule.Truncatedto match howWithdrawalFeeAmountrenders.Default is
Fiat.ZeroThe fee and price flags (
newCurrencyPurchaseAmount,newCurrencyFeeAmount) default toFiat.MAX_VALUE— for an amount the user pays, an unknown value should fail closed. This one is a minimum balance to hold, the same shape asminimumHolderValue, so it takes that flag'sFiat.Zerodefault instead.Zero means an absent flag leaves the gate open and the server's
INSUFFICIENT_BALANCEresult stays the real enforcement, rather than hard-blocking a claim the server would have allowed. The tradeoff to be aware of: a silent mapping failure would look identical to "no gate configured."The resemblance to
minimumHolderValuestops at the default.minimumHolderValueis a per-mint threshold —TokenDiscoveryViewModelchecks it against one token's balance — whereasusername_min_balanceis cumulative across every mint. Whoever writes the claim gate should compare it against the summed balance (LocalFiat.underlyingTokenAmount), not a single token's. The domain property carries that note in a comment.CachedFlagsneeded the field tooUserFlagsCoordinatorholds a@Serializablecache model whosetoDomain()reconstructs the wholeUserFlags, so it doesn't compile without the new field. It defaults to zero quarks so payloads cached before this change still decode — the read path doesrunCatching { json.decodeFromString<CachedFlags>(raw) }.getOrNull() ?: return, which discards the entire cached flag set on a decode failure. An undefaulted field would blank the flags on the first launch after upgrade.