@rev-net/core-v6 0.0.1

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.
Files changed (92) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +65 -0
  3. package/REVNET_SECURITY_CHECKLIST.md +164 -0
  4. package/SECURITY.md +68 -0
  5. package/SKILLS.md +166 -0
  6. package/deployments/revnet-core-v5/arbitrum/REVDeployer.json +2821 -0
  7. package/deployments/revnet-core-v5/arbitrum/REVLoans.json +2260 -0
  8. package/deployments/revnet-core-v5/arbitrum_sepolia/REVDeployer.json +2821 -0
  9. package/deployments/revnet-core-v5/arbitrum_sepolia/REVLoans.json +2260 -0
  10. package/deployments/revnet-core-v5/base/REVDeployer.json +2825 -0
  11. package/deployments/revnet-core-v5/base/REVLoans.json +2264 -0
  12. package/deployments/revnet-core-v5/base_sepolia/REVDeployer.json +2825 -0
  13. package/deployments/revnet-core-v5/base_sepolia/REVLoans.json +2264 -0
  14. package/deployments/revnet-core-v5/ethereum/REVDeployer.json +2825 -0
  15. package/deployments/revnet-core-v5/ethereum/REVLoans.json +2264 -0
  16. package/deployments/revnet-core-v5/optimism/REVDeployer.json +2821 -0
  17. package/deployments/revnet-core-v5/optimism/REVLoans.json +2260 -0
  18. package/deployments/revnet-core-v5/optimism_sepolia/REVDeployer.json +2825 -0
  19. package/deployments/revnet-core-v5/optimism_sepolia/REVLoans.json +2264 -0
  20. package/deployments/revnet-core-v5/sepolia/REVDeployer.json +2825 -0
  21. package/deployments/revnet-core-v5/sepolia/REVLoans.json +2264 -0
  22. package/docs/book.css +13 -0
  23. package/docs/book.toml +13 -0
  24. package/docs/solidity.min.js +74 -0
  25. package/docs/src/README.md +88 -0
  26. package/docs/src/SUMMARY.md +20 -0
  27. package/docs/src/src/README.md +7 -0
  28. package/docs/src/src/REVDeployer.sol/contract.REVDeployer.md +968 -0
  29. package/docs/src/src/REVLoans.sol/contract.REVLoans.md +1047 -0
  30. package/docs/src/src/interfaces/IREVDeployer.sol/interface.IREVDeployer.md +243 -0
  31. package/docs/src/src/interfaces/IREVLoans.sol/interface.IREVLoans.md +296 -0
  32. package/docs/src/src/interfaces/README.md +5 -0
  33. package/docs/src/src/structs/README.md +14 -0
  34. package/docs/src/src/structs/REVAutoIssuance.sol/struct.REVAutoIssuance.md +19 -0
  35. package/docs/src/src/structs/REVBuybackHookConfig.sol/struct.REVBuybackHookConfig.md +19 -0
  36. package/docs/src/src/structs/REVBuybackPoolConfig.sol/struct.REVBuybackPoolConfig.md +21 -0
  37. package/docs/src/src/structs/REVConfig.sol/struct.REVConfig.md +35 -0
  38. package/docs/src/src/structs/REVCroptopAllowedPost.sol/struct.REVCroptopAllowedPost.md +28 -0
  39. package/docs/src/src/structs/REVDeploy721TiersHookConfig.sol/struct.REVDeploy721TiersHookConfig.md +34 -0
  40. package/docs/src/src/structs/REVDescription.sol/struct.REVDescription.md +23 -0
  41. package/docs/src/src/structs/REVLoan.sol/struct.REVLoan.md +28 -0
  42. package/docs/src/src/structs/REVLoanSource.sol/struct.REVLoanSource.md +16 -0
  43. package/docs/src/src/structs/REVStageConfig.sol/struct.REVStageConfig.md +44 -0
  44. package/docs/src/src/structs/REVSuckerDeploymentConfig.sol/struct.REVSuckerDeploymentConfig.md +16 -0
  45. package/foundry.lock +11 -0
  46. package/foundry.toml +23 -0
  47. package/package.json +31 -0
  48. package/remappings.txt +1 -0
  49. package/script/Deploy.s.sol +350 -0
  50. package/script/helpers/RevnetCoreDeploymentLib.sol +72 -0
  51. package/slither-ci.config.json +10 -0
  52. package/sphinx.lock +507 -0
  53. package/src/REVDeployer.sol +1257 -0
  54. package/src/REVLoans.sol +1333 -0
  55. package/src/interfaces/IREVDeployer.sol +198 -0
  56. package/src/interfaces/IREVLoans.sol +241 -0
  57. package/src/structs/REVAutoIssuance.sol +11 -0
  58. package/src/structs/REVConfig.sol +17 -0
  59. package/src/structs/REVCroptopAllowedPost.sol +20 -0
  60. package/src/structs/REVDeploy721TiersHookConfig.sol +25 -0
  61. package/src/structs/REVDescription.sol +14 -0
  62. package/src/structs/REVLoan.sol +19 -0
  63. package/src/structs/REVLoanSource.sol +11 -0
  64. package/src/structs/REVStageConfig.sol +34 -0
  65. package/src/structs/REVSuckerDeploymentConfig.sol +11 -0
  66. package/test/REV.integrations.t.sol +420 -0
  67. package/test/REVAutoIssuanceFuzz.t.sol +276 -0
  68. package/test/REVDeployerAuditRegressions.t.sol +328 -0
  69. package/test/REVInvincibility.t.sol +1275 -0
  70. package/test/REVInvincibilityHandler.sol +357 -0
  71. package/test/REVLifecycle.t.sol +364 -0
  72. package/test/REVLoans.invariants.t.sol +642 -0
  73. package/test/REVLoansAttacks.t.sol +739 -0
  74. package/test/REVLoansAuditRegressions.t.sol +314 -0
  75. package/test/REVLoansFeeRecovery.t.sol +704 -0
  76. package/test/REVLoansSourced.t.sol +1732 -0
  77. package/test/REVLoansUnSourced.t.sol +331 -0
  78. package/test/TestPR09_ConversionDocumentation.t.sol +304 -0
  79. package/test/TestPR10_LiquidationBehavior.t.sol +340 -0
  80. package/test/TestPR11_LowFindings.t.sol +571 -0
  81. package/test/TestPR12_FlashLoanSurplus.t.sol +305 -0
  82. package/test/TestPR13_CrossSourceReallocation.t.sol +302 -0
  83. package/test/TestPR15_CashOutCallerValidation.t.sol +320 -0
  84. package/test/TestPR16_ZeroRepayment.t.sol +297 -0
  85. package/test/TestPR21_Uint112Overflow.t.sol +251 -0
  86. package/test/TestPR22_HookArrayOOB.t.sol +221 -0
  87. package/test/TestPR26_BurnHeldTokens.t.sol +331 -0
  88. package/test/TestPR27_CEIPattern.t.sol +448 -0
  89. package/test/TestPR29_SwapTerminalPermission.t.sol +206 -0
  90. package/test/TestPR32_MixedFixes.t.sol +529 -0
  91. package/test/helpers/MaliciousContracts.sol +233 -0
  92. package/test/mock/MockBuybackDataHook.sol +61 -0
