@ballkidz/defifa 0.0.21 → 0.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,44 +1,79 @@
1
1
  # Defifa
2
2
 
3
- Defifa is an on-chain prediction game system built on Juicebox. Players mint NFT game pieces, scorecards determine how the pot is distributed, and winners cash out by burning the NFTs that backed their position.
3
+ Defifa is an onchain prediction game system built on Juicebox. Each game is a Juicebox project with staged rulesets, tiered NFT game pieces, scorecard governance, and a final settlement path that turns the project's surplus into winner payouts.
4
4
 
5
- Architecture: [ARCHITECTURE.md](./ARCHITECTURE.md)
5
+ Use this repo when the question is about game lifecycle, scorecard ratification, attestation power, or Defifa-specific settlement behavior. Do not start here for generic project accounting, terminal behavior, or standard 721-tier mechanics.
6
6
 
7
- ## Overview
7
+ Architecture: [ARCHITECTURE.md](./ARCHITECTURE.md)
8
+ User journeys: [USER_JOURNEYS.md](./USER_JOURNEYS.md)
9
+ Skills: [SKILLS.md](./SKILLS.md)
10
+ Risks: [RISKS.md](./RISKS.md)
11
+ Administration: [ADMINISTRATION.md](./ADMINISTRATION.md)
12
+ Audit instructions: [AUDIT_INSTRUCTIONS.md](./AUDIT_INSTRUCTIONS.md)
8
13
 
9
- Each Defifa game is a Juicebox project with a staged lifecycle:
14
+ ## What This Repo Owns
15
+
16
+ Defifa adds game-specific behavior on top of Juicebox and the 721 hook stack:
17
+
18
+ - phased game launch and completion packaging in `DefifaDeployer`
19
+ - game-piece behavior, delegation, and settlement weighting in `DefifaHook`
20
+ - scorecard submission, attestation, quorum, grace periods, and ratification in `DefifaGovernor`
21
+ - onchain card rendering and token metadata in `DefifaTokenUriResolver`
22
+
23
+ This repo does not own:
24
+
25
+ - canonical terminal accounting or surplus math
26
+ - generic 721 tier storage and most shared NFT-hook machinery
27
+ - generic Juicebox permission, project, or ruleset semantics
28
+
29
+ ## Mental Model
30
+
31
+ Defifa is easiest to read as one state machine split across three contracts:
32
+
33
+ 1. `DefifaDeployer` launches the game and wires the components together
34
+ 2. `DefifaGovernor` decides which scorecard, if any, becomes final
35
+ 3. `DefifaHook` converts that ratified result into cash-out weights for game-piece holders
10
36
 
11
- - countdown before minting opens
12
- - mint phase where players buy outcome NFTs
13
- - optional refund window
14
- - scoring phase where holders attest to scorecards
15
- - completion or no-contest settlement
37
+ Most real issues live at the seams between those contracts.
16
38
 
17
- The project's surplus is the prize pot. Once a scorecard reaches quorum and survives its grace period, the hook updates cash-out weights so players can redeem winning pieces for their share.
39
+ ## Read These Files First
18
40
 
19
- Use this repo when you want a full game system with lifecycle, governance, and settlement. Do not treat it as a generic tournament payout primitive; its assumptions are Defifa-specific.
41
+ 1. [`src/DefifaDeployer.sol`](./src/DefifaDeployer.sol)
42
+ 2. [`src/DefifaHook.sol`](./src/DefifaHook.sol)
43
+ 3. [`src/DefifaGovernor.sol`](./src/DefifaGovernor.sol)
44
+ 4. [`src/libraries/DefifaHookLib.sol`](./src/libraries/DefifaHookLib.sol)
45
+ 5. [`test/DefifaGovernor.t.sol`](./test/DefifaGovernor.t.sol)
46
+ 6. [`test/DefifaFeeAccounting.t.sol`](./test/DefifaFeeAccounting.t.sol)
47
+ 7. [`test/DefifaNoContest.t.sol`](./test/DefifaNoContest.t.sol)
20
48
 
21
- If the issue is basic NFT issuance, project accounting, or generic governance plumbing, start in the underlying protocol repos first. Defifa is where the game-specific lifecycle and settlement assumptions get introduced.
49
+ Then read the upstream repos this package depends on:
50
+
51
+ - [`../nana-721-hook-v6/README.md`](../nana-721-hook-v6/README.md)
52
+ - [`../nana-core-v6/README.md`](../nana-core-v6/README.md)
22
53
 
23
54
  ## Key Contracts
24
55
 
25
56
  | Contract | Role |
26
57
  | --- | --- |
27
58
  | `DefifaDeployer` | Launches games, clones hooks, initializes governance, and fulfills post-game fee commitments. |
28
- | `DefifaHook` | ERC-721 game piece hook that tracks tiers, delegation, and cash-out weights for settlement. |
29
- | `DefifaGovernor` | Scorecard governance surface that accepts submissions, attestations, and ratification. |
30
- | `DefifaTokenUriResolver` | On-chain metadata renderer for game cards. |
31
- | `DefifaProjectOwner` | Ownership helper for the Defifa fee project. |
59
+ | `DefifaHook` | ERC-721 game-piece hook that tracks tiers, delegation, pending reserves, and cash-out weights for settlement. |
60
+ | `DefifaGovernor` | Scorecard governance surface that accepts submissions, attestations, quorum checks, grace periods, and ratification. |
61
+ | `DefifaHookLib` | Shared validation and weight logic extracted from the hook. |
62
+ | `DefifaTokenUriResolver` | Onchain metadata renderer for game cards. |
63
+ | `DefifaProjectOwner` | Ownership sink used for the fee-project surface. |
32
64
 
33
- ## Mental Model
65
+ ## Lifecycle
34
66
 
35
- Defifa is easiest to read as three layers:
67
+ Each Defifa game is a Juicebox project with a staged lifecycle:
36
68
 
