@rev-net/core-v6 0.0.23 → 0.0.25

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.
@@ -0,0 +1,311 @@
1
+ # Revnet Operations Reference
2
+
3
+ Use this file when you need revnet-specific risks, state reads, constants, or example integration details after `revnet-core-v6/SKILLS.md` has already routed you here.
4
+
5
+ ## Events
6
+
7
+ ### REVDeployer
8
+
9
+ | Event | When It Fires |
10
+ |-------|---------------|
11
+ | `AutoIssue(revnetId, stageId, beneficiary, count, caller)` | When tokens are auto-issued for a beneficiary during a stage via `autoIssueFor`. |
12
+ | `BurnHeldTokens(revnetId, count, caller)` | When held tokens are burned from the deployer contract via `burnHeldTokensOf`. |
13
+ | `DeployRevnet(revnetId, configuration, terminalConfigurations, suckerDeploymentConfiguration, rulesetConfigurations, encodedConfigurationHash, caller)` | When a new revnet is deployed via `deployFor`. |
14
+ | `DeploySuckers(revnetId, encodedConfigurationHash, suckerDeploymentConfiguration, caller)` | When suckers are deployed for a revnet via `deploySuckersFor`. |
15
+ | `ReplaceSplitOperator(revnetId, newSplitOperator, caller)` | When the split operator of a revnet is replaced via `setSplitOperatorOf`. |
16
+ | `SetCashOutDelay(revnetId, cashOutDelay, caller)` | When the cash out delay is set for a revnet during deployment to a new chain. |
17
+ | `StoreAutoIssuanceAmount(revnetId, stageId, beneficiary, count, caller)` | When an auto-issuance amount is stored for a beneficiary during deployment. |
18
+
19
+ ### REVLoans
20
+
21
+ | Event | When It Fires |
22
+ |-------|---------------|
23
+ | `Borrow(loanId, revnetId, loan, source, borrowAmount, collateralCount, sourceFeeAmount, beneficiary, caller)` | When a loan is created by borrowing from a revnet via `borrowFrom`. |
24
+ | `Liquidate(loanId, revnetId, loan, caller)` | When a loan is liquidated after exceeding the 10-year liquidation duration via `liquidateExpiredLoansFrom`. |
25
+ | `ReallocateCollateral(loanId, revnetId, reallocatedLoanId, reallocatedLoan, removedCollateralCount, caller)` | When collateral is reallocated from one loan to a new loan via `reallocateCollateralFromLoan`. |
26
+ | `RepayLoan(loanId, revnetId, paidOffLoanId, loan, paidOffLoan, repayBorrowAmount, sourceFeeAmount, collateralCountToReturn, beneficiary, caller)` | When a loan is repaid via `repayLoan`. |
27
+ | `SetTokenUriResolver(resolver, caller)` | When the token URI resolver is changed via `setTokenUriResolver`. |
28
+
29
+ ## Errors
30
+
31
+ ### REVDeployer
32
+
33
+ | Error | When It Fires |
34
+ |-------|---------------|
35
+ | `REVDeployer_AutoIssuanceBeneficiaryZeroAddress()` | When an auto-issuance config has a zero-address beneficiary. |
36
+ | `REVDeployer_CashOutDelayNotFinished(cashOutDelay, blockTimestamp)` | When a cash out is attempted before the 30-day delay has elapsed. |
37
+ | `REVDeployer_CashOutsCantBeTurnedOffCompletely(cashOutTaxRate, maxCashOutTaxRate)` | When `cashOutTaxRate` equals `MAX_CASH_OUT_TAX_RATE` (10,000). Must be strictly less. |
38
+ | `REVDeployer_MustHaveSplits()` | When a stage with `splitPercent > 0` has no splits configured. |
39
+ | `REVDeployer_NothingToAutoIssue()` | When `autoIssueFor` is called but no tokens are available for auto-issuance. |
40
+ | `REVDeployer_NothingToBurn()` | When `burnHeldTokensOf` is called but the deployer holds no tokens. |
41
+ | `REVDeployer_RulesetDoesNotAllowDeployingSuckers()` | When `deploySuckersFor` is called but the current ruleset's `extraMetadata` bit 2 is not set. |
42
+ | `REVDeployer_StageNotStarted(stageId)` | When `autoIssueFor` is called for a stage that hasn't started yet. |
43
+ | `REVDeployer_StagesRequired()` | When `deployFor` is called with zero stage configurations. |
44
+ | `REVDeployer_StageTimesMustIncrease()` | When stage `startsAtOrAfter` values are not strictly increasing. |
45
+ | `REVDeployer_Unauthorized(revnetId, caller)` | When a non-split-operator calls a split-operator-only function. |
46
+
47
+ ### REVLoans
48
+
49
+ | Error | When It Fires |
50
+ |-------|---------------|
51
+ | `REVLoans_CashOutDelayNotFinished(cashOutDelay, blockTimestamp)` | When borrowing during the 30-day cash-out delay period (cross-chain deployment protection). |
52
+ | `REVLoans_CollateralExceedsLoan(collateralToReturn, loanCollateral)` | When trying to return more collateral than the loan holds. |
53
+ | `REVLoans_InvalidPrepaidFeePercent(prepaidFeePercent, min, max)` | When `prepaidFeePercent` is outside the allowed range (2.5%--50%). |
54
+ | `REVLoans_InvalidTerminal(terminal, revnetId)` | When the specified terminal is not registered for the revnet. |
55
+ | `REVLoans_LoanExpired(timeSinceLoanCreated, loanLiquidationDuration)` | When trying to repay or reallocate an expired loan. |
56
+ | `REVLoans_LoanIdOverflow()` | When the loan ID counter exceeds the per-revnet trillion-ID namespace. |
57
+ | `REVLoans_NewBorrowAmountGreaterThanLoanAmount(newBorrowAmount, loanAmount)` | When a reallocation would produce a reduced loan with a larger borrow amount than the original. |
58
+ | `REVLoans_NoMsgValueAllowed()` | When `msg.value > 0` on a non-native-token repayment. |
59
+ | `REVLoans_NotEnoughCollateral()` | When the caller does not have enough tokens for the requested collateral. |
60
+ | `REVLoans_NothingToRepay()` | When `repayLoan` is called with zero repay amount and zero collateral to return. |
61
+ | `REVLoans_OverMaxRepayBorrowAmount(maxRepayBorrowAmount, repayBorrowAmount)` | When the actual repay cost exceeds the caller's `maxRepayBorrowAmount`. |
62
+ | `REVLoans_OverflowAlert(value, limit)` | When a value would overflow `uint112` storage. |
63
+ | `REVLoans_PermitAllowanceNotEnough(allowanceAmount, requiredAmount)` | When the permit2 allowance is insufficient for the repayment. |
64
+ | `REVLoans_ReallocatingMoreCollateralThanBorrowedAmountAllows(newBorrowAmount, loanAmount)` | When the collateral being transferred out would leave the original loan undercollateralized. |
65
+ | `REVLoans_SourceMismatch()` | When `reallocateCollateralFromLoan` specifies a source that doesn't match the existing loan's source. |
66
+ | `REVLoans_Unauthorized(caller, owner)` | When a non-owner tries to repay or reallocate someone else's loan. |
67
+ | `REVLoans_UnderMinBorrowAmount(minBorrowAmount, borrowAmount)` | When the actual borrow amount is less than the caller's `minBorrowAmount`. |
68
+ | `REVLoans_ZeroBorrowAmount()` | When a borrow or reallocation would result in zero borrowed funds. |
69
+ | `REVLoans_ZeroCollateralLoanIsInvalid()` | When a loan would end up with zero collateral. |
70
+
71
+ ## Constants
72
+
73
+ ### REVDeployer
74
+
75
+ | Constant | Value | Purpose |
76
+ |----------|-------|---------|
77
+ | `CASH_OUT_DELAY` | 2,592,000 (30 days) | Prevents cross-chain liquidity arbitrage on new chain deployments |
78
+ | `FEE` | 25 (of MAX_FEE=1000) | 2.5% cash-out fee paid to fee revnet |
79
+ | `DEFAULT_BUYBACK_POOL_FEE` | 10,000 | 1% Uniswap fee tier for default buyback pools |
80
+ | `DEFAULT_BUYBACK_TWAP_WINDOW` | 2 days | TWAP observation window for buyback price |
81
+ | `DEFAULT_BUYBACK_TICK_SPACING` | 200 | Tick spacing for default buyback V4 pools |
82
+
83
+ ### REVLoans
84
+
85
+ | Constant | Value | Purpose |
86
+ |----------|-------|---------|
87
+ | `LOAN_LIQUIDATION_DURATION` | 3,650 days (10 years) | After this, collateral is forfeit |
88
+ | `MIN_PREPAID_FEE_PERCENT` | 25 (2.5%) | Minimum upfront fee borrowers must pay |
89
+ | `MAX_PREPAID_FEE_PERCENT` | 500 (50%) | Maximum upfront fee |
90
+ | `REV_PREPAID_FEE_PERCENT` | 10 (1%) | Protocol-level fee to $REV revnet |
91
+ | `_ONE_TRILLION` | 1,000,000,000,000 | Loan ID generator base: `revnetId * 1T + loanNumber` |
92
+
93
+ ## Storage
94
+
95
+ ### REVDeployer
96
+
97
+ | Mapping | Visibility | Type | Purpose |
98
+ |---------|-----------|------|---------|
99
+ | `amountToAutoIssue` | `public` | `revnetId => stageId => beneficiary => uint256` | Premint tokens per stage per beneficiary |
100
+ | `hashedEncodedConfigurationOf` | `public` | `revnetId => bytes32` | Config hash for cross-chain sucker validation |
101
+ | `_extraOperatorPermissions` | `internal` | `revnetId => uint256[]` | Custom permissions for split operator (no auto-getter) |
102
+
103
+ ### REVOwner
104
+
105
+ | Mapping | Visibility | Type | Purpose |
106
+ |---------|-----------|------|---------|
107
+ | `DEPLOYER` | `public` | `address` | REVDeployer address (storage variable, set once via `setDeployer()` called from REVDeployer's constructor) |
108
+ | `cashOutDelayOf` | `public` | `revnetId => uint256` | Timestamp when cash outs unlock (0 = no delay). Set by REVDeployer via `setCashOutDelayOf()`. |
109
+ | `tiered721HookOf` | `public` | `revnetId => address` | Deployed 721 hook address (if any). Set by REVDeployer via `setTiered721HookOf()`. |
110
+
111
+ ### REVLoans
112
+
113
+ | Mapping | Visibility | Type | Purpose |
114
+ |---------|-----------|------|---------|
115
+ | `isLoanSourceOf` | `public` | `revnetId => terminal => token => bool` | Is this (terminal, token) pair used for loans? |
116
+ | `totalLoansBorrowedFor` | `public` | `revnetId => uint256` | Counter for loan numbering |
117
+ | `totalBorrowedFrom` | `public` | `revnetId => terminal => token => uint256` | Tracks debt per loan source |
118
+ | `totalCollateralOf` | `public` | `revnetId => uint256` | Sum of all burned collateral |
119
+ | `_loanOf` | `internal` | `loanId => REVLoan` | Per-loan state (use `loanOf(loanId)` view) |
120
+ | `_loanSourcesOf` | `internal` | `revnetId => REVLoanSource[]` | Array of all loan sources used (use `loanSourcesOf(revnetId)` view) |
121
+ | `tokenUriResolver` | `public` | `IJBTokenUriResolver` | Resolver for loan NFT token URIs |
122
+
123
+ ## Gotchas
124
+
125
+ 1. **Revnets are permanently ownerless.** `REVDeployer` holds the project NFT forever. There is no function to release it. Stage parameters cannot be changed after deployment.
126
+ 2. **Collateral is burned, not held.** Unlike traditional lending, collateral tokens are destroyed at borrow time and re-minted on repay. If a loan liquidates after 10 years, the collateral is permanently lost.
127
+ 3. **100% LTV by design.** Borrowable amount equals the pro-rata cash-out value. No safety margin unless the stage has `cashOutTaxRate > 0`. A tax of 20% creates ~20% effective collateral buffer.
128
+ 4. **Loan ID encoding.** `loanId = revnetId * 1_000_000_000_000 + loanNumber`. Each revnet supports ~1 trillion loans. Use `revnetIdOfLoanWith(loanId)` to decode.
129
+ 5. **uint112 truncation risk.** `REVLoan.amount` and `REVLoan.collateral` are `uint112`. Values above ~5.19e33 truncate silently.
130
+ 6. **Auto-issuance stage IDs.** Computed as `block.timestamp + i` during deployment. These match the Juicebox ruleset IDs because `JBRulesets` assigns IDs the same way (`latestId >= block.timestamp ? latestId + 1 : block.timestamp`), producing identical sequential IDs when all stages are queued in a single `deployFor()` call.
131
+ 7. **Cash-out fee stacking.** Cash outs incur both the Juicebox terminal fee (2.5%) and the revnet cash-out fee (2.5% to fee revnet). These compound. The 2.5% fee is deducted from the TOKEN AMOUNT being cashed out, not from the reclaim value. 2.5% of the tokens are redirected to the fee revnet, which then redeems them at the bonding curve independently. The net reclaim to the caller is based on 97.5% of the tokens, not 97.5% of the computed ETH value. This is by design.
132
+ 8. **30-day cash-out delay.** Applied when deploying an existing revnet to a new chain where the first stage has already started. Prevents cross-chain liquidity arbitrage. Enforced in both `beforeCashOutRecordedWith` (direct cash outs) and `REVLoans.borrowFrom` / `borrowableAmountFrom` (loans). The delay is stored on REVOwner (`cashOutDelayOf(revnetId)`) and set by REVDeployer during deployment via `setCashOutDelayOf()`. REVLoans imports IREVOwner (not IREVDeployer) to read it.
133
+ 9. **`cashOutTaxRate` cannot be MAX.** Must be strictly less than `MAX_CASH_OUT_TAX_RATE` (10,000). Revnets cannot fully disable cash outs.
134
+ 10. **Split operator is singular.** Only ONE address can be split operator at a time. The operator can replace itself via `setSplitOperatorOf` but cannot delegate or multi-sig.
135
+ 11. **NATIVE_TOKEN on non-ETH chains.** `JBConstants.NATIVE_TOKEN` on Celo means CELO, on Polygon means MATIC -- not ETH. Use ERC-20 WETH instead. The config matching hash does NOT catch terminal configuration differences.
136
+ 12. **Loan source array is unbounded.** `_loanSourcesOf[revnetId]` grows without limit. No validation that a terminal is actually registered for the project.
137
+ 13. **Flash-loan surplus exposure.** `borrowableAmountFrom` reads live surplus. A flash loan can temporarily inflate the treasury to borrow more than the sustained value supports.
138
+ 14. **Fee revnet must have terminals.** Cash-out fees and loan protocol fees are paid to `FEE_REVNET_ID`. If that project has no terminal for the token, the fee silently fails (try-catch).
139
+ 15. **Buyback hook is immutable per deployer.** `BUYBACK_HOOK` is set at construction time on both REVDeployer and REVOwner. All revnets deployed by the same deployer share the same buyback hook.
140
+ 16. **Cross-chain config matching.** `hashedEncodedConfigurationOf` covers economic parameters (baseCurrency, stages, auto-issuances) but NOT terminal configurations, accounting contexts, or sucker token mappings. Two deployments with identical hashes can have different terminal setups.
141
+ 17. **Loan fee model has three layers.** See Constants table for exact values: REV protocol fee, terminal fee, and prepaid source fee (borrower-chosen, buys interest-free window). After the prepaid window, source fee accrues linearly over the remaining loan duration.
142
+ 18. **Permit2 fallback.** `REVLoans` uses permit2 for ERC-20 transfers as a fallback when standard allowance is insufficient. Wrapped in try-catch.
143
+ 19. **39.16% cash-out tax crossover.** Below ~39% cash-out tax, cashing out is more capital-efficient than borrowing. Above ~39%, loans become more efficient because they preserve upside while providing liquidity. Based on CryptoEconLab academic research. Design implication: revnets intended for active token trading should consider this threshold when setting `cashOutTaxRate`.
144
+ 20. **REVDeployer always deploys a 721 hook** via `HOOK_DEPLOYER.deployHookFor` — even if `baseline721HookConfiguration` has empty tiers. This is correct by design: it lets the split operator add and sell NFTs later without migration. Non-revnet projects should follow the same pattern by using `JB721TiersHookProjectDeployer.launchProjectFor` (or `JBOmnichainDeployer.launchProjectFor`) instead of bare `launchProjectFor`.
145
+ 21. **REVOwner circular dependency.** REVOwner and REVDeployer have a circular dependency broken by `setDeployer()`, called atomically from REVDeployer's constructor. `REVOwner.DEPLOYER` is a storage variable (not immutable). `setDeployer()` sets `msg.sender` as `DEPLOYER` if not already set -- reverts if already set. If `setDeployer()` is never called, all runtime hook behavior breaks. Deploy order: REVOwner first, then REVDeployer(owner=REVOwner) -- the constructor calls `REVOwner.setDeployer()` atomically. REVOwner stores `cashOutDelayOf` and `tiered721HookOf` mappings, which are set by REVDeployer via DEPLOYER-restricted setters (`setCashOutDelayOf()`, `setTiered721HookOf()`).
146
+
147
+ ### NATIVE_TOKEN Accounting on Non-ETH Chains
148
+
149
+ When deploying to a chain where the native token is NOT ETH (Celo, Polygon), the terminal must NOT use `JBConstants.NATIVE_TOKEN` as its accounting context. `NATIVE_TOKEN` represents whatever is native on that chain, but `baseCurrency=1` (ETH) assumes ETH-denominated value.
150
+
151
+ **Correct (Celo):**
152
+ ```solidity
153
+ JBAccountingContext({
154
+ token: WETH_CELO, // ERC-20 WETH, not native CELO
155
+ decimals: 18,
156
+ currency: uint32(uint160(WETH_CELO))
157
+ })
158
+ ```
159
+
160
+ **Wrong (Celo):**
161
+ ```solidity
162
+ JBAccountingContext({
163
+ token: JBConstants.NATIVE_TOKEN, // This is CELO, not ETH!
164
+ decimals: 18,
165
+ currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
166
+ })
167
+ ```
168
+
169
+ ## Reading Revnet State
170
+
171
+ Quick-reference for common read operations. All functions are `view`/`pure` and permissionless.
172
+
173
+ ### Current Stage & Ruleset
174
+
175
+ | What | Call | Returns |
176
+ |------|------|---------|
177
+ | Current ruleset (stage) | `IJBController(CONTROLLER).currentRulesetOf(revnetId)` | `(JBRuleset, JBRulesetMetadata)` -- the active stage's parameters |
178
+ | All queued rulesets | `IJBController(CONTROLLER).allRulesetsOf(revnetId, startingId, size)` | `JBRulesetWithMetadata[]` -- paginated list of stages |
179
+ | Specific stage by ID | `IJBController(CONTROLLER).getRulesetOf(revnetId, stageId)` | `(JBRuleset, JBRulesetMetadata)` for that stage |
180
+
181
+ ### Split Operator
182
+
183
+ | What | Call | Returns |
184
+ |------|------|---------|
185
+ | Check if address is split operator | `REVDeployer.isSplitOperatorOf(revnetId, addr)` | `bool` |
186
+
187
+ ### Token Supply & Surplus
188
+
189
+ | What | Call | Returns |
190
+ |------|------|---------|
191
+ | Total supply (incl. pending reserved) | `IJBController(CONTROLLER).totalTokenSupplyWithReservedTokensOf(revnetId)` | `uint256` |
192
+ | Pending reserved tokens | `IJBController(CONTROLLER).pendingReservedTokenBalanceOf(revnetId)` | `uint256` |
193
+ | Current surplus (single terminal) | `IJBTerminalStore(STORE).currentSurplusOf(terminal, revnetId, configs, decimals, currency)` | `uint256` |
194
+
195
+ ### Auto-Issuance
196
+
197
+ | What | Call | Returns |
198
+ |------|------|---------|
199
+ | Remaining auto-issuance for beneficiary | `REVDeployer.amountToAutoIssue(revnetId, stageId, beneficiary)` | `uint256` (0 if already claimed) |
200
+
201
+ ### Loans
202
+
203
+ | What | Call | Returns |
204
+ |------|------|---------|
205
+ | Borrowable amount for collateral | `REVLoans.borrowableAmountFrom(revnetId, collateralCount, decimals, currency)` | `uint256` |
206
+ | Total borrowed (per source) | `REVLoans.totalBorrowedFrom(revnetId, terminal, token)` | `uint256` |
207
+ | Total collateral locked | `REVLoans.totalCollateralOf(revnetId)` | `uint256` |
208
+ | Loan details | `REVLoans.loanOf(loanId)` | `REVLoan` struct |
209
+ | All loan sources | `REVLoans.loanSourcesOf(revnetId)` | `REVLoanSource[]` |
210
+ | Loan count | `REVLoans.totalLoansBorrowedFor(revnetId)` | `uint256` |
211
+ | Source fee for repayment | `REVLoans.determineSourceFeeAmount(loan, amount)` | `uint256` |
212
+ | Revnet ID from loan ID | `REVLoans.revnetIdOfLoanWith(loanId)` | `uint256` (pure) |
213
+ | Loan NFT owner | `REVLoans.ownerOf(loanId)` | `address` (ERC-721) |
214
+
215
+ ### Deployer Config
216
+
217
+ | What | Call | Returns |
218
+ |------|------|---------|
219
+ | Config hash (cross-chain matching) | `REVDeployer.hashedEncodedConfigurationOf(revnetId)` | `bytes32` |
220
+ | REVOwner address | `REVDeployer.OWNER()` | `address` |
221
+
222
+ ### REVOwner State
223
+
224
+ | What | Call | Returns |
225
+ |------|------|---------|
226
+ | 721 hook address | `REVOwner.tiered721HookOf(revnetId)` | `IJB721TiersHook` |
227
+ | Cash-out delay timestamp | `REVOwner.cashOutDelayOf(revnetId)` | `uint256` (0 = no delay) |
228
+
229
+ ## Example Integration
230
+
231
+ ```solidity
232
+ import {REVConfig} from "@rev-net/core-v6/src/structs/REVConfig.sol";
233
+ import {REVStageConfig} from "@rev-net/core-v6/src/structs/REVStageConfig.sol";
234
+ import {REVDescription} from "@rev-net/core-v6/src/structs/REVDescription.sol";
235
+ import {REVSuckerDeploymentConfig} from "@rev-net/core-v6/src/structs/REVSuckerDeploymentConfig.sol";
236
+ import {IREVDeployer} from "@rev-net/core-v6/src/interfaces/IREVDeployer.sol";
237
+
238
+ // --- Deploy a simple revnet with one stage ---
239
+
240
+ REVStageConfig[] memory stages = new REVStageConfig[](1);
241
+ stages[0] = REVStageConfig({
242
+ startsAtOrAfter: 0, // Start immediately (uses block.timestamp)
243
+ autoIssuances: new REVAutoIssuance[](0),
244
+ splitPercent: 2000, // 20% of new tokens go to splits
245
+ splits: splits, // Reserved token split destinations
246
+ initialIssuance: 1_000_000e18, // 1M tokens per unit of base currency
247
+ issuanceCutFrequency: 30 days, // Decay period
248
+ issuanceCutPercent: 100_000_000, // 10% cut per period (out of 1e9)
249
+ cashOutTaxRate: 2000, // 20% tax on cash outs
250
+ extraMetadata: 0
251
+ });
252
+
253
+ REVConfig memory config = REVConfig({
254
+ description: REVDescription({
255
+ name: "My Revnet Token",
256
+ ticker: "MYREV",
257
+ uri: "ipfs://...",
258
+ salt: bytes32(0)
259
+ }),
260
+ baseCurrency: 1, // ETH
261
+ splitOperator: msg.sender,
262
+ stageConfigurations: stages
263
+ });
264
+
265
+ deployer.deployFor({
266
+ revnetId: 0, // 0 = deploy new
267
+ configuration: config,
268
+ terminalConfigurations: terminals,
269
+ suckerDeploymentConfiguration: REVSuckerDeploymentConfig({
270
+ deployerConfigurations: new JBSuckerDeployerConfig[](0),
271
+ salt: bytes32(0)
272
+ })
273
+ });
274
+
275
+ // --- Borrow against revnet tokens ---
276
+
277
+ loans.borrowFrom({
278
+ revnetId: revnetId,
279
+ source: REVLoanSource({ token: JBConstants.NATIVE_TOKEN, terminal: terminal }),
280
+ minBorrowAmount: 0,
281
+ collateralCount: 1000e18, // Burn 1000 tokens as collateral
282
+ beneficiary: msg.sender, // Receive borrowed funds
283
+ prepaidFeePercent: 25 // 2.5% prepaid fee (minimum)
284
+ });
285
+
286
+ // --- Reallocate collateral (refinance) ---
287
+ // Remove 500 tokens of collateral from an existing loan,
288
+ // use them (plus 200 new tokens) to open a fresh loan.
289
+ // The original loan shrinks, and a new loan NFT is minted.
290
+ (uint256 reallocatedLoanId, uint256 newLoanId, , ) = loans.reallocateCollateralFromLoan({
291
+ loanId: loanId,
292
+ collateralCountToTransfer: 500e18, // Move 500 tokens out of existing loan
293
+ source: REVLoanSource({ token: JBConstants.NATIVE_TOKEN, terminal: terminal }),
294
+ minBorrowAmount: 0,
295
+ collateralCountToAdd: 200e18, // Add 200 fresh tokens on top
296
+ beneficiary: payable(msg.sender), // Receive new loan proceeds
297
+ prepaidFeePercent: 25 // 2.5% prepaid fee on new loan
298
+ });
299
+ // Result: original loan now has 500 fewer collateral tokens (reallocatedLoanId),
300
+ // new loan has 700 tokens of collateral (newLoanId).
301
+
302
+ // --- Repay a loan ---
303
+
304
+ loans.repayLoan({
305
+ loanId: loanId,
306
+ maxRepayBorrowAmount: type(uint256).max, // Repay in full
307
+ collateralCountToReturn: loan.collateral, // Return all collateral
308
+ beneficiary: msg.sender, // Receive re-minted tokens
309
+ allowance: JBSingleAllowance({ ... }) // Optional permit2
310
+ });
311
+ ```
@@ -0,0 +1,98 @@
1
+ # Revnet Runtime Reference
2
+
3
+ Use this file when you already know the task is in `revnet-core-v6` and need the deployer, owner, or loans surface in detail.
4
+
5
+ ## Purpose
6
+
7
+ Deploy and manage Revnets -- autonomous, unowned Juicebox projects with staged issuance schedules, built-in Uniswap buyback pools, cross-chain suckers, and token-collateralized lending.
8
+
9
+ ## Contracts
10
+
11
+ | Contract | Role |
12
+ |----------|------|
13
+ | `REVDeployer` | Deploys revnets, permanently owns the project NFT. Manages stages, splits, auto-issuance, buyback hooks, suckers, split operators, and configuration state storage. Exposes `OWNER()` view returning the REVOwner address. Calls DEPLOYER-restricted setters on REVOwner during deployment to store `cashOutDelayOf` and `tiered721HookOf`. |
14
+ | `REVOwner` | Runtime hook contract for all revnets. Implements `IJBRulesetDataHook` + `IJBCashOutHook`. Set as the `dataHook` in each revnet's ruleset metadata. Handles pay hooks, cash-out hooks, mint permissions, and sucker verification. Stores `cashOutDelayOf` and `tiered721HookOf` mappings (set by REVDeployer via DEPLOYER-restricted setters `setCashOutDelayOf()` and `setTiered721HookOf()`). |
15
+ | `REVLoans` | Issues token-collateralized loans from revnet treasuries. Each loan is an ERC-721 NFT. Burns collateral on borrow, re-mints on repay. Charges tiered fees (REV protocol fee + source fee + prepaid fee). |
16
+
17
+ ## Key Functions
18
+
19
+ ### Deployment
20
+
21
+ | Function | Permissions | What it does |
22
+ |----------|------------|-------------|
23
+ | `REVDeployer.deployFor(revnetId, config, terminals, suckerConfig)` | Permissionless | Deploy a new revnet (`revnetId=0`) or convert an existing Juicebox project. Encodes stage configs into rulesets, deploys ERC-20 token, initializes buyback pool at 1:1 price, sets up split operator, suckers, loans permissions, and deploys a default empty tiered ERC-721 hook. |
24
+ | `REVDeployer.deployFor(revnetId, config, terminals, suckerConfig, hookConfig, allowedPosts)` | Permissionless | Same as `deployFor` but deploys a tiered ERC-721 hook with pre-configured tiers. Optionally configures Croptop posting criteria and grants publisher permission to add tiers. |
25
+ | `REVDeployer.deploySuckersFor(revnetId, suckerConfig)` | Split operator | Deploy new cross-chain suckers post-launch. Validates ruleset allows sucker deployment (bit 2 of `extraMetadata`). Uses stored config hash for cross-chain matching. |
26
+
27
+ ### Data Hooks (REVOwner)
28
+
29
+ | Function | Permissions | What it does |
30
+ |----------|------------|-------------|
31
+ | `REVOwner.beforePayRecordedWith(context)` | Terminal callback | Calls the 721 hook first for split specs, then calls the buyback hook with a reduced amount context (payment minus split amount). Adjusts the returned weight proportionally for splits (`weight = mulDiv(weight, amount - splitAmount, amount)`) so the terminal only mints tokens for the amount entering the project. Assembles pay hook specs (721 hook specs first, then buyback spec). Reads `tiered721HookOf` from REVOwner storage. |
32
+ | `REVOwner.beforeCashOutRecordedWith(context)` | Terminal callback | If sucker: returns full amount with 0 tax (fee exempt). Otherwise: calculates 2.5% fee, enforces 30-day cash-out delay (reads `cashOutDelayOf` from REVOwner storage), returns modified count + fee hook spec. |
33
+ | `REVOwner.afterCashOutRecordedWith(context)` | Permissionless | Cash-out hook callback. Receives fee amount and pays it to the fee revnet's terminal. Falls back to returning funds if fee payment fails. |
34
+ | `REVOwner.hasMintPermissionFor(revnetId, ruleset, addr)` | View | Returns `true` for: loans contract, buyback hook, buyback hook delegates, or suckers. |
35
+ | `REVOwner.cashOutDelayOf(revnetId)` | View | Returns the cash-out delay timestamp from REVOwner storage. Exposed for REVLoans compatibility (REVLoans imports IREVOwner for this). |
36
+
37
+ ### Split Operator
38
+
39
+ | Function | Permissions | What it does |
40
+ |----------|------------|-------------|
41
+ | `REVDeployer.setSplitOperatorOf(revnetId, newOperator)` | Split operator | Replace the current split operator. Revokes old permissions, grants new ones. |
42
+
43
+ ### Auto-Issuance
44
+
45
+ | Function | Permissions | What it does |
46
+ |----------|------------|-------------|
47
+ | `REVDeployer.autoIssueFor(revnetId, stageId, beneficiary)` | Permissionless | Mint pre-configured auto-issuance tokens for a beneficiary once a stage has started. One-time per stage per beneficiary. |
48
+ | `REVDeployer.burnHeldTokensOf(revnetId)` | Permissionless | Burn any reserved tokens held by the deployer (when splits < 100%). |
49
+
50
+ ### Loans -- Borrowing
51
+
52
+ | Function | Permissions | What it does |
53
+ |----------|------------|-------------|
54
+ | `REVLoans.borrowFrom(revnetId, source, minBorrowAmount, collateralCount, beneficiary, prepaidFeePercent)` | Permissionless (caller must grant BURN_TOKENS to REVLoans) | Open a loan: enforce cash-out delay if set (cross-chain deployment protection), burn collateral tokens, pull funds from revnet via `useAllowanceOf`, pay REV fee (1%) + terminal fee (2.5%), transfer remainder to beneficiary, mint loan NFT. |
55
+ | `REVLoans.repayLoan(loanId, maxRepayBorrowAmount, collateralCountToReturn, beneficiary, allowance)` | Loan NFT owner | Repay fully or partially. Returns funds to revnet via `addToBalanceOf`, re-mints collateral tokens, burns/replaces the loan NFT. Supports permit2 signatures. |
56
+ | `REVLoans.reallocateCollateralFromLoan(loanId, collateralCountToTransfer, source, minBorrowAmount, collateralCountToAdd, beneficiary, prepaidFeePercent)` | Loan NFT owner | Refinance: remove excess collateral from an existing loan and open a new loan with the freed collateral. Burns original, mints two replacements. |
57
+ | `REVLoans.liquidateExpiredLoansFrom(revnetId, startingLoanId, count)` | Permissionless | Clean up loans past the 10-year liquidation duration. Burns NFTs and decrements accounting totals. Collateral is permanently lost. |
58
+ | `REVLoans.setTokenUriResolver(resolver)` | Contract owner (`onlyOwner`) | Set the `IJBTokenUriResolver` used for loan NFT token URIs. |
59
+
60
+ ### Loans -- Views
61
+
62
+ | Function | What it does |
63
+ |----------|-------------|
64
+ | `REVLoans.borrowableAmountFrom(revnetId, collateralCount, decimals, currency)` | Calculate how much can be borrowed for a given collateral amount. Returns 0 during the cash-out delay period. Aggregates surplus from all terminals, applies bonding curve. |
65
+ | `REVLoans.determineSourceFeeAmount(loan, amount)` | Calculate the time-proportional source fee for a loan repayment. Zero during prepaid window, linear accrual after. |
66
+ | `REVLoans.loanOf(loanId)` | Returns the full `REVLoan` struct for a loan. |
67
+ | `REVLoans.loanSourcesOf(revnetId)` | Returns all `(terminal, token)` pairs used for loans by a revnet. |
68
+ | `REVLoans.revnetIdOfLoanWith(loanId)` | Decode the revnet ID from a loan ID (`loanId / 1_000_000_000_000`). |
69
+
70
+ ## Integration Points
71
+
72
+ | Dependency | Import | Used For |
73
+ |------------|--------|----------|
74
+ | `@bananapus/core-v6` | `IJBController`, `IJBDirectory`, `IJBPermissions`, `IJBProjects`, `IJBTerminal`, `IJBPrices`, `JBConstants`, `JBCashOuts`, `JBSurplus` | Project lifecycle, rulesets, token minting/burning, fund access, terminal payments, price feeds, bonding curve |
75
+ | `@bananapus/721-hook-v6` | `IJB721TiersHook`, `IJB721TiersHookDeployer` | Deploying and registering tiered ERC-721 pay hooks |
76
+ | `@bananapus/buyback-hook-v6` | `IJBBuybackHookRegistry` | Configuring Uniswap buyback pools per revnet |
77
+ | `@bananapus/suckers-v6` | `IJBSuckerRegistry` | Deploying cross-chain suckers, checking sucker status for fee exemption |
78
+ | `@croptop/core-v6` | `CTPublisher` | Configuring Croptop posting criteria for 721 tiers |
79
+ | `@bananapus/permission-ids-v6` | `JBPermissionIds` | Permission ID constants (SET_SPLIT_GROUPS, USE_ALLOWANCE, etc.) |
80
+ | `@openzeppelin/contracts` | `ERC721`, `ERC2771Context`, `Ownable`, `SafeERC20` | Loan NFTs, meta-transactions, ownership, safe token transfers |
81
+ | `@uniswap/permit2` | `IPermit2`, `IAllowanceTransfer` | Gasless token approvals for loan repayments |
82
+ | `@prb/math` | `mulDiv` | Precise fixed-point multiplication and division |
83
+
84
+ ## Key Types
85
+
86
+ | Struct | Key Fields | Used In |
87
+ |--------|------------|---------|
88
+ | `REVConfig` | `description` (REVDescription), `baseCurrency`, `splitOperator`, `stageConfigurations[]` | `deployFor` |
89
+ | `REVStageConfig` | `startsAtOrAfter` (uint48), `initialIssuance` (uint112), `issuanceCutFrequency` (uint32), `issuanceCutPercent` (uint32), `cashOutTaxRate` (uint16), `splitPercent` (uint16), `splits[]`, `autoIssuances[]`, `extraMetadata` (uint16) | Translated into `JBRulesetConfig` |
90
+ | `REVDescription` | `name`, `ticker`, `uri`, `salt` | ERC-20 token deployment and project metadata |
91
+ | `REVAutoIssuance` | `chainId` (uint32), `count` (uint104), `beneficiary` | Per-stage cross-chain token auto-minting |
92
+ | `REVLoan` | `amount` (uint112), `collateral` (uint112), `createdAt` (uint48), `prepaidFeePercent` (uint16), `prepaidDuration` (uint32), `source` (REVLoanSource) | Per-loan state in `REVLoans` |
93
+ | `REVLoanSource` | `token`, `terminal` (IJBPayoutTerminal) | Identifies which terminal and token a loan draws from |
94
+ | `REVDeploy721TiersHookConfig` | `baseline721HookConfiguration` (REVBaseline721HookConfig), `salt`, `preventSplitOperatorAdjustingTiers`, `preventSplitOperatorUpdatingMetadata`, `preventSplitOperatorMinting`, `preventSplitOperatorIncreasingDiscountPercent` | 721 hook deployment with operator permissions (preventive flags — `false` = allowed). Uses `REVBaseline721HookConfig` (not `JBDeploy721TiersHookConfig`) to omit `issueTokensForSplits` — revnets always force it to `false`. |
95
+ | `REVBaseline721HookConfig` | `name`, `symbol`, `baseUri`, `tokenUriResolver`, `contractUri`, `tiersConfig`, `reserveBeneficiary`, `flags` (REV721TiersHookFlags) | Same as `JBDeploy721TiersHookConfig` but uses `REV721TiersHookFlags` which omits `issueTokensForSplits`. |
96
+ | `REV721TiersHookFlags` | `noNewTiersWithReserves`, `noNewTiersWithVotes`, `noNewTiersWithOwnerMinting`, `preventOverspending` | Same as `JB721TiersHookFlags` minus `issueTokensForSplits`. Revnets do their own weight adjustment for splits. |
97
+ | `REVCroptopAllowedPost` | `category` (uint24), `minimumPrice` (uint104), `minimumTotalSupply` (uint32), `maximumTotalSupply` (uint32), `allowedAddresses[]` | Croptop posting criteria |
98
+ | `REVSuckerDeploymentConfig` | `deployerConfigurations[]`, `salt` | Cross-chain sucker deployment |
@@ -1,18 +1,18 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.28;
3
3
 
4
- // forge-lint: disable-next-line(unaliased-plain-import)
5
- import "@bananapus/721-hook-v6/script/helpers/Hook721DeploymentLib.sol";
6
- // forge-lint: disable-next-line(unaliased-plain-import)
7
- import "@bananapus/buyback-hook-v6/script/helpers/BuybackDeploymentLib.sol";
8
- // forge-lint: disable-next-line(unaliased-plain-import)
9
- import "@bananapus/core-v6/script/helpers/CoreDeploymentLib.sol";
10
- // forge-lint: disable-next-line(unaliased-plain-import)
11
- import "@bananapus/suckers-v6/script/helpers/SuckerDeploymentLib.sol";
12
- // forge-lint: disable-next-line(unaliased-plain-import)
13
- import "@bananapus/router-terminal-v6/script/helpers/RouterTerminalDeploymentLib.sol";
14
- // forge-lint: disable-next-line(unaliased-plain-import)
15
- import "@croptop/core-v6/script/helpers/CroptopDeploymentLib.sol";
4
+ import {Hook721Deployment, Hook721DeploymentLib} from "@bananapus/721-hook-v6/script/helpers/Hook721DeploymentLib.sol";
5
+ import {
6
+ BuybackDeployment,
7
+ BuybackDeploymentLib
8
+ } from "@bananapus/buyback-hook-v6/script/helpers/BuybackDeploymentLib.sol";
9
+ import {CoreDeployment, CoreDeploymentLib} from "@bananapus/core-v6/script/helpers/CoreDeploymentLib.sol";
10
+ import {SuckerDeployment, SuckerDeploymentLib} from "@bananapus/suckers-v6/script/helpers/SuckerDeploymentLib.sol";
11
+ import {
12
+ RouterTerminalDeployment,
13
+ RouterTerminalDeploymentLib
14
+ } from "@bananapus/router-terminal-v6/script/helpers/RouterTerminalDeploymentLib.sol";
15
+ import {CroptopDeployment, CroptopDeploymentLib} from "@croptop/core-v6/script/helpers/CroptopDeploymentLib.sol";
16
16
 
17
17
  import {Sphinx} from "@sphinx-labs/contracts/contracts/foundry/SphinxPlugin.sol";
18
18
  import {Script} from "forge-std/Script.sol";
package/src/REVLoans.sol CHANGED
@@ -1,16 +1,6 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.28;
3
3
 
4
- import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
5
- import {ERC2771Context} from "@openzeppelin/contracts/metatx/ERC2771Context.sol";
6
- import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
7
- import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
8
- import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
9
- import {Address} from "@openzeppelin/contracts/utils/Address.sol";
10
- import {Context} from "@openzeppelin/contracts/utils/Context.sol";
11
- import {mulDiv} from "@prb/math/src/Common.sol";
12
- import {IAllowanceTransfer} from "@uniswap/permit2/src/interfaces/IAllowanceTransfer.sol";
13
- import {IPermit2} from "@uniswap/permit2/src/interfaces/IPermit2.sol";
14
4
  import {IJBController} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
15
5
  import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
16
6
  import {IJBPayoutTerminal} from "@bananapus/core-v6/src/interfaces/IJBPayoutTerminal.sol";
@@ -26,6 +16,16 @@ import {JBSurplus} from "@bananapus/core-v6/src/libraries/JBSurplus.sol";
26
16
  import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
27
17
  import {JBRuleset} from "@bananapus/core-v6/src/structs/JBRuleset.sol";
28
18
  import {JBSingleAllowance} from "@bananapus/core-v6/src/structs/JBSingleAllowance.sol";
19
+ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
20
+ import {ERC2771Context} from "@openzeppelin/contracts/metatx/ERC2771Context.sol";
21
+ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
22
+ import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
23
+ import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
24
+ import {Address} from "@openzeppelin/contracts/utils/Address.sol";
25
+ import {Context} from "@openzeppelin/contracts/utils/Context.sol";
26
+ import {mulDiv} from "@prb/math/src/Common.sol";
27
+ import {IAllowanceTransfer} from "@uniswap/permit2/src/interfaces/IAllowanceTransfer.sol";
28
+ import {IPermit2} from "@uniswap/permit2/src/interfaces/IPermit2.sol";
29
29
 
30
30
  import {IREVLoans} from "./interfaces/IREVLoans.sol";
31
31
  import {IREVOwner} from "./interfaces/IREVOwner.sol";
@@ -3,11 +3,11 @@ pragma solidity ^0.8.0;
3
3
 
4
4
  import {IJB721TiersHook} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHook.sol";
5
5
  import {IJB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHookDeployer.sol";
6
+ import {IJBBuybackHookRegistry} from "@bananapus/buyback-hook-v6/src/interfaces/IJBBuybackHookRegistry.sol";
6
7
  import {IJBController} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
7
8
  import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
8
9
  import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
9
10
  import {IJBProjects} from "@bananapus/core-v6/src/interfaces/IJBProjects.sol";
10
- import {IJBBuybackHookRegistry} from "@bananapus/buyback-hook-v6/src/interfaces/IJBBuybackHookRegistry.sol";
11
11
  import {JBRulesetConfig} from "@bananapus/core-v6/src/structs/JBRulesetConfig.sol";
12
12
  import {JBTerminalConfig} from "@bananapus/core-v6/src/structs/JBTerminalConfig.sol";
13
13
  import {IJBSuckerRegistry} from "@bananapus/suckers-v6/src/interfaces/IJBSuckerRegistry.sol";
@@ -39,6 +39,7 @@ import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/
39
39
  import {IJBRulesetDataHook} from "@bananapus/core-v6/src/interfaces/IJBRulesetDataHook.sol";
40
40
  import {IJBBuybackHookRegistry} from "@bananapus/buyback-hook-v6/src/interfaces/IJBBuybackHookRegistry.sol";
41
41
  import {JB721TierConfig} from "@bananapus/721-hook-v6/src/structs/JB721TierConfig.sol";
42
+ import {JB721TierConfigFlags} from "@bananapus/721-hook-v6/src/structs/JB721TierConfigFlags.sol";
42
43
  import {JB721InitTiersConfig} from "@bananapus/721-hook-v6/src/structs/JB721InitTiersConfig.sol";
43
44
  import {IJB721TokenUriResolver} from "@bananapus/721-hook-v6/src/interfaces/IJB721TokenUriResolver.sol";
44
45
  import {REVDeploy721TiersHookConfig} from "../src/structs/REVDeploy721TiersHookConfig.sol";
@@ -211,12 +212,15 @@ contract TestSplitWeightE2E is TestBaseWorkflow {
211
212
  encodedIPFSUri: bytes32("tier1"),
212
213
  category: 1,
213
214
  discountPercent: 0,
214
- allowOwnerMint: false,
215
- useReserveBeneficiaryAsDefault: false,
216
- transfersPausable: false,
217
- useVotingUnits: false,
218
- cannotBeRemoved: false,
219
- cannotIncreaseDiscountPercent: false,
215
+ flags: JB721TierConfigFlags({
216
+ allowOwnerMint: false,
217
+ useReserveBeneficiaryAsDefault: false,
218
+ transfersPausable: false,
219
+ useVotingUnits: false,
220
+ cantBeRemoved: false,
221
+ cantIncreaseDiscountPercent: false,
222
+ cantBuyWithCredits: false
223
+ }),
220
224
  splitPercent: SPLIT_PERCENT,
221
225
  splits: tierSplits
222
226
  });
@@ -39,6 +39,7 @@ import {IJBBuybackHookRegistry} from "@bananapus/buyback-hook-v6/src/interfaces/
39
39
  import {REVBaseline721HookConfig} from "../src/structs/REVBaseline721HookConfig.sol";
40
40
  import {REV721TiersHookFlags} from "../src/structs/REV721TiersHookFlags.sol";
41
41
  import {JB721TierConfig} from "@bananapus/721-hook-v6/src/structs/JB721TierConfig.sol";
42
+ import {JB721TierConfigFlags} from "@bananapus/721-hook-v6/src/structs/JB721TierConfigFlags.sol";
42
43
  import {JB721InitTiersConfig} from "@bananapus/721-hook-v6/src/structs/JB721InitTiersConfig.sol";
43
44
  import {IJB721TokenUriResolver} from "@bananapus/721-hook-v6/src/interfaces/IJB721TokenUriResolver.sol";
44
45
  import {REVDeploy721TiersHookConfig} from "../src/structs/REVDeploy721TiersHookConfig.sol";
@@ -422,12 +423,15 @@ contract TestSplitWeightFork is TestBaseWorkflow {
422
423
  encodedIPFSUri: bytes32("tier1"),
423
424
  category: 1,
424
425
  discountPercent: 0,
425
- allowOwnerMint: false,
426
- useReserveBeneficiaryAsDefault: false,
427
- transfersPausable: false,
428
- useVotingUnits: false,
429
- cannotBeRemoved: false,
430
- cannotIncreaseDiscountPercent: false,
426
+ flags: JB721TierConfigFlags({
427
+ allowOwnerMint: false,
428
+ useReserveBeneficiaryAsDefault: false,
429
+ transfersPausable: false,
430
+ useVotingUnits: false,
431
+ cantBeRemoved: false,
432
+ cantIncreaseDiscountPercent: false,
433
+ cantBuyWithCredits: false
434
+ }),
431
435
  splitPercent: SPLIT_PERCENT,
432
436
  splits: tierSplits
433
437
  });
