@rev-net/core-v6 0.0.34 → 0.0.35
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/ARCHITECTURE.md +14 -0
- package/RISKS.md +1 -1
- package/package.json +1 -1
- package/src/REVDeployer.sol +10 -0
- package/test/TestTerminalEncodingInHash.t.sol +326 -0
package/ARCHITECTURE.md
CHANGED
|
@@ -82,6 +82,18 @@ The repo does not replace core treasury accounting. Its critical economic logic
|
|
|
82
82
|
- If you change borrowability, re-check cash-out-delay gating, omnichain surplus inputs, and local-surplus caps together.
|
|
83
83
|
- If you change hook composition, re-check 721 split handling, buyback assumptions, and mint-permission flows.
|
|
84
84
|
|
|
85
|
+
## Cross-Chain Configuration Hash
|
|
86
|
+
|
|
87
|
+
`REVDeployer` produces an `encodedConfigurationHash` for each revnet that determines sucker deployment salts. This hash commits the revnet's identity across chains. It includes:
|
|
88
|
+
|
|
89
|
+
- `baseCurrency`, `description.name`, `description.ticker`, `description.salt`
|
|
90
|
+
- Terminal addresses (order-sensitive)
|
|
91
|
+
- Stage parameters (timing, issuance, splits, tax rates, auto-issuances)
|
|
92
|
+
|
|
93
|
+
Terminal addresses are included because they are deployed deterministically at the same address across chains. Accounting contexts (token addresses) are excluded because tokens like USDC legitimately differ per chain.
|
|
94
|
+
|
|
95
|
+
This means a revnet can only expand to a new chain if it uses the exact same terminal contract it used on the host chain. Different terminal addresses produce a different hash, preventing accidental cross-chain mismatches in sucker deployments.
|
|
96
|
+
|
|
85
97
|
## Canonical Checks
|
|
86
98
|
|
|
87
99
|
- cash-out-delay interaction with loans:
|
|
@@ -90,6 +102,8 @@ The repo does not replace core treasury accounting. Its critical economic logic
|
|
|
90
102
|
`test/TestStageTransitionBorrowable.t.sol`
|
|
91
103
|
- omnichain or phantom-surplus edge cases:
|
|
92
104
|
`test/audit/CodexPhantomSurplusTerminal.t.sol`
|
|
105
|
+
- terminal encoding in configuration hash:
|
|
106
|
+
`test/TestTerminalEncodingInHash.t.sol`
|
|
93
107
|
|
|
94
108
|
## Source Map
|
|
95
109
|
|
package/RISKS.md
CHANGED
|
@@ -86,4 +86,4 @@ The model assumes that attempts to inflate surplus through donations are not pro
|
|
|
86
86
|
|
|
87
87
|
### 8.5 Omnichain terminal expansion inherits remote-chain trust
|
|
88
88
|
|
|
89
|
-
A project that expands to a new chain can register additional terminals on that chain. Because borrowability calculations aggregate surplus from all registered terminals across all chains, a compromised or misconfigured terminal on a remote chain can corrupt the project's surplus accounting globally. This is
|
|
89
|
+
A project that expands to a new chain can register additional terminals on that chain. Because borrowability calculations aggregate surplus from all registered terminals across all chains, a compromised or misconfigured terminal on a remote chain can corrupt the project's surplus accounting globally. This is mitigated by including terminal addresses in the `encodedConfigurationHash` — cross-chain expansions via suckers must use the exact same terminal address as the host chain. Terminal addresses are deterministic across chains (same CREATE2 deployment), so this prevents expansions from silently using a different terminal. Project operators should still treat each chain expansion as a trust-boundary decision since bridge integrity and network assumptions remain outside protocol control.
|
package/package.json
CHANGED
package/src/REVDeployer.sol
CHANGED
|
@@ -956,6 +956,16 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
956
956
|
configuration.description.salt
|
|
957
957
|
);
|
|
958
958
|
|
|
959
|
+
// Include terminal addresses in the hash so cross-chain expansions must use the same terminals.
|
|
960
|
+
// Terminal addresses are deterministic across chains. Accounting contexts are excluded because
|
|
961
|
+
// token addresses (e.g. USDC) legitimately differ per chain.
|
|
962
|
+
for (uint256 i; i < terminalConfigurations.length;) {
|
|
963
|
+
encodedConfiguration = abi.encode(encodedConfiguration, terminalConfigurations[i].terminal);
|
|
964
|
+
unchecked {
|
|
965
|
+
++i;
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
|
|
959
969
|
// Initialize fund access limit groups for the loan contract.
|
|
960
970
|
JBFundAccessLimitGroup[] memory fundAccessLimitGroups =
|
|
961
971
|
_makeLoanFundAccessLimits({terminalConfigurations: terminalConfigurations});
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.28;
|
|
3
|
+
|
|
4
|
+
// forge-lint: disable-next-line(unaliased-plain-import)
|
|
5
|
+
import "forge-std/Test.sol";
|
|
6
|
+
// forge-lint: disable-next-line(unaliased-plain-import)
|
|
7
|
+
import /* {*} from */ "@bananapus/core-v6/test/helpers/TestBaseWorkflow.sol";
|
|
8
|
+
// forge-lint: disable-next-line(unaliased-plain-import)
|
|
9
|
+
import /* {*} from */ "./../src/REVDeployer.sol";
|
|
10
|
+
// forge-lint: disable-next-line(unaliased-plain-import)
|
|
11
|
+
import "@croptop/core-v6/src/CTPublisher.sol";
|
|
12
|
+
import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
|
|
13
|
+
|
|
14
|
+
// forge-lint: disable-next-line(unaliased-plain-import)
|
|
15
|
+
import "@bananapus/core-v6/script/helpers/CoreDeploymentLib.sol";
|
|
16
|
+
// forge-lint: disable-next-line(unaliased-plain-import)
|
|
17
|
+
import "@bananapus/721-hook-v6/script/helpers/Hook721DeploymentLib.sol";
|
|
18
|
+
// forge-lint: disable-next-line(unaliased-plain-import)
|
|
19
|
+
import "@bananapus/suckers-v6/script/helpers/SuckerDeploymentLib.sol";
|
|
20
|
+
// forge-lint: disable-next-line(unaliased-plain-import)
|
|
21
|
+
import "@croptop/core-v6/script/helpers/CroptopDeploymentLib.sol";
|
|
22
|
+
// forge-lint: disable-next-line(unaliased-plain-import)
|
|
23
|
+
import "@bananapus/router-terminal-v6/script/helpers/RouterTerminalDeploymentLib.sol";
|
|
24
|
+
|
|
25
|
+
import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
|
|
26
|
+
import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
|
|
27
|
+
import {REVLoans} from "../src/REVLoans.sol";
|
|
28
|
+
import {REVStageConfig, REVAutoIssuance} from "../src/structs/REVStageConfig.sol";
|
|
29
|
+
import {REVDescription} from "../src/structs/REVDescription.sol";
|
|
30
|
+
import {IREVLoans} from "./../src/interfaces/IREVLoans.sol";
|
|
31
|
+
import {JBSuckerDeployerConfig} from "@bananapus/suckers-v6/src/structs/JBSuckerDeployerConfig.sol";
|
|
32
|
+
import {JBSuckerRegistry} from "@bananapus/suckers-v6/src/JBSuckerRegistry.sol";
|
|
33
|
+
import {JB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
|
|
34
|
+
import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
|
|
35
|
+
import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
|
|
36
|
+
import {JB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/JB721CheckpointsDeployer.sol";
|
|
37
|
+
import {IJB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721CheckpointsDeployer.sol";
|
|
38
|
+
import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
|
|
39
|
+
import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
|
|
40
|
+
import {REVOwner} from "../src/REVOwner.sol";
|
|
41
|
+
import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
|
|
42
|
+
import {MockSuckerRegistry} from "./mock/MockSuckerRegistry.sol";
|
|
43
|
+
import {MockBuybackDataHook} from "./mock/MockBuybackDataHook.sol";
|
|
44
|
+
|
|
45
|
+
/// @notice Tests that terminal addresses are included in the encoded configuration hash.
|
|
46
|
+
contract TestTerminalEncodingInHash is TestBaseWorkflow {
|
|
47
|
+
using JBRulesetMetadataResolver for JBRuleset;
|
|
48
|
+
|
|
49
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
50
|
+
bytes32 REV_DEPLOYER_SALT = "REVDeployer";
|
|
51
|
+
|
|
52
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
53
|
+
REVDeployer REV_DEPLOYER;
|
|
54
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
55
|
+
REVOwner REV_OWNER;
|
|
56
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
57
|
+
IJB721TiersHookDeployer HOOK_DEPLOYER;
|
|
58
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
59
|
+
IJB721TiersHookStore HOOK_STORE;
|
|
60
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
61
|
+
IJBAddressRegistry ADDRESS_REGISTRY;
|
|
62
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
63
|
+
IREVLoans LOANS_CONTRACT;
|
|
64
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
65
|
+
IJBSuckerRegistry SUCKER_REGISTRY;
|
|
66
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
67
|
+
CTPublisher PUBLISHER;
|
|
68
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
69
|
+
MockBuybackDataHook MOCK_BUYBACK;
|
|
70
|
+
|
|
71
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
72
|
+
uint256 FEE_PROJECT_ID;
|
|
73
|
+
|
|
74
|
+
address private constant TRUSTED_FORWARDER = 0xB2b5841DBeF766d4b521221732F9B618fCf34A87;
|
|
75
|
+
|
|
76
|
+
function setUp() public override {
|
|
77
|
+
super.setUp();
|
|
78
|
+
|
|
79
|
+
FEE_PROJECT_ID = jbProjects().createFor(multisig());
|
|
80
|
+
|
|
81
|
+
SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
|
|
82
|
+
HOOK_STORE = new JB721TiersHookStore();
|
|
83
|
+
JB721TiersHook exampleHook = new JB721TiersHook(
|
|
84
|
+
jbDirectory(),
|
|
85
|
+
jbPermissions(),
|
|
86
|
+
jbPrices(),
|
|
87
|
+
jbRulesets(),
|
|
88
|
+
HOOK_STORE,
|
|
89
|
+
jbSplits(),
|
|
90
|
+
IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
|
|
91
|
+
multisig()
|
|
92
|
+
);
|
|
93
|
+
ADDRESS_REGISTRY = new JBAddressRegistry();
|
|
94
|
+
HOOK_DEPLOYER = new JB721TiersHookDeployer(exampleHook, HOOK_STORE, ADDRESS_REGISTRY, multisig());
|
|
95
|
+
PUBLISHER = new CTPublisher(jbDirectory(), jbPermissions(), FEE_PROJECT_ID, multisig());
|
|
96
|
+
MOCK_BUYBACK = new MockBuybackDataHook();
|
|
97
|
+
|
|
98
|
+
LOANS_CONTRACT = new REVLoans({
|
|
99
|
+
controller: jbController(),
|
|
100
|
+
suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
|
|
101
|
+
revId: FEE_PROJECT_ID,
|
|
102
|
+
owner: address(this),
|
|
103
|
+
permit2: permit2(),
|
|
104
|
+
trustedForwarder: TRUSTED_FORWARDER
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
REV_OWNER = new REVOwner(
|
|
108
|
+
IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
|
|
109
|
+
jbDirectory(),
|
|
110
|
+
FEE_PROJECT_ID,
|
|
111
|
+
SUCKER_REGISTRY,
|
|
112
|
+
address(LOANS_CONTRACT),
|
|
113
|
+
address(0)
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
|
|
117
|
+
jbController(),
|
|
118
|
+
SUCKER_REGISTRY,
|
|
119
|
+
FEE_PROJECT_ID,
|
|
120
|
+
HOOK_DEPLOYER,
|
|
121
|
+
PUBLISHER,
|
|
122
|
+
IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
|
|
123
|
+
address(LOANS_CONTRACT),
|
|
124
|
+
TRUSTED_FORWARDER,
|
|
125
|
+
address(REV_OWNER)
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
REV_OWNER.setDeployer(REV_DEPLOYER);
|
|
129
|
+
|
|
130
|
+
vm.prank(multisig());
|
|
131
|
+
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
132
|
+
|
|
133
|
+
// Deploy fee project.
|
|
134
|
+
_deployFeeProject();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/// @notice Two revnets with identical base config but different terminals produce different hashes.
|
|
138
|
+
function test_differentTerminals_produceDifferentHashes() public {
|
|
139
|
+
// Deploy revnet A with the primary multi-terminal (same description salt for both).
|
|
140
|
+
(uint256 revnetA,) = REV_DEPLOYER.deployFor({
|
|
141
|
+
revnetId: 0,
|
|
142
|
+
configuration: _baseRevConfig("DIFF_TERM"),
|
|
143
|
+
terminalConfigurations: _terminalConfigs(jbMultiTerminal()),
|
|
144
|
+
suckerDeploymentConfiguration: REVSuckerDeploymentConfig({
|
|
145
|
+
deployerConfigurations: new JBSuckerDeployerConfig[](0), salt: keccak256("A")
|
|
146
|
+
}),
|
|
147
|
+
tiered721HookConfiguration: REVEmpty721Config.empty721Config(uint32(uint160(JBConstants.NATIVE_TOKEN))),
|
|
148
|
+
allowedPosts: REVEmpty721Config.emptyAllowedPosts()
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Deploy revnet B with the secondary multi-terminal (same config, only terminal differs).
|
|
152
|
+
(uint256 revnetB,) = REV_DEPLOYER.deployFor({
|
|
153
|
+
revnetId: 0,
|
|
154
|
+
configuration: _baseRevConfig("DIFF_TERM"),
|
|
155
|
+
terminalConfigurations: _terminalConfigs(jbMultiTerminal2()),
|
|
156
|
+
suckerDeploymentConfiguration: REVSuckerDeploymentConfig({
|
|
157
|
+
deployerConfigurations: new JBSuckerDeployerConfig[](0), salt: keccak256("B")
|
|
158
|
+
}),
|
|
159
|
+
tiered721HookConfiguration: REVEmpty721Config.empty721Config(uint32(uint160(JBConstants.NATIVE_TOKEN))),
|
|
160
|
+
allowedPosts: REVEmpty721Config.emptyAllowedPosts()
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
bytes32 hashA = REV_DEPLOYER.hashedEncodedConfigurationOf(revnetA);
|
|
164
|
+
bytes32 hashB = REV_DEPLOYER.hashedEncodedConfigurationOf(revnetB);
|
|
165
|
+
|
|
166
|
+
assertNotEq(hashA, hashB, "Different terminals must produce different configuration hashes");
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/// @notice The hash includes the terminal address — verify by computing it off-chain.
|
|
170
|
+
function test_hashIncludesTerminalAddress() public {
|
|
171
|
+
// Deploy a revnet.
|
|
172
|
+
(uint256 revnetId,) = REV_DEPLOYER.deployFor({
|
|
173
|
+
revnetId: 0,
|
|
174
|
+
configuration: _baseRevConfig("VERIFY"),
|
|
175
|
+
terminalConfigurations: _terminalConfigs(jbMultiTerminal()),
|
|
176
|
+
suckerDeploymentConfiguration: REVSuckerDeploymentConfig({
|
|
177
|
+
deployerConfigurations: new JBSuckerDeployerConfig[](0), salt: keccak256("VERIFY")
|
|
178
|
+
}),
|
|
179
|
+
tiered721HookConfiguration: REVEmpty721Config.empty721Config(uint32(uint160(JBConstants.NATIVE_TOKEN))),
|
|
180
|
+
allowedPosts: REVEmpty721Config.emptyAllowedPosts()
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Recompute the expected hash manually.
|
|
184
|
+
bytes memory encodedConfiguration = abi.encode(
|
|
185
|
+
uint32(uint160(JBConstants.NATIVE_TOKEN)), // baseCurrency
|
|
186
|
+
"Terminal Test", // name
|
|
187
|
+
"TERM", // ticker
|
|
188
|
+
bytes32("VERIFY") // salt
|
|
189
|
+
);
|
|
190
|
+
// Terminal address encoding.
|
|
191
|
+
encodedConfiguration = abi.encode(encodedConfiguration, jbMultiTerminal());
|
|
192
|
+
// Stage encoding.
|
|
193
|
+
encodedConfiguration = abi.encode(
|
|
194
|
+
encodedConfiguration,
|
|
195
|
+
block.timestamp, // startsAtOrAfter
|
|
196
|
+
uint256(0), // splitPercent
|
|
197
|
+
uint112(1000e18), // initialIssuance
|
|
198
|
+
uint256(0), // issuanceCutFrequency
|
|
199
|
+
uint256(0), // issuanceCutPercent
|
|
200
|
+
uint256(5000) // cashOutTaxRate
|
|
201
|
+
);
|
|
202
|
+
bytes32 expectedHash = keccak256(encodedConfiguration);
|
|
203
|
+
|
|
204
|
+
assertEq(
|
|
205
|
+
REV_DEPLOYER.hashedEncodedConfigurationOf(revnetId),
|
|
206
|
+
expectedHash,
|
|
207
|
+
"On-chain hash must match off-chain computation including terminal address"
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/// @notice Terminal ordering matters — [A, B] != [B, A].
|
|
212
|
+
function test_terminalOrder_affectsHash() public {
|
|
213
|
+
// Deploy revnet with terminals in order [main, alt].
|
|
214
|
+
JBTerminalConfig[] memory tcAB = new JBTerminalConfig[](2);
|
|
215
|
+
JBAccountingContext[] memory acc = new JBAccountingContext[](1);
|
|
216
|
+
acc[0] = JBAccountingContext({
|
|
217
|
+
token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
|
|
218
|
+
});
|
|
219
|
+
tcAB[0] = JBTerminalConfig({terminal: jbMultiTerminal(), accountingContextsToAccept: acc});
|
|
220
|
+
tcAB[1] = JBTerminalConfig({terminal: jbMultiTerminal2(), accountingContextsToAccept: acc});
|
|
221
|
+
|
|
222
|
+
(uint256 revnetAB,) = REV_DEPLOYER.deployFor({
|
|
223
|
+
revnetId: 0,
|
|
224
|
+
configuration: _baseRevConfig("ORDER"),
|
|
225
|
+
terminalConfigurations: tcAB,
|
|
226
|
+
suckerDeploymentConfiguration: REVSuckerDeploymentConfig({
|
|
227
|
+
deployerConfigurations: new JBSuckerDeployerConfig[](0), salt: keccak256("AB")
|
|
228
|
+
}),
|
|
229
|
+
tiered721HookConfiguration: REVEmpty721Config.empty721Config(uint32(uint160(JBConstants.NATIVE_TOKEN))),
|
|
230
|
+
allowedPosts: REVEmpty721Config.emptyAllowedPosts()
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Deploy revnet with terminals in order [alt, main].
|
|
234
|
+
JBTerminalConfig[] memory tcBA = new JBTerminalConfig[](2);
|
|
235
|
+
tcBA[0] = JBTerminalConfig({terminal: jbMultiTerminal2(), accountingContextsToAccept: acc});
|
|
236
|
+
tcBA[1] = JBTerminalConfig({terminal: jbMultiTerminal(), accountingContextsToAccept: acc});
|
|
237
|
+
|
|
238
|
+
(uint256 revnetBA,) = REV_DEPLOYER.deployFor({
|
|
239
|
+
revnetId: 0,
|
|
240
|
+
configuration: _baseRevConfig("ORDER"),
|
|
241
|
+
terminalConfigurations: tcBA,
|
|
242
|
+
suckerDeploymentConfiguration: REVSuckerDeploymentConfig({
|
|
243
|
+
deployerConfigurations: new JBSuckerDeployerConfig[](0), salt: keccak256("BA")
|
|
244
|
+
}),
|
|
245
|
+
tiered721HookConfiguration: REVEmpty721Config.empty721Config(uint32(uint160(JBConstants.NATIVE_TOKEN))),
|
|
246
|
+
allowedPosts: REVEmpty721Config.emptyAllowedPosts()
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
bytes32 hashAB = REV_DEPLOYER.hashedEncodedConfigurationOf(revnetAB);
|
|
250
|
+
bytes32 hashBA = REV_DEPLOYER.hashedEncodedConfigurationOf(revnetBA);
|
|
251
|
+
|
|
252
|
+
assertNotEq(hashAB, hashBA, "Terminal order must affect the configuration hash");
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// ─── Helpers
|
|
256
|
+
// ───────────────────────────────────────────────────────────────
|
|
257
|
+
// //
|
|
258
|
+
|
|
259
|
+
function _baseRevConfig(bytes32 salt) internal view returns (REVConfig memory) {
|
|
260
|
+
REVStageConfig[] memory stages = new REVStageConfig[](1);
|
|
261
|
+
stages[0] = REVStageConfig({
|
|
262
|
+
startsAtOrAfter: uint48(block.timestamp),
|
|
263
|
+
autoIssuances: new REVAutoIssuance[](0),
|
|
264
|
+
splitPercent: 0,
|
|
265
|
+
splits: new JBSplit[](0),
|
|
266
|
+
initialIssuance: uint112(1000e18),
|
|
267
|
+
issuanceCutFrequency: 0,
|
|
268
|
+
issuanceCutPercent: 0,
|
|
269
|
+
cashOutTaxRate: 5000,
|
|
270
|
+
extraMetadata: 0
|
|
271
|
+
});
|
|
272
|
+
return REVConfig({
|
|
273
|
+
description: REVDescription("Terminal Test", "TERM", "", salt),
|
|
274
|
+
baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
|
|
275
|
+
splitOperator: multisig(),
|
|
276
|
+
stageConfigurations: stages
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function _terminalConfigs(IJBMultiTerminal terminal) internal pure returns (JBTerminalConfig[] memory tc) {
|
|
281
|
+
JBAccountingContext[] memory acc = new JBAccountingContext[](1);
|
|
282
|
+
acc[0] = JBAccountingContext({
|
|
283
|
+
token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
|
|
284
|
+
});
|
|
285
|
+
tc = new JBTerminalConfig[](1);
|
|
286
|
+
tc[0] = JBTerminalConfig({terminal: terminal, accountingContextsToAccept: acc});
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function _deployFeeProject() internal {
|
|
290
|
+
JBAccountingContext[] memory acc = new JBAccountingContext[](1);
|
|
291
|
+
acc[0] = JBAccountingContext({
|
|
292
|
+
token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
|
|
293
|
+
});
|
|
294
|
+
JBTerminalConfig[] memory tc = new JBTerminalConfig[](1);
|
|
295
|
+
tc[0] = JBTerminalConfig({terminal: jbMultiTerminal(), accountingContextsToAccept: acc});
|
|
296
|
+
REVStageConfig[] memory stages = new REVStageConfig[](1);
|
|
297
|
+
stages[0] = REVStageConfig({
|
|
298
|
+
startsAtOrAfter: uint48(block.timestamp),
|
|
299
|
+
autoIssuances: new REVAutoIssuance[](0),
|
|
300
|
+
splitPercent: 0,
|
|
301
|
+
splits: new JBSplit[](0),
|
|
302
|
+
initialIssuance: uint112(1000e18),
|
|
303
|
+
issuanceCutFrequency: 0,
|
|
304
|
+
issuanceCutPercent: 0,
|
|
305
|
+
cashOutTaxRate: 0,
|
|
306
|
+
extraMetadata: 0
|
|
307
|
+
});
|
|
308
|
+
REVConfig memory feeConfig = REVConfig({
|
|
309
|
+
description: REVDescription("Fee Project", "FEE", "", bytes32("FEE")),
|
|
310
|
+
baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
|
|
311
|
+
splitOperator: multisig(),
|
|
312
|
+
stageConfigurations: stages
|
|
313
|
+
});
|
|
314
|
+
vm.prank(multisig());
|
|
315
|
+
REV_DEPLOYER.deployFor({
|
|
316
|
+
revnetId: FEE_PROJECT_ID,
|
|
317
|
+
configuration: feeConfig,
|
|
318
|
+
terminalConfigurations: tc,
|
|
319
|
+
suckerDeploymentConfiguration: REVSuckerDeploymentConfig({
|
|
320
|
+
deployerConfigurations: new JBSuckerDeployerConfig[](0), salt: keccak256("FEE")
|
|
321
|
+
}),
|
|
322
|
+
tiered721HookConfiguration: REVEmpty721Config.empty721Config(uint32(uint160(JBConstants.NATIVE_TOKEN))),
|
|
323
|
+
allowedPosts: REVEmpty721Config.emptyAllowedPosts()
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
}
|