@ballkidz/defifa 0.0.17 → 0.0.18
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/ADMINISTRATION.md +34 -6
- package/ARCHITECTURE.md +54 -102
- package/AUDIT_INSTRUCTIONS.md +96 -504
- package/CHANGELOG.md +26 -0
- package/README.md +61 -207
- package/RISKS.md +19 -2
- package/SKILLS.md +29 -281
- package/STYLE_GUIDE.md +57 -18
- package/USER_JOURNEYS.md +45 -1011
- package/package.json +2 -2
- package/references/operations.md +27 -0
- package/references/runtime.md +32 -0
- package/src/DefifaDeployer.sol +10 -7
- package/src/DefifaHook.sol +2 -2
- package/src/interfaces/IDefifaDeployer.sol +28 -1
- package/src/interfaces/IDefifaGovernor.sol +26 -0
- package/src/interfaces/IDefifaHook.sol +30 -1
- package/CHANGE_LOG.md +0 -164
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ballkidz/defifa",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.18",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=20.0.0"
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"url": "https://github.com/BallKidz/defifa-collection-deployer"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@bananapus/721-hook-v6": "^0.0.
|
|
16
|
+
"@bananapus/721-hook-v6": "^0.0.30",
|
|
17
17
|
"@bananapus/address-registry-v6": "^0.0.16",
|
|
18
18
|
"@bananapus/core-v6": "^0.0.30",
|
|
19
19
|
"@bananapus/permission-ids-v6": "^0.0.15",
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Defifa Operations
|
|
2
|
+
|
|
3
|
+
## Deployment Surface
|
|
4
|
+
|
|
5
|
+
- [`src/DefifaDeployer.sol`](../src/DefifaDeployer.sol) is the first stop for launch-time config, phase queueing, and post-ratification fulfillment.
|
|
6
|
+
- [`script/Deploy.s.sol`](../script/Deploy.s.sol) is the deployment entry point when the task is about current wiring rather than game mechanics.
|
|
7
|
+
- [`src/structs/`](../src/structs/) and [`src/enums/`](../src/enums/) define launch data, phase types, and other inputs that often drift from remembered assumptions.
|
|
8
|
+
|
|
9
|
+
## Change Checklist
|
|
10
|
+
|
|
11
|
+
- If you edit lifecycle timing, verify phase transitions, no-contest triggers, and the governor's attestation windows together.
|
|
12
|
+
- If you edit hook settlement logic, re-check fee accounting and mint-cost invariants.
|
|
13
|
+
- If you touch governance thresholds or attestation behavior, inspect the governor tests before assuming the change is local.
|
|
14
|
+
- If you touch token metadata or rendering, verify whether the bug belongs in the resolver instead of settlement code.
|
|
15
|
+
|
|
16
|
+
## Common Failure Modes
|
|
17
|
+
|
|
18
|
+
- Game-state issue is blamed on the hook even though the deployer queued the wrong phase or timing.
|
|
19
|
+
- Governance behavior looks wrong, but the real issue is stale launch configuration.
|
|
20
|
+
- Settlement changes accidentally affect fee distribution or redemption accounting.
|
|
21
|
+
- Resolver issues get misdiagnosed as hook or governor problems because they surface through NFTs.
|
|
22
|
+
|
|
23
|
+
## Useful Proof Points
|
|
24
|
+
|
|
25
|
+
- [`test/Fork.t.sol`](../test/Fork.t.sol) for live-integration assumptions.
|
|
26
|
+
- [`test/TestAuditGaps.sol`](../test/TestAuditGaps.sol) and [`test/TestQALastMile.t.sol`](../test/TestQALastMile.t.sol) for pinned edge cases.
|
|
27
|
+
- [`test/BWAFunctionComparison.t.sol`](../test/BWAFunctionComparison.t.sol) and [`test/DefifaUSDC.t.sol`](../test/DefifaUSDC.t.sol) when currency or accounting context matters.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Defifa Runtime
|
|
2
|
+
|
|
3
|
+
## Contract Roles
|
|
4
|
+
|
|
5
|
+
- [`src/DefifaDeployer.sol`](../src/DefifaDeployer.sol) launches games, manages phase progression, fulfills commitments, and triggers safety exits such as no-contest.
|
|
6
|
+
- [`src/DefifaHook.sol`](../src/DefifaHook.sol) manages the NFT game pieces, delegation, and settlement-side cash-out behavior.
|
|
7
|
+
- [`src/DefifaGovernor.sol`](../src/DefifaGovernor.sol) handles scorecard submission, attestation, quorum, and ratification.
|
|
8
|
+
- [`src/DefifaTokenUriResolver.sol`](../src/DefifaTokenUriResolver.sol) renders game-card metadata.
|
|
9
|
+
- [`src/DefifaProjectOwner.sol`](../src/DefifaProjectOwner.sol) is the ownership helper for the fee project.
|
|
10
|
+
|
|
11
|
+
## Lifecycle
|
|
12
|
+
|
|
13
|
+
1. Countdown before minting opens.
|
|
14
|
+
2. Mint phase where players buy outcome NFTs and can delegate attestation power.
|
|
15
|
+
3. Optional refund phase.
|
|
16
|
+
4. Scoring phase where scorecards are submitted, attested, and ratified.
|
|
17
|
+
5. Complete or no-contest settlement depending on governance and safety conditions.
|
|
18
|
+
|
|
19
|
+
## High-Risk Areas
|
|
20
|
+
|
|
21
|
+
- Scorecard ratification and quorum assumptions: changes here directly affect who can settle the pot.
|
|
22
|
+
- No-contest and refund behavior: these paths are economic safety valves, not edge-case garnish.
|
|
23
|
+
- Fee accounting and commitment fulfillment: payout ordering and accounting drift can change final redemption value.
|
|
24
|
+
- Hook/governor/deployer coupling: many bugs come from changing one layer while assuming the others are passive.
|
|
25
|
+
|
|
26
|
+
## Tests To Trust First
|
|
27
|
+
|
|
28
|
+
- [`test/DefifaGovernor.t.sol`](../test/DefifaGovernor.t.sol) for governance flow.
|
|
29
|
+
- [`test/DefifaNoContest.t.sol`](../test/DefifaNoContest.t.sol) for safety exits.
|
|
30
|
+
- [`test/DefifaFeeAccounting.t.sol`](../test/DefifaFeeAccounting.t.sol) and [`test/DefifaMintCostInvariant.t.sol`](../test/DefifaMintCostInvariant.t.sol) for economic correctness.
|
|
31
|
+
- [`test/DefifaHookRegressions.t.sol`](../test/DefifaHookRegressions.t.sol) and [`test/regression/`](../test/regression/) for pinned regressions.
|
|
32
|
+
- [`test/DefifaSecurity.t.sol`](../test/DefifaSecurity.t.sol) and [`test/DefifaGovernanceHardening.t.sol`](../test/DefifaGovernanceHardening.t.sol) for adversarial cases.
|
package/src/DefifaDeployer.sol
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
JB721TiersRulesetMetadataResolver
|
|
8
8
|
} from "@bananapus/721-hook-v6/src/libraries/JB721TiersRulesetMetadataResolver.sol";
|
|
9
9
|
import {JB721TierConfig} from "@bananapus/721-hook-v6/src/structs/JB721TierConfig.sol";
|
|
10
|
+
import {JB721TierConfigFlags} from "@bananapus/721-hook-v6/src/structs/JB721TierConfigFlags.sol";
|
|
10
11
|
import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
|
|
11
12
|
import {IJBController, JBRulesetConfig, JBTerminalConfig} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
|
|
12
13
|
import {IJBMultiTerminal} from "@bananapus/core-v6/src/interfaces/IJBMultiTerminal.sol";
|
|
@@ -471,13 +472,15 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
|
|
|
471
472
|
encodedIPFSUri: defifaTier.encodedIPFSUri,
|
|
472
473
|
category: 0,
|
|
473
474
|
discountPercent: 0,
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
475
|
+
flags: JB721TierConfigFlags({
|
|
476
|
+
allowOwnerMint: false,
|
|
477
|
+
useReserveBeneficiaryAsDefault: defifaTier.shouldUseReservedTokenBeneficiaryAsDefault,
|
|
478
|
+
transfersPausable: false,
|
|
479
|
+
useVotingUnits: false,
|
|
480
|
+
cantBeRemoved: true,
|
|
481
|
+
cantIncreaseDiscountPercent: true,
|
|
482
|
+
cantBuyWithCredits: false
|
|
483
|
+
}),
|
|
481
484
|
splitPercent: 0,
|
|
482
485
|
splits: new JBSplit[](0)
|
|
483
486
|
});
|
package/src/DefifaHook.sol
CHANGED
|
@@ -882,7 +882,7 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
882
882
|
uint256[] memory tokenIds;
|
|
883
883
|
|
|
884
884
|
// Record the mint. The returned token IDs correspond to the tiers passed in.
|
|
885
|
-
// slither-disable-next-line reentrancy-benign
|
|
885
|
+
// slither-disable-next-line unused-return,reentrancy-benign
|
|
886
886
|
(tokenIds, leftoverAmount,) = store.recordMint({
|
|
887
887
|
amount: amount,
|
|
888
888
|
tierIds: mintTierIds,
|
|
@@ -1083,7 +1083,7 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
1083
1083
|
// Transfers must not be paused (when not minting or burning).
|
|
1084
1084
|
if (from != address(0)) {
|
|
1085
1085
|
// If transfers are pausable, check if they're paused.
|
|
1086
|
-
if (tier.transfersPausable) {
|
|
1086
|
+
if (tier.flags.transfersPausable) {
|
|
1087
1087
|
// Get a reference to the project's current ruleset.
|
|
1088
1088
|
JBRuleset memory ruleset = rulesets.currentOf(PROJECT_ID);
|
|
1089
1089
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity ^0.8.0;
|
|
3
3
|
|
|
4
|
-
import {IJB721TokenUriResolver} from "@bananapus/721-hook-v6/src/interfaces/IJB721TokenUriResolver.sol";
|
|
5
4
|
import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
|
|
5
|
+
import {IJB721TokenUriResolver} from "@bananapus/721-hook-v6/src/interfaces/IJB721TokenUriResolver.sol";
|
|
6
6
|
import {IJBController} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
|
|
7
7
|
import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
|
|
8
8
|
|
|
@@ -13,12 +13,30 @@ import {IDefifaHook} from "./IDefifaHook.sol";
|
|
|
13
13
|
/// @notice Deploys and manages Defifa prediction games, including lifecycle phase transitions
|
|
14
14
|
/// and commitment fulfillment.
|
|
15
15
|
interface IDefifaDeployer {
|
|
16
|
+
/// @notice Emitted when a commitment payout fails during fulfillment.
|
|
17
|
+
/// @param gameId The ID of the game being fulfilled.
|
|
18
|
+
/// @param amount The amount that failed to pay out.
|
|
19
|
+
/// @param reason The revert reason bytes from the failed payout.
|
|
16
20
|
event CommitmentPayoutFailed(uint256 indexed gameId, uint256 amount, bytes reason);
|
|
17
21
|
|
|
22
|
+
/// @notice Emitted when a split receives a portion of the game pot.
|
|
23
|
+
/// @param split The split that received funds.
|
|
24
|
+
/// @param amount The amount sent to the split.
|
|
25
|
+
/// @param caller The address that triggered the distribution.
|
|
18
26
|
event DistributeToSplit(JBSplit split, uint256 amount, address caller);
|
|
19
27
|
|
|
28
|
+
/// @notice Emitted when a game's commitments have been fulfilled.
|
|
29
|
+
/// @param gameId The ID of the fulfilled game.
|
|
30
|
+
/// @param pot The total game pot that was fulfilled.
|
|
31
|
+
/// @param caller The address that triggered fulfillment.
|
|
20
32
|
event FulfilledCommitments(uint256 indexed gameId, uint256 pot, address caller);
|
|
21
33
|
|
|
34
|
+
/// @notice Emitted when a new Defifa game is launched.
|
|
35
|
+
/// @param gameId The ID of the launched game.
|
|
36
|
+
/// @param hook The hook deployed for the game.
|
|
37
|
+
/// @param governor The governor responsible for scorecard ratification.
|
|
38
|
+
/// @param tokenUriResolver The token URI resolver used for the game's NFTs.
|
|
39
|
+
/// @param caller The address that launched the game.
|
|
22
40
|
event LaunchGame(
|
|
23
41
|
uint256 indexed gameId,
|
|
24
42
|
IDefifaHook indexed hook,
|
|
@@ -27,10 +45,19 @@ interface IDefifaDeployer {
|
|
|
27
45
|
address caller
|
|
28
46
|
);
|
|
29
47
|
|
|
48
|
+
/// @notice Emitted when a game is queued into its no-contest phase.
|
|
49
|
+
/// @param gameId The ID of the game.
|
|
50
|
+
/// @param caller The address that queued the phase transition.
|
|
30
51
|
event QueuedNoContest(uint256 indexed gameId, address caller);
|
|
31
52
|
|
|
53
|
+
/// @notice Emitted when a game is queued into its refund phase.
|
|
54
|
+
/// @param gameId The ID of the game.
|
|
55
|
+
/// @param caller The address that queued the phase transition.
|
|
32
56
|
event QueuedRefundPhase(uint256 indexed gameId, address caller);
|
|
33
57
|
|
|
58
|
+
/// @notice Emitted when a game is queued into its scoring phase.
|
|
59
|
+
/// @param gameId The ID of the game.
|
|
60
|
+
/// @param caller The address that queued the phase transition.
|
|
34
61
|
event QueuedScoringPhase(uint256 indexed gameId, address caller);
|
|
35
62
|
|
|
36
63
|
/// @notice The fee divisor for base protocol fees (100 / fee percent).
|
|
@@ -8,6 +8,12 @@ import {DefifaTierCashOutWeight} from "../structs/DefifaTierCashOutWeight.sol";
|
|
|
8
8
|
|
|
9
9
|
/// @notice Manages the ratification of Defifa scorecards through attestation-based governance.
|
|
10
10
|
interface IDefifaGovernor {
|
|
11
|
+
/// @notice Emitted when governance is initialized for a game.
|
|
12
|
+
/// @param gameId The ID of the game.
|
|
13
|
+
/// @param attestationStartTime The timestamp when attestation begins.
|
|
14
|
+
/// @param attestationGracePeriod The grace period after attestation begins.
|
|
15
|
+
/// @param timelockDuration The timelock duration after quorum is met.
|
|
16
|
+
/// @param caller The address that initialized the game.
|
|
11
17
|
event GameInitialized(
|
|
12
18
|
uint256 indexed gameId,
|
|
13
19
|
uint256 attestationStartTime,
|
|
@@ -16,10 +22,25 @@ interface IDefifaGovernor {
|
|
|
16
22
|
address caller
|
|
17
23
|
);
|
|
18
24
|
|
|
25
|
+
/// @notice Emitted when an account attests to a scorecard.
|
|
26
|
+
/// @param gameId The ID of the game.
|
|
27
|
+
/// @param scorecardId The ID of the scorecard being attested to.
|
|
28
|
+
/// @param weight The attestation weight applied.
|
|
29
|
+
/// @param caller The address that submitted the attestation.
|
|
19
30
|
event ScorecardAttested(uint256 indexed gameId, uint256 indexed scorecardId, uint256 weight, address caller);
|
|
20
31
|
|
|
32
|
+
/// @notice Emitted when a scorecard is ratified.
|
|
33
|
+
/// @param gameId The ID of the game.
|
|
34
|
+
/// @param scorecardId The ID of the ratified scorecard.
|
|
35
|
+
/// @param caller The address that ratified the scorecard.
|
|
21
36
|
event ScorecardRatified(uint256 indexed gameId, uint256 indexed scorecardId, address caller);
|
|
22
37
|
|
|
38
|
+
/// @notice Emitted when a scorecard is submitted for attestation.
|
|
39
|
+
/// @param gameId The ID of the game.
|
|
40
|
+
/// @param scorecardId The ID of the submitted scorecard.
|
|
41
|
+
/// @param tierWeights The proposed tier cash out weights.
|
|
42
|
+
/// @param isDefaultAttestationDelegate Whether the submitter is the default attestation delegate.
|
|
43
|
+
/// @param caller The address that submitted the scorecard.
|
|
23
44
|
event ScorecardSubmitted(
|
|
24
45
|
uint256 indexed gameId,
|
|
25
46
|
uint256 indexed scorecardId,
|
|
@@ -28,6 +49,11 @@ interface IDefifaGovernor {
|
|
|
28
49
|
address caller
|
|
29
50
|
);
|
|
30
51
|
|
|
52
|
+
/// @notice Emitted when an attestation is revoked from a scorecard.
|
|
53
|
+
/// @param gameId The ID of the game.
|
|
54
|
+
/// @param scorecardId The ID of the scorecard.
|
|
55
|
+
/// @param account The address whose attestation was revoked.
|
|
56
|
+
/// @param weight The revoked attestation weight.
|
|
31
57
|
event AttestationRevoked(uint256 indexed gameId, uint256 indexed scorecardId, address account, uint256 weight);
|
|
32
58
|
|
|
33
59
|
/// @notice The number of attestations for a scorecard.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity ^0.8.0;
|
|
3
3
|
|
|
4
|
-
import {IJB721Hook} from "@bananapus/721-hook-v6/src/interfaces/IJB721Hook.sol";
|
|
5
4
|
import {IJB721TiersHookStore} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHookStore.sol";
|
|
6
5
|
import {IJB721TokenUriResolver} from "@bananapus/721-hook-v6/src/interfaces/IJB721TokenUriResolver.sol";
|
|
6
|
+
import {IJB721Hook} from "@bananapus/721-hook-v6/src/interfaces/IJB721Hook.sol";
|
|
7
7
|
import {JB721TierConfig} from "@bananapus/721-hook-v6/src/structs/JB721TierConfig.sol";
|
|
8
8
|
import {JB721TiersMintReservesConfig} from "@bananapus/721-hook-v6/src/structs/JB721TiersMintReservesConfig.sol";
|
|
9
9
|
import {IJBRulesets} from "@bananapus/core-v6/src/interfaces/IJBRulesets.sol";
|
|
@@ -17,6 +17,12 @@ import {IDefifaGamePotReporter} from "./IDefifaGamePotReporter.sol";
|
|
|
17
17
|
/// @notice The hook interface for Defifa games, extending the 721 hook with game-specific attestation delegation,
|
|
18
18
|
/// scorecard-based cash out weights, and token claiming.
|
|
19
19
|
interface IDefifaHook is IJB721Hook {
|
|
20
|
+
/// @notice Emitted when an NFT is minted from a contribution.
|
|
21
|
+
/// @param tokenId The token ID of the minted NFT.
|
|
22
|
+
/// @param tierId The tier the NFT was minted from.
|
|
23
|
+
/// @param beneficiary The address that received the NFT.
|
|
24
|
+
/// @param totalAmountContributed The total amount contributed in the minting transaction.
|
|
25
|
+
/// @param caller The address that triggered the mint.
|
|
20
26
|
event Mint(
|
|
21
27
|
uint256 indexed tokenId,
|
|
22
28
|
uint256 indexed tierId,
|
|
@@ -25,20 +31,43 @@ interface IDefifaHook is IJB721Hook {
|
|
|
25
31
|
address caller
|
|
26
32
|
);
|
|
27
33
|
|
|
34
|
+
/// @notice Emitted when a reserved token is minted.
|
|
35
|
+
/// @param tokenId The token ID of the minted reserved token.
|
|
36
|
+
/// @param tierId The tier the reserved token was minted from.
|
|
37
|
+
/// @param beneficiary The address that received the reserved token.
|
|
38
|
+
/// @param caller The address that triggered the mint.
|
|
28
39
|
event MintReservedToken(
|
|
29
40
|
uint256 indexed tokenId, uint256 indexed tierId, address indexed beneficiary, address caller
|
|
30
41
|
);
|
|
31
42
|
|
|
43
|
+
/// @notice Emitted when a delegate's attestation balance changes for a tier.
|
|
44
|
+
/// @param delegate The delegate whose attestation balance changed.
|
|
45
|
+
/// @param tierId The tier whose attestation balance changed.
|
|
46
|
+
/// @param previousBalance The prior attestation balance.
|
|
47
|
+
/// @param newBalance The updated attestation balance.
|
|
48
|
+
/// @param caller The address that triggered the change.
|
|
32
49
|
event TierDelegateAttestationsChanged(
|
|
33
50
|
address indexed delegate, uint256 indexed tierId, uint256 previousBalance, uint256 newBalance, address caller
|
|
34
51
|
);
|
|
35
52
|
|
|
53
|
+
/// @notice Emitted when a delegator changes delegates for a tier.
|
|
54
|
+
/// @param delegator The address changing its delegate.
|
|
55
|
+
/// @param fromDelegate The previous delegate.
|
|
56
|
+
/// @param toDelegate The new delegate.
|
|
36
57
|
event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
|
|
37
58
|
|
|
59
|
+
/// @notice Emitted when claimable game tokens are claimed.
|
|
60
|
+
/// @param beneficiary The address receiving the claimed tokens.
|
|
61
|
+
/// @param defifaTokenAmount The amount of Defifa tokens claimed.
|
|
62
|
+
/// @param baseProtocolTokenAmount The amount of base protocol tokens claimed.
|
|
63
|
+
/// @param caller The address that triggered the claim.
|
|
38
64
|
event ClaimedTokens(
|
|
39
65
|
address indexed beneficiary, uint256 defifaTokenAmount, uint256 baseProtocolTokenAmount, address caller
|
|
40
66
|
);
|
|
41
67
|
|
|
68
|
+
/// @notice Emitted when tier cash out weights are set.
|
|
69
|
+
/// @param tierWeights The cash out weights that were set for each tier.
|
|
70
|
+
/// @param caller The address that set the tier weights.
|
|
42
71
|
event TierCashOutWeightsSet(DefifaTierCashOutWeight[] tierWeights, address caller);
|
|
43
72
|
|
|
44
73
|
/// @notice The total amount redeemed from this game (refunds not counted).
|
package/CHANGE_LOG.md
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
# defifa-collection-deployer-v6 Changelog (v5 → v6)
|
|
2
|
-
|
|
3
|
-
This document describes the changes between `defifa-collection-deployer` (v5) and `defifa-collection-deployer-v6` (v6). Defifa is an on-chain prediction game framework built on Juicebox where players mint NFTs representing outcomes, a governor ratifies scorecard distributions, and winners burn NFTs to claim proportional shares.
|
|
4
|
-
|
|
5
|
-
## Summary
|
|
6
|
-
|
|
7
|
-
- **V6 hook migration**: All 721 hook interactions updated from `nana-721-hook-v5` to `nana-721-hook-v6`, including the new tier splits system and `splitPercent` field in `JB721TierConfig`.
|
|
8
|
-
- **Dependency modernization**: Core, permission IDs, address registry, and ownable dependencies all updated to v6. New ecosystem dependencies on `croptop-core-v6` and `revnet-core-v6`.
|
|
9
|
-
- **Error naming standardized**: Error names changed from bare names (e.g., `InvalidCashoutWeights`) to contract-prefixed names (e.g., `DefifaHook_InvalidCashoutWeights`).
|
|
10
|
-
- **Cash out hook spec gains `noop` field**: `beforeCashOutRecordedWith` now returns `noop=false` in all specifications, ensuring the terminal always calls the hook callback.
|
|
11
|
-
- **Compiler/tooling updated**: The v6 repo now builds and tests on Solidity `0.8.28`, matching the rest of the V6 ecosystem.
|
|
12
|
-
- **Game lifecycle preserved**: The core game phases (COUNTDOWN → MINT → REFUND → SCORING → COMPLETE) and governance model (50% quorum, scorecard ratification) remain the same at the product level even though the underlying hook/controller integrations changed.
|
|
13
|
-
|
|
14
|
-
## ABI Status
|
|
15
|
-
|
|
16
|
-
This repo does have meaningful ABI migration surface. The main ABI-facing contracts for integrators are:
|
|
17
|
-
- `IDefifaDeployer`
|
|
18
|
-
- `IDefifaHook`
|
|
19
|
-
- `IDefifaGovernor`
|
|
20
|
-
|
|
21
|
-
The largest ABI risks are:
|
|
22
|
-
- inherited 721-hook/core-v6 struct and return-shape changes flowing through Defifa interfaces;
|
|
23
|
-
- event families now living on v6 interfaces/contracts with prefixed errors and updated dependent types;
|
|
24
|
-
- hook return values that now include v6 `noop`-aware hook-spec structures.
|
|
25
|
-
|
|
26
|
-
---
|
|
27
|
-
|
|
28
|
-
## 1. Breaking Changes
|
|
29
|
-
|
|
30
|
-
### 1.1 Dependency Updates
|
|
31
|
-
|
|
32
|
-
| Dependency | v5 | v6 |
|
|
33
|
-
|------------|----|----|
|
|
34
|
-
| `@bananapus/core` | `v5` | `v6` |
|
|
35
|
-
| `@bananapus/721-hook` | `v5` | `v6` |
|
|
36
|
-
| `@bananapus/address-registry` | `v5` | `v6` |
|
|
37
|
-
| `@bananapus/permission-ids` | `v5` | `v6` (new dependency) |
|
|
38
|
-
| `@openzeppelin/contracts` | `^5.4.0` | `5.2.0` (pinned) |
|
|
39
|
-
| `@croptop/core` | N/A | `v6` (new) |
|
|
40
|
-
| `@rev-net/core` | N/A | `v6` (new) |
|
|
41
|
-
|
|
42
|
-
### 1.2 Error Naming Convention
|
|
43
|
-
|
|
44
|
-
All custom errors now use a contract-name prefix:
|
|
45
|
-
|
|
46
|
-
| v5 | v6 |
|
|
47
|
-
|----|----|
|
|
48
|
-
| `InvalidCashoutWeights` | `DefifaHook_InvalidCashoutWeights` |
|
|
49
|
-
| `InvalidPhase` | `DefifaHook_InvalidPhase` |
|
|
50
|
-
| (and similar for all other errors) | Contract prefix added throughout |
|
|
51
|
-
|
|
52
|
-
### 1.3 `JBCashOutHookSpecification` Gains `noop` Field
|
|
53
|
-
|
|
54
|
-
The v6 `JBCashOutHookSpecification` struct has a `noop` boolean field. `DefifaHook.beforeCashOutRecordedWith` returns `noop=false` in all specifications, ensuring the terminal always invokes `afterCashOutRecordedWith` for game-phase-aware cashout processing.
|
|
55
|
-
|
|
56
|
-
### 1.4 Solidity Version
|
|
57
|
-
|
|
58
|
-
- **v5:** `pragma solidity 0.8.23`
|
|
59
|
-
- **v6:** `pragma solidity 0.8.28`
|
|
60
|
-
|
|
61
|
-
### 1.5 721 Hook API Changes
|
|
62
|
-
|
|
63
|
-
Inherited from `nana-721-hook-v6`:
|
|
64
|
-
- `cashOutWeightOf()` and `totalCashOutWeight()` signatures simplified (removed `JBBeforeCashOutRecordedContext` parameter)
|
|
65
|
-
- `pricingContext()` returns 2 values instead of 3
|
|
66
|
-
- `JB721TierConfig` gained `splitPercent` and `splits` fields
|
|
67
|
-
- `JB721TiersHookFlags` gained `issueTokensForSplits` field
|
|
68
|
-
|
|
69
|
-
### 1.6 Function-Level Integration Changes
|
|
70
|
-
|
|
71
|
-
These are the main V6 surface changes integrators should care about:
|
|
72
|
-
- `beforeCashOutRecordedWith(...)` now returns a `JBCashOutHookSpecification` that includes the new `noop` field from core-v6.
|
|
73
|
-
- Any integration constructing or decoding `JB721TierConfig` must account for the added `splitPercent` and `splits` fields.
|
|
74
|
-
- Any integration reading pricing context from the inherited 721 hook must expect 2 return values, not 3.
|
|
75
|
-
- Defifa deployer integrations should re-check `launchGameWith(...)`, `fulfillCommitmentsOf(...)`, `triggerNoContestFor(...)`, `nextPhaseNeedsQueueing(...)`, `safetyParamsOf(...)`, and `timesFor(...)` against the v6 ABIs and dependent core-v6 structs.
|
|
76
|
-
|
|
77
|
-
---
|
|
78
|
-
|
|
79
|
-
## 2. Game Lifecycle (Unchanged)
|
|
80
|
-
|
|
81
|
-
The core game phases remain identical between v5 and v6:
|
|
82
|
-
|
|
83
|
-
```
|
|
84
|
-
COUNTDOWN (ruleset 0) → MINT (ruleset 1) → REFUND (ruleset 2)
|
|
85
|
-
→ SCORING (ruleset 3+) → COMPLETE (after ratification)
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
Safety mechanisms:
|
|
89
|
-
- **NO_CONTEST**: Triggered if `minParticipation` not met or `scorecardTimeout` exceeded
|
|
90
|
-
- **Scorecard governance**: 50% quorum, tier-delegated voting power with checkpointed snapshots
|
|
91
|
-
- **Grace period**: Minimum 1 day for governance proposals
|
|
92
|
-
|
|
93
|
-
---
|
|
94
|
-
|
|
95
|
-
## 3. Architecture
|
|
96
|
-
|
|
97
|
-
### 3.1 Key Contracts
|
|
98
|
-
|
|
99
|
-
| Contract | Role |
|
|
100
|
-
|----------|------|
|
|
101
|
-
| `DefifaDeployer` | Game factory -- launches projects with phased rulesets, manages fulfillment |
|
|
102
|
-
| `DefifaHook` | ERC-721 hook with game logic, attestation, per-tier cashout weights |
|
|
103
|
-
| `DefifaGovernor` | Shared singleton for scorecard submission/attestation/ratification |
|
|
104
|
-
| `DefifaProjectOwner` | Proxy that receives project NFT and grants deployer permissions |
|
|
105
|
-
| `DefifaTokenUriResolver` | On-chain SVG metadata with dynamic game state |
|
|
106
|
-
|
|
107
|
-
### 3.2 Deployment Pattern
|
|
108
|
-
|
|
109
|
-
DefifaHook instances are deployed as minimal proxy clones via `Clones.cloneDeterministic()`:
|
|
110
|
-
- Salt includes `msg.sender` + nonce (prevents cross-caller collision)
|
|
111
|
-
- One-time `initialize()` call per clone
|
|
112
|
-
- Owned by DefifaGovernor for scorecard weight setting
|
|
113
|
-
|
|
114
|
-
## 4. Events and Errors
|
|
115
|
-
|
|
116
|
-
The most important integration-facing patterns are:
|
|
117
|
-
- Errors are now consistently contract-prefixed (`DefifaHook_*`, `DefifaDeployer_*`, `DefifaGovernor_*`, `DefifaProjectOwner_*`) instead of using the older unprefixed style.
|
|
118
|
-
- Defifa-specific events remain centered around game launch, phase transitions, fulfillment, scoring, minting, claims, and delegation, but they now live against the V6 hook/controller stack and should be indexed using the V6 ABIs.
|
|
119
|
-
- `CommitmentPayoutFailed`, `LaunchGame`, `QueuedRefundPhase`, `QueuedScoringPhase`, `QueuedNoContest`, `GameInitialized`, `ScorecardSubmitted`, `ScorecardAttested`, `ScorecardRatified`, `Mint`, `MintReservedToken`, `ClaimedTokens`, and `TierCashOutWeightsSet` are the key integration events to watch across the deployer, governor, and hook.
|
|
120
|
-
- Other hook-level events worth indexing for governance clients are `TierDelegateAttestationsChanged` and `DelegateChanged`.
|
|
121
|
-
|
|
122
|
-
Key runtime errors now exposed by the v6 contracts include:
|
|
123
|
-
- `DefifaDeployer_*` errors such as `DefifaDeployer_InvalidGameConfiguration`, `DefifaDeployer_TerminalNotFound`, `DefifaDeployer_SplitsDontAddUp`, `DefifaDeployer_CantFulfillYet`, and `DefifaDeployer_NoContestAlreadyTriggered`.
|
|
124
|
-
- `DefifaHook_*` errors such as `DefifaHook_InvalidCashoutWeights`, `DefifaHook_InvalidTierId`, `DefifaHook_ReservedTokenMintingPaused`, `DefifaHook_TransfersPaused`, and `DefifaHook_Unauthorized(...)`.
|
|
125
|
-
- `DefifaGovernor_*` errors such as `DefifaGovernor_AlreadyAttested`, `DefifaGovernor_AlreadyRatified`, `DefifaGovernor_DuplicateScorecard`, `DefifaGovernor_NotAllowed`, and `DefifaGovernor_UnknownProposal`.
|
|
126
|
-
|
|
127
|
-
---
|
|
128
|
-
|
|
129
|
-
## 5. Migration Table
|
|
130
|
-
|
|
131
|
-
| Aspect | v5 | v6 |
|
|
132
|
-
|--------|----|----|
|
|
133
|
-
| Core dependency | `@bananapus/core-v5` | `@bananapus/core-v6` |
|
|
134
|
-
| 721 hook dependency | `@bananapus/721-hook-v5` | `@bananapus/721-hook-v6` |
|
|
135
|
-
| Permission IDs | Not a direct dependency | `@bananapus/permission-ids-v6` |
|
|
136
|
-
| Error naming | Bare names | Contract-prefixed names |
|
|
137
|
-
| `JBCashOutHookSpecification` | No `noop` field | `noop=false` on all specs |
|
|
138
|
-
| Solidity version | `0.8.23` | `0.8.28` |
|
|
139
|
-
| Game lifecycle | COUNTDOWN->MINT->REFUND->SCORING->COMPLETE | Identical |
|
|
140
|
-
| Governance model | 50% quorum, tier-delegated | Identical |
|
|
141
|
-
|
|
142
|
-
> **Cross-repo impact**: Uses `nana-721-hook-v6` for all tier management and cashout weight distribution. The `nana-permission-ids-v6` ID shifts affect any hardcoded permission checks. `deploy-all-v6` now includes Defifa as Phase 10, so canonical deployments can source Defifa addresses from the top-level rollout.
|
|
143
|
-
|
|
144
|
-
---
|
|
145
|
-
|
|
146
|
-
## 6. Post-Audit Fixes (Codex R2)
|
|
147
|
-
|
|
148
|
-
### 6.1 H-1: Prevent same-block double attestation via checkpoint snapshot
|
|
149
|
-
|
|
150
|
-
**File:** `DefifaGovernor.sol` -- `attestToScorecardFrom()`
|
|
151
|
-
|
|
152
|
-
Previously, attestation weight was snapshot at `_scorecard.attestationsBegin`, which could equal `block.timestamp` during the same block as a transfer. This allowed a holder to attest, transfer the NFT, and have the recipient also attest in the same block -- both counting because `upperLookup(block.timestamp)` includes same-block checkpoints.
|
|
153
|
-
|
|
154
|
-
**Fix:** Changed the checkpoint timestamp to `attestationsBegin - 1`, ensuring only state from before the attestation window opens is visible. Same-block transfer recipients now receive zero attestation weight. Note: NFTs minted in the same block as `attestationsBegin` have zero weight for attestation -- a negligible trade-off since attestation typically happens well after minting.
|
|
155
|
-
|
|
156
|
-
### 6.2 H-2: Snapshot pending reserves at scorecard submission and include in denominators
|
|
157
|
-
|
|
158
|
-
**Files:** `DefifaGovernor.sol` -- `submitScorecardFor()`, `getBWAAttestationWeight()`; `DefifaHook.sol` -- `afterCashOutRecordedWith()`
|
|
159
|
-
|
|
160
|
-
Two related fixes to prevent gaming via pending reserve manipulation:
|
|
161
|
-
|
|
162
|
-
**Governance (attestation weight):** Previously, `getBWAAttestationWeight()` read pending reserve counts live from the store. Minting reserves between scorecard submission and attestation could inflate a holder's BWA power by removing the pending-reserve dilution. **Fix:** `submitScorecardFor()` now snapshots `numberOfPendingReservesFor()` for every tier into `_pendingReservesSnapshotOf[gameId][scorecardId][tierId]`. `getBWAAttestationWeight()` reads from this snapshot instead of live state, locking the dilution in place regardless of subsequent reserve minting.
|
|
163
|
-
|
|
164
|
-
**Cash-out (fee token distribution):** Previously, the fee token claim denominator (`_totalMintCost`) only counted minted tokens. Pending (unminted) reserve NFTs were excluded, allowing paid holders to cash out before reserves were minted and claim a disproportionate share of fee tokens ($DEFIFA/$NANA). **Fix:** `afterCashOutRecordedWith()` now passes `_totalMintCost + _pendingReserveMintCost()` as the denominator when distributing fee tokens. The new `_pendingReserveMintCost()` function iterates all tiers and sums `pendingReserves * tier.price`, ensuring pending reserves are accounted for in fee token distribution.
|