@rev-net/core-v6 0.0.58 → 0.0.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +10 -10
- package/references/operations.md +8 -8
- package/references/runtime.md +2 -3
- package/script/Deploy.s.sol +23 -20
- package/src/REVDeployer.sol +80 -74
- package/src/REVLoans.sol +197 -189
- package/src/REVOwner.sol +56 -46
- package/src/interfaces/IREVDeployer.sol +14 -4
- package/src/interfaces/IREVLoans.sol +24 -30
- package/src/interfaces/IREVOwner.sol +4 -0
- package/src/libraries/REVLoansSourceFees.sol +57 -0
- package/src/structs/REVLoan.sol +2 -4
- package/src/structs/REVLoanSource.sol +0 -11
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.61",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -26,19 +26,19 @@
|
|
|
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.
|
|
32
|
-
"@bananapus/ownable-v6": "^0.0.
|
|
33
|
-
"@bananapus/permission-ids-v6": "^0.0.
|
|
34
|
-
"@bananapus/router-terminal-v6": "^0.0.
|
|
35
|
-
"@bananapus/suckers-v6": "^0.0.
|
|
36
|
-
"@croptop/core-v6": "^0.0.
|
|
29
|
+
"@bananapus/721-hook-v6": "^0.0.54",
|
|
30
|
+
"@bananapus/buyback-hook-v6": "^0.0.49",
|
|
31
|
+
"@bananapus/core-v6": "^0.0.57",
|
|
32
|
+
"@bananapus/ownable-v6": "^0.0.27",
|
|
33
|
+
"@bananapus/permission-ids-v6": "^0.0.26",
|
|
34
|
+
"@bananapus/router-terminal-v6": "^0.0.46",
|
|
35
|
+
"@bananapus/suckers-v6": "^0.0.49",
|
|
36
|
+
"@croptop/core-v6": "^0.0.52",
|
|
37
37
|
"@openzeppelin/contracts": "5.6.1",
|
|
38
38
|
"@uniswap/permit2": "github:Uniswap/permit2#cc56ad0f3439c502c246fc5cfcc3db92bb8b7219"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@bananapus/address-registry-v6": "0.0.
|
|
41
|
+
"@bananapus/address-registry-v6": "0.0.26",
|
|
42
42
|
"@sphinx-labs/plugins": "0.33.3",
|
|
43
43
|
"@uniswap/v4-core": "1.0.2"
|
|
44
44
|
}
|
package/references/operations.md
CHANGED
|
@@ -112,12 +112,12 @@ Use this file when you need revnet-specific risks, state reads, constants, or ex
|
|
|
112
112
|
|
|
113
113
|
| Mapping | Visibility | Type | Purpose |
|
|
114
114
|
|---------|-----------|------|---------|
|
|
115
|
-
| `isLoanSourceOf` | `public` | `revnetId =>
|
|
115
|
+
| `isLoanSourceOf` | `public` | `revnetId => token => bool` | Is this token used for loans? |
|
|
116
116
|
| `totalLoansBorrowedFor` | `public` | `revnetId => uint256` | Counter for loan numbering |
|
|
117
|
-
| `totalBorrowedFrom` | `public` | `revnetId =>
|
|
117
|
+
| `totalBorrowedFrom` | `public` | `revnetId => token => uint256` | Tracks debt per loan source token |
|
|
118
118
|
| `totalCollateralOf` | `public` | `revnetId => uint256` | Sum of all burned collateral |
|
|
119
119
|
| `_loanOf` | `internal` | `loanId => REVLoan` | Per-loan state (use `loanOf(loanId)` view) |
|
|
120
|
-
| `
|
|
120
|
+
| `_loanSourceTokensOf` | `internal` | `revnetId => address[]` | Array of all loan source tokens used (use `loanSourceTokensOf(revnetId)` view) |
|
|
121
121
|
| `tokenUriResolver` | `public` | `IJBTokenUriResolver` | Resolver for loan NFT token URIs |
|
|
122
122
|
|
|
123
123
|
## Gotchas
|
|
@@ -133,7 +133,7 @@ Use this file when you need revnet-specific risks, state reads, constants, or ex
|
|
|
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
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
|
-
12. **Loan source array is unbounded.** `
|
|
136
|
+
12. **Loan source array is unbounded.** `_loanSourceTokensOf[revnetId]` grows without limit, bounded in practice by the token accounting contexts accepted by the canonical `MULTI_TERMINAL`.
|
|
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.
|
|
138
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
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.
|
|
@@ -202,10 +202,10 @@ Quick-reference for common read operations. All functions are `view`/`pure` and
|
|
|
202
202
|
| What | Call | Returns |
|
|
203
203
|
|------|------|---------|
|
|
204
204
|
| Borrowable amount for collateral | `REVLoans.borrowableAmountFrom(revnetId, collateralCount, decimals, currency)` | `uint256` |
|
|
205
|
-
| Total borrowed (per source) | `REVLoans.totalBorrowedFrom(revnetId,
|
|
205
|
+
| Total borrowed (per source token) | `REVLoans.totalBorrowedFrom(revnetId, token)` | `uint256` |
|
|
206
206
|
| Total collateral locked | `REVLoans.totalCollateralOf(revnetId)` | `uint256` |
|
|
207
207
|
| Loan details | `REVLoans.loanOf(loanId)` | `REVLoan` struct |
|
|
208
|
-
| All loan
|
|
208
|
+
| All loan source tokens | `REVLoans.loanSourceTokensOf(revnetId)` | `address[]` |
|
|
209
209
|
| Loan count | `REVLoans.totalLoansBorrowedFor(revnetId)` | `uint256` |
|
|
210
210
|
| Source fee for repayment | `REVLoans.determineSourceFeeAmount(loan, amount)` | `uint256` |
|
|
211
211
|
| Revnet ID from loan ID | `REVLoans.revnetIdOfLoanWith(loanId)` | `uint256` (pure) |
|
|
@@ -276,7 +276,7 @@ deployer.deployFor({
|
|
|
276
276
|
|
|
277
277
|
loans.borrowFrom({
|
|
278
278
|
revnetId: revnetId,
|
|
279
|
-
|
|
279
|
+
token: JBConstants.NATIVE_TOKEN,
|
|
280
280
|
minBorrowAmount: 0,
|
|
281
281
|
collateralCount: 1000e18, // Burn 1000 tokens as collateral
|
|
282
282
|
beneficiary: msg.sender, // Receive borrowed funds
|
|
@@ -290,7 +290,7 @@ loans.borrowFrom({
|
|
|
290
290
|
(uint256 reallocatedLoanId, uint256 newLoanId, , ) = loans.reallocateCollateralFromLoan({
|
|
291
291
|
loanId: loanId,
|
|
292
292
|
collateralCountToTransfer: 500e18, // Move 500 tokens out of existing loan
|
|
293
|
-
|
|
293
|
+
token: JBConstants.NATIVE_TOKEN,
|
|
294
294
|
minBorrowAmount: 0,
|
|
295
295
|
collateralCountToAdd: 200e18, // Add 200 fresh tokens on top
|
|
296
296
|
beneficiary: payable(msg.sender), // Receive new loan proceeds
|
package/references/runtime.md
CHANGED
|
@@ -64,7 +64,7 @@ Deploy and manage Revnets -- autonomous, unowned Juicebox projects with staged i
|
|
|
64
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
65
|
| `REVLoans.determineSourceFeeAmount(loan, amount)` | Calculate the time-proportional source fee for a loan repayment. Zero during prepaid window, linear accrual after. |
|
|
66
66
|
| `REVLoans.loanOf(loanId)` | Returns the full `REVLoan` struct for a loan. |
|
|
67
|
-
| `REVLoans.
|
|
67
|
+
| `REVLoans.loanSourceTokensOf(revnetId)` | Returns all token sources used for loans by a revnet. Loans always source funds from the canonical `MULTI_TERMINAL`. |
|
|
68
68
|
| `REVLoans.revnetIdOfLoanWith(loanId)` | Decode the revnet ID from a loan ID (`loanId / 1_000_000_000_000`). |
|
|
69
69
|
## Integration Points
|
|
70
70
|
|
|
@@ -88,8 +88,7 @@ Deploy and manage Revnets -- autonomous, unowned Juicebox projects with staged i
|
|
|
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
|
-
| `REVLoan` | `amount` (uint112), `collateral` (uint112), `createdAt` (uint48), `prepaidFeePercent` (uint16), `prepaidDuration` (uint32), `
|
|
92
|
-
| `REVLoanSource` | `token`, `terminal` (IJBPayoutTerminal) | Identifies which terminal and token a loan draws from |
|
|
91
|
+
| `REVLoan` | `amount` (uint112), `collateral` (uint112), `createdAt` (uint48), `prepaidFeePercent` (uint16), `prepaidDuration` (uint32), `sourceToken` (address) | Per-loan state in `REVLoans` |
|
|
93
92
|
| `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
93
|
| `REVBaseline721HookConfig` | `name`, `symbol`, `baseUri`, `tokenUriResolver`, `contractUri`, `tiersConfig`, `reserveBeneficiary`, `flags` (REV721TiersHookFlags) | Same as `JBDeploy721TiersHookConfig` but uses `REV721TiersHookFlags` which omits `issueTokensForSplits`. |
|
|
95
94
|
| `REV721TiersHookFlags` | `noNewTiersWithReserves`, `noNewTiersWithVotes`, `noNewTiersWithOwnerMinting`, `preventOverspending` | Same as `JB721TiersHookFlags` minus `issueTokensForSplits`. Revnets do their own weight adjustment for splits. |
|
package/script/Deploy.s.sol
CHANGED
|
@@ -20,7 +20,6 @@ import {Script} from "forge-std/Script.sol";
|
|
|
20
20
|
import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
|
|
21
21
|
import {JBCurrencyIds} from "@bananapus/core-v6/src/libraries/JBCurrencyIds.sol";
|
|
22
22
|
import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
|
|
23
|
-
import {JBTerminalConfig} from "@bananapus/core-v6/src/structs/JBTerminalConfig.sol";
|
|
24
23
|
import {JBSuckerDeployerConfig} from "@bananapus/suckers-v6/src/structs/JBSuckerDeployerConfig.sol";
|
|
25
24
|
import {JBTokenMapping} from "@bananapus/suckers-v6/src/structs/JBTokenMapping.sol";
|
|
26
25
|
import {IPermit2} from "@uniswap/permit2/src/interfaces/IPermit2.sol";
|
|
@@ -48,7 +47,7 @@ import {REV721TiersHookFlags} from "../src/structs/REV721TiersHookFlags.sol";
|
|
|
48
47
|
|
|
49
48
|
struct FeeProjectConfig {
|
|
50
49
|
REVConfig configuration;
|
|
51
|
-
|
|
50
|
+
JBAccountingContext[] accountingContextsToAccept;
|
|
52
51
|
REVSuckerDeploymentConfig suckerDeploymentConfiguration;
|
|
53
52
|
REVDeploy721TiersHookConfig tiered721HookConfiguration;
|
|
54
53
|
REVCroptopAllowedPost[] allowedPosts;
|
|
@@ -65,7 +64,7 @@ contract DeployScript is Script, Sphinx {
|
|
|
65
64
|
Hook721Deployment hook;
|
|
66
65
|
/// @notice tracks the deployment of the sucker contracts for the chain we are deploying to.
|
|
67
66
|
SuckerDeployment suckers;
|
|
68
|
-
/// @notice tracks the deployment of the router terminal.
|
|
67
|
+
/// @notice tracks the deployment of the router terminal registry package.
|
|
69
68
|
RouterTerminalDeployment routerTerminal;
|
|
70
69
|
uint32 private constant _PREMINT_CHAIN_ID = 1;
|
|
71
70
|
string private constant _NAME = "Revnet";
|
|
@@ -130,7 +129,7 @@ contract DeployScript is Script, Sphinx {
|
|
|
130
129
|
defaultValue: string("node_modules/@bananapus/721-hook-v6/deployments/")
|
|
131
130
|
})
|
|
132
131
|
);
|
|
133
|
-
// Get the deployment addresses for the router terminal
|
|
132
|
+
// Get the deployment addresses for the router terminal registry package for this chain.
|
|
134
133
|
routerTerminal = RouterTerminalDeploymentLib.getDeployment(
|
|
135
134
|
vm.envOr({
|
|
136
135
|
name: "NANA_ROUTER_TERMINAL_DEPLOYMENT_PATH",
|
|
@@ -161,15 +160,6 @@ contract DeployScript is Script, Sphinx {
|
|
|
161
160
|
accountingContextsToAccept[0] =
|
|
162
161
|
JBAccountingContext({token: JBConstants.NATIVE_TOKEN, decimals: _DECIMALS, currency: _NATIVE_CURRENCY});
|
|
163
162
|
|
|
164
|
-
// The terminals that the project will accept funds through.
|
|
165
|
-
JBTerminalConfig[] memory terminalConfigurations = new JBTerminalConfig[](2);
|
|
166
|
-
terminalConfigurations[0] =
|
|
167
|
-
JBTerminalConfig({terminal: core.terminal, accountingContextsToAccept: accountingContextsToAccept});
|
|
168
|
-
terminalConfigurations[1] = JBTerminalConfig({
|
|
169
|
-
terminal: IJBTerminal(address(routerTerminal.registry)),
|
|
170
|
-
accountingContextsToAccept: new JBAccountingContext[](0)
|
|
171
|
-
});
|
|
172
|
-
|
|
173
163
|
// The project's revnet stage configurations.
|
|
174
164
|
REVStageConfig[] memory stageConfigurations = new REVStageConfig[](3);
|
|
175
165
|
|
|
@@ -296,7 +286,7 @@ contract DeployScript is Script, Sphinx {
|
|
|
296
286
|
|
|
297
287
|
return FeeProjectConfig({
|
|
298
288
|
configuration: revnetConfiguration,
|
|
299
|
-
|
|
289
|
+
accountingContextsToAccept: accountingContextsToAccept,
|
|
300
290
|
suckerDeploymentConfiguration: suckerDeploymentConfiguration,
|
|
301
291
|
tiered721HookConfiguration: REVDeploy721TiersHookConfig({
|
|
302
292
|
baseline721HookConfiguration: REVBaseline721HookConfig({
|
|
@@ -364,7 +354,13 @@ contract DeployScript is Script, Sphinx {
|
|
|
364
354
|
salt: _REVLOANS_SALT,
|
|
365
355
|
creationCode: type(REVLoans).creationCode,
|
|
366
356
|
arguments: abi.encode(
|
|
367
|
-
core.controller,
|
|
357
|
+
core.controller,
|
|
358
|
+
core.terminal,
|
|
359
|
+
suckers.registry,
|
|
360
|
+
_candidateId,
|
|
361
|
+
loansOwner,
|
|
362
|
+
permit2,
|
|
363
|
+
trustedForwarder
|
|
368
364
|
)
|
|
369
365
|
});
|
|
370
366
|
|
|
@@ -397,9 +393,11 @@ contract DeployScript is Script, Sphinx {
|
|
|
397
393
|
creationCode: type(REVDeployer).creationCode,
|
|
398
394
|
arguments: abi.encode(
|
|
399
395
|
core.controller,
|
|
396
|
+
core.terminal,
|
|
397
|
+
IJBTerminal(address(routerTerminal.registry)),
|
|
400
398
|
suckers.registry,
|
|
401
399
|
_candidateId,
|
|
402
|
-
hook.
|
|
400
|
+
hook.hookDeployer,
|
|
403
401
|
croptop.publisher,
|
|
404
402
|
IJBBuybackHookRegistry(address(buybackHook.registry)),
|
|
405
403
|
_candidateRevloansAddr,
|
|
@@ -432,11 +430,12 @@ contract DeployScript is Script, Sphinx {
|
|
|
432
430
|
}
|
|
433
431
|
}
|
|
434
432
|
|
|
435
|
-
// Deploy REVLoans first — it
|
|
433
|
+
// Deploy REVLoans first — it depends on the canonical controller and multi terminal.
|
|
436
434
|
REVLoans revloans = _revloansExists
|
|
437
435
|
? REVLoans(payable(_existingRevloansAddr))
|
|
438
436
|
: new REVLoans{salt: _REVLOANS_SALT}({
|
|
439
437
|
controller: core.controller,
|
|
438
|
+
terminal: core.terminal,
|
|
440
439
|
suckerRegistry: suckers.registry,
|
|
441
440
|
revId: feeProjectId,
|
|
442
441
|
owner: loansOwner,
|
|
@@ -464,9 +463,11 @@ contract DeployScript is Script, Sphinx {
|
|
|
464
463
|
creationCode: type(REVDeployer).creationCode,
|
|
465
464
|
arguments: abi.encode(
|
|
466
465
|
core.controller,
|
|
466
|
+
core.terminal,
|
|
467
|
+
IJBTerminal(address(routerTerminal.registry)),
|
|
467
468
|
suckers.registry,
|
|
468
469
|
feeProjectId,
|
|
469
|
-
hook.
|
|
470
|
+
hook.hookDeployer,
|
|
470
471
|
croptop.publisher,
|
|
471
472
|
IJBBuybackHookRegistry(address(buybackHook.registry)),
|
|
472
473
|
revloans,
|
|
@@ -481,9 +482,11 @@ contract DeployScript is Script, Sphinx {
|
|
|
481
482
|
? REVDeployer(payable(_deployerAddr))
|
|
482
483
|
: new REVDeployer{salt: _DEPLOYER_SALT}({
|
|
483
484
|
controller: core.controller,
|
|
485
|
+
multiTerminal: core.terminal,
|
|
486
|
+
routerTerminalRegistry: IJBTerminal(address(routerTerminal.registry)),
|
|
484
487
|
suckerRegistry: suckers.registry,
|
|
485
488
|
feeRevnetId: feeProjectId,
|
|
486
|
-
hookDeployer: hook.
|
|
489
|
+
hookDeployer: hook.hookDeployer,
|
|
487
490
|
publisher: croptop.publisher,
|
|
488
491
|
buybackHook: IJBBuybackHookRegistry(address(buybackHook.registry)),
|
|
489
492
|
loans: revloans,
|
|
@@ -506,7 +509,7 @@ contract DeployScript is Script, Sphinx {
|
|
|
506
509
|
_basicDeployer.deployFor({
|
|
507
510
|
revnetId: feeProjectId,
|
|
508
511
|
configuration: feeProjectConfig.configuration,
|
|
509
|
-
|
|
512
|
+
accountingContextsToAccept: feeProjectConfig.accountingContextsToAccept,
|
|
510
513
|
suckerDeploymentConfiguration: feeProjectConfig.suckerDeploymentConfiguration,
|
|
511
514
|
tiered721HookConfiguration: feeProjectConfig.tiered721HookConfiguration,
|
|
512
515
|
allowedPosts: feeProjectConfig.allowedPosts
|
package/src/REVDeployer.sol
CHANGED
|
@@ -12,6 +12,7 @@ import {IJBPermissioned} from "@bananapus/core-v6/src/interfaces/IJBPermissioned
|
|
|
12
12
|
import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
|
|
13
13
|
import {IJBProjects} from "@bananapus/core-v6/src/interfaces/IJBProjects.sol";
|
|
14
14
|
import {IJBRulesetApprovalHook} from "@bananapus/core-v6/src/interfaces/IJBRulesetApprovalHook.sol";
|
|
15
|
+
import {IJBTerminal} from "@bananapus/core-v6/src/interfaces/IJBTerminal.sol";
|
|
15
16
|
import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
|
|
16
17
|
import {JBSplitGroupIds} from "@bananapus/core-v6/src/libraries/JBSplitGroupIds.sol";
|
|
17
18
|
import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
|
|
@@ -22,7 +23,6 @@ import {JBRuleset} from "@bananapus/core-v6/src/structs/JBRuleset.sol";
|
|
|
22
23
|
import {JBRulesetConfig} from "@bananapus/core-v6/src/structs/JBRulesetConfig.sol";
|
|
23
24
|
import {JBRulesetMetadata} from "@bananapus/core-v6/src/structs/JBRulesetMetadata.sol";
|
|
24
25
|
import {JBSplitGroup} from "@bananapus/core-v6/src/structs/JBSplitGroup.sol";
|
|
25
|
-
import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
|
|
26
26
|
import {JBTerminalConfig} from "@bananapus/core-v6/src/structs/JBTerminalConfig.sol";
|
|
27
27
|
import {JBPermissionIds} from "@bananapus/permission-ids-v6/src/JBPermissionIds.sol";
|
|
28
28
|
import {IJBSuckerRegistry} from "@bananapus/suckers-v6/src/interfaces/IJBSuckerRegistry.sol";
|
|
@@ -115,6 +115,9 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
115
115
|
/// Participants can borrow up to the current cash out value of their tokens.
|
|
116
116
|
IREVLoans public immutable override LOANS;
|
|
117
117
|
|
|
118
|
+
/// @notice The canonical terminal that holds revnet treasury balances.
|
|
119
|
+
IJBTerminal public immutable override MULTI_TERMINAL;
|
|
120
|
+
|
|
118
121
|
/// @notice The runtime data hook contract that handles pay and cash out callbacks for revnets.
|
|
119
122
|
/// @dev Set as `dataHook` in each revnet's ruleset metadata. Implements `IJBRulesetDataHook` and `IJBCashOutHook`.
|
|
120
123
|
address public immutable override OWNER;
|
|
@@ -128,6 +131,10 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
128
131
|
/// @notice Manages the publishing of ERC-721 posts to revnet's tiered ERC-721 hooks.
|
|
129
132
|
CTPublisher public immutable override PUBLISHER;
|
|
130
133
|
|
|
134
|
+
/// @notice The canonical router terminal registry installed as a project terminal for alternate payment routes.
|
|
135
|
+
/// @dev Deployments pass the router terminal registry here, not the underlying router terminal implementation.
|
|
136
|
+
IJBTerminal public immutable override ROUTER_TERMINAL_REGISTRY;
|
|
137
|
+
|
|
131
138
|
/// @notice Deploys and tracks suckers for revnets.
|
|
132
139
|
IJBSuckerRegistry public immutable override SUCKER_REGISTRY;
|
|
133
140
|
|
|
@@ -165,6 +172,10 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
165
172
|
//*********************************************************************//
|
|
166
173
|
|
|
167
174
|
/// @param controller The controller to use for launching and operating the Juicebox projects which will be revnets.
|
|
175
|
+
/// @param multiTerminal The canonical terminal that holds revnet treasury balances. Assumed to be a valid
|
|
176
|
+
/// deployment-time dependency.
|
|
177
|
+
/// @param routerTerminalRegistry The canonical router terminal registry used for alternate payment routes. Assumed
|
|
178
|
+
/// to be a valid deployment-time dependency.
|
|
168
179
|
/// @param suckerRegistry The registry to use for deploying and tracking each revnet's suckers.
|
|
169
180
|
/// @param feeRevnetId The Juicebox project ID of the revnet that will receive fees.
|
|
170
181
|
/// @param hookDeployer The deployer to use for revnet's tiered ERC-721 hooks.
|
|
@@ -175,6 +186,8 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
175
186
|
/// @param owner The runtime data hook contract (REVOwner) that handles pay and cash out callbacks.
|
|
176
187
|
constructor(
|
|
177
188
|
IJBController controller,
|
|
189
|
+
IJBTerminal multiTerminal,
|
|
190
|
+
IJBTerminal routerTerminalRegistry,
|
|
178
191
|
IJBSuckerRegistry suckerRegistry,
|
|
179
192
|
uint256 feeRevnetId,
|
|
180
193
|
IJB721TiersHookDeployer hookDeployer,
|
|
@@ -190,6 +203,8 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
190
203
|
DIRECTORY = controller.DIRECTORY();
|
|
191
204
|
PROJECTS = controller.PROJECTS();
|
|
192
205
|
PERMISSIONS = IJBPermissioned(address(CONTROLLER)).PERMISSIONS();
|
|
206
|
+
MULTI_TERMINAL = multiTerminal;
|
|
207
|
+
ROUTER_TERMINAL_REGISTRY = routerTerminalRegistry;
|
|
193
208
|
SUCKER_REGISTRY = suckerRegistry;
|
|
194
209
|
FEE_REVNET_ID = feeRevnetId;
|
|
195
210
|
HOOK_DEPLOYER = hookDeployer;
|
|
@@ -259,49 +274,32 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
259
274
|
}
|
|
260
275
|
|
|
261
276
|
/// @notice Initialize fund access limits for the loan contract.
|
|
262
|
-
/// @dev Returns an unlimited surplus allowance for each
|
|
263
|
-
///
|
|
264
|
-
/// @param terminalConfigurations The terminals to set up for the revnet.
|
|
277
|
+
/// @dev Returns an unlimited surplus allowance for each accepted token in the canonical multi terminal.
|
|
278
|
+
/// @param accountingContextsToAccept The accounting contexts the canonical multi terminal should accept.
|
|
265
279
|
/// @return fundAccessLimitGroups The fund access limit groups for the loans.
|
|
266
|
-
function _makeLoanFundAccessLimits(
|
|
280
|
+
function _makeLoanFundAccessLimits(JBAccountingContext[] calldata accountingContextsToAccept)
|
|
267
281
|
internal
|
|
268
|
-
|
|
282
|
+
view
|
|
269
283
|
returns (JBFundAccessLimitGroup[] memory fundAccessLimitGroups)
|
|
270
284
|
{
|
|
271
|
-
// Count the total number of accounting contexts across all terminals.
|
|
272
|
-
uint256 count;
|
|
273
|
-
for (uint256 i; i < terminalConfigurations.length;) {
|
|
274
|
-
count += terminalConfigurations[i].accountingContextsToAccept.length;
|
|
275
|
-
unchecked {
|
|
276
|
-
++i;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
285
|
// Initialize the fund access limit groups.
|
|
281
|
-
fundAccessLimitGroups = new JBFundAccessLimitGroup[](
|
|
286
|
+
fundAccessLimitGroups = new JBFundAccessLimitGroup[](accountingContextsToAccept.length);
|
|
282
287
|
|
|
283
288
|
// Set up the fund access limits.
|
|
284
|
-
uint256
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
for
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
payoutLimits: new JBCurrencyAmount[](0),
|
|
299
|
-
surplusAllowances: loanAllowances
|
|
300
|
-
});
|
|
301
|
-
unchecked {
|
|
302
|
-
++j;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
289
|
+
for (uint256 i; i < accountingContextsToAccept.length;) {
|
|
290
|
+
JBAccountingContext calldata accountingContext = accountingContextsToAccept[i];
|
|
291
|
+
|
|
292
|
+
// Set up an unlimited allowance for the loan contract to use.
|
|
293
|
+
JBCurrencyAmount[] memory loanAllowances = new JBCurrencyAmount[](1);
|
|
294
|
+
loanAllowances[0] = JBCurrencyAmount({currency: accountingContext.currency, amount: type(uint224).max});
|
|
295
|
+
|
|
296
|
+
// Set up the fund access limits for the loans.
|
|
297
|
+
fundAccessLimitGroups[i] = JBFundAccessLimitGroup({
|
|
298
|
+
terminal: address(MULTI_TERMINAL),
|
|
299
|
+
token: accountingContext.token,
|
|
300
|
+
payoutLimits: new JBCurrencyAmount[](0),
|
|
301
|
+
surplusAllowances: loanAllowances
|
|
302
|
+
});
|
|
305
303
|
unchecked {
|
|
306
304
|
++i;
|
|
307
305
|
}
|
|
@@ -353,6 +351,26 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
353
351
|
});
|
|
354
352
|
}
|
|
355
353
|
|
|
354
|
+
/// @notice Build the canonical terminal configuration used by every revnet.
|
|
355
|
+
/// @dev `MULTI_TERMINAL` accepts the revnet's accounting contexts and owns the treasury/loan accounting surface.
|
|
356
|
+
/// `ROUTER_TERMINAL_REGISTRY` is registered without accounting contexts so users can pay through the router path
|
|
357
|
+
/// without letting callers choose arbitrary terminals or loan sources. The deployer is constructed with distinct
|
|
358
|
+
/// addresses in the two slots; reusing the same address would be rejected by the directory's duplicate check.
|
|
359
|
+
/// @param accountingContextsToAccept The accounting contexts the canonical multi terminal should accept.
|
|
360
|
+
/// @return terminalConfigurations The canonical terminal configuration for the revnet.
|
|
361
|
+
function _makeTerminalConfigurations(JBAccountingContext[] calldata accountingContextsToAccept)
|
|
362
|
+
internal
|
|
363
|
+
view
|
|
364
|
+
returns (JBTerminalConfig[] memory terminalConfigurations)
|
|
365
|
+
{
|
|
366
|
+
terminalConfigurations = new JBTerminalConfig[](2);
|
|
367
|
+
terminalConfigurations[0] =
|
|
368
|
+
JBTerminalConfig({terminal: MULTI_TERMINAL, accountingContextsToAccept: accountingContextsToAccept});
|
|
369
|
+
terminalConfigurations[1] = JBTerminalConfig({
|
|
370
|
+
terminal: ROUTER_TERMINAL_REGISTRY, accountingContextsToAccept: new JBAccountingContext[](0)
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
|
|
356
374
|
/// @notice Returns the permissions that the operator should have for a revnet.
|
|
357
375
|
/// @param revnetId The ID of the revnet to look up.
|
|
358
376
|
/// @return allOperatorPermissions The permissions the operator should have for the revnet,
|
|
@@ -512,7 +530,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
512
530
|
/// REVDeployer, and the project becomes subject to immutable revnet rules. This cannot be undone.
|
|
513
531
|
/// @param revnetId The ID of the Juicebox project to initialize as a revnet. Send 0 to deploy a new revnet.
|
|
514
532
|
/// @param configuration Core revnet configuration. See `REVConfig`.
|
|
515
|
-
/// @param
|
|
533
|
+
/// @param accountingContextsToAccept The accounting contexts the canonical multi terminal should accept.
|
|
516
534
|
/// @param suckerDeploymentConfiguration The suckers to set up for cross-chain token transfers.
|
|
517
535
|
/// @param tiered721HookConfiguration How to configure the tiered ERC-721 hook for the revnet.
|
|
518
536
|
/// @param allowedPosts Restrictions on which croptop posts to allow on the revnet's ERC-721 tiers.
|
|
@@ -522,7 +540,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
522
540
|
function deployFor(
|
|
523
541
|
uint256 revnetId,
|
|
524
542
|
REVConfig calldata configuration,
|
|
525
|
-
|
|
543
|
+
JBAccountingContext[] calldata accountingContextsToAccept,
|
|
526
544
|
REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration,
|
|
527
545
|
REVDeploy721TiersHookConfig calldata tiered721HookConfiguration,
|
|
528
546
|
REVCroptopAllowedPost[] calldata allowedPosts
|
|
@@ -542,7 +560,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
542
560
|
revnetId: revnetId,
|
|
543
561
|
shouldDeployNewRevnet: shouldDeployNewRevnet,
|
|
544
562
|
configuration: configuration,
|
|
545
|
-
|
|
563
|
+
accountingContextsToAccept: accountingContextsToAccept,
|
|
546
564
|
suckerDeploymentConfiguration: suckerDeploymentConfiguration,
|
|
547
565
|
tiered721HookConfiguration: tiered721HookConfiguration,
|
|
548
566
|
allowedPosts: allowedPosts
|
|
@@ -556,7 +574,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
556
574
|
function deployFor(
|
|
557
575
|
uint256 revnetId,
|
|
558
576
|
REVConfig calldata configuration,
|
|
559
|
-
|
|
577
|
+
JBAccountingContext[] calldata accountingContextsToAccept,
|
|
560
578
|
REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration
|
|
561
579
|
)
|
|
562
580
|
external
|
|
@@ -571,7 +589,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
571
589
|
revnetId: revnetId,
|
|
572
590
|
shouldDeployNewRevnet: shouldDeployNewRevnet,
|
|
573
591
|
configuration: configuration,
|
|
574
|
-
|
|
592
|
+
accountingContextsToAccept: accountingContextsToAccept,
|
|
575
593
|
suckerDeploymentConfiguration: suckerDeploymentConfiguration
|
|
576
594
|
});
|
|
577
595
|
|
|
@@ -669,7 +687,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
669
687
|
uint256 revnetId,
|
|
670
688
|
bool shouldDeployNewRevnet,
|
|
671
689
|
REVConfig calldata configuration,
|
|
672
|
-
|
|
690
|
+
JBAccountingContext[] calldata accountingContextsToAccept,
|
|
673
691
|
REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration,
|
|
674
692
|
REVDeploy721TiersHookConfig memory tiered721HookConfiguration,
|
|
675
693
|
REVCroptopAllowedPost[] memory allowedPosts
|
|
@@ -682,7 +700,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
682
700
|
revnetId: revnetId,
|
|
683
701
|
shouldDeployNewRevnet: shouldDeployNewRevnet,
|
|
684
702
|
configuration: configuration,
|
|
685
|
-
|
|
703
|
+
accountingContextsToAccept: accountingContextsToAccept,
|
|
686
704
|
suckerDeploymentConfiguration: suckerDeploymentConfiguration
|
|
687
705
|
});
|
|
688
706
|
|
|
@@ -788,14 +806,14 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
788
806
|
/// @param shouldDeployNewRevnet Whether the revnet ID was reserved by this deployment call, or the caller is
|
|
789
807
|
/// converting an existing Juicebox project into a revnet.
|
|
790
808
|
/// @param configuration Core revnet configuration. See `REVConfig`.
|
|
791
|
-
/// @param
|
|
809
|
+
/// @param accountingContextsToAccept The accounting contexts the canonical multi terminal should accept.
|
|
792
810
|
/// @param suckerDeploymentConfiguration The suckers to set up for cross-chain token transfers.
|
|
793
811
|
/// @return encodedConfigurationHash A hash that represents the revnet's configuration.
|
|
794
812
|
function _deployRevnetFor(
|
|
795
813
|
uint256 revnetId,
|
|
796
814
|
bool shouldDeployNewRevnet,
|
|
797
815
|
REVConfig calldata configuration,
|
|
798
|
-
|
|
816
|
+
JBAccountingContext[] calldata accountingContextsToAccept,
|
|
799
817
|
REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration
|
|
800
818
|
)
|
|
801
819
|
internal
|
|
@@ -804,9 +822,13 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
804
822
|
// Normalize and encode the configurations.
|
|
805
823
|
JBRulesetConfig[] memory rulesetConfigurations;
|
|
806
824
|
(rulesetConfigurations, encodedConfigurationHash) = _makeRulesetConfigurations({
|
|
807
|
-
revnetId: revnetId, configuration: configuration,
|
|
825
|
+
revnetId: revnetId, configuration: configuration, accountingContextsToAccept: accountingContextsToAccept
|
|
808
826
|
});
|
|
809
827
|
|
|
828
|
+
// Build the canonical terminal set from the deployer's immutable terminal choices.
|
|
829
|
+
JBTerminalConfig[] memory terminalConfigurations =
|
|
830
|
+
_makeTerminalConfigurations({accountingContextsToAccept: accountingContextsToAccept});
|
|
831
|
+
|
|
810
832
|
address owner;
|
|
811
833
|
if (!shouldDeployNewRevnet) {
|
|
812
834
|
// Keep a reference to the Juicebox project's owner.
|
|
@@ -848,20 +870,14 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
848
870
|
salt: keccak256(abi.encode(configuration.description.salt, encodedConfigurationHash, _msgSender()))
|
|
849
871
|
});
|
|
850
872
|
|
|
851
|
-
// Now that the ERC-20 exists, initialize buyback pools for each
|
|
852
|
-
for (uint256 i; i <
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
initialIssuance: configuration.stageConfigurations[0].initialIssuance
|
|
860
|
-
});
|
|
861
|
-
unchecked {
|
|
862
|
-
++j;
|
|
863
|
-
}
|
|
864
|
-
}
|
|
873
|
+
// Now that the ERC-20 exists, initialize buyback pools for each accepted treasury token.
|
|
874
|
+
for (uint256 i; i < accountingContextsToAccept.length;) {
|
|
875
|
+
_tryInitializeBuybackPoolFor({
|
|
876
|
+
revnetId: revnetId,
|
|
877
|
+
terminalToken: accountingContextsToAccept[i].token,
|
|
878
|
+
terminalTokenDecimals: accountingContextsToAccept[i].decimals,
|
|
879
|
+
initialIssuance: configuration.stageConfigurations[0].initialIssuance
|
|
880
|
+
});
|
|
865
881
|
unchecked {
|
|
866
882
|
++i;
|
|
867
883
|
}
|
|
@@ -926,13 +942,13 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
926
942
|
/// configured immutably at deployment time.
|
|
927
943
|
/// @param revnetId The ID of the revnet to build rulesets for.
|
|
928
944
|
/// @param configuration The configuration containing the revnet's stages.
|
|
929
|
-
/// @param
|
|
945
|
+
/// @param accountingContextsToAccept The accounting contexts the canonical multi terminal should accept.
|
|
930
946
|
/// @return rulesetConfigurations A list of ruleset configurations derived from the stages.
|
|
931
947
|
/// @return encodedConfigurationHash A hash that represents the revnet's configuration.
|
|
932
948
|
function _makeRulesetConfigurations(
|
|
933
949
|
uint256 revnetId,
|
|
934
950
|
REVConfig calldata configuration,
|
|
935
|
-
|
|
951
|
+
JBAccountingContext[] calldata accountingContextsToAccept
|
|
936
952
|
)
|
|
937
953
|
internal
|
|
938
954
|
returns (JBRulesetConfig[] memory rulesetConfigurations, bytes32 encodedConfigurationHash)
|
|
@@ -954,19 +970,9 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
954
970
|
configuration.description.salt
|
|
955
971
|
);
|
|
956
972
|
|
|
957
|
-
// Include terminal addresses in the hash so cross-chain expansions must use the same terminals.
|
|
958
|
-
// Terminal addresses are deterministic across chains. Accounting contexts are excluded because
|
|
959
|
-
// token addresses (e.g. USDC) legitimately differ per chain.
|
|
960
|
-
for (uint256 i; i < terminalConfigurations.length;) {
|
|
961
|
-
encodedConfiguration = abi.encode(encodedConfiguration, terminalConfigurations[i].terminal);
|
|
962
|
-
unchecked {
|
|
963
|
-
++i;
|
|
964
|
-
}
|
|
965
|
-
}
|
|
966
|
-
|
|
967
973
|
// Initialize fund access limit groups for the loan contract.
|
|
968
974
|
JBFundAccessLimitGroup[] memory fundAccessLimitGroups =
|
|
969
|
-
_makeLoanFundAccessLimits({
|
|
975
|
+
_makeLoanFundAccessLimits({accountingContextsToAccept: accountingContextsToAccept});
|
|
970
976
|
|
|
971
977
|
// Track the previous stage's effective start time for ordering validation.
|
|
972
978
|
// When stage 0 uses `startsAtOrAfter == 0`, the effective value is `block.timestamp`.
|