@@ -0,0 +1,23 @@
1
+ # REVDescription
2
+ [Git Source](https://github.com/rev-net/revnet-core-v5/blob/364afaae78a8f60af2b98252dc96af1c2e4760d3/src/structs/REVDescription.sol)
3
+
4
+ **Notes:**
5
+ - member: name The name of the ERC-20 token being create for the revnet.
6
+
7
+ - member: ticker The ticker of the ERC-20 token being created for the revnet.
8
+
9
+ - member: uri The metadata URI containing revnet's info.
10
+
11
+ - member: salt Revnets deployed across chains by the same address with the same salt will have the same
12
+ address.
13
+
14
+
15
+ ```solidity
16
+ struct REVDescription {
17
+ string name;
18
+ string ticker;
19
+ string uri;
20
+ bytes32 salt;
21
+ }
22
+ ```
23
+
@@ -0,0 +1,28 @@
1
+ # REVLoan
2
+ [Git Source](https://github.com/rev-net/revnet-core-v5/blob/364afaae78a8f60af2b98252dc96af1c2e4760d3/src/structs/REVLoan.sol)
3
+
4
+ **Notes:**
5
+ - member: borrowedAmount The amount that is being borrowed.
6
+
7
+ - member: collateralTokenCount The number of collateral tokens currently accounted for.
8
+
9
+ - member: createdAt The timestamp when the loan was created.
10
+
11
+ - member: prepaidFeePercent The percentage of the loan's fees that were prepaid.
12
+
13
+ - member: prepaidDuration The duration that the loan was prepaid for.
14
+
15
+ - member: source The source of the loan.
16
+
17
+
18
+ ```solidity
19
+ struct REVLoan {
20
+ uint112 amount;
21
+ uint112 collateral;
22
+ uint48 createdAt;
23
+ uint16 prepaidFeePercent;
24
+ uint32 prepaidDuration;
25
+ REVLoanSource source;
26
+ }
27
+ ```
28
+
@@ -0,0 +1,16 @@
1
+ # REVLoanSource
2
+ [Git Source](https://github.com/rev-net/revnet-core-v5/blob/364afaae78a8f60af2b98252dc96af1c2e4760d3/src/structs/REVLoanSource.sol)
3
+
4
+ **Notes:**
5
+ - member: token The token that is being loaned.
6
+
7
+ - member: terminal The terminal that the loan is being made from.
8
+
9
+
10
+ ```solidity
11
+ struct REVLoanSource {
12
+ address token;
13
+ IJBPayoutTerminal terminal;
14
+ }
15
+ ```
16
+
@@ -0,0 +1,44 @@
1
+ # REVStageConfig
2
+ [Git Source](https://github.com/rev-net/revnet-core-v5/blob/364afaae78a8f60af2b98252dc96af1c2e4760d3/src/structs/REVStageConfig.sol)
3
+
4
+ **Notes:**
5
+ - member: startsAtOrAfter The timestamp to start a stage at the given rate at or after.
6
+
7
+ - member: autoIssuances The configurations of mints during this stage.
8
+
9
+ - member: splitPercent The percentage of newly issued tokens that should be split with the operator, out
10
+ of 10_000 (JBConstants.MAX_RESERVED_PERCENT).
11
+
12
+ - member: splits The splits for the revnet.
13
+
14
+ - member: initialIssuance The number of revnet tokens that one unit of the revnet's base currency will buy, as
15
+ a fixed point number
16
+ with 18 decimals.
17
+
18
+ - member: issuanceCutFrequency The number of seconds between applied issuance decreases. This
19
+ should be at least 24 hours.
20
+
21
+ - member: issuanceCutPercent The percent that issuance should decrease over time. This percentage is out
22
+ of 1_000_000_000 (JBConstants.MAX_CUT_PERCENT). 0% corresponds to no issuance increase.
23
+
24
+ - member: cashOutTaxRate The factor determining how much each token can cash out from the revnet once
25
+ cashed out. This rate is out of 10_000 (JBConstants.MAX_CASH_OUT_TAX_RATE). 0% corresponds to no tax when cashing
26
+ out.
27
+
28
+ - member: extraMetadata Extra info to attach set into this stage that may affect hooks.
29
+
30
+
31
+ ```solidity
32
+ struct REVStageConfig {
33
+ uint48 startsAtOrAfter;
34
+ REVAutoIssuance[] autoIssuances;
35
+ uint16 splitPercent;
36
+ JBSplit[] splits;
37
+ uint112 initialIssuance;
38
+ uint32 issuanceCutFrequency;
39
+ uint32 issuanceCutPercent;
40
+ uint16 cashOutTaxRate;
41
+ uint16 extraMetadata;
42
+ }
43
+ ```
44
+
@@ -0,0 +1,16 @@
1
+ # REVSuckerDeploymentConfig
2
+ [Git Source](https://github.com/rev-net/revnet-core-v5/blob/364afaae78a8f60af2b98252dc96af1c2e4760d3/src/structs/REVSuckerDeploymentConfig.sol)
3
+
4
+ **Notes:**
5
+ - member: deployerConfigurations The information for how to suck tokens to other chains.
6
+
7
+ - member: salt The salt to use for creating suckers so that they use the same address across chains.
8
+
9
+
10
+ ```solidity
11
+ struct REVSuckerDeploymentConfig {
12
+ JBSuckerDeployerConfig[] deployerConfigurations;
13
+ bytes32 salt;
14
+ }
15
+ ```
16
+
package/foundry.lock ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "lib/forge-std": {
3
+ "rev": "83c5d212a01f8950727da4095cdfe2654baccb5b"
4
+ },
5
+ "lib/sphinx": {
6
+ "branch": {
7
+ "name": "v0.23.0",
8
+ "rev": "5fb24a825f46bd6ae0b5359fe0da1d2346126b09"
9
+ }
10
+ }
11
+ }
package/foundry.toml ADDED
@@ -0,0 +1,23 @@
1
+ [profile.default]
2
+ solc = '0.8.23'
3
+ evm_version = 'paris'
4
+ optimizer_runs = 500
5
+ libs = ["node_modules", "lib"]
6
+ fs_permissions = [{ access = "read-write", path = "./"}]
7
+
8
+ [profile.ci_sizes]
9
+ optimizer_runs = 200
10
+ via_ir = true
11
+
12
+ [fuzz]
13
+ runs = 4096
14
+
15
+ [invariant]
16
+ runs = 1024
17
+ depth = 100
18
+ fail_on_revert = false
19
+
20
+ [fmt]
21
+ number_underscore = "thousands"
22
+ multiline_func_header = "all"
23
+ wrap_comments = true
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@rev-net/core-v6",
3
+ "version": "0.0.1",
4
+ "license": "MIT",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/rev-net/revnet-core-v6"
8
+ },
9
+ "scripts": {
10
+ "test": "forge test",
11
+ "coverage:integration": "forge coverage --match-path \"./src/*.sol\" --report lcov --report summary",
12
+ "deploy:mainnets": "source ./.env && export START_TIME=$(date +%s) && npx sphinx propose ./script/Deploy.s.sol --networks mainnets",
13
+ "deploy:mainnets:1_1": "source ./.env && npx sphinx propose ./script/Deploy1_1.s.sol --networks mainnets",
14
+ "deploy:testnets": "source ./.env && export START_TIME=$(date +%s) && npx sphinx propose ./script/Deploy.s.sol --networks testnets",
15
+ "deploy:testnets:1_1": "source ./.env && npx sphinx propose ./script/Deploy1_1.s.sol --networks testnets",
16
+ "artifacts": "source ./.env && npx sphinx artifacts --org-id 'ea165b21-7cdc-4d7b-be59-ecdd4c26bee4' --project-name 'revnet-core-v6'"
17
+ },
18
+ "dependencies": {
19
+ "@bananapus/721-hook-v6": "^0.0.2",
20
+ "@bananapus/buyback-hook-v6": "^0.0.1",
21
+ "@bananapus/core-v6": "^0.0.3",
22
+ "@bananapus/permission-ids-v6": "^0.0.1",
23
+ "@bananapus/suckers-v6": "^0.0.1",
24
+ "@bananapus/swap-terminal-v6": "^0.0.2",
25
+ "@croptop/core-v6": "^0.0.3",
26
+ "@openzeppelin/contracts": "^5.2.0"
27
+ },
28
+ "devDependencies": {
29
+ "@sphinx-labs/plugins": "^0.33.1"
30
+ }
31
+ }
package/remappings.txt ADDED
@@ -0,0 +1 @@
1
+ @sphinx-labs/contracts/=node_modules/@sphinx-labs/contracts/contracts/foundry
@@ -0,0 +1,350 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.23;
3
+
4
+ import "@bananapus/721-hook-v6/script/helpers/Hook721DeploymentLib.sol";
5
+ import "@bananapus/buyback-hook-v6/script/helpers/BuybackDeploymentLib.sol";
6
+ import "@bananapus/core-v6/script/helpers/CoreDeploymentLib.sol";
7
+ import "@bananapus/suckers-v6/script/helpers/SuckerDeploymentLib.sol";
8
+ import "@bananapus/swap-terminal-v6/script/helpers/SwapTerminalDeploymentLib.sol";
9
+ import "@croptop/core-v6/script/helpers/CroptopDeploymentLib.sol";
10
+
11
+ import {Sphinx} from "@sphinx-labs/contracts/SphinxPlugin.sol";
12
+ import {Script} from "forge-std/Script.sol";
13
+
14
+ import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
15
+ import {JBCurrencyIds} from "@bananapus/core-v6/src/libraries/JBCurrencyIds.sol";
16
+ import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
17
+ import {JBTerminalConfig} from "@bananapus/core-v6/src/structs/JBTerminalConfig.sol";
18
+ import {JBSuckerDeployerConfig} from "@bananapus/suckers-v6/src/structs/JBSuckerDeployerConfig.sol";
19
+ import {JBTokenMapping} from "@bananapus/suckers-v6/src/structs/JBTokenMapping.sol";
20
+ import {IPermit2} from "@uniswap/permit2/src/interfaces/IPermit2.sol";
21
+ import {IJBSplitHook} from "@bananapus/core-v6/src/interfaces/IJBSplitHook.sol";
22
+ import {IJBTerminal} from "@bananapus/core-v6/src/interfaces/IJBTerminal.sol";
23
+ import {IJBRulesetDataHook} from "@bananapus/core-v6/src/interfaces/IJBRulesetDataHook.sol";
24
+ import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
25
+
26
+ import {REVDeployer} from "./../src/REVDeployer.sol";
27
+ import {REVAutoIssuance} from "../src/structs/REVAutoIssuance.sol";
28
+ import {REVConfig} from "../src/structs/REVConfig.sol";
29
+ import {REVDescription} from "../src/structs/REVDescription.sol";
30
+ import {REVStageConfig} from "../src/structs/REVStageConfig.sol";
31
+ import {REVSuckerDeploymentConfig} from "../src/structs/REVSuckerDeploymentConfig.sol";
32
+ import {REVLoans, IREVLoans} from "./../src/REVLoans.sol";
33
+
34
+ struct FeeProjectConfig {
35
+ REVConfig configuration;
36
+ JBTerminalConfig[] terminalConfigurations;
37
+ REVSuckerDeploymentConfig suckerDeploymentConfiguration;
38
+ }
39
+
40
+ contract DeployScript is Script, Sphinx {
41
+ /// @notice tracks the deployment of the buyback hook.
42
+ BuybackDeployment buybackHook;
43
+ /// @notice tracks the deployment of the core contracts for the chain we are deploying to.
44
+ CoreDeployment core;
45
+ /// @notice tracks the deployment of the croptop contracts for the chain we are deploying to.
46
+ CroptopDeployment croptop;
47
+ /// @notice tracks the deployment of the 721 hook contracts for the chain we are deploying to.
48
+ Hook721Deployment hook;
49
+ /// @notice tracks the deployment of the sucker contracts for the chain we are deploying to.
50
+ SuckerDeployment suckers;
51
+ /// @notice tracks the deployment of the swap terminal.
52
+ SwapTerminalDeployment swapTerminal;
53
+
54
+ uint32 PREMINT_CHAIN_ID = 1;
55
+ string NAME = "Revnet";
56
+ string SYMBOL = "REV";
57
+ string PROJECT_URI = "ipfs://QmcCBD5fM927LjkLDSJWtNEU9FohcbiPSfqtGRHXFHzJ4W";
58
+ uint32 NATIVE_CURRENCY = uint32(uint160(JBConstants.NATIVE_TOKEN));
59
+ uint32 ETH_CURRENCY = JBCurrencyIds.ETH;
60
+ uint8 DECIMALS = 18;
61
+ uint256 DECIMAL_MULTIPLIER = 10 ** DECIMALS;
62
+ bytes32 ERC20_SALT = "_REV_ERC20_SALT_V6_";
63
+ bytes32 SUCKER_SALT = "_REV_SUCKER_SALT_V6_";
64
+ bytes32 DEPLOYER_SALT = "_REV_DEPLOYER_SALT_V6_";
65
+ bytes32 REVLOANS_SALT = "_REV_LOANS_SALT_V6_";
66
+ address LOANS_OWNER;
67
+ address OPERATOR;
68
+ address TRUSTED_FORWARDER;
69
+ IPermit2 PERMIT2;
70
+ uint48 REV_START_TIME = 1_740_089_444;
71
+ uint104 REV_MAINNET_AUTO_ISSUANCE_ = 1_050_482_341_387_116_262_330_122;
72
+ uint104 REV_BASE_AUTO_ISSUANCE_ = 38_544_322_230_437_559_731_228;
73
+ uint104 REV_OP_AUTO_ISSUANCE_ = 32_069_388_242_375_817_844;
74
+ uint104 REV_ARB_AUTO_ISSUANCE_ = 3_479_431_776_906_850_000_000;
75
+
76
+ function configureSphinx() public override {
77
+ // TODO: Update to contain revnet devs.
78
+ sphinxConfig.projectName = "revnet-core-v6";
79
+ sphinxConfig.mainnets = ["ethereum", "optimism", "base", "arbitrum"];
80
+ sphinxConfig.testnets = ["ethereum_sepolia", "optimism_sepolia", "base_sepolia", "arbitrum_sepolia"];
81
+ }
82
+
83
+ function run() public {
84
+ // Get the operator address.
85
+ OPERATOR = safeAddress();
86
+ // Get the loans owner address.
87
+ LOANS_OWNER = safeAddress();
88
+
89
+ // Get the deployment addresses for the nana CORE for this chain.
90
+ // We want to do this outside of the `sphinx` modifier.
91
+ core = CoreDeploymentLib.getDeployment(
92
+ vm.envOr("NANA_CORE_DEPLOYMENT_PATH", string("node_modules/@bananapus/core-v6/deployments/"))
93
+ );
94
+ // Get the deployment addresses for the suckers contracts for this chain.
95
+ suckers = SuckerDeploymentLib.getDeployment(
96
+ vm.envOr("NANA_SUCKERS_DEPLOYMENT_PATH", string("node_modules/@bananapus/suckers-v6/deployments/"))
97
+ );
98
+ // Get the deployment addresses for the 721 hook contracts for this chain.
99
+ croptop = CroptopDeploymentLib.getDeployment(
100
+ vm.envOr("CROPTOP_CORE_DEPLOYMENT_PATH", string("node_modules/@croptop/core-v6/deployments/"))
101
+ );
102
+ // Get the deployment addresses for the 721 hook contracts for this chain.
103
+ hook = Hook721DeploymentLib.getDeployment(
104
+ vm.envOr("NANA_721_DEPLOYMENT_PATH", string("node_modules/@bananapus/721-hook-v6/deployments/"))
105
+ );
106
+ // Get the deployment addresses for the 721 hook contracts for this chain.
107
+ swapTerminal = SwapTerminalDeploymentLib.getDeployment(
108
+ vm.envOr(
109
+ "NANA_SWAP_TERMINAL_DEPLOYMENT_PATH", string("node_modules/@bananapus/swap-terminal-v6/deployments/")
110
+ )
111
+ );
112
+ // Get the deployment addresses for the 721 hook contracts for this chain.
113
+ buybackHook = BuybackDeploymentLib.getDeployment(
114
+ vm.envOr(
115
+ "NANA_BUYBACK_HOOK_DEPLOYMENT_PATH", string("node_modules/@bananapus/buyback-hook-v6/deployments/")
116
+ )
117
+ );
118
+
119
+ // We use the same trusted forwarder and permit2 as the core deployment.
120
+ TRUSTED_FORWARDER = core.controller.trustedForwarder();
121
+ PERMIT2 = core.terminal.PERMIT2();
122
+
123
+ // Perform the deployment transactions.
124
+ deploy();
125
+ }
126
+
127
+ function getFeeProjectConfig() internal view returns (FeeProjectConfig memory) {
128
+ // The tokens that the project accepts and stores.
129
+ JBAccountingContext[] memory accountingContextsToAccept = new JBAccountingContext[](1);
130
+
131
+ // Accept the chain's native currency through the multi terminal.
132
+ accountingContextsToAccept[0] =
133
+ JBAccountingContext({token: JBConstants.NATIVE_TOKEN, decimals: DECIMALS, currency: NATIVE_CURRENCY});
134
+
135
+ // The terminals that the project will accept funds through.
136
+ JBTerminalConfig[] memory terminalConfigurations = new JBTerminalConfig[](2);
137
+ terminalConfigurations[0] =
138
+ JBTerminalConfig({terminal: core.terminal, accountingContextsToAccept: accountingContextsToAccept});
139
+ terminalConfigurations[1] = JBTerminalConfig({
140
+ terminal: IJBTerminal(address(swapTerminal.native_registry)),
141
+ accountingContextsToAccept: new JBAccountingContext[](0)
142
+ });
143
+
144
+ // The project's revnet stage configurations.
145
+ REVStageConfig[] memory stageConfigurations = new REVStageConfig[](3);
146
+
147
+ // Create a split group that assigns all of the splits to the operator.
148
+ JBSplit[] memory splits = new JBSplit[](1);
149
+ splits[0] = JBSplit({
150
+ preferAddToBalance: false,
151
+ percent: JBConstants.SPLITS_TOTAL_PERCENT,
152
+ projectId: 0,
153
+ beneficiary: payable(OPERATOR),
154
+ lockedUntil: 0,
155
+ hook: IJBSplitHook(address(0))
156
+ });
157
+
158
+ {
159
+ REVAutoIssuance[] memory issuanceConfs = new REVAutoIssuance[](4);
160
+ issuanceConfs[0] = REVAutoIssuance({chainId: 1, count: REV_MAINNET_AUTO_ISSUANCE_, beneficiary: OPERATOR});
161
+ issuanceConfs[1] = REVAutoIssuance({chainId: 8453, count: REV_BASE_AUTO_ISSUANCE_, beneficiary: OPERATOR});
162
+ issuanceConfs[2] = REVAutoIssuance({chainId: 10, count: REV_OP_AUTO_ISSUANCE_, beneficiary: OPERATOR});
163
+ issuanceConfs[3] = REVAutoIssuance({chainId: 42_161, count: REV_ARB_AUTO_ISSUANCE_, beneficiary: OPERATOR});
164
+
165
+ stageConfigurations[0] = REVStageConfig({
166
+ startsAtOrAfter: REV_START_TIME,
167
+ autoIssuances: issuanceConfs,
168
+ splitPercent: 3800, // 38%
169
+ splits: splits,
170
+ initialIssuance: uint112(10_000 * DECIMAL_MULTIPLIER),
171
+ issuanceCutFrequency: 90 days,
172
+ issuanceCutPercent: 380_000_000, // 38%
173
+ cashOutTaxRate: 1000, // 0.1
174
+ extraMetadata: 4 // Allow adding suckers.
175
+ });
176
+ }
177
+
178
+ {
179
+ REVAutoIssuance[] memory issuanceConfs = new REVAutoIssuance[](1);
180
+ issuanceConfs[0] = REVAutoIssuance({
181
+ chainId: PREMINT_CHAIN_ID, count: uint104(1_550_000 * DECIMAL_MULTIPLIER), beneficiary: OPERATOR
182
+ });
183
+
184
+ stageConfigurations[1] = REVStageConfig({
185
+ startsAtOrAfter: uint40(stageConfigurations[0].startsAtOrAfter + 720 days),
186
+ autoIssuances: issuanceConfs,
187
+ splitPercent: 3800, // 38%
188
+ splits: splits,
189
+ initialIssuance: 1, // inherit from previous cycle.
190
+ issuanceCutFrequency: 30 days,
191
+ issuanceCutPercent: 70_000_000, // 7%
192
+ cashOutTaxRate: 1000, // 0.1
193
+ extraMetadata: 4 // Allow adding suckers.
194
+ });
195
+ }
196
+
197
+ stageConfigurations[2] = REVStageConfig({
198
+ startsAtOrAfter: uint40(stageConfigurations[1].startsAtOrAfter + 3600 days),
199
+ autoIssuances: new REVAutoIssuance[](0),
200
+ splitPercent: 3800, // 38%
201
+ splits: splits,
202
+ initialIssuance: 0, // no more issaunce.
203
+ issuanceCutFrequency: 0,
204
+ issuanceCutPercent: 0,
205
+ cashOutTaxRate: 1000, // 0.1
206
+ extraMetadata: 4 // Allow adding suckers.
207
+ });
208
+
209
+ // The project's revnet configuration
210
+ REVConfig memory revnetConfiguration = REVConfig({
211
+ description: REVDescription(NAME, SYMBOL, PROJECT_URI, ERC20_SALT),
212
+ baseCurrency: ETH_CURRENCY,
213
+ splitOperator: OPERATOR,
214
+ stageConfigurations: stageConfigurations
215
+ });
216
+
217
+ // Organize the instructions for how this project will connect to other chains.
218
+ JBTokenMapping[] memory tokenMappings = new JBTokenMapping[](1);
219
+ tokenMappings[0] = JBTokenMapping({
220
+ localToken: JBConstants.NATIVE_TOKEN,
221
+ remoteToken: bytes32(uint256(uint160(JBConstants.NATIVE_TOKEN))),
222
+ minGas: 200_000,
223
+ minBridgeAmount: 0.01 ether
224
+ });
225
+
226
+ REVSuckerDeploymentConfig memory suckerDeploymentConfiguration;
227
+
228
+ {
229
+ JBSuckerDeployerConfig[] memory suckerDeployerConfigurations;
230
+ if (block.chainid == 1 || block.chainid == 11_155_111) {
231
+ suckerDeployerConfigurations = new JBSuckerDeployerConfig[](3);
232
+ // OP
233
+ suckerDeployerConfigurations[0] =
234
+ JBSuckerDeployerConfig({deployer: suckers.optimismDeployer, mappings: tokenMappings});
235
+
236
+ suckerDeployerConfigurations[1] =
237
+ JBSuckerDeployerConfig({deployer: suckers.baseDeployer, mappings: tokenMappings});
238
+
239
+ suckerDeployerConfigurations[2] =
240
+ JBSuckerDeployerConfig({deployer: suckers.arbitrumDeployer, mappings: tokenMappings});
241
+ } else {
242
+ suckerDeployerConfigurations = new JBSuckerDeployerConfig[](1);
243
+ // L2 -> Mainnet
244
+ suckerDeployerConfigurations[0] = JBSuckerDeployerConfig({
245
+ deployer: address(suckers.optimismDeployer) != address(0)
246
+ ? suckers.optimismDeployer
247
+ : address(suckers.baseDeployer) != address(0) ? suckers.baseDeployer : suckers.arbitrumDeployer,
248
+ mappings: tokenMappings
249
+ });
250
+
251
+ if (address(suckerDeployerConfigurations[0].deployer) == address(0)) {
252
+ revert("L2 > L1 Sucker is not configured");
253
+ }
254
+ }
255
+ // Specify all sucker deployments.
256
+ suckerDeploymentConfiguration =
257
+ REVSuckerDeploymentConfig({deployerConfigurations: suckerDeployerConfigurations, salt: SUCKER_SALT});
258
+ }
259
+
260
+ return FeeProjectConfig({
261
+ configuration: revnetConfiguration,
262
+ terminalConfigurations: terminalConfigurations,
263
+ suckerDeploymentConfiguration: suckerDeploymentConfiguration
264
+ });
265
+ }
266
+
267
+ function deploy() public sphinx {
268
+ // TODO figure out how to reference project ID if the contracts are already deployed.
269
+ uint256 FEE_PROJECT_ID = core.projects.createFor(safeAddress());
270
+
271
+ // Deploy REVLoans first — it only depends on the controller.
272
+ (address _revloansAddr, bool _revloansIsDeployed) = _isDeployed(
273
+ REVLOANS_SALT,
274
+ type(REVLoans).creationCode,
275
+ abi.encode(core.controller, core.projects, FEE_PROJECT_ID, LOANS_OWNER, PERMIT2, TRUSTED_FORWARDER)
276
+ );
277
+ REVLoans revloans = _revloansIsDeployed
278
+ ? REVLoans(payable(_revloansAddr))
279
+ : new REVLoans{salt: REVLOANS_SALT}({
280
+ controller: core.controller,
281
+ projects: core.projects,
282
+ revId: FEE_PROJECT_ID,
283
+ owner: LOANS_OWNER,
284
+ permit2: PERMIT2,
285
+ trustedForwarder: TRUSTED_FORWARDER
286
+ });
287
+
288
+ // Deploy REVDeployer with the REVLoans and buyback hook addresses.
289
+ (address _deployerAddr, bool _deployerIsDeployed) = _isDeployed(
290
+ DEPLOYER_SALT,
291
+ type(REVDeployer).creationCode,
292
+ abi.encode(
293
+ core.controller,
294
+ suckers.registry,
295
+ FEE_PROJECT_ID,
296
+ hook.hook_deployer,
297
+ croptop.publisher,
298
+ IJBRulesetDataHook(address(buybackHook.registry)),
299
+ address(revloans),
300
+ TRUSTED_FORWARDER
301
+ )
302
+ );
303
+ REVDeployer _basicDeployer = _deployerIsDeployed
304
+ ? REVDeployer(payable(_deployerAddr))
305
+ : new REVDeployer{salt: DEPLOYER_SALT}(
306
+ core.controller,
307
+ suckers.registry,
308
+ FEE_PROJECT_ID,
309
+ hook.hook_deployer,
310
+ croptop.publisher,
311
+ IJBRulesetDataHook(address(buybackHook.registry)),
312
+ address(revloans),
313
+ TRUSTED_FORWARDER
314
+ );
315
+
316
+ // Approve the basic deployer to configure the project.
317
+ core.projects.approve(address(_basicDeployer), FEE_PROJECT_ID);
318
+
319
+ // Build the config.
320
+ FeeProjectConfig memory feeProjectConfig = getFeeProjectConfig();
321
+
322
+ // Configure the project.
323
+ _basicDeployer.deployFor({
324
+ revnetId: FEE_PROJECT_ID,
325
+ configuration: feeProjectConfig.configuration,
326
+ terminalConfigurations: feeProjectConfig.terminalConfigurations,
327
+ suckerDeploymentConfiguration: feeProjectConfig.suckerDeploymentConfiguration
328
+ });
329
+ }
330
+
331
+ function _isDeployed(
332
+ bytes32 salt,
333
+ bytes memory creationCode,
334
+ bytes memory arguments
335
+ )
336
+ internal
337
+ view
338
+ returns (address deployedTo, bool isDeployed)
339
+ {
340
+ address _deployedTo = vm.computeCreate2Address({
341
+ salt: salt,
342
+ initCodeHash: keccak256(abi.encodePacked(creationCode, arguments)),
343
+ // Arachnid/deterministic-deployment-proxy address.
344
+ deployer: address(0x4e59b44847b379578588920cA78FbF26c0B4956C)
345
+ });
346
+
347
+ // Return if code is already present at this address.
348
+ return (_deployedTo, address(_deployedTo).code.length != 0);
349
+ }
350
+ }
@@ -0,0 +1,72 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.23;
3
+
4
+ import {stdJson} from "forge-std/Script.sol";
5
+ import {Vm} from "forge-std/Vm.sol";
6
+ import {SphinxConstants, NetworkInfo} from "@sphinx-labs/contracts/SphinxConstants.sol";
7
+
8
+ import {IREVDeployer} from "./../../src/interfaces/IREVDeployer.sol";
9
+ import {IREVLoans} from "./../../src/interfaces/IREVLoans.sol";
10
+
11
+ struct RevnetCoreDeployment {
12
+ IREVDeployer basic_deployer;
13
+ IREVLoans loans;
14
+ }
15
+
16
+ library RevnetCoreDeploymentLib {
17
+ // Cheat code address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D.
18
+ address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code"))));
19
+ Vm internal constant vm = Vm(VM_ADDRESS);
20
+
21
+ function getDeployment(string memory path) internal returns (RevnetCoreDeployment memory deployment) {
22
+ // get chainId for which we need to get the deployment.
23
+ uint256 chainId = block.chainid;
24
+
25
+ // Deploy to get the constants.
26
+ // TODO: get constants without deploy.
27
+ SphinxConstants sphinxConstants = new SphinxConstants();
28
+ NetworkInfo[] memory networks = sphinxConstants.getNetworkInfoArray();
29
+
30
+ for (uint256 _i; _i < networks.length; _i++) {
31
+ if (networks[_i].chainId == chainId) {
32
+ return getDeployment(path, networks[_i].name);
33
+ }
34
+ }
35
+
36
+ revert("ChainID is not (currently) supported by Sphinx.");
37
+ }
38
+
39
+ function getDeployment(
40
+ string memory path,
41
+ string memory network_name
42
+ )
43
+ internal
44
+ view
45
+ returns (RevnetCoreDeployment memory deployment)
46
+ {
47
+ deployment.basic_deployer =
48
+ IREVDeployer(_getDeploymentAddress(path, "revnet-core-v6", network_name, "REVDeployer"));
49
+
50
+ deployment.loans = IREVLoans(_getDeploymentAddress(path, "revnet-core-v6", network_name, "REVLoans"));
51
+ }
52
+
53
+ /// @notice Get the address of a contract that was deployed by the Deploy script.
54
+ /// @dev Reverts if the contract was not found.
55
+ /// @param path The path to the deployment file.
56
+ /// @param contractName The name of the contract to get the address of.
57
+ /// @return The address of the contract.
58
+ function _getDeploymentAddress(
59
+ string memory path,
60
+ string memory project_name,
61
+ string memory network_name,
62
+ string memory contractName
63
+ )
64
+ internal
65
+ view
66
+ returns (address)
67
+ {
68
+ string memory deploymentJson =
69
+ vm.readFile(string.concat(path, project_name, "/", network_name, "/", contractName, ".json"));
70
+ return stdJson.readAddress(deploymentJson, ".address");
71
+ }
72
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "detectors_to_exclude": "timestamp,uninitialized-local,naming-convention,solc-version,shadowing-local",
3
+ "exclude_informational": true,
4
+ "exclude_low": false,
5
+ "exclude_medium": false,
6
+ "exclude_high": false,
7
+ "disable_color": false,
8
+ "filter_paths": "(mocks/|test/|node_modules/)",
9
+ "legacy_ast": false
10
+ }