@rev-net/core-v6 0.0.54 → 0.0.56
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 +14 -1
- package/README.md +2 -2
- package/package.json +7 -7
- package/references/operations.md +8 -8
- package/references/runtime.md +6 -6
- package/script/Deploy.s.sol +5 -5
- package/src/REVDeployer.sol +52 -52
- package/src/interfaces/IREVDeployer.sol +10 -10
- package/src/structs/REVConfig.sol +3 -3
- package/src/structs/REVDeploy721TiersHookConfig.sol +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.0.56 — Bump v6 deps to nana-core-v6 0.0.53 cohort
|
|
4
|
+
|
|
5
|
+
- `@bananapus/core-v6`: `^0.0.48 → ^0.0.53` ([PR #145](https://github.com/Bananapus/nana-core-v6/pull/145)).
|
|
6
|
+
- `@bananapus/721-hook-v6`: `^0.0.47 → ^0.0.50`.
|
|
7
|
+
- `@bananapus/buyback-hook-v6`: `^0.0.39 → ^0.0.46`.
|
|
8
|
+
- `@bananapus/router-terminal-v6`: `^0.0.37 → ^0.0.43`.
|
|
9
|
+
- `@bananapus/suckers-v6`: `^0.0.37 → ^0.0.46`.
|
|
10
|
+
- `@bananapus/permission-ids-v6`: `^0.0.24 → ^0.0.25`.
|
|
11
|
+
- Test updates:
|
|
12
|
+
- `jbMultiTerminal().FEE()` → `JBConstants.FEE` (FEE moved to a compile-time constant in core 0.0.52+).
|
|
13
|
+
- `JBBuybackHook` constructor signature changed in 0.0.45 (V4 PoolManager + Hooks moved to a one-shot setter). Updated `ForkTestBase` and `TestSplitWeightFork` to construct then call `setChainSpecificConstants`.
|
|
14
|
+
- All `JBRulesetMetadata` test literals patched to include `pauseCrossProjectFeeFreeInflows: false`. `REVConfig` and `JBBeforeCashOutRecordedContext` literals are unchanged (no new fields).
|
|
15
|
+
|
|
3
16
|
## Scope
|
|
4
17
|
|
|
5
18
|
This file describes the verified change from `revnet-core-v5` to the current `revnet-core-v6` repo.
|
|
@@ -61,7 +74,7 @@ Integrator impact: omnichain cash-outs that previously reverted with `Inadequate
|
|
|
61
74
|
- `deployWith721sFor(...)` was removed.
|
|
62
75
|
- `deployFor(...)` overloads changed shape and return the deployed 721 hook.
|
|
63
76
|
- `REVConfig` no longer carries `loanSources` or `loans`.
|
|
64
|
-
- `REVDeploy721TiersHookConfig` now uses `REVBaseline721HookConfig` and inverted `
|
|
77
|
+
- `REVDeploy721TiersHookConfig` now uses `REVBaseline721HookConfig` and inverted `preventOperator*` booleans.
|
|
65
78
|
- `IREVOwner` is a new interface that some integrations must track separately from `IREVDeployer`.
|
|
66
79
|
|
|
67
80
|
## Indexer impact
|
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ Use this repo when the product is a treasury-backed network with encoded stage t
|
|
|
28
28
|
|
|
29
29
|
| Contract | Role |
|
|
30
30
|
| --- | --- |
|
|
31
|
-
| `REVDeployer` | Launches and configures Revnets, stages,
|
|
31
|
+
| `REVDeployer` | Launches and configures Revnets, stages, operators, and optional auxiliary features. |
|
|
32
32
|
| `REVOwner` | Runtime data-hook and cash-out-hook surface used by active Revnets. |
|
|
33
33
|
| `REVLoans` | Loan surface that lets users borrow against Revnet tokens with burned collateral and NFT loan positions. |
|
|
34
34
|
## Mental Model
|
|
@@ -50,7 +50,7 @@ Most mistakes come from assuming a deploy-time parameter can be changed later or
|
|
|
50
50
|
## Integration Traps
|
|
51
51
|
|
|
52
52
|
- the deployer holding the project NFT is part of the ownership model, not an implementation detail
|
|
53
|
-
-
|
|
53
|
+
- operators are constrained, not equivalent to general protocol governance
|
|
54
54
|
- the loan system depends on live revnet economics and should be reviewed together with the runtime hook
|
|
55
55
|
- optional integrations like buybacks, 721 hooks, and suckers materially change the resulting network
|
|
56
56
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rev-net/core-v6",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.56",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -26,13 +26,13 @@
|
|
|
26
26
|
"artifacts": "source ./.env && npx sphinx artifacts --org-id 'ea165b21-7cdc-4d7b-be59-ecdd4c26bee4' --project-name 'revnet-core-v6'"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@bananapus/721-hook-v6": "^0.0.
|
|
30
|
-
"@bananapus/buyback-hook-v6": "^0.0.
|
|
31
|
-
"@bananapus/core-v6": "^0.0.
|
|
29
|
+
"@bananapus/721-hook-v6": "^0.0.50",
|
|
30
|
+
"@bananapus/buyback-hook-v6": "^0.0.46",
|
|
31
|
+
"@bananapus/core-v6": "^0.0.53",
|
|
32
32
|
"@bananapus/ownable-v6": "^0.0.24",
|
|
33
|
-
"@bananapus/permission-ids-v6": "^0.0.
|
|
34
|
-
"@bananapus/router-terminal-v6": "^0.0.
|
|
35
|
-
"@bananapus/suckers-v6": "^0.0.
|
|
33
|
+
"@bananapus/permission-ids-v6": "^0.0.25",
|
|
34
|
+
"@bananapus/router-terminal-v6": "^0.0.43",
|
|
35
|
+
"@bananapus/suckers-v6": "^0.0.46",
|
|
36
36
|
"@croptop/core-v6": "^0.0.42",
|
|
37
37
|
"@openzeppelin/contracts": "5.6.1",
|
|
38
38
|
"@uniswap/permit2": "github:Uniswap/permit2#cc56ad0f3439c502c246fc5cfcc3db92bb8b7219"
|
package/references/operations.md
CHANGED
|
@@ -12,7 +12,7 @@ Use this file when you need revnet-specific risks, state reads, constants, or ex
|
|
|
12
12
|
| `BurnHeldTokens(revnetId, count, caller)` | When held tokens are burned from the deployer contract via `burnHeldTokensOf`. |
|
|
13
13
|
| `DeployRevnet(revnetId, configuration, terminalConfigurations, suckerDeploymentConfiguration, rulesetConfigurations, encodedConfigurationHash, caller)` | When a new revnet is deployed via `deployFor`. |
|
|
14
14
|
| `DeploySuckers(revnetId, encodedConfigurationHash, suckerDeploymentConfiguration, caller)` | When suckers are deployed for a revnet via `deploySuckersFor`. |
|
|
15
|
-
| `
|
|
15
|
+
| `ReplaceOperator(revnetId, newOperator, caller)` | When the operator of a revnet is replaced via `setOperatorOf`. |
|
|
16
16
|
| `SetCashOutDelay(revnetId, cashOutDelay, caller)` | When the cash out delay is set for a revnet during deployment to a new chain. |
|
|
17
17
|
| `StoreAutoIssuanceAmount(revnetId, stageId, beneficiary, count, caller)` | When an auto-issuance amount is stored for a beneficiary during deployment. |
|
|
18
18
|
|
|
@@ -42,7 +42,7 @@ Use this file when you need revnet-specific risks, state reads, constants, or ex
|
|
|
42
42
|
| `REVDeployer_StageNotStarted(stageId)` | When `autoIssueFor` is called for a stage that hasn't started yet. |
|
|
43
43
|
| `REVDeployer_StagesRequired()` | When `deployFor` is called with zero stage configurations. |
|
|
44
44
|
| `REVDeployer_StageTimesMustIncrease()` | When stage `startsAtOrAfter` values are not strictly increasing. |
|
|
45
|
-
| `REVDeployer_Unauthorized(revnetId, caller)` | When a non-
|
|
45
|
+
| `REVDeployer_Unauthorized(revnetId, caller)` | When a non-operator calls a operator-only function. |
|
|
46
46
|
|
|
47
47
|
### REVLoans
|
|
48
48
|
|
|
@@ -98,7 +98,7 @@ Use this file when you need revnet-specific risks, state reads, constants, or ex
|
|
|
98
98
|
|---------|-----------|------|---------|
|
|
99
99
|
| `amountToAutoIssue` | `public` | `revnetId => stageId => beneficiary => uint256` | Premint tokens per stage per beneficiary |
|
|
100
100
|
| `hashedEncodedConfigurationOf` | `public` | `revnetId => bytes32` | Config hash for cross-chain sucker validation |
|
|
101
|
-
| `_extraOperatorPermissions` | `internal` | `revnetId => uint256[]` | Custom permissions for
|
|
101
|
+
| `_extraOperatorPermissions` | `internal` | `revnetId => uint256[]` | Custom permissions for operator (no auto-getter) |
|
|
102
102
|
|
|
103
103
|
### REVOwner
|
|
104
104
|
|
|
@@ -131,7 +131,7 @@ Use this file when you need revnet-specific risks, state reads, constants, or ex
|
|
|
131
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
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
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
|
|
134
|
+
10. **Split operator is singular.** Only ONE address can be operator at a time. The operator can replace itself via `setOperatorOf` but cannot delegate or multi-sig.
|
|
135
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
136
|
12. **Loan source array is unbounded.** `_loanSourcesOf[revnetId]` grows without limit. No validation that a terminal is actually registered for the project.
|
|
137
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.
|
|
@@ -141,7 +141,7 @@ Use this file when you need revnet-specific risks, state reads, constants, or ex
|
|
|
141
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
142
|
18. **Permit2 fallback.** `REVLoans` uses permit2 for ERC-20 transfers as a fallback when standard allowance is insufficient. Wrapped in try-catch.
|
|
143
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
|
|
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 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
145
|
21. **REVOwner deployer binding is precomputed.** REVOwner records the account that created it as an internal one-time binder. That account must call `setDeployer(precomputedRevDeployerAddress)` exactly once before the canonical REVDeployer is deployed. This avoids an ambient public initializer while keeping the circular dependency manageable. If `setDeployer(...)` is never called, all DEPLOYER-gated runtime configuration breaks.
|
|
146
146
|
### NATIVE_TOKEN Accounting on Non-ETH Chains
|
|
147
147
|
|
|
@@ -177,11 +177,11 @@ Quick-reference for common read operations. All functions are `view`/`pure` and
|
|
|
177
177
|
| All queued rulesets | `IJBController(CONTROLLER).allRulesetsOf(revnetId, startingId, size)` | `JBRulesetWithMetadata[]` -- paginated list of stages |
|
|
178
178
|
| Specific stage by ID | `IJBController(CONTROLLER).getRulesetOf(revnetId, stageId)` | `(JBRuleset, JBRulesetMetadata)` for that stage |
|
|
179
179
|
|
|
180
|
-
###
|
|
180
|
+
### Operator
|
|
181
181
|
|
|
182
182
|
| What | Call | Returns |
|
|
183
183
|
|------|------|---------|
|
|
184
|
-
| Check if address is
|
|
184
|
+
| Check if address is operator | `REVDeployer.isOperatorOf(revnetId, addr)` | `bool` |
|
|
185
185
|
|
|
186
186
|
### Token Supply & Surplus
|
|
187
187
|
|
|
@@ -257,7 +257,7 @@ REVConfig memory config = REVConfig({
|
|
|
257
257
|
salt: bytes32(0)
|
|
258
258
|
}),
|
|
259
259
|
baseCurrency: 1, // ETH
|
|
260
|
-
|
|
260
|
+
operator: msg.sender,
|
|
261
261
|
scopeCashOutsToLocalBalances: false,
|
|
262
262
|
stageConfigurations: stages
|
|
263
263
|
});
|
package/references/runtime.md
CHANGED
|
@@ -10,7 +10,7 @@ Deploy and manage Revnets -- autonomous, unowned Juicebox projects with staged i
|
|
|
10
10
|
|
|
11
11
|
| Contract | Role |
|
|
12
12
|
|----------|------|
|
|
13
|
-
| `REVDeployer` | Deploys revnets, permanently owns the project NFT. Manages stages, splits, auto-issuance, buyback hooks, suckers,
|
|
13
|
+
| `REVDeployer` | Deploys revnets, permanently owns the project NFT. Manages stages, splits, auto-issuance, buyback hooks, suckers, 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
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
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
16
|
|
|
@@ -20,7 +20,7 @@ Deploy and manage Revnets -- autonomous, unowned Juicebox projects with staged i
|
|
|
20
20
|
|
|
21
21
|
| Function | Permissions | What it does |
|
|
22
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
|
|
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 operator, suckers, loans permissions, and deploys a default empty tiered ERC-721 hook. |
|
|
24
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
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
26
|
|
|
@@ -34,11 +34,11 @@ Deploy and manage Revnets -- autonomous, unowned Juicebox projects with staged i
|
|
|
34
34
|
| `REVOwner.hasMintPermissionFor(revnetId, ruleset, addr)` | View | Returns `true` for: loans contract, buyback hook, buyback hook delegates, or suckers. |
|
|
35
35
|
| `REVOwner.cashOutDelayOf(revnetId)` | View | Returns the cash-out delay timestamp from REVOwner storage. Exposed for REVLoans compatibility (REVLoans imports IREVOwner for this). |
|
|
36
36
|
|
|
37
|
-
###
|
|
37
|
+
### Operator
|
|
38
38
|
|
|
39
39
|
| Function | Permissions | What it does |
|
|
40
40
|
|----------|------------|-------------|
|
|
41
|
-
| `REVDeployer.
|
|
41
|
+
| `REVDeployer.setOperatorOf(revnetId, newOperator)` | Split operator | Replace the current operator. Revokes old permissions, grants new ones. |
|
|
42
42
|
|
|
43
43
|
### Auto-Issuance
|
|
44
44
|
|
|
@@ -84,13 +84,13 @@ Deploy and manage Revnets -- autonomous, unowned Juicebox projects with staged i
|
|
|
84
84
|
|
|
85
85
|
| Struct | Key Fields | Used In |
|
|
86
86
|
|--------|------------|---------|
|
|
87
|
-
| `REVConfig` | `description` (REVDescription), `baseCurrency`, `
|
|
87
|
+
| `REVConfig` | `description` (REVDescription), `baseCurrency`, `operator`, `stageConfigurations[]` | `deployFor` |
|
|
88
88
|
| `REVStageConfig` | `startsAtOrAfter` (uint48), `initialIssuance` (uint112), `issuanceCutFrequency` (uint32), `issuanceCutPercent` (uint32), `cashOutTaxRate` (uint16), `splitPercent` (uint16), `splits[]`, `autoIssuances[]`, `extraMetadata` (uint16) | Translated into `JBRulesetConfig` |
|
|
89
89
|
| `REVDescription` | `name`, `ticker`, `uri`, `salt` | ERC-20 token deployment and project metadata |
|
|
90
90
|
| `REVAutoIssuance` | `chainId` (uint32), `count` (uint104), `beneficiary` | Per-stage cross-chain token auto-minting |
|
|
91
91
|
| `REVLoan` | `amount` (uint112), `collateral` (uint112), `createdAt` (uint48), `prepaidFeePercent` (uint16), `prepaidDuration` (uint32), `source` (REVLoanSource) | Per-loan state in `REVLoans` |
|
|
92
92
|
| `REVLoanSource` | `token`, `terminal` (IJBPayoutTerminal) | Identifies which terminal and token a loan draws from |
|
|
93
|
-
| `REVDeploy721TiersHookConfig` | `baseline721HookConfiguration` (REVBaseline721HookConfig), `salt`, `
|
|
93
|
+
| `REVDeploy721TiersHookConfig` | `baseline721HookConfiguration` (REVBaseline721HookConfig), `salt`, `preventOperatorAdjustingTiers`, `preventOperatorUpdatingMetadata`, `preventOperatorMinting`, `preventOperatorIncreasingDiscountPercent` | 721 hook deployment with operator permissions (preventive flags — `false` = allowed). Uses `REVBaseline721HookConfig` (not `JBDeploy721TiersHookConfig`) to omit `issueTokensForSplits` — revnets always force it to `false`. |
|
|
94
94
|
| `REVBaseline721HookConfig` | `name`, `symbol`, `baseUri`, `tokenUriResolver`, `contractUri`, `tiersConfig`, `reserveBeneficiary`, `flags` (REV721TiersHookFlags) | Same as `JBDeploy721TiersHookConfig` but uses `REV721TiersHookFlags` which omits `issueTokensForSplits`. |
|
|
95
95
|
| `REV721TiersHookFlags` | `noNewTiersWithReserves`, `noNewTiersWithVotes`, `noNewTiersWithOwnerMinting`, `preventOverspending` | Same as `JB721TiersHookFlags` minus `issueTokensForSplits`. Revnets do their own weight adjustment for splits. |
|
|
96
96
|
| `REVCroptopAllowedPost` | `category` (uint24), `minimumPrice` (uint104), `minimumTotalSupply` (uint32), `maximumTotalSupply` (uint32), `allowedAddresses[]` | Croptop posting criteria |
|
package/script/Deploy.s.sol
CHANGED
|
@@ -267,7 +267,7 @@ contract DeployScript is Script, Sphinx {
|
|
|
267
267
|
REVConfig memory revnetConfiguration = REVConfig({
|
|
268
268
|
description: REVDescription({name: NAME, ticker: SYMBOL, uri: PROJECT_URI, salt: ERC20_SALT}),
|
|
269
269
|
baseCurrency: ETH_CURRENCY,
|
|
270
|
-
|
|
270
|
+
operator: OPERATOR,
|
|
271
271
|
scopeCashOutsToLocalBalances: false,
|
|
272
272
|
stageConfigurations: stageConfigurations
|
|
273
273
|
});
|
|
@@ -339,10 +339,10 @@ contract DeployScript is Script, Sphinx {
|
|
|
339
339
|
})
|
|
340
340
|
}),
|
|
341
341
|
salt: bytes32(0),
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
342
|
+
preventOperatorAdjustingTiers: false,
|
|
343
|
+
preventOperatorUpdatingMetadata: false,
|
|
344
|
+
preventOperatorMinting: false,
|
|
345
|
+
preventOperatorIncreasingDiscountPercent: false
|
|
346
346
|
}),
|
|
347
347
|
allowedPosts: new REVCroptopAllowedPost[](0)
|
|
348
348
|
});
|
package/src/REVDeployer.sol
CHANGED
|
@@ -161,7 +161,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
161
161
|
// ------------------- internal stored properties -------------------- //
|
|
162
162
|
//*********************************************************************//
|
|
163
163
|
|
|
164
|
-
/// @notice A list of `JBPermissonIds` indices to grant to the
|
|
164
|
+
/// @notice A list of `JBPermissonIds` indices to grant to the operator of a specific revnet.
|
|
165
165
|
/// @dev These should be set in the revnet's deployment process.
|
|
166
166
|
/// @custom:param revnetId The ID of the revnet to look up.
|
|
167
167
|
mapping(uint256 revnetId => uint256[]) internal _extraOperatorPermissions;
|
|
@@ -229,16 +229,16 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
229
229
|
// -------------------------- public views --------------------------- //
|
|
230
230
|
//*********************************************************************//
|
|
231
231
|
|
|
232
|
-
/// @notice Check whether an address is a revnet's
|
|
232
|
+
/// @notice Check whether an address is a revnet's operator.
|
|
233
233
|
/// @param revnetId The ID of the revnet to check.
|
|
234
234
|
/// @param addr The address to check.
|
|
235
|
-
/// @return flag A flag indicating whether the address is the revnet's
|
|
236
|
-
function
|
|
235
|
+
/// @return flag A flag indicating whether the address is the revnet's operator.
|
|
236
|
+
function isOperatorOf(uint256 revnetId, address addr) public view override returns (bool) {
|
|
237
237
|
return PERMISSIONS.hasPermissions({
|
|
238
238
|
operator: addr,
|
|
239
239
|
account: address(this),
|
|
240
240
|
projectId: revnetId,
|
|
241
|
-
permissionIds:
|
|
241
|
+
permissionIds: _operatorPermissionIndexesOf(revnetId),
|
|
242
242
|
includeRoot: false,
|
|
243
243
|
includeWildcardProjectId: false
|
|
244
244
|
});
|
|
@@ -255,11 +255,11 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
255
255
|
// -------------------------- internal views ------------------------- //
|
|
256
256
|
//*********************************************************************//
|
|
257
257
|
|
|
258
|
-
/// @notice If the specified address is not the revnet's current
|
|
258
|
+
/// @notice If the specified address is not the revnet's current operator, revert.
|
|
259
259
|
/// @param revnetId The ID of the revnet to check.
|
|
260
260
|
/// @param operator The address to check.
|
|
261
|
-
function
|
|
262
|
-
if (!
|
|
261
|
+
function _checkIfIsOperatorOf(uint256 revnetId, address operator) internal view {
|
|
262
|
+
if (!isOperatorOf({revnetId: revnetId, addr: operator})) {
|
|
263
263
|
revert REVDeployer_Unauthorized({revnetId: revnetId, caller: operator});
|
|
264
264
|
}
|
|
265
265
|
}
|
|
@@ -359,20 +359,20 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
359
359
|
});
|
|
360
360
|
}
|
|
361
361
|
|
|
362
|
-
/// @notice Returns the permissions that the
|
|
362
|
+
/// @notice Returns the permissions that the operator should have for a revnet.
|
|
363
363
|
/// @param revnetId The ID of the revnet to look up.
|
|
364
|
-
/// @return allOperatorPermissions The permissions the
|
|
364
|
+
/// @return allOperatorPermissions The permissions the operator should have for the revnet,
|
|
365
365
|
/// including both default and custom permissions.
|
|
366
|
-
function
|
|
366
|
+
function _operatorPermissionIndexesOf(uint256 revnetId)
|
|
367
367
|
internal
|
|
368
368
|
view
|
|
369
369
|
returns (uint256[] memory allOperatorPermissions)
|
|
370
370
|
{
|
|
371
|
-
// Keep a reference to the custom
|
|
372
|
-
uint256[] memory
|
|
371
|
+
// Keep a reference to the custom operator permissions.
|
|
372
|
+
uint256[] memory customOperatorPermissionIndexes = _extraOperatorPermissions[revnetId];
|
|
373
373
|
|
|
374
374
|
// Make the array that merges the default and custom operator permissions.
|
|
375
|
-
allOperatorPermissions = new uint256[](9 +
|
|
375
|
+
allOperatorPermissions = new uint256[](9 + customOperatorPermissionIndexes.length);
|
|
376
376
|
allOperatorPermissions[0] = JBPermissionIds.SET_SPLIT_GROUPS;
|
|
377
377
|
allOperatorPermissions[1] = JBPermissionIds.SET_BUYBACK_POOL;
|
|
378
378
|
allOperatorPermissions[2] = JBPermissionIds.SET_BUYBACK_TWAP;
|
|
@@ -384,8 +384,8 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
384
384
|
allOperatorPermissions[8] = JBPermissionIds.SIGN_FOR_ERC20;
|
|
385
385
|
|
|
386
386
|
// Copy the custom permissions into the array.
|
|
387
|
-
for (uint256 i; i <
|
|
388
|
-
allOperatorPermissions[9 + i] =
|
|
387
|
+
for (uint256 i; i < customOperatorPermissionIndexes.length;) {
|
|
388
|
+
allOperatorPermissions[9 + i] = customOperatorPermissionIndexes[i];
|
|
389
389
|
unchecked {
|
|
390
390
|
++i;
|
|
391
391
|
}
|
|
@@ -595,22 +595,22 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
595
595
|
// Store the tiered ERC-721 hook in the owner contract.
|
|
596
596
|
REVOwner(OWNER).setTiered721HookOf({revnetId: revnetId, hook: hook});
|
|
597
597
|
|
|
598
|
-
// Grant the
|
|
599
|
-
// These permission IDs are only consumed by `
|
|
598
|
+
// Grant the operator all 721 permissions (no prevent* flags for default config).
|
|
599
|
+
// These permission IDs are only consumed by `_setOperatorOf` below, after revnet setup has either
|
|
600
600
|
// completed or reverted atomically.
|
|
601
601
|
_extraOperatorPermissions[revnetId].push(JBPermissionIds.ADJUST_721_TIERS);
|
|
602
602
|
_extraOperatorPermissions[revnetId].push(JBPermissionIds.SET_721_METADATA);
|
|
603
603
|
_extraOperatorPermissions[revnetId].push(JBPermissionIds.MINT_721);
|
|
604
604
|
_extraOperatorPermissions[revnetId].push(JBPermissionIds.SET_721_DISCOUNT_PERCENT);
|
|
605
605
|
|
|
606
|
-
// Give the
|
|
607
|
-
|
|
606
|
+
// Give the operator their permissions (base + 721 extras).
|
|
607
|
+
_setOperatorOf({revnetId: revnetId, operator: configuration.operator});
|
|
608
608
|
|
|
609
609
|
return (revnetId, hook);
|
|
610
610
|
}
|
|
611
611
|
|
|
612
612
|
/// @notice Deploy new suckers for an existing revnet.
|
|
613
|
-
/// @dev Only the revnet's
|
|
613
|
+
/// @dev Only the revnet's operator can deploy new suckers.
|
|
614
614
|
/// @param revnetId The ID of the revnet to deploy suckers for.
|
|
615
615
|
/// @param suckerDeploymentConfiguration The suckers to set up for the revnet.
|
|
616
616
|
function deploySuckersFor(
|
|
@@ -621,8 +621,8 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
621
621
|
override
|
|
622
622
|
returns (address[] memory suckers)
|
|
623
623
|
{
|
|
624
|
-
// Make sure the caller is the revnet's
|
|
625
|
-
|
|
624
|
+
// Make sure the caller is the revnet's operator.
|
|
625
|
+
_checkIfIsOperatorOf({revnetId: revnetId, operator: _msgSender()});
|
|
626
626
|
|
|
627
627
|
// Check if the current ruleset allows deploying new suckers.
|
|
628
628
|
(, JBRulesetMetadata memory metadata) = CONTROLLER.currentRulesetOf(revnetId);
|
|
@@ -642,25 +642,25 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
642
642
|
});
|
|
643
643
|
}
|
|
644
644
|
|
|
645
|
-
/// @notice Change a revnet's
|
|
646
|
-
/// @dev Only a revnet's current
|
|
647
|
-
/// @dev Passing `address(0)` as `
|
|
645
|
+
/// @notice Change a revnet's operator.
|
|
646
|
+
/// @dev Only a revnet's current operator can set a new operator.
|
|
647
|
+
/// @dev Passing `address(0)` as `newOperator` relinquishes operator powers permanently — the permissions
|
|
648
648
|
/// are granted to the zero address (which cannot execute transactions), effectively burning them.
|
|
649
|
-
/// @param revnetId The ID of the revnet to change the
|
|
650
|
-
/// @param
|
|
651
|
-
function
|
|
649
|
+
/// @param revnetId The ID of the revnet to change the operator for.
|
|
650
|
+
/// @param newOperator The new operator's address. Use `address(0)` to relinquish operator powers.
|
|
651
|
+
function setOperatorOf(uint256 revnetId, address newOperator) external override {
|
|
652
652
|
// Enforce permissions.
|
|
653
|
-
|
|
653
|
+
_checkIfIsOperatorOf({revnetId: revnetId, operator: _msgSender()});
|
|
654
654
|
|
|
655
|
-
emit
|
|
655
|
+
emit ReplaceOperator({revnetId: revnetId, newOperator: newOperator, caller: _msgSender()});
|
|
656
656
|
|
|
657
|
-
// Remove operator permissions from the old
|
|
657
|
+
// Remove operator permissions from the old operator.
|
|
658
658
|
_setPermissionsFor({
|
|
659
659
|
account: address(this), operator: _msgSender(), revnetId: revnetId, permissionIds: new uint8[](0)
|
|
660
660
|
});
|
|
661
661
|
|
|
662
|
-
// Set the new
|
|
663
|
-
|
|
662
|
+
// Set the new operator.
|
|
663
|
+
_setOperatorOf({revnetId: revnetId, operator: newOperator});
|
|
664
664
|
}
|
|
665
665
|
|
|
666
666
|
//*********************************************************************//
|
|
@@ -719,32 +719,32 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
719
719
|
// Store the tiered ERC-721 hook in the owner contract.
|
|
720
720
|
REVOwner(OWNER).setTiered721HookOf({revnetId: revnetId, hook: hook});
|
|
721
721
|
|
|
722
|
-
// These permission IDs are only consumed by `
|
|
722
|
+
// These permission IDs are only consumed by `_setOperatorOf` below, after revnet setup has either
|
|
723
723
|
// completed or reverted atomically.
|
|
724
724
|
|
|
725
|
-
// Give the
|
|
726
|
-
if (!tiered721HookConfiguration.
|
|
725
|
+
// Give the operator permission to add and remove tiers unless prevented.
|
|
726
|
+
if (!tiered721HookConfiguration.preventOperatorAdjustingTiers) {
|
|
727
727
|
_extraOperatorPermissions[revnetId].push(JBPermissionIds.ADJUST_721_TIERS);
|
|
728
728
|
}
|
|
729
729
|
|
|
730
|
-
// Give the
|
|
731
|
-
if (!tiered721HookConfiguration.
|
|
730
|
+
// Give the operator permission to set ERC-721 tier metadata unless prevented.
|
|
731
|
+
if (!tiered721HookConfiguration.preventOperatorUpdatingMetadata) {
|
|
732
732
|
_extraOperatorPermissions[revnetId].push(JBPermissionIds.SET_721_METADATA);
|
|
733
733
|
}
|
|
734
734
|
|
|
735
|
-
// Give the
|
|
735
|
+
// Give the operator permission to mint ERC-721s (without a payment)
|
|
736
736
|
// from tiers with `allowOwnerMint` set to true, unless prevented.
|
|
737
|
-
if (!tiered721HookConfiguration.
|
|
737
|
+
if (!tiered721HookConfiguration.preventOperatorMinting) {
|
|
738
738
|
_extraOperatorPermissions[revnetId].push(JBPermissionIds.MINT_721);
|
|
739
739
|
}
|
|
740
740
|
|
|
741
|
-
// Give the
|
|
742
|
-
if (!tiered721HookConfiguration.
|
|
741
|
+
// Give the operator permission to increase the discount of a tier unless prevented.
|
|
742
|
+
if (!tiered721HookConfiguration.preventOperatorIncreasingDiscountPercent) {
|
|
743
743
|
_extraOperatorPermissions[revnetId].push(JBPermissionIds.SET_721_DISCOUNT_PERCENT);
|
|
744
744
|
}
|
|
745
745
|
|
|
746
|
-
// Give the
|
|
747
|
-
|
|
746
|
+
// Give the operator their permissions (base + 721 extras).
|
|
747
|
+
_setOperatorOf({revnetId: revnetId, operator: configuration.operator});
|
|
748
748
|
|
|
749
749
|
// If there are posts to allow, configure them.
|
|
750
750
|
if (allowedPosts.length != 0) {
|
|
@@ -1136,13 +1136,13 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
1136
1136
|
PERMISSIONS.setPermissionsFor({account: account, permissionsData: permissionData});
|
|
1137
1137
|
}
|
|
1138
1138
|
|
|
1139
|
-
/// @notice Give a
|
|
1140
|
-
/// @dev Only a revnet's current
|
|
1141
|
-
/// @param revnetId The ID of the revnet to grant
|
|
1142
|
-
/// @param operator The new
|
|
1143
|
-
function
|
|
1144
|
-
// Get the permission indexes for the
|
|
1145
|
-
uint256[] memory permissionIndexes =
|
|
1139
|
+
/// @notice Give a operator their permissions.
|
|
1140
|
+
/// @dev Only a revnet's current operator can set a new operator, by calling `setOperatorOf(…)`.
|
|
1141
|
+
/// @param revnetId The ID of the revnet to grant operator permissions for.
|
|
1142
|
+
/// @param operator The new operator's address.
|
|
1143
|
+
function _setOperatorOf(uint256 revnetId, address operator) internal {
|
|
1144
|
+
// Get the permission indexes for the operator.
|
|
1145
|
+
uint256[] memory permissionIndexes = _operatorPermissionIndexesOf(revnetId);
|
|
1146
1146
|
uint8[] memory permissionIds = new uint8[](permissionIndexes.length);
|
|
1147
1147
|
|
|
1148
1148
|
for (uint256 i; i < permissionIndexes.length;) {
|
|
@@ -66,11 +66,11 @@ interface IREVDeployer {
|
|
|
66
66
|
address caller
|
|
67
67
|
);
|
|
68
68
|
|
|
69
|
-
/// @notice Emitted when the
|
|
69
|
+
/// @notice Emitted when the operator of a revnet is replaced.
|
|
70
70
|
/// @param revnetId The ID of the revnet.
|
|
71
|
-
/// @param
|
|
72
|
-
/// @param caller The address that replaced the
|
|
73
|
-
event
|
|
71
|
+
/// @param newOperator The address of the new operator.
|
|
72
|
+
/// @param caller The address that replaced the operator.
|
|
73
|
+
event ReplaceOperator(uint256 indexed revnetId, address indexed newOperator, address caller);
|
|
74
74
|
|
|
75
75
|
/// @notice Emitted when the cash out delay is set for a revnet.
|
|
76
76
|
/// @param revnetId The ID of the revnet.
|
|
@@ -136,11 +136,11 @@ interface IREVDeployer {
|
|
|
136
136
|
/// @return The hook deployer contract.
|
|
137
137
|
function HOOK_DEPLOYER() external view returns (IJB721TiersHookDeployer);
|
|
138
138
|
|
|
139
|
-
/// @notice Check whether an address is a revnet's
|
|
139
|
+
/// @notice Check whether an address is a revnet's operator.
|
|
140
140
|
/// @param revnetId The ID of the revnet to check.
|
|
141
141
|
/// @param addr The address to check.
|
|
142
|
-
/// @return A flag indicating whether the address is the revnet's
|
|
143
|
-
function
|
|
142
|
+
/// @return A flag indicating whether the address is the revnet's operator.
|
|
143
|
+
function isOperatorOf(uint256 revnetId, address addr) external view returns (bool);
|
|
144
144
|
|
|
145
145
|
/// @notice The loan contract used by all revnets.
|
|
146
146
|
/// @return The loans contract address.
|
|
@@ -225,8 +225,8 @@ interface IREVDeployer {
|
|
|
225
225
|
external
|
|
226
226
|
returns (address[] memory suckers);
|
|
227
227
|
|
|
228
|
-
/// @notice Change a revnet's
|
|
228
|
+
/// @notice Change a revnet's operator. Only the current operator can call this.
|
|
229
229
|
/// @param revnetId The ID of the revnet.
|
|
230
|
-
/// @param
|
|
231
|
-
function
|
|
230
|
+
/// @param newOperator The new operator's address.
|
|
231
|
+
function setOperatorOf(uint256 revnetId, address newOperator) external;
|
|
232
232
|
}
|
|
@@ -5,11 +5,11 @@ import {REVDescription} from "./REVDescription.sol";
|
|
|
5
5
|
import {REVStageConfig} from "./REVStageConfig.sol";
|
|
6
6
|
|
|
7
7
|
/// @notice Top-level configuration for deploying a revnet. Defines the revnet's identity, base currency for issuance
|
|
8
|
-
/// pricing, the
|
|
8
|
+
/// pricing, the operator (who receives production splits and can reassign that role), and the ordered list of
|
|
9
9
|
/// stages that govern the revnet's lifecycle.
|
|
10
10
|
/// @custom:member description The revnet's name, ticker, metadata URI, and deployment salt.
|
|
11
11
|
/// @custom:member baseCurrency The currency that issuance pricing is denominated in (e.g. ETH or USD).
|
|
12
|
-
/// @custom:member
|
|
12
|
+
/// @custom:member operator The address that receives production splits and can reassign the operator role.
|
|
13
13
|
/// Only the current operator can replace itself after deployment.
|
|
14
14
|
/// @custom:member scopeCashOutsToLocalBalances If true, cash-out calculations use only the local terminal's surplus.
|
|
15
15
|
/// When false, the bonding curve considers surplus from every terminal across all chains.
|
|
@@ -17,7 +17,7 @@ import {REVStageConfig} from "./REVStageConfig.sol";
|
|
|
17
17
|
struct REVConfig {
|
|
18
18
|
REVDescription description;
|
|
19
19
|
uint32 baseCurrency;
|
|
20
|
-
address
|
|
20
|
+
address operator;
|
|
21
21
|
bool scopeCashOutsToLocalBalances;
|
|
22
22
|
REVStageConfig[] stageConfigurations;
|
|
23
23
|
}
|
|
@@ -5,19 +5,19 @@ import {REVBaseline721HookConfig} from "./REVBaseline721HookConfig.sol";
|
|
|
5
5
|
|
|
6
6
|
/// @custom:member baseline721HookConfiguration The baseline 721 hook config.
|
|
7
7
|
/// @custom:member salt The salt to derive the collection's address from.
|
|
8
|
-
/// @custom:member
|
|
8
|
+
/// @custom:member preventOperatorAdjustingTiers Whether to prevent the operator from adding and removing
|
|
9
9
|
/// tiers.
|
|
10
|
-
/// @custom:member
|
|
10
|
+
/// @custom:member preventOperatorUpdatingMetadata Whether to prevent the operator from updating the 721's
|
|
11
11
|
/// metadata.
|
|
12
|
-
/// @custom:member
|
|
12
|
+
/// @custom:member preventOperatorMinting Whether to prevent the operator from minting 721s from tiers that
|
|
13
13
|
/// allow it.
|
|
14
|
-
/// @custom:member
|
|
14
|
+
/// @custom:member preventOperatorIncreasingDiscountPercent Whether to prevent the operator from increasing
|
|
15
15
|
/// the discount of a tier.
|
|
16
16
|
struct REVDeploy721TiersHookConfig {
|
|
17
17
|
REVBaseline721HookConfig baseline721HookConfiguration;
|
|
18
18
|
bytes32 salt;
|
|
19
|
-
bool
|
|
20
|
-
bool
|
|
21
|
-
bool
|
|
22
|
-
bool
|
|
19
|
+
bool preventOperatorAdjustingTiers;
|
|
20
|
+
bool preventOperatorUpdatingMetadata;
|
|
21
|
+
bool preventOperatorMinting;
|
|
22
|
+
bool preventOperatorIncreasingDiscountPercent;
|
|
23
23
|
}
|