@rev-net/core-v6 0.0.35 → 0.0.37
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/RISKS.md +19 -1
- package/package.json +9 -9
- package/src/REVDeployer.sol +19 -10
- package/src/REVLoans.sol +138 -89
- package/src/REVOwner.sol +6 -4
- package/test/REV.integrations.t.sol +14 -14
- package/test/REVInvincibility.t.sol +16 -16
- package/test/REVLifecycle.t.sol +32 -32
- package/test/REVLoansSourced.t.sol +15 -15
- package/test/TestCashOutCallerValidation.t.sol +8 -8
- package/test/TestConversionDocumentation.t.sol +2 -5
- package/test/TestCrossCurrencyReclaim.t.sol +72 -72
- package/test/TestLongTailEconomics.t.sol +56 -56
- package/test/TestSwapTerminalPermission.t.sol +21 -21
- package/test/audit/HiddenSupplyCashout.t.sol +61 -0
- package/test/audit/NemesisVerification.t.sol +97 -0
- package/test/audit/REVOwnerCurrencyMismatch.t.sol +188 -0
- package/test/audit/REVOwnerRemoteSurplusCurrencyMismatch.t.sol +140 -0
- package/test/audit/ReallocatePermission.t.sol +363 -0
- package/test/audit/RemoteLoanAccountingGap.t.sol +74 -0
- package/test/audit/SupportsInterfaceTest.t.sol +51 -0
- package/test/audit/TestFeeAllowanceLeak.t.sol +197 -0
- package/test/audit/TestLoansAndDeployerFixes.t.sol +576 -0
- package/test/fork/TestCashOutFork.t.sol +48 -48
- package/test/fork/TestLoanAdversarialFork.t.sol +744 -0
- package/test/fork/TestLoanERC20Fork.t.sol +2 -8
- package/test/fork/TestPermit2PaymentFork.t.sol +32 -32
- package/test/regression/TestBurnPermissionRequired.t.sol +5 -5
- package/test/regression/TestCashOutBuybackFeeLeak.t.sol +8 -8
- /package/test/audit/{CodexCrossChainBuybackRouteMismatch.t.sol → CrossChainBuybackRouteMismatch.t.sol} +0 -0
- /package/test/audit/{NemesisOperatorDelegation.t.sol → OperatorDelegation.t.sol} +0 -0
- /package/test/audit/{CodexPhantomSurplusTerminal.t.sol → PhantomSurplusTerminal.t.sol} +0 -0
|
@@ -751,11 +751,11 @@ contract REVLoansSourcedTests is TestBaseWorkflow {
|
|
|
751
751
|
|
|
752
752
|
uint256 fullReclaimableSurplus = jbMultiTerminal().STORE()
|
|
753
753
|
.currentReclaimableSurplusOf({
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
754
|
+
projectId: revnetProjectId,
|
|
755
|
+
cashOutCount: tokensToCashout,
|
|
756
|
+
totalSupply: totalSupplyExcludingAutoMint,
|
|
757
|
+
surplus: nativeSurplus
|
|
758
|
+
});
|
|
759
759
|
|
|
760
760
|
assertGe(fullReclaimableSurplus, loanable);
|
|
761
761
|
|
|
@@ -764,11 +764,11 @@ contract REVLoansSourcedTests is TestBaseWorkflow {
|
|
|
764
764
|
|
|
765
765
|
uint256 reclaimableSurplus = jbMultiTerminal().STORE()
|
|
766
766
|
.currentReclaimableSurplusOf({
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
767
|
+
projectId: revnetProjectId,
|
|
768
|
+
cashOutCount: tokensToCashout - feeTokenCount,
|
|
769
|
+
totalSupply: totalSupplyExcludingAutoMint,
|
|
770
|
+
surplus: nativeSurplus
|
|
771
|
+
});
|
|
772
772
|
|
|
773
773
|
// In the `revFee` calculation we decrease the `nativeSurplus` by the `reclaimableSurplus`
|
|
774
774
|
// but due to a `stack too deep` we can't do that there, so we decrease it here.
|
|
@@ -777,11 +777,11 @@ contract REVLoansSourcedTests is TestBaseWorkflow {
|
|
|
777
777
|
|
|
778
778
|
uint256 revFee = jbMultiTerminal().STORE()
|
|
779
779
|
.currentReclaimableSurplusOf({
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
780
|
+
projectId: revnetProjectId,
|
|
781
|
+
cashOutCount: feeTokenCount,
|
|
782
|
+
totalSupply: totalSupplyExcludingAutoMint - (tokensToCashout - feeTokenCount),
|
|
783
|
+
surplus: nativeSurplus
|
|
784
|
+
});
|
|
785
785
|
|
|
786
786
|
assertGe(fullReclaimableSurplus, mulDiv((reclaimableSurplus + revFee), 995, 1000)); // small marging for curve
|
|
787
787
|
// rounding.
|
|
@@ -315,14 +315,14 @@ contract TestCashOutCallerValidation is TestBaseWorkflow {
|
|
|
315
315
|
vm.prank(USER);
|
|
316
316
|
uint256 reclaimed = jbMultiTerminal()
|
|
317
317
|
.cashOutTokensOf({
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
318
|
+
holder: USER,
|
|
319
|
+
projectId: REVNET_ID,
|
|
320
|
+
cashOutCount: tokenCount,
|
|
321
|
+
tokenToReclaim: JBConstants.NATIVE_TOKEN,
|
|
322
|
+
minTokensReclaimed: 0,
|
|
323
|
+
beneficiary: payable(USER),
|
|
324
|
+
metadata: ""
|
|
325
|
+
});
|
|
326
326
|
|
|
327
327
|
assertGt(reclaimed, 0, "Should have reclaimed some ETH");
|
|
328
328
|
|
|
@@ -286,11 +286,8 @@ contract TestConversionDocumentation is TestBaseWorkflow {
|
|
|
286
286
|
vm.prank(USER);
|
|
287
287
|
jbController()
|
|
288
288
|
.launchRulesetsFor({
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
terminalConfigurations: termConfigs,
|
|
292
|
-
memo: ""
|
|
293
|
-
});
|
|
289
|
+
projectId: projectId, rulesetConfigurations: rulesetConfigs, terminalConfigurations: termConfigs, memo: ""
|
|
290
|
+
});
|
|
294
291
|
|
|
295
292
|
// Now try to convert this project to a revnet — should revert.
|
|
296
293
|
// Approve NFT to REV_DEPLOYER.
|
|
@@ -268,14 +268,14 @@ contract TestCrossCurrencyReclaim is TestBaseWorkflow {
|
|
|
268
268
|
vm.prank(USER1);
|
|
269
269
|
uint256 reclaimed = jbMultiTerminal()
|
|
270
270
|
.cashOutTokensOf({
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
271
|
+
holder: USER1,
|
|
272
|
+
projectId: REVNET_ID,
|
|
273
|
+
cashOutCount: tokens,
|
|
274
|
+
tokenToReclaim: JBConstants.NATIVE_TOKEN,
|
|
275
|
+
minTokensReclaimed: 0,
|
|
276
|
+
beneficiary: payable(USER1),
|
|
277
|
+
metadata: ""
|
|
278
|
+
});
|
|
279
279
|
|
|
280
280
|
assertGt(reclaimed, 0, "should reclaim some ETH");
|
|
281
281
|
// With 50% tax and single holder cashing out everything, the bonding curve returns the full surplus.
|
|
@@ -310,14 +310,14 @@ contract TestCrossCurrencyReclaim is TestBaseWorkflow {
|
|
|
310
310
|
vm.prank(USER1);
|
|
311
311
|
uint256 reclaimedToken = jbMultiTerminal()
|
|
312
312
|
.cashOutTokensOf({
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
313
|
+
holder: USER1,
|
|
314
|
+
projectId: REVNET_ID,
|
|
315
|
+
cashOutCount: revTokens,
|
|
316
|
+
tokenToReclaim: address(TOKEN),
|
|
317
|
+
minTokensReclaimed: 0,
|
|
318
|
+
beneficiary: payable(USER1),
|
|
319
|
+
metadata: ""
|
|
320
|
+
});
|
|
321
321
|
|
|
322
322
|
assertGt(reclaimedToken, 0, "should reclaim some TOKEN");
|
|
323
323
|
assertLe(reclaimedToken, tokenAmount, "should not exceed total TOKEN paid in");
|
|
@@ -358,14 +358,14 @@ contract TestCrossCurrencyReclaim is TestBaseWorkflow {
|
|
|
358
358
|
vm.expectRevert();
|
|
359
359
|
jbMultiTerminal()
|
|
360
360
|
.cashOutTokensOf({
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
361
|
+
holder: USER1,
|
|
362
|
+
projectId: REVNET_ID,
|
|
363
|
+
cashOutCount: revTokens,
|
|
364
|
+
tokenToReclaim: address(TOKEN),
|
|
365
|
+
minTokensReclaimed: 0,
|
|
366
|
+
beneficiary: payable(USER1),
|
|
367
|
+
metadata: ""
|
|
368
|
+
});
|
|
369
369
|
}
|
|
370
370
|
|
|
371
371
|
/// @notice Pay with TOKEN (so the surplus is in TOKEN), then pay with ETH too.
|
|
@@ -395,14 +395,14 @@ contract TestCrossCurrencyReclaim is TestBaseWorkflow {
|
|
|
395
395
|
vm.prank(USER1);
|
|
396
396
|
uint256 reclaimedToken = jbMultiTerminal()
|
|
397
397
|
.cashOutTokensOf({
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
398
|
+
holder: USER1,
|
|
399
|
+
projectId: REVNET_ID,
|
|
400
|
+
cashOutCount: cashOutCount,
|
|
401
|
+
tokenToReclaim: address(TOKEN),
|
|
402
|
+
minTokensReclaimed: 0,
|
|
403
|
+
beneficiary: payable(USER1),
|
|
404
|
+
metadata: ""
|
|
405
|
+
});
|
|
406
406
|
|
|
407
407
|
assertGt(reclaimedToken, 0, "should reclaim some TOKEN");
|
|
408
408
|
assertLe(reclaimedToken, tokenPayment, "should not exceed total TOKEN paid in");
|
|
@@ -442,14 +442,14 @@ contract TestCrossCurrencyReclaim is TestBaseWorkflow {
|
|
|
442
442
|
vm.prank(USER1);
|
|
443
443
|
uint256 reclaimed = jbMultiTerminal()
|
|
444
444
|
.cashOutTokensOf({
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
445
|
+
holder: USER1,
|
|
446
|
+
projectId: REVNET_ID,
|
|
447
|
+
cashOutCount: tokens1,
|
|
448
|
+
tokenToReclaim: JBConstants.NATIVE_TOKEN,
|
|
449
|
+
minTokensReclaimed: 0,
|
|
450
|
+
beneficiary: payable(USER1),
|
|
451
|
+
metadata: ""
|
|
452
|
+
});
|
|
453
453
|
assertGt(reclaimed, 0, "should reclaim ETH from mixed-currency surplus");
|
|
454
454
|
|
|
455
455
|
// The reclaimed amount should be less than the original payment (due to bonding curve tax).
|
|
@@ -480,14 +480,14 @@ contract TestCrossCurrencyReclaim is TestBaseWorkflow {
|
|
|
480
480
|
vm.prank(USER1);
|
|
481
481
|
uint256 reclaimed = jbMultiTerminal()
|
|
482
482
|
.cashOutTokensOf({
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
483
|
+
holder: USER1,
|
|
484
|
+
projectId: REVNET_ID,
|
|
485
|
+
cashOutCount: tokens,
|
|
486
|
+
tokenToReclaim: JBConstants.NATIVE_TOKEN,
|
|
487
|
+
minTokensReclaimed: 0,
|
|
488
|
+
beneficiary: payable(USER1),
|
|
489
|
+
metadata: ""
|
|
490
|
+
});
|
|
491
491
|
|
|
492
492
|
assertLe(reclaimed, 1, "tiny payment should not yield more than original amount");
|
|
493
493
|
}
|
|
@@ -517,14 +517,14 @@ contract TestCrossCurrencyReclaim is TestBaseWorkflow {
|
|
|
517
517
|
vm.prank(USER1);
|
|
518
518
|
uint256 reclaimed = jbMultiTerminal()
|
|
519
519
|
.cashOutTokensOf({
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
520
|
+
holder: USER1,
|
|
521
|
+
projectId: REVNET_ID,
|
|
522
|
+
cashOutCount: revTokens,
|
|
523
|
+
tokenToReclaim: address(TOKEN),
|
|
524
|
+
minTokensReclaimed: 0,
|
|
525
|
+
beneficiary: payable(USER1),
|
|
526
|
+
metadata: ""
|
|
527
|
+
});
|
|
528
528
|
|
|
529
529
|
// Should reclaim some TOKEN (bounded by the original payment amount).
|
|
530
530
|
assertLe(reclaimed, tokenAmount, "should not exceed original TOKEN payment");
|
|
@@ -559,14 +559,14 @@ contract TestCrossCurrencyReclaim is TestBaseWorkflow {
|
|
|
559
559
|
vm.prank(USER1);
|
|
560
560
|
uint256 reclaimed = jbMultiTerminal()
|
|
561
561
|
.cashOutTokensOf({
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
562
|
+
holder: USER1,
|
|
563
|
+
projectId: REVNET_ID,
|
|
564
|
+
cashOutCount: revTokens,
|
|
565
|
+
tokenToReclaim: address(TOKEN),
|
|
566
|
+
minTokensReclaimed: 0,
|
|
567
|
+
beneficiary: payable(USER1),
|
|
568
|
+
metadata: ""
|
|
569
|
+
});
|
|
570
570
|
|
|
571
571
|
assertLe(reclaimed, tokenAmount, "should not exceed total TOKEN paid");
|
|
572
572
|
}
|
|
@@ -595,14 +595,14 @@ contract TestCrossCurrencyReclaim is TestBaseWorkflow {
|
|
|
595
595
|
vm.prank(USER1);
|
|
596
596
|
uint256 reclaimed = jbMultiTerminal()
|
|
597
597
|
.cashOutTokensOf({
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
598
|
+
holder: USER1,
|
|
599
|
+
projectId: REVNET_ID,
|
|
600
|
+
cashOutCount: tokens,
|
|
601
|
+
tokenToReclaim: JBConstants.NATIVE_TOKEN,
|
|
602
|
+
minTokensReclaimed: 0,
|
|
603
|
+
beneficiary: payable(USER1),
|
|
604
|
+
metadata: ""
|
|
605
|
+
});
|
|
606
606
|
|
|
607
607
|
// With 0% cash out tax, no fee is charged on cash outs (per REVDeployer.beforeCashOutRecordedWith).
|
|
608
608
|
assertEq(reclaimed, balanceBefore, "0% tax, single holder should reclaim full balance");
|
|
@@ -363,14 +363,14 @@ contract TestLongTailEconomics is TestBaseWorkflow {
|
|
|
363
363
|
vm.prank(users[i]);
|
|
364
364
|
uint256 reclaimed = jbMultiTerminal()
|
|
365
365
|
.cashOutTokensOf({
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
366
|
+
holder: users[i],
|
|
367
|
+
projectId: REVNET_ID,
|
|
368
|
+
cashOutCount: userTokens[i],
|
|
369
|
+
tokenToReclaim: JBConstants.NATIVE_TOKEN,
|
|
370
|
+
minTokensReclaimed: 0,
|
|
371
|
+
beneficiary: payable(users[i]),
|
|
372
|
+
metadata: ""
|
|
373
|
+
});
|
|
374
374
|
totalReclaimed += reclaimed;
|
|
375
375
|
}
|
|
376
376
|
|
|
@@ -412,14 +412,14 @@ contract TestLongTailEconomics is TestBaseWorkflow {
|
|
|
412
412
|
vm.prank(payer);
|
|
413
413
|
uint256 reclaimedHalf = jbMultiTerminal()
|
|
414
414
|
.cashOutTokensOf({
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
415
|
+
holder: payer,
|
|
416
|
+
projectId: REVNET_ID,
|
|
417
|
+
cashOutCount: halfTokens,
|
|
418
|
+
tokenToReclaim: JBConstants.NATIVE_TOKEN,
|
|
419
|
+
minTokensReclaimed: 0,
|
|
420
|
+
beneficiary: payable(payer),
|
|
421
|
+
metadata: ""
|
|
422
|
+
});
|
|
423
423
|
|
|
424
424
|
// With a 50% tax rate and being the only holder, cashing out half the tokens
|
|
425
425
|
// should return less than half the surplus (bonding curve subproportional behavior).
|
|
@@ -452,14 +452,14 @@ contract TestLongTailEconomics is TestBaseWorkflow {
|
|
|
452
452
|
vm.prank(users[i]);
|
|
453
453
|
jbMultiTerminal()
|
|
454
454
|
.cashOutTokensOf({
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
455
|
+
holder: users[i],
|
|
456
|
+
projectId: REVNET_ID,
|
|
457
|
+
cashOutCount: userBalance / 2,
|
|
458
|
+
tokenToReclaim: JBConstants.NATIVE_TOKEN,
|
|
459
|
+
minTokensReclaimed: 0,
|
|
460
|
+
beneficiary: payable(users[i]),
|
|
461
|
+
metadata: ""
|
|
462
|
+
});
|
|
463
463
|
}
|
|
464
464
|
}
|
|
465
465
|
|
|
@@ -479,14 +479,14 @@ contract TestLongTailEconomics is TestBaseWorkflow {
|
|
|
479
479
|
vm.prank(users[3]);
|
|
480
480
|
jbMultiTerminal()
|
|
481
481
|
.cashOutTokensOf({
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
482
|
+
holder: users[3],
|
|
483
|
+
projectId: REVNET_ID,
|
|
484
|
+
cashOutCount: user3Balance,
|
|
485
|
+
tokenToReclaim: JBConstants.NATIVE_TOKEN,
|
|
486
|
+
minTokensReclaimed: 0,
|
|
487
|
+
beneficiary: payable(users[3]),
|
|
488
|
+
metadata: ""
|
|
489
|
+
});
|
|
490
490
|
}
|
|
491
491
|
}
|
|
492
492
|
|
|
@@ -556,14 +556,14 @@ contract TestLongTailEconomics is TestBaseWorkflow {
|
|
|
556
556
|
vm.prank(lateUser);
|
|
557
557
|
uint256 reclaimed = jbMultiTerminal()
|
|
558
558
|
.cashOutTokensOf({
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
559
|
+
holder: lateUser,
|
|
560
|
+
projectId: REVNET_ID,
|
|
561
|
+
cashOutCount: lateTokens,
|
|
562
|
+
tokenToReclaim: JBConstants.NATIVE_TOKEN,
|
|
563
|
+
minTokensReclaimed: 0,
|
|
564
|
+
beneficiary: payable(lateUser),
|
|
565
|
+
metadata: ""
|
|
566
|
+
});
|
|
567
567
|
|
|
568
568
|
// The late entrant should not extract more than they put in.
|
|
569
569
|
assertLe(reclaimed, 10e18, "late entrant should not extract more than they paid");
|
|
@@ -599,14 +599,14 @@ contract TestLongTailEconomics is TestBaseWorkflow {
|
|
|
599
599
|
vm.prank(users[0]);
|
|
600
600
|
jbMultiTerminal()
|
|
601
601
|
.cashOutTokensOf({
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
602
|
+
holder: users[0],
|
|
603
|
+
projectId: REVNET_ID,
|
|
604
|
+
cashOutCount: balance0 / 3,
|
|
605
|
+
tokenToReclaim: JBConstants.NATIVE_TOKEN,
|
|
606
|
+
minTokensReclaimed: 0,
|
|
607
|
+
beneficiary: payable(users[0]),
|
|
608
|
+
metadata: ""
|
|
609
|
+
});
|
|
610
610
|
}
|
|
611
611
|
}
|
|
612
612
|
|
|
@@ -654,14 +654,14 @@ contract TestLongTailEconomics is TestBaseWorkflow {
|
|
|
654
654
|
vm.prank(user);
|
|
655
655
|
jbMultiTerminal()
|
|
656
656
|
.cashOutTokensOf({
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
657
|
+
holder: user,
|
|
658
|
+
projectId: REVNET_ID,
|
|
659
|
+
cashOutCount: portion,
|
|
660
|
+
tokenToReclaim: JBConstants.NATIVE_TOKEN,
|
|
661
|
+
minTokensReclaimed: 0,
|
|
662
|
+
beneficiary: payable(user),
|
|
663
|
+
metadata: ""
|
|
664
|
+
});
|
|
665
665
|
|
|
666
666
|
uint256 feeBalanceAfterRound =
|
|
667
667
|
jbTerminalStore().balanceOf(address(jbMultiTerminal()), FEE_PROJECT_ID, JBConstants.NATIVE_TOKEN);
|
|
@@ -206,24 +206,24 @@ contract TestSwapTerminalPermission is TestBaseWorkflow {
|
|
|
206
206
|
function test_splitOperator_hasRegistryPermissions() public view {
|
|
207
207
|
bool hasBuybackHook = jbPermissions()
|
|
208
208
|
.hasPermission({
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
209
|
+
operator: multisig(),
|
|
210
|
+
account: address(REV_DEPLOYER),
|
|
211
|
+
projectId: TEST_REVNET_ID,
|
|
212
|
+
permissionId: JBPermissionIds.SET_BUYBACK_HOOK,
|
|
213
|
+
includeRoot: false,
|
|
214
|
+
includeWildcardProjectId: false
|
|
215
|
+
});
|
|
216
216
|
assertTrue(hasBuybackHook, "Split operator should have SET_BUYBACK_HOOK permission");
|
|
217
217
|
|
|
218
218
|
bool hasRouterTerminal = jbPermissions()
|
|
219
219
|
.hasPermission({
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
220
|
+
operator: multisig(),
|
|
221
|
+
account: address(REV_DEPLOYER),
|
|
222
|
+
projectId: TEST_REVNET_ID,
|
|
223
|
+
permissionId: JBPermissionIds.SET_ROUTER_TERMINAL,
|
|
224
|
+
includeRoot: false,
|
|
225
|
+
includeWildcardProjectId: false
|
|
226
|
+
});
|
|
227
227
|
assertTrue(hasRouterTerminal, "Split operator should have SET_ROUTER_TERMINAL permission");
|
|
228
228
|
}
|
|
229
229
|
|
|
@@ -244,13 +244,13 @@ contract TestSwapTerminalPermission is TestBaseWorkflow {
|
|
|
244
244
|
for (uint256 i = 0; i < expectedPermissions.length; i++) {
|
|
245
245
|
bool hasPermission = jbPermissions()
|
|
246
246
|
.hasPermission({
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
247
|
+
operator: multisig(),
|
|
248
|
+
account: address(REV_DEPLOYER),
|
|
249
|
+
projectId: TEST_REVNET_ID,
|
|
250
|
+
permissionId: expectedPermissions[i],
|
|
251
|
+
includeRoot: false,
|
|
252
|
+
includeWildcardProjectId: false
|
|
253
|
+
});
|
|
254
254
|
assertTrue(
|
|
255
255
|
hasPermission,
|
|
256
256
|
string.concat(
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.28;
|
|
3
|
+
|
|
4
|
+
import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
|
|
5
|
+
|
|
6
|
+
import {TestHiddenTokens} from "../TestHiddenTokens.t.sol";
|
|
7
|
+
|
|
8
|
+
contract CodexNemesisHiddenSupplyCashoutTest is TestHiddenTokens {
|
|
9
|
+
function test_hiddenSupplyCanDrainCashoutAndThenBeRevealed() public {
|
|
10
|
+
uint256 payAmount = 10 ether;
|
|
11
|
+
|
|
12
|
+
vm.prank(USER);
|
|
13
|
+
uint256 minted = jbMultiTerminal().pay{value: payAmount}({
|
|
14
|
+
projectId: REVNET_ID,
|
|
15
|
+
token: JBConstants.NATIVE_TOKEN,
|
|
16
|
+
amount: payAmount,
|
|
17
|
+
beneficiary: USER,
|
|
18
|
+
minReturnedTokens: 0,
|
|
19
|
+
memo: "",
|
|
20
|
+
metadata: ""
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
uint256 terminalBalanceBefore =
|
|
24
|
+
jbTerminalStore().balanceOf(address(jbMultiTerminal()), REVNET_ID, JBConstants.NATIVE_TOKEN);
|
|
25
|
+
assertEq(terminalBalanceBefore, payAmount, "setup: revnet terminal balance");
|
|
26
|
+
|
|
27
|
+
_allowHolderToHide(USER, REVNET_ID);
|
|
28
|
+
|
|
29
|
+
uint256 hiddenCount = minted / 2;
|
|
30
|
+
vm.prank(USER);
|
|
31
|
+
HIDDEN_TOKENS.hideTokensOf(REVNET_ID, hiddenCount, USER);
|
|
32
|
+
|
|
33
|
+
uint256 visibleSupply = jbController().TOKENS().totalSupplyOf(REVNET_ID);
|
|
34
|
+
assertEq(visibleSupply, minted - hiddenCount, "hidden tokens left the cash-out denominator");
|
|
35
|
+
|
|
36
|
+
vm.prank(USER);
|
|
37
|
+
jbMultiTerminal()
|
|
38
|
+
.cashOutTokensOf({
|
|
39
|
+
holder: USER,
|
|
40
|
+
projectId: REVNET_ID,
|
|
41
|
+
cashOutCount: visibleSupply,
|
|
42
|
+
tokenToReclaim: JBConstants.NATIVE_TOKEN,
|
|
43
|
+
minTokensReclaimed: 0,
|
|
44
|
+
beneficiary: payable(USER),
|
|
45
|
+
metadata: ""
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
uint256 terminalBalanceAfter =
|
|
49
|
+
jbTerminalStore().balanceOf(address(jbMultiTerminal()), REVNET_ID, JBConstants.NATIVE_TOKEN);
|
|
50
|
+
assertEq(terminalBalanceAfter, 0, "visible tranche drained the revnet balance");
|
|
51
|
+
|
|
52
|
+
vm.prank(USER);
|
|
53
|
+
HIDDEN_TOKENS.revealTokensOf(REVNET_ID, hiddenCount, USER);
|
|
54
|
+
|
|
55
|
+
assertEq(
|
|
56
|
+
jbController().TOKENS().totalBalanceOf(USER, REVNET_ID),
|
|
57
|
+
hiddenCount,
|
|
58
|
+
"hidden tranche was restored after the cash out"
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
}
|