@ballkidz/defifa 0.0.40 → 0.0.42
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/package.json +7 -16
- package/references/operations.md +32 -0
- package/references/runtime.md +43 -0
- package/script/Deploy.s.sol +2 -1
- package/src/DefifaDeployer.sol +58 -15
- package/src/interfaces/IDefifaDeployer.sol +22 -0
- package/ADMINISTRATION.md +0 -79
- package/ARCHITECTURE.md +0 -131
- package/AUDIT_INSTRUCTIONS.md +0 -100
- package/CHANGELOG.md +0 -40
- package/CRYPTO_ECON.md +0 -1190
- package/RISKS.md +0 -116
- package/SKILLS.md +0 -46
- package/STYLE_GUIDE.md +0 -565
- package/USER_JOURNEYS.md +0 -169
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ballkidz/defifa",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.42",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": "25.9.0"
|
|
@@ -13,22 +13,13 @@
|
|
|
13
13
|
"url": "git+https://github.com/BallKidz/defifa.git"
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
|
-
"src",
|
|
17
|
-
"script",
|
|
18
|
-
"lib/base64/base64.sol",
|
|
19
|
-
"lib/typeface/contracts/interfaces/ITypeface.sol",
|
|
20
|
-
"README.md",
|
|
21
|
-
"ARCHITECTURE.md",
|
|
22
|
-
"ADMINISTRATION.md",
|
|
23
|
-
"AUDIT_INSTRUCTIONS.md",
|
|
24
|
-
"CHANGELOG.md",
|
|
25
|
-
"CRYPTO_ECON.md",
|
|
26
|
-
"RISKS.md",
|
|
27
|
-
"SKILLS.md",
|
|
28
|
-
"STYLE_GUIDE.md",
|
|
29
|
-
"USER_JOURNEYS.md",
|
|
30
16
|
"foundry.toml",
|
|
31
|
-
"
|
|
17
|
+
"references/",
|
|
18
|
+
"remappings.txt",
|
|
19
|
+
"script/",
|
|
20
|
+
"src/",
|
|
21
|
+
"lib/base64/base64.sol",
|
|
22
|
+
"lib/typeface/contracts/interfaces/ITypeface.sol"
|
|
32
23
|
],
|
|
33
24
|
"dependencies": {
|
|
34
25
|
"@bananapus/721-hook-v6": "^0.0.54",
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Defifa Operations
|
|
2
|
+
|
|
3
|
+
Use this file when the task is about launch config, phase timing, governance windows, or deciding whether a symptom is operational drift or runtime logic.
|
|
4
|
+
|
|
5
|
+
## Deployment Surface
|
|
6
|
+
|
|
7
|
+
- [`src/DefifaDeployer.sol`](../src/DefifaDeployer.sol) is the first stop for launch-time config, phase queueing, and post-ratification fulfillment.
|
|
8
|
+
- [`script/Deploy.s.sol`](../script/Deploy.s.sol) and [`script/helpers/DefifaDeploymentLib.sol`](../script/helpers/DefifaDeploymentLib.sol) are the deployment entrypoints when the task is about current wiring rather than game mechanics.
|
|
9
|
+
- [`src/structs/`](../src/structs/) and [`src/enums/`](../src/enums/) define launch data, phase types, and other inputs that often drift from remembered assumptions.
|
|
10
|
+
|
|
11
|
+
## Change Checklist
|
|
12
|
+
|
|
13
|
+
- If you edit lifecycle timing, verify phase transitions, no-contest triggers, and the governor's attestation windows together.
|
|
14
|
+
- If you edit hook settlement logic, re-check fee accounting and mint-cost invariants.
|
|
15
|
+
- If you touch governance thresholds or attestation behavior, inspect the governor tests before assuming the change is local.
|
|
16
|
+
- If you touch token metadata or rendering, verify whether the bug belongs in the resolver instead of settlement code.
|
|
17
|
+
- If you touch anything supply-sensitive, inspect the review tests around pending reserves and quorum before relying on current intuition.
|
|
18
|
+
|
|
19
|
+
## Common Failure Modes
|
|
20
|
+
|
|
21
|
+
- Game-state issue is blamed on the hook even though the deployer queued the wrong phase or timing.
|
|
22
|
+
- Governance behavior looks wrong, but the real issue is stale launch configuration.
|
|
23
|
+
- Settlement changes accidentally affect fee distribution or redemption accounting.
|
|
24
|
+
- Resolver issues get misdiagnosed as hook or governor problems because they surface through NFTs.
|
|
25
|
+
- Review-style failures around reserve dilution or attestation counting are treated as isolated math issues even though they cross deployer, hook, and governor boundaries.
|
|
26
|
+
|
|
27
|
+
## Useful Proof Points
|
|
28
|
+
|
|
29
|
+
- [`test/Fork.t.sol`](../test/Fork.t.sol) for live-integration assumptions.
|
|
30
|
+
- [`test/TestRegressionGaps.sol`](../test/TestRegressionGaps.sol) and [`test/TestQALastMile.t.sol`](../test/TestQALastMile.t.sol) for pinned edge cases.
|
|
31
|
+
- [`test/BWAFunctionComparison.t.sol`](../test/BWAFunctionComparison.t.sol) and [`test/DefifaUSDC.t.sol`](../test/DefifaUSDC.t.sol) when currency or accounting context matters.
|
|
32
|
+
- [`test/regression/`](../test/regression/) when a change touches pending reserves, registry alignment, quorum griefing, or double-counting.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Defifa Runtime
|
|
2
|
+
|
|
3
|
+
Use this file when `defifa/SKILLS.md` has already routed you here and you need to reason about the game as a state machine rather than as isolated contracts.
|
|
4
|
+
|
|
5
|
+
## Contract Roles
|
|
6
|
+
|
|
7
|
+
- [`src/DefifaDeployer.sol`](../src/DefifaDeployer.sol) launches games, manages phase progression, fulfills commitments, and triggers safety exits such as no-contest.
|
|
8
|
+
- [`src/DefifaHook.sol`](../src/DefifaHook.sol) manages the NFT game pieces, delegation, and settlement-side cash-out behavior.
|
|
9
|
+
- [`src/DefifaGovernor.sol`](../src/DefifaGovernor.sol) handles scorecard submission, attestation, quorum, and ratification.
|
|
10
|
+
- [`src/DefifaTokenUriResolver.sol`](../src/DefifaTokenUriResolver.sol) renders game-card metadata.
|
|
11
|
+
- [`src/DefifaProjectOwner.sol`](../src/DefifaProjectOwner.sol) is the ownership helper for the fee project.
|
|
12
|
+
|
|
13
|
+
## Lifecycle
|
|
14
|
+
|
|
15
|
+
1. Countdown before minting opens.
|
|
16
|
+
2. Mint phase where players buy outcome NFTs and can delegate attestation power.
|
|
17
|
+
3. Optional refund phase if the launch configuration allows it.
|
|
18
|
+
4. Scoring phase where scorecards are submitted, attested, and ratified.
|
|
19
|
+
5. Complete or no-contest settlement depending on governance outcome and safety checks.
|
|
20
|
+
|
|
21
|
+
## High-Risk Areas
|
|
22
|
+
|
|
23
|
+
- Scorecard ratification and quorum assumptions: changes here directly affect who can settle the pot.
|
|
24
|
+
- No-contest and refund behavior: these paths are economic safety valves, not edge-case garnish.
|
|
25
|
+
- Fee accounting and commitment fulfillment: payout ordering and accounting drift can change final redemption value.
|
|
26
|
+
- Hook/governor/deployer coupling: many bugs come from changing one layer while assuming the others are passive.
|
|
27
|
+
- Pending reserved supply and snapshot assumptions: settlement and quorum logic can drift if supply-sensitive views are taken at the wrong time.
|
|
28
|
+
- Scorecards that miss quorum do not naturally “finish.” New scorecards can still be submitted until no-contest logic takes over, so do not assume a clean defeated terminal state.
|
|
29
|
+
|
|
30
|
+
## Common Misdiagnoses
|
|
31
|
+
|
|
32
|
+
- A settlement bug is blamed on [`src/DefifaHook.sol`](../src/DefifaHook.sol) even though the wrong phase or grace-period state was created in [`src/DefifaDeployer.sol`](../src/DefifaDeployer.sol) or [`src/DefifaGovernor.sol`](../src/DefifaGovernor.sol).
|
|
33
|
+
- A governance bug is blamed on the governor even though attestation power or delegation semantics were wrong in the hook layer.
|
|
34
|
+
- An NFT-facing bug is blamed on settlement code even though the problem is resolver output in [`src/DefifaTokenUriResolver.sol`](../src/DefifaTokenUriResolver.sol).
|
|
35
|
+
- A Defifa-specific payout result is patched in this repo when the real bug is shared 721 or core protocol behavior upstream.
|
|
36
|
+
|
|
37
|
+
## Tests To Trust First
|
|
38
|
+
|
|
39
|
+
- [`test/DefifaGovernor.t.sol`](../test/DefifaGovernor.t.sol) for governance flow.
|
|
40
|
+
- [`test/DefifaNoContest.t.sol`](../test/DefifaNoContest.t.sol) for safety exits.
|
|
41
|
+
- [`test/DefifaFeeAccounting.t.sol`](../test/DefifaFeeAccounting.t.sol) and [`test/DefifaMintCostInvariant.t.sol`](../test/DefifaMintCostInvariant.t.sol) for economic correctness.
|
|
42
|
+
- [`test/DefifaHookRegressions.t.sol`](../test/DefifaHookRegressions.t.sol), [`test/regression/GracePeriodBypass.t.sol`](../test/regression/GracePeriodBypass.t.sol), [`test/regression/FulfillmentBlocksRatification.t.sol`](../test/regression/FulfillmentBlocksRatification.t.sol), and [`test/regression/AttestationDelegateBeneficiary.t.sol`](../test/regression/AttestationDelegateBeneficiary.t.sol) for pinned regressions.
|
|
43
|
+
- [`test/DefifaSecurity.t.sol`](../test/DefifaSecurity.t.sol), [`test/DefifaGovernanceHardening.t.sol`](../test/DefifaGovernanceHardening.t.sol), [`test/DefifaAdversarialQuorum.t.sol`](../test/DefifaAdversarialQuorum.t.sol), and [`test/regression/`](../test/regression/) for adversarial and regression-derived cases.
|
package/script/Deploy.s.sol
CHANGED
|
@@ -119,7 +119,8 @@ contract DeployMainnet is Script, Sphinx {
|
|
|
119
119
|
registry: registry.registry,
|
|
120
120
|
defifaProjectId: _defifaProjectId,
|
|
121
121
|
baseProtocolProjectId: _baseProtocolProjectId,
|
|
122
|
-
hookStore: hookStore
|
|
122
|
+
hookStore: hookStore,
|
|
123
|
+
initialOwner: safeAddress()
|
|
123
124
|
});
|
|
124
125
|
|
|
125
126
|
governor.transferOwnership(address(deployer));
|
package/src/DefifaDeployer.sol
CHANGED
|
@@ -21,6 +21,7 @@ import {JBFundAccessLimitGroup} from "@bananapus/core-v6/src/structs/JBFundAcces
|
|
|
21
21
|
import {JBRulesetMetadata} from "@bananapus/core-v6/src/structs/JBRulesetMetadata.sol";
|
|
22
22
|
import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
|
|
23
23
|
import {JBSplitGroup} from "@bananapus/core-v6/src/structs/JBSplitGroup.sol";
|
|
24
|
+
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
|
|
24
25
|
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
|
|
25
26
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
26
27
|
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
@@ -46,7 +47,7 @@ import {DefifaTierParams} from "./structs/DefifaTierParams.sol";
|
|
|
46
47
|
/// the event concludes, a scorecard assigns cash-out weights to each tier. The treasury is distributed proportionally
|
|
47
48
|
/// to winning NFT holders. Games progress through phases: COUNTDOWN → MINT → REFUND → SCORING → COMPLETE (or
|
|
48
49
|
/// NO_CONTEST if minimum participation isn't met or scorecard ratification times out).
|
|
49
|
-
contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGamePotReporter, IERC721Receiver {
|
|
50
|
+
contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGamePotReporter, IERC721Receiver, Ownable {
|
|
50
51
|
using Strings for uint256;
|
|
51
52
|
using SafeERC20 for IERC20;
|
|
52
53
|
|
|
@@ -61,6 +62,8 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
|
|
|
61
62
|
error DefifaDeployer_InvalidCurrency(address token, uint256 currency);
|
|
62
63
|
error DefifaDeployer_NotNoContest(uint256 gameId, DefifaGamePhase phase);
|
|
63
64
|
error DefifaDeployer_NoContestAlreadyTriggered(uint256 gameId);
|
|
65
|
+
error DefifaDeployer_ReferralChainIdTooLarge(uint256 referralChainId);
|
|
66
|
+
error DefifaDeployer_ReferralProjectIdTooLarge(uint256 referralProjectId);
|
|
64
67
|
error DefifaDeployer_SplitsDontAddUp(uint256 totalPercent, uint256 maxPercent);
|
|
65
68
|
|
|
66
69
|
//*********************************************************************//
|
|
@@ -133,6 +136,12 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
|
|
|
133
136
|
/// @dev Once triggered, the game stays in NO_CONTEST and refunds are enabled.
|
|
134
137
|
mapping(uint256 => bool) public noContestTriggeredFor;
|
|
135
138
|
|
|
139
|
+
/// @notice The packed `(referralChainId << 48) | referralProjectId` reference credited as the referrer on
|
|
140
|
+
/// every fee-payout `sendPayoutsOf` call this deployer makes during `fulfillCommitmentsOf`. Defaults to
|
|
141
|
+
/// `(1, DEFIFA_PROJECT_ID)` so fee-volume credit accrues to the Defifa project on Ethereum mainnet
|
|
142
|
+
/// regardless of which chain the game runs on. Settable by the owner via `setReferralProjectId`.
|
|
143
|
+
uint256 public override referralProjectId;
|
|
144
|
+
|
|
136
145
|
//*********************************************************************//
|
|
137
146
|
// ------------------------- external views -------------------------- //
|
|
138
147
|
//*********************************************************************//
|
|
@@ -281,6 +290,9 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
|
|
|
281
290
|
/// @param defifaProjectId The ID of the project that should take the fee from the games.
|
|
282
291
|
/// @param baseProtocolProjectId The ID of the protocol project that'll receive fees from fulfilling commitments.
|
|
283
292
|
/// @param hookStore The store used by Defifa hooks.
|
|
293
|
+
/// @param initialOwner The address granted authority to call `setReferralProjectId`. The contract is otherwise
|
|
294
|
+
/// stateless from an admin perspective — the owner only controls the referrer reference used when crediting
|
|
295
|
+
/// fee-volume on `fulfillCommitmentsOf` payouts.
|
|
284
296
|
constructor(
|
|
285
297
|
address hookCodeOrigin,
|
|
286
298
|
IJB721TokenUriResolver tokenUriResolver,
|
|
@@ -289,8 +301,11 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
|
|
|
289
301
|
IJBAddressRegistry registry,
|
|
290
302
|
uint256 defifaProjectId,
|
|
291
303
|
uint256 baseProtocolProjectId,
|
|
292
|
-
IJB721TiersHookStore hookStore
|
|
293
|
-
|
|
304
|
+
IJB721TiersHookStore hookStore,
|
|
305
|
+
address initialOwner
|
|
306
|
+
)
|
|
307
|
+
Ownable(initialOwner)
|
|
308
|
+
{
|
|
294
309
|
HOOK_CODE_ORIGIN = hookCodeOrigin;
|
|
295
310
|
TOKEN_URI_RESOLVER = tokenUriResolver;
|
|
296
311
|
GOVERNOR = governor;
|
|
@@ -301,6 +316,10 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
|
|
|
301
316
|
HOOK_STORE = hookStore;
|
|
302
317
|
/// @dev Uses the deployer address as group ID. Game scoring rulesets use uint160(token) as group ID.
|
|
303
318
|
SPLIT_GROUP = uint256(uint160(address(this)));
|
|
319
|
+
|
|
320
|
+
// Default referrer reference: Defifa project on Ethereum mainnet. Encoded `(chainId << 48) | projectId`
|
|
321
|
+
// per `JBMultiTerminal.currentReferralProjectId`. Owner can retarget via `setReferralProjectId`.
|
|
322
|
+
referralProjectId = (uint256(1) << 48) | defifaProjectId;
|
|
304
323
|
}
|
|
305
324
|
|
|
306
325
|
//*********************************************************************//
|
|
@@ -346,24 +365,18 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
|
|
|
346
365
|
|
|
347
366
|
// Send only the fee portion as payouts. The remaining balance stays as surplus for cash-outs.
|
|
348
367
|
// Use the ruleset's baseCurrency — this matches the currency under which payout limits were stored
|
|
349
|
-
// at launch time, regardless of whether the token is native ETH or an ERC-20.
|
|
350
|
-
//
|
|
351
|
-
//
|
|
352
|
-
//
|
|
353
|
-
//
|
|
354
|
-
//
|
|
355
|
-
// The referrer reference is encoded as `(referralChainId << 48) | referralProjectId` per `JBMultiTerminal`'s
|
|
356
|
-
// `currentReferralProjectId` packing. Defifa lives on Ethereum mainnet, so we hard-code `referralChainId = 1`
|
|
357
|
-
// here: this ensures the protocol fee volume credit accrues to Defifa on mainnet regardless of which chain
|
|
358
|
-
// the game runs on. (Auto-resolving to `block.chainid` would scatter credit across L2s where Defifa has no
|
|
359
|
-
// canonical project ID, so we pin mainnet explicitly.)
|
|
368
|
+
// at launch time, regardless of whether the token is native ETH or an ERC-20. Wrapped in try-catch so
|
|
369
|
+
// the final ruleset is always queued even if payout fails. The configured `referralProjectId` (default
|
|
370
|
+
// `(1, DEFIFA_PROJECT_ID)`, owner-settable via `setReferralProjectId`) credits Defifa with the protocol
|
|
371
|
+
// fee volume from every game's commitment payout. Pinning mainnet by default avoids scattering credit
|
|
372
|
+
// across L2s where Defifa has no canonical project ID.
|
|
360
373
|
try terminal.sendPayoutsOf({
|
|
361
374
|
projectId: gameId,
|
|
362
375
|
token: token,
|
|
363
376
|
amount: feeAmount,
|
|
364
377
|
currency: metadata.baseCurrency,
|
|
365
378
|
minTokensPaidOut: 0,
|
|
366
|
-
referralProjectId:
|
|
379
|
+
referralProjectId: referralProjectId
|
|
367
380
|
}) {}
|
|
368
381
|
catch (bytes memory reason) {
|
|
369
382
|
// Payout failed — fee stays in pot. Reset to 0 so currentGamePotOf
|
|
@@ -653,6 +666,36 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
|
|
|
653
666
|
return IERC721Receiver.onERC721Received.selector;
|
|
654
667
|
}
|
|
655
668
|
|
|
669
|
+
/// @notice Update the referrer reference credited on every fee-payout `sendPayoutsOf` call this deployer
|
|
670
|
+
/// makes during `fulfillCommitmentsOf`.
|
|
671
|
+
/// @dev Stores the packed `(newReferralChainId << 48) | newReferralProjectId` value used by
|
|
672
|
+
/// `JBMultiTerminal.currentReferralProjectId`. Either field may be zero — passing `(0, 0)` disables the
|
|
673
|
+
/// referral credit entirely. Bounded so the pack is lossless: `newReferralProjectId` must fit in `uint48`,
|
|
674
|
+
/// `newReferralChainId` must fit in `uint208` (so the left-shift by 48 doesn't drop high bits).
|
|
675
|
+
/// @param newReferralProjectId The referring project's bare ID on `newReferralChainId`.
|
|
676
|
+
/// @param newReferralChainId The EIP-155 chain ID of the referrer's home chain.
|
|
677
|
+
function setReferralProjectId(
|
|
678
|
+
uint256 newReferralProjectId,
|
|
679
|
+
uint256 newReferralChainId
|
|
680
|
+
)
|
|
681
|
+
external
|
|
682
|
+
override
|
|
683
|
+
onlyOwner
|
|
684
|
+
{
|
|
685
|
+
// Bound the inputs to the on-chain encoding so the pack is lossless. The same shape JBMultiTerminal uses:
|
|
686
|
+
// projectId in bits [47:0], chainId in bits [255:48].
|
|
687
|
+
if (newReferralProjectId > type(uint48).max) {
|
|
688
|
+
revert DefifaDeployer_ReferralProjectIdTooLarge(newReferralProjectId);
|
|
689
|
+
}
|
|
690
|
+
if (newReferralChainId >> 208 != 0) revert DefifaDeployer_ReferralChainIdTooLarge(newReferralChainId);
|
|
691
|
+
|
|
692
|
+
referralProjectId = (newReferralChainId << 48) | newReferralProjectId;
|
|
693
|
+
|
|
694
|
+
emit SetReferralProjectId({
|
|
695
|
+
referralChainId: newReferralChainId, referralProjectId: newReferralProjectId, caller: msg.sender
|
|
696
|
+
});
|
|
697
|
+
}
|
|
698
|
+
|
|
656
699
|
/// @notice Triggers the no-contest refund mechanism for a game.
|
|
657
700
|
/// @dev Anyone can call this once the game is in the NO_CONTEST phase. This queues a new ruleset without
|
|
658
701
|
/// payout limits, making the surplus equal to the balance so users can cash out at their mint price.
|
|
@@ -45,6 +45,12 @@ interface IDefifaDeployer {
|
|
|
45
45
|
/// @param caller The address that queued the phase transition.
|
|
46
46
|
event QueuedNoContest(uint256 indexed gameId, address caller);
|
|
47
47
|
|
|
48
|
+
/// @notice Emitted when the referrer reference for fee-volume credit is updated.
|
|
49
|
+
/// @param referralChainId The EIP-155 chain ID of the new referrer's home chain.
|
|
50
|
+
/// @param referralProjectId The new referring project's bare project ID on `referralChainId`.
|
|
51
|
+
/// @param caller The address that set the new referrer.
|
|
52
|
+
event SetReferralProjectId(uint256 indexed referralChainId, uint256 indexed referralProjectId, address caller);
|
|
53
|
+
|
|
48
54
|
/// @notice The fee divisor for base protocol fees (100 / fee percent).
|
|
49
55
|
/// @return The fee divisor.
|
|
50
56
|
function BASE_PROTOCOL_FEE_DIVISOR() external view returns (uint256);
|
|
@@ -81,6 +87,12 @@ interface IDefifaDeployer {
|
|
|
81
87
|
/// @return The address registry contract.
|
|
82
88
|
function REGISTRY() external view returns (IJBAddressRegistry);
|
|
83
89
|
|
|
90
|
+
/// @notice The packed `(referralChainId << 48) | referralProjectId` reference credited as the referrer on
|
|
91
|
+
/// every fee-payout `sendPayoutsOf` call this deployer makes. Defaults to `(1, DEFIFA_PROJECT_ID)` so
|
|
92
|
+
/// credit accrues to Defifa on Ethereum mainnet; owner-settable via `setReferralProjectId`.
|
|
93
|
+
/// @return The packed referrer reference.
|
|
94
|
+
function referralProjectId() external view returns (uint256);
|
|
95
|
+
|
|
84
96
|
/// @notice The split group ID used for distributing game pot funds.
|
|
85
97
|
/// @return The split group.
|
|
86
98
|
function SPLIT_GROUP() external view returns (uint256);
|
|
@@ -119,6 +131,16 @@ interface IDefifaDeployer {
|
|
|
119
131
|
/// @return gameId The ID of the newly launched game.
|
|
120
132
|
function launchGameWith(DefifaLaunchProjectData calldata launchProjectData) external returns (uint256 gameId);
|
|
121
133
|
|
|
134
|
+
/// @notice Update the referrer reference credited on every fee-payout `sendPayoutsOf` call this deployer
|
|
135
|
+
/// makes during `fulfillCommitmentsOf`.
|
|
136
|
+
/// @dev Stores the packed `(newReferralChainId << 48) | newReferralProjectId` value used by
|
|
137
|
+
/// `JBMultiTerminal.currentReferralProjectId`. Either field may be zero (passing `(0, 0)` disables the
|
|
138
|
+
/// referral credit). Bounded so the pack is lossless: `newReferralProjectId <= type(uint48).max`,
|
|
139
|
+
/// `newReferralChainId <= type(uint208).max`.
|
|
140
|
+
/// @param newReferralProjectId The referring project's bare ID on `newReferralChainId`.
|
|
141
|
+
/// @param newReferralChainId The EIP-155 chain ID of the referrer's home chain.
|
|
142
|
+
function setReferralProjectId(uint256 newReferralProjectId, uint256 newReferralChainId) external;
|
|
143
|
+
|
|
122
144
|
/// @notice Trigger a no-contest outcome for a game.
|
|
123
145
|
/// @param gameId The ID of the game.
|
|
124
146
|
function triggerNoContestFor(uint256 gameId) external;
|
package/ADMINISTRATION.md
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
# Administration
|
|
2
|
-
|
|
3
|
-
## At A Glance
|
|
4
|
-
|
|
5
|
-
| Item | Details |
|
|
6
|
-
| --- | --- |
|
|
7
|
-
| Scope | Game launch configuration, scorecard governance, no-contest recovery, and optional fee-project ownership locking |
|
|
8
|
-
| Control posture | Permissionless launch, then collective governance plus bounded contract-controlled lifecycle paths |
|
|
9
|
-
| Highest-risk actions | Launching with wrong immutable game settings, misconfiguring governance thresholds, and misunderstanding no-contest handling |
|
|
10
|
-
| Recovery posture | Mostly replacement or documented no-contest handling; there is no broad post-launch owner override |
|
|
11
|
-
|
|
12
|
-
## Purpose
|
|
13
|
-
|
|
14
|
-
`defifa` is unusual because game creation is permissionless but ongoing game control is intentionally narrow. The main administration job is understanding what is fixed at launch, what collective governance can still do, and what the deployer must do to finish settlement.
|
|
15
|
-
|
|
16
|
-
## Control Model
|
|
17
|
-
|
|
18
|
-
- `launchGameWith(...)` is the real governance commitment. Core game shape is fixed there.
|
|
19
|
-
- `DefifaGovernor` controls scorecard submission, attestation, and ratification.
|
|
20
|
-
- `DefifaHook` controls phase-aware mint and cash-out behavior but does not expose broad admin mutability.
|
|
21
|
-
- `DefifaDeployer` still owns structural lifecycle duties such as fulfillment and no-contest queuing.
|
|
22
|
-
- `DefifaProjectOwner` is an optional irreversible sink for the fee-project NFT.
|
|
23
|
-
|
|
24
|
-
## Roles
|
|
25
|
-
|
|
26
|
-
| Role | How Assigned | Scope | Notes |
|
|
27
|
-
| --- | --- | --- | --- |
|
|
28
|
-
| Game creator | Calls `launchGameWith(...)` | Launch only | Does not receive broad runtime admin power afterward |
|
|
29
|
-
| Scorecard participant | Holds or receives attestation power | Per game | Can submit, attest, revoke, and help ratify |
|
|
30
|
-
| Ratification path caller | Any caller who meets the documented conditions | Per game | Finalizes a valid scorecard |
|
|
31
|
-
| Fulfillment path caller | Any valid caller once ratified | Per game | Must run the completion commitment path |
|
|
32
|
-
| `DefifaProjectOwner` holder | Project NFT sent into sink | Per fee project | Irreversible ownership lock |
|
|
33
|
-
|
|
34
|
-
## Privileged Surfaces
|
|
35
|
-
|
|
36
|
-
- `launchGameWith(...)` fixes phase timing, tiers, fee routing, and governance shape
|
|
37
|
-
- `submitScorecardFor(...)`, `attestToScorecardFrom(...)`, `revokeAttestationFrom(...)`, and `ratifyScorecardFrom(...)` govern outcome selection
|
|
38
|
-
- `fulfillCommitmentsOf(...)` turns a ratified scorecard into real settlement
|
|
39
|
-
- `triggerNoContestFor(...)` moves failed games into the documented recovery path
|
|
40
|
-
|
|
41
|
-
## Immutable And One-Way
|
|
42
|
-
|
|
43
|
-
- Game phase timing is fixed at launch.
|
|
44
|
-
- Scorecard timeout, minimum participation, and default delegation choices are fixed at launch.
|
|
45
|
-
- `setTierCashOutWeightsTo()` is effectively one-way once final weights are installed.
|
|
46
|
-
- `cashOutWeightIsSet` permanently closes the score-setting path after success.
|
|
47
|
-
- `DefifaProjectOwner` permanently locks the project NFT it receives.
|
|
48
|
-
- `fulfillCommitmentsOf()` and `triggerNoContestFor()` are single-use style lifecycle paths.
|
|
49
|
-
|
|
50
|
-
## Operational Notes
|
|
51
|
-
|
|
52
|
-
- Validate game timings, tier setup, fee routing, and attestation settings before launch.
|
|
53
|
-
- Treat `launchGameWith()` as the real admin commitment.
|
|
54
|
-
- During scoring, follow the submission, attestation, and ratification flow rather than looking for discretionary overrides.
|
|
55
|
-
- Use `triggerNoContestFor()` only when the game has actually entered the documented no-contest condition.
|
|
56
|
-
- Treat the fee-project ownership proxy as a burn-lock mechanism, not a recoverable custody tool.
|
|
57
|
-
|
|
58
|
-
## Machine Notes
|
|
59
|
-
|
|
60
|
-
- Do not infer ongoing admin power for the game creator; launch is permissionless but not an ongoing authority grant.
|
|
61
|
-
- Treat `DefifaDeployer`, `DefifaGovernor`, `DefifaHook`, and `DefifaProjectOwner` as the minimum source-of-truth set for authority review.
|
|
62
|
-
- If scorecard state, quorum assumptions, or timeout state differ from the expected lifecycle, inspect the current phase before documenting the next action.
|
|
63
|
-
- If a game launched with wrong immutable economics, timing, or split assumptions, do not guess at an in-place fix.
|
|
64
|
-
|
|
65
|
-
## Recovery
|
|
66
|
-
|
|
67
|
-
- If a scorecard never reaches a valid ratification path and timeout conditions are met, use the documented no-contest flow.
|
|
68
|
-
- If a game launched with wrong immutable economics, timing, fee routing, or tier design, recovery is usually a replacement deployment.
|
|
69
|
-
- If fee-project ownership was transferred into `DefifaProjectOwner`, there is no recovery path for that NFT.
|
|
70
|
-
- There is no broad owner override that can pause, cancel, or rewrite a live game after launch.
|
|
71
|
-
|
|
72
|
-
## Admin Boundaries
|
|
73
|
-
|
|
74
|
-
- No one can change tier prices, timing, payment token, fees, or split configuration after launch.
|
|
75
|
-
- No one can unilaterally set scorecard weights without the documented governance path.
|
|
76
|
-
- No one can manually pause, cancel, or rewind a game phase.
|
|
77
|
-
- No one can set cash-out weights twice.
|
|
78
|
-
- No one can fulfill commitments twice.
|
|
79
|
-
- No one can recover the project NFT from `DefifaProjectOwner`.
|
package/ARCHITECTURE.md
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
# Architecture
|
|
2
|
-
|
|
3
|
-
## Purpose
|
|
4
|
-
|
|
5
|
-
`defifa` builds phased prediction games on top of Juicebox and the 721 hook stack. A game is a Juicebox project with a custom NFT hook, a scorecard governor, and a deployer that launches the project and later fulfills the economic commitments that make completion real.
|
|
6
|
-
|
|
7
|
-
## System Overview
|
|
8
|
-
|
|
9
|
-
`DefifaHook`, `DefifaGovernor`, and `DefifaDeployer` form one game-state machine even though they are deployed separately. The hook owns game-piece NFT behavior, attestation delegation, and phase-sensitive cash-out weighting. The governor owns scorecard submission, attestation, quorum, and ratification. The deployer owns game launch, phased ruleset setup, and commitment fulfillment after governance decides the outcome.
|
|
10
|
-
|
|
11
|
-
## Core Invariants
|
|
12
|
-
|
|
13
|
-
- The game is economically coherent only if deployer, governor, and hook agree on phase progression.
|
|
14
|
-
- Ratification is the only path that should install final cash-out weights for the complete phase.
|
|
15
|
-
- Attestation power should reflect tier semantics, not raw circulating supply.
|
|
16
|
-
- Refund, scoring, complete, and no-contest behavior must be mutually coherent.
|
|
17
|
-
- The deployer's post-ratification fulfillment path is mandatory economics, not optional housekeeping.
|
|
18
|
-
- Completion-phase cash outs must account for already redeemed tokens and pending reserve dilution correctly.
|
|
19
|
-
|
|
20
|
-
## Modules
|
|
21
|
-
|
|
22
|
-
| Module | Responsibility | Notes |
|
|
23
|
-
| --- | --- | --- |
|
|
24
|
-
| `DefifaDeployer` | Launches games, sets phased rulesets, clones hooks, initializes governance, and fulfills commitments | Launch-time and completion-time runtime surface |
|
|
25
|
-
| `DefifaHook` | NFT minting, delegation, game-phase-aware cash-out behavior, and completion claims | Main game-facing runtime hook |
|
|
26
|
-
| `DefifaGovernor` | Scorecard submission, attestation weighting, quorum, grace periods, and ratification | Governance surface |
|
|
27
|
-
| `DefifaHookLib` | Shared validation and weight math extracted from the hook | Bytecode-management helper |
|
|
28
|
-
| `DefifaTokenUriResolver` | Dynamic token metadata and SVG rendering | Metadata layer |
|
|
29
|
-
| `DefifaProjectOwner` | Irreversible project-owner sink that preserves selected operator permissions | Governance-sensitive helper |
|
|
30
|
-
|
|
31
|
-
## Trust Boundaries
|
|
32
|
-
|
|
33
|
-
- Canonical treasury accounting, project ownership, rulesets, terminals, and payout mechanics remain in `nana-core-v6`.
|
|
34
|
-
- Tier storage, reserve minting mechanics, and generic ERC-721 behavior come from `nana-721-hook-v6`.
|
|
35
|
-
- `DefifaGovernor` is trusted to ratify scorecards only through its quorum, grace-period, and timelock rules.
|
|
36
|
-
- `DefifaDeployer` is trusted to convert governance output into the final completion envelope.
|
|
37
|
-
|
|
38
|
-
## Critical Flows
|
|
39
|
-
|
|
40
|
-
### Launch Game
|
|
41
|
-
|
|
42
|
-
```text
|
|
43
|
-
creator
|
|
44
|
-
-> deployer validates mint/refund/start timings
|
|
45
|
-
-> deployer predicts the game project ID and clones a game hook deterministically
|
|
46
|
-
-> deployer builds phased rulesets and optional fee splits
|
|
47
|
-
-> controller launches the project
|
|
48
|
-
-> governor is initialized for the game
|
|
49
|
-
-> hook ownership and project ownership are transferred into the intended long-term shape
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### Mint During Open Play
|
|
53
|
-
|
|
54
|
-
```text
|
|
55
|
-
player
|
|
56
|
-
-> pays the game project during the mint window
|
|
57
|
-
-> hook mints the selected game-piece NFT tier
|
|
58
|
-
-> delegation state and total mint-cost accounting are updated
|
|
59
|
-
-> reserved mints and pending reserves continue to affect later completion claims
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### Scorecard Governance
|
|
63
|
-
|
|
64
|
-
```text
|
|
65
|
-
attester or proposer
|
|
66
|
-
-> governor accepts a scorecard candidate
|
|
67
|
-
-> attestation power is computed from tier-relative holdings
|
|
68
|
-
-> quorum, grace period, and timelock gates are enforced
|
|
69
|
-
-> governor ratifies exactly one winning scorecard
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### Fulfill Commitments And Complete
|
|
73
|
-
|
|
74
|
-
```text
|
|
75
|
-
authorized completion path
|
|
76
|
-
-> deployer reads the ratified outcome
|
|
77
|
-
-> deployer fulfills the game's promised commitments and queues the final ruleset
|
|
78
|
-
-> hook installs final cash-out weights
|
|
79
|
-
-> holders burn pieces during complete phase to reclaim their weighted share of the pot
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## Accounting Model
|
|
83
|
-
|
|
84
|
-
This repo does not replace `nana-core-v6` treasury accounting. Its critical economic state is:
|
|
85
|
-
|
|
86
|
-
- phase timestamps and game ops data in the deployer
|
|
87
|
-
- scorecard and attestation state in the governor
|
|
88
|
-
- tier cash-out weights, redeemed-token tracking, mint-cost totals, and delegation state in the hook
|
|
89
|
-
|
|
90
|
-
The hook's completion math is intentionally phase-sensitive:
|
|
91
|
-
|
|
92
|
-
- before completion, cash-out behavior is refund or fallback oriented
|
|
93
|
-
- after ratification and fulfillment, cash-out weights become the game outcome
|
|
94
|
-
- completion claims use minted cost, redeemed tracking, and pending-reserve-aware dilution together
|
|
95
|
-
|
|
96
|
-
## Security Model
|
|
97
|
-
|
|
98
|
-
- The primary risk is semantic drift across hook, governor, and deployer.
|
|
99
|
-
- Ratification and fulfillment are separate steps; a ratified scorecard without correct fulfillment still leaves the game economically unfinished.
|
|
100
|
-
- Attestation weighting is part of game fairness, not just governance plumbing.
|
|
101
|
-
- Pending reserves and reserved-mint behavior affect both quorum fairness and completion-time claim dilution.
|
|
102
|
-
- Phase transitions are safety-critical. A timing bug can enable refunds, scoring, or completion in the wrong order.
|
|
103
|
-
|
|
104
|
-
## Safe Change Guide
|
|
105
|
-
|
|
106
|
-
- Review `DefifaHook`, `DefifaGovernor`, and `DefifaDeployer` together for any nontrivial change.
|
|
107
|
-
- If phase semantics change, re-check mint, refund, scoring, ratification, fulfillment, and completion cash-out behavior together.
|
|
108
|
-
- If attestation math changes, inspect tier semantics, delegation, quorum, and ratification thresholds together.
|
|
109
|
-
- If completion claim math changes, re-check redeemed tracking, pending reserve dilution, and fee-token side claims in the same review.
|
|
110
|
-
|
|
111
|
-
## Canonical Checks
|
|
112
|
-
|
|
113
|
-
- governor state transitions and scorecard handling:
|
|
114
|
-
`test/DefifaGovernor.t.sol`
|
|
115
|
-
- fulfillment and ratification coupling:
|
|
116
|
-
`test/regression/FulfillmentBlocksRatification.t.sol`
|
|
117
|
-
- pending reserve effects on completion fairness:
|
|
118
|
-
`test/regression/PendingReserveSnapshotBypass.t.sol`
|
|
119
|
-
|
|
120
|
-
## Source Map
|
|
121
|
-
|
|
122
|
-
- `src/DefifaDeployer.sol`
|
|
123
|
-
- `src/DefifaGovernor.sol`
|
|
124
|
-
- `src/DefifaHook.sol`
|
|
125
|
-
- `src/libraries/DefifaHookLib.sol`
|
|
126
|
-
- `src/DefifaTokenUriResolver.sol`
|
|
127
|
-
- `test/DefifaGovernor.t.sol`
|
|
128
|
-
- `test/DefifaHookRegressions.t.sol`
|
|
129
|
-
- `test/DefifaFeeAccounting.t.sol`
|
|
130
|
-
- `test/regression/FulfillmentBlocksRatification.t.sol`
|
|
131
|
-
- `test/regression/PendingReserveSnapshotBypass.t.sol`
|
package/AUDIT_INSTRUCTIONS.md
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
# Audit Instructions
|
|
2
|
-
|
|
3
|
-
Defifa is a staged prediction-game system built on Juicebox and the tiered 721 stack. Audit it as a governance-and-settlement protocol, not just an NFT game.
|
|
4
|
-
|
|
5
|
-
## Audit Objective
|
|
6
|
-
|
|
7
|
-
There is a billion dollars of well-meaning projects' money in the Juicebox Money Engine, growing exponentially. Your job is to hack it before anyone else. Whoever hacks it first saves/steals the money, and you are obsessed with being this winner, while also being a steward of the protocol and wanting it to keep growing safely.
|
|
8
|
-
|
|
9
|
-
Suggestions of where to look:
|
|
10
|
-
|
|
11
|
-
- let players extract more than their fair share of the game pot
|
|
12
|
-
- break the game-phase lifecycle or allow actions in the wrong phase
|
|
13
|
-
- corrupt scorecard submission, attestation, quorum, delegation, grace-period, or ratification logic
|
|
14
|
-
- miscompute tier cash-out weights or fee-token distribution
|
|
15
|
-
- leave a deployed game misconfigured through deployer or owner-helper mistakes
|
|
16
|
-
|
|
17
|
-
## Scope
|
|
18
|
-
|
|
19
|
-
In scope:
|
|
20
|
-
|
|
21
|
-
- `src/DefifaDeployer.sol`
|
|
22
|
-
- `src/DefifaGovernor.sol`
|
|
23
|
-
- `src/DefifaHook.sol`
|
|
24
|
-
- `src/DefifaProjectOwner.sol`
|
|
25
|
-
- `src/DefifaTokenUriResolver.sol`
|
|
26
|
-
- `src/libraries/DefifaHookLib.sol`
|
|
27
|
-
- enums, interfaces, structs, and deployment helpers
|
|
28
|
-
|
|
29
|
-
## Start Here
|
|
30
|
-
|
|
31
|
-
1. `src/DefifaGovernor.sol`
|
|
32
|
-
2. `src/DefifaHook.sol`
|
|
33
|
-
3. `src/DefifaDeployer.sol`
|
|
34
|
-
4. `src/DefifaProjectOwner.sol`
|
|
35
|
-
|
|
36
|
-
## Security Model
|
|
37
|
-
|
|
38
|
-
High-level lifecycle:
|
|
39
|
-
|
|
40
|
-
- deploy a game as a Juicebox project
|
|
41
|
-
- sell outcome NFTs during the mint phase
|
|
42
|
-
- optionally allow refunds or no-contest handling
|
|
43
|
-
- run scorecard governance through submissions and attestations
|
|
44
|
-
- ratify one scorecard
|
|
45
|
-
- update cash-out weights so winning pieces can redeem the treasury
|
|
46
|
-
|
|
47
|
-
The contracts split responsibility as follows:
|
|
48
|
-
|
|
49
|
-
- `DefifaDeployer` launches the project and wires lifecycle configuration
|
|
50
|
-
- `DefifaHook` handles minting, burning, fee accounting, and game-specific cash-out math
|
|
51
|
-
- `DefifaGovernor` owns scorecard governance and ratification
|
|
52
|
-
- `DefifaProjectOwner` acts as a project-owner helper where governance needs a stable admin surface
|
|
53
|
-
- `DefifaTokenUriResolver` handles game NFT metadata
|
|
54
|
-
|
|
55
|
-
## Roles And Privileges
|
|
56
|
-
|
|
57
|
-
| Role | Powers | How constrained |
|
|
58
|
-
|------|--------|-----------------|
|
|
59
|
-
| Game deployer or owner path | Configure a game's initial lifecycle and helper wiring | Must not retain hidden post-launch powers |
|
|
60
|
-
| Governor participants | Submit, attest to, and ratify scorecards | Must remain bounded by phase, quorum, and delegation rules |
|
|
61
|
-
| `DefifaHook` | Determine mint and final redeem economics | Must not over-credit players or under-account fees |
|
|
62
|
-
| Project owner helper | Stand in for project ownership where configured | Must not diverge from the intended governance authority |
|
|
63
|
-
|
|
64
|
-
## Integration Assumptions
|
|
65
|
-
|
|
66
|
-
| Dependency | Assumption | What breaks if wrong |
|
|
67
|
-
|------------|------------|----------------------|
|
|
68
|
-
| `nana-core-v6` | Treasury accounting, rulesets, and cash-out surfaces stay coherent | Pot settlement and redeem math become unsound |
|
|
69
|
-
| `nana-721-hook-v6` | Tier issuance and reserve behavior match Defifa's game logic | Voting power, supply, and cash-out weights drift |
|
|
70
|
-
| Owner-helper and deployer patterns | Launch-time authority fully converges to the intended game authority | Games remain misconfigured or over-privileged |
|
|
71
|
-
|
|
72
|
-
## Critical Invariants
|
|
73
|
-
|
|
74
|
-
1. Pot conservation.
|
|
75
|
-
2. Governance phase safety.
|
|
76
|
-
3. Quorum and grace-period correctness.
|
|
77
|
-
4. Settlement determinism once a scorecard is final.
|
|
78
|
-
5. Fee-token and reserve correctness.
|
|
79
|
-
|
|
80
|
-
## Attack Surfaces
|
|
81
|
-
|
|
82
|
-
- `DefifaGovernor` scorecard state transitions and ratification gating
|
|
83
|
-
- delegation, attestation, and quorum calculations
|
|
84
|
-
- `DefifaHook` cash-out weight and fee-token accounting
|
|
85
|
-
- reserve-related denominators during governance and settlement
|
|
86
|
-
- deployer logic that queues or fulfills lifecycle rulesets
|
|
87
|
-
|
|
88
|
-
## Accepted Risks Or Behaviors
|
|
89
|
-
|
|
90
|
-
- Governance and settlement are intentionally phase-heavy, so timestamp and lifecycle transitions are core audit targets rather than edge cases.
|
|
91
|
-
|
|
92
|
-
## Verification
|
|
93
|
-
|
|
94
|
-
- `npm install`
|
|
95
|
-
- `forge fmt --check`
|
|
96
|
-
- `forge build --deny notes`
|
|
97
|
-
- `forge build --deny notes --sizes --skip "*/test/**" --skip "*/script/**"`
|
|
98
|
-
- `forge build --deny notes --build-info --skip "*/test/**" --skip "*/script/**"`
|
|
99
|
-
- `forge test --deny notes`
|
|
100
|
-
- `npm pack --dry-run --json`
|