Fix referral TTL squatting, tier downgrade reversion, and impact - #493
Merged
abayomicornelius merged 1 commit intoJul 25, 2026
Conversation
…ding - referral_storage: add self-service renew_code so a code owner can keep their CodeOwner entry's TTL alive without depending on trader activity, closing the window where a dormant code's TTL lapses and a different address can register the same code string and inherit any trader still linked to it. - referral_storage: add admin-only set_referrer_volume so a manual set_referrer_tier downgrade can be paired with a volume reset, since increment_referrer_volume's auto-upgrade otherwise re-evaluates the unchanged, still-large cumulative volume on the next trade and silently reverts the downgrade. - pricing_utils: round the token-unit conversion of a negative price impact (a charge) up in magnitude instead of down, matching how fee amounts round up elsewhere so the protocol never under-collects. apply_swap_impact_value, apply_position_impact_value, and the inline conversion in get_swap_output_amount now share one conversion helper that floors payouts and ceils charges. - docs/ttl-strategy.md: correct the blanket "persistent storage is never extend_ttl'd" claim — order_handler, data_store's bytes32-set helpers, and referral_storage all call it on specific keys — and precisely list which related keys in those same contracts still aren't covered.
|
@vjuliaife Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
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.
Closes #445
Closes #444
Closes #455
Closes #460
Summary
Fixes three logic bugs and one stale-documentation issue in
referral_storageand
pricing_utils.#445 — referral code squatting after TTL expiry
register_codeonly guards against duplicate registration by checkingwhether the
CodeOwnerpersistent entry currently exists. That entry's TTLis only bumped as a side effect of trader activity, and there was no way for
an owner to renew it directly. A code nobody trades through can therefore run
out its TTL; once archived,
register_codereads it as "unregistered" and adifferent address can claim the same code string, silently inheriting any
trader still linked to it via a live
TraderCodeentry.Added a self-service
renew_code(caller, code)entrypoint: the current owner(verified via
require_auth+ an explicit ownership check) can extend theCodeOwnerTTL at any time, independent of trader activity.#444 — tier auto-upgrade reverts manual admin downgrades
increment_referrer_volumerecomputes a referrer's tier purely from lifetimecumulative volume, which only ever grows. If an admin manually lowers a
referrer's tier via
set_referrer_tier, the next trade re-evaluates theunchanged, still-large volume against the thresholds and silently upgrades
the referrer right back — there was no way to make a downgrade durable.
Added an admin-only
set_referrer_volume(admin, referrer, volume_usd)so amanual tier downgrade can be paired with a volume reset, consistent with the
existing volume-driven auto-upgrade model.
#455 — negative price impact under-charged by floor rounding
apply_swap_impact_value,apply_position_impact_value, and the inlineimpact conversion in
get_swap_output_amountconverted signed USD priceimpact to token units with
mul_div_wide, which truncates toward zero forboth signs. For a positive impact (a payout) that's correct — it should
floor. For a negative impact (a charge), truncating toward zero also rounds
the charge down, so the protocol collected strictly less than owed on
almost every negative-impact swap/position adjustment.
All three call sites now go through one
convert_impact_usd_to_tokenshelper that floors payouts and takes the ceiling of the magnitude for
charges (mirroring how fee amounts already round up via
mul_div_wide_up),so the charge is never under-collected.
#460 — TTL strategy doc claimed persistent storage is never extended
docs/ttl-strategy.mdclaimed, in several places, that no contract in theworkspace ever calls
extend_ttlon persistent storage. That's false:order_handler,data_store's bytes32-set index helpers, andreferral_storageall do, on specific keys. Rewrote the current-statewarning, the persistent-tier table row, the bump-policy section, and the
"Current gaps" list to precisely state which keys in each of those three
contracts are covered and which related keys (e.g. the
Positionentryitself,
transfer_code_ownership'sCodeOwnerwrite,data_store'sAddrSethelpers and scalar accounting) are not — so the gap is preciseinstead of blanket.
Changes
contracts/referral_storage/src/lib.rs—renew_code,set_referrer_volume, and testslibs/pricing_utils/src/lib.rs—convert_impact_usd_to_tokenshelper, applied at all threeimpact-conversion call sites
docs/ttl-strategy.md— corrected TTL coverage claimsTest plan
renew_code(owner succeeds, non-owner rejected, unregistered coderejected)
pricing_utilstests re-verified by hand against the new rounding (fixturesdivide evenly, so behavior is unchanged for those cases)
cargo test -p gmx-pricing-utils -p referral-storage(run locally before merge)