37
- 1. launch and lifecycle packaging in `DefifaDeployer`
38
- 2. player position and settlement state in `DefifaHook`
39
- 3. scorecard selection in `DefifaGovernor`
69
+ 1. countdown before minting opens
70
+ 2. mint phase where players buy outcome NFTs
71
+ 3. optional refund or no-contest handling if the game cannot settle normally
72
+ 4. scoring phase where participants submit and attest to scorecards
73
+ 5. completion after a scorecard reaches quorum and survives its grace period
74
+ 6. final cash out where winning pieces redeem against the prize pot
40
75
 
41
- Most system-level issues come from how those layers interact, not from one layer in isolation.
76
+ The important boundary is that the pot is still ordinary Juicebox project value until governance ratifies a scorecard. Defifa-specific settlement starts only when the governor installs final cash-out weights on the hook.
42
77
 
43
78
  ## Install
44
79
 
@@ -59,10 +94,6 @@ Useful scripts:
59
94
  - `npm run deploy:mainnets`
60
95
  - `npm run deploy:testnets`
61
96
 
62
- ## Deployment Notes
63
-
64
- Deployments are handled through Sphinx. The system composes Juicebox core, the 721 hook stack, and Defifa-specific governance and resolver contracts into a single game-launch surface.
65
-
66
97
  ## Repository Layout
67
98
 
68
99
  ```text
@@ -77,15 +108,49 @@ src/
77
108
  libraries/
78
109
  structs/
79
110
  test/
80
- lifecycle, fee, governance, invariant, fork, audit, and regression coverage
111
+ governance, fee-accounting, no-contest, adversarial, regression, fork, and audit coverage
81
112
  script/
82
113
  Deploy.s.sol
83
114
  helpers/
115
+ references/
116
+ operations.md
117
+ runtime.md
84
118
  ```
85
119
 
86
- ## Risks And Notes
120
+ ## Integration Traps
121
+
122
+ - Defifa is not a generic tournament payout primitive
123
+ - `DefifaGovernor` and `DefifaHook` must be read together
124
+ - fee accounting and prize accounting are coupled
125
+ - a timeout into `NO_CONTEST` is a real terminal state
126
+ - the shared `JB721TiersHookStore` surface is an upstream ecosystem dependency, not a Defifa-only detail
127
+
128
+ ## High-Signal Tests
129
+
130
+ - [`test/DefifaGovernor.t.sol`](./test/DefifaGovernor.t.sol)
131
+ - [`test/DefifaGovernanceHardening.t.sol`](./test/DefifaGovernanceHardening.t.sol)
132
+ - [`test/DefifaFeeAccounting.t.sol`](./test/DefifaFeeAccounting.t.sol)
133
+ - [`test/DefifaNoContest.t.sol`](./test/DefifaNoContest.t.sol)
134
+ - [`test/DefifaAdversarialQuorum.t.sol`](./test/DefifaAdversarialQuorum.t.sol)
135
+ - [`test/audit/PendingReserveDilution.t.sol`](./test/audit/PendingReserveDilution.t.sol)
136
+ - [`test/audit/AttestationDoubleCount.t.sol`](./test/audit/AttestationDoubleCount.t.sol)
137
+ - [`test/regression/GracePeriodBypass.t.sol`](./test/regression/GracePeriodBypass.t.sol)
138
+
139
+ ## Deployment Notes
140
+
141
+ Deployments are handled through Sphinx. The deployer composes Juicebox core, the 721 hook stack, Defifa-specific governance, and metadata rendering into one game-launch surface.
142
+
143
+ ## Where State Lives
144
+
145
+ - game lifecycle config and post-game fulfillment bookkeeping: `DefifaDeployer`
146
+ - submitted scorecards, attestations, quorum state, and ratification timing: `DefifaGovernor`
147
+ - tier state, delegation, pending reserve awareness, and final cash-out weights: `DefifaHook`
148
+ - base project balance and terminal settlement: `nana-core-v6`
149
+ - shared 721 tier store semantics: `nana-721-hook-v6`
150
+
151
+ ## For AI Agents
87
152
 
88
- - scorecard governance quality depends on quorum, grace period, and participation assumptions set at launch
89
- - optional refund windows and no-contest thresholds materially change game economics
90
- - settlement is only as good as the ratified scorecard; bad governance configuration can still produce bad outcomes
91
- - fee-accounting and pending-reserve edge cases are heavily tested because they are easy places for pot dilution or griefing
153
+ - Treat Defifa as a game-specific layer on top of `nana-core-v6` and `nana-721-hook-v6`, not as a standalone accounting system.
154
+ - Use `DefifaDeployer`, `DefifaHook`, and `DefifaGovernor` as the primary execution surfaces.
155
+ - Treat `NO_CONTEST`, refund handling, and grace-period logic as normal product behavior.
156
+ - If the question is about generic tier storage, terminal settlement, or project accounting, hand off to upstream repos first.
package/RISKS.md CHANGED
@@ -4,7 +4,7 @@ This file focuses on the game-theoretic, governance, and settlement risks in Def
4
4
 
5
5
  ## How to use this file
6
6
 
7
- - Read `Priority risks` first; they identify the main ways a game can settle unfairly or get stuck.
7
+ - Read `Priority risks` first.
8
8
  - Use the detailed sections below to reason about governor power, live supply assumptions, and downstream hook dependencies.
9
9
  - Treat `Accepted Behaviors` and `Invariants to Verify` as explicit boundaries for audit scope.
10
10
 
@@ -12,87 +12,78 @@ This file focuses on the game-theoretic, governance, and settlement risks in Def
12
12
 
13
13
  | Priority | Risk | Why it matters | Primary controls |
14
14
  |----------|------|----------------|------------------|
