@rev-net/core-v6 0.0.57 → 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 +93 -115
- package/script/helpers/RevnetCoreDeploymentLib.sol +12 -17
- package/src/REVDeployer.sol +84 -76
- package/src/REVLoans.sol +205 -189
- package/src/REVOwner.sol +66 -56
- package/src/interfaces/IREVDeployer.sol +14 -4
- package/src/interfaces/IREVLoans.sol +24 -30
- package/src/interfaces/IREVOwner.sol +6 -2
- 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,56 +64,33 @@ 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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
bytes32 DEPLOYER_SALT = "_REV_DEPLOYER_SALT_V6_";
|
|
93
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
94
|
-
bytes32 REVLOANS_SALT = "_REV_LOANS_SALT_V6_";
|
|
95
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
96
|
-
bytes32 REVOWNER_SALT = "_REV_OWNER_SALT_V6_";
|
|
97
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
98
|
-
address LOANS_OWNER;
|
|
99
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
100
|
-
address OPERATOR;
|
|
101
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
102
|
-
address TRUSTED_FORWARDER;
|
|
103
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
104
|
-
IPermit2 PERMIT2;
|
|
105
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
106
|
-
uint48 REV_START_TIME = 1_740_089_444;
|
|
107
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
108
|
-
uint104 REV_MAINNET_AUTO_ISSUANCE_ = 1_050_482_341_387_116_262_330_122;
|
|
109
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
110
|
-
uint104 REV_BASE_AUTO_ISSUANCE_ = 38_544_322_230_437_559_731_228;
|
|
111
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
112
|
-
uint104 REV_OP_AUTO_ISSUANCE_ = 32_069_388_242_375_817_844;
|
|
113
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
114
|
-
uint104 REV_ARB_AUTO_ISSUANCE_ = 3_479_431_776_906_850_000_000;
|
|
69
|
+
uint32 private constant _PREMINT_CHAIN_ID = 1;
|
|
70
|
+
string private constant _NAME = "Revnet";
|
|
71
|
+
string private constant _SYMBOL = "REV";
|
|
72
|
+
string private constant _PROJECT_URI = "ipfs://QmcCBD5fM927LjkLDSJWtNEU9FohcbiPSfqtGRHXFHzJ4W";
|
|
73
|
+
uint32 private constant _NATIVE_CURRENCY = uint32(uint160(JBConstants.NATIVE_TOKEN));
|
|
74
|
+
uint32 private constant _ETH_CURRENCY = JBCurrencyIds.ETH;
|
|
75
|
+
uint8 private constant _DECIMALS = 18;
|
|
76
|
+
uint256 private constant _DECIMAL_MULTIPLIER = 10 ** _DECIMALS;
|
|
77
|
+
bytes32 private constant _ERC20_SALT = "_REV_ERC20_SALT_V6_";
|
|
78
|
+
bytes32 private constant _SUCKER_SALT = "_REV_SUCKER_SALT_V6_";
|
|
79
|
+
bytes32 private constant _DEPLOYER_SALT = "_REV_DEPLOYER_SALT_V6_";
|
|
80
|
+
bytes32 private constant _REVLOANS_SALT = "_REV_LOANS_SALT_V6_";
|
|
81
|
+
bytes32 private constant _REVOWNER_SALT = "_REV_OWNER_SALT_V6_";
|
|
82
|
+
address private loansOwner;
|
|
83
|
+
address private operator;
|
|
84
|
+
address private trustedForwarder;
|
|
85
|
+
IPermit2 private permit2;
|
|
86
|
+
uint48 private constant _REV_START_TIME = 1_740_089_444;
|
|
87
|
+
uint104 private constant _REV_MAINNET_AUTO_ISSUANCE = 1_050_482_341_387_116_262_330_122;
|
|
88
|
+
uint104 private constant _REV_BASE_AUTO_ISSUANCE = 38_544_322_230_437_559_731_228;
|
|
89
|
+
uint104 private constant _REV_OP_AUTO_ISSUANCE = 32_069_388_242_375_817_844;
|
|
90
|
+
uint104 private constant _REV_ARB_AUTO_ISSUANCE = 3_479_431_776_906_850_000_000;
|
|
115
91
|
|
|
116
92
|
function configureSphinx() public override {
|
|
117
|
-
//
|
|
93
|
+
// Safe owners and threshold are resolved by the Sphinx project config.
|
|
118
94
|
sphinxConfig.projectName = "revnet-core-v6";
|
|
119
95
|
sphinxConfig.mainnets = ["ethereum", "optimism", "base", "arbitrum"];
|
|
120
96
|
sphinxConfig.testnets = ["ethereum_sepolia", "optimism_sepolia", "base_sepolia", "arbitrum_sepolia"];
|
|
@@ -122,9 +98,9 @@ contract DeployScript is Script, Sphinx {
|
|
|
122
98
|
|
|
123
99
|
function run() public {
|
|
124
100
|
// Get the operator address.
|
|
125
|
-
|
|
101
|
+
operator = safeAddress();
|
|
126
102
|
// Get the loans owner address.
|
|
127
|
-
|
|
103
|
+
loansOwner = safeAddress();
|
|
128
104
|
|
|
129
105
|
// Get the deployment addresses for the nana CORE for this chain.
|
|
130
106
|
// We want to do this outside of the `sphinx` modifier.
|
|
@@ -153,7 +129,7 @@ contract DeployScript is Script, Sphinx {
|
|
|
153
129
|
defaultValue: string("node_modules/@bananapus/721-hook-v6/deployments/")
|
|
154
130
|
})
|
|
155
131
|
);
|
|
156
|
-
// Get the deployment addresses for the router terminal
|
|
132
|
+
// Get the deployment addresses for the router terminal registry package for this chain.
|
|
157
133
|
routerTerminal = RouterTerminalDeploymentLib.getDeployment(
|
|
158
134
|
vm.envOr({
|
|
159
135
|
name: "NANA_ROUTER_TERMINAL_DEPLOYMENT_PATH",
|
|
@@ -169,8 +145,8 @@ contract DeployScript is Script, Sphinx {
|
|
|
169
145
|
);
|
|
170
146
|
|
|
171
147
|
// We use the same trusted forwarder and permit2 as the core deployment.
|
|
172
|
-
|
|
173
|
-
|
|
148
|
+
trustedForwarder = core.controller.trustedForwarder();
|
|
149
|
+
permit2 = core.terminal.PERMIT2();
|
|
174
150
|
|
|
175
151
|
// Perform the deployment transactions.
|
|
176
152
|
deploy();
|
|
@@ -182,16 +158,7 @@ contract DeployScript is Script, Sphinx {
|
|
|
182
158
|
|
|
183
159
|
// Accept the chain's native currency through the multi terminal.
|
|
184
160
|
accountingContextsToAccept[0] =
|
|
185
|
-
JBAccountingContext({token: JBConstants.NATIVE_TOKEN, decimals:
|
|
186
|
-
|
|
187
|
-
// The terminals that the project will accept funds through.
|
|
188
|
-
JBTerminalConfig[] memory terminalConfigurations = new JBTerminalConfig[](2);
|
|
189
|
-
terminalConfigurations[0] =
|
|
190
|
-
JBTerminalConfig({terminal: core.terminal, accountingContextsToAccept: accountingContextsToAccept});
|
|
191
|
-
terminalConfigurations[1] = JBTerminalConfig({
|
|
192
|
-
terminal: IJBTerminal(address(routerTerminal.registry)),
|
|
193
|
-
accountingContextsToAccept: new JBAccountingContext[](0)
|
|
194
|
-
});
|
|
161
|
+
JBAccountingContext({token: JBConstants.NATIVE_TOKEN, decimals: _DECIMALS, currency: _NATIVE_CURRENCY});
|
|
195
162
|
|
|
196
163
|
// The project's revnet stage configurations.
|
|
197
164
|
REVStageConfig[] memory stageConfigurations = new REVStageConfig[](3);
|
|
@@ -202,25 +169,25 @@ contract DeployScript is Script, Sphinx {
|
|
|
202
169
|
preferAddToBalance: false,
|
|
203
170
|
percent: JBConstants.SPLITS_TOTAL_PERCENT,
|
|
204
171
|
projectId: 0,
|
|
205
|
-
beneficiary: payable(
|
|
172
|
+
beneficiary: payable(operator),
|
|
206
173
|
lockedUntil: 0,
|
|
207
174
|
hook: IJBSplitHook(address(0))
|
|
208
175
|
});
|
|
209
176
|
|
|
210
177
|
{
|
|
211
178
|
REVAutoIssuance[] memory issuanceConfs = new REVAutoIssuance[](4);
|
|
212
|
-
issuanceConfs[0] = REVAutoIssuance({chainId: 1, count:
|
|
213
|
-
issuanceConfs[1] = REVAutoIssuance({chainId: 8453, count:
|
|
214
|
-
issuanceConfs[2] = REVAutoIssuance({chainId: 10, count:
|
|
215
|
-
issuanceConfs[3] = REVAutoIssuance({chainId: 42_161, count:
|
|
179
|
+
issuanceConfs[0] = REVAutoIssuance({chainId: 1, count: _REV_MAINNET_AUTO_ISSUANCE, beneficiary: operator});
|
|
180
|
+
issuanceConfs[1] = REVAutoIssuance({chainId: 8453, count: _REV_BASE_AUTO_ISSUANCE, beneficiary: operator});
|
|
181
|
+
issuanceConfs[2] = REVAutoIssuance({chainId: 10, count: _REV_OP_AUTO_ISSUANCE, beneficiary: operator});
|
|
182
|
+
issuanceConfs[3] = REVAutoIssuance({chainId: 42_161, count: _REV_ARB_AUTO_ISSUANCE, beneficiary: operator});
|
|
216
183
|
|
|
217
184
|
stageConfigurations[0] = REVStageConfig({
|
|
218
|
-
startsAtOrAfter:
|
|
185
|
+
startsAtOrAfter: _REV_START_TIME,
|
|
219
186
|
autoIssuances: issuanceConfs,
|
|
220
187
|
splitPercent: 3800, // 38%
|
|
221
188
|
splits: splits,
|
|
222
189
|
// forge-lint: disable-next-line(unsafe-typecast)
|
|
223
|
-
initialIssuance: uint112(10_000 *
|
|
190
|
+
initialIssuance: uint112(10_000 * _DECIMAL_MULTIPLIER),
|
|
224
191
|
issuanceCutFrequency: 90 days,
|
|
225
192
|
issuanceCutPercent: 380_000_000, // 38%
|
|
226
193
|
cashOutTaxRate: 1000, // 0.1
|
|
@@ -232,10 +199,10 @@ contract DeployScript is Script, Sphinx {
|
|
|
232
199
|
REVAutoIssuance[] memory issuanceConfs = new REVAutoIssuance[](1);
|
|
233
200
|
issuanceConfs[0] = REVAutoIssuance({
|
|
234
201
|
// forge-lint: disable-next-line(unsafe-typecast)
|
|
235
|
-
chainId:
|
|
202
|
+
chainId: _PREMINT_CHAIN_ID,
|
|
236
203
|
// forge-lint: disable-next-line(unsafe-typecast)
|
|
237
|
-
count: uint104(1_550_000 *
|
|
238
|
-
beneficiary:
|
|
204
|
+
count: uint104(1_550_000 * _DECIMAL_MULTIPLIER),
|
|
205
|
+
beneficiary: operator
|
|
239
206
|
});
|
|
240
207
|
|
|
241
208
|
stageConfigurations[1] = REVStageConfig({
|
|
@@ -265,9 +232,9 @@ contract DeployScript is Script, Sphinx {
|
|
|
265
232
|
|
|
266
233
|
// The project's revnet configuration
|
|
267
234
|
REVConfig memory revnetConfiguration = REVConfig({
|
|
268
|
-
description: REVDescription({name:
|
|
269
|
-
baseCurrency:
|
|
270
|
-
operator:
|
|
235
|
+
description: REVDescription({name: _NAME, ticker: _SYMBOL, uri: _PROJECT_URI, salt: _ERC20_SALT}),
|
|
236
|
+
baseCurrency: _ETH_CURRENCY,
|
|
237
|
+
operator: operator,
|
|
271
238
|
scopeCashOutsToLocalBalances: false,
|
|
272
239
|
stageConfigurations: stageConfigurations
|
|
273
240
|
});
|
|
@@ -314,12 +281,12 @@ contract DeployScript is Script, Sphinx {
|
|
|
314
281
|
}
|
|
315
282
|
// Specify all sucker deployments.
|
|
316
283
|
suckerDeploymentConfiguration =
|
|
317
|
-
REVSuckerDeploymentConfig({deployerConfigurations: suckerDeployerConfigurations, salt:
|
|
284
|
+
REVSuckerDeploymentConfig({deployerConfigurations: suckerDeployerConfigurations, salt: _SUCKER_SALT});
|
|
318
285
|
}
|
|
319
286
|
|
|
320
287
|
return FeeProjectConfig({
|
|
321
288
|
configuration: revnetConfiguration,
|
|
322
|
-
|
|
289
|
+
accountingContextsToAccept: accountingContextsToAccept,
|
|
323
290
|
suckerDeploymentConfiguration: suckerDeploymentConfiguration,
|
|
324
291
|
tiered721HookConfiguration: REVDeploy721TiersHookConfig({
|
|
325
292
|
baseline721HookConfiguration: REVBaseline721HookConfig({
|
|
@@ -329,7 +296,7 @@ contract DeployScript is Script, Sphinx {
|
|
|
329
296
|
tokenUriResolver: IJB721TokenUriResolver(address(0)),
|
|
330
297
|
contractUri: "",
|
|
331
298
|
tiersConfig: JB721InitTiersConfig({
|
|
332
|
-
tiers: new JB721TierConfig[](0), currency:
|
|
299
|
+
tiers: new JB721TierConfig[](0), currency: _ETH_CURRENCY, decimals: 18
|
|
333
300
|
}),
|
|
334
301
|
flags: REV721TiersHookFlags({
|
|
335
302
|
noNewTiersWithReserves: false,
|
|
@@ -351,8 +318,7 @@ contract DeployScript is Script, Sphinx {
|
|
|
351
318
|
function deploy() public sphinx {
|
|
352
319
|
// Check if singletons are already deployed before creating a new fee project.
|
|
353
320
|
// This prevents creating orphan projects on script restarts.
|
|
354
|
-
|
|
355
|
-
uint256 FEE_PROJECT_ID;
|
|
321
|
+
uint256 feeProjectId;
|
|
356
322
|
|
|
357
323
|
// Predict the REVLoans address for an arbitrary fee project ID to check if it exists.
|
|
358
324
|
// We can't predict without a fee project ID, so we first check the REVDeployer which also stores it.
|
|
@@ -360,7 +326,7 @@ contract DeployScript is Script, Sphinx {
|
|
|
360
326
|
|
|
361
327
|
// First, check if REVLoans is already deployed by trying with project ID = 0 (placeholder).
|
|
362
328
|
// We need to iterate: if either singleton exists, extract the fee project ID from it.
|
|
363
|
-
// Since both encode
|
|
329
|
+
// Since both encode feeProjectId, we check if any code exists at the predicted address
|
|
364
330
|
// for sequential project IDs starting from 1.
|
|
365
331
|
|
|
366
332
|
// A simpler approach: predict the REVDeployer address for each possible fee project ID
|
|
@@ -385,10 +351,16 @@ contract DeployScript is Script, Sphinx {
|
|
|
385
351
|
for (uint256 _candidateId = 1; _candidateId < _nextProjectId; _candidateId++) {
|
|
386
352
|
// Predict REVLoans address for this candidate fee project ID.
|
|
387
353
|
(address _candidateRevloansAddr, bool _candidateRevloansDeployed) = _isDeployed({
|
|
388
|
-
salt:
|
|
354
|
+
salt: _REVLOANS_SALT,
|
|
389
355
|
creationCode: type(REVLoans).creationCode,
|
|
390
356
|
arguments: abi.encode(
|
|
391
|
-
core.controller,
|
|
357
|
+
core.controller,
|
|
358
|
+
core.terminal,
|
|
359
|
+
suckers.registry,
|
|
360
|
+
_candidateId,
|
|
361
|
+
loansOwner,
|
|
362
|
+
permit2,
|
|
363
|
+
trustedForwarder
|
|
392
364
|
)
|
|
393
365
|
});
|
|
394
366
|
|
|
@@ -396,14 +368,14 @@ contract DeployScript is Script, Sphinx {
|
|
|
396
368
|
// Verify the fee project ID matches by reading the immutable.
|
|
397
369
|
if (REVLoans(payable(_candidateRevloansAddr)).REV_ID() == _candidateId) {
|
|
398
370
|
// Record the fee project ID from the existing deployment.
|
|
399
|
-
|
|
371
|
+
feeProjectId = _candidateId;
|
|
400
372
|
// Record the existing REVLoans address.
|
|
401
373
|
_existingRevloansAddr = _candidateRevloansAddr;
|
|
402
374
|
_revloansExists = true;
|
|
403
375
|
|
|
404
376
|
// Also predict and verify the owner.
|
|
405
377
|
(_existingOwnerAddr, _revOwnerExists) = _isDeployed({
|
|
406
|
-
salt:
|
|
378
|
+
salt: _REVOWNER_SALT,
|
|
407
379
|
creationCode: type(REVOwner).creationCode,
|
|
408
380
|
arguments: abi.encode(
|
|
409
381
|
IJBBuybackHookRegistry(address(buybackHook.registry)),
|
|
@@ -417,17 +389,19 @@ contract DeployScript is Script, Sphinx {
|
|
|
417
389
|
|
|
418
390
|
// Also predict and verify the deployer.
|
|
419
391
|
(_existingDeployerAddr, _revDeployerExists) = _isDeployed({
|
|
420
|
-
salt:
|
|
392
|
+
salt: _DEPLOYER_SALT,
|
|
421
393
|
creationCode: type(REVDeployer).creationCode,
|
|
422
394
|
arguments: abi.encode(
|
|
423
395
|
core.controller,
|
|
396
|
+
core.terminal,
|
|
397
|
+
IJBTerminal(address(routerTerminal.registry)),
|
|
424
398
|
suckers.registry,
|
|
425
399
|
_candidateId,
|
|
426
|
-
hook.
|
|
400
|
+
hook.hookDeployer,
|
|
427
401
|
croptop.publisher,
|
|
428
402
|
IJBBuybackHookRegistry(address(buybackHook.registry)),
|
|
429
403
|
_candidateRevloansAddr,
|
|
430
|
-
|
|
404
|
+
trustedForwarder,
|
|
431
405
|
_existingOwnerAddr
|
|
432
406
|
)
|
|
433
407
|
});
|
|
@@ -445,93 +419,97 @@ contract DeployScript is Script, Sphinx {
|
|
|
445
419
|
for (uint256 i = _nextProjectId - 1; i >= 1; i--) {
|
|
446
420
|
if (core.projects.ownerOf(i) == safeAddress()) {
|
|
447
421
|
if (address(core.controller.DIRECTORY().controllerOf(i)) == address(0)) {
|
|
448
|
-
|
|
422
|
+
feeProjectId = i;
|
|
449
423
|
_foundExisting = true;
|
|
450
424
|
break;
|
|
451
425
|
}
|
|
452
426
|
}
|
|
453
427
|
}
|
|
454
428
|
if (!_foundExisting) {
|
|
455
|
-
|
|
456
|
-
FEE_PROJECT_ID = core.projects.createFor(safeAddress());
|
|
429
|
+
feeProjectId = core.projects.createFor(safeAddress());
|
|
457
430
|
}
|
|
458
431
|
}
|
|
459
432
|
|
|
460
|
-
// Deploy REVLoans first — it
|
|
433
|
+
// Deploy REVLoans first — it depends on the canonical controller and multi terminal.
|
|
461
434
|
REVLoans revloans = _revloansExists
|
|
462
435
|
? REVLoans(payable(_existingRevloansAddr))
|
|
463
|
-
: new REVLoans{salt:
|
|
436
|
+
: new REVLoans{salt: _REVLOANS_SALT}({
|
|
464
437
|
controller: core.controller,
|
|
438
|
+
terminal: core.terminal,
|
|
465
439
|
suckerRegistry: suckers.registry,
|
|
466
|
-
revId:
|
|
467
|
-
owner:
|
|
468
|
-
permit2:
|
|
469
|
-
trustedForwarder:
|
|
440
|
+
revId: feeProjectId,
|
|
441
|
+
owner: loansOwner,
|
|
442
|
+
permit2: permit2,
|
|
443
|
+
trustedForwarder: trustedForwarder
|
|
470
444
|
});
|
|
471
445
|
|
|
472
446
|
// Deploy REVOwner — the runtime data hook that handles pay and cash out callbacks.
|
|
473
447
|
REVOwner revOwner = _revOwnerExists
|
|
474
448
|
? REVOwner(_existingOwnerAddr)
|
|
475
|
-
: new REVOwner{salt:
|
|
449
|
+
: new REVOwner{salt: _REVOWNER_SALT}({
|
|
476
450
|
buybackHook: IJBBuybackHookRegistry(address(buybackHook.registry)),
|
|
477
451
|
directory: core.controller.DIRECTORY(),
|
|
478
|
-
feeRevnetId:
|
|
452
|
+
feeRevnetId: feeProjectId,
|
|
479
453
|
suckerRegistry: suckers.registry,
|
|
480
454
|
loans: revloans,
|
|
481
|
-
|
|
455
|
+
deployerAddress: msg.sender
|
|
482
456
|
});
|
|
483
457
|
|
|
484
458
|
// Deploy REVDeployer with the REVLoans, buyback hook, and REVOwner addresses.
|
|
485
459
|
(address _deployerAddr, bool _deployerIsDeployed) = _revDeployerExists
|
|
486
460
|
? (_existingDeployerAddr, true)
|
|
487
461
|
: _isDeployed({
|
|
488
|
-
salt:
|
|
462
|
+
salt: _DEPLOYER_SALT,
|
|
489
463
|
creationCode: type(REVDeployer).creationCode,
|
|
490
464
|
arguments: abi.encode(
|
|
491
465
|
core.controller,
|
|
466
|
+
core.terminal,
|
|
467
|
+
IJBTerminal(address(routerTerminal.registry)),
|
|
492
468
|
suckers.registry,
|
|
493
|
-
|
|
494
|
-
hook.
|
|
469
|
+
feeProjectId,
|
|
470
|
+
hook.hookDeployer,
|
|
495
471
|
croptop.publisher,
|
|
496
472
|
IJBBuybackHookRegistry(address(buybackHook.registry)),
|
|
497
473
|
revloans,
|
|
498
|
-
|
|
474
|
+
trustedForwarder,
|
|
499
475
|
address(revOwner)
|
|
500
476
|
)
|
|
501
477
|
});
|
|
502
|
-
if (address(revOwner.
|
|
478
|
+
if (address(revOwner.deployer()) == address(0)) {
|
|
503
479
|
revOwner.setDeployer(IREVDeployer(_deployerAddr));
|
|
504
480
|
}
|
|
505
481
|
REVDeployer _basicDeployer = _deployerIsDeployed
|
|
506
482
|
? REVDeployer(payable(_deployerAddr))
|
|
507
|
-
: new REVDeployer{salt:
|
|
483
|
+
: new REVDeployer{salt: _DEPLOYER_SALT}({
|
|
508
484
|
controller: core.controller,
|
|
485
|
+
multiTerminal: core.terminal,
|
|
486
|
+
routerTerminalRegistry: IJBTerminal(address(routerTerminal.registry)),
|
|
509
487
|
suckerRegistry: suckers.registry,
|
|
510
|
-
feeRevnetId:
|
|
511
|
-
hookDeployer: hook.
|
|
488
|
+
feeRevnetId: feeProjectId,
|
|
489
|
+
hookDeployer: hook.hookDeployer,
|
|
512
490
|
publisher: croptop.publisher,
|
|
513
491
|
buybackHook: IJBBuybackHookRegistry(address(buybackHook.registry)),
|
|
514
492
|
loans: revloans,
|
|
515
|
-
trustedForwarder:
|
|
493
|
+
trustedForwarder: trustedForwarder,
|
|
516
494
|
owner: address(revOwner)
|
|
517
495
|
});
|
|
518
496
|
|
|
519
497
|
// Only configure the fee project if it doesn't already have a controller.
|
|
520
498
|
// This handles both fresh deploys and restarts where singletons exist but the fee project
|
|
521
499
|
// was not yet configured.
|
|
522
|
-
bool _feeProjectConfigured = address(core.controller.DIRECTORY().controllerOf(
|
|
500
|
+
bool _feeProjectConfigured = address(core.controller.DIRECTORY().controllerOf(feeProjectId)) != address(0);
|
|
523
501
|
if (!_feeProjectConfigured) {
|
|
524
502
|
// Approve the basic deployer to configure the project.
|
|
525
|
-
core.projects.approve({to: address(_basicDeployer), tokenId:
|
|
503
|
+
core.projects.approve({to: address(_basicDeployer), tokenId: feeProjectId});
|
|
526
504
|
|
|
527
505
|
// Build the config.
|
|
528
506
|
FeeProjectConfig memory feeProjectConfig = getFeeProjectConfig();
|
|
529
507
|
|
|
530
508
|
// Configure the project.
|
|
531
509
|
_basicDeployer.deployFor({
|
|
532
|
-
revnetId:
|
|
510
|
+
revnetId: feeProjectId,
|
|
533
511
|
configuration: feeProjectConfig.configuration,
|
|
534
|
-
|
|
512
|
+
accountingContextsToAccept: feeProjectConfig.accountingContextsToAccept,
|
|
535
513
|
suckerDeploymentConfiguration: feeProjectConfig.suckerDeploymentConfiguration,
|
|
536
514
|
tiered721HookConfiguration: feeProjectConfig.tiered721HookConfiguration,
|
|
537
515
|
allowedPosts: feeProjectConfig.allowedPosts
|
|
@@ -10,8 +10,7 @@ import {IREVLoans} from "./../../src/interfaces/IREVLoans.sol";
|
|
|
10
10
|
import {REVOwner} from "./../../src/REVOwner.sol";
|
|
11
11
|
|
|
12
12
|
struct RevnetCoreDeployment {
|
|
13
|
-
|
|
14
|
-
IREVDeployer basic_deployer;
|
|
13
|
+
IREVDeployer basicDeployer;
|
|
15
14
|
IREVLoans loans;
|
|
16
15
|
REVOwner owner;
|
|
17
16
|
}
|
|
@@ -23,17 +22,16 @@ library RevnetCoreDeploymentLib {
|
|
|
23
22
|
Vm internal constant vm = Vm(VM_ADDRESS);
|
|
24
23
|
|
|
25
24
|
function getDeployment(string memory path) internal returns (RevnetCoreDeployment memory deployment) {
|
|
26
|
-
//
|
|
25
|
+
// Match the current chain ID to the Sphinx network name used in deployment artifacts.
|
|
27
26
|
uint256 chainId = block.chainid;
|
|
28
27
|
|
|
29
|
-
//
|
|
30
|
-
// TODO: get constants without deploy.
|
|
28
|
+
// `SphinxConstants` exposes Sphinx's supported chain ID to network name mapping.
|
|
31
29
|
SphinxConstants sphinxConstants = new SphinxConstants();
|
|
32
30
|
NetworkInfo[] memory networks = sphinxConstants.getNetworkInfoArray();
|
|
33
31
|
|
|
34
32
|
for (uint256 _i; _i < networks.length; _i++) {
|
|
35
33
|
if (networks[_i].chainId == chainId) {
|
|
36
|
-
return getDeployment({path: path,
|
|
34
|
+
return getDeployment({path: path, networkName: networks[_i].name});
|
|
37
35
|
}
|
|
38
36
|
}
|
|
39
37
|
|
|
@@ -42,28 +40,27 @@ library RevnetCoreDeploymentLib {
|
|
|
42
40
|
|
|
43
41
|
function getDeployment(
|
|
44
42
|
string memory path,
|
|
45
|
-
|
|
46
|
-
string memory network_name
|
|
43
|
+
string memory networkName
|
|
47
44
|
)
|
|
48
45
|
internal
|
|
49
46
|
view
|
|
50
47
|
returns (RevnetCoreDeployment memory deployment)
|
|
51
48
|
{
|
|
52
|
-
deployment.
|
|
49
|
+
deployment.basicDeployer = IREVDeployer(
|
|
53
50
|
_getDeploymentAddress({
|
|
54
|
-
path: path,
|
|
51
|
+
path: path, projectName: "revnet-core-v6", networkName: networkName, contractName: "REVDeployer"
|
|
55
52
|
})
|
|
56
53
|
);
|
|
57
54
|
|
|
58
55
|
deployment.loans = IREVLoans(
|
|
59
56
|
_getDeploymentAddress({
|
|
60
|
-
path: path,
|
|
57
|
+
path: path, projectName: "revnet-core-v6", networkName: networkName, contractName: "REVLoans"
|
|
61
58
|
})
|
|
62
59
|
);
|
|
63
60
|
|
|
64
61
|
deployment.owner = REVOwner(
|
|
65
62
|
_getDeploymentAddress({
|
|
66
|
-
path: path,
|
|
63
|
+
path: path, projectName: "revnet-core-v6", networkName: networkName, contractName: "REVOwner"
|
|
67
64
|
})
|
|
68
65
|
);
|
|
69
66
|
}
|
|
@@ -75,10 +72,8 @@ library RevnetCoreDeploymentLib {
|
|
|
75
72
|
/// @return The address of the contract.
|
|
76
73
|
function _getDeploymentAddress(
|
|
77
74
|
string memory path,
|
|
78
|
-
|
|
79
|
-
string memory
|
|
80
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
81
|
-
string memory network_name,
|
|
75
|
+
string memory projectName,
|
|
76
|
+
string memory networkName,
|
|
82
77
|
string memory contractName
|
|
83
78
|
)
|
|
84
79
|
internal
|
|
@@ -87,7 +82,7 @@ library RevnetCoreDeploymentLib {
|
|
|
87
82
|
{
|
|
88
83
|
string memory deploymentJson =
|
|
89
84
|
// forge-lint: disable-next-line(unsafe-cheatcode)
|
|
90
|
-
vm.readFile(string.concat(path,
|
|
85
|
+
vm.readFile(string.concat(path, projectName, "/", networkName, "/", contractName, ".json"));
|
|
91
86
|
return stdJson.readAddress({json: deploymentJson, key: ".address"});
|
|
92
87
|
}
|
|
93
88
|
}
|