@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 +1 -1
- package/script/Deploy.s.sol +71 -96
- package/script/helpers/RevnetCoreDeploymentLib.sol +12 -17
- package/src/REVDeployer.sol +4 -2
- package/src/REVLoans.sol +8 -0
- package/src/REVOwner.sol +12 -12
- package/src/interfaces/IREVOwner.sol +2 -2
package/package.json
CHANGED
package/script/Deploy.s.sol
CHANGED
|
@@ -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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
102
|
+
operator = safeAddress();
|
|
126
103
|
// Get the loans owner address.
|
|
127
|
-
|
|
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
|
-
|
|
173
|
-
|
|
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:
|
|
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(
|
|
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:
|
|
213
|
-
issuanceConfs[1] = REVAutoIssuance({chainId: 8453, count:
|
|
214
|
-
issuanceConfs[2] = REVAutoIssuance({chainId: 10, count:
|
|
215
|
-
issuanceConfs[3] = REVAutoIssuance({chainId: 42_161, count:
|
|
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:
|
|
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 *
|
|
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:
|
|
212
|
+
chainId: _PREMINT_CHAIN_ID,
|
|
236
213
|
// forge-lint: disable-next-line(unsafe-typecast)
|
|
237
|
-
count: uint104(1_550_000 *
|
|
238
|
-
beneficiary:
|
|
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:
|
|
269
|
-
baseCurrency:
|
|
270
|
-
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:
|
|
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:
|
|
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
|
-
|
|
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
|
|
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:
|
|
364
|
+
salt: _REVLOANS_SALT,
|
|
389
365
|
creationCode: type(REVLoans).creationCode,
|
|
390
366
|
arguments: abi.encode(
|
|
391
|
-
core.controller, suckers.registry, _candidateId,
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
424
|
+
feeProjectId = i;
|
|
449
425
|
_foundExisting = true;
|
|
450
426
|
break;
|
|
451
427
|
}
|
|
452
428
|
}
|
|
453
429
|
}
|
|
454
430
|
if (!_foundExisting) {
|
|
455
|
-
|
|
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:
|
|
438
|
+
: new REVLoans{salt: _REVLOANS_SALT}({
|
|
464
439
|
controller: core.controller,
|
|
465
440
|
suckerRegistry: suckers.registry,
|
|
466
|
-
revId:
|
|
467
|
-
owner:
|
|
468
|
-
permit2:
|
|
469
|
-
trustedForwarder:
|
|
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:
|
|
450
|
+
: new REVOwner{salt: _REVOWNER_SALT}({
|
|
476
451
|
buybackHook: IJBBuybackHookRegistry(address(buybackHook.registry)),
|
|
477
452
|
directory: core.controller.DIRECTORY(),
|
|
478
|
-
feeRevnetId:
|
|
453
|
+
feeRevnetId: feeProjectId,
|
|
479
454
|
suckerRegistry: suckers.registry,
|
|
480
455
|
loans: revloans,
|
|
481
|
-
|
|
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:
|
|
463
|
+
salt: _DEPLOYER_SALT,
|
|
489
464
|
creationCode: type(REVDeployer).creationCode,
|
|
490
465
|
arguments: abi.encode(
|
|
491
466
|
core.controller,
|
|
492
467
|
suckers.registry,
|
|
493
|
-
|
|
468
|
+
feeProjectId,
|
|
494
469
|
hook.hook_deployer,
|
|
495
470
|
croptop.publisher,
|
|
496
471
|
IJBBuybackHookRegistry(address(buybackHook.registry)),
|
|
497
472
|
revloans,
|
|
498
|
-
|
|
473
|
+
trustedForwarder,
|
|
499
474
|
address(revOwner)
|
|
500
475
|
)
|
|
501
476
|
});
|
|
502
|
-
if (address(revOwner.
|
|
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:
|
|
482
|
+
: new REVDeployer{salt: _DEPLOYER_SALT}({
|
|
508
483
|
controller: core.controller,
|
|
509
484
|
suckerRegistry: suckers.registry,
|
|
510
|
-
feeRevnetId:
|
|
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:
|
|
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(
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
-
//
|
|
25
|
+
// Match the current chain ID to the Sphinx network name used in deployment artifacts.
|
|
27
26
|
uint256 chainId = block.chainid;
|
|
28
27
|
|
|
29
|
-
//
|
|
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,
|
|
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
|
-
|
|
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.
|
|
49
|
+
deployment.basicDeployer = IREVDeployer(
|
|
53
50
|
_getDeploymentAddress({
|
|
54
|
-
path: path,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
79
|
-
string memory
|
|
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,
|
|
85
|
+
vm.readFile(string.concat(path, projectName, "/", networkName, "/", contractName, ".json"));
|
|
91
86
|
return stdJson.readAddress({json: deploymentJson, key: ".address"});
|
|
92
87
|
}
|
|
93
88
|
}
|
package/src/REVDeployer.sol
CHANGED
|
@@ -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 =
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
512
|
-
function setDeployer(IREVDeployer
|
|
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(
|
|
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
|
-
|
|
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(
|
|
527
|
-
revert REVOwner_Unauthorized({caller: msg.sender, expectedCaller: address(
|
|
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(
|
|
538
|
-
revert REVOwner_Unauthorized({caller: msg.sender, expectedCaller: address(
|
|
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
|
|
15
|
-
function setDeployer(IREVDeployer
|
|
14
|
+
/// @param newDeployer The revnet deployer instance.
|
|
15
|
+
function setDeployer(IREVDeployer newDeployer) external;
|
|
16
16
|
}
|