@rev-net/core-v6 0.0.57 → 0.0.58

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rev-net/core-v6",
3
- "version": "0.0.57",
3
+ "version": "0.0.58",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -67,54 +67,31 @@ contract DeployScript is Script, Sphinx {
67
67
  SuckerDeployment suckers;
68
68
  /// @notice tracks the deployment of the router terminal.
69
69
  RouterTerminalDeployment routerTerminal;
70
-
71
- // forge-lint: disable-next-line(mixed-case-variable)
72
- uint32 PREMINT_CHAIN_ID = 1;
73
- // forge-lint: disable-next-line(mixed-case-variable)
74
- string NAME = "Revnet";
75
- // forge-lint: disable-next-line(mixed-case-variable)
76
- string SYMBOL = "REV";
77
- // forge-lint: disable-next-line(mixed-case-variable)
78
- string PROJECT_URI = "ipfs://QmcCBD5fM927LjkLDSJWtNEU9FohcbiPSfqtGRHXFHzJ4W";
79
- // forge-lint: disable-next-line(mixed-case-variable)
80
- uint32 NATIVE_CURRENCY = uint32(uint160(JBConstants.NATIVE_TOKEN));
81
- // forge-lint: disable-next-line(mixed-case-variable)
82
- uint32 ETH_CURRENCY = JBCurrencyIds.ETH;
83
- // forge-lint: disable-next-line(mixed-case-variable)
84
- uint8 DECIMALS = 18;
85
- // forge-lint: disable-next-line(mixed-case-variable)
86
- uint256 DECIMAL_MULTIPLIER = 10 ** DECIMALS;
87
- // forge-lint: disable-next-line(mixed-case-variable)
88
- bytes32 ERC20_SALT = "_REV_ERC20_SALT_V6_";
89
- // forge-lint: disable-next-line(mixed-case-variable)
90
- bytes32 SUCKER_SALT = "_REV_SUCKER_SALT_V6_";
91
- // forge-lint: disable-next-line(mixed-case-variable)
92
- bytes32 DEPLOYER_SALT = "_REV_DEPLOYER_SALT_V6_";
93
- // forge-lint: disable-next-line(mixed-case-variable)
94
- bytes32 REVLOANS_SALT = "_REV_LOANS_SALT_V6_";
95
- // forge-lint: disable-next-line(mixed-case-variable)
96
- bytes32 REVOWNER_SALT = "_REV_OWNER_SALT_V6_";
97
- // forge-lint: disable-next-line(mixed-case-variable)
98
- address LOANS_OWNER;
99
- // forge-lint: disable-next-line(mixed-case-variable)
100
- address OPERATOR;
101
- // forge-lint: disable-next-line(mixed-case-variable)
102
- address TRUSTED_FORWARDER;
103
- // forge-lint: disable-next-line(mixed-case-variable)
104
- IPermit2 PERMIT2;
105
- // forge-lint: disable-next-line(mixed-case-variable)
106
- uint48 REV_START_TIME = 1_740_089_444;
107
- // forge-lint: disable-next-line(mixed-case-variable)
108
- uint104 REV_MAINNET_AUTO_ISSUANCE_ = 1_050_482_341_387_116_262_330_122;
109
- // forge-lint: disable-next-line(mixed-case-variable)
110
- uint104 REV_BASE_AUTO_ISSUANCE_ = 38_544_322_230_437_559_731_228;
111
- // forge-lint: disable-next-line(mixed-case-variable)
112
- uint104 REV_OP_AUTO_ISSUANCE_ = 32_069_388_242_375_817_844;
113
- // forge-lint: disable-next-line(mixed-case-variable)
114
- uint104 REV_ARB_AUTO_ISSUANCE_ = 3_479_431_776_906_850_000_000;
70
+ uint32 private constant _PREMINT_CHAIN_ID = 1;
71
+ string private constant _NAME = "Revnet";
72
+ string private constant _SYMBOL = "REV";
73
+ string private constant _PROJECT_URI = "ipfs://QmcCBD5fM927LjkLDSJWtNEU9FohcbiPSfqtGRHXFHzJ4W";
74
+ uint32 private constant _NATIVE_CURRENCY = uint32(uint160(JBConstants.NATIVE_TOKEN));
75
+ uint32 private constant _ETH_CURRENCY = JBCurrencyIds.ETH;
76
+ uint8 private constant _DECIMALS = 18;
77
+ uint256 private constant _DECIMAL_MULTIPLIER = 10 ** _DECIMALS;
78
+ bytes32 private constant _ERC20_SALT = "_REV_ERC20_SALT_V6_";
79
+ bytes32 private constant _SUCKER_SALT = "_REV_SUCKER_SALT_V6_";
80
+ bytes32 private constant _DEPLOYER_SALT = "_REV_DEPLOYER_SALT_V6_";
81
+ bytes32 private constant _REVLOANS_SALT = "_REV_LOANS_SALT_V6_";
82
+ bytes32 private constant _REVOWNER_SALT = "_REV_OWNER_SALT_V6_";
83
+ address private loansOwner;
84
+ address private operator;
85
+ address private trustedForwarder;
86
+ IPermit2 private permit2;
87
+ uint48 private constant _REV_START_TIME = 1_740_089_444;
88
+ uint104 private constant _REV_MAINNET_AUTO_ISSUANCE = 1_050_482_341_387_116_262_330_122;
89
+ uint104 private constant _REV_BASE_AUTO_ISSUANCE = 38_544_322_230_437_559_731_228;
90
+ uint104 private constant _REV_OP_AUTO_ISSUANCE = 32_069_388_242_375_817_844;
91
+ uint104 private constant _REV_ARB_AUTO_ISSUANCE = 3_479_431_776_906_850_000_000;
115
92
 
116
93
  function configureSphinx() public override {
117
- // TODO: Update to contain revnet devs.
94
+ // Safe owners and threshold are resolved by the Sphinx project config.
118
95
  sphinxConfig.projectName = "revnet-core-v6";
119
96
  sphinxConfig.mainnets = ["ethereum", "optimism", "base", "arbitrum"];
120
97
  sphinxConfig.testnets = ["ethereum_sepolia", "optimism_sepolia", "base_sepolia", "arbitrum_sepolia"];
@@ -122,9 +99,9 @@ contract DeployScript is Script, Sphinx {
122
99
 
123
100
  function run() public {
124
101
  // Get the operator address.
125
- OPERATOR = safeAddress();
102
+ operator = safeAddress();
126
103
  // Get the loans owner address.
127
- LOANS_OWNER = safeAddress();
104
+ loansOwner = safeAddress();
128
105
 
129
106
  // Get the deployment addresses for the nana CORE for this chain.
130
107
  // We want to do this outside of the `sphinx` modifier.
@@ -169,8 +146,8 @@ contract DeployScript is Script, Sphinx {
169
146
  );
170
147
 
171
148
  // We use the same trusted forwarder and permit2 as the core deployment.
172
- TRUSTED_FORWARDER = core.controller.trustedForwarder();
173
- PERMIT2 = core.terminal.PERMIT2();
149
+ trustedForwarder = core.controller.trustedForwarder();
150
+ permit2 = core.terminal.PERMIT2();
174
151
 
175
152
  // Perform the deployment transactions.
176
153
  deploy();
@@ -182,7 +159,7 @@ contract DeployScript is Script, Sphinx {
182
159
 
183
160
  // Accept the chain's native currency through the multi terminal.
184
161
  accountingContextsToAccept[0] =
185
- JBAccountingContext({token: JBConstants.NATIVE_TOKEN, decimals: DECIMALS, currency: NATIVE_CURRENCY});
162
+ JBAccountingContext({token: JBConstants.NATIVE_TOKEN, decimals: _DECIMALS, currency: _NATIVE_CURRENCY});
186
163
 
187
164
  // The terminals that the project will accept funds through.
188
165
  JBTerminalConfig[] memory terminalConfigurations = new JBTerminalConfig[](2);
@@ -202,25 +179,25 @@ contract DeployScript is Script, Sphinx {
202
179
  preferAddToBalance: false,
203
180
  percent: JBConstants.SPLITS_TOTAL_PERCENT,
204
181
  projectId: 0,
205
- beneficiary: payable(OPERATOR),
182
+ beneficiary: payable(operator),
206
183
  lockedUntil: 0,
207
184
  hook: IJBSplitHook(address(0))
208
185
  });
209
186
 
210
187
  {
211
188
  REVAutoIssuance[] memory issuanceConfs = new REVAutoIssuance[](4);
212
- issuanceConfs[0] = REVAutoIssuance({chainId: 1, count: REV_MAINNET_AUTO_ISSUANCE_, beneficiary: OPERATOR});
213
- issuanceConfs[1] = REVAutoIssuance({chainId: 8453, count: REV_BASE_AUTO_ISSUANCE_, beneficiary: OPERATOR});
214
- issuanceConfs[2] = REVAutoIssuance({chainId: 10, count: REV_OP_AUTO_ISSUANCE_, beneficiary: OPERATOR});
215
- issuanceConfs[3] = REVAutoIssuance({chainId: 42_161, count: REV_ARB_AUTO_ISSUANCE_, beneficiary: OPERATOR});
189
+ issuanceConfs[0] = REVAutoIssuance({chainId: 1, count: _REV_MAINNET_AUTO_ISSUANCE, beneficiary: operator});
190
+ issuanceConfs[1] = REVAutoIssuance({chainId: 8453, count: _REV_BASE_AUTO_ISSUANCE, beneficiary: operator});
191
+ issuanceConfs[2] = REVAutoIssuance({chainId: 10, count: _REV_OP_AUTO_ISSUANCE, beneficiary: operator});
192
+ issuanceConfs[3] = REVAutoIssuance({chainId: 42_161, count: _REV_ARB_AUTO_ISSUANCE, beneficiary: operator});
216
193
 
217
194
  stageConfigurations[0] = REVStageConfig({
218
- startsAtOrAfter: REV_START_TIME,
195
+ startsAtOrAfter: _REV_START_TIME,
219
196
  autoIssuances: issuanceConfs,
220
197
  splitPercent: 3800, // 38%
221
198
  splits: splits,
222
199
  // forge-lint: disable-next-line(unsafe-typecast)
223
- initialIssuance: uint112(10_000 * DECIMAL_MULTIPLIER),
200
+ initialIssuance: uint112(10_000 * _DECIMAL_MULTIPLIER),
224
201
  issuanceCutFrequency: 90 days,
225
202
  issuanceCutPercent: 380_000_000, // 38%
226
203
  cashOutTaxRate: 1000, // 0.1
@@ -232,10 +209,10 @@ contract DeployScript is Script, Sphinx {
232
209
  REVAutoIssuance[] memory issuanceConfs = new REVAutoIssuance[](1);
233
210
  issuanceConfs[0] = REVAutoIssuance({
234
211
  // forge-lint: disable-next-line(unsafe-typecast)
235
- chainId: PREMINT_CHAIN_ID,
212
+ chainId: _PREMINT_CHAIN_ID,
236
213
  // forge-lint: disable-next-line(unsafe-typecast)
237
- count: uint104(1_550_000 * DECIMAL_MULTIPLIER),
238
- beneficiary: OPERATOR
214
+ count: uint104(1_550_000 * _DECIMAL_MULTIPLIER),
215
+ beneficiary: operator
239
216
  });
240
217
 
241
218
  stageConfigurations[1] = REVStageConfig({
@@ -265,9 +242,9 @@ contract DeployScript is Script, Sphinx {
265
242
 
266
243
  // The project's revnet configuration
267
244
  REVConfig memory revnetConfiguration = REVConfig({
268
- description: REVDescription({name: NAME, ticker: SYMBOL, uri: PROJECT_URI, salt: ERC20_SALT}),
269
- baseCurrency: ETH_CURRENCY,
270
- operator: OPERATOR,
245
+ description: REVDescription({name: _NAME, ticker: _SYMBOL, uri: _PROJECT_URI, salt: _ERC20_SALT}),
246
+ baseCurrency: _ETH_CURRENCY,
247
+ operator: operator,
271
248
  scopeCashOutsToLocalBalances: false,
272
249
  stageConfigurations: stageConfigurations
273
250
  });
@@ -314,7 +291,7 @@ contract DeployScript is Script, Sphinx {
314
291
  }
315
292
  // Specify all sucker deployments.
316
293
  suckerDeploymentConfiguration =
317
- REVSuckerDeploymentConfig({deployerConfigurations: suckerDeployerConfigurations, salt: SUCKER_SALT});
294
+ REVSuckerDeploymentConfig({deployerConfigurations: suckerDeployerConfigurations, salt: _SUCKER_SALT});
318
295
  }
319
296
 
320
297
  return FeeProjectConfig({
@@ -329,7 +306,7 @@ contract DeployScript is Script, Sphinx {
329
306
  tokenUriResolver: IJB721TokenUriResolver(address(0)),
330
307
  contractUri: "",
331
308
  tiersConfig: JB721InitTiersConfig({
332
- tiers: new JB721TierConfig[](0), currency: ETH_CURRENCY, decimals: 18
309
+ tiers: new JB721TierConfig[](0), currency: _ETH_CURRENCY, decimals: 18
333
310
  }),
334
311
  flags: REV721TiersHookFlags({
335
312
  noNewTiersWithReserves: false,
@@ -351,8 +328,7 @@ contract DeployScript is Script, Sphinx {
351
328
  function deploy() public sphinx {
352
329
  // Check if singletons are already deployed before creating a new fee project.
353
330
  // This prevents creating orphan projects on script restarts.
354
- // forge-lint: disable-next-line(mixed-case-variable)
355
- uint256 FEE_PROJECT_ID;
331
+ uint256 feeProjectId;
356
332
 
357
333
  // Predict the REVLoans address for an arbitrary fee project ID to check if it exists.
358
334
  // We can't predict without a fee project ID, so we first check the REVDeployer which also stores it.
@@ -360,7 +336,7 @@ contract DeployScript is Script, Sphinx {
360
336
 
361
337
  // First, check if REVLoans is already deployed by trying with project ID = 0 (placeholder).
362
338
  // We need to iterate: if either singleton exists, extract the fee project ID from it.
363
- // Since both encode FEE_PROJECT_ID, we check if any code exists at the predicted address
339
+ // Since both encode feeProjectId, we check if any code exists at the predicted address
364
340
  // for sequential project IDs starting from 1.
365
341
 
366
342
  // A simpler approach: predict the REVDeployer address for each possible fee project ID
@@ -385,10 +361,10 @@ contract DeployScript is Script, Sphinx {
385
361
  for (uint256 _candidateId = 1; _candidateId < _nextProjectId; _candidateId++) {
386
362
  // Predict REVLoans address for this candidate fee project ID.
387
363
  (address _candidateRevloansAddr, bool _candidateRevloansDeployed) = _isDeployed({
388
- salt: REVLOANS_SALT,
364
+ salt: _REVLOANS_SALT,
389
365
  creationCode: type(REVLoans).creationCode,
390
366
  arguments: abi.encode(
391
- core.controller, suckers.registry, _candidateId, LOANS_OWNER, PERMIT2, TRUSTED_FORWARDER
367
+ core.controller, suckers.registry, _candidateId, loansOwner, permit2, trustedForwarder
392
368
  )
393
369
  });
394
370
 
@@ -396,14 +372,14 @@ contract DeployScript is Script, Sphinx {
396
372
  // Verify the fee project ID matches by reading the immutable.
397
373
  if (REVLoans(payable(_candidateRevloansAddr)).REV_ID() == _candidateId) {
398
374
  // Record the fee project ID from the existing deployment.
399
- FEE_PROJECT_ID = _candidateId;
375
+ feeProjectId = _candidateId;
400
376
  // Record the existing REVLoans address.
401
377
  _existingRevloansAddr = _candidateRevloansAddr;
402
378
  _revloansExists = true;
403
379
 
404
380
  // Also predict and verify the owner.
405
381
  (_existingOwnerAddr, _revOwnerExists) = _isDeployed({
406
- salt: REVOWNER_SALT,
382
+ salt: _REVOWNER_SALT,
407
383
  creationCode: type(REVOwner).creationCode,
408
384
  arguments: abi.encode(
409
385
  IJBBuybackHookRegistry(address(buybackHook.registry)),
@@ -417,7 +393,7 @@ contract DeployScript is Script, Sphinx {
417
393
 
418
394
  // Also predict and verify the deployer.
419
395
  (_existingDeployerAddr, _revDeployerExists) = _isDeployed({
420
- salt: DEPLOYER_SALT,
396
+ salt: _DEPLOYER_SALT,
421
397
  creationCode: type(REVDeployer).creationCode,
422
398
  arguments: abi.encode(
423
399
  core.controller,
@@ -427,7 +403,7 @@ contract DeployScript is Script, Sphinx {
427
403
  croptop.publisher,
428
404
  IJBBuybackHookRegistry(address(buybackHook.registry)),
429
405
  _candidateRevloansAddr,
430
- TRUSTED_FORWARDER,
406
+ trustedForwarder,
431
407
  _existingOwnerAddr
432
408
  )
433
409
  });
@@ -445,91 +421,90 @@ contract DeployScript is Script, Sphinx {
445
421
  for (uint256 i = _nextProjectId - 1; i >= 1; i--) {
446
422
  if (core.projects.ownerOf(i) == safeAddress()) {
447
423
  if (address(core.controller.DIRECTORY().controllerOf(i)) == address(0)) {
448
- FEE_PROJECT_ID = i;
424
+ feeProjectId = i;
449
425
  _foundExisting = true;
450
426
  break;
451
427
  }
452
428
  }
453
429
  }
454
430
  if (!_foundExisting) {
455
- // forge-lint: disable-next-line(mixed-case-variable)
456
- FEE_PROJECT_ID = core.projects.createFor(safeAddress());
431
+ feeProjectId = core.projects.createFor(safeAddress());
457
432
  }
458
433
  }
459
434
 
460
435
  // Deploy REVLoans first — it only depends on the controller.
461
436
  REVLoans revloans = _revloansExists
462
437
  ? REVLoans(payable(_existingRevloansAddr))
463
- : new REVLoans{salt: REVLOANS_SALT}({
438
+ : new REVLoans{salt: _REVLOANS_SALT}({
464
439
  controller: core.controller,
465
440
  suckerRegistry: suckers.registry,
466
- revId: FEE_PROJECT_ID,
467
- owner: LOANS_OWNER,
468
- permit2: PERMIT2,
469
- trustedForwarder: TRUSTED_FORWARDER
441
+ revId: feeProjectId,
442
+ owner: loansOwner,
443
+ permit2: permit2,
444
+ trustedForwarder: trustedForwarder
470
445
  });
471
446
 
472
447
  // Deploy REVOwner — the runtime data hook that handles pay and cash out callbacks.
473
448
  REVOwner revOwner = _revOwnerExists
474
449
  ? REVOwner(_existingOwnerAddr)
475
- : new REVOwner{salt: REVOWNER_SALT}({
450
+ : new REVOwner{salt: _REVOWNER_SALT}({
476
451
  buybackHook: IJBBuybackHookRegistry(address(buybackHook.registry)),
477
452
  directory: core.controller.DIRECTORY(),
478
- feeRevnetId: FEE_PROJECT_ID,
453
+ feeRevnetId: feeProjectId,
479
454
  suckerRegistry: suckers.registry,
480
455
  loans: revloans,
481
- deployer: msg.sender
456
+ deployerAddress: msg.sender
482
457
  });
483
458
 
484
459
  // Deploy REVDeployer with the REVLoans, buyback hook, and REVOwner addresses.
485
460
  (address _deployerAddr, bool _deployerIsDeployed) = _revDeployerExists
486
461
  ? (_existingDeployerAddr, true)
487
462
  : _isDeployed({
488
- salt: DEPLOYER_SALT,
463
+ salt: _DEPLOYER_SALT,
489
464
  creationCode: type(REVDeployer).creationCode,
490
465
  arguments: abi.encode(
491
466
  core.controller,
492
467
  suckers.registry,
493
- FEE_PROJECT_ID,
468
+ feeProjectId,
494
469
  hook.hook_deployer,
495
470
  croptop.publisher,
496
471
  IJBBuybackHookRegistry(address(buybackHook.registry)),
497
472
  revloans,
498
- TRUSTED_FORWARDER,
473
+ trustedForwarder,
499
474
  address(revOwner)
500
475
  )
501
476
  });
502
- if (address(revOwner.DEPLOYER()) == address(0)) {
477
+ if (address(revOwner.deployer()) == address(0)) {
503
478
  revOwner.setDeployer(IREVDeployer(_deployerAddr));
504
479
  }
505
480
  REVDeployer _basicDeployer = _deployerIsDeployed
506
481
  ? REVDeployer(payable(_deployerAddr))
507
- : new REVDeployer{salt: DEPLOYER_SALT}({
482
+ : new REVDeployer{salt: _DEPLOYER_SALT}({
508
483
  controller: core.controller,
509
484
  suckerRegistry: suckers.registry,
510
- feeRevnetId: FEE_PROJECT_ID,
485
+ feeRevnetId: feeProjectId,
511
486
  hookDeployer: hook.hook_deployer,
512
487
  publisher: croptop.publisher,
513
488
  buybackHook: IJBBuybackHookRegistry(address(buybackHook.registry)),
514
489
  loans: revloans,
515
- trustedForwarder: TRUSTED_FORWARDER,
490
+ trustedForwarder: trustedForwarder,
516
491
  owner: address(revOwner)
517
492
  });
518
493
 
519
494
  // Only configure the fee project if it doesn't already have a controller.
520
495
  // This handles both fresh deploys and restarts where singletons exist but the fee project
521
496
  // was not yet configured.
522
- bool _feeProjectConfigured = address(core.controller.DIRECTORY().controllerOf(FEE_PROJECT_ID)) != address(0);
497
+ bool _feeProjectConfigured = address(core.controller.DIRECTORY().controllerOf(feeProjectId)) != address(0);
523
498
  if (!_feeProjectConfigured) {
524
499
  // Approve the basic deployer to configure the project.
525
- core.projects.approve({to: address(_basicDeployer), tokenId: FEE_PROJECT_ID});
500
+ core.projects.approve({to: address(_basicDeployer), tokenId: feeProjectId});
526
501
 
527
502
  // Build the config.
528
503
  FeeProjectConfig memory feeProjectConfig = getFeeProjectConfig();
529
504
 
530
505
  // Configure the project.
531
506
  _basicDeployer.deployFor({
532
- revnetId: FEE_PROJECT_ID,
507
+ revnetId: feeProjectId,
533
508
  configuration: feeProjectConfig.configuration,
534
509
  terminalConfigurations: feeProjectConfig.terminalConfigurations,
535
510
  suckerDeploymentConfiguration: feeProjectConfig.suckerDeploymentConfiguration,
@@ -10,8 +10,7 @@ import {IREVLoans} from "./../../src/interfaces/IREVLoans.sol";
10
10
  import {REVOwner} from "./../../src/REVOwner.sol";
11
11
 
12
12
  struct RevnetCoreDeployment {
13
- // forge-lint: disable-next-line(mixed-case-variable)
14
- IREVDeployer basic_deployer;
13
+ IREVDeployer basicDeployer;
15
14
  IREVLoans loans;
16
15
  REVOwner owner;
17
16
  }
@@ -23,17 +22,16 @@ library RevnetCoreDeploymentLib {
23
22
  Vm internal constant vm = Vm(VM_ADDRESS);
24
23
 
25
24
  function getDeployment(string memory path) internal returns (RevnetCoreDeployment memory deployment) {
26
- // get chainId for which we need to get the deployment.
25
+ // Match the current chain ID to the Sphinx network name used in deployment artifacts.
27
26
  uint256 chainId = block.chainid;
28
27
 
29
- // Deploy to get the constants.
30
- // TODO: get constants without deploy.
28
+ // `SphinxConstants` exposes Sphinx's supported chain ID to network name mapping.
31
29
  SphinxConstants sphinxConstants = new SphinxConstants();
32
30
  NetworkInfo[] memory networks = sphinxConstants.getNetworkInfoArray();
33
31
 
34
32
  for (uint256 _i; _i < networks.length; _i++) {
35
33
  if (networks[_i].chainId == chainId) {
36
- return getDeployment({path: path, network_name: networks[_i].name});
34
+ return getDeployment({path: path, networkName: networks[_i].name});
37
35
  }
38
36
  }
39
37
 
@@ -42,28 +40,27 @@ library RevnetCoreDeploymentLib {
42
40
 
43
41
  function getDeployment(
44
42
  string memory path,
45
- // forge-lint: disable-next-line(mixed-case-variable)
46
- string memory network_name
43
+ string memory networkName
47
44
  )
48
45
  internal
49
46
  view
50
47
  returns (RevnetCoreDeployment memory deployment)
51
48
  {
52
- deployment.basic_deployer = IREVDeployer(
49
+ deployment.basicDeployer = IREVDeployer(
53
50
  _getDeploymentAddress({
54
- path: path, project_name: "revnet-core-v6", network_name: network_name, contractName: "REVDeployer"
51
+ path: path, projectName: "revnet-core-v6", networkName: networkName, contractName: "REVDeployer"
55
52
  })
56
53
  );
57
54
 
58
55
  deployment.loans = IREVLoans(
59
56
  _getDeploymentAddress({
60
- path: path, project_name: "revnet-core-v6", network_name: network_name, contractName: "REVLoans"
57
+ path: path, projectName: "revnet-core-v6", networkName: networkName, contractName: "REVLoans"
61
58
  })
62
59
  );
63
60
 
64
61
  deployment.owner = REVOwner(
65
62
  _getDeploymentAddress({
66
- path: path, project_name: "revnet-core-v6", network_name: network_name, contractName: "REVOwner"
63
+ path: path, projectName: "revnet-core-v6", networkName: networkName, contractName: "REVOwner"
67
64
  })
68
65
  );
69
66
  }
@@ -75,10 +72,8 @@ library RevnetCoreDeploymentLib {
75
72
  /// @return The address of the contract.
76
73
  function _getDeploymentAddress(
77
74
  string memory path,
78
- // forge-lint: disable-next-line(mixed-case-variable)
79
- string memory project_name,
80
- // forge-lint: disable-next-line(mixed-case-variable)
81
- string memory network_name,
75
+ string memory projectName,
76
+ string memory networkName,
82
77
  string memory contractName
83
78
  )
84
79
  internal
@@ -87,7 +82,7 @@ library RevnetCoreDeploymentLib {
87
82
  {
88
83
  string memory deploymentJson =
89
84
  // forge-lint: disable-next-line(unsafe-cheatcode)
90
- vm.readFile(string.concat(path, project_name, "/", network_name, "/", contractName, ".json"));
85
+ vm.readFile(string.concat(path, projectName, "/", networkName, "/", contractName, ".json"));
91
86
  return stdJson.readAddress({json: deploymentJson, key: ".address"});
92
87
  }
93
88
  }
@@ -415,10 +415,12 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
415
415
  sqrtPriceX96 = uint160(1 << 96);
416
416
  } else if (normalizedTerminalToken < projectToken) {
417
417
  // token0 = terminal, token1 = project → price = issuance / terminalTokenUnit
418
- sqrtPriceX96 = uint160(sqrt(mulDiv(uint256(initialIssuance), 1 << 192, terminalTokenUnit)));
418
+ sqrtPriceX96 =
419
+ uint160(sqrt(mulDiv({x: uint256(initialIssuance), y: 1 << 192, denominator: terminalTokenUnit})));
419
420
  } else {
420
421
  // token0 = project, token1 = terminal → price = terminalTokenUnit / issuance
421
- sqrtPriceX96 = uint160(sqrt(mulDiv(terminalTokenUnit, 1 << 192, uint256(initialIssuance))));
422
+ sqrtPriceX96 =
423
+ uint160(sqrt(mulDiv({x: terminalTokenUnit, y: 1 << 192, denominator: uint256(initialIssuance)})));
422
424
  }
423
425
  }
424
426
 
package/src/REVLoans.sol CHANGED
@@ -747,6 +747,14 @@ contract REVLoans is ERC721, ERC2771Context, JBPermissioned, Ownable, IREVLoans
747
747
  address loanOwner = _ownerOf(loanId);
748
748
  _requirePermissionFrom({account: loanOwner, projectId: revnetId, permissionId: JBPermissionIds.REALLOCATE_LOAN});
749
749
 
750
+ // If the caller is adding fresh holder collateral on top of the reallocated amount, they must also have
751
+ // OPEN_LOAN permission for the loan owner: that fresh collateral comes from the owner's project-token
752
+ // balance and would otherwise let a REALLOCATE_LOAN-only operator open a brand-new loan against the owner's
753
+ // tokens through this entry point, bypassing the OPEN_LOAN gate that `borrowFrom` enforces.
754
+ if (collateralCountToAdd != 0) {
755
+ _requirePermissionFrom({account: loanOwner, projectId: revnetId, permissionId: JBPermissionIds.OPEN_LOAN});
756
+ }
757
+
750
758
  // Make sure the loan hasn't expired.
751
759
  // forge-lint: disable-next-line(block-timestamp)
752
760
  if (block.timestamp - _loanOf[loanId].createdAt > LOAN_LIQUIDATION_DURATION) {
package/src/REVOwner.sol CHANGED
@@ -81,7 +81,7 @@ contract REVOwner is IJBRulesetDataHook, IJBCashOutHook, IJBPeerChainAdjustedAcc
81
81
 
82
82
  /// @notice The deployer that manages revnet state.
83
83
  /// @dev Set once via `setDeployer()` using the precomputed canonical REVDeployer address.
84
- IREVDeployer public DEPLOYER;
84
+ IREVDeployer public deployer;
85
85
 
86
86
  //*********************************************************************//
87
87
  // -------------------- private stored properties -------------------- //
@@ -99,7 +99,7 @@ contract REVOwner is IJBRulesetDataHook, IJBCashOutHook, IJBPeerChainAdjustedAcc
99
99
  /// @param feeRevnetId The Juicebox project ID of the fee revnet.
100
100
  /// @param suckerRegistry The sucker registry.
101
101
  /// @param loans The loan contract.
102
- /// @param deployer The account allowed to bind the canonical deployer via `setDeployer`. Passed explicitly
102
+ /// @param deployerAddress The account allowed to bind the canonical deployer via `setDeployer`. Passed explicitly
103
103
  /// because CREATE2 deployments set `msg.sender` to the factory, not the intended operator.
104
104
  constructor(
105
105
  IJBBuybackHookRegistry buybackHook,
@@ -107,14 +107,14 @@ contract REVOwner is IJBRulesetDataHook, IJBCashOutHook, IJBPeerChainAdjustedAcc
107
107
  uint256 feeRevnetId,
108
108
  IJBSuckerRegistry suckerRegistry,
109
109
  IREVLoans loans,
110
- address deployer
110
+ address deployerAddress
111
111
  ) {
112
112
  BUYBACK_HOOK = buybackHook;
113
113
  DIRECTORY = directory;
114
114
  FEE_REVNET_ID = feeRevnetId;
115
115
  SUCKER_REGISTRY = suckerRegistry;
116
116
  LOANS = loans;
117
- _DEPLOYER = deployer;
117
+ _DEPLOYER = deployerAddress;
118
118
  }
119
119
 
120
120
  //*********************************************************************//
@@ -508,14 +508,14 @@ contract REVOwner is IJBRulesetDataHook, IJBCashOutHook, IJBPeerChainAdjustedAcc
508
508
  /// @dev The deployer address is precomputed and supplied by the account that created this REVOwner instance.
509
509
  /// Only that deploy-time binder may call this, which avoids an ambient public initializer where any first caller
510
510
  /// could seize the deployer role before the deterministic REVDeployer is actually deployed.
511
- /// @param deployer The canonical REVDeployer instance that will manage revnet runtime state.
512
- function setDeployer(IREVDeployer deployer) external {
511
+ /// @param newDeployer The canonical REVDeployer instance that will manage revnet runtime state.
512
+ function setDeployer(IREVDeployer newDeployer) external {
513
513
  // Only the account that deployed this REVOwner may complete the one-time deployer binding.
514
514
  if (msg.sender != _DEPLOYER) revert REVOwner_Unauthorized({caller: msg.sender, expectedCaller: _DEPLOYER});
515
515
  // Prevent the deployer binding from being overwritten after initialization.
516
- if (address(DEPLOYER) != address(0)) revert REVOwner_AlreadyInitialized({deployer: address(DEPLOYER)});
516
+ if (address(deployer) != address(0)) revert REVOwner_AlreadyInitialized({deployer: address(deployer)});
517
517
  // Store the canonical REVDeployer that is authorized to manage runtime hook state.
518
- DEPLOYER = deployer;
518
+ deployer = newDeployer;
519
519
  }
520
520
 
521
521
  /// @notice Store the cash out delay for a revnet.
@@ -523,8 +523,8 @@ contract REVOwner is IJBRulesetDataHook, IJBCashOutHook, IJBPeerChainAdjustedAcc
523
523
  /// @param revnetId The ID of the revnet.
524
524
  /// @param cashOutDelay The timestamp after which cash outs are allowed.
525
525
  function setCashOutDelayOf(uint256 revnetId, uint256 cashOutDelay) external {
526
- if (msg.sender != address(DEPLOYER)) {
527
- revert REVOwner_Unauthorized({caller: msg.sender, expectedCaller: address(DEPLOYER)});
526
+ if (msg.sender != address(deployer)) {
527
+ revert REVOwner_Unauthorized({caller: msg.sender, expectedCaller: address(deployer)});
528
528
  }
529
529
  cashOutDelayOf[revnetId] = cashOutDelay;
530
530
  }
@@ -534,8 +534,8 @@ contract REVOwner is IJBRulesetDataHook, IJBCashOutHook, IJBPeerChainAdjustedAcc
534
534
  /// @param revnetId The ID of the revnet.
535
535
  /// @param hook The tiered ERC-721 hook.
536
536
  function setTiered721HookOf(uint256 revnetId, IJB721TiersHook hook) external {
537
- if (msg.sender != address(DEPLOYER)) {
538
- revert REVOwner_Unauthorized({caller: msg.sender, expectedCaller: address(DEPLOYER)});
537
+ if (msg.sender != address(deployer)) {
538
+ revert REVOwner_Unauthorized({caller: msg.sender, expectedCaller: address(deployer)});
539
539
  }
540
540
  tiered721HookOf[revnetId] = hook;
541
541
  }
@@ -11,6 +11,6 @@ interface IREVOwner {
11
11
  function cashOutDelayOf(uint256 revnetId) external view returns (uint256);
12
12
 
13
13
  /// @notice Bind the canonical deployer exactly once.
14
- /// @param deployer The revnet deployer instance.
15
- function setDeployer(IREVDeployer deployer) external;
14
+ /// @param newDeployer The revnet deployer instance.
15
+ function setDeployer(IREVDeployer newDeployer) external;
16
16
  }