Repository navigation
feat(badges): add key NFT badge minting trigger service (#1148) - #1185
Merged
Chucks1093 merged 1 commit intoOct 21, 2026
Merged
Conversation
…rg#1148) Awards key NFT badges automatically from qualifying on-chain activity, routed through the centralised Soroban contract service so retry, transaction tracking, and resolution events apply uniformly. - Triggers: first swap (FIRST_BUYER), whale swap (WHALE_HOLDER), governance vote (GOVERNANCE_VOTER), 365d hold (DIAMOND_HANDS), top-10 leaderboard (TOP_TRADER) - Deduplication guard via unique (wallet, badgeType) on badge_mint_log - Retry on transient mint failures; user-kind failures are terminal - Every attempt persisted to badge_mint_log for audit - Config thresholds + docs; mint_badge added to ContractOperation
|
@CHKM001 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.
PR #1148 feat(badges): add key NFT badge minting trigger service
Summary
Adds a service that automatically awards key NFT badges when a wallet performs
qualifying on-chain activity. All minting is routed through the centralised
Soroban Contract Service, so submission
retries, transaction tracking, and resolution events are applied uniformly —
the service does not re-implement any of that.
The design mirrors the existing
campaignsmodule (server-submitted contractcall + a deduplicating audit log), keeping it consistent with established repo
conventions.
Closes #1148.
Badges and triggers
FIRST_BUYERfirst_swapWHALE_HOLDERwhale_swapBADGE_WHALE_THRESHOLD_XLM(10,000).GOVERNANCE_VOTERvote_castDIAMOND_HANDShold_milestoneBADGE_HOLD_MILESTONE_DAYS(365).TOP_TRADERleaderboard_entryBADGE_TOP_TRADER_MAX_RANK(10).A single swap can earn both
FIRST_BUYERandWHALE_HOLDER.What's included
badge-trigger.service.ts) —evaluateEvent(purequalification rules) +
processQualifyingEvent(dispatch to minting).badge-mint.service.ts) —mintBadge: deduplication guard→ mint with retry → audit log, all dependencies injectable.
badge-mint.client.ts) — submitsmint_badgethroughthe shared contract service; translates failures into retry-classifiable
errors.
badge-mint.builder.ts) — builds + signs themint_badge(wallet, badge_type)envelope with the server minter key.BadgeMintLogPrisma model + migration (audit table / dedup backing).mint_badgeadded toContractOperation.README.
How it meets the acceptance criteria
FIRST_BUYER— covered by trigger tests.WHALE_HOLDER— covered by trigger tests.GOVERNANCE_VOTER— covered by trigger tests.(wallet, badgeType)onbadge_mint_log;mintBadgereturnsSKIPPEDfor an already-minted badgewith no contract call. Covered by tests.
BADGE_MINT_MAX_ATTEMPTSwith linear backoff; user-kind failures areterminal. Covered by tests.
Deduplication & retry details
badge_mint_logkeeps one row per(wallet, badgeType). Reprocessing thesame (or an overlapping) event never re-mints. A row left
FAILEDby anexhausted retry is eligible to be re-attempted on the next event.
mintBadgeretriesthe whole mint on transient outcomes (RPC down / timeout / unconfirmed). Final
attempt count and last error are persisted on the log row.
Configuration
Minting stays disabled until both
BADGE_CONTRACT_IDandBADGE_MINTER_SECRETare set (fail-safe, consistent with other contractadapters). Thresholds are overridable:
Integration point
Indexer / webhook consumers call
processQualifyingEventas activity isobserved:
Wiring this entry point into the live swap/governance/indexer emitters is
intentionally left as a follow-up so this PR stays within scope; the service
exposes a clean, tested entry point for it.
Testing
pnpm lint— cleanpnpm build(tsc) — cleanpnpm exec jest src/modules/badges src/modules/contracts— 57 passed(18 new badge tests + 39 existing contract tests)
Notes for reviewers
other Soroban builders (dividends/claims). If a deployment requires footprint
simulation before submit, that belongs in the shared contract pipeline rather
than this module.
cumulative holdings instead, the rule in
evaluateEventis the single place tochange.
Closes #1148