@ballkidz/defifa 0.0.11 → 0.0.13
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 +2 -2
- package/CHANGE_LOG.md +60 -5
- package/CRYPTO_ECON.md +505 -270
- package/CRYPTO_ECON.pdf +0 -0
- package/CRYPTO_ECON.tex +438 -241
- package/RISKS.md +9 -1
- package/SKILLS.md +3 -2
- package/STYLE_GUIDE.md +2 -2
- package/foundry.toml +1 -1
- package/package.json +7 -7
- package/script/Deploy.s.sol +1 -1
- package/script/helpers/DefifaDeploymentLib.sol +1 -1
- package/src/DefifaDeployer.sol +129 -131
- package/src/DefifaGovernor.sol +279 -84
- package/src/DefifaHook.sol +159 -172
- package/src/DefifaProjectOwner.sol +1 -1
- package/src/DefifaTokenUriResolver.sol +1 -1
- package/src/enums/DefifaScorecardState.sol +1 -0
- package/src/interfaces/IDefifaGovernor.sol +41 -2
- package/src/libraries/DefifaFontImporter.sol +1 -1
- package/src/libraries/DefifaHookLib.sol +70 -63
- package/src/structs/DefifaAttestations.sol +3 -3
- package/src/structs/DefifaLaunchProjectData.sol +1 -0
- package/src/structs/DefifaScorecard.sol +2 -0
- package/test/BWAFunctionComparison.t.sol +1320 -0
- package/test/DefifaAdversarialQuorum.t.sol +53 -38
- package/test/DefifaAuditLowGuards.t.sol +10 -6
- package/test/DefifaFeeAccounting.t.sol +3 -2
- package/test/DefifaGovernanceHardening.t.sol +1311 -0
- package/test/DefifaGovernor.t.sol +5 -3
- package/test/DefifaHookRegressions.t.sol +3 -2
- package/test/DefifaMintCostInvariant.t.sol +3 -2
- package/test/DefifaNoContest.t.sol +4 -3
- package/test/DefifaSecurity.t.sol +55 -42
- package/test/DefifaUSDC.t.sol +4 -3
- package/test/Fork.t.sol +12 -13
- package/test/SVG.t.sol +1 -1
- package/test/TestAuditGaps.sol +7 -5
- package/test/TestQALastMile.t.sol +5 -3
- package/test/audit/{CodexAttestationDoubleCount.t.sol → AttestationDoubleCount.t.sol} +4 -3
- package/test/audit/FixPendingReserveDilution.t.sol +366 -0
- package/test/audit/PendingReserveDilution.t.sol +298 -0
- package/test/audit/PendingReserveQuorumGrief.t.sol +355 -0
- package/test/deployScript.t.sol +1 -1
- package/test/regression/AttestationDelegateBeneficiary.t.sol +3 -2
- package/test/regression/FulfillmentBlocksRatification.t.sol +3 -2
- package/test/regression/GracePeriodBypass.t.sol +3 -2
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
// SPDX-License-Identifier: UNLICENSED
|
|
2
|
+
pragma solidity 0.8.28;
|
|
3
|
+
|
|
4
|
+
import {TestBaseWorkflow} from "@bananapus/core-v6/test/helpers/TestBaseWorkflow.sol";
|
|
5
|
+
|
|
6
|
+
import {DefifaGovernor} from "../../src/DefifaGovernor.sol";
|
|
7
|
+
import {DefifaDeployer} from "../../src/DefifaDeployer.sol";
|
|
8
|
+
import {DefifaHook} from "../../src/DefifaHook.sol";
|
|
9
|
+
import {DefifaTokenUriResolver} from "../../src/DefifaTokenUriResolver.sol";
|
|
10
|
+
import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
|
|
11
|
+
import {JB721TiersMintReservesConfig} from "@bananapus/721-hook-v6/src/structs/JB721TiersMintReservesConfig.sol";
|
|
12
|
+
|
|
13
|
+
import {JBTest} from "@bananapus/core-v6/test/helpers/JBTest.sol";
|
|
14
|
+
import {JBRuleset} from "@bananapus/core-v6/src/structs/JBRuleset.sol";
|
|
15
|
+
import {JBRulesetMetadataResolver} from "@bananapus/core-v6/src/libraries/JBRulesetMetadataResolver.sol";
|
|
16
|
+
import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
|
|
17
|
+
|
|
18
|
+
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
19
|
+
import {ITypeface} from "lib/typeface/contracts/interfaces/ITypeface.sol";
|
|
20
|
+
import {IJB721TokenUriResolver} from "@bananapus/721-hook-v6/src/interfaces/IJB721TokenUriResolver.sol";
|
|
21
|
+
import {DefifaDelegation} from "../../src/structs/DefifaDelegation.sol";
|
|
22
|
+
import {DefifaLaunchProjectData} from "../../src/structs/DefifaLaunchProjectData.sol";
|
|
23
|
+
import {DefifaTierParams} from "../../src/structs/DefifaTierParams.sol";
|
|
24
|
+
import {DefifaTierCashOutWeight} from "../../src/structs/DefifaTierCashOutWeight.sol";
|
|
25
|
+
import {DefifaScorecardState} from "../../src/enums/DefifaScorecardState.sol";
|
|
26
|
+
import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
|
|
27
|
+
import {JBTerminalConfig} from "@bananapus/core-v6/src/structs/JBTerminalConfig.sol";
|
|
28
|
+
import {JBRulesetConfig} from "@bananapus/core-v6/src/structs/JBRulesetConfig.sol";
|
|
29
|
+
import {JBRulesetMetadata} from "@bananapus/core-v6/src/structs/JBRulesetMetadata.sol";
|
|
30
|
+
import {JBSplitGroup} from "@bananapus/core-v6/src/structs/JBSplitGroup.sol";
|
|
31
|
+
import {JBFundAccessLimitGroup} from "@bananapus/core-v6/src/structs/JBFundAccessLimitGroup.sol";
|
|
32
|
+
import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
|
|
33
|
+
import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
|
|
34
|
+
import {JBCurrencyIds} from "@bananapus/core-v6/src/libraries/JBCurrencyIds.sol";
|
|
35
|
+
import {IJBRulesetApprovalHook} from "@bananapus/core-v6/src/interfaces/IJBRulesetApprovalHook.sol";
|
|
36
|
+
|
|
37
|
+
contract PendingReserveQuorumGriefTest is JBTest, TestBaseWorkflow {
|
|
38
|
+
using JBRulesetMetadataResolver for JBRuleset;
|
|
39
|
+
|
|
40
|
+
uint256 internal _protocolFeeProjectId;
|
|
41
|
+
uint256 internal _defifaProjectId;
|
|
42
|
+
uint256 internal _gameId = 3;
|
|
43
|
+
|
|
44
|
+
DefifaDeployer internal _deployer;
|
|
45
|
+
DefifaHook internal _hookImpl;
|
|
46
|
+
DefifaGovernor internal _governorImpl;
|
|
47
|
+
|
|
48
|
+
address internal _projectOwner = address(bytes20(keccak256("projectOwner")));
|
|
49
|
+
address internal _reserveBeneficiary = address(bytes20(keccak256("reserveBeneficiary")));
|
|
50
|
+
address internal _player0 = address(bytes20(keccak256("player0")));
|
|
51
|
+
address internal _player1 = address(bytes20(keccak256("player1")));
|
|
52
|
+
address internal _player2 = address(bytes20(keccak256("player2")));
|
|
53
|
+
address internal _player3 = address(bytes20(keccak256("player3")));
|
|
54
|
+
|
|
55
|
+
DefifaHook internal _nft;
|
|
56
|
+
DefifaGovernor internal _gov;
|
|
57
|
+
uint256 internal _pid;
|
|
58
|
+
|
|
59
|
+
function setUp() public virtual override {
|
|
60
|
+
super.setUp();
|
|
61
|
+
|
|
62
|
+
JBAccountingContext[] memory tokens = new JBAccountingContext[](1);
|
|
63
|
+
tokens[0] = JBAccountingContext({token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: JBCurrencyIds.ETH});
|
|
64
|
+
|
|
65
|
+
JBTerminalConfig[] memory terminalConfigs = new JBTerminalConfig[](1);
|
|
66
|
+
terminalConfigs[0] = JBTerminalConfig({terminal: jbMultiTerminal(), accountingContextsToAccept: tokens});
|
|
67
|
+
|
|
68
|
+
JBRulesetConfig[] memory rulesetConfigs = new JBRulesetConfig[](1);
|
|
69
|
+
rulesetConfigs[0] = JBRulesetConfig({
|
|
70
|
+
mustStartAtOrAfter: 0,
|
|
71
|
+
duration: 10 days,
|
|
72
|
+
weight: 1e18,
|
|
73
|
+
weightCutPercent: 0,
|
|
74
|
+
approvalHook: IJBRulesetApprovalHook(address(0)),
|
|
75
|
+
metadata: JBRulesetMetadata({
|
|
76
|
+
reservedPercent: 0,
|
|
77
|
+
cashOutTaxRate: 0,
|
|
78
|
+
baseCurrency: JBCurrencyIds.ETH,
|
|
79
|
+
pausePay: false,
|
|
80
|
+
pauseCreditTransfers: false,
|
|
81
|
+
allowOwnerMinting: false,
|
|
82
|
+
allowSetCustomToken: false,
|
|
83
|
+
allowTerminalMigration: false,
|
|
84
|
+
allowSetTerminals: false,
|
|
85
|
+
allowSetController: false,
|
|
86
|
+
allowAddAccountingContext: false,
|
|
87
|
+
allowAddPriceFeed: false,
|
|
88
|
+
ownerMustSendPayouts: false,
|
|
89
|
+
holdFees: false,
|
|
90
|
+
useTotalSurplusForCashOuts: false,
|
|
91
|
+
useDataHookForPay: true,
|
|
92
|
+
useDataHookForCashOut: true,
|
|
93
|
+
dataHook: address(0),
|
|
94
|
+
metadata: 0
|
|
95
|
+
}),
|
|
96
|
+
splitGroups: new JBSplitGroup[](0),
|
|
97
|
+
fundAccessLimitGroups: new JBFundAccessLimitGroup[](0)
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
_protocolFeeProjectId =
|
|
101
|
+
jbController().launchProjectFor(address(_projectOwner), "", rulesetConfigs, terminalConfigs, "");
|
|
102
|
+
vm.prank(_projectOwner);
|
|
103
|
+
address nanaToken =
|
|
104
|
+
address(jbController().deployERC20For(_protocolFeeProjectId, "Bananapus", "NANA", bytes32(0)));
|
|
105
|
+
|
|
106
|
+
_defifaProjectId =
|
|
107
|
+
jbController().launchProjectFor(address(_projectOwner), "", rulesetConfigs, terminalConfigs, "");
|
|
108
|
+
vm.prank(_projectOwner);
|
|
109
|
+
address defifaToken = address(jbController().deployERC20For(_defifaProjectId, "Defifa", "DEFIFA", bytes32(0)));
|
|
110
|
+
|
|
111
|
+
_hookImpl = new DefifaHook(jbDirectory(), IERC20(defifaToken), IERC20(nanaToken));
|
|
112
|
+
_governorImpl = new DefifaGovernor(jbController(), address(this));
|
|
113
|
+
_deployer = new DefifaDeployer(
|
|
114
|
+
address(_hookImpl),
|
|
115
|
+
new DefifaTokenUriResolver(ITypeface(address(0))),
|
|
116
|
+
_governorImpl,
|
|
117
|
+
jbController(),
|
|
118
|
+
new JBAddressRegistry(),
|
|
119
|
+
_defifaProjectId,
|
|
120
|
+
_protocolFeeProjectId
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
_hookImpl.transferOwnership(address(_deployer));
|
|
124
|
+
_governorImpl.transferOwnership(address(_deployer));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/// @notice RPT-H-2 FIX VERIFICATION: Pending reserves in quorum + attestation denominator prevent manipulation.
|
|
128
|
+
///
|
|
129
|
+
/// 1. Four players mint into tiers 1-4 (tiers 1-2 have reserveRate=1, creating pending reserves;
|
|
130
|
+
/// tiers 3-4 have no reserves)
|
|
131
|
+
/// 2. Pending reserves dilute tiers 1-2 players' attestation power to 50% of MAX_POWER per tier
|
|
132
|
+
/// 3. With BWA + HHI-adjusted quorum, disinterested tiers 3-4 (0 weight) provide full power
|
|
133
|
+
/// 4. Minting reserves doesn't change quorum (tier was already counted via pending reserves)
|
|
134
|
+
function test_reserveMintDoesNotChangeQuorumWhenPendingReservesAlreadyCounted() external {
|
|
135
|
+
(_pid, _nft, _gov) = _launch(_launchData());
|
|
136
|
+
|
|
137
|
+
// --- MINT phase --- players mint 1 NFT each into tiers 1-4
|
|
138
|
+
vm.warp(86_402);
|
|
139
|
+
_mint(_player0, 1);
|
|
140
|
+
_mint(_player1, 2);
|
|
141
|
+
_mint(_player2, 3);
|
|
142
|
+
_mint(_player3, 4);
|
|
143
|
+
_delegateSelf(_player0, 1);
|
|
144
|
+
_delegateSelf(_player1, 2);
|
|
145
|
+
_delegateSelf(_player2, 3);
|
|
146
|
+
_delegateSelf(_player3, 4);
|
|
147
|
+
|
|
148
|
+
// --- Skip REFUND phase (no cash-outs) ---
|
|
149
|
+
vm.warp(172_802);
|
|
150
|
+
|
|
151
|
+
// --- SCORING phase --- submit scorecard
|
|
152
|
+
vm.warp(259_202);
|
|
153
|
+
DefifaTierCashOutWeight[] memory scorecard = _buildScorecard();
|
|
154
|
+
uint256 proposalId = _gov.submitScorecardFor(_gameId, scorecard);
|
|
155
|
+
|
|
156
|
+
// Quorum = 4 tiers * MAX_POWER / 2 = 2 * MAX_POWER
|
|
157
|
+
uint256 snapshotQuorum = _gov.quorum(_gameId);
|
|
158
|
+
assertEq(snapshotQuorum, _gov.MAX_ATTESTATION_POWER_TIER() * 2, "4 tiers, quorum = 2 * MAX_POWER");
|
|
159
|
+
|
|
160
|
+
// Tiers 1-2 (with pending reserves): raw power = 500M per player, BWA * 0.5 = 250M.
|
|
161
|
+
// Tiers 3-4 (no reserves, 0 weight): raw power = 1e9 per player, BWA * 1.0 = 1e9.
|
|
162
|
+
// Total BWA = 250M + 250M + 1e9 + 1e9 = 2.5e9, meeting adjusted quorum of 2.5e9.
|
|
163
|
+
vm.prank(_player0);
|
|
164
|
+
_gov.attestToScorecardFrom(_gameId, proposalId);
|
|
165
|
+
vm.prank(_player1);
|
|
166
|
+
_gov.attestToScorecardFrom(_gameId, proposalId);
|
|
167
|
+
vm.prank(_player2);
|
|
168
|
+
_gov.attestToScorecardFrom(_gameId, proposalId);
|
|
169
|
+
vm.prank(_player3);
|
|
170
|
+
_gov.attestToScorecardFrom(_gameId, proposalId);
|
|
171
|
+
|
|
172
|
+
vm.warp(block.timestamp + _gov.attestationGracePeriodOf(_gameId) + 1);
|
|
173
|
+
|
|
174
|
+
assertEq(
|
|
175
|
+
uint256(_gov.stateOf(_gameId, proposalId)),
|
|
176
|
+
uint256(DefifaScorecardState.SUCCEEDED),
|
|
177
|
+
"scorecard succeeds with disinterested attestors providing quorum"
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
// --- ATTEMPTED ATTACK --- anyone mints pending reserves for tier 1
|
|
181
|
+
JB721TiersMintReservesConfig[] memory reserveConfigs = new JB721TiersMintReservesConfig[](1);
|
|
182
|
+
reserveConfigs[0] = JB721TiersMintReservesConfig({tierId: 1, count: 1});
|
|
183
|
+
_nft.mintReservesFor(reserveConfigs);
|
|
184
|
+
|
|
185
|
+
// Scorecard STILL SUCCEEDED — reserve mint doesn't change which tiers are counted
|
|
186
|
+
assertEq(
|
|
187
|
+
uint256(_gov.stateOf(_gameId, proposalId)),
|
|
188
|
+
uint256(DefifaScorecardState.SUCCEEDED),
|
|
189
|
+
"quorum unchanged after reserve mint"
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/// @notice RPT-H-2 FIX VERIFICATION: Ratification succeeds after reserve mint because quorum is stable.
|
|
194
|
+
function test_ratificationSucceedsAfterReserveMint() external {
|
|
195
|
+
(_pid, _nft, _gov) = _launch(_launchData());
|
|
196
|
+
|
|
197
|
+
// MINT phase
|
|
198
|
+
vm.warp(86_402);
|
|
199
|
+
_mint(_player0, 1);
|
|
200
|
+
_mint(_player1, 2);
|
|
201
|
+
_mint(_player2, 3);
|
|
202
|
+
_mint(_player3, 4);
|
|
203
|
+
_delegateSelf(_player0, 1);
|
|
204
|
+
_delegateSelf(_player1, 2);
|
|
205
|
+
_delegateSelf(_player2, 3);
|
|
206
|
+
_delegateSelf(_player3, 4);
|
|
207
|
+
|
|
208
|
+
// Skip REFUND phase
|
|
209
|
+
vm.warp(172_802);
|
|
210
|
+
|
|
211
|
+
// SCORING phase — submit, all 4 attest.
|
|
212
|
+
// Tiers 3-4 (no reserves, 0 weight) provide disinterested attestation power.
|
|
213
|
+
vm.warp(259_202);
|
|
214
|
+
DefifaTierCashOutWeight[] memory scorecard = _buildScorecard();
|
|
215
|
+
uint256 proposalId = _gov.submitScorecardFor(_gameId, scorecard);
|
|
216
|
+
vm.prank(_player0);
|
|
217
|
+
_gov.attestToScorecardFrom(_gameId, proposalId);
|
|
218
|
+
vm.prank(_player1);
|
|
219
|
+
_gov.attestToScorecardFrom(_gameId, proposalId);
|
|
220
|
+
vm.prank(_player2);
|
|
221
|
+
_gov.attestToScorecardFrom(_gameId, proposalId);
|
|
222
|
+
vm.prank(_player3);
|
|
223
|
+
_gov.attestToScorecardFrom(_gameId, proposalId);
|
|
224
|
+
vm.warp(block.timestamp + _gov.attestationGracePeriodOf(_gameId) + 1);
|
|
225
|
+
|
|
226
|
+
assertEq(
|
|
227
|
+
uint256(_gov.stateOf(_gameId, proposalId)),
|
|
228
|
+
uint256(DefifaScorecardState.SUCCEEDED),
|
|
229
|
+
"scorecard should be succeeded"
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
// Mint reserves for tier 1 — shouldn't affect ratification
|
|
233
|
+
JB721TiersMintReservesConfig[] memory reserveConfigs = new JB721TiersMintReservesConfig[](1);
|
|
234
|
+
reserveConfigs[0] = JB721TiersMintReservesConfig({tierId: 1, count: 1});
|
|
235
|
+
_nft.mintReservesFor(reserveConfigs);
|
|
236
|
+
|
|
237
|
+
// Ratification succeeds because quorum is unchanged (tier already counted via pending reserves)
|
|
238
|
+
uint256 ratifiedId = _gov.ratifyScorecardFrom(_gameId, scorecard);
|
|
239
|
+
assertEq(ratifiedId, proposalId, "ratification succeeds after reserve mint");
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function _buildScorecard() internal view returns (DefifaTierCashOutWeight[] memory scorecard) {
|
|
243
|
+
scorecard = new DefifaTierCashOutWeight[](4);
|
|
244
|
+
uint256 totalWeight = _nft.TOTAL_CASHOUT_WEIGHT();
|
|
245
|
+
scorecard[0] = DefifaTierCashOutWeight({id: 1, cashOutWeight: totalWeight / 2});
|
|
246
|
+
scorecard[1] = DefifaTierCashOutWeight({id: 2, cashOutWeight: totalWeight / 2});
|
|
247
|
+
scorecard[2] = DefifaTierCashOutWeight({id: 3, cashOutWeight: 0});
|
|
248
|
+
scorecard[3] = DefifaTierCashOutWeight({id: 4, cashOutWeight: 0});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function _launchData() internal returns (DefifaLaunchProjectData memory data) {
|
|
252
|
+
DefifaTierParams[] memory tiers = new DefifaTierParams[](4);
|
|
253
|
+
// Tiers 1-2: have reserves (reserveRate=1, 1 reserve per mint)
|
|
254
|
+
for (uint256 i; i < 2; i++) {
|
|
255
|
+
tiers[i] = DefifaTierParams({
|
|
256
|
+
reservedRate: 1,
|
|
257
|
+
reservedTokenBeneficiary: _reserveBeneficiary,
|
|
258
|
+
encodedIPFSUri: bytes32(0),
|
|
259
|
+
shouldUseReservedTokenBeneficiaryAsDefault: false,
|
|
260
|
+
name: "TEAM"
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
// Tiers 3-4: no reserves (disinterested attestors for BWA governance)
|
|
264
|
+
for (uint256 i = 2; i < 4; i++) {
|
|
265
|
+
tiers[i] = DefifaTierParams({
|
|
266
|
+
reservedRate: 1001,
|
|
267
|
+
reservedTokenBeneficiary: address(0),
|
|
268
|
+
encodedIPFSUri: bytes32(0),
|
|
269
|
+
shouldUseReservedTokenBeneficiaryAsDefault: false,
|
|
270
|
+
name: "TEAM"
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
data = DefifaLaunchProjectData({
|
|
275
|
+
name: "DEFIFA",
|
|
276
|
+
projectUri: "",
|
|
277
|
+
contractUri: "",
|
|
278
|
+
baseUri: "",
|
|
279
|
+
tiers: tiers,
|
|
280
|
+
tierPrice: 1 ether,
|
|
281
|
+
token: JBAccountingContext({token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: JBCurrencyIds.ETH}),
|
|
282
|
+
mintPeriodDuration: 1 days,
|
|
283
|
+
refundPeriodDuration: 1 days,
|
|
284
|
+
start: uint48(block.timestamp + 3 days),
|
|
285
|
+
splits: new JBSplit[](0),
|
|
286
|
+
attestationStartTime: 0,
|
|
287
|
+
attestationGracePeriod: 100_381,
|
|
288
|
+
defaultAttestationDelegate: address(0),
|
|
289
|
+
defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
|
|
290
|
+
terminal: jbMultiTerminal(),
|
|
291
|
+
store: new JB721TiersHookStore(),
|
|
292
|
+
minParticipation: 0,
|
|
293
|
+
scorecardTimeout: 0,
|
|
294
|
+
timelockDuration: 0
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function _launch(DefifaLaunchProjectData memory data)
|
|
299
|
+
internal
|
|
300
|
+
returns (uint256 projectId, DefifaHook nft, DefifaGovernor gov)
|
|
301
|
+
{
|
|
302
|
+
gov = _governorImpl;
|
|
303
|
+
projectId = _deployer.launchGameWith(data);
|
|
304
|
+
JBRuleset memory ruleset = jbRulesets().currentOf(projectId);
|
|
305
|
+
if (ruleset.dataHook() == address(0)) (ruleset,) = jbRulesets().latestQueuedOf(projectId);
|
|
306
|
+
nft = DefifaHook(ruleset.dataHook());
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function _mint(address user, uint256 tierId) internal {
|
|
310
|
+
vm.deal(user, 1 ether);
|
|
311
|
+
uint16[] memory tiers = new uint16[](1);
|
|
312
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
313
|
+
tiers[0] = uint16(tierId);
|
|
314
|
+
bytes[] memory data = new bytes[](1);
|
|
315
|
+
data[0] = abi.encode(user, tiers);
|
|
316
|
+
bytes4[] memory ids = new bytes4[](1);
|
|
317
|
+
ids[0] = metadataHelper().getId("pay", address(_hookImpl));
|
|
318
|
+
bytes memory metadata = metadataHelper().createMetadata(ids, data);
|
|
319
|
+
|
|
320
|
+
vm.prank(user);
|
|
321
|
+
jbMultiTerminal().pay{value: 1 ether}(_pid, JBConstants.NATIVE_TOKEN, 1 ether, user, 0, "", metadata);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function _delegateSelf(address user, uint256 tierId) internal {
|
|
325
|
+
DefifaDelegation[] memory delegations = new DefifaDelegation[](1);
|
|
326
|
+
delegations[0] = DefifaDelegation({delegatee: user, tierId: tierId});
|
|
327
|
+
vm.prank(user);
|
|
328
|
+
_nft.setTierDelegatesTo(delegations);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function _cashOut(address user, uint256 tierId, uint256 tokenNumber) internal {
|
|
332
|
+
bytes memory metadata = _cashOutMetadata(tierId, tokenNumber);
|
|
333
|
+
vm.prank(user);
|
|
334
|
+
jbMultiTerminal()
|
|
335
|
+
.cashOutTokensOf({
|
|
336
|
+
holder: user,
|
|
337
|
+
projectId: _pid,
|
|
338
|
+
cashOutCount: 0,
|
|
339
|
+
tokenToReclaim: JBConstants.NATIVE_TOKEN,
|
|
340
|
+
minTokensReclaimed: 0,
|
|
341
|
+
beneficiary: payable(user),
|
|
342
|
+
metadata: metadata
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function _cashOutMetadata(uint256 tierId, uint256 tokenNumber) internal view returns (bytes memory) {
|
|
347
|
+
uint256[] memory tokenIds = new uint256[](1);
|
|
348
|
+
tokenIds[0] = (tierId * 1_000_000_000) + tokenNumber;
|
|
349
|
+
bytes[] memory data = new bytes[](1);
|
|
350
|
+
data[0] = abi.encode(tokenIds);
|
|
351
|
+
bytes4[] memory ids = new bytes4[](1);
|
|
352
|
+
ids[0] = metadataHelper().getId("cashOut", address(_hookImpl));
|
|
353
|
+
return metadataHelper().createMetadata(ids, data);
|
|
354
|
+
}
|
|
355
|
+
}
|
package/test/deployScript.t.sol
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: UNLICENSED
|
|
2
|
-
pragma solidity
|
|
2
|
+
pragma solidity 0.8.28;
|
|
3
3
|
|
|
4
4
|
import {TestBaseWorkflow} from "@bananapus/core-v6/test/helpers/TestBaseWorkflow.sol";
|
|
5
5
|
|
|
@@ -248,7 +248,8 @@ contract AttestationDelegateBeneficiary is JBTest, TestBaseWorkflow {
|
|
|
248
248
|
defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
|
|
249
249
|
terminal: jbMultiTerminal(),
|
|
250
250
|
minParticipation: 0,
|
|
251
|
-
scorecardTimeout: 0
|
|
251
|
+
scorecardTimeout: 0,
|
|
252
|
+
timelockDuration: 0
|
|
252
253
|
});
|
|
253
254
|
|
|
254
255
|
_mintPhaseStart = d.start - d.mintPeriodDuration - d.refundPeriodDuration;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: UNLICENSED
|
|
2
|
-
pragma solidity
|
|
2
|
+
pragma solidity 0.8.28;
|
|
3
3
|
|
|
4
4
|
import {TestBaseWorkflow} from "@bananapus/core-v6/test/helpers/TestBaseWorkflow.sol";
|
|
5
5
|
|
|
@@ -251,7 +251,8 @@ contract FulfillmentBlocksRatification is JBTest, TestBaseWorkflow {
|
|
|
251
251
|
defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
|
|
252
252
|
terminal: jbMultiTerminal(),
|
|
253
253
|
minParticipation: 0,
|
|
254
|
-
scorecardTimeout: 0
|
|
254
|
+
scorecardTimeout: 0,
|
|
255
|
+
timelockDuration: 0
|
|
255
256
|
});
|
|
256
257
|
}
|
|
257
258
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: UNLICENSED
|
|
2
|
-
pragma solidity
|
|
2
|
+
pragma solidity 0.8.28;
|
|
3
3
|
|
|
4
4
|
import {TestBaseWorkflow} from "@bananapus/core-v6/test/helpers/TestBaseWorkflow.sol";
|
|
5
5
|
|
|
@@ -274,7 +274,8 @@ contract GracePeriodBypass is JBTest, TestBaseWorkflow {
|
|
|
274
274
|
defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
|
|
275
275
|
terminal: jbMultiTerminal(),
|
|
276
276
|
minParticipation: 0,
|
|
277
|
-
scorecardTimeout: 0
|
|
277
|
+
scorecardTimeout: 0,
|
|
278
|
+
timelockDuration: 0
|
|
278
279
|
});
|
|
279
280
|
}
|
|
280
281
|
|