15
- | P0 | Scorecard capture at quorum | An actor that assembles 50%+ of attestation power can ratify an arbitrary scorecard and redirect the pot. | Tier-level attestation caps, grace period, and governance review of delegate concentration. |
16
- | P1 | Shared 721 hook store blast radius | Defifa inherits the same shared `JB721TiersHookStore` surface as the general 721 hook ecosystem. A store bug hits every game. | Reuse of audited 721-hook invariants, store-focused testing, and ecosystem-level monitoring. |
17
- | P1 | Supply and reserve accounting drift | Game fairness depends on attestation power, fee-token dilution, and cash-out weights tracking real mint/reserve state. | Explicit invariants on supply, reserve inclusion, and tier-weight arithmetic. |
18
-
15
+ | P0 | Scorecard capture at quorum | An actor that assembles enough attestation power can ratify an arbitrary scorecard and redirect the pot. | Tier-level attestation caps, grace period, and governance review of delegate concentration. |
16
+ | P1 | Shared 721-hook store blast radius | Defifa inherits the same shared `JB721TiersHookStore` surface as the general 721-hook ecosystem. | Reuse of 721-hook invariants, store-focused testing, and ecosystem-level monitoring. |
17
+ | P1 | Supply and reserve accounting drift | Game fairness depends on attestation power, fee-token dilution, and cash-out weights tracking real mint and reserve state. | Explicit invariants on supply, reserve inclusion, and tier-weight arithmetic. |
19
18
 
20
19
  ## 1. Trust Assumptions
21
20
 
22
- - **Governor as Hook Owner.** The DefifaGovernor owns each DefifaHook clone. The governor can set tier cash-out weights via `ratifyScorecardFrom`, which executes an arbitrary call to the hook. If the governor is compromised, the hook's cash-out weights can be set to any values.
23
- - **Deployer as Project Owner.** The DefifaDeployer contract owns all game projects. It controls ruleset queuing, payout sending, and split configuration. Its logic is immutable (no upgradability), so the trust boundary is the contract code itself.
24
- - **DefifaProjectOwner Irrecoverability.** Once the Defifa project NFT is transferred to DefifaProjectOwner, it cannot be recovered. This is intentional but irreversible.
25
- - **External Dependencies.** Relies on JB721TiersHookStore, JBController, JBMultiTerminal, JBRulesets, and JBPrices. Bugs in any upstream contract affect all Defifa games.
26
- - **Default Attestation Delegate.** If set, the default attestation delegate receives delegated attestation power for all new minters who do not specify a delegate. This entity accumulates significant governance power.
27
- - **721 hook store shared with nana-721-hook-v6.** `DefifaHook` uses the same `JB721TiersHookStore` dependency as the broader 721-hook ecosystem even though it has its own hook implementation. All store-level risks from [nana-721-hook-v6 RISKS.md](../nana-721-hook-v6/RISKS.md) still apply wherever Defifa relies on shared tier-store semantics. Store bugs affect all Defifa games simultaneously.
21
+ - **Governor as hook owner.** The governor can set tier cash-out weights through ratification.
22
+ - **Deployer as project owner.** The deployer owns game projects and controls ruleset queuing and commitment fulfillment.
23
+ - **DefifaProjectOwner irrecoverability.** Once the project NFT is transferred there, it cannot be recovered.
24
+ - **External dependencies.** Core protocol and shared 721-store behavior remain upstream trust boundaries.
25
+ - **Default attestation delegate.** If set, it can accumulate meaningful governance power across new minters.
28
26
 
29
27
  ## 2. Economic Risks
30
28
 
31
- - **Scorecard manipulation via 50% quorum.** A single entity that acquires 50%+ of attestation power across tiers can unilaterally ratify any scorecard, directing the entire pot to chosen tiers. Per-tier cap at `MAX_ATTESTATION_POWER_TIER` limits single-tier dominance. 1-day minimum grace period gives counter-attestors time to respond.
32
- - **Dynamic quorum from live supply (mitigated).** `quorum()` counts tiers with circulating supply (`currentSupplyOfTier > 0`) OR pending reserves (`numberOfPendingReservesFor > 0`). No snapshot is needed because during SCORING, supply is frozen (no new paid mints, no burns) and reserve minting doesn't change which tiers are counted — tiers with pending reserves are already included. Pending reserves also dilute attestation power — `getAttestationWeight` includes them in the denominator so every token holder's voting power already accounts for reserves that will eventually be minted. When the reserve beneficiary mints later, power redistributes smoothly (no shift). Consistent with the cash-out path which also dilutes by pending reserves.
33
- - **Cash-out weight integer division truncation.** `_weight / _totalTokensForCashoutInTier` rounds down, permanently locking dust in the contract. Maximum loss: 1 wei per tier per game (128 wei max with 128 tiers).
34
- - **Fee token dilution from reserved mints.** Reserved mints increment `_totalMintCost` by `tier.price * count` even though no ETH was paid. This dilutes paid minters' share of fee tokens (`$DEFIFA` / `$NANA`). Example: if 1000 NFTs are minted by payers (paying 1 ETH each = 1000 ETH total), and 100 reserved NFTs are minted (adding 100 ETH to `_totalMintCost` with no ETH deposited), fee token claims are diluted by ~9.1% (100/1100). The dilution is bounded by the reserve frequency — at `reserveFrequency=10`, every 10th mint is a reserve, capping dilution at ~10%.
35
- - **128-tier limit hard-coded.** `_tierCashOutWeights` is a fixed `uint256[128]` array. Games with more than 128 tiers have tiers beyond index 128 unable to receive cash-out weights.
29
+ - **Scorecard manipulation via quorum.** Enough attestation power can redirect the whole pot.
30
+ - **Supply and pending-reserve drift.** Governance and settlement both depend on correct reserve-aware denominators.
31
+ - **Cash-out-weight truncation.** Integer division can lock small dust amounts.
32
+ - **Fee-token dilution from reserved mints.** Reserved mints can dilute fee-token shares even though no ETH was paid for them.
33
+ - **128-tier settlement ceiling.** Games that rely on more than 128 scored tiers can fail settlement.
36
34
 