@@ -41,6 +41,7 @@ import {IJBBuybackHookRegistry} from "@bananapus/buyback-hook-v6/src/interfaces/
41
41
  // forge-lint: disable-next-line(unused-import)
42
42
  import {IJBPayHook} from "@bananapus/core-v6/src/interfaces/IJBPayHook.sol";
43
43
  import {JB721TierConfig} from "@bananapus/721-hook-v6/src/structs/JB721TierConfig.sol";
44
+ import {JB721TierConfigFlags} from "@bananapus/721-hook-v6/src/structs/JB721TierConfigFlags.sol";
44
45
  import {JB721InitTiersConfig} from "@bananapus/721-hook-v6/src/structs/JB721InitTiersConfig.sol";
45
46
  import {IJB721TokenUriResolver} from "@bananapus/721-hook-v6/src/interfaces/IJB721TokenUriResolver.sol";
46
47
  import {REVDeploy721TiersHookConfig} from "../../src/structs/REVDeploy721TiersHookConfig.sol";
@@ -428,12 +429,15 @@ abstract contract ForkTestBase is TestBaseWorkflow {
428
429
  encodedIPFSUri: bytes32("tier1"),
429
430
  category: 1,
430
431
  discountPercent: 0,
431
- allowOwnerMint: false,
432
- useReserveBeneficiaryAsDefault: false,
433
- transfersPausable: false,
434
- useVotingUnits: false,
435
- cannotBeRemoved: false,
436
- cannotIncreaseDiscountPercent: false,
432
+ flags: JB721TierConfigFlags({
433
+ allowOwnerMint: false,
434
+ useReserveBeneficiaryAsDefault: false,
435
+ transfersPausable: false,
436
+ useVotingUnits: false,
437
+ cantBeRemoved: false,
438
+ cantIncreaseDiscountPercent: false,
439
+ cantBuyWithCredits: false
440
+ }),
437
441
  splitPercent: SPLIT_PERCENT,
438
442
  splits: tierSplits
439
443
  });