@rev-net/core-v6 0.0.37 → 0.0.39
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/CHANGELOG.md +2 -2
- package/README.md +6 -7
- package/foundry.toml +1 -1
- package/package.json +23 -16
- package/references/operations.md +1 -1
- package/references/runtime.md +1 -1
- package/script/Deploy.s.sol +12 -9
- package/src/REVDeployer.sol +60 -65
- package/src/REVHiddenTokens.sol +2 -2
- package/src/REVLoans.sol +17 -10
- package/src/REVOwner.sol +121 -14
- package/src/interfaces/IREVDeployer.sol +2 -1
- package/src/interfaces/IREVHiddenTokens.sol +4 -1
- package/src/interfaces/IREVOwner.sol +5 -0
- package/ADMINISTRATION.md +0 -73
- package/ARCHITECTURE.md +0 -116
- package/AUDIT_INSTRUCTIONS.md +0 -90
- package/RISKS.md +0 -107
- package/SKILLS.md +0 -46
- package/STYLE_GUIDE.md +0 -610
- package/USER_JOURNEYS.md +0 -195
- package/foundry.lock +0 -11
- package/slither-ci.config.json +0 -10
- package/sphinx.lock +0 -507
- package/test/REV.integrations.t.sol +0 -573
- package/test/REVAutoIssuanceFuzz.t.sol +0 -328
- package/test/REVDeployerRegressions.t.sol +0 -396
- package/test/REVInvincibility.t.sol +0 -1371
- package/test/REVInvincibilityHandler.sol +0 -387
- package/test/REVLifecycle.t.sol +0 -420
- package/test/REVLoans.invariants.t.sol +0 -724
- package/test/REVLoansAttacks.t.sol +0 -816
- package/test/REVLoansFeeRecovery.t.sol +0 -783
- package/test/REVLoansFindings.t.sol +0 -711
- package/test/REVLoansRegressions.t.sol +0 -364
- package/test/REVLoansSourceFeeRecovery.t.sol +0 -517
- package/test/REVLoansSourced.t.sol +0 -1839
- package/test/REVLoansUnSourced.t.sol +0 -409
- package/test/TestAuditFixVerification.t.sol +0 -675
- package/test/TestBurnHeldTokens.t.sol +0 -394
- package/test/TestCEIPattern.t.sol +0 -508
- package/test/TestCashOutCallerValidation.t.sol +0 -452
- package/test/TestConversionDocumentation.t.sol +0 -365
- package/test/TestCrossCurrencyReclaim.t.sol +0 -610
- package/test/TestCrossSourceReallocation.t.sol +0 -361
- package/test/TestERC2771MetaTx.t.sol +0 -585
- package/test/TestEmptyBuybackSpecs.t.sol +0 -300
- package/test/TestFlashLoanSurplus.t.sol +0 -365
- package/test/TestHiddenTokens.t.sol +0 -474
- package/test/TestHookArrayOOB.t.sol +0 -278
- package/test/TestLiquidationBehavior.t.sol +0 -398
- package/test/TestLoanSourceRotation.t.sol +0 -553
- package/test/TestLoansCashOutDelay.t.sol +0 -493
- package/test/TestLongTailEconomics.t.sol +0 -677
- package/test/TestLowFindings.t.sol +0 -677
- package/test/TestMixedFixes.t.sol +0 -593
- package/test/TestPermit2Signatures.t.sol +0 -683
- package/test/TestReallocationSandwich.t.sol +0 -412
- package/test/TestRevnetRegressions.t.sol +0 -350
- package/test/TestSplitWeightAdjustment.t.sol +0 -527
- package/test/TestSplitWeightE2E.t.sol +0 -605
- package/test/TestSplitWeightFork.t.sol +0 -855
- package/test/TestStageTransitionBorrowable.t.sol +0 -301
- package/test/TestSwapTerminalPermission.t.sol +0 -262
- package/test/TestTerminalEncodingInHash.t.sol +0 -326
- package/test/TestUint112Overflow.t.sol +0 -311
- package/test/TestZeroAmountLoanGuard.t.sol +0 -378
- package/test/TestZeroRepayment.t.sol +0 -354
- package/test/audit/CrossChainBuybackRouteMismatch.t.sol +0 -184
- package/test/audit/HiddenSupplyCashout.t.sol +0 -61
- package/test/audit/LoanIdOverflowGuard.t.sol +0 -523
- package/test/audit/NemesisVerification.t.sol +0 -97
- package/test/audit/OperatorDelegation.t.sol +0 -356
- package/test/audit/PhantomSurplusTerminal.t.sol +0 -367
- package/test/audit/REVOwnerCurrencyMismatch.t.sol +0 -188
- package/test/audit/REVOwnerRemoteSurplusCurrencyMismatch.t.sol +0 -140
- package/test/audit/ReallocatePermission.t.sol +0 -363
- package/test/audit/RemoteLoanAccountingGap.t.sol +0 -74
- package/test/audit/SupportsInterfaceTest.t.sol +0 -51
- package/test/audit/TestFeeAllowanceLeak.t.sol +0 -197
- package/test/audit/TestLoansAndDeployerFixes.t.sol +0 -576
- package/test/fork/ForkTestBase.sol +0 -727
- package/test/fork/TestAutoIssuanceFork.t.sol +0 -148
- package/test/fork/TestCashOutFork.t.sol +0 -253
- package/test/fork/TestIssuanceDecayFork.t.sol +0 -158
- package/test/fork/TestLoanAdversarialFork.t.sol +0 -744
- package/test/fork/TestLoanBorrowFork.t.sol +0 -163
- package/test/fork/TestLoanCrossRulesetFork.t.sol +0 -308
- package/test/fork/TestLoanERC20Fork.t.sol +0 -459
- package/test/fork/TestLoanLiquidationFork.t.sol +0 -135
- package/test/fork/TestLoanReallocateFork.t.sol +0 -113
- package/test/fork/TestLoanRepayFork.t.sol +0 -188
- package/test/fork/TestLoanTransferFork.t.sol +0 -143
- package/test/fork/TestPermit2PaymentFork.t.sol +0 -300
- package/test/fork/TestSplitWeightFork.t.sol +0 -189
- package/test/helpers/MaliciousContracts.sol +0 -247
- package/test/helpers/REVEmpty721Config.sol +0 -45
- package/test/mock/MockBuybackCashOutRecorder.sol +0 -84
- package/test/mock/MockBuybackDataHook.sol +0 -112
- package/test/mock/MockBuybackDataHookMintPath.sol +0 -68
- package/test/mock/MockSuckerRegistry.sol +0 -17
- package/test/regression/TestBurnPermissionRequired.t.sol +0 -294
- package/test/regression/TestCashOutBuybackFeeLeak.t.sol +0 -232
- package/test/regression/TestCrossRevnetLiquidation.t.sol +0 -255
- package/test/regression/TestCumulativeLoanCounter.t.sol +0 -361
- package/test/regression/TestLiquidateGapHandling.t.sol +0 -394
- package/test/regression/TestZeroPriceFeed.t.sol +0 -422
package/src/REVOwner.sol
CHANGED
|
@@ -9,12 +9,14 @@ import {IJBRulesetDataHook} from "@bananapus/core-v6/src/interfaces/IJBRulesetDa
|
|
|
9
9
|
import {IJBTerminal} from "@bananapus/core-v6/src/interfaces/IJBTerminal.sol";
|
|
10
10
|
import {JBCashOuts} from "@bananapus/core-v6/src/libraries/JBCashOuts.sol";
|
|
11
11
|
import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
|
|
12
|
+
import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
|
|
12
13
|
import {JBAfterCashOutRecordedContext} from "@bananapus/core-v6/src/structs/JBAfterCashOutRecordedContext.sol";
|
|
13
14
|
import {JBBeforeCashOutRecordedContext} from "@bananapus/core-v6/src/structs/JBBeforeCashOutRecordedContext.sol";
|
|
14
15
|
import {JBBeforePayRecordedContext} from "@bananapus/core-v6/src/structs/JBBeforePayRecordedContext.sol";
|
|
15
16
|
import {JBCashOutHookSpecification} from "@bananapus/core-v6/src/structs/JBCashOutHookSpecification.sol";
|
|
16
17
|
import {JBPayHookSpecification} from "@bananapus/core-v6/src/structs/JBPayHookSpecification.sol";
|
|
17
18
|
import {JBRuleset} from "@bananapus/core-v6/src/structs/JBRuleset.sol";
|
|
19
|
+
import {IJBPeerChainAdjustedAccounts} from "@bananapus/suckers-v6/src/interfaces/IJBPeerChainAdjustedAccounts.sol";
|
|
18
20
|
import {IJBSuckerRegistry} from "@bananapus/suckers-v6/src/interfaces/IJBSuckerRegistry.sol";
|
|
19
21
|
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
|
|
20
22
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
@@ -22,11 +24,14 @@ import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol
|
|
|
22
24
|
import {mulDiv} from "@prb/math/src/Common.sol";
|
|
23
25
|
|
|
24
26
|
import {IREVDeployer} from "./interfaces/IREVDeployer.sol";
|
|
27
|
+
import {IREVHiddenTokens} from "./interfaces/IREVHiddenTokens.sol";
|
|
28
|
+
import {IREVLoans} from "./interfaces/IREVLoans.sol";
|
|
29
|
+
import {REVLoanSource} from "./structs/REVLoanSource.sol";
|
|
25
30
|
|
|
26
31
|
/// @notice Handles the runtime data hook and cash out hook behavior for revnets.
|
|
27
32
|
/// @dev Separated from `REVDeployer` to stay within the EIP-170 contract size limit.
|
|
28
33
|
/// This contract is set as the `dataHook` in each revnet's ruleset metadata.
|
|
29
|
-
contract REVOwner is IJBRulesetDataHook, IJBCashOutHook {
|
|
34
|
+
contract REVOwner is IJBRulesetDataHook, IJBCashOutHook, IJBPeerChainAdjustedAccounts {
|
|
30
35
|
// A library that adds default safety checks to ERC20 functionality.
|
|
31
36
|
using SafeERC20 for IERC20;
|
|
32
37
|
|
|
@@ -61,10 +66,10 @@ contract REVOwner is IJBRulesetDataHook, IJBCashOutHook {
|
|
|
61
66
|
uint256 public immutable FEE_REVNET_ID;
|
|
62
67
|
|
|
63
68
|
/// @notice The hidden tokens contract used by all revnets.
|
|
64
|
-
|
|
69
|
+
IREVHiddenTokens public immutable HIDDEN_TOKENS;
|
|
65
70
|
|
|
66
71
|
/// @notice The loan contract used by all revnets.
|
|
67
|
-
|
|
72
|
+
IREVLoans public immutable LOANS;
|
|
68
73
|
|
|
69
74
|
/// @notice Deploys and tracks suckers for revnets.
|
|
70
75
|
IJBSuckerRegistry public immutable SUCKER_REGISTRY;
|
|
@@ -102,23 +107,21 @@ contract REVOwner is IJBRulesetDataHook, IJBCashOutHook {
|
|
|
102
107
|
/// @param directory The directory of terminals and controllers.
|
|
103
108
|
/// @param feeRevnetId The Juicebox project ID of the fee revnet.
|
|
104
109
|
/// @param suckerRegistry The sucker registry.
|
|
105
|
-
/// @param loans The loan contract
|
|
106
|
-
/// @param hiddenTokens The hidden tokens contract
|
|
110
|
+
/// @param loans The loan contract.
|
|
111
|
+
/// @param hiddenTokens The hidden tokens contract.
|
|
107
112
|
constructor(
|
|
108
113
|
IJBBuybackHookRegistry buybackHook,
|
|
109
114
|
IJBDirectory directory,
|
|
110
115
|
uint256 feeRevnetId,
|
|
111
116
|
IJBSuckerRegistry suckerRegistry,
|
|
112
|
-
|
|
113
|
-
|
|
117
|
+
IREVLoans loans,
|
|
118
|
+
IREVHiddenTokens hiddenTokens
|
|
114
119
|
) {
|
|
115
120
|
BUYBACK_HOOK = buybackHook;
|
|
116
121
|
DIRECTORY = directory;
|
|
117
122
|
FEE_REVNET_ID = feeRevnetId;
|
|
118
123
|
SUCKER_REGISTRY = suckerRegistry;
|
|
119
|
-
// slither-disable-next-line missing-zero-check
|
|
120
124
|
LOANS = loans;
|
|
121
|
-
// slither-disable-next-line missing-zero-check
|
|
122
125
|
HIDDEN_TOKENS = hiddenTokens;
|
|
123
126
|
_DEPLOYER_BINDER = msg.sender;
|
|
124
127
|
}
|
|
@@ -153,11 +156,23 @@ contract REVOwner is IJBRulesetDataHook, IJBCashOutHook {
|
|
|
153
156
|
JBCashOutHookSpecification[] memory hookSpecifications
|
|
154
157
|
)
|
|
155
158
|
{
|
|
159
|
+
// Treat outstanding local loans as temporarily off-terminal revnet assets. Borrowed funds are owed back to
|
|
160
|
+
// the revnet, while burned loan collateral can be re-minted on repayment, so both affect fair cash-out math.
|
|
161
|
+
(uint256 totalBorrowed, uint256 totalCollateral) = _localLoanStateOf({
|
|
162
|
+
revnetId: context.projectId, decimals: context.surplus.decimals, currency: context.surplus.currency
|
|
163
|
+
});
|
|
164
|
+
|
|
156
165
|
// If the cash out is from a sucker, return the full cash out amount without taxes or fees.
|
|
157
166
|
// This relies on the sucker registry to only contain trusted sucker contracts deployed via
|
|
158
167
|
// the registry's own deploySuckersFor flow — external addresses cannot register as suckers.
|
|
159
168
|
if (_isSuckerOf({revnetId: context.projectId, addr: context.holder})) {
|
|
160
|
-
return (
|
|
169
|
+
return (
|
|
170
|
+
0,
|
|
171
|
+
context.cashOutCount,
|
|
172
|
+
context.totalSupply + totalCollateral,
|
|
173
|
+
context.surplus.value + totalBorrowed,
|
|
174
|
+
hookSpecifications
|
|
175
|
+
);
|
|
161
176
|
}
|
|
162
177
|
|
|
163
178
|
// Keep a reference to the cash out delay of the revnet.
|
|
@@ -173,8 +188,8 @@ contract REVOwner is IJBRulesetDataHook, IJBCashOutHook {
|
|
|
173
188
|
|
|
174
189
|
// Compute the cross-chain total supply (local + remote peer chain supplies) for cross-chain-aware bonding
|
|
175
190
|
// curve.
|
|
176
|
-
totalSupply = context.totalSupply + SUCKER_REGISTRY.remoteTotalSupplyOf(context.projectId);
|
|
177
|
-
effectiveSurplusValue = context.surplus.value
|
|
191
|
+
totalSupply = context.totalSupply + totalCollateral + SUCKER_REGISTRY.remoteTotalSupplyOf(context.projectId);
|
|
192
|
+
effectiveSurplusValue = context.surplus.value + totalBorrowed
|
|
178
193
|
+ SUCKER_REGISTRY.remoteSurplusOf({
|
|
179
194
|
projectId: context.projectId,
|
|
180
195
|
decimals: context.surplus.decimals,
|
|
@@ -350,11 +365,35 @@ contract REVOwner is IJBRulesetDataHook, IJBCashOutHook {
|
|
|
350
365
|
{
|
|
351
366
|
// The loans contract, hidden tokens contract, buyback hook (and its delegates), and suckers are allowed to mint
|
|
352
367
|
// the revnet's tokens.
|
|
353
|
-
return addr == LOANS || addr == HIDDEN_TOKENS || addr == address(BUYBACK_HOOK)
|
|
368
|
+
return addr == address(LOANS) || addr == address(HIDDEN_TOKENS) || addr == address(BUYBACK_HOOK)
|
|
354
369
|
|| BUYBACK_HOOK.hasMintPermissionFor({projectId: revnetId, ruleset: ruleset, addr: addr})
|
|
355
370
|
|| _isSuckerOf({revnetId: revnetId, addr: addr});
|
|
356
371
|
}
|
|
357
372
|
|
|
373
|
+
/// @notice Additional revnet accounts that peer-chain snapshots should include.
|
|
374
|
+
/// @dev Hidden tokens are intentionally excluded. Revnet operators can hide tokens as a security handle without
|
|
375
|
+
/// changing loan or cash-out math for other holders. Outstanding loan debt is counted as both surplus and balance:
|
|
376
|
+
/// it is value owed back to this chain's revnet and should travel to peer snapshots with the collateral supply.
|
|
377
|
+
/// @param revnetId The ID of the revnet being snapshotted.
|
|
378
|
+
/// @param decimals The decimals the returned surplus should use.
|
|
379
|
+
/// @param currency The currency the returned surplus should be in terms of.
|
|
380
|
+
/// @return supply The loan-collateral supply to include in the peer snapshot.
|
|
381
|
+
/// @return surplus The outstanding loan debt to include in `sourceSurplus`.
|
|
382
|
+
/// @return balance The outstanding loan debt to include in `sourceBalance`.
|
|
383
|
+
function peerChainAdjustedAccountsOf(
|
|
384
|
+
uint256 revnetId,
|
|
385
|
+
uint256 decimals,
|
|
386
|
+
uint256 currency
|
|
387
|
+
)
|
|
388
|
+
external
|
|
389
|
+
view
|
|
390
|
+
override
|
|
391
|
+
returns (uint256 supply, uint256 surplus, uint256 balance)
|
|
392
|
+
{
|
|
393
|
+
(surplus, supply) = _localLoanStateOf({revnetId: revnetId, decimals: decimals, currency: currency});
|
|
394
|
+
balance = surplus;
|
|
395
|
+
}
|
|
396
|
+
|
|
358
397
|
//*********************************************************************//
|
|
359
398
|
// --------------------- external transactions ----------------------- //
|
|
360
399
|
//*********************************************************************//
|
|
@@ -460,7 +499,8 @@ contract REVOwner is IJBRulesetDataHook, IJBCashOutHook {
|
|
|
460
499
|
/// @return A flag indicating if the provided interface ID is supported.
|
|
461
500
|
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
|
|
462
501
|
return interfaceId == type(IERC165).interfaceId || interfaceId == type(IJBRulesetDataHook).interfaceId
|
|
463
|
-
|| interfaceId == type(IJBCashOutHook).interfaceId
|
|
502
|
+
|| interfaceId == type(IJBCashOutHook).interfaceId
|
|
503
|
+
|| interfaceId == type(IJBPeerChainAdjustedAccounts).interfaceId;
|
|
464
504
|
}
|
|
465
505
|
|
|
466
506
|
//*********************************************************************//
|
|
@@ -475,6 +515,73 @@ contract REVOwner is IJBRulesetDataHook, IJBCashOutHook {
|
|
|
475
515
|
return SUCKER_REGISTRY.isSuckerOf({projectId: revnetId, addr: addr});
|
|
476
516
|
}
|
|
477
517
|
|
|
518
|
+
/// @notice Total outstanding local loan debt and collateral for a revnet.
|
|
519
|
+
/// @dev This is included in cash-out and peer-snapshot math because borrowed funds are still owed to the revnet
|
|
520
|
+
/// and collateral can re-enter supply when the loan is repaid.
|
|
521
|
+
/// @param revnetId The ID of the revnet to check.
|
|
522
|
+
/// @param decimals The decimals the resulting fixed point debt value should use.
|
|
523
|
+
/// @param currency The currency the resulting debt value should be in terms of.
|
|
524
|
+
/// @return borrowedAmount The local outstanding loan debt converted into `currency`.
|
|
525
|
+
/// @return collateralCount The local burned loan collateral count.
|
|
526
|
+
function _localLoanStateOf(
|
|
527
|
+
uint256 revnetId,
|
|
528
|
+
uint256 decimals,
|
|
529
|
+
uint256 currency
|
|
530
|
+
)
|
|
531
|
+
internal
|
|
532
|
+
view
|
|
533
|
+
returns (uint256 borrowedAmount, uint256 collateralCount)
|
|
534
|
+
{
|
|
535
|
+
IREVLoans loans = LOANS;
|
|
536
|
+
if (address(loans) == address(0) || address(loans).code.length == 0) return (0, 0);
|
|
537
|
+
|
|
538
|
+
collateralCount = loans.totalCollateralOf(revnetId);
|
|
539
|
+
|
|
540
|
+
REVLoanSource[] memory sources = loans.loanSourcesOf(revnetId);
|
|
541
|
+
// Loan sources are project configuration, and this read-only aggregation needs the latest terminal/pricing
|
|
542
|
+
// state for each configured source.
|
|
543
|
+
for (uint256 i; i < sources.length; i++) {
|
|
544
|
+
REVLoanSource memory source = sources[i];
|
|
545
|
+
// Each configured source must be queried live so cash-out math includes current outstanding debt.
|
|
546
|
+
// slither-disable-next-line calls-loop
|
|
547
|
+
uint256 tokensLoaned =
|
|
548
|
+
loans.totalBorrowedFrom({revnetId: revnetId, terminal: source.terminal, token: source.token});
|
|
549
|
+
if (tokensLoaned == 0) continue;
|
|
550
|
+
|
|
551
|
+
// Read the source token's accounting context so debt can be normalized before cross-currency conversion.
|
|
552
|
+
// slither-disable-next-line calls-loop
|
|
553
|
+
JBAccountingContext memory accountingContext =
|
|
554
|
+
source.terminal.accountingContextForTokenOf({projectId: revnetId, token: source.token});
|
|
555
|
+
|
|
556
|
+
// Normalize each source from its native token decimals into the caller's requested decimals.
|
|
557
|
+
uint256 normalizedTokens;
|
|
558
|
+
if (accountingContext.decimals > decimals) {
|
|
559
|
+
normalizedTokens = tokensLoaned / (10 ** (accountingContext.decimals - decimals));
|
|
560
|
+
} else if (accountingContext.decimals < decimals) {
|
|
561
|
+
normalizedTokens = tokensLoaned * (10 ** (decimals - accountingContext.decimals));
|
|
562
|
+
} else {
|
|
563
|
+
normalizedTokens = tokensLoaned;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
if (accountingContext.currency == currency) {
|
|
567
|
+
borrowedAmount += normalizedTokens;
|
|
568
|
+
} else {
|
|
569
|
+
// Convert source-token debt into the requested currency using the loans contract's shared prices.
|
|
570
|
+
// slither-disable-next-line calls-loop
|
|
571
|
+
uint256 pricePerUnit = loans.PRICES()
|
|
572
|
+
.pricePerUnitOf({
|
|
573
|
+
projectId: revnetId,
|
|
574
|
+
pricingCurrency: accountingContext.currency,
|
|
575
|
+
unitCurrency: currency,
|
|
576
|
+
decimals: decimals
|
|
577
|
+
});
|
|
578
|
+
if (pricePerUnit == 0) continue;
|
|
579
|
+
|
|
580
|
+
borrowedAmount += mulDiv({x: normalizedTokens, y: 10 ** decimals, denominator: pricePerUnit});
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
478
585
|
//*********************************************************************//
|
|
479
586
|
// --------------------- internal transactions ----------------------- //
|
|
480
587
|
//*********************************************************************//
|
|
@@ -16,6 +16,7 @@ import {REVConfig} from "../structs/REVConfig.sol";
|
|
|
16
16
|
import {REVCroptopAllowedPost} from "../structs/REVCroptopAllowedPost.sol";
|
|
17
17
|
import {REVDeploy721TiersHookConfig} from "../structs/REVDeploy721TiersHookConfig.sol";
|
|
18
18
|
import {REVSuckerDeploymentConfig} from "../structs/REVSuckerDeploymentConfig.sol";
|
|
19
|
+
import {IREVLoans} from "./IREVLoans.sol";
|
|
19
20
|
|
|
20
21
|
/// @notice Deploys and manages revnets -- Juicebox projects with pre-configured tokenomics.
|
|
21
22
|
interface IREVDeployer {
|
|
@@ -143,7 +144,7 @@ interface IREVDeployer {
|
|
|
143
144
|
|
|
144
145
|
/// @notice The loan contract used by all revnets.
|
|
145
146
|
/// @return The loans contract address.
|
|
146
|
-
function LOANS() external view returns (
|
|
147
|
+
function LOANS() external view returns (IREVLoans);
|
|
147
148
|
|
|
148
149
|
/// @notice The runtime data hook contract that handles pay and cash out callbacks for revnets.
|
|
149
150
|
/// @return The owner contract address.
|
|
@@ -3,7 +3,10 @@ pragma solidity ^0.8.0;
|
|
|
3
3
|
|
|
4
4
|
import {IJBController} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
|
|
5
5
|
|
|
6
|
-
/// @notice Manages hiding (burning) and revealing (re-minting) revnet tokens to exclude them from totalSupply.
|
|
6
|
+
/// @notice Manages hiding (burning) and revealing (re-minting) revnet tokens to exclude them from live totalSupply.
|
|
7
|
+
/// @dev Hidden balances are an operator-controlled security handle. They remain revealable, but cash-out and loan
|
|
8
|
+
/// accounting intentionally excludes `totalHiddenOf` so hidden inventory cannot dilute other holders' access to
|
|
9
|
+
/// revnet capital.
|
|
7
10
|
interface IREVHiddenTokens {
|
|
8
11
|
/// @notice Emitted when a holder is allowed or disallowed to hide their own tokens.
|
|
9
12
|
/// @param revnetId The ID of the revnet.
|
|
@@ -2,9 +2,14 @@
|
|
|
2
2
|
pragma solidity ^0.8.0;
|
|
3
3
|
|
|
4
4
|
import {IREVDeployer} from "./IREVDeployer.sol";
|
|
5
|
+
import {IREVHiddenTokens} from "./IREVHiddenTokens.sol";
|
|
5
6
|
|
|
6
7
|
/// @notice Interface for the REVOwner contract that handles runtime data hook and cash out hook behavior for revnets.
|
|
7
8
|
interface IREVOwner {
|
|
9
|
+
/// @notice The hidden tokens contract used by the revnet owner hook.
|
|
10
|
+
/// @return The hidden tokens contract.
|
|
11
|
+
function HIDDEN_TOKENS() external view returns (IREVHiddenTokens);
|
|
12
|
+
|
|
8
13
|
/// @notice The timestamp of when cashouts will become available to a specific revnet's participants.
|
|
9
14
|
/// @param revnetId The ID of the revnet.
|
|
10
15
|
/// @return The cash out delay timestamp.
|
package/ADMINISTRATION.md
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
# Administration
|
|
2
|
-
|
|
3
|
-
## At A Glance
|
|
4
|
-
|
|
5
|
-
| Item | Details |
|
|
6
|
-
| --- | --- |
|
|
7
|
-
| Scope | Revnet deployment shape, bounded runtime operators, loan-owner cosmetics, and optional integration control surfaces |
|
|
8
|
-
| Control posture | Intentionally narrow and mostly deployment-defined |
|
|
9
|
-
| Highest-risk actions | Bad stage design, wrong split-operator assignment, and misunderstanding which runtime surfaces stay live after launch |
|
|
10
|
-
| Recovery posture | Usually replacement, not patching; the design intentionally avoids easy admin escape hatches |
|
|
11
|
-
|
|
12
|
-
## Purpose
|
|
13
|
-
|
|
14
|
-
`revnet-core-v6` is designed to collapse ordinary post-launch governance into deployment-time decisions plus a small set of bounded runtime roles. The main administration task is understanding which power still exists and which power was intentionally removed.
|
|
15
|
-
|
|
16
|
-
## Control Model
|
|
17
|
-
|
|
18
|
-
- `REVDeployer` holds the project NFT and therefore remains part of the ownership model.
|
|
19
|
-
- Revnet economics are mainly fixed at deployment through staged rulesets.
|
|
20
|
-
- `REVOwner` provides live runtime policy, but not broad human governance.
|
|
21
|
-
- Split operators can hold narrow powers depending on stage and deployment config.
|
|
22
|
-
- `REVLoans` has a cosmetic global owner surface, but loan economics are still bounded by revnet logic.
|
|
23
|
-
|
|
24
|
-
## Roles
|
|
25
|
-
|
|
26
|
-
| Role | How Assigned | Scope | Notes |
|
|
27
|
-
| --- | --- | --- | --- |
|
|
28
|
-
| `REVDeployer` | Deployed singleton | Global launcher and project-NFT holder | Part of the ownership model |
|
|
29
|
-
| Split operator | Deployment config | Per revnet | Holds only the allowed operator envelope |
|
|
30
|
-
| Auto-issuance beneficiary | Deployment config | Per stage | Can receive preconfigured stage issuance |
|
|
31
|
-
| Borrower or delegated loan operator | Token holder plus permission | Per holder or loan | Can open or manage loans within loan rules |
|
|
32
|
-
| `REVLoans` owner | Constructor owner | Global cosmetic/admin surface | Does not turn Revnets back into ordinary governed projects |
|
|
33
|
-
|
|
34
|
-
## Privileged Surfaces
|
|
35
|
-
|
|
36
|
-
- `deployFor(...)` defines the revnet's long-lived shape
|
|
37
|
-
- split-operator paths can manage only the permissions left open by deployment
|
|
38
|
-
- `autoIssueFor(...)` consumes preconfigured stage issuance
|
|
39
|
-
- loan operators can redirect borrowed value if a holder delegates loan permissions
|
|
40
|
-
- hidden-token flows require the holder's permission grant and mint permission wiring through `REVOwner`
|
|
41
|
-
|
|
42
|
-
## Immutable And One-Way
|
|
43
|
-
|
|
44
|
-
- Stage configuration is effectively permanent after deployment.
|
|
45
|
-
- The deployer-held project NFT is not a normal owner-recovery tool.
|
|
46
|
-
- Loan collateral is burned at borrow time and only reminted through repayment or documented flows.
|
|
47
|
-
- Hidden-token balances change visible supply until reveal.
|
|
48
|
-
|
|
49
|
-
## Operational Notes
|
|
50
|
-
|
|
51
|
-
- Treat revnet launch as the real governance decision.
|
|
52
|
-
- Validate stage timing, split-operator scope, and optional integrations before deployment.
|
|
53
|
-
- Review cash-out delay, hidden-token semantics, and loan permissions together.
|
|
54
|
-
- Do not assume there is a broad admin override for bad economics after launch.
|
|
55
|
-
|
|
56
|
-
## Machine Notes
|
|
57
|
-
|
|
58
|
-
- Do not describe Revnets as fully adminless if the deployer-held NFT still matters for the trust model.
|
|
59
|
-
- Also do not describe them as ordinary owner-controlled projects. The point is that the available control surface is intentionally narrow.
|
|
60
|
-
- If a question is about runtime cash-outs, buybacks, or mint permissions, inspect `REVOwner` before inferring behavior from deployment prose.
|
|
61
|
-
|
|
62
|
-
## Recovery
|
|
63
|
-
|
|
64
|
-
- If launch-time economics are wrong, recovery usually means replacement, not in-place repair.
|
|
65
|
-
- If optional integrations are misconfigured, fix only where the code still exposes a valid path.
|
|
66
|
-
- If the design intentionally omitted a recovery path, do not invent one in documentation or ops guidance.
|
|
67
|
-
|
|
68
|
-
## Admin Boundaries
|
|
69
|
-
|
|
70
|
-
- No ordinary owner can casually rewrite staged economics after launch.
|
|
71
|
-
- Split operators are not general-purpose governors.
|
|
72
|
-
- Loan mechanics, hidden-token mechanics, and cash-out policy remain bounded by the deployed revnet logic.
|
|
73
|
-
- This repo should not be documented as if it had a normal mutable project-owner model.
|
package/ARCHITECTURE.md
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
# Architecture
|
|
2
|
-
|
|
3
|
-
## Purpose
|
|
4
|
-
|
|
5
|
-
`revnet-core-v6` defines an autonomous Juicebox project pattern with staged, precommitted economics and token-collateralized loans. A revnet is intentionally ownerless after deployment in the human sense: behavior follows staged configuration and constrained runtime hooks instead of ongoing governance.
|
|
6
|
-
|
|
7
|
-
## System Overview
|
|
8
|
-
|
|
9
|
-
`REVDeployer` handles launch-time shape, staged rulesets, hook wiring, and runtime wrapper behavior. `REVOwner` provides the owner-like runtime policy surface for pay and cash-out hooks after launch. `REVLoans` manages burn-collateral loan positions represented as NFTs. `REVHiddenTokens` lets holders burn tokens to exclude them from visible supply until they reveal them again.
|
|
10
|
-
|
|
11
|
-
## Core Invariants
|
|
12
|
-
|
|
13
|
-
- Revnets are intended to be ownerless after deployment; easy admin recovery paths would violate the product model.
|
|
14
|
-
- Stage configuration is effectively permanent once queued.
|
|
15
|
-
- Loan collateral is burned, not escrowed.
|
|
16
|
-
- Hidden tokens are burned, not escrowed, and reduce visible supply until revealed.
|
|
17
|
-
- `REVOwner` and `REVDeployer` are tightly coupled; their setup order matters.
|
|
18
|
-
- Cash-out delay affects both exits and borrowing power.
|
|
19
|
-
- Cross-chain supply and surplus are part of revnet economics. Local payouts and loans must not ignore remote sucker snapshots.
|
|
20
|
-
|
|
21
|
-
## Modules
|
|
22
|
-
|
|
23
|
-
| Module | Responsibility | Notes |
|
|
24
|
-
| --- | --- | --- |
|
|
25
|
-
| `REVDeployer` | Launch, staged rulesets, hook wiring, permissions, runtime wrapper behavior | Launch-time and runtime wrapper |
|
|
26
|
-
| `REVOwner` | Runtime owner-like policy surface | Hook-facing policy |
|
|
27
|
-
| `REVLoans` | Borrow, repay, and liquidate burned-collateral loan positions | Economic core |
|
|
28
|
-
| `REVHiddenTokens` | Temporary supply exclusion through burn and reveal | Supply-sensitive utility |
|
|
29
|
-
| config structs | Stage, loan-source, auto-issuance, and hook config | Launch-time inputs |
|
|
30
|
-
|
|
31
|
-
## Trust Boundaries
|
|
32
|
-
|
|
33
|
-
- Treasury and ruleset mechanics remain rooted in `nana-core-v6`.
|
|
34
|
-
- Optional integrations come from `nana-buyback-hook-v6`, `nana-router-terminal-v6`, `nana-suckers-v6`, and `nana-721-hook-v6`.
|
|
35
|
-
- This repo composes those systems into an ownerless product shape instead of reimplementing them.
|
|
36
|
-
|
|
37
|
-
## Critical Flows
|
|
38
|
-
|
|
39
|
-
### Revnet Lifecycle
|
|
40
|
-
|
|
41
|
-
```text
|
|
42
|
-
creator
|
|
43
|
-
-> deploys a revnet with a fixed stage sequence
|
|
44
|
-
stage transitions
|
|
45
|
-
-> activate automatically over time through rulesets
|
|
46
|
-
participants
|
|
47
|
-
-> pay in, receive tokens, cash out, and interact with enabled integrations
|
|
48
|
-
operators or permissionless callers
|
|
49
|
-
-> perform bounded maintenance such as auto-issuance claims
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### Loan Lifecycle
|
|
53
|
-
|
|
54
|
-
```text
|
|
55
|
-
borrower
|
|
56
|
-
-> burns revnet tokens as collateral
|
|
57
|
-
-> borrowability is computed from the current stage, omnichain supply/surplus, and local liquidity caps
|
|
58
|
-
-> receives treasury-backed funds through REVLoans
|
|
59
|
-
-> later repays to remint collateral
|
|
60
|
-
-> or is liquidated after the expiration window
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## Accounting Model
|
|
64
|
-
|
|
65
|
-
The repo does not replace core treasury accounting. Its critical economic logic is the interaction between staged revnet config, burned-collateral loan state, hidden-token supply exclusion, and omnichain revnet state imported from suckers.
|
|
66
|
-
|
|
67
|
-
`REVOwner` also composes payment and cash-out hooks. On pay, it can merge 721-tier split forwarding with buyback-hook behavior and scale mint weight so the terminal only mints against the share that actually enters the project. On cash out, it can use omnichain supply and surplus for reclaim math, exempt trusted suckers, and append fee-hook specs.
|
|
68
|
-
|
|
69
|
-
## Security Model
|
|
70
|
-
|
|
71
|
-
- The highest-risk interactions sit where stage economics, treasury state, and loan borrowability meet.
|
|
72
|
-
- Ownerlessness removes convenient recovery from misconfiguration.
|
|
73
|
-
- Hidden-token and burned-collateral semantics materially affect supply-sensitive pricing.
|
|
74
|
-
- `REVOwner` is a live runtime policy surface, not just a launch helper.
|
|
75
|
-
- Rev cash-out fees stack on top of protocol-fee behavior rather than replacing it.
|
|
76
|
-
|
|
77
|
-
## Safe Change Guide
|
|
78
|
-
|
|
79
|
-
- Review deploy-time behavior and runtime wrapper behavior together.
|
|
80
|
-
- If stage semantics change, inspect loan math, cash-out behavior, and downstream fee expectations together.
|
|
81
|
-
- Do not casually add mutable admin escape hatches.
|
|
82
|
-
- If you change borrowability, re-check cash-out-delay gating, omnichain surplus inputs, and local-surplus caps together.
|
|
83
|
-
- If you change hook composition, re-check 721 split handling, buyback assumptions, and mint-permission flows.
|
|
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
|
-
|
|
97
|
-
## Canonical Checks
|
|
98
|
-
|
|
99
|
-
- cash-out-delay interaction with loans:
|
|
100
|
-
`test/TestLoansCashOutDelay.t.sol`
|
|
101
|
-
- stage transitions and borrowability drift:
|
|
102
|
-
`test/TestStageTransitionBorrowable.t.sol`
|
|
103
|
-
- omnichain or phantom-surplus edge cases:
|
|
104
|
-
`test/audit/CodexPhantomSurplusTerminal.t.sol`
|
|
105
|
-
- terminal encoding in configuration hash:
|
|
106
|
-
`test/TestTerminalEncodingInHash.t.sol`
|
|
107
|
-
|
|
108
|
-
## Source Map
|
|
109
|
-
|
|
110
|
-
- `src/REVDeployer.sol`
|
|
111
|
-
- `src/REVOwner.sol`
|
|
112
|
-
- `src/REVLoans.sol`
|
|
113
|
-
- `src/REVHiddenTokens.sol`
|
|
114
|
-
- `test/TestLoansCashOutDelay.t.sol`
|
|
115
|
-
- `test/TestStageTransitionBorrowable.t.sol`
|
|
116
|
-
- `test/audit/CodexPhantomSurplusTerminal.t.sol`
|
package/AUDIT_INSTRUCTIONS.md
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
# Audit Instructions
|
|
2
|
-
|
|
3
|
-
Revnet is a staged, owner-minimized product layer on top of Juicebox core. Audit it as an economic system, not just a deployer plus a loan contract.
|
|
4
|
-
|
|
5
|
-
## Audit Objective
|
|
6
|
-
|
|
7
|
-
Find issues that:
|
|
8
|
-
|
|
9
|
-
- break stage progression or let users act under the wrong stage assumptions
|
|
10
|
-
- overstate or understate borrowability
|
|
11
|
-
- mis-handle hidden tokens or burned-collateral accounting
|
|
12
|
-
- give operators or integrations more power than the revnet model intends
|
|
13
|
-
- make omnichain supply, surplus, or sucker assumptions drift from runtime behavior
|
|
14
|
-
|
|
15
|
-
## Scope
|
|
16
|
-
|
|
17
|
-
In scope:
|
|
18
|
-
|
|
19
|
-
- `src/REVDeployer.sol`
|
|
20
|
-
- `src/REVOwner.sol`
|
|
21
|
-
- `src/REVLoans.sol`
|
|
22
|
-
- `src/REVHiddenTokens.sol`
|
|
23
|
-
- structs, interfaces, and deployment helpers
|
|
24
|
-
|
|
25
|
-
## Start Here
|
|
26
|
-
|
|
27
|
-
1. `src/REVDeployer.sol`
|
|
28
|
-
2. `src/REVOwner.sol`
|
|
29
|
-
3. `src/REVLoans.sol`
|
|
30
|
-
4. `src/REVHiddenTokens.sol`
|
|
31
|
-
|
|
32
|
-
## Security Model
|
|
33
|
-
|
|
34
|
-
Revnet composes several sensitive systems:
|
|
35
|
-
|
|
36
|
-
- staged rulesets and launch-time immutability
|
|
37
|
-
- runtime pay and cash-out policy in `REVOwner`
|
|
38
|
-
- burned-collateral lending in `REVLoans`
|
|
39
|
-
- hidden-token supply exclusion in `REVHiddenTokens`
|
|
40
|
-
|
|
41
|
-
The main audit mindset is composition:
|
|
42
|
-
|
|
43
|
-
- stage economics affect borrowability
|
|
44
|
-
- hidden supply affects cash-out math
|
|
45
|
-
- omnichain state can affect reclaim and borrowing power
|
|
46
|
-
- optional integrations can widen the effective trust surface
|
|
47
|
-
|
|
48
|
-
## Roles And Privileges
|
|
49
|
-
|
|
50
|
-
| Role | Powers | How constrained |
|
|
51
|
-
|------|--------|-----------------|
|
|
52
|
-
| Revnet deployer path | Define long-lived stage and operator shape | Must not retain unexpected mutable governance |
|
|
53
|
-
| Split operator | Use the allowed runtime envelope | Must stay within deployment-defined permissions |
|
|
54
|
-
| Borrower or delegated operator | Open or manage loans | Must not escape collateral, delay, or source limits |
|
|
55
|
-
| Hidden-token user or delegate | Burn and reveal visible supply | Must not create extra supply or break accounting |
|
|
56
|
-
|
|
57
|
-
## Integration Assumptions
|
|
58
|
-
|
|
59
|
-
| Dependency | Assumption | What breaks if wrong |
|
|
60
|
-
|------------|------------|----------------------|
|
|
61
|
-
| `nana-core-v6` | Rulesets, reclaim math, and surplus views stay coherent | Stage and cash-out behavior drift |
|
|
62
|
-
| `nana-suckers-v6` | Remote supply/surplus snapshots are authentic | Omnichain reclaim and borrowability drift |
|
|
63
|
-
| Buyback and 721 integrations | Hook composition remains consistent with revnet expectations | Pay-path and mint-permission behavior drift |
|
|
64
|
-
|
|
65
|
-
## Critical Invariants
|
|
66
|
-
|
|
67
|
-
1. Stage progression stays monotonic and follows deployed timing.
|
|
68
|
-
2. Borrowability respects cash-out delay, surplus, supply, and source limits.
|
|
69
|
-
3. Burned collateral is not accidentally treated like escrowed collateral.
|
|
70
|
-
4. Hidden-token accounting preserves total claims while changing visible supply intentionally.
|
|
71
|
-
5. Optional integrations do not silently widen revnet authority or mint rights.
|
|
72
|
-
|
|
73
|
-
## Attack Surfaces
|
|
74
|
-
|
|
75
|
-
- stage-transition boundaries
|
|
76
|
-
- live borrowability and cross-currency debt aggregation
|
|
77
|
-
- hidden-token burn and reveal flows
|
|
78
|
-
- omnichain surplus and sucker exemptions
|
|
79
|
-
- payment and cash-out hook composition in `REVOwner`
|
|
80
|
-
|
|
81
|
-
## Accepted Risks Or Behaviors
|
|
82
|
-
|
|
83
|
-
- Revnets intentionally trade recoverability for predictable launch-time economics.
|
|
84
|
-
- Some economic surfaces are conservative by design and may refuse otherwise-valid actions rather than risk an unsafe result.
|
|
85
|
-
|
|
86
|
-
## Verification
|
|
87
|
-
|
|
88
|
-
- `npm install`
|
|
89
|
-
- `forge build`
|
|
90
|
-
- `forge test`
|