37
35
  ## 3. Governance Risks
38
36
 
39
- - **Single governor instance across all games.** All games share one DefifaGovernor. A bug in `ratifyScorecardFrom`, `attestToScorecardFrom`, or `submitScorecardFor` affects every game simultaneously.
40
- - **Scorecard timeout can block legitimate ratification.** If `scorecardTimeout` elapses before ratification, the game permanently enters NO_CONTEST. Even a scorecard that has reached quorum cannot be ratified. `triggerNoContestFor()` is permissionless and allows fund recovery.
41
- - **Delegation locked after MINT phase.** `setTierDelegateTo` only works during MINT phase. After MINT, NFT transfers auto-delegate to the recipient, but holders cannot explicitly re-delegate to a third party.
42
- - **No-contest requires explicit trigger.** In NO_CONTEST, users cannot immediately cash out -- someone must call `triggerNoContestFor()` to queue a refund ruleset. Without this trigger, the SCORING ruleset allocates the entire balance as payouts, leaving surplus at 0.
37
+ - **Single governor instance across games.** A bug in the governor affects every game that uses it.
38
+ - **Scorecard timeout can block legitimate ratification.** Once timeout is reached, the game may have to fall into no-contest even if a scorecard was close to success.
39
+ - **Delegation is phase-sensitive.** Some delegation behavior freezes after mint phase.
40
+ - **No-contest requires an explicit trigger.** The fallback path does not activate itself just because the timeout happened.
41
+ - **No-contest trigger is not the same as active refund state.** Integrators must distinguish queued recovery from currently active refund rules.
43
42
 
44
43
  ## 4. Reentrancy Surface
45
44
 
46
- - **afterCashOutRecordedWith.** Burns tokens before external calls. `_claimTokensFor` calls `safeTransfer` on ERC-20 tokens (DEFIFA_TOKEN, BASE_PROTOCOL_TOKEN). Preceding burn and state updates prevent meaningful reentrancy profit.
45
+ - **`afterCashOutRecordedWith`.** Burns happen before external fee-token transfers, which narrows the surface, but transfer compatibility still matters.
46
+ - **Ratification uses a low-level call into the hook.** Double-set protections must hold.
47
47
 
48
48
  ## 5. DoS Vectors
49
49
 
50
- - **Unbounded tier iteration in governance.** `getAttestationWeight` and `quorum` iterate over all tiers (`maxTierIdOf`). Gas cost: ~3-5k per tier (storage read + bitmap check). At 128 tiers (the hard cap), ~400-650k gas for a single `quorum()` call. At the block gas limit (30M), this is safe, but composing `quorum()` inside a larger transaction (e.g., `ratifyScorecardFrom`) adds the iteration cost on top of the ratification logic. Games should target <64 tiers for comfortable gas headroom.
51
- - **_buildSplits iteration.** Iterates over user-provided splits array. No explicit cap, but total percent constraint limits practical count.
50
+ - **Tier iteration in governance.** Quorum and attestation-weight calculations scale with tier count.
51
+ - **Large split arrays.** User-provided split arrays can increase gas and complexity even if practical counts stay bounded.
52
52
 
53
53
  ## 6. Integration Risks
54
54
 
55
- - **Immutable phase timing.** Game rulesets are queued at launch and progress automatically based on duration. Once deployed, phase timing cannot be changed.
56
- - **Permanent cash-out weights.** Cash-out weights are set once via the governor. There is no mechanism to correct a ratified scorecard.
57
- - **No deployer upgrade.** The deployer contract has no upgrade mechanism. Bugs require deploying a new deployer.
58
- - **Clone initialization.** Clones use `cloneDeterministic` with `msg.sender` + nonce in the salt. Salt includes `msg.sender`, preventing cross-caller collision. `initialize()` has a re-initialization guard.
55
+ - **Immutable phase timing.** Once deployed, the game timeline cannot be edited.
56
+ - **Permanent cash-out weights.** A ratified scorecard is final.
57
+ - **No deployer upgrade path.** Bugs require a new deployer, not an in-place fix.
58
+ - **Clone initialization assumptions matter.** Per-game clone setup must stay correct.
59
59
 
60
60
  ## 7. Invariants to Verify
61
61
 
62
- - `_totalMintCost == tierPrice * liveTokenCount` after every mint and burn.
63
- - Total cash-outs + remaining surplus == pre-fulfillment pot minus fees.
64
- - Scorecard weights sum to exactly `TOTAL_CASHOUT_WEIGHT` (1e18).
65
- - Attestation units are conserved across all transfers (no units lost to `address(0)`).
66
- - `fulfilledCommitmentsOf[gameId]` is set at most once per game.
62
+ - `_totalMintCost` stays consistent with live tier state and burns.
63
+ - Total cash-outs plus remaining surplus match the pre-fulfillment pot minus intended fees.
64
+ - Scorecard weights sum to `TOTAL_CASHOUT_WEIGHT`.
65
+ - Attestation units are conserved across transfers and delegation.
66
+ - `fulfilledCommitmentsOf[gameId]` is set at most once.
67
67
  - Per-tier supply never exceeds `initialSupply`.
68
- - Sum of all delegate attestation units equals total attestation supply.
69
68
 
70
69
  ## 8. Accepted Behaviors
71
70
 
72
71
  ### 8.1 Scorecard timeout is intentionally irreversible
73
72
 
