@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,308 +0,0 @@
|
|
|
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
|
-
|
|
12
|
-
import {JBTest} from "@bananapus/core-v6/test/helpers/JBTest.sol";
|
|
13
|
-
import {JBRulesetMetadataResolver} from "@bananapus/core-v6/src/libraries/JBRulesetMetadataResolver.sol";
|
|
14
|
-
import {JBRuleset} from "@bananapus/core-v6/src/structs/JBRuleset.sol";
|
|
15
|
-
import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
|
|
16
|
-
|
|
17
|
-
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
18
|
-
import {ITypeface} from "lib/typeface/contracts/interfaces/ITypeface.sol";
|
|
19
|
-
import {IJB721TokenUriResolver} from "@bananapus/721-hook-v6/src/interfaces/IJB721TokenUriResolver.sol";
|
|
20
|
-
import {DefifaDelegation} from "../src/structs/DefifaDelegation.sol";
|
|
21
|
-
import {DefifaLaunchProjectData} from "../src/structs/DefifaLaunchProjectData.sol";
|
|
22
|
-
import {DefifaTierParams} from "../src/structs/DefifaTierParams.sol";
|
|
23
|
-
import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
|
|
24
|
-
import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
|
|
25
|
-
import {JBCurrencyIds} from "@bananapus/core-v6/src/libraries/JBCurrencyIds.sol";
|
|
26
|
-
import {JBFundAccessLimitGroup} from "@bananapus/core-v6/src/structs/JBFundAccessLimitGroup.sol";
|
|
27
|
-
import {JBRulesetConfig, JBTerminalConfig} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
|
|
28
|
-
import {JBRulesetMetadata} from "@bananapus/core-v6/src/structs/JBRulesetMetadata.sol";
|
|
29
|
-
import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
|
|
30
|
-
import {JBSplitGroup} from "@bananapus/core-v6/src/structs/JBSplitGroup.sol";
|
|
31
|
-
import {IJBRulesetApprovalHook} from "@bananapus/core-v6/src/interfaces/IJBRulesets.sol";
|
|
32
|
-
|
|
33
|
-
/// @title DefifaAuditLowGuardsTest
|
|
34
|
-
/// @notice Tests for validation guards added in the audit/low-findings branch:
|
|
35
|
-
/// - DefifaGovernor_AlreadyInitialized (re-initialization guard)
|
|
36
|
-
/// - uint48 overflow checks on attestationStartTime and attestationGracePeriod
|
|
37
|
-
/// - DefifaHook_DelegateAddressZero (address(0) delegation guard)
|
|
38
|
-
contract DefifaAuditLowGuardsTest is JBTest, TestBaseWorkflow {
|
|
39
|
-
using JBRulesetMetadataResolver for JBRuleset;
|
|
40
|
-
|
|
41
|
-
address _protocolFeeProjectTokenAccount;
|
|
42
|
-
address _defifaProjectTokenAccount;
|
|
43
|
-
uint256 _protocolFeeProjectId;
|
|
44
|
-
uint256 _defifaProjectId;
|
|
45
|
-
uint256 _gameId = 3;
|
|
46
|
-
|
|
47
|
-
DefifaDeployer deployer;
|
|
48
|
-
DefifaHook hook;
|
|
49
|
-
DefifaGovernor governor;
|
|
50
|
-
address projectOwner = address(bytes20(keccak256("projectOwner")));
|
|
51
|
-
|
|
52
|
-
// Shared test state (set by _setupGame)
|
|
53
|
-
uint256 _pid;
|
|
54
|
-
DefifaHook _nft;
|
|
55
|
-
DefifaGovernor _gov;
|
|
56
|
-
address[] _users;
|
|
57
|
-
|
|
58
|
-
function setUp() public virtual override {
|
|
59
|
-
super.setUp();
|
|
60
|
-
|
|
61
|
-
JBAccountingContext[] memory _tokens = new JBAccountingContext[](1);
|
|
62
|
-
_tokens[0] = JBAccountingContext({token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: JBCurrencyIds.ETH});
|
|
63
|
-
JBTerminalConfig[] memory tc = new JBTerminalConfig[](1);
|
|
64
|
-
tc[0] = JBTerminalConfig({terminal: jbMultiTerminal(), accountingContextsToAccept: _tokens});
|
|
65
|
-
JBRulesetConfig[] memory rc = new JBRulesetConfig[](1);
|
|
66
|
-
rc[0] = JBRulesetConfig({
|
|
67
|
-
mustStartAtOrAfter: 0,
|
|
68
|
-
duration: 10 days,
|
|
69
|
-
weight: 1e18,
|
|
70
|
-
weightCutPercent: 0,
|
|
71
|
-
approvalHook: IJBRulesetApprovalHook(address(0)),
|
|
72
|
-
metadata: JBRulesetMetadata({
|
|
73
|
-
reservedPercent: 0,
|
|
74
|
-
cashOutTaxRate: 0,
|
|
75
|
-
baseCurrency: JBCurrencyIds.ETH,
|
|
76
|
-
pausePay: false,
|
|
77
|
-
pauseCreditTransfers: false,
|
|
78
|
-
allowOwnerMinting: false,
|
|
79
|
-
allowSetCustomToken: false,
|
|
80
|
-
allowTerminalMigration: false,
|
|
81
|
-
allowSetTerminals: false,
|
|
82
|
-
allowSetController: false,
|
|
83
|
-
allowAddAccountingContext: false,
|
|
84
|
-
allowAddPriceFeed: false,
|
|
85
|
-
ownerMustSendPayouts: false,
|
|
86
|
-
holdFees: false,
|
|
87
|
-
useTotalSurplusForCashOuts: false,
|
|
88
|
-
useDataHookForPay: true,
|
|
89
|
-
useDataHookForCashOut: true,
|
|
90
|
-
dataHook: address(0),
|
|
91
|
-
metadata: 0
|
|
92
|
-
}),
|
|
93
|
-
splitGroups: new JBSplitGroup[](0),
|
|
94
|
-
fundAccessLimitGroups: new JBFundAccessLimitGroup[](0)
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
_protocolFeeProjectId = jbController().launchProjectFor(projectOwner, "", rc, tc, "");
|
|
98
|
-
vm.prank(projectOwner);
|
|
99
|
-
_protocolFeeProjectTokenAccount =
|
|
100
|
-
address(jbController().deployERC20For(_protocolFeeProjectId, "Bananapus", "NANA", bytes32(0)));
|
|
101
|
-
_defifaProjectId = jbController().launchProjectFor(projectOwner, "", rc, tc, "");
|
|
102
|
-
vm.prank(projectOwner);
|
|
103
|
-
_defifaProjectTokenAccount =
|
|
104
|
-
address(jbController().deployERC20For(_defifaProjectId, "Defifa", "DEFIFA", bytes32(0)));
|
|
105
|
-
|
|
106
|
-
hook =
|
|
107
|
-
new DefifaHook(jbDirectory(), IERC20(_defifaProjectTokenAccount), IERC20(_protocolFeeProjectTokenAccount));
|
|
108
|
-
governor = new DefifaGovernor(jbController(), address(this));
|
|
109
|
-
deployer = new DefifaDeployer(
|
|
110
|
-
address(hook),
|
|
111
|
-
new DefifaTokenUriResolver(ITypeface(address(0))),
|
|
112
|
-
governor,
|
|
113
|
-
jbController(),
|
|
114
|
-
new JBAddressRegistry(),
|
|
115
|
-
_protocolFeeProjectId,
|
|
116
|
-
_defifaProjectId
|
|
117
|
-
);
|
|
118
|
-
hook.transferOwnership(address(deployer));
|
|
119
|
-
governor.transferOwnership(address(deployer));
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// =========================================================================
|
|
123
|
-
// 1. DefifaGovernor_AlreadyInitialized: re-initialization blocked
|
|
124
|
-
// =========================================================================
|
|
125
|
-
function testRevert_initializeGame_alreadyInitialized() external {
|
|
126
|
-
// Deploy a standalone governor where this test contract is the owner, so we can call initializeGame directly.
|
|
127
|
-
DefifaGovernor _standaloneGov = new DefifaGovernor(jbController(), address(this));
|
|
128
|
-
|
|
129
|
-
// First initialization should succeed.
|
|
130
|
-
uint256 gameId = 42;
|
|
131
|
-
_standaloneGov.initializeGame({
|
|
132
|
-
gameId: gameId, attestationStartTime: block.timestamp, attestationGracePeriod: 2 days, timelockDuration: 0
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
// Second initialization for the same gameId should revert.
|
|
136
|
-
vm.expectRevert(DefifaGovernor.DefifaGovernor_AlreadyInitialized.selector);
|
|
137
|
-
_standaloneGov.initializeGame({
|
|
138
|
-
gameId: gameId, attestationStartTime: block.timestamp, attestationGracePeriod: 2 days, timelockDuration: 0
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// =========================================================================
|
|
143
|
-
// 1b. Re-initialization blocked even through the deployer (integration)
|
|
144
|
-
// =========================================================================
|
|
145
|
-
function testRevert_initializeGame_alreadyInitialized_viaDeployer() external {
|
|
146
|
-
// Launch a game (this calls initializeGame internally).
|
|
147
|
-
_setupGame(4, 1 ether);
|
|
148
|
-
|
|
149
|
-
// The governor is now owned by the deployer. Trying to initialize the same game again
|
|
150
|
-
// via the deployer is not possible because there is no public re-init path. But we
|
|
151
|
-
// verify the packed info is non-zero, confirming the guard would trigger.
|
|
152
|
-
assertTrue(_gov.attestationStartTimeOf(_gameId) > 0 || _gov.attestationGracePeriodOf(_gameId) > 0);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// =========================================================================
|
|
156
|
-
// 2. uint48 overflow on attestationStartTime
|
|
157
|
-
// =========================================================================
|
|
158
|
-
function testRevert_initializeGame_attestationStartTimeOverflow() external {
|
|
159
|
-
DefifaGovernor _standaloneGov = new DefifaGovernor(jbController(), address(this));
|
|
160
|
-
|
|
161
|
-
// type(uint48).max + 1 should overflow the 48-bit packing.
|
|
162
|
-
uint256 overflowStartTime = uint256(type(uint48).max) + 1;
|
|
163
|
-
|
|
164
|
-
vm.expectRevert(DefifaGovernor.DefifaGovernor_Uint48Overflow.selector);
|
|
165
|
-
_standaloneGov.initializeGame({
|
|
166
|
-
gameId: 99, attestationStartTime: overflowStartTime, attestationGracePeriod: 2 days, timelockDuration: 0
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// =========================================================================
|
|
171
|
-
// 3. uint48 overflow on attestationGracePeriod
|
|
172
|
-
// =========================================================================
|
|
173
|
-
function testRevert_initializeGame_attestationGracePeriodOverflow() external {
|
|
174
|
-
DefifaGovernor _standaloneGov = new DefifaGovernor(jbController(), address(this));
|
|
175
|
-
|
|
176
|
-
// type(uint48).max + 1 should overflow the 48-bit packing.
|
|
177
|
-
uint256 overflowGracePeriod = uint256(type(uint48).max) + 1;
|
|
178
|
-
|
|
179
|
-
vm.expectRevert(DefifaGovernor.DefifaGovernor_Uint48Overflow.selector);
|
|
180
|
-
_standaloneGov.initializeGame({
|
|
181
|
-
gameId: 100,
|
|
182
|
-
attestationStartTime: block.timestamp,
|
|
183
|
-
attestationGracePeriod: overflowGracePeriod,
|
|
184
|
-
timelockDuration: 0
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// =========================================================================
|
|
189
|
-
// 4. DefifaHook_DelegateAddressZero in setTierDelegateTo
|
|
190
|
-
// =========================================================================
|
|
191
|
-
function testRevert_setTierDelegateTo_zeroAddress() external {
|
|
192
|
-
_setupGame(4, 1 ether);
|
|
193
|
-
|
|
194
|
-
// _users[0] owns an NFT in tier 1 during the MINT phase.
|
|
195
|
-
vm.prank(_users[0]);
|
|
196
|
-
vm.expectRevert(DefifaHook.DefifaHook_DelegateAddressZero.selector);
|
|
197
|
-
_nft.setTierDelegateTo({delegatee: address(0), tierId: 1});
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// =========================================================================
|
|
201
|
-
// 5. DefifaHook_DelegateAddressZero in setTierDelegatesTo (batch)
|
|
202
|
-
// =========================================================================
|
|
203
|
-
function testRevert_setTierDelegatesTo_zeroAddress() external {
|
|
204
|
-
_setupGame(4, 1 ether);
|
|
205
|
-
|
|
206
|
-
DefifaDelegation[] memory delegations = new DefifaDelegation[](1);
|
|
207
|
-
delegations[0] = DefifaDelegation({delegatee: address(0), tierId: 1});
|
|
208
|
-
|
|
209
|
-
vm.prank(_users[0]);
|
|
210
|
-
vm.expectRevert(DefifaHook.DefifaHook_DelegateAddressZero.selector);
|
|
211
|
-
_nft.setTierDelegatesTo(delegations);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// =========================================================================
|
|
215
|
-
// 5b. Batch delegation reverts on address(0) even in second element
|
|
216
|
-
// =========================================================================
|
|
217
|
-
function testRevert_setTierDelegatesTo_zeroAddress_secondElement() external {
|
|
218
|
-
_setupGame(4, 1 ether);
|
|
219
|
-
|
|
220
|
-
// First delegation is valid, second has address(0).
|
|
221
|
-
DefifaDelegation[] memory delegations = new DefifaDelegation[](2);
|
|
222
|
-
delegations[0] = DefifaDelegation({delegatee: _users[0], tierId: 1});
|
|
223
|
-
delegations[1] = DefifaDelegation({delegatee: address(0), tierId: 2});
|
|
224
|
-
|
|
225
|
-
vm.prank(_users[0]);
|
|
226
|
-
vm.expectRevert(DefifaHook.DefifaHook_DelegateAddressZero.selector);
|
|
227
|
-
_nft.setTierDelegatesTo(delegations);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// =========================================================================
|
|
231
|
-
// SETUP HELPERS (adapted from DefifaSecurity.t.sol)
|
|
232
|
-
// =========================================================================
|
|
233
|
-
|
|
234
|
-
function _setupGame(uint8 nTiers, uint256 tierPrice) internal {
|
|
235
|
-
DefifaLaunchProjectData memory d = _launchData(nTiers, tierPrice);
|
|
236
|
-
(_pid, _nft, _gov) = _launch(d);
|
|
237
|
-
vm.warp(d.start - d.mintPeriodDuration - d.refundPeriodDuration);
|
|
238
|
-
_users = new address[](nTiers);
|
|
239
|
-
for (uint256 i; i < nTiers; i++) {
|
|
240
|
-
_users[i] = _addr(i);
|
|
241
|
-
_mint(_users[i], i + 1, tierPrice);
|
|
242
|
-
vm.warp(block.timestamp + 1);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
function _launchData(uint8 n, uint256 tierPrice) internal returns (DefifaLaunchProjectData memory) {
|
|
247
|
-
DefifaTierParams[] memory tp = new DefifaTierParams[](n);
|
|
248
|
-
for (uint256 i; i < n; i++) {
|
|
249
|
-
tp[i] = DefifaTierParams({
|
|
250
|
-
reservedRate: 1001,
|
|
251
|
-
reservedTokenBeneficiary: address(0),
|
|
252
|
-
encodedIPFSUri: bytes32(0),
|
|
253
|
-
shouldUseReservedTokenBeneficiaryAsDefault: false,
|
|
254
|
-
name: "DEFIFA"
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
return DefifaLaunchProjectData({
|
|
258
|
-
name: "DEFIFA",
|
|
259
|
-
projectUri: "",
|
|
260
|
-
contractUri: "",
|
|
261
|
-
baseUri: "",
|
|
262
|
-
token: JBAccountingContext({token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: JBCurrencyIds.ETH}),
|
|
263
|
-
mintPeriodDuration: 1 days,
|
|
264
|
-
start: uint48(block.timestamp + 3 days),
|
|
265
|
-
refundPeriodDuration: 1 days,
|
|
266
|
-
store: new JB721TiersHookStore(),
|
|
267
|
-
splits: new JBSplit[](0),
|
|
268
|
-
attestationStartTime: 0,
|
|
269
|
-
attestationGracePeriod: 100_381,
|
|
270
|
-
defaultAttestationDelegate: address(0),
|
|
271
|
-
// forge-lint: disable-next-line(unsafe-typecast)
|
|
272
|
-
tierPrice: uint104(tierPrice),
|
|
273
|
-
tiers: tp,
|
|
274
|
-
defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
|
|
275
|
-
terminal: jbMultiTerminal(),
|
|
276
|
-
minParticipation: 0,
|
|
277
|
-
scorecardTimeout: 0,
|
|
278
|
-
timelockDuration: 0
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
function _launch(DefifaLaunchProjectData memory d) internal returns (uint256 p, DefifaHook n, DefifaGovernor g) {
|
|
283
|
-
g = governor;
|
|
284
|
-
p = deployer.launchGameWith(d);
|
|
285
|
-
JBRuleset memory fc = jbRulesets().currentOf(p);
|
|
286
|
-
if (fc.dataHook() == address(0)) (fc,) = jbRulesets().latestQueuedOf(p);
|
|
287
|
-
n = DefifaHook(fc.dataHook());
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
function _addr(uint256 i) internal pure returns (address) {
|
|
291
|
-
return address(bytes20(keccak256(abi.encode("su", i))));
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
function _mint(address user, uint256 tid, uint256 amt) internal {
|
|
295
|
-
vm.deal(user, amt);
|
|
296
|
-
uint16[] memory m = new uint16[](1);
|
|
297
|
-
// forge-lint: disable-next-line(unsafe-typecast)
|
|
298
|
-
m[0] = uint16(tid);
|
|
299
|
-
bytes[] memory data = new bytes[](1);
|
|
300
|
-
data[0] = abi.encode(user, m);
|
|
301
|
-
bytes4[] memory ids = new bytes4[](1);
|
|
302
|
-
ids[0] = metadataHelper().getId("pay", address(hook));
|
|
303
|
-
vm.prank(user);
|
|
304
|
-
jbMultiTerminal().pay{value: amt}(
|
|
305
|
-
_pid, JBConstants.NATIVE_TOKEN, amt, user, 0, "", metadataHelper().createMetadata(ids, data)
|
|
306
|
-
);
|
|
307
|
-
}
|
|
308
|
-
}
|