@ballkidz/defifa 0.0.25 → 0.0.27
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/AUDIT_INSTRUCTIONS.md +6 -2
- package/README.md +11 -2
- package/RISKS.md +3 -1
- package/STYLE_GUIDE.md +14 -11
- package/package.json +31 -14
- package/script/Deploy.s.sol +4 -1
- package/src/DefifaDeployer.sol +79 -47
- package/src/DefifaGovernor.sol +57 -12
- package/src/DefifaHook.sol +83 -26
- package/src/DefifaProjectOwner.sol +4 -3
- package/src/DefifaTokenUriResolver.sol +113 -20
- package/src/enums/DefifaGamePhase.sol +6 -0
- package/src/enums/DefifaScorecardState.sol +4 -0
- package/src/interfaces/IDefifaDeployer.sol +5 -0
- package/src/interfaces/IDefifaGamePhaseReporter.sol +4 -0
- package/src/interfaces/IDefifaGamePotReporter.sol +10 -0
- package/src/interfaces/IDefifaGovernor.sol +4 -0
- package/src/interfaces/IDefifaHook.sol +5 -0
- package/src/interfaces/IDefifaTokenUriResolver.sol +3 -0
- package/src/libraries/DefifaFontImporter.sol +1 -1
- package/src/libraries/DefifaHookLib.sol +9 -10
- package/src/structs/DefifaAttestations.sol +3 -2
- package/src/structs/DefifaDelegation.sol +1 -0
- package/src/structs/DefifaLaunchProjectData.sol +2 -3
- package/src/structs/DefifaOpsData.sol +1 -0
- package/src/structs/DefifaScorecard.sol +2 -0
- package/src/structs/DefifaTierCashOutWeight.sol +3 -1
- package/src/structs/DefifaTierParams.sol +1 -0
- package/CRYPTO_ECON.pdf +0 -0
- package/CRYPTO_ECON.tex +0 -997
- package/foundry.lock +0 -17
- package/references/operations.md +0 -32
- package/references/runtime.md +0 -43
- package/slither-ci.config.json +0 -10
- package/sphinx.lock +0 -521
- package/test/BWAFunctionComparison.t.sol +0 -1320
- package/test/DefifaAdversarialQuorum.t.sol +0 -617
- package/test/DefifaAuditLowGuards.t.sol +0 -308
- package/test/DefifaFeeAccounting.t.sol +0 -581
- package/test/DefifaGovernanceHardening.t.sol +0 -1315
- package/test/DefifaGovernor.t.sol +0 -1378
- package/test/DefifaHookRegressions.t.sol +0 -415
- package/test/DefifaMintCostInvariant.t.sol +0 -319
- package/test/DefifaNoContest.t.sol +0 -941
- package/test/DefifaSecurity.t.sol +0 -741
- package/test/DefifaUSDC.t.sol +0 -480
- package/test/Fork.t.sol +0 -2388
- package/test/TestAuditGaps.sol +0 -984
- package/test/TestQALastMile.t.sol +0 -514
- package/test/audit/AttestationDoubleCount.t.sol +0 -218
- package/test/audit/CodexNemesisCurrencyMismatchBypass.t.sol +0 -112
- package/test/audit/CodexNemesisNoContestReserveDrain.t.sol +0 -238
- package/test/audit/CodexNemesisOneTierZeroTimeoutLockVerified.t.sol +0 -218
- package/test/audit/CodexNemesisSingleTierTimeoutLock.t.sol +0 -237
- package/test/audit/CodexRegistryMismatch.t.sol +0 -191
- package/test/audit/CodexTierCapMismatch.t.sol +0 -171
- package/test/audit/CurrencyMismatchFix.t.sol +0 -265
- package/test/audit/FixPendingReserveDilution.t.sol +0 -366
- package/test/audit/H5TierCapValidation.t.sol +0 -184
- package/test/audit/PendingReserveDilution.t.sol +0 -298
- package/test/audit/PendingReserveQuorumGrief.t.sol +0 -355
- package/test/audit/PendingReserveSnapshotBypass.t.sol +0 -319
- package/test/regression/AttestationDelegateBeneficiary.t.sol +0 -271
- package/test/regression/FulfillmentBlocksRatification.t.sol +0 -279
- package/test/regression/GracePeriodBypass.t.sol +0 -302
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: UNLICENSED
|
|
2
|
-
pragma solidity 0.8.28;
|
|
3
|
-
|
|
4
|
-
import {DefifaDeployer} from "../../src/DefifaDeployer.sol";
|
|
5
|
-
import {DefifaGovernor} from "../../src/DefifaGovernor.sol";
|
|
6
|
-
import {DefifaHook} from "../../src/DefifaHook.sol";
|
|
7
|
-
import {DefifaTokenUriResolver} from "../../src/DefifaTokenUriResolver.sol";
|
|
8
|
-
import {DefifaGamePhase} from "../../src/enums/DefifaGamePhase.sol";
|
|
9
|
-
import {DefifaLaunchProjectData} from "../../src/structs/DefifaLaunchProjectData.sol";
|
|
10
|
-
import {DefifaTierCashOutWeight} from "../../src/structs/DefifaTierCashOutWeight.sol";
|
|
11
|
-
import {DefifaTierParams} from "../../src/structs/DefifaTierParams.sol";
|
|
12
|
-
|
|
13
|
-
import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
|
|
14
|
-
import {IJB721TokenUriResolver} from "@bananapus/721-hook-v6/src/interfaces/IJB721TokenUriResolver.sol";
|
|
15
|
-
import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
|
|
16
|
-
import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
|
|
17
|
-
import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
|
|
18
|
-
import {JBCurrencyIds} from "@bananapus/core-v6/src/libraries/JBCurrencyIds.sol";
|
|
19
|
-
import {JBFundAccessLimitGroup} from "@bananapus/core-v6/src/structs/JBFundAccessLimitGroup.sol";
|
|
20
|
-
import {JBRuleset} from "@bananapus/core-v6/src/structs/JBRuleset.sol";
|
|
21
|
-
import {JBRulesetConfig} from "@bananapus/core-v6/src/structs/JBRulesetConfig.sol";
|
|
22
|
-
import {JBRulesetMetadataResolver} from "@bananapus/core-v6/src/libraries/JBRulesetMetadataResolver.sol";
|
|
23
|
-
import {JBRulesetMetadata} from "@bananapus/core-v6/src/structs/JBRulesetMetadata.sol";
|
|
24
|
-
import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
|
|
25
|
-
import {JBSplitGroup} from "@bananapus/core-v6/src/structs/JBSplitGroup.sol";
|
|
26
|
-
import {JBTerminalConfig} from "@bananapus/core-v6/src/structs/JBTerminalConfig.sol";
|
|
27
|
-
import {IJBRulesetApprovalHook} from "@bananapus/core-v6/src/interfaces/IJBRulesets.sol";
|
|
28
|
-
import {JBTest} from "@bananapus/core-v6/test/helpers/JBTest.sol";
|
|
29
|
-
import {TestBaseWorkflow} from "@bananapus/core-v6/test/helpers/TestBaseWorkflow.sol";
|
|
30
|
-
|
|
31
|
-
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
32
|
-
import {ITypeface} from "lib/typeface/contracts/interfaces/ITypeface.sol";
|
|
33
|
-
|
|
34
|
-
contract CodexTierCapMismatchTest is JBTest, TestBaseWorkflow {
|
|
35
|
-
using JBRulesetMetadataResolver for JBRuleset;
|
|
36
|
-
|
|
37
|
-
DefifaDeployer internal deployer;
|
|
38
|
-
DefifaGovernor internal governor;
|
|
39
|
-
DefifaHook internal hookCodeOrigin;
|
|
40
|
-
|
|
41
|
-
function setUp() public virtual override {
|
|
42
|
-
super.setUp();
|
|
43
|
-
|
|
44
|
-
JBAccountingContext[] memory tokens = new JBAccountingContext[](1);
|
|
45
|
-
tokens[0] = JBAccountingContext({token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: JBCurrencyIds.ETH});
|
|
46
|
-
|
|
47
|
-
JBTerminalConfig[] memory terminalConfigs = new JBTerminalConfig[](1);
|
|
48
|
-
terminalConfigs[0] = JBTerminalConfig({terminal: jbMultiTerminal(), accountingContextsToAccept: tokens});
|
|
49
|
-
|
|
50
|
-
JBRulesetConfig[] memory rulesetConfigs = new JBRulesetConfig[](1);
|
|
51
|
-
rulesetConfigs[0] = JBRulesetConfig({
|
|
52
|
-
mustStartAtOrAfter: 0,
|
|
53
|
-
duration: 10 days,
|
|
54
|
-
weight: 1e18,
|
|
55
|
-
weightCutPercent: 0,
|
|
56
|
-
approvalHook: IJBRulesetApprovalHook(address(0)),
|
|
57
|
-
metadata: JBRulesetMetadata({
|
|
58
|
-
reservedPercent: 0,
|
|
59
|
-
cashOutTaxRate: 0,
|
|
60
|
-
baseCurrency: JBCurrencyIds.ETH,
|
|
61
|
-
pausePay: false,
|
|
62
|
-
pauseCreditTransfers: false,
|
|
63
|
-
allowOwnerMinting: false,
|
|
64
|
-
allowSetCustomToken: false,
|
|
65
|
-
allowTerminalMigration: false,
|
|
66
|
-
allowSetTerminals: false,
|
|
67
|
-
allowSetController: false,
|
|
68
|
-
allowAddAccountingContext: false,
|
|
69
|
-
allowAddPriceFeed: false,
|
|
70
|
-
ownerMustSendPayouts: false,
|
|
71
|
-
holdFees: false,
|
|
72
|
-
useTotalSurplusForCashOuts: false,
|
|
73
|
-
useDataHookForPay: true,
|
|
74
|
-
useDataHookForCashOut: true,
|
|
75
|
-
dataHook: address(0),
|
|
76
|
-
metadata: 0
|
|
77
|
-
}),
|
|
78
|
-
splitGroups: new JBSplitGroup[](0),
|
|
79
|
-
fundAccessLimitGroups: new JBFundAccessLimitGroup[](0)
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
address projectOwner = address(bytes20(keccak256("projectOwner")));
|
|
83
|
-
uint256 protocolFeeProjectId =
|
|
84
|
-
jbController().launchProjectFor(projectOwner, "", rulesetConfigs, terminalConfigs, "");
|
|
85
|
-
vm.prank(projectOwner);
|
|
86
|
-
address nanaToken =
|
|
87
|
-
address(jbController().deployERC20For(protocolFeeProjectId, "Bananapus", "NANA", bytes32(0)));
|
|
88
|
-
|
|
89
|
-
uint256 defifaProjectId = jbController().launchProjectFor(projectOwner, "", rulesetConfigs, terminalConfigs, "");
|
|
90
|
-
vm.prank(projectOwner);
|
|
91
|
-
address defifaToken = address(jbController().deployERC20For(defifaProjectId, "Defifa", "DEFIFA", bytes32(0)));
|
|
92
|
-
|
|
93
|
-
hookCodeOrigin = new DefifaHook(jbDirectory(), IERC20(defifaToken), IERC20(nanaToken));
|
|
94
|
-
governor = new DefifaGovernor(jbController(), address(this));
|
|
95
|
-
deployer = new DefifaDeployer(
|
|
96
|
-
address(hookCodeOrigin),
|
|
97
|
-
new DefifaTokenUriResolver(ITypeface(address(0))),
|
|
98
|
-
governor,
|
|
99
|
-
jbController(),
|
|
100
|
-
new JBAddressRegistry(),
|
|
101
|
-
defifaProjectId,
|
|
102
|
-
protocolFeeProjectId
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
hookCodeOrigin.transferOwnership(address(deployer));
|
|
106
|
-
governor.transferOwnership(address(deployer));
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function test_launchRevertsFor129Tiers() external {
|
|
110
|
-
DefifaLaunchProjectData memory data = _launchData(129);
|
|
111
|
-
|
|
112
|
-
// H-5 fix: the deployer now caps tiers at 128, so launching with 129 reverts.
|
|
113
|
-
vm.expectRevert(DefifaDeployer.DefifaDeployer_InvalidGameConfiguration.selector);
|
|
114
|
-
deployer.launchGameWith(data);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function _launchData(uint256 tierCount) internal returns (DefifaLaunchProjectData memory) {
|
|
118
|
-
DefifaTierParams[] memory tiers = new DefifaTierParams[](tierCount);
|
|
119
|
-
for (uint256 i; i < tierCount; i++) {
|
|
120
|
-
tiers[i] = DefifaTierParams({
|
|
121
|
-
name: "TEAM",
|
|
122
|
-
reservedRate: 0,
|
|
123
|
-
reservedTokenBeneficiary: address(0),
|
|
124
|
-
encodedIPFSUri: bytes32(0),
|
|
125
|
-
shouldUseReservedTokenBeneficiaryAsDefault: false
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return DefifaLaunchProjectData({
|
|
130
|
-
name: "DEFIFA",
|
|
131
|
-
projectUri: "",
|
|
132
|
-
contractUri: "",
|
|
133
|
-
baseUri: "",
|
|
134
|
-
tiers: tiers,
|
|
135
|
-
tierPrice: 1 ether,
|
|
136
|
-
token: JBAccountingContext({token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: JBCurrencyIds.ETH}),
|
|
137
|
-
mintPeriodDuration: 1 days,
|
|
138
|
-
refundPeriodDuration: 1 days,
|
|
139
|
-
start: uint48(block.timestamp + 3 days),
|
|
140
|
-
splits: new JBSplit[](0),
|
|
141
|
-
attestationStartTime: 0,
|
|
142
|
-
attestationGracePeriod: 100_381,
|
|
143
|
-
defaultAttestationDelegate: address(0),
|
|
144
|
-
defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
|
|
145
|
-
terminal: jbMultiTerminal(),
|
|
146
|
-
store: new JB721TiersHookStore(),
|
|
147
|
-
minParticipation: 0,
|
|
148
|
-
scorecardTimeout: 7 days,
|
|
149
|
-
timelockDuration: 0
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function _mintTier(uint256 gameId, uint16 tierId, uint256 amount) internal {
|
|
154
|
-
address buyer = address(bytes20(keccak256(abi.encodePacked("buyer", tierId))));
|
|
155
|
-
vm.deal(buyer, amount);
|
|
156
|
-
|
|
157
|
-
uint16[] memory tierIds = new uint16[](1);
|
|
158
|
-
tierIds[0] = tierId;
|
|
159
|
-
|
|
160
|
-
bytes[] memory payloads = new bytes[](1);
|
|
161
|
-
payloads[0] = abi.encode(address(0), tierIds);
|
|
162
|
-
|
|
163
|
-
bytes4[] memory ids = new bytes4[](1);
|
|
164
|
-
ids[0] = metadataHelper().getId("pay", address(hookCodeOrigin));
|
|
165
|
-
|
|
166
|
-
bytes memory metadata = metadataHelper().createMetadata(ids, payloads);
|
|
167
|
-
|
|
168
|
-
vm.prank(buyer);
|
|
169
|
-
jbMultiTerminal().pay{value: amount}(gameId, JBConstants.NATIVE_TOKEN, amount, buyer, 0, "", metadata);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: UNLICENSED
|
|
2
|
-
pragma solidity 0.8.28;
|
|
3
|
-
|
|
4
|
-
import {DefifaUSDCTest, DefifaMockUSDC} from "../DefifaUSDC.t.sol";
|
|
5
|
-
import {DefifaDeployer} from "../../src/DefifaDeployer.sol";
|
|
6
|
-
import {DefifaGovernor} from "../../src/DefifaGovernor.sol";
|
|
7
|
-
import {DefifaHook} from "../../src/DefifaHook.sol";
|
|
8
|
-
import {DefifaTokenUriResolver} from "../../src/DefifaTokenUriResolver.sol";
|
|
9
|
-
import {DefifaLaunchProjectData} from "../../src/structs/DefifaLaunchProjectData.sol";
|
|
10
|
-
import {DefifaTierCashOutWeight} from "../../src/structs/DefifaTierCashOutWeight.sol";
|
|
11
|
-
import {DefifaTierParams} from "../../src/structs/DefifaTierParams.sol";
|
|
12
|
-
import {DefifaDelegation} from "../../src/structs/DefifaDelegation.sol";
|
|
13
|
-
import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
|
|
14
|
-
import {IJB721TokenUriResolver} from "@bananapus/721-hook-v6/src/interfaces/IJB721TokenUriResolver.sol";
|
|
15
|
-
import {IJBRulesetApprovalHook} from "@bananapus/core-v6/src/interfaces/IJBRulesetApprovalHook.sol";
|
|
16
|
-
import {JBRulesetConfig, JBTerminalConfig} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
|
|
17
|
-
import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
|
|
18
|
-
import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
|
|
19
|
-
import {JBCurrencyIds} from "@bananapus/core-v6/src/libraries/JBCurrencyIds.sol";
|
|
20
|
-
import {JBFundAccessLimitGroup} from "@bananapus/core-v6/src/structs/JBFundAccessLimitGroup.sol";
|
|
21
|
-
import {JBMultiTerminal} from "@bananapus/core-v6/src/JBMultiTerminal.sol";
|
|
22
|
-
import {JBPermissionIds} from "@bananapus/permission-ids-v6/src/JBPermissionIds.sol";
|
|
23
|
-
import {JBPermissionsData} from "@bananapus/core-v6/src/structs/JBPermissionsData.sol";
|
|
24
|
-
import {JBRuleset} from "@bananapus/core-v6/src/structs/JBRuleset.sol";
|
|
25
|
-
import {JBRulesetMetadata} from "@bananapus/core-v6/src/structs/JBRulesetMetadata.sol";
|
|
26
|
-
import {JBRulesetMetadataResolver} from "@bananapus/core-v6/src/libraries/JBRulesetMetadataResolver.sol";
|
|
27
|
-
import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
|
|
28
|
-
import {JBSplitGroup} from "@bananapus/core-v6/src/structs/JBSplitGroup.sol";
|
|
29
|
-
import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
|
|
30
|
-
import {TestBaseWorkflow} from "@bananapus/core-v6/test/helpers/TestBaseWorkflow.sol";
|
|
31
|
-
import {JBTest} from "@bananapus/core-v6/test/helpers/JBTest.sol";
|
|
32
|
-
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
33
|
-
import {ITypeface} from "lib/typeface/contracts/interfaces/ITypeface.sol";
|
|
34
|
-
|
|
35
|
-
/// @title CurrencyMismatchFixTest
|
|
36
|
-
/// @notice Adversarial tests for the currency mismatch fix: verifies that fulfillCommitmentsOf correctly resolves
|
|
37
|
-
/// payout limits for both ETH and ERC-20 games, and that launch-time validation rejects zero-currency ERC-20
|
|
38
|
-
/// configurations. Inherits DefifaUSDCTest for USDC helpers and fee project setup.
|
|
39
|
-
contract CurrencyMismatchFixTest is DefifaUSDCTest {
|
|
40
|
-
// =========================================================================
|
|
41
|
-
// HELPERS
|
|
42
|
-
// =========================================================================
|
|
43
|
-
|
|
44
|
-
function _launchDataNonCanonical(uint8 n, uint104 tierPrice) internal returns (DefifaLaunchProjectData memory) {
|
|
45
|
-
DefifaTierParams[] memory tp = new DefifaTierParams[](n);
|
|
46
|
-
for (uint256 i; i < n; i++) {
|
|
47
|
-
tp[i] = DefifaTierParams({
|
|
48
|
-
reservedRate: 1001,
|
|
49
|
-
reservedTokenBeneficiary: address(0),
|
|
50
|
-
encodedIPFSUri: bytes32(0),
|
|
51
|
-
shouldUseReservedTokenBeneficiaryAsDefault: false,
|
|
52
|
-
name: "DEFIFA"
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Non-canonical currency (1) for a USDC token.
|
|
57
|
-
return DefifaLaunchProjectData({
|
|
58
|
-
name: "DEFIFA_NONCANONICAL",
|
|
59
|
-
projectUri: "",
|
|
60
|
-
contractUri: "",
|
|
61
|
-
baseUri: "",
|
|
62
|
-
token: JBAccountingContext({token: address(usdc), decimals: 6, currency: 1}),
|
|
63
|
-
mintPeriodDuration: 1 days,
|
|
64
|
-
start: uint48(block.timestamp + 3 days),
|
|
65
|
-
refundPeriodDuration: 1 days,
|
|
66
|
-
store: new JB721TiersHookStore(),
|
|
67
|
-
splits: new JBSplit[](0),
|
|
68
|
-
attestationStartTime: 0,
|
|
69
|
-
attestationGracePeriod: 1 days,
|
|
70
|
-
defaultAttestationDelegate: address(0),
|
|
71
|
-
tierPrice: tierPrice,
|
|
72
|
-
tiers: tp,
|
|
73
|
-
defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
|
|
74
|
-
terminal: jbMultiTerminal(),
|
|
75
|
-
minParticipation: 0,
|
|
76
|
-
scorecardTimeout: 0,
|
|
77
|
-
timelockDuration: 0
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function _setupNonCanonicalGame(uint8 nTiers, uint104 tierPrice) internal {
|
|
82
|
-
DefifaLaunchProjectData memory d = _launchDataNonCanonical(nTiers, tierPrice);
|
|
83
|
-
(_pid, _nft, _gov) = _launch(d);
|
|
84
|
-
vm.warp(d.start - d.mintPeriodDuration - d.refundPeriodDuration);
|
|
85
|
-
_users = new address[](nTiers);
|
|
86
|
-
for (uint256 i; i < nTiers; i++) {
|
|
87
|
-
_users[i] = _addr(i);
|
|
88
|
-
_mintUsdc(_users[i], i + 1, tierPrice);
|
|
89
|
-
_delegateSelf(_users[i], i + 1);
|
|
90
|
-
vm.warp(block.timestamp + 1);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// =========================================================================
|
|
95
|
-
// TEST 1: ERC-20 game with non-canonical currency correctly resolves payout limit
|
|
96
|
-
// =========================================================================
|
|
97
|
-
|
|
98
|
-
/// @notice An ERC-20 game launched with currency=1 (non-canonical) now correctly sends commitment payouts
|
|
99
|
-
/// because fulfillCommitmentsOf uses metadata.baseCurrency instead of uint32(uint160(token)).
|
|
100
|
-
function test_currencyMismatchFix_erc20NonCanonicalCurrencyFulfillsCorrectly() external {
|
|
101
|
-
uint104 tierPrice = 100e6;
|
|
102
|
-
_setupNonCanonicalGame(4, tierPrice);
|
|
103
|
-
|
|
104
|
-
// Advance to scoring phase.
|
|
105
|
-
_toScoring();
|
|
106
|
-
|
|
107
|
-
uint256 potBefore = _balance();
|
|
108
|
-
assertEq(potBefore, 400e6, "pot = 400 USDC before fulfillment");
|
|
109
|
-
|
|
110
|
-
uint256 expectedFee = (potBefore * 75_000_000) / JBConstants.SPLITS_TOTAL_PERCENT;
|
|
111
|
-
|
|
112
|
-
_attestAndRatify(_evenScorecard(4));
|
|
113
|
-
|
|
114
|
-
// Verify: payout succeeded. fulfilledCommitmentsOf stores the actual fee amount, not sentinel (1).
|
|
115
|
-
uint256 fulfilled = deployer.fulfilledCommitmentsOf(_pid);
|
|
116
|
-
assertEq(fulfilled, expectedFee, "fulfilled = expected fee (payout succeeded)");
|
|
117
|
-
|
|
118
|
-
// Verify: balance reduced by the fee.
|
|
119
|
-
assertEq(_balance(), potBefore - expectedFee, "balance = pot - fee");
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// =========================================================================
|
|
123
|
-
// TEST 2: ETH game fulfillment still works correctly (no regression)
|
|
124
|
-
// =========================================================================
|
|
125
|
-
|
|
126
|
-
/// @notice ETH game (canonical currency) continues to work after the fix.
|
|
127
|
-
/// Covered by DefifaFeeAccountingTest; this verifies no regression from the baseCurrency change.
|
|
128
|
-
function test_currencyMismatchFix_ethGameFeeAccountingUnchanged() external {
|
|
129
|
-
// The DefifaFeeAccountingTest suite tests ETH fulfillment comprehensively.
|
|
130
|
-
// Here we verify the core assertion: fee percentage matches for USDC canonical game too.
|
|
131
|
-
uint104 tierPrice = 100e6;
|
|
132
|
-
_setupGameUsdc(4, tierPrice);
|
|
133
|
-
|
|
134
|
-
_toScoring();
|
|
135
|
-
|
|
136
|
-
uint256 potBefore = _balance();
|
|
137
|
-
uint256 expectedFee = (potBefore * 75_000_000) / JBConstants.SPLITS_TOTAL_PERCENT;
|
|
138
|
-
|
|
139
|
-
_attestAndRatify(_evenScorecard(4));
|
|
140
|
-
|
|
141
|
-
uint256 fulfilled = deployer.fulfilledCommitmentsOf(_pid);
|
|
142
|
-
assertEq(fulfilled, expectedFee, "canonical USDC fee unchanged by fix");
|
|
143
|
-
assertEq(fulfilled + _balance(), potBefore, "fee + surplus = original pot");
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// =========================================================================
|
|
147
|
-
// TEST 3: Non-canonical ERC-20 winner cash-out is correct after fulfillment
|
|
148
|
-
// =========================================================================
|
|
149
|
-
|
|
150
|
-
/// @notice After the fix, the winner of a non-canonical-currency ERC-20 game receives the post-fee surplus
|
|
151
|
-
/// (not the full pot). This confirms the fee was actually deducted.
|
|
152
|
-
function test_currencyMismatchFix_winnerReceivesPostFeeSurplusNotFullPot() external {
|
|
153
|
-
uint104 tierPrice = 100e6;
|
|
154
|
-
_setupNonCanonicalGame(2, tierPrice);
|
|
155
|
-
|
|
156
|
-
_toScoring();
|
|
157
|
-
|
|
158
|
-
uint256 potBefore = _balance();
|
|
159
|
-
uint256 expectedFee = (potBefore * 75_000_000) / JBConstants.SPLITS_TOTAL_PERCENT;
|
|
160
|
-
|
|
161
|
-
// Tier 1 gets 100% of the cashout weight.
|
|
162
|
-
DefifaTierCashOutWeight[] memory sc = new DefifaTierCashOutWeight[](2);
|
|
163
|
-
sc[0] = DefifaTierCashOutWeight({id: 1, cashOutWeight: _nft.TOTAL_CASHOUT_WEIGHT()});
|
|
164
|
-
sc[1] = DefifaTierCashOutWeight({id: 2, cashOutWeight: 0});
|
|
165
|
-
_attestAndRatify(sc);
|
|
166
|
-
|
|
167
|
-
// Fulfillment succeeded -- fee was deducted.
|
|
168
|
-
assertEq(deployer.fulfilledCommitmentsOf(_pid), expectedFee, "fee was deducted");
|
|
169
|
-
|
|
170
|
-
// Winner cashes out and receives the post-fee surplus.
|
|
171
|
-
uint256 winnerBalBefore = usdc.balanceOf(_users[0]);
|
|
172
|
-
_cashOutUsdc(_users[0], 1, 1);
|
|
173
|
-
uint256 winnerReceived = usdc.balanceOf(_users[0]) - winnerBalBefore;
|
|
174
|
-
|
|
175
|
-
// Before the fix, winner would have received the full pot (fee was skipped).
|
|
176
|
-
// After the fix, winner receives pot minus fee.
|
|
177
|
-
assertEq(winnerReceived, potBefore - expectedFee, "winner receives post-fee surplus, not the full pot");
|
|
178
|
-
assertLt(winnerReceived, potBefore, "winner does NOT receive the full pot");
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// =========================================================================
|
|
182
|
-
// TEST 4: Launch rejects zero currency for non-native tokens
|
|
183
|
-
// =========================================================================
|
|
184
|
-
|
|
185
|
-
/// @notice Launching an ERC-20 game with currency=0 is rejected at launch time.
|
|
186
|
-
function test_currencyMismatchFix_revertOnZeroCurrencyForErc20() external {
|
|
187
|
-
DefifaTierParams[] memory tp = new DefifaTierParams[](2);
|
|
188
|
-
for (uint256 i; i < 2; i++) {
|
|
189
|
-
tp[i] = DefifaTierParams({
|
|
190
|
-
reservedRate: 1001,
|
|
191
|
-
reservedTokenBeneficiary: address(0),
|
|
192
|
-
encodedIPFSUri: bytes32(0),
|
|
193
|
-
shouldUseReservedTokenBeneficiaryAsDefault: false,
|
|
194
|
-
name: "DEFIFA"
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
DefifaLaunchProjectData memory d = DefifaLaunchProjectData({
|
|
199
|
-
name: "DEFIFA_ZERO_CURRENCY",
|
|
200
|
-
projectUri: "",
|
|
201
|
-
contractUri: "",
|
|
202
|
-
baseUri: "",
|
|
203
|
-
token: JBAccountingContext({token: address(usdc), decimals: 6, currency: 0}),
|
|
204
|
-
mintPeriodDuration: 1 days,
|
|
205
|
-
start: uint48(block.timestamp + 3 days),
|
|
206
|
-
refundPeriodDuration: 1 days,
|
|
207
|
-
store: new JB721TiersHookStore(),
|
|
208
|
-
splits: new JBSplit[](0),
|
|
209
|
-
attestationStartTime: 0,
|
|
210
|
-
attestationGracePeriod: 1 days,
|
|
211
|
-
defaultAttestationDelegate: address(0),
|
|
212
|
-
tierPrice: 100e6,
|
|
213
|
-
tiers: tp,
|
|
214
|
-
defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
|
|
215
|
-
terminal: jbMultiTerminal(),
|
|
216
|
-
minParticipation: 0,
|
|
217
|
-
scorecardTimeout: 0,
|
|
218
|
-
timelockDuration: 0
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
vm.expectRevert(abi.encodeWithSignature("DefifaDeployer_InvalidCurrency()"));
|
|
222
|
-
deployer.launchGameWith(d);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/// @notice Native token (ETH) is exempt from the zero-currency check.
|
|
226
|
-
function test_currencyMismatchFix_nativeTokenAllowsAnyCurrency() external {
|
|
227
|
-
DefifaTierParams[] memory tp = new DefifaTierParams[](2);
|
|
228
|
-
for (uint256 i; i < 2; i++) {
|
|
229
|
-
tp[i] = DefifaTierParams({
|
|
230
|
-
reservedRate: 1001,
|
|
231
|
-
reservedTokenBeneficiary: address(0),
|
|
232
|
-
encodedIPFSUri: bytes32(0),
|
|
233
|
-
shouldUseReservedTokenBeneficiaryAsDefault: false,
|
|
234
|
-
name: "DEFIFA"
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
DefifaLaunchProjectData memory d = DefifaLaunchProjectData({
|
|
239
|
-
name: "DEFIFA_ETH_LAUNCH",
|
|
240
|
-
projectUri: "",
|
|
241
|
-
contractUri: "",
|
|
242
|
-
baseUri: "",
|
|
243
|
-
token: JBAccountingContext({token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: JBCurrencyIds.ETH}),
|
|
244
|
-
mintPeriodDuration: 1 days,
|
|
245
|
-
start: uint48(block.timestamp + 3 days),
|
|
246
|
-
refundPeriodDuration: 1 days,
|
|
247
|
-
store: new JB721TiersHookStore(),
|
|
248
|
-
splits: new JBSplit[](0),
|
|
249
|
-
attestationStartTime: 0,
|
|
250
|
-
attestationGracePeriod: 1 days,
|
|
251
|
-
defaultAttestationDelegate: address(0),
|
|
252
|
-
tierPrice: 1 ether,
|
|
253
|
-
tiers: tp,
|
|
254
|
-
defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
|
|
255
|
-
terminal: jbMultiTerminal(),
|
|
256
|
-
minParticipation: 0,
|
|
257
|
-
scorecardTimeout: 0,
|
|
258
|
-
timelockDuration: 0
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
// Should succeed without revert.
|
|
262
|
-
uint256 gameId = deployer.launchGameWith(d);
|
|
263
|
-
assertGt(gameId, 0, "ETH game launched successfully");
|
|
264
|
-
}
|
|
265
|
-
}
|