74
- If `scorecardTimeout` elapses before ratification, the game permanently enters NO_CONTEST. Even a scorecard that has reached quorum cannot be ratified after timeout. This is accepted because: (1) allowing late ratification would keep player funds locked indefinitely while governance debates, (2) NO_CONTEST triggers a refund path (`triggerNoContestFor`) that returns funds pro-rata, and (3) the timeout creates a credible commitment to resolve the game within a bounded time. The timeout duration is set at deployment and cannot be changed.
75
-
76
- ### 8.2 Permanent cash-out weights (no correction mechanism)
77
-
78
- Cash-out weights set via `ratifyScorecardFrom` cannot be updated or corrected. This is accepted because: (1) allowing weight changes would introduce governance attack surfaces where a quorum re-ratifies to steal from other tiers, (2) the attestation process provides a dispute window (grace period) before ratification finalizes, and (3) the alternative (upgradeable weights) would undermine the trust-minimized game design. If a scorecard is wrong, the game should be allowed to timeout into NO_CONTEST for refunds.
79
-
80
- ### 8.3 fulfillCommitmentsOf reentrancy is guarded
81
-
82
- `fulfillCommitmentsOf` uses `fulfilledCommitmentsOf[gameId]` as a reentrancy guard (set before `sendPayoutsOf`). Returns early if already non-zero. Uses `max(feeAmount, 1)` to ensure the guard works even when pot rounds to 0. `sendPayoutsOf` is wrapped in try-catch: on failure, resets to sentinel (1) and emits `CommitmentPayoutFailed`, ensuring the final ruleset is always queued.
73
+ If timeout elapses before ratification, the game can permanently move toward `NO_CONTEST`. This bounds how long funds can remain locked in unresolved governance.
83
74
 
84
- ### 8.4 ratifyScorecardFrom reentrancy is double-guarded
75
+ ### 8.2 Permanent cash-out weights
85
76
 
86
- `ratifyScorecardFrom` executes arbitrary calldata on the hook via low-level call. The hook's `setTierCashOutWeightsTo` has an `onlyOwner` guard and a `cashOutWeightIsSet` check preventing double-set. Both guards prevent reentrancy exploitation.
77
+ Once cash-out weights are installed through a valid ratification path, they cannot be corrected in place. The design prefers determinism over mutable post-hoc fixes.
87
78
 
88
- ### 8.5 Attestation snapshot uses attestationsBegin - 1 (Codex R2 fix)
79
+ ### 8.3 `fulfillCommitmentsOf` and ratification are deliberately guarded
89
80
 
90
- `attestToScorecardFrom` snapshots attestation weight at `attestationsBegin - 1` instead of `attestationsBegin`. This prevents same-block transfer manipulation where a holder attests, transfers the NFT, and the recipient also attests in the same block. The trade-off is that NFTs minted in the same block as `attestationsBegin` have zero weight for that attestation call. This is acceptable because attestation typically happens well after minting, and the delay is negligible.
81
+ Completion and ratification paths use one-way state to prevent replay or double-finalization.
91
82
 
92
- ### 8.6 Pending reserves snapshotted at submission and included in denominators (Codex R2 fix)
83
+ ### 8.4 Pending reserves are intentionally included in governance and fee-accounting logic
93
84
 
94
- Two related protections:
85
+ This is conservative, but it prevents users from front-running reserve dilution out of governance power or fee-token distribution.
95
86
 
96
- **Governance:** `submitScorecardFor` snapshots `numberOfPendingReservesFor()` per tier into `_pendingReservesSnapshotOf`. `getBWAAttestationWeight` reads from this snapshot instead of live state. This prevents reserve minting between submission and attestation from inflating a holder's voting power by removing pending-reserve dilution. The trade-off is that if reserves are minted after submission, the dilution persists even though the reserves are no longer pending. This is conservative but correct -- it locks governance power at submission time.
87
+ ### 8.5 One-tier games always resolve via no-contest
97
88
 
98
- **Cash-out (fee tokens):** `afterCashOutRecordedWith` includes `_pendingReserveMintCost()` (sum of `pendingReserves * tier.price` across all tiers) in the fee token claim denominator. This prevents paid holders from claiming a disproportionate share of $DEFIFA/$NANA tokens before reserves are minted. The trade-off is that if reserve NFTs are never minted (e.g., the reserve beneficiary is set to address(0) and minting reverts), those shares of fee tokens remain locked in the contract. This is acceptable because: (1) it prevents paid holders from front-running reserve minting to extract the reserves' share, and (2) reserve beneficiaries are set at deployment and should always be valid.
89
+ A single-tier game cannot complete normal governance because the governance attestation model gives zero weight to holders of a tier that receives 100% of the scorecard, making quorum unreachable. This is expected: the game falls through to `NO_CONTEST` once `scorecardTimeout` elapses, and players recover their mint price via the permissionless `triggerNoContestFor()` refund path that queues a refund ruleset. This only works when `scorecardTimeout > 0`. A one-tier game launched with `scorecardTimeout = 0` disables the timeout path entirely, and funds become permanently locked with no exit. Game deployers must ensure `scorecardTimeout > 0` for single-tier configurations.
package/SKILLS.md CHANGED
@@ -3,18 +3,20 @@
3
3
  ## Use This File For
4
4
 
5
5
  - Use this file when the task involves Defifa game deployment, phase transitions, scorecards, attestations, governance thresholds, fee accounting, or Defifa token URI behavior.
6
- - Start here, then open the deployer, hook, governor, resolver, or tests based on which phase or subsystem is relevant.
6
+ - Start here, then decide whether the issue is launch shape, hook runtime, governor ratification, or resolver output.
7
7
 
8
8
  ## Read This Next
9
9
 
10
10
  | If you need... | Open this next |
11
11
  |---|---|
12
- | Repo overview and lifecycle framing | [`README.md`](./README.md), [`ARCHITECTURE.md`](./ARCHITECTURE.md) |
13
- | Deployment and phase scheduling | [`src/DefifaDeployer.sol`](./src/DefifaDeployer.sol), [`script/Deploy.s.sol`](./script/Deploy.s.sol) |
14
- | Cash-out and game-phase behavior | [`src/DefifaHook.sol`](./src/DefifaHook.sol), [`src/libraries/`](./src/libraries/) |
15
- | Governance and scorecards | [`src/DefifaGovernor.sol`](./src/DefifaGovernor.sol) |
16
- | Project-owner or token URI behavior | [`src/DefifaProjectOwner.sol`](./src/DefifaProjectOwner.sol), [`src/DefifaTokenUriResolver.sol`](./src/DefifaTokenUriResolver.sol) |
17
- | Security, lifecycle, and regressions | [`test/DefifaGovernor.t.sol`](./test/DefifaGovernor.t.sol), [`test/DefifaNoContest.t.sol`](./test/DefifaNoContest.t.sol), [`test/DefifaFeeAccounting.t.sol`](./test/DefifaFeeAccounting.t.sol), [`test/regression/`](./test/regression/) |
12
+ | Lifecycle framing and repo boundaries | [`ARCHITECTURE.md`](./ARCHITECTURE.md) |
13
+ | Launch shape, phase queueing, and commitment fulfillment | [`src/DefifaDeployer.sol`](./src/DefifaDeployer.sol), [`script/Deploy.s.sol`](./script/Deploy.s.sol) |
14
+ | Minting, delegation, game-state gating, and cash-out behavior | [`src/DefifaHook.sol`](./src/DefifaHook.sol), [`src/libraries/DefifaHookLib.sol`](./src/libraries/DefifaHookLib.sol) |
15
+ | Scorecard submission, attestation power, quorum, and ratification | [`src/DefifaGovernor.sol`](./src/DefifaGovernor.sol) |
16
+ | Token URI rendering and fee-project ownership helper | [`src/DefifaTokenUriResolver.sol`](./src/DefifaTokenUriResolver.sol), [`src/DefifaProjectOwner.sol`](./src/DefifaProjectOwner.sol) |
17
+ | Runtime and operational invariants | [`references/runtime.md`](./references/runtime.md), [`references/operations.md`](./references/operations.md) |
18
+ | Governance and lifecycle proofs | [`test/DefifaGovernor.t.sol`](./test/DefifaGovernor.t.sol), [`test/DefifaGovernanceHardening.t.sol`](./test/DefifaGovernanceHardening.t.sol), [`test/DefifaNoContest.t.sol`](./test/DefifaNoContest.t.sol) |
19
+ | Fee and adversarial accounting coverage | [`test/DefifaFeeAccounting.t.sol`](./test/DefifaFeeAccounting.t.sol), [`test/DefifaMintCostInvariant.t.sol`](./test/DefifaMintCostInvariant.t.sol), [`test/DefifaSecurity.t.sol`](./test/DefifaSecurity.t.sol), [`test/DefifaAdversarialQuorum.t.sol`](./test/DefifaAdversarialQuorum.t.sol) |
18
20
 
19
21
  ## Repo Map
20
22
 
@@ -27,16 +29,18 @@
27
29
 
28
30
  ## Purpose
29
31
 
30
- Defifa is an on-chain prediction game system built on Juicebox. This repo packages game launch, phased lifecycle control, scorecard governance, and NFT-based settlement into a single game-specific deployment surface.
32
+ Defifa is an onchain prediction game system built on Juicebox. This repo packages game launch, phased lifecycle control, scorecard governance, and NFT-based settlement into one game-specific deployment surface.
31
33
 
32
34
  ## Reference Files
33
35
 
34
- - Open [`references/runtime.md`](./references/runtime.md) when you need the game lifecycle, contract roles, settlement path, or the main economic and governance invariants.
35
- - Open [`references/operations.md`](./references/operations.md) when you need deployment and phase-queueing behavior, test breadcrumbs, or the common sources of stale operational assumptions.
36
+ - Open [`references/runtime.md`](./references/runtime.md) for the game lifecycle, contract roles, settlement path, and the main economic and governance invariants.
37
+ - Open [`references/operations.md`](./references/operations.md) for deployment and phase-queueing behavior, test breadcrumbs, and common stale operational assumptions.
36
38
 
37
39
  ## Working Rules
38
40
 
39
- - Start in [`src/DefifaDeployer.sol`](./src/DefifaDeployer.sol) for lifecycle and queueing behavior, but verify hook and governor assumptions before treating a game-state issue as deployer-only.
40
- - Treat scorecard ratification, no-contest behavior, and fee accounting as treasury-sensitive. Small changes there can alter settlement outcomes materially.
41
- - When a task mentions NFT rendering or metadata, confirm whether it belongs in [`src/DefifaTokenUriResolver.sol`](./src/DefifaTokenUriResolver.sol) instead of the hook or deployer.
42
- - If you edit phase transitions, check both lifecycle tests and fee/governance tests. Defifa behavior is cross-coupled.
41
+ - Start in [`src/DefifaDeployer.sol`](./src/DefifaDeployer.sol) for phase shape and commitment fulfillment, [`src/DefifaHook.sol`](./src/DefifaHook.sol) for NFT runtime and settlement behavior, and [`src/DefifaGovernor.sol`](./src/DefifaGovernor.sol) for scorecards, attestation, and ratification.
42
+ - Treat phase transitions, scorecard ratification, no-contest behavior, and fee accounting as one economic system.
43
+ - Defifa-specific cash-out weights and governance thresholds sit on top of `nana-721-hook-v6` and `nana-core-v6`.
44
+ - When a task mentions NFT rendering or metadata, confirm whether it belongs in [`src/DefifaTokenUriResolver.sol`](./src/DefifaTokenUriResolver.sol).
45
+ - If you edit phase transitions, check lifecycle, governance, and fee-accounting tests together.
46
+ - If ratification, attestation, or quorum behavior changes, re-read the audit and regression tests before trusting a clean happy-path result.
package/USER_JOURNEYS.md CHANGED
@@ -1,69 +1,169 @@
1
1
  # User Journeys
2
2
 
3
- ## Who This Repo Serves
3
+ ## Repo Purpose
4
4
 
5
- - teams launching Defifa prediction games
6
- - players minting outcome pieces and later redeeming winning positions
7
- - participants submitting, attesting to, and ratifying scorecards
8
- - operators handling refund, no-contest, and fee-settlement edges
5
+ This repo turns a Juicebox project into a prediction-game lifecycle with fixed phase timing, tiered outcome pieces, attestation-based scorecard governance, and final cash-out weights that decide how the pot settles. It owns Defifa's game-specific launch, scoring, no-contest, and settlement logic.
6
+
7
+ ## Primary Actors
8
+
9
+ - game creators launching a new Defifa market with fixed timing, tiers, and fee routing
10
+ - players minting outcome pieces during MINT and later redeeming or refunding them
11
+ - attestors and delegates submitting, supporting, revoking, and ratifying scorecards during SCORING
12
+ - auditors tracing where game fairness depends on shared 721-store behavior, governor state, and core terminal flows
13
+ - operators handling no-contest recovery or optional fee-project ownership locking
14
+
15
+ ## Key Surfaces
16
+
17
+ - `DefifaDeployer.launchGameWith(...)`: launches a Defifa game as a JB project and wires hook, governor, splits, and lifecycle timing
18
+ - `DefifaHook.afterPayRecordedWith(...)`: mints outcome NFTs when players pay during the mintable phase
19
+ - `DefifaHook.beforeCashOutRecordedWith(...)` and `afterCashOutRecordedWith(...)`: define refund, winning-piece redemption, and fee-token claim behavior
20
+ - `DefifaGovernor.submitScorecardFor(...)`, `attestToScorecardFrom(...)`, `revokeAttestationFrom(...)`, `ratifyScorecardFrom(...)`: scorecard governance lifecycle
21
+ - `DefifaDeployer.fulfillCommitmentsOf(...)` and `triggerNoContestFor(...)`: finalize commitments after ratification or unlock refund-oriented no-contest recovery
9
22
 
10
23
  ## Journey 1: Launch A Defifa Game
11
24
 
12
- **Starting state:** the team knows the countdown, mint window, scoring mechanics, and payout assumptions for a new game.
25
+ **Actor:** game creator.
26
+
27
+ **Intent:** launch a prediction game with fixed timing, tiers, fee routing, and governance rules.
28
+
29
+ **Preconditions**
30
+
31
+ - the creator knows the game start time, mint duration, optional refund duration, and scoring-timeout assumptions
32
+ - tier count, tier names, tier price, and split commitments are finalized
33
+ - the chosen terminal and payment token are correct because the launch path is intentionally one-way
34
+
35
+ **Main Flow**
36
+
37
+ 1. Prepare launch data with timing, tiers, splits, fee-project settings, terminal, and governance params.
38
+ 2. Call `DefifaDeployer.launchGameWith(...)`.
39
+ 3. The deployer launches the JB project, clones and initializes `DefifaHook`, initializes the governor state, and stores the game's immutable ops data.
40
+ 4. The game now advances through its documented phase sequence.
41
+
42
+ **Failure Modes**
43
+
44
+ - launch parameters are wrong, but the creator assumes they can patch them later
45
+ - fee routing, token decimals, or terminal assumptions drift from the terminal actually configured
46
+ - the creator mistakes permissionless launch for ongoing admin power
47
+
48
+ **Postconditions**
49
+
50
+ - the game exists as a staged JB project with Defifa-specific lifecycle wiring
51
+
52
+ ## Journey 2: Mint Outcome Pieces During Open Play
53
+
54
+ **Actor:** player.
55
+
56
+ **Intent:** buy one or more outcome pieces during the mint phase.
57
+
58
+ **Preconditions**
59
+
60
+ - the game is in the mintable phase
61
+ - the selected tier exists and is still mintable
62
+
63
+ **Main Flow**
64
+
65
+ 1. Pay the game project during the mint window.
66
+ 2. `DefifaHook` mints the selected outcome NFT tier.
67
+ 3. Delegation and mint-cost accounting are updated.
68
+ 4. Reserved mints and pending reserves continue to matter for later governance and settlement.
69
+
70
+ **Failure Modes**
71
+
72
+ - mint is attempted in the wrong phase
73
+ - assumptions about attestation power ignore pending reserves or tier weighting
74
+
75
+ **Postconditions**
76
+
77
+ - the player holds game pieces that later affect governance and settlement
78
+
79
+ ## Journey 3: Submit And Ratify A Scorecard
80
+
81
+ **Actor:** proposer, attestor, or delegate.
82
+
83
+ **Intent:** turn the game's result into a ratified scorecard.
84
+
85
+ **Preconditions**
86
+
87
+ - the game is in SCORING
88
+ - the actor understands quorum, grace-period, and timeout rules
89
+
90
+ **Main Flow**
91
+
92
+ 1. Submit a scorecard candidate.
93
+ 2. Attest or revoke while the scorecard is active.
94
+ 3. Wait for quorum and the grace period.
95
+ 4. Ratify one winning scorecard.
96
+
97
+ **Failure Modes**
98
+
99
+ - attestation power is concentrated enough to capture the result
100
+ - timeout is reached before ratification
101
+ - integrations misread live attestation power or pending-reserve dilution
102
+
103
+ **Postconditions**
104
+
105
+ - exactly one scorecard can become the game's final outcome, or the game moves toward no-contest handling
106
+
107
+ ## Journey 4: Fulfill Commitments And Settle The Game
108
+
109
+ **Actor:** completion path caller.
110
+
111
+ **Intent:** turn the ratified scorecard into final redeemable economics.
112
+
113
+ **Preconditions**
114
+
115
+ - a scorecard has been ratified
116
+ - the fulfillment path has not already run
117
+
118
+ **Main Flow**
13
119
 
14
- **Success:** the game launches as a staged Juicebox project with hook, governor, and metadata surfaces all aligned.
120
+ 1. Read the ratified outcome.
121
+ 2. Call `fulfillCommitmentsOf(...)`.
122
+ 3. Queue the completion ruleset and finalize the promised commitment flow.
123
+ 4. Let winning-piece holders redeem under the installed cash-out weights.
15
124
 
16
- **Flow**
17
- 1. Use `DefifaDeployer` with launch config, tier params, governance settings, and fee commitments.
18
- 2. The deployer launches the project, clones or wires the game hook, and initializes governance through `DefifaGovernor`.
19
- 3. The game now has a defined lifecycle instead of being a plain NFT sale.
125
+ **Failure Modes**
20
126
 
21
- ## Journey 2: Participate As A Player During The Mint Phase
127
+ - ratification succeeds but fulfillment is never run
128
+ - commitment logic or fee accounting drifts from the documented outcome
22
129
 
23
- **Starting state:** the game is in its countdown or live mint window and players want to buy outcome pieces.
130
+ **Postconditions**
24
131
 
25
- **Success:** the player mints the intended game pieces and their payment becomes part of the prize pot.
132
+ - the game enters its final redeemable state
26
133
 
27
- **Flow**
28
- 1. Wait until the lifecycle enters the mintable phase.
29
- 2. Pay into the game to mint the chosen outcome NFTs through `DefifaHook`.
30
- 3. The treasury accumulates the prize pot and the player's position is now represented by the minted pieces.
134
+ ## Journey 5: Enter No-Contest And Unlock Refund Recovery
31
135
 
32
- ## Journey 3: Handle Refund Or No-Contest Outcomes
136
+ **Actor:** any caller when the no-contest conditions are met.
33
137
 
34
- **Starting state:** the game cannot settle normally, either because the refund window is triggered or because governance fails to reach a contestable result.
138
+ **Intent:** move a game out of failed scoring and into the documented refund-oriented fallback path.
35
139
 
36
- **Success:** participants can exit under the repo's explicit failure-mode rules instead of ad hoc admin intervention.
140
+ **Preconditions**
37
141
 
38
- **Flow**
39
- 1. Observe the current game phase and whether it has entered refund or no-contest handling.
40
- 2. Use the game-defined exit path for participants rather than assuming the winning-scorecard path will eventually resolve.
41
- 3. Keep treasury and piece-state assumptions aligned with the phase actually reached.
142
+ - the game has hit its no-contest conditions
143
+ - the caller understands that `NO_CONTEST` and active refund rules are related but not identical states
42
144
 
43
- ## Journey 4: Submit, Attest To, And Ratify A Scorecard
145
+ **Main Flow**
44
146
 
45
- **Starting state:** minting is over and the game is in its scoring phase.
147
+ 1. Call `triggerNoContestFor(...)` when the timeout or participation conditions make the game ineligible for normal settlement.
148
+ 2. Queue the no-contest recovery ruleset.
149
+ 3. Let players exit under the fallback path once the queued ruleset becomes active.
46
150
 
47
- **Success:** a valid scorecard reaches quorum, survives any grace period, and becomes the game's settled result.
151
+ **Failure Modes**
48
152
 
49
- **Flow**
50
- 1. A participant submits a scorecard through `DefifaGovernor`.
51
- 2. Holders attest, delegate where permitted, and push the preferred scorecard toward quorum.
52
- 3. After the grace period, the governor ratifies the winning scorecard if it still satisfies the game's rules.
53
- 4. `DefifaHook` updates the relevant cash-out weights for settlement.
153
+ - integrators assume same-transaction full refunds immediately after the trigger
154
+ - the game becomes stuck because nobody triggers the no-contest path
54
155
 
55
- ## Journey 5: Redeem Winning Pieces And Settle The Pot
156
+ **Postconditions**
56
157
 
57
- **Starting state:** the game has a ratified result and winning positions are now known.
158
+ - the game moves onto the documented no-contest recovery track
58
159
 
59
- **Success:** holders of winning pieces burn or cash out them for their share of the prize pot.
160
+ ## Trust Boundaries
60
161
 
61
- **Flow**
62
- 1. Holders use the game's redemption path after settlement.
63
- 2. The hook applies the now-final weights associated with the winning scorecard.
64
- 3. Winners receive their proportional share while losers no longer have equivalent claim on the pot.
162
+ - this repo is trusted for game-specific phase logic, governance, and settlement weighting
163
+ - terminal accounting still comes from `nana-core-v6`
164
+ - shared tier-storage behavior still comes from `nana-721-hook-v6`
65
165
 
66
166
  ## Hand-Offs
67
167
 
68
- - Use [nana-721-hook-v6](../nana-721-hook-v6/USER_JOURNEYS.md) for the standard tiered NFT mechanics underneath the game-specific logic.
69
- - Use [nana-core-v6](../nana-core-v6/USER_JOURNEYS.md) for base project accounting once the question is no longer Defifa-specific lifecycle or governance behavior.
168
+ - Use [nana-core-v6](../nana-core-v6/USER_JOURNEYS.md) for underlying treasury and terminal behavior.
169
+ - Use [nana-721-hook-v6](../nana-721-hook-v6/USER_JOURNEYS.md) for shared tier-store and reserve semantics that Defifa builds on.
package/foundry.toml CHANGED
@@ -17,6 +17,8 @@ runs = 1024
17
17
  depth = 100
18
18
  fail_on_revert = false
19
19
 
20
+ [lint]
21
+ exclude_lints = ["pascal-case-struct", "mixed-case-variable"]
20
22
  [fmt]
21
23
  number_underscore = "thousands"
22
24
  multiline_func_header = "all"