├── .github ├── ISSUE_TEMPLATE │ └── security-review-issue-template.md └── workflows │ └── ci.yml ├── .gitignore ├── .gitmodules ├── .vscode └── settings.json ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── SECURITY.md ├── assets └── logo_circle.svg ├── audits ├── 2024-06-19-macro.pdf ├── 2024-07-29-team-omega-issuance-token.pdf ├── 2024-08-12-hats.pdf └── README.md ├── dev.env ├── foundry.toml ├── remappings.txt ├── script ├── README.md ├── deploymentScript │ ├── DeploymentScript.s.sol │ └── TestnetDeploymentScript.s.sol ├── deploymentSuite │ ├── MetadataCollection_v1.s.sol │ ├── ModuleBeaconDeployer_v1.s.sol │ ├── ProtocolConstants_v1.s.sol │ ├── ProxyAndBeaconDeployer_v1.s.sol │ └── SingletonDeployer_v1.s.sol └── utils │ └── CreateAndDeployModuleBeacon.s.sol ├── slither.config.json ├── src ├── external │ ├── fees │ │ ├── FeeManager_v1.sol │ │ └── interfaces │ │ │ └── IFeeManager_v1.sol │ ├── forwarder │ │ ├── TransactionForwarder_v1.sol │ │ └── interfaces │ │ │ └── ITransactionForwarder_v1.sol │ ├── governance │ │ ├── Governor_v1.sol │ │ └── interfaces │ │ │ └── IGovernor_v1.sol │ ├── interfaces │ │ └── IERC2771Context.sol │ ├── reverter │ │ └── InverterReverter_v1.sol │ └── token │ │ ├── ERC20Issuance_v1.sol │ │ └── IERC20Issuance_v1.sol ├── factories │ ├── ModuleFactory_v1.sol │ ├── OrchestratorFactory_v1.sol │ ├── interfaces │ │ ├── IModuleFactory_v1.sol │ │ ├── IOrchestratorFactory_v1.sol │ │ └── IPIM_WorkflowFactory_v1.sol │ └── workflow-specific │ │ └── PIM_WorkflowFactory_v1.sol ├── modules │ ├── authorizer │ │ ├── IAuthorizer_v1.sol │ │ ├── extensions │ │ │ └── AUT_EXT_VotingRoles_v1.sol │ │ └── role │ │ │ ├── AUT_Roles_v1.sol │ │ │ ├── AUT_TokenGated_Roles_v1.sol │ │ │ └── interfaces │ │ │ ├── IAUT_EXT_VotingRoles_v1.sol │ │ │ └── IAUT_TokenGated_Roles_v1.sol │ ├── base │ │ ├── IModule_v1.sol │ │ └── Module_v1.sol │ ├── fundingManager │ │ ├── IFundingManager_v1.sol │ │ ├── bondingCurve │ │ │ ├── FM_BC_Bancor_Redeeming_VirtualSupply_v1.sol │ │ │ ├── FM_BC_Restricted_Bancor_Redeeming_VirtualSupply_v1.sol │ │ │ ├── FM_BC_Tools.sol │ │ │ ├── abstracts │ │ │ │ ├── BondingCurveBase_v1.sol │ │ │ │ ├── RedeemingBondingCurveBase_v1.sol │ │ │ │ ├── VirtualCollateralSupplyBase_v1.sol │ │ │ │ └── VirtualIssuanceSupplyBase_v1.sol │ │ │ ├── formulas │ │ │ │ ├── BancorFormula.sol │ │ │ │ └── Utils.sol │ │ │ └── interfaces │ │ │ │ ├── IBancorFormula.sol │ │ │ │ ├── IBondingCurveBase_v1.sol │ │ │ │ ├── IFM_BC_Bancor_Redeeming_VirtualSupply_v1.sol │ │ │ │ ├── IRedeemingBondingCurveBase_v1.sol │ │ │ │ ├── IVirtualCollateralSupplyBase_v1.sol │ │ │ │ └── IVirtualIssuanceSupplyBase_v1.sol │ │ ├── depositVault │ │ │ ├── FM_DepositVault_v1.sol │ │ │ └── interfaces │ │ │ │ └── IFM_DepositVault_v1.sol │ │ └── rebasing │ │ │ ├── FM_Rebasing_v1.sol │ │ │ ├── abstracts │ │ │ └── ElasticReceiptTokenBase_v1.sol │ │ │ └── interfaces │ │ │ ├── IERC20.sol │ │ │ ├── IERC20Metadata.sol │ │ │ └── IRebasingERC20.sol │ ├── lib │ │ ├── LibMetadata.sol │ │ ├── LinkedIdList.sol │ │ └── SafeMath.sol │ ├── logicModule │ │ ├── LM_PC_Bounties_v1.sol │ │ ├── LM_PC_KPIRewarder_v1.sol │ │ ├── LM_PC_PaymentRouter_v1.sol │ │ ├── LM_PC_RecurringPayments_v1.sol │ │ ├── LM_PC_Staking_v1.sol │ │ ├── abstracts │ │ │ ├── ERC20PaymentClientBase_v1.sol │ │ │ └── oracleIntegrations │ │ │ │ └── UMA_OptimisticOracleV3 │ │ │ │ ├── IOptimisticOracleIntegrator.sol │ │ │ │ ├── OptimisticOracleIntegrator.sol │ │ │ │ └── optimistic-oracle-v3 │ │ │ │ ├── AncillaryData.sol │ │ │ │ ├── ClaimData.sol │ │ │ │ └── interfaces │ │ │ │ ├── OptimisticOracleV3CallbackRecipientInterface.sol │ │ │ │ └── OptimisticOracleV3Interface.sol │ │ └── interfaces │ │ │ ├── IERC20PaymentClientBase_v1.sol │ │ │ ├── ILM_PC_Bounties_v1.sol │ │ │ ├── ILM_PC_KPIRewarder_v1.sol │ │ │ ├── ILM_PC_PaymentRouter_v1.sol │ │ │ ├── ILM_PC_RecurringPayments_v1.sol │ │ │ └── ILM_PC_Staking_v1.sol │ └── paymentProcessor │ │ ├── IPaymentProcessor_v1.sol │ │ ├── PP_Simple_v1.sol │ │ ├── PP_Streaming_v1.sol │ │ └── interfaces │ │ └── IPP_Streaming_v1.sol ├── orchestrator │ ├── Orchestrator_v1.sol │ ├── abstracts │ │ └── ModuleManagerBase_v1.sol │ └── interfaces │ │ ├── IModuleManagerBase_v1.sol │ │ └── IOrchestrator_v1.sol └── proxies │ ├── InverterBeaconProxy_v1.sol │ ├── InverterBeacon_v1.sol │ ├── InverterProxyAdmin_v1.sol │ ├── InverterTransparentUpgradeableProxy_v1.sol │ └── interfaces │ ├── IInverterBeacon_v1.sol │ ├── IInverterProxyAdmin_v1.sol │ └── IInverterTransparentUpgradeableProxy_v1.sol ├── test ├── common │ └── LinkedIdList.t.sol ├── e2e │ ├── E2EModuleRegistry.sol │ ├── E2ETest.sol │ ├── ModuleTest_Template.txt │ ├── README.md │ ├── authorizer │ │ ├── RoleAuthorizerE2E.t.sol │ │ ├── TokenGatedRoleAuthorizerE2E.t.sol │ │ └── extensions │ │ │ └── VotingRoleManagerE2E.t.sol │ ├── fundingManager │ │ ├── BondingCurveFundingManagerE2E.sol │ │ └── RebasingFundingManagerE2E.sol │ ├── logicModules │ │ ├── BountyManagerE2E.t.sol │ │ ├── KPIRewarderLifecycle.t.sol │ │ ├── RecurringPaymentManagerE2E.t.sol │ │ └── StakingManagerLifecycle.t.sol │ ├── module │ │ └── MetaTxAndMulticallE2E.t.sol │ ├── orchestrator_and_structural │ │ └── OrchestratorE2E.sol │ ├── paymentProcessor │ │ └── StreamingPaymentProcessorE2E.sol │ └── proxies │ │ └── InverterBeaconE2E.t.sol ├── external │ ├── ERC20Issuance.t.sol │ ├── FeeManager_v1.t.sol │ ├── Governor_v1.t.sol │ ├── InverterReverter_v1.t.sol │ └── TransactionForwarder_v1.t.sol ├── factories │ ├── ModuleFactory_v1.t.sol │ ├── OrchestratorFactory_v1.t.sol │ └── workflow-specific │ │ └── PIM_WorkflowFactory_v1.t.sol ├── modules │ ├── ModuleTest.sol │ ├── authorizer │ │ ├── extensions │ │ │ └── AUT_EXT_VotingRoles_v1.t.sol │ │ └── role │ │ │ ├── AUT_Roles_v1.t.sol │ │ │ └── AUT_TokenGated_Roles_v1.t.sol │ ├── base │ │ └── Module_v1.t.sol │ ├── fundingManager │ │ ├── bondingCurve │ │ │ ├── FM_BC_Bancor_Redeeming_VirtualSupply_v1.t.sol │ │ │ ├── FM_BC_Restricted_Bancor_Redeeming_VirtualSupply_v1.t.sol │ │ │ ├── abstracts │ │ │ │ ├── BondingCurveBase_v1.t.sol │ │ │ │ ├── RedeemingBondingCurveBase_v1.t.sol │ │ │ │ ├── VirtualCollateralSupplyBase_v1.t.sol │ │ │ │ └── VirtualIssuanceSupplyBase_v1.t.sol │ │ │ └── utils │ │ │ │ └── mocks │ │ │ │ ├── BancorFormulaMock.sol │ │ │ │ ├── BondingCurveBaseV1Mock.sol │ │ │ │ ├── FM_BC_Bancor_Redeeming_VirtualSupplyV1Mock.sol │ │ │ │ ├── FM_BC_Restricted_Bancor_Redeeming_VirtualSupplyV1Mock.sol │ │ │ │ ├── RedeemingBondingCurveBaseV1Mock.sol │ │ │ │ ├── VirtualCollateralSupplyBaseV1Mock.sol │ │ │ │ └── VirtualIssuanceSupplyBaseV1Mock.sol │ │ ├── depositVault │ │ │ └── FM_DepositVault_v1.t.sol │ │ └── rebasing │ │ │ ├── FM_Rebasing_v1.t.sol │ │ │ ├── abstracts │ │ │ ├── Deployment.t.sol │ │ │ ├── ERC20.t.sol │ │ │ ├── ElasticReceiptTokenBase_v1.t.sol │ │ │ ├── MintBurn.t.sol │ │ │ ├── Rebase.t.sol │ │ │ └── SimulateTransferPrecision.t.sol │ │ │ └── utils │ │ │ └── mocks │ │ │ ├── ERC20Mock.sol │ │ │ └── ElasticReceiptTokenBaseV1Mock.sol │ ├── lib │ │ └── LibMetadata.t.sol │ ├── logicModule │ │ ├── LM_PC_KPIRewarder_v1.t.sol │ │ ├── LM_PC_Staking_v1.t.sol │ │ ├── oracle │ │ │ ├── OptimisticOracleIntegrator.t.sol │ │ │ └── utils │ │ │ │ ├── OptimisiticOracleIntegratorMock.sol │ │ │ │ └── OptimisiticOracleV3Mock.sol │ │ └── paymentClient │ │ │ ├── ERCPaymentClientBase_v1.t.sol │ │ │ ├── LM_PC_Bounties_v1.t.sol │ │ │ ├── LM_PC_PaymentRouter_v1.t.sol │ │ │ └── LM_PC_RecurringPayments_v1.t.sol │ └── paymentProcessor │ │ ├── PP_Simple_v1.t.sol │ │ └── PP_Streaming_v1.t.sol ├── orchestrator │ ├── Orchestrator_v1.t.sol │ ├── abstracts │ │ └── ModuleManagerBase_v1.t.sol │ └── helper │ │ └── TypeSanityHelper.sol ├── proxies │ ├── InverterBeaconProxy_v1.t.sol │ ├── InverterBeacon_v1.t.sol │ ├── InverterProxyAdmin.sol │ └── InverterTransparentUpgradeableProxy_v1.t.sol └── utils │ ├── errors │ └── OZErrors.sol │ └── mocks │ ├── ERC20Mock.sol │ ├── ERC721Mock.sol │ ├── external │ ├── CallIntercepter.sol │ ├── FeeManagerV1Mock.sol │ ├── GovernorV1Mock.sol │ └── TransactionForwarderV1AccessMock.sol │ ├── factories │ └── ModuleFactoryV1Mock.sol │ ├── modules │ ├── AuthorizerV1Mock.sol │ ├── FundingManagerV1Mock.sol │ ├── PaymentProcessorV1Mock.sol │ ├── base │ │ └── ModuleV1Mock.sol │ ├── logicModules │ │ ├── LM_PC_Bounties_v1AccessMock.sol │ │ └── LM_PC_Staking_v1AccessMock.sol │ ├── paymentClient │ │ ├── ERC20PaymentClientBaseV1AccessMock.sol │ │ └── ERC20PaymentClientBaseV1Mock.sol │ └── paymentProcessor │ │ ├── PP_Simple_v1AccessMock.sol │ │ └── PP_Streaming_v1AccessMock.sol │ ├── orchestrator │ ├── OrchestratorV1AccessMock.sol │ ├── OrchestratorV1Mock.sol │ └── abstracts │ │ └── ModuleManagerBaseV1Mock.sol │ └── proxies │ ├── IModuleImplementationMock.sol │ ├── InverterBeaconV1AccessMock.sol │ ├── InverterBeaconV1Mock.sol │ ├── InverterBeaconV1OwnableMock.sol │ ├── InverterTransparentUpgradeableProxyV1AccessMock.sol │ ├── ModuleImplementationV1Mock.sol │ └── ModuleImplementationV2Mock.sol └── testnet.env /.github/ISSUE_TEMPLATE/security-review-issue-template.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Security Review Issue Template 3 | about: 4 | This template should be used to write down the issues resulting from PR comments 5 | within an Inverter security review 6 | title: "Security Review # : " 7 | labels: security-review fix 8 | assignees: "" 9 | --- 10 | 11 | --- 12 | 13 | _How to section, please remove before submitting issue_ 14 | 15 | 1. Add PR number and descriptive title 16 | 1. Add PR number to link the issue within first section 17 | 1. Chose category of issue, delete the rest 18 | 1. Add context, if applicable 19 | 1. Link PR comment and mark them as done once implemented. This can be sees as acceptance criteria. 20 | 1. **Important:** when adding a PR comment to an issue please make sure to mark the comment so it is clear that it has been captured within an issue. An example of marking could be reacting with a :+1: 21 | 1. Tag relevant people in the comment section 22 | 23 | --- 24 | 25 | ### This issue is linked to 26 | 27 | - Security Review with PR #__ 28 | 29 | ### Explanation 30 | 31 | _Add description needed for solving the issue_ 32 | 33 | ### Category: 34 | 35 | - Critical severity issue 36 | - Medium severity issue 37 | - Low severity / Information issue 38 | - Architectural Reconsideration 39 | - Gas Optimizations 40 | - General Comments and Suggestions 41 | - Custom (for cases when Omega think their issue needs a separate category) 42 | 43 | ### Link to review comments 44 | 45 | - [ ] __ 46 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - dev 8 | pull_request: 9 | branches: 10 | - "*" 11 | 12 | env: 13 | FOUNDRY_PROFILE: ci 14 | SEPOLIA_RPC_URL: ${{ secrets.SEPOLIA_RPC }} 15 | 16 | jobs: 17 | compile: 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - name: Checkout repository 22 | uses: actions/checkout@v4 23 | with: 24 | submodules: recursive 25 | 26 | - name: Install Foundry 27 | uses: foundry-rs/foundry-toolchain@v1 28 | with: 29 | version: nightly 30 | 31 | - name: Compile contracts 32 | run: forge build 33 | 34 | - name: Save compiled artifacts 35 | uses: actions/upload-artifact@v4 36 | with: 37 | name: compiled-artifacts 38 | path: | 39 | out/ 40 | cache/ 41 | 42 | check-size: 43 | runs-on: ubuntu-latest 44 | needs: compile 45 | if: always() 46 | 47 | steps: 48 | - name: Checkout repository 49 | uses: actions/checkout@v4 50 | with: 51 | submodules: recursive 52 | 53 | - name: Install Foundry 54 | uses: foundry-rs/foundry-toolchain@v1 55 | with: 56 | version: nightly 57 | 58 | - name: Download compiled artifacts 59 | uses: actions/download-artifact@v4 60 | with: 61 | name: compiled-artifacts 62 | path: | 63 | out/ 64 | cache/ 65 | 66 | - name: Check contract sizes 67 | run: make check-size 68 | 69 | verify-formatting: 70 | runs-on: ubuntu-latest 71 | needs: compile 72 | if: always() 73 | 74 | steps: 75 | - name: Checkout repository 76 | uses: actions/checkout@v4 77 | with: 78 | submodules: recursive 79 | 80 | - name: Install Foundry 81 | uses: foundry-rs/foundry-toolchain@v1 82 | with: 83 | version: nightly 84 | 85 | - name: Download compiled artifacts 86 | uses: actions/download-artifact@v4 87 | with: 88 | name: compiled-artifacts 89 | path: | 90 | out/ 91 | cache/ 92 | 93 | - name: Verify formatting 94 | run: forge fmt --check 95 | 96 | verify-scripts: 97 | runs-on: ubuntu-latest 98 | needs: compile 99 | if: always() 100 | 101 | steps: 102 | - name: Checkout repository 103 | uses: actions/checkout@v4 104 | with: 105 | submodules: recursive 106 | 107 | - name: Install Foundry 108 | uses: foundry-rs/foundry-toolchain@v1 109 | with: 110 | version: nightly 111 | 112 | - name: Download compiled artifacts 113 | uses: actions/download-artifact@v4 114 | with: 115 | name: compiled-artifacts 116 | path: | 117 | out/ 118 | cache/ 119 | 120 | - name: Run scripts 121 | run: make testScripts 122 | 123 | verify-tests: 124 | runs-on: ubuntu-latest 125 | needs: compile 126 | if: always() 127 | 128 | steps: 129 | - name: Checkout repository 130 | uses: actions/checkout@v4 131 | with: 132 | submodules: recursive 133 | 134 | - name: Install Foundry 135 | uses: foundry-rs/foundry-toolchain@v1 136 | with: 137 | version: nightly 138 | 139 | - name: Download compiled artifacts 140 | uses: actions/download-artifact@v4 141 | with: 142 | name: compiled-artifacts 143 | path: | 144 | out/ 145 | cache/ 146 | 147 | - name: Run tests 148 | run: forge test -vvv 149 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiler files 2 | cache/ 3 | out/ 4 | 5 | # Test files 6 | coverage/ 7 | lcov.info 8 | .gas-snapshot 9 | 10 | # Ignores development broadcast logs 11 | !/broadcast 12 | /broadcast/* 13 | /broadcast/*/31337/ 14 | 15 | # Dotenv file 16 | .env 17 | 18 | .DS_Store 19 | test/.DS_Store -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/forge-std"] 2 | path = lib/forge-std 3 | url = https://github.com/foundry-rs/forge-std 4 | [submodule "lib/openzeppelin-contracts"] 5 | path = lib/openzeppelin-contracts 6 | url = https://github.com/openzeppelin/openzeppelin-contracts 7 | [submodule "lib/openzeppelin-contracts-upgradeable"] 8 | path = lib/openzeppelin-contracts-upgradeable 9 | url = https://github.com/openzeppelin/openzeppelin-contracts-upgradeable 10 | [submodule "lib/deterministic-factory"] 11 | path = lib/deterministic-factory 12 | url = https://github.com/InverterNetwork/deterministic-factory 13 | [submodule "lib/uma-protocol"] 14 | path = lib/uma-protocol 15 | url = https://github.com/UMAprotocol/protocol 16 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "solidity.packageDefaultDependenciesContractsDirectory": "src", 3 | "solidity.packageDefaultDependenciesDirectory": "lib", 4 | "solidity.compileUsingRemoteVersion": "v0.8.23", 5 | "solidity.formatter": "forge", 6 | "git.detectSubmodules": false, 7 | "search.exclude": { 8 | "lib": true 9 | }, 10 | "editor.formatOnSave": true 11 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Inverter Network Smart Contracts 4 | *Inverter is the pioneering web3 protocol for token economies, enabling conditional token issuance, dynamic utility management, and token distribution. Build, customize, and innovate with Inverter's modular logic and extensive web3 interoperability.* 5 | 6 | ## Installation 7 | 8 | The Inverter Network smart contracts are developed using the [foundry toolchain](https://getfoundry.sh) 9 | 10 | 1. Clone the repository 11 | 2. `cd` into the repository 12 | 3. Run `make install` to install contract dependencies 13 | 4. (_Optional_) Run `source dev.env` to set up environment variables 14 | 15 | ## Usage 16 | 17 | Common tasks are executed through a `Makefile`. The most common commands are: 18 | * `make build` to compile the project. 19 | * `make test` to run the test suite. 20 | * Note: _Some of our tests require a working Sepolia RPC URL, as we test certain contracts via fork testing. We implemented fallbacks for these particular test cases in the code directly, so they will work even without any RPC set in the environment. In the unlikely case that the tests do not work without RPC, please set a working one via `export SEPOLIA_RPC_URL=https://rpc-url-here`._ 21 | * `make pre-commit` to ensure all of the development requirements are met, such as 22 | * the Foundry Formatter has been run. 23 | * the scripts are all working. 24 | * the tests all run without any issues. 25 | 26 | Additionally, the `Makefile` supports a help command, i.e. `make help`. 27 | 28 | ``` 29 | $ make help 30 | > build Build project 31 | > clean Remove build artifacts 32 | > test Run whole testsuite 33 | > update Update dependencies 34 | > [...] 35 | ``` 36 | 37 | ## Documentation 38 | The protocol is based on our [technical specification](https://docs.google.com/document/d/1j6WXBZzyYCOfO36ZYvKkgqrO2UAcy0kW5eJeZousn7E), which outlines its architecture and is the foundation of the implementation. Our documentation can be found [here](https://docs.inverter.network). 39 | 40 | ## Dependencies 41 | - [OpenZeppelin Contracts](https://github.com/OpenZeppelin/openzeppelin-contracts) 42 | - [OpenZeppelin Upgradeable-Contracts](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable) 43 | - [UMAProtocol](https://github.com/UMAprotocol/protocol) (_for the [KPIRewarder Staking Module](./src/modules/logicModule/LM_PC_KPIRewarder_v1.sol)_) 44 | 45 | ## Contributing 46 | You are considering to contribute to our protocol? Awesome - please refer to our [Contribution Guidelines](./CONTRIBUTING.md) to find our about the processes we established to ensure highest quality within our codebase. 47 | 48 | ## Security 49 | Our [Security Policy](./SECURITY.md) provides details about our Security Guidelines, audits, and more. If you have discovered a potential security vulnerability within the Inverter Protocol, please report it to us by emailing [security@inverter.network](mailto:security@inverter.network). 50 | 51 | ----- 52 | _Disclaimer: This is experimental software and is provided on an "as is" and "as available" basis. We do not give any warranties and will not be liable for any loss incurred through any use of this codebase._ 53 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Security Policy 4 | 5 | At Inverter Network, we are committed to ensuring the security and integrity of our protocol and smart contracts. We value the input of the community and security researchers in identifying and responsibly disclosing any potential vulnerabilities or security issues. 6 | 7 | ## Reporting Security Issues 8 | 9 | If you discover a potential security vulnerability or issue within our smart contracts or any part of the Inverter Network ecosystem, we strongly encourage you to report it promptly. Please email [security@inverter.network](mailto:security@inverter.network) with a detailed description of the issue, steps to reproduce it, and any relevant information that can assist us in understanding and resolving the problem. 10 | 11 | We appreciate your efforts to disclose any security findings responsibly, and we are committed to collaborating with you to address the issue. Rest assured that you will be given proper credit for your contribution. 12 | 13 | ## Audits and Security Reviews 14 | 15 | At Inverter Network, we prioritize the security of our smart contracts and follow a rigorous process of security reviews and audits: 16 | 17 | * Per our development and security guidelines, we require an external review for each pull request (PR) that goes from the `dev` branch to the `main` branch in our repository. We have partnered with [Team Omega](https://teamomega.eth.limo) to conduct these security reviews directly in the PRs. 18 | 19 | * Additionally, prior to major releases, we perform a full audit of any changed contracts via an external auditing company before the deployment. This ensures that our contracts undergo thorough scrutiny by professional auditors. 20 | 21 | * Our version 1 has been audited by [0xMacro](https://0xmacro.com/) and underwent a public audit competition on [Hats Finance](https://hats.finance/), leveraging the expertise of the broader security community. 22 | 23 | We are committed to transparency and will make the results of our security reviews and audits available to the public, fostering trust and confidence in the security of our platform. 24 | 25 | **You can find all of our audit reports [here](./audits/).** 26 | 27 | ## Responsible Disclosure 28 | 29 | Please practice responsible disclosure when reporting security issues. We kindly request that you do not publicly disclose or discuss the vulnerability until we have had sufficient time to investigate and address it. Privately disclosing the issue to us via email allows us to work on a fix without putting our users' funds at risk. 30 | 31 | We understand the importance of acknowledging and rewarding security researchers for their efforts. Even though our bug bounty program is currently not set up, we assure you that you will not be unpaid for your valuable contributions. We are committed to fairly compensating those who help us improve the security of our platform. 32 | 33 | ## Security Guideline 34 | 35 | At Inverter Network, we adhere to a comprehensive Security Guideline that outlines our best practices and approach to ensuring the security of our smart contracts. This guideline is a public document that we follow at all times. You can find our Security Guideline [here](https://docs.google.com/document/d/1CZgM9OEuibNrimbNeActve5n9ro3Ydu03OfSnZfRo_s). 36 | 37 | We encourage you to review our Security Guideline to understand our commitment to security and the measures we have in place to protect our users and the integrity of our platform. 38 | 39 | ## Bug Bounty Program 40 | 41 | We are currently in the process of setting up a bug bounty program to incentivize and reward security researchers for their contributions. Further details about the program will be announced once it is officially launched. Stay tuned for updates on how you can participate and be rewarded for your efforts in strengthening the security of the Inverter Network. 42 | 43 | ## Contact Us 44 | 45 | If you have any questions, concerns, or feedback regarding the security of the Inverter Network, please don't hesitate to reach out to us at [security@inverter.network](mailto:security@inverter.network). We value open communication and collaboration with the security community. 46 | 47 | ----- 48 | _Disclaimer: This is experimental software and is provided on an "as is" and "as available" basis. We do not give any warranties and will not be liable for any loss incurred through any use of this codebase._ -------------------------------------------------------------------------------- /assets/logo_circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /audits/2024-06-19-macro.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InverterNetwork/contracts/2a8a4c80ff4f24a59546d4e6126b81bc51228c94/audits/2024-06-19-macro.pdf -------------------------------------------------------------------------------- /audits/2024-07-29-team-omega-issuance-token.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InverterNetwork/contracts/2a8a4c80ff4f24a59546d4e6126b81bc51228c94/audits/2024-07-29-team-omega-issuance-token.pdf -------------------------------------------------------------------------------- /audits/2024-08-12-hats.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InverterNetwork/contracts/2a8a4c80ff4f24a59546d4e6126b81bc51228c94/audits/2024-08-12-hats.pdf -------------------------------------------------------------------------------- /audits/README.md: -------------------------------------------------------------------------------- 1 | ## Audits and Security Reviews 2 | 3 | At Inverter Network, we prioritize the security of our smart contracts and follow a rigorous process of security reviews and audits: 4 | 5 | * Per our development and security guidelines, we require an external review for each pull request (PR) that goes from the `dev` branch to the `main` branch in our repository. We have partnered with [Team Omega](https://teamomega.eth.limo) to conduct these security reviews directly in the PRs. 6 | * 2024-07-29 - Team Omega - Issuance Token Audit - [Report](./2024-07-29-team-omega-issuance-token.pdf) 7 | 8 | * Additionally, prior to major releases, we perform a full audit of any changed contracts via an external auditing company before the deployment. This ensures that our contracts undergo thorough scrutiny by professional auditors. 9 | 10 | * Our version 1 has been audited by [0xMacro](https://0xmacro.com/) and underwent a public audit competition on [Hats Finance](https://hats.finance/), leveraging the expertise of the broader security community. 11 | * 2024-07-19 - 0xMacro Audit - [Report](./2024-06-19-macro.pdf) - [[*original*](https://0xmacro.com/library/audits/inverter-1)] 12 | * 2024-08-12 - Hats Finance Audit Competition - [Report](./2024-08-12-hats.pdf) - [[*original*](https://github.com/hats-finance/Inverter-Network-0xe47e52c4fea05e555920f1dcdcc6fb8eca103eeb/blob/main/report.md)] 13 | 14 | We are committed to transparency and will make the results of our security reviews and audits available to the public, fostering trust and confidence in the security of our platform. -------------------------------------------------------------------------------- /dev.env: -------------------------------------------------------------------------------- 1 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 | # Development Environment Variables 3 | # 4 | # WARNING: This file is part of the git repo. DO NOT INCLUDE SENSITIVE DATA! 5 | # 6 | # The environment variables are read by 7 | # - Solidity scripts in script/ 8 | # - forge commands 9 | # 10 | # Note that the variables need to be exported in order for make to read them 11 | # directly. 12 | # 13 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 14 | 15 | # ------------------------------------------------------------------------------ 16 | 17 | # RPC endpoints (these are public links, substitute with alchemy or similar for less rate limiting) 18 | 19 | export RPC_URL="http://127.0.0.1:8545" # Local anvil node 20 | export SEPOLIA_RPC_URL=https://sepolia.drpc.org 21 | export OPTIMISM_SEPOLIA_RPC_URL=https://sepolia.optimism.io 22 | export POLYGON_AMOY_RPC_URL=https://rpc-amoy.polygon.technology/ 23 | export POLYGON_CARDONA_RPC_URL=https://rpc.cardona.zkevm-rpc.com 24 | 25 | 26 | # ------------------------------------------------------------------------------ 27 | # Wallets 28 | 29 | # Default Anvil Wallet 30 | export ANVIL_WALLET_DEPLOYER=0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 31 | export ANVIL_WALLET_DEPLOYER_PK=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 32 | 33 | # Deployer Wallet 34 | # (Note that for this example we are reusing anvil's default wallets.) 35 | export DEPLOYER_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 36 | 37 | # ------------------------------------------------------------------------------ 38 | # Multisig Addresses 39 | 40 | export COMMUNITY_MULTISIG_ADDRESS=0x0000000000000000000000000000000000000000 41 | export TEAM_MULTISIG_ADDRESS=0x0000000000000000000000000000000000000000 42 | 43 | # ------------------------------------------------------------------------------ 44 | # Treasury Addresses 45 | export TREASURY_ADDRESS=0x0000000000000000000000000000000000000000 46 | 47 | # ------------------------------------------------------------------------------ 48 | # DETERMINISTIC_FACTORY_ADDRESS 49 | export DETERMINISTIC_FACTORY_ADDRESS=0x0000000000000000000000000000000000000000 50 | 51 | # ------------------------------------------------------------------------------ 52 | # Contract Verification 53 | 54 | # Etherscan API Keys 55 | export ETHERSCAN_API_KEY=ABC123ABC123ABC123ABC123ABC123ABC1 56 | export POLYGONSCAN_API_KEY=ABC123ABC123ABC123ABC123ABC123ABC1 57 | export OP_ETHERSCAN_API_KEY=ABC123ABC123ABC123ABC123ABC123ABC1 58 | 59 | 60 | # ------------------------------------------------------------------------------ 61 | # Command to run a deployment script 62 | # In general, the command to run a deployment script will look like this: 63 | # forge script script/deploymentScript/DeploymentScript.s.sol --rpc-url $SEPOLIA_RPC_URL --chain-id 11155111 --private-key $WALLET_DEPLOYER_PK --etherscan-api-key $ETHERSCAN_API_KEY --verify --broadcast --legacy -vvv 64 | 65 | # @todo Move the last part to readme -------------------------------------------------------------------------------- /foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = 'src' 3 | out = 'out' 4 | libs = ['lib'] 5 | fs_permissions = [{ access = "read-write", path = "./"}] 6 | 7 | # Compilation 8 | solc_version = "0.8.23" 9 | optimizer = true 10 | optimizer_runs = 750 11 | via_ir = false 12 | 13 | [fuzz] 14 | runs = 256 15 | 16 | [fmt] 17 | line_length = 80 18 | int_types = "short" 19 | number_underscore = "thousands" 20 | ignore = ['src/generated/*', 'src/modules/fundingManager/bondingCurveFundingManager/formula/*'] 21 | 22 | [profile.ci] 23 | fuzz = { runs = 1_024 } 24 | verbosity = 4 25 | 26 | [rpc_endpoints] 27 | mainnet = "${RPC_URL}" 28 | sepolia = "${SEPOLIA_RPC_URL}" 29 | 30 | # See more config options https://github.com/foundry-rs/foundry/tree/master/config 31 | -------------------------------------------------------------------------------- /remappings.txt: -------------------------------------------------------------------------------- 1 | @oz-up/=lib/openzeppelin-contracts-upgradeable/contracts/ 2 | @oz/=lib/openzeppelin-contracts/contracts/ 3 | @df/=lib/deterministic-factory/src/ 4 | @uma/=lib/uma-protocol/packages/core/contracts/ 5 | @ex/=src/external/ 6 | @fm/=src/modules/fundingManager/ 7 | @pp/=src/modules/paymentProcessor/ 8 | @lm/=src/modules/logicModule/ 9 | @lm_pc/=src/modules/logicModule/paymentClient/ 10 | @aut/=src/modules/authorizer/ 11 | -------------------------------------------------------------------------------- /script/README.md: -------------------------------------------------------------------------------- 1 | # How to use the Deployment Scripts 2 | 3 | ## Deploy the protocol Foundation 4 | 5 | Use DeploymentScript.s.sol to deploy the protocol foundation. We can run it with the following command: 6 | 7 | ``` 8 | forge script script/deploymentScript/DeploymentScript.s.sol 9 | ``` 10 | 11 | ## Deploy a new standalone module 12 | 13 | For this usecase we use the CreateAndDeployModuleBeacon.s.sol script. We can run it with the following command: 14 | 15 | ``` 16 | forge script script/utils/CreateAndDeployModuleBeacon.s.sol "run(string,string,address,address,uint,uint,uint)" "ExampleModule" "src/module/ExampleModule.sol" "0x0000000000000000000000000000000000000001" "0x0000000000000000000000000000000000000002" 1 0 0 17 | ``` 18 | 19 | ## Add a new module to the deployment script 20 | 21 | For us to a add a new module to the deployment script, we need to: 22 | 23 | 1. Add the module metadata to the MetadataCollection_v1.s.sol 24 | 2. Add the module implementation to the SingletonDeployer_v1.s.sol 25 | 3. Add the module beacon to the ModuleBeaconDeployer_v1.s.sol 26 | -------------------------------------------------------------------------------- /script/deploymentScript/TestnetDeploymentScript.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.0; 3 | 4 | import "forge-std/Script.sol"; 5 | 6 | // Scripts 7 | import {DeploymentScript} from "script/deploymentScript/DeploymentScript.s.sol"; 8 | 9 | // Contracts 10 | import {DeterministicFactory_v1} from "@df/DeterministicFactory_v1.sol"; 11 | 12 | // Interfaces 13 | import {IERC20} from "@oz/token/ERC20/IERC20.sol"; 14 | 15 | // Mocks 16 | import { 17 | OptimisticOracleV3Mock, 18 | OptimisticOracleV3Interface 19 | } from "test/modules/logicModule/oracle/utils/OptimisiticOracleV3Mock.sol"; 20 | import {ERC20Mock} from "test/utils/mocks/ERC20Mock.sol"; 21 | 22 | /** 23 | * @title Inverter Testnet Deployment Script 24 | * 25 | * @dev Script to deploy the Inverter protocol in a testnet environment. 26 | * This means that the script deploys the DeterministicFactory as well. 27 | * 28 | * @author Inverter Network 29 | */ 30 | contract TestnetDeploymentScript is DeploymentScript { 31 | OptimisticOracleV3Mock ooV3; 32 | ERC20Mock mockCollateralToken; 33 | 34 | uint64 immutable DEFAULT_LIVENESS = 25_000; 35 | 36 | function run() public virtual override { 37 | console2.log(); 38 | console2.log( 39 | "================================================================================" 40 | ); 41 | console2.log("Start Testnet Deployment Script"); 42 | console2.log( 43 | "================================================================================" 44 | ); 45 | 46 | // Set required parameters to testnet values 47 | // For a testnet deployment, this means that if not set otherwise, 48 | // the deployer will also act as both multisigs and the treasury. 49 | if (communityMultisig == address(0)) { 50 | communityMultisig = deployer; 51 | } 52 | if (teamMultisig == address(0)) { 53 | teamMultisig = deployer; 54 | } 55 | if (treasury == address(0)) { 56 | treasury = deployer; 57 | } 58 | 59 | vm.startBroadcast(deployerPrivateKey); 60 | { 61 | console2.log(" Set up dependency contracts "); 62 | 63 | // Deploy and setup DeterministicFactory 64 | deterministicFactory = 65 | address(new DeterministicFactory_v1(deployer)); 66 | DeterministicFactory_v1(deterministicFactory).setAllowedDeployer( 67 | deployer 68 | ); 69 | console2.log("\tDeterministic Factory: %s", deterministicFactory); 70 | 71 | console2.log(" Set up mocks"); 72 | 73 | // Deploy and setup UMA's OptimisticOracleV3Mock 74 | ooV3 = new OptimisticOracleV3Mock( 75 | IERC20(address(mockCollateralToken)), DEFAULT_LIVENESS 76 | ); // @note FeeToken? 77 | console2.log("\tOptimisticOracleV3Mock: %s", address(ooV3)); 78 | 79 | // Deploy and setup Mock Collateral Token 80 | mockCollateralToken = new ERC20Mock("Inverter USD", "iUSD"); 81 | console2.log("\tERC20Mock iUSD: %s", address(mockCollateralToken)); 82 | } 83 | vm.stopBroadcast(); 84 | 85 | // Set DeterministicFactory so it's used in the DeploymentScript 86 | // downstream 87 | setFactory(deterministicFactory); 88 | proxyAndBeaconDeployer.setFactory(deterministicFactory); 89 | 90 | super.run(); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /script/deploymentSuite/ProtocolConstants_v1.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.0; 3 | 4 | import "forge-std/Script.sol"; 5 | 6 | /** 7 | * @title Inverter Protocol Deployment Constants 8 | * 9 | * @dev Contains protocol-wide constants for critical information and addresses in 10 | * deployments, like the deployer and multisigs. They are loaded from the 11 | * environment variables. 12 | * 13 | * @author Inverter Network 14 | */ 15 | contract ProtocolConstants_v1 is Script { 16 | // ------------------------------------------------------------------------ 17 | // Important addresses 18 | // ------------------------------------------------------------------------ 19 | 20 | // Fetch the deployer details 21 | uint public deployerPrivateKey = vm.envUint("DEPLOYER_PRIVATE_KEY"); 22 | address public deployer = vm.addr(deployerPrivateKey); 23 | 24 | // Fetch the Multisig addresses 25 | address public communityMultisig = 26 | vm.envAddress("COMMUNITY_MULTISIG_ADDRESS"); 27 | address public teamMultisig = vm.envAddress("TEAM_MULTISIG_ADDRESS"); 28 | 29 | // Fetch the treasury address 30 | address public treasury = vm.envAddress("TREASURY_ADDRESS"); 31 | 32 | // Fetch the deterministic factory address 33 | address public deterministicFactory = 34 | vm.envAddress("DETERMINISTIC_FACTORY_ADDRESS"); 35 | 36 | // ------------------------------------------------------------------------ 37 | // Deployment Salt 38 | // ------------------------------------------------------------------------ 39 | 40 | string public constant factorySaltString = "inverter-deployment-1"; 41 | 42 | bytes32 public factorySalt = keccak256(abi.encodePacked(factorySaltString)); 43 | 44 | // ------------------------------------------------------------------------ 45 | // Important Configuration Data 46 | // ------------------------------------------------------------------------ 47 | 48 | // TODO: load from env? 49 | // FeeManager 50 | uint public feeManager_defaultCollateralFee = 100; 51 | uint public feeManager_defaultIssuanceFee = 100; 52 | 53 | // Governor 54 | uint public governor_timelockPeriod = 1 weeks; 55 | 56 | // Function to log data in a readable format 57 | function logProtocolMultisigsAndAddresses() public view { 58 | console2.log( 59 | "--------------------------------------------------------------------------------" 60 | ); 61 | console2.log(" Protocol-Level Addresses Used for the Deployment"); 62 | console2.log("\tDeployer: %s", deployer); 63 | console2.log("\tCommunity Multisig: %s", communityMultisig); 64 | console2.log("\tTeam Multisig: %s", teamMultisig); 65 | console2.log("\tTreasury: %s", treasury); 66 | console2.log("\tDeterministicFactory: %s", deterministicFactory); 67 | console2.log("\t -> Salt used: \"%s\"", factorySaltString); 68 | } 69 | 70 | // Function to log the protocol configuration in a readable format 71 | function logProtocolConfigurationData() public view { 72 | console2.log( 73 | "--------------------------------------------------------------------------------" 74 | ); 75 | console2.log(" Protocol Configuration Data Used for Initialization:"); 76 | 77 | console2.log("\tFeeManager:"); 78 | console2.log( 79 | "\t\tDefault Collateral Fee: %s BPS", 80 | feeManager_defaultCollateralFee 81 | ); 82 | console2.log( 83 | "\t\tDefault Issuance Fee: %s BPS", feeManager_defaultIssuanceFee 84 | ); 85 | console2.log("\tGovernor:"); 86 | console2.log("\t\tTimelock Period: %s seconds", governor_timelockPeriod); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /script/deploymentSuite/ProxyAndBeaconDeployer_v1.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.0; 3 | 4 | import "forge-std/Script.sol"; 5 | 6 | // Scripts 7 | import {ProtocolConstants_v1} from 8 | "script/deploymentSuite/ProtocolConstants_v1.s.sol"; 9 | 10 | // Interfaces 11 | import {InverterBeacon_v1} from "src/proxies/InverterBeacon_v1.sol"; 12 | import {IDeterministicFactory_v1} from 13 | "@df/interfaces/IDeterministicFactory_v1.sol"; 14 | 15 | /** 16 | * @title Inverter Beacon Deployment & Setup Script 17 | * 18 | * @dev Script to deploy and setup InverterBeacon_v1's. 19 | * 20 | * @author Inverter Network 21 | */ 22 | contract ProxyAndBeaconDeployer_v1 is Script, ProtocolConstants_v1 { 23 | IDeterministicFactory_v1 public factory = 24 | IDeterministicFactory_v1(deterministicFactory); 25 | 26 | function setFactory(address _factory) external { 27 | factory = IDeterministicFactory_v1(_factory); 28 | } 29 | 30 | function deployBeaconAndSetupProxy( 31 | string memory implementationName, 32 | address reverter, 33 | address owner, 34 | address implementation, 35 | uint majorVersion, 36 | uint minorVersion, 37 | uint patchVersion 38 | ) external returns (address beacon, address proxy) { 39 | // Deploy the beacon. 40 | beacon = deployInverterBeacon( 41 | implementationName, 42 | reverter, 43 | owner, 44 | implementation, 45 | majorVersion, 46 | minorVersion, 47 | patchVersion 48 | ); 49 | vm.startBroadcast(deployerPrivateKey); 50 | { 51 | proxy = factory.deployWithCreate2( 52 | factorySalt, 53 | abi.encodePacked( 54 | vm.getCode( 55 | "InverterBeaconProxy_v1.sol:InverterBeaconProxy_v1" 56 | ), 57 | abi.encode(InverterBeacon_v1(beacon)) 58 | ) 59 | ); 60 | } 61 | vm.stopBroadcast(); 62 | 63 | console2.log( 64 | "\t%s InverterBeaconProxy_v1: %s", 65 | implementationName, 66 | address(proxy) 67 | ); 68 | } 69 | 70 | function deployInverterBeacon( 71 | string memory implementationName, 72 | address reverter, 73 | address owner, 74 | address implementation, 75 | uint majorVersion, 76 | uint minorVersion, 77 | uint patchVersion 78 | ) public returns (address beacon) { 79 | vm.startBroadcast(deployerPrivateKey); 80 | { 81 | beacon = factory.deployWithCreate2( 82 | factorySalt, 83 | abi.encodePacked( 84 | vm.getCode("InverterBeacon_v1.sol:InverterBeacon_v1"), 85 | abi.encode( 86 | reverter, 87 | owner, 88 | majorVersion, 89 | implementation, 90 | minorVersion, 91 | patchVersion 92 | ) 93 | ) 94 | ); 95 | } 96 | 97 | vm.stopBroadcast(); 98 | 99 | // Log the deployed Beacon contract address. 100 | console2.log("\t%s InverterBeacon_v1: %s", implementationName, beacon); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /script/utils/CreateAndDeployModuleBeacon.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.0; 3 | 4 | import "forge-std/Script.sol"; 5 | 6 | import {ProtocolConstants_v1} from 7 | "script/deploymentSuite/ProtocolConstants_v1.s.sol"; 8 | 9 | import {ProxyAndBeaconDeployer_v1} from 10 | "script/deploymentSuite/ProxyAndBeaconDeployer_v1.s.sol"; 11 | 12 | import {IDeterministicFactory_v1} from 13 | "@df/interfaces/IDeterministicFactory_v1.sol"; 14 | 15 | contract CreateAndDeployModuleBeacon is Script, ProtocolConstants_v1 { 16 | IDeterministicFactory_v1 public factory = 17 | IDeterministicFactory_v1(deterministicFactory); 18 | 19 | ProxyAndBeaconDeployer_v1 public proxyAndBeaconDeployer = 20 | new ProxyAndBeaconDeployer_v1(); 21 | 22 | // How to use: 23 | // forge script 24 | // script/utils/CreateAndDeployModuleBeacon.s.sol 25 | // "run(string,string,address,address,uint,uint,uint)" 26 | // "ExampleModule" "src/module/ExampleModule.sol" ??? "0x0000000000000000000000000000000000000001" "0x0000000000000000000000000000000000000002" 1 0 0 27 | 28 | // @TODO Above explanation is lacking the bytes-encoded optionalParams 29 | 30 | function run( 31 | string memory moduleName, 32 | string memory modulePath, 33 | bytes memory optionalParams, 34 | address reverter, 35 | address owner, 36 | uint majorVersion, 37 | uint minorVersion, 38 | uint patchVersion 39 | ) external verifyRequiredParameters { 40 | vm.startBroadcast(deployerPrivateKey); 41 | { 42 | // Deploy the implementation 43 | address implementation = factory.deployWithCreate2( 44 | factorySalt, 45 | abi.encodePacked(vm.getCode(modulePath), optionalParams) 46 | ); 47 | console2.log( 48 | "Deployed %s implementation at address %s", 49 | moduleName, 50 | implementation 51 | ); 52 | 53 | // Deploy the beacon 54 | address beacon = proxyAndBeaconDeployer.deployInverterBeacon( 55 | moduleName, 56 | reverter, 57 | owner, 58 | implementation, 59 | majorVersion, 60 | minorVersion, 61 | patchVersion 62 | ); 63 | console2.log("Deployed %s beacon at address %s", moduleName, beacon); 64 | } 65 | vm.stopBroadcast(); 66 | } 67 | 68 | modifier verifyRequiredParameters() { 69 | require( 70 | deterministicFactory != address(0), 71 | "Deterministic Factory address not set - aborting!" 72 | ); 73 | _; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /slither.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "filter_paths": "lib", 3 | "solc_remaps": [ 4 | "forge-std/=lib/forge-std/src/", 5 | "@oz-up/=lib/openzeppelin-contracts-upgradeable/contracts/", 6 | "@oz/=lib/openzeppelin-contracts/contracts/", 7 | "@elastic-receipt-token/=lib/elastic-receipt-token/src/" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /src/external/forwarder/interfaces/ITransactionForwarder_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | // External Dependencies 5 | import {ERC2771ForwarderUpgradeable} from 6 | "@oz-up/metatx/ERC2771ForwarderUpgradeable.sol"; 7 | 8 | interface ITransactionForwarder_v1 { 9 | //-------------------------------------------------------------------------- 10 | // Structs 11 | 12 | /// @notice Struct used to store information about a single call. 13 | /// @param target Target contract that will receive the call. 14 | /// @param allowFailure Is the call allowed to fail in the multicall execution. 15 | /// @param callData Data of the call. 16 | struct SingleCall { 17 | address target; 18 | bool allowFailure; 19 | bytes callData; 20 | } 21 | 22 | /// @notice Struct used to store information about a call result. 23 | /// @param success Was the call a success. 24 | /// @param returnData Return data of the call. 25 | struct Result { 26 | bool success; 27 | bytes returnData; 28 | } 29 | 30 | //-------------------------------------------------------------------------- 31 | // Errors 32 | 33 | /// @notice The request `from` doesn't match with the recovered `signer`. 34 | /// @param call The call that failed. 35 | error CallFailed(SingleCall call); 36 | 37 | //-------------------------------------------------------------------------- 38 | // Metatransaction Helper Functions 39 | 40 | /// @notice Creates a digest for the given `ForwardRequestData`. 41 | /// @dev The signature field of the given `ForwardRequestData` can be empty. 42 | /// @param req The ForwardRequest you want to get the digest from. 43 | /// @return digest The digest needed to create a signature for the request. 44 | function createDigest( 45 | ERC2771ForwarderUpgradeable.ForwardRequestData memory req 46 | ) external view returns (bytes32 digest); 47 | 48 | //-------------------------------------------------------------------------- 49 | // Multicall Functions 50 | 51 | /// @notice Enables the execution of multiple calls in a single transaction. 52 | /// @param calls Array of call structs that should be executed in the multicall. 53 | /// @return returnData The return data of the calls that were executed. 54 | function executeMulticall(SingleCall[] calldata calls) 55 | external 56 | returns (Result[] memory returnData); 57 | } 58 | -------------------------------------------------------------------------------- /src/external/interfaces/IERC2771Context.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | interface IERC2771Context { 5 | /// @notice Returns the trusted forwarder for the EIP2771 Standard. 6 | function isTrustedForwarder(address forwarder) 7 | external 8 | view 9 | returns (bool); 10 | } 11 | -------------------------------------------------------------------------------- /src/external/reverter/InverterReverter_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity 0.8.23; 3 | 4 | /** 5 | * @title Inverter Reverter 6 | * 7 | * @notice Enables the Inverter beacon structure to return a predefined error message in case a paused contract is 8 | * called. 9 | * 10 | * @dev Reverts all transactions with a predefined error 11 | * 12 | * @custom:security-contact security@inverter.network 13 | * In case of any concerns or findings, please refer to our Security Policy 14 | * at security.inverter.network or email us directly! 15 | * 16 | * @author Inverter Network 17 | */ 18 | contract InverterReverter_v1 { 19 | /// @notice The contract that the transactions was meant to interact with is paused. 20 | error InverterReverter__ContractPaused(); 21 | 22 | fallback() external { 23 | revert InverterReverter__ContractPaused(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/external/token/ERC20Issuance_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity 0.8.23; 3 | 4 | // External Interfaces 5 | import {IERC20Issuance_v1} from "@ex/token/IERC20Issuance_v1.sol"; 6 | 7 | // External Dependencies 8 | import {ERC20, ERC20Capped} from "@oz/token/ERC20/extensions/ERC20Capped.sol"; 9 | import {Ownable} from "@oz/access/Ownable.sol"; 10 | 11 | /** 12 | * @title Inverter ERC20 Issuance Token 13 | * 14 | * @notice This contract creates an {ERC20} token with a supply cap and a whitelist-gated functionality 15 | * to mint and burn tokens. 16 | * 17 | * @dev The contract implements functionalities for: 18 | * - Managing a whitelist of allowed minters. 19 | * - Minting and burning tokens by members of said whitelist. 20 | * - Enforcing a supply cap on minted tokens. 21 | * 22 | * @custom:security-contact security@inverter.network 23 | * In case of any concerns or findings, please refer to our Security Policy 24 | * at security.inverter.network or email us directly! 25 | * 26 | * @author Inverter Network 27 | */ 28 | contract ERC20Issuance_v1 is IERC20Issuance_v1, ERC20Capped, Ownable { 29 | // State Variables 30 | /// @dev The mapping of allowed minters. 31 | mapping(address => bool) public allowedMinters; 32 | /// @dev The number of decimals of the token. 33 | uint8 internal immutable _decimals; 34 | 35 | //------------------------------------------------------------------------------ 36 | // Modifiers 37 | 38 | /// @dev Modifier to guarantee the caller is a minter. 39 | modifier onlyMinter() { 40 | if (!allowedMinters[_msgSender()]) { 41 | revert IERC20Issuance__CallerIsNotMinter(); 42 | } 43 | _; 44 | } 45 | 46 | //------------------------------------------------------------------------------ 47 | // Constructor 48 | 49 | constructor( 50 | string memory name_, 51 | string memory symbol_, 52 | uint8 decimals_, 53 | uint maxSupply_, 54 | address initialAdmin_ 55 | ) ERC20(name_, symbol_) ERC20Capped(maxSupply_) Ownable(initialAdmin_) { 56 | _setMinter(initialAdmin_, true); 57 | _decimals = decimals_; 58 | } 59 | 60 | //------------------------------------------------------------------------------ 61 | // External Functions 62 | 63 | function decimals() public view override returns (uint8) { 64 | return _decimals; 65 | } 66 | 67 | /// @inheritdoc IERC20Issuance_v1 68 | function setMinter(address _minter, bool _allowed) external onlyOwner { 69 | _setMinter(_minter, _allowed); 70 | } 71 | 72 | /// @inheritdoc IERC20Issuance_v1 73 | function mint(address _to, uint _amount) external onlyMinter { 74 | _mint(_to, _amount); 75 | } 76 | 77 | /// @inheritdoc IERC20Issuance_v1 78 | function burn(address _from, uint _amount) external onlyMinter { 79 | _burn(_from, _amount); 80 | } 81 | 82 | //------------------------------------------------------------------------------ 83 | // Internal Functions 84 | 85 | /// @notice Sets the minting rights of an address. 86 | /// @param _minter The address of the minter. 87 | /// @param _allowed If the address is allowed to mint or not. 88 | function _setMinter(address _minter, bool _allowed) internal { 89 | allowedMinters[_minter] = _allowed; 90 | emit MinterSet(_minter, _allowed); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/external/token/IERC20Issuance_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | // External Interfaces 5 | import {IERC20} from "@oz/token/ERC20/IERC20.sol"; 6 | 7 | interface IERC20Issuance_v1 is IERC20 { 8 | //-------------------------------------------------------------------------- 9 | // Events 10 | 11 | /// @notice Emitted when the minter is set. 12 | event MinterSet(address indexed minter, bool allowed); 13 | 14 | //-------------------------------------------------------------------------- 15 | // Errors 16 | error IERC20Issuance__CallerIsNotMinter(); 17 | 18 | //-------------------------------------------------------------------------- 19 | // Functions 20 | 21 | // Write 22 | 23 | /// @notice Sets the minting rights of an address. 24 | /// @param _minter The address of the minter. 25 | /// @param _allowed If the address is allowed to mint or not. 26 | function setMinter(address _minter, bool _allowed) external; 27 | 28 | /// @notice Mints new tokens. 29 | /// @param _to The address of the recipient. 30 | /// @param _amount The amount of tokens to mint. 31 | function mint(address _to, uint _amount) external; 32 | 33 | /// @notice Burns tokens. 34 | /// @param _from The address of the owner or approved address. 35 | /// @param _amount The amount of tokens to burn. 36 | function burn(address _from, uint _amount) external; 37 | 38 | // Read 39 | 40 | /// @notice Mapping of allowed minters. 41 | /// @param _minter The address of the minter. 42 | /// @return If the address is allowed to mint or not. 43 | function allowedMinters(address _minter) external view returns (bool); 44 | } 45 | -------------------------------------------------------------------------------- /src/modules/fundingManager/IFundingManager_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | // External Interfaces 5 | import {IERC20} from "@oz/token/ERC20/IERC20.sol"; 6 | 7 | interface IFundingManager_v1 { 8 | //-------------------------------------------------------------------------- 9 | // Events 10 | 11 | /// @notice Event emitted when a transferal of orchestrator tokens takes place. 12 | /// @param _to The address that will receive the underlying tokens. 13 | /// @param _amount The amount of underlying tokens transfered. 14 | event TransferOrchestratorToken(address indexed _to, uint _amount); 15 | 16 | /// @notice Event emitted when collateral token has been set. 17 | /// @param token The token that serves as collateral token making up the curve's reserve. 18 | event OrchestratorTokenSet(address indexed token, uint8 decimals); 19 | 20 | //-------------------------------------------------------------------------- 21 | // Functions 22 | 23 | /// @notice Returns the token. 24 | /// @return The token. 25 | function token() external view returns (IERC20); 26 | 27 | /// @notice Transfer a specified amount of Tokens to a designated receiver address. 28 | /// @dev This function MUST be restricted to be called only by the {Orchestrator_v1}. 29 | /// @dev This function CAN update internal user balances to account for the new token balance. 30 | /// @param to The address that will receive the tokens. 31 | /// @param amount The amount of tokens to be transfered. 32 | function transferOrchestratorToken(address to, uint amount) external; 33 | } 34 | -------------------------------------------------------------------------------- /src/modules/fundingManager/bondingCurve/FM_BC_Restricted_Bancor_Redeeming_VirtualSupply_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity 0.8.23; 3 | 4 | // Internal Dependencies 5 | 6 | import { 7 | FM_BC_Bancor_Redeeming_VirtualSupply_v1, 8 | IFM_BC_Bancor_Redeeming_VirtualSupply_v1, 9 | IFundingManager_v1 10 | } from "@fm/bondingCurve/FM_BC_Bancor_Redeeming_VirtualSupply_v1.sol"; 11 | 12 | /** 13 | * @title Inverter Restricted Bancor Virtual Supply Bonding Curve Funding Manager 14 | * 15 | * @notice This contract enables the issuance and redeeming of tokens on a bonding curve, using 16 | * a virtual supply for both the issuance and the collateral as input. It integrates 17 | * Aragon's Bancor Formula to manage the calculations for token issuance and redemption 18 | * rates based on specified reserve ratios. 19 | * 20 | * @dev It overrides the `buyFor()` and `sellTo()` functions of its parent contract to limit 21 | * them to callers holding a "Curve Interaction" role. Since the upstream functions `buy()` and `sell()` 22 | * call these functions internally, they also become gated. 23 | * 24 | * PLEASE NOTE: This means that the workflow itself can only mint tokens through buying 25 | * and selling by somebody with the `CURVE_INTERACTION_ROLE`, but NOT that there are no other ways to 26 | * mint tokens. The Bonding Curve uses an external token contract, and there is no guarantee that said 27 | * uses an external token contract, and there is no guarantee that said contract won't 28 | * have an additional way to mint tokens (and potentially sell them on the cruve to receive 29 | * backing collateral) 30 | * 31 | * @custom:security-contact security@inverter.network 32 | * In case of any concerns or findings, please refer to our Security Policy 33 | * at security.inverter.network or email us directly! 34 | * 35 | * @author Inverter Network 36 | */ 37 | contract FM_BC_Restricted_Bancor_Redeeming_VirtualSupply_v1 is 38 | FM_BC_Bancor_Redeeming_VirtualSupply_v1 39 | { 40 | //-------------------------------------------------------------------------- 41 | // Errors 42 | 43 | /// @notice The feature is deactivated in this implementation. 44 | error Module__FM_BC_Restricted_Bancor_Redeeming_VirtualSupply__FeatureDeactivated( 45 | ); 46 | 47 | //-------------------------------------------------------------------------- 48 | // Storage 49 | 50 | /// @dev Minter/Burner Role. 51 | bytes32 public constant CURVE_INTERACTION_ROLE = "CURVE_USER"; 52 | 53 | /// @dev Storage gap for future upgrades. 54 | uint[50] private __gap; 55 | 56 | //-------------------------------------------------------------------------- 57 | // Public Functions 58 | 59 | /// @inheritdoc FM_BC_Bancor_Redeeming_VirtualSupply_v1 60 | /// @dev Adds additional role check to the buyFor function. 61 | function buyFor(address _receiver, uint _depositAmount, uint _minAmountOut) 62 | public 63 | override 64 | onlyModuleRole(CURVE_INTERACTION_ROLE) 65 | { 66 | super.buyFor(_receiver, _depositAmount, _minAmountOut); 67 | } 68 | 69 | /// @inheritdoc FM_BC_Bancor_Redeeming_VirtualSupply_v1 70 | /// @dev Adds addtional role check to the sellTo function. 71 | function sellTo(address _receiver, uint _depositAmount, uint _minAmountOut) 72 | public 73 | override 74 | onlyModuleRole(CURVE_INTERACTION_ROLE) 75 | { 76 | super.sellTo(_receiver, _depositAmount, _minAmountOut); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/modules/fundingManager/bondingCurve/FM_BC_Tools.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity 0.8.23; 3 | 4 | /** 5 | * @title Inverter Bonding Curve Tools Library 6 | * 7 | * @custom:security-contact security@inverter.network 8 | * In case of any concerns or findings, please refer to our Security Policy 9 | * at security.inverter.network or email us directly! 10 | * 11 | * @author Inverter Network 12 | */ 13 | library FM_BC_Tools { 14 | /// @dev Error thrown when the fee amount is too high. 15 | /// This error is thrown when the fee amount is greater than the maximum fee percentage. 16 | /// It takes care of both upscaling and downscaling the decimals based on the required decimals. 17 | /// @param _amount The amount to be converted. 18 | /// @param _tokenDecimals The current decimal places of the token. 19 | /// @param _requiredDecimals The required decimal places for the token. 20 | /// @return The converted amount with required decimal places. 21 | function _convertAmountToRequiredDecimal( 22 | uint _amount, 23 | uint8 _tokenDecimals, 24 | uint8 _requiredDecimals 25 | ) internal pure returns (uint) { 26 | // If the token decimal is the same as required decimal, return amount 27 | if (_tokenDecimals == _requiredDecimals) { 28 | return _amount; 29 | } 30 | // If the decimal of token is > required decimal, calculate conversion rate and 31 | // return amount converted to required decimal 32 | if (_tokenDecimals > _requiredDecimals) { 33 | uint conversionFactor = (10 ** (_tokenDecimals - _requiredDecimals)); 34 | return (_amount / conversionFactor); 35 | } else { 36 | // If the decimal of token is < required decimal, calculate conversion rate and 37 | // return amount converted to required decimals 38 | uint conversionFactor = (10 ** (_requiredDecimals - _tokenDecimals)); 39 | return (_amount * conversionFactor); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/modules/fundingManager/bondingCurve/abstracts/VirtualIssuanceSupplyBase_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity 0.8.23; 3 | 4 | // Internal Dependencies 5 | import {IVirtualIssuanceSupplyBase_v1} from 6 | "@fm/bondingCurve/interfaces/IVirtualIssuanceSupplyBase_v1.sol"; 7 | 8 | // External Dependencies 9 | import {ERC165Upgradeable} from 10 | "@oz-up/utils/introspection/ERC165Upgradeable.sol"; 11 | 12 | /** 13 | * @title Inverter Virtual Issuance Supply Base 14 | * 15 | * @notice Manages a virtual issuance supply to facilitate interactions with Inverter's 16 | * Funding Manager 17 | * 18 | * @dev Implements {IVirtualIssuancelSupplyBase_v1} for handling virtual issuance. 19 | * Includes functions to set, get, add, and subtract virtual issuance amounts. 20 | * 21 | * @custom:security-contact security@inverter.network 22 | * In case of any concerns or findings, please refer to our Security Policy 23 | * at security.inverter.network or email us directly! 24 | * 25 | * @author Inverter Network 26 | */ 27 | abstract contract VirtualIssuanceSupplyBase_v1 is 28 | IVirtualIssuanceSupplyBase_v1, 29 | ERC165Upgradeable 30 | { 31 | /// @inheritdoc ERC165Upgradeable 32 | function supportsInterface(bytes4 interfaceId) 33 | public 34 | view 35 | virtual 36 | override(ERC165Upgradeable) 37 | returns (bool) 38 | { 39 | bytes4 interfaceId_IVirtualIssuanceSupply = 40 | type(IVirtualIssuanceSupplyBase_v1).interfaceId; 41 | return interfaceId == interfaceId_IVirtualIssuanceSupply 42 | || super.supportsInterface(interfaceId); 43 | } 44 | 45 | //-------------------------------------------------------------------------- 46 | // Storage 47 | 48 | /// @dev The internal state variable to keep track of the virtual issuance supply. 49 | uint internal virtualIssuanceSupply; 50 | /// @dev Maximum unsigned integer value for overflow checks. 51 | uint private constant MAX_UINT = type(uint).max; 52 | 53 | /// @dev Storage gap for future upgrades. 54 | uint[50] private __gap; 55 | 56 | //-------------------------------------------------------------------------- 57 | // Public Functions 58 | 59 | /// @inheritdoc IVirtualIssuanceSupplyBase_v1 60 | function getVirtualIssuanceSupply() external view virtual returns (uint) { 61 | return virtualIssuanceSupply; 62 | } 63 | 64 | //-------------------------------------------------------------------------- 65 | // Public Functions Implemented in Downstream Contract 66 | 67 | /// @inheritdoc IVirtualIssuanceSupplyBase_v1 68 | function setVirtualIssuanceSupply(uint _virtualSupply) external virtual; 69 | 70 | //-------------------------------------------------------------------------- 71 | // Internal Functions 72 | 73 | /// @dev Adds a specified amount to the virtual issuance supply. 74 | /// Checks for overflow and reverts if an overflow occurs. 75 | /// @param _amount The amount to add to the virtual issuance supply. 76 | function _addVirtualIssuanceAmount(uint _amount) internal virtual { 77 | if (_amount > (MAX_UINT - virtualIssuanceSupply)) { 78 | revert Module__VirtualIssuanceSupplyBase__AddResultsInOverflow(); 79 | } 80 | unchecked { 81 | virtualIssuanceSupply += _amount; 82 | } 83 | 84 | emit VirtualIssuanceAmountAdded(_amount, virtualIssuanceSupply); 85 | } 86 | 87 | /// @dev Subtracts a specified amount from the virtual issuance supply. 88 | /// Checks for underflow and reverts if an underflow occurs. 89 | /// @param _amount The amount to subtract from the virtual issuance supply. 90 | function _subVirtualIssuanceAmount(uint _amount) internal virtual { 91 | if (_amount > virtualIssuanceSupply) { 92 | revert Module__VirtualIssuanceSupplyBase__SubtractResultsInUnderflow( 93 | ); 94 | } 95 | 96 | if (_amount == virtualIssuanceSupply) { 97 | revert Module__VirtualIssuanceSupplyBase__VirtualSupplyCannotBeZero( 98 | ); 99 | } 100 | unchecked { 101 | virtualIssuanceSupply -= _amount; 102 | } 103 | emit VirtualIssuanceAmountSubtracted(_amount, virtualIssuanceSupply); 104 | } 105 | 106 | /// @dev Internal function to directly set the virtual issuance supply to a new value. 107 | /// @param _virtualSupply The new value to set for the virtual issuance supply. 108 | function _setVirtualIssuanceSupply(uint _virtualSupply) internal virtual { 109 | if (_virtualSupply == 0) { 110 | revert Module__VirtualIssuanceSupplyBase__VirtualSupplyCannotBeZero( 111 | ); 112 | } 113 | emit VirtualIssuanceSupplySet(_virtualSupply, virtualIssuanceSupply); 114 | virtualIssuanceSupply = _virtualSupply; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/modules/fundingManager/bondingCurve/formulas/Utils.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.23; 2 | 3 | /// @title Aragon Bancor Formula Utils 4 | /// @author https://github.com/AragonBlack/fundraising/blob/master/apps/bancor-formula/contracts/utility/Utils.sol 5 | /// @notice The sole modification implemented in the contract involves altering the Soldity version number 6 | /// while also removing the 'public' keyword from the constructor, as per version-specified. 7 | 8 | /* 9 | Utilities & Common Modifiers 10 | */ 11 | contract Utils { 12 | /** 13 | * constructor 14 | */ 15 | constructor() {} 16 | 17 | // verifies that an amount is greater than zero 18 | modifier greaterThanZero(uint _amount) { 19 | require(_amount > 0); 20 | _; 21 | } 22 | 23 | // verifies that the address is different than this contract address 24 | modifier notThis(address _address) { 25 | require(_address != address(this)); 26 | _; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/modules/fundingManager/bondingCurve/interfaces/IBancorFormula.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | /// @title Aragon Interface for the Bancor Formula 4 | /// @author https://github.com/AragonBlack/fundraising/blob/master/apps/bancor-formula/contracts/interfaces/IBancorFormula.sol 5 | /// @notice The only revision that has been enacted within this distinct contract pertains to the 6 | /// adjustment of the Solidity version, accompanied by version-specific changes. These 7 | /// revisions encompass the changing of the 'contract' keyword into an 'interface' and the 8 | /// modification of function visibility, transitioning from 'public' to 'external' 9 | 10 | /* 11 | Bancor Formula interface 12 | */ 13 | interface IBancorFormula { 14 | function calculatePurchaseReturn( 15 | uint _supply, 16 | uint _connectorBalance, 17 | uint32 _connectorWeight, 18 | uint _depositAmount 19 | ) external view returns (uint); 20 | function calculateSaleReturn( 21 | uint _supply, 22 | uint _connectorBalance, 23 | uint32 _connectorWeight, 24 | uint _sellAmount 25 | ) external view returns (uint); 26 | function calculateCrossConnectorReturn( 27 | uint _fromConnectorBalance, 28 | uint32 _fromConnectorWeight, 29 | uint _toConnectorBalance, 30 | uint32 _toConnectorWeight, 31 | uint _amount 32 | ) external view returns (uint); 33 | } 34 | -------------------------------------------------------------------------------- /src/modules/fundingManager/bondingCurve/interfaces/IFM_BC_Bancor_Redeeming_VirtualSupply_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | interface IFM_BC_Bancor_Redeeming_VirtualSupply_v1 { 5 | //-------------------------------------------------------------------------- 6 | // Errors 7 | 8 | /// @notice Reserve ratio can not be be bigger than 100% expressed in PPM. 9 | error Module__FM_BC_Bancor_Redeeming_VirtualSupply__InvalidReserveRatio(); 10 | 11 | /// @notice To avoid destructive precision loss when using the Bancor Formula, 12 | /// the Token decimals should: 13 | /// - Not be lower than 7 decimals. 14 | /// - Higher or equal to the collateral token decimals. 15 | error Module__FM_BC_Bancor_Redeeming_VirtualSupply__InvalidTokenDecimal(); 16 | 17 | /// @notice Invalid Bancor Formula contract 18 | error Module__FM_BC_Bancor_Redeeming_VirtualSupply__InvalidBancorFormula(); 19 | 20 | /// @notice Buying and Selling must be closed before changing the virtual supply. 21 | error Module__FM_BC_Bancor_Redeeming_VirtualSupply__CurveInteractionsMustBeClosed( 22 | ); 23 | /// @notice Funding manager does not hold the amount of collateral the payment client tries to transfer. 24 | error Module__FM_BC_Bancor_Redeeming_VirtualSupply__InvalidOrchestratorTokenWithdrawAmount( 25 | ); 26 | 27 | //-------------------------------------------------------------------------- 28 | // Events 29 | 30 | /// @notice Event emitted when the reserve ratio for buying is updated. 31 | /// @param newBuyReserveRatio The new reserve ratio for buying. 32 | /// @param oldBuyReserveRatio The old reserve ratio for buying. 33 | event BuyReserveRatioSet( 34 | uint32 newBuyReserveRatio, uint32 oldBuyReserveRatio 35 | ); 36 | 37 | /// @notice Event emitted when the reserve ratio for selling is updated. 38 | /// @param newSellReserveRatio The new reserve ratio for selling. 39 | /// @param oldSellReserveRatio The old reserve ratio for selling. 40 | event SellReserveRatioSet( 41 | uint32 newSellReserveRatio, uint32 oldSellReserveRatio 42 | ); 43 | 44 | //-------------------------------------------------------------------------- 45 | // Structs 46 | 47 | /// @notice Struct used to store information about the bonding curve properties. 48 | /// @param formula The formula contract used to calculate the issuance and redemption rate. 49 | /// @param reserveRatioForBuying The reserve ratio, expressed in PPM, used for issuance on the bonding curve. 50 | /// @param reserveRatioForSelling The reserve ratio, expressed in PPM, used for redeeming on the bonding curve. 51 | /// @param buyFee The buy fee expressed in base points. 52 | /// @param sellFee The sell fee expressed in base points. 53 | /// @param buyIsOpen The indicator used for enabling/disabling the buying functionalities on deployment. 54 | /// @param sellIsOpen The indicator used for enabling/disabling the selling functionalities on deployment. 55 | /// @param initialIssuanceSupply The initial virtual issuance token supply. 56 | /// @param initialCollateralSupply The initial virtual collateral token supply. 57 | struct BondingCurveProperties { 58 | address formula; 59 | uint32 reserveRatioForBuying; 60 | uint32 reserveRatioForSelling; 61 | uint buyFee; 62 | uint sellFee; 63 | bool buyIsOpen; 64 | bool sellIsOpen; 65 | uint initialIssuanceSupply; 66 | uint initialCollateralSupply; 67 | } 68 | 69 | //-------------------------------------------------------------------------- 70 | // Functions 71 | 72 | /// @notice Set the reserve ratio used for issuing tokens on a bonding curve. 73 | /// @dev This function can only be called by the {Orchestrator_v1} admin. 74 | /// @param _reserveRatio The new reserve ratio for buying, expressed in PPM. 75 | function setReserveRatioForBuying(uint32 _reserveRatio) external; 76 | 77 | /// @notice Set the reserve ratio used for redeeming tokens on a bonding curve. 78 | /// @dev This function can only be called by the {Orchestrator_v1} admin. 79 | /// @param _reserveRatio The new reserve ratio for selling, expressed in PPM. 80 | function setReserveRatioForSelling(uint32 _reserveRatio) external; 81 | 82 | /// @notice Returns reserve ratio set for buying, used in the {BancorFormula} contract. 83 | /// @return Reserve Ratio for buying. 84 | function getReserveRatioForBuying() external view returns (uint32); 85 | 86 | /// @notice Returns reserve ratio set for selling, used in the {BancorFormula} contract. 87 | /// @return Reserve Ratio for selling. 88 | function getReserveRatioForSelling() external view returns (uint32); 89 | } 90 | -------------------------------------------------------------------------------- /src/modules/fundingManager/bondingCurve/interfaces/IRedeemingBondingCurveBase_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | interface IRedeemingBondingCurveBase_v1 { 5 | //-------------------------------------------------------------------------- 6 | // Errors 7 | 8 | /// @notice Selling functionalities are set to closed. 9 | error Module__RedeemingBondingCurveBase__SellingFunctionaltiesClosed(); 10 | 11 | /// @notice Not enough collateral in contract for redemption. 12 | error Module__RedeemingBondingCurveBase__InsufficientCollateralForRedemption( 13 | ); 14 | 15 | //-------------------------------------------------------------------------- 16 | // Events 17 | 18 | /// @notice Event emitted when selling is opened. 19 | event SellingEnabled(); 20 | 21 | /// @notice Event emitted when selling is closed. 22 | event SellingDisabled(); 23 | 24 | /// @notice Event emitted when sell fee is updated. 25 | /// @param newSellFee The new sell fee. 26 | /// @param oldSellFee The old sell fee. 27 | event SellFeeUpdated(uint newSellFee, uint oldSellFee); 28 | 29 | /// @notice Event emitted when tokens have been succesfully redeemed. 30 | /// @param receiver The address that will receive the redeemed tokens. 31 | /// @param depositAmount The amount of issued token deposited. 32 | /// @param receivedAmount The amount of collateral token received. 33 | /// @param seller The address that initiated the sell order. 34 | event TokensSold( 35 | address indexed receiver, 36 | uint depositAmount, 37 | uint receivedAmount, 38 | address seller 39 | ); 40 | 41 | //-------------------------------------------------------------------------- 42 | // Functions 43 | 44 | /// @notice Redeem tokens and directs the proceeds to a specified receiver address. 45 | /// @dev Executes a sell order, with the proceeds being sent directly to the _receiver's address. 46 | /// This function wraps the `_sellOrder` internal function with specified parameters to handle 47 | /// the transaction and direct the proceeds. 48 | /// @param _receiver The address that will receive the redeemed tokens. 49 | /// @param _depositAmount The amount of tokens to be sold. 50 | /// @param _minAmountOut The minimum acceptable amount of proceeds that the receiver should receive from the sale. 51 | function sellTo(address _receiver, uint _depositAmount, uint _minAmountOut) 52 | external; 53 | 54 | /// @notice Redeem collateral for the sender's address. 55 | /// @dev Redirects to the internal function `_sellOrder` by passing the sender's address and deposit amount. 56 | /// @param _depositAmount The amount of issued token deposited. 57 | /// @param _minAmountOut The minimum acceptable amount the user expects to receive from the transaction. 58 | function sell(uint _depositAmount, uint _minAmountOut) external; 59 | 60 | /// @notice Opens the selling functionality for the collateral. 61 | /// @dev Only callable by the {Orchestrator_v1} admin. 62 | /// Reverts if selling is already open. 63 | function openSell() external; 64 | 65 | /// @notice Closes the selling functionality for the collateral. 66 | /// @dev Only callable by the {Orchestrator_v1} admin. 67 | /// Reverts if selling is already closed. 68 | function closeSell() external; 69 | 70 | /// @notice Sets the fee percentage for selling collateral, payed in collateral. 71 | /// @dev Only callable by the {Orchestrator_v1} admin. 72 | /// The fee cannot exceed 10000 basis points. Reverts if an invalid fee is provided. 73 | /// @param _fee The fee in basis points. 74 | function setSellFee(uint _fee) external; 75 | 76 | /// @notice Calculates and returns the static price for selling the issuance token. 77 | /// @return uint The static price for selling the issuance token. 78 | function getStaticPriceForSelling() external view returns (uint); 79 | 80 | /// @notice Calculates the amount of tokens to be redeemed based on a given deposit amount. 81 | /// @dev This function takes into account any applicable sell fees before computing the 82 | /// collateral amount to be redeemed. Revert when `_depositAmount` is zero. 83 | /// @param _depositAmount The amount of tokens deposited by the user. 84 | /// @return redeemAmount The amount of collateral that will be redeemed as a result of the deposit. 85 | function calculateSaleReturn(uint _depositAmount) 86 | external 87 | returns (uint redeemAmount); 88 | } 89 | -------------------------------------------------------------------------------- /src/modules/fundingManager/bondingCurve/interfaces/IVirtualCollateralSupplyBase_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | interface IVirtualCollateralSupplyBase_v1 { 5 | //-------------------------------------------------------------------------- 6 | // Errors 7 | 8 | /// @notice The virtual supply cannot be zero. 9 | error Module__VirtualCollateralSupplyBase__VirtualSupplyCannotBeZero(); 10 | 11 | // @notice Subtracting would result in an underflow. 12 | error Module__VirtualCollateralSupplyBase__SubtractResultsInUnderflow(); 13 | 14 | /// @notice Adding would result in and overflow. 15 | error Module__VirtualCollateralSupplyBase__AddResultsInOverflow(); 16 | 17 | //-------------------------------------------------------------------------- 18 | // Events 19 | 20 | /// @notice Event emitted when virtual collateral supply has been set. 21 | event VirtualCollateralSupplySet(uint newSupply, uint oldSupply); 22 | 23 | /// @notice Event emitted when virtual collateral amount has been added. 24 | event VirtualCollateralAmountAdded(uint amountAdded, uint newSupply); 25 | 26 | /// @notice Event emitted when virtual collateral amount has been subtracted. 27 | event VirtualCollateralAmountSubtracted( 28 | uint amountSubtracted, uint newSupply 29 | ); 30 | 31 | //-------------------------------------------------------------------------- 32 | // Functions 33 | 34 | /// @notice Sets the virtual collateral supply to a new value. 35 | /// @dev This function should call the internal function `_setVirtualCollateralSupply`. 36 | /// The function must be implemented by the downstream contract. The downstream contract should 37 | /// manage access control for setting the supply. 38 | /// @param _virtualSupply The new value to set for the virtual collateral supply. 39 | function setVirtualCollateralSupply(uint _virtualSupply) external; 40 | 41 | /// @notice Returns the current virtual collateral supply. 42 | /// @dev This function returns the virtual supply by calling the 43 | /// internal `_getVirtualCollateralSupply` function. 44 | /// @return The current virtual collateral supply as a uint. 45 | function getVirtualCollateralSupply() external view returns (uint); 46 | } 47 | -------------------------------------------------------------------------------- /src/modules/fundingManager/bondingCurve/interfaces/IVirtualIssuanceSupplyBase_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | interface IVirtualIssuanceSupplyBase_v1 { 5 | //-------------------------------------------------------------------------- 6 | // Errors 7 | 8 | /// @notice The virtual supply cannot be zero. 9 | error Module__VirtualIssuanceSupplyBase__VirtualSupplyCannotBeZero(); 10 | 11 | /// @notice Subtracting would result in an underflow. 12 | error Module__VirtualIssuanceSupplyBase__SubtractResultsInUnderflow(); 13 | 14 | /// @notice Adding would result in and overflow. 15 | error Module__VirtualIssuanceSupplyBase__AddResultsInOverflow(); 16 | 17 | //-------------------------------------------------------------------------- 18 | // Events 19 | 20 | /// @notice Event emitted when virtual issuance supply has been set. 21 | /// @param newSupply The new virtual issuance supply. 22 | /// @param oldSupply The old virtual issuance supply. 23 | event VirtualIssuanceSupplySet(uint newSupply, uint oldSupply); 24 | 25 | /// @notice Event emitted when virtual issuance amount has been added. 26 | /// @param amountAdded The amount added to the virtual issuance supply. 27 | /// @param newSupply The new virtual issuance supply. 28 | event VirtualIssuanceAmountAdded(uint amountAdded, uint newSupply); 29 | 30 | /// @notice Event emitted when virtual issuance amount has ben subtracted. 31 | /// @param amountSubtracted The amount subtracted from the virtual issuance supply. 32 | /// @param newSupply The new virtual issuance supply. 33 | event VirtualIssuanceAmountSubtracted( 34 | uint amountSubtracted, uint newSupply 35 | ); 36 | 37 | //-------------------------------------------------------------------------- 38 | // Functions 39 | 40 | /// @notice Sets the virtual issuance supply to a new value. 41 | /// @dev This function calls the internal function `_setVirtualIssuanceSupply`. 42 | /// The function must be implemented by the downstream contract. The downstream contract should 43 | /// manage access control for setting the supply. 44 | /// @param _virtualSupply The new value to set for the virtual issuance supply. 45 | function setVirtualIssuanceSupply(uint _virtualSupply) external; 46 | 47 | /// @notice Returns the current virtual issuance supply. 48 | /// @dev This function returns the virtual supply by calling the 49 | /// internal `_getVirtualIssuanceSupply` function. 50 | /// @return The current virtual issuance supply as a uint. 51 | function getVirtualIssuanceSupply() external view returns (uint); 52 | } 53 | -------------------------------------------------------------------------------- /src/modules/fundingManager/depositVault/FM_DepositVault_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity 0.8.23; 3 | 4 | // Internal Interfaces 5 | import {IOrchestrator_v1} from 6 | "src/orchestrator/interfaces/IOrchestrator_v1.sol"; 7 | import {IFundingManager_v1} from "@fm/IFundingManager_v1.sol"; 8 | import {IFM_DepositVault_v1} from 9 | "@fm/depositVault/interfaces/IFM_DepositVault_v1.sol"; 10 | 11 | // Internal Dependencies 12 | import {Module_v1} from "src/modules/base/Module_v1.sol"; 13 | 14 | // External Interfaces 15 | import {IERC20} from "@oz/token/ERC20/extensions/IERC20Metadata.sol"; 16 | 17 | // External Dependencies 18 | import {ERC165Upgradeable} from 19 | "@oz-up/utils/introspection/ERC165Upgradeable.sol"; 20 | 21 | // External Libraries 22 | import {SafeERC20} from "@oz/token/ERC20/utils/SafeERC20.sol"; 23 | 24 | /** 25 | * @title Inverter Deposit Vault Funding Manager 26 | * 27 | * @notice This contract allows users to deposit tokens to fund the workflow. 28 | * 29 | * @dev Implements {IFundingManager_v1} interface. 30 | * 31 | * @custom:security-contact security@inverter.network 32 | * In case of any concerns or findings, please refer to our Security Policy 33 | * at security.inverter.network or email us directly! 34 | * 35 | * @author Inverter Network 36 | */ 37 | contract FM_DepositVault_v1 is 38 | IFundingManager_v1, 39 | IFM_DepositVault_v1, 40 | Module_v1 41 | { 42 | /// @inheritdoc ERC165Upgradeable 43 | function supportsInterface(bytes4 interfaceId) 44 | public 45 | view 46 | virtual 47 | override(Module_v1) 48 | returns (bool) 49 | { 50 | return interfaceId == type(IFundingManager_v1).interfaceId 51 | || interfaceId == type(IFM_DepositVault_v1).interfaceId 52 | || super.supportsInterface(interfaceId); 53 | } 54 | 55 | using SafeERC20 for IERC20; 56 | 57 | //-------------------------------------------------------------------------- 58 | // Storage 59 | 60 | /// @dev The token that is deposited. 61 | IERC20 private _token; 62 | 63 | /// @dev Storage gap for future upgrades. 64 | uint[50] private __gap; 65 | 66 | //-------------------------------------------------------------------------- 67 | // Init Function 68 | 69 | /// @inheritdoc Module_v1 70 | function init( 71 | IOrchestrator_v1 orchestrator_, 72 | Metadata memory metadata, 73 | bytes memory configData 74 | ) external override initializer { 75 | __Module_init(orchestrator_, metadata); 76 | 77 | address orchestratorTokenAddress = abi.decode(configData, (address)); 78 | _token = IERC20(orchestratorTokenAddress); 79 | } 80 | 81 | //-------------------------------------------------------------------------- 82 | // Public View Functions 83 | 84 | /// @inheritdoc IFundingManager_v1 85 | function token() public view returns (IERC20) { 86 | return _token; 87 | } 88 | 89 | //-------------------------------------------------------------------------- 90 | // Public Mutating Functions 91 | 92 | /// @inheritdoc IFM_DepositVault_v1 93 | function deposit(uint amount) external { 94 | address from = _msgSender(); 95 | token().safeTransferFrom(from, address(this), amount); 96 | 97 | emit Deposit(from, amount); 98 | } 99 | 100 | //-------------------------------------------------------------------------- 101 | // OnlyOrchestrator Mutating Functions 102 | 103 | /// @inheritdoc IFundingManager_v1 104 | function transferOrchestratorToken(address to, uint amount) 105 | external 106 | onlyPaymentClient 107 | validAddress(to) 108 | { 109 | token().safeTransfer(to, amount); 110 | 111 | emit TransferOrchestratorToken(to, amount); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/modules/fundingManager/depositVault/interfaces/IFM_DepositVault_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.0; 3 | 4 | interface IFM_DepositVault_v1 { 5 | //-------------------------------------------------------------------------- 6 | // Events 7 | 8 | /// @notice Event emitted when a deposit takes place. 9 | /// @param _from The address depositing tokens. 10 | /// @param _amount The amount of tokens deposited. 11 | event Deposit(address indexed _from, uint _amount); 12 | 13 | //-------------------------------------------------------------------------- 14 | // Functions 15 | 16 | /// @notice Deposits a specified amount of tokens into the contract from the sender's account. 17 | /// @dev When using the {TransactionForwarder_v1}, validate transaction success to prevent nonce 18 | /// exploitation and ensure transaction integrity. 19 | /// @param amount The number of tokens to deposit. 20 | function deposit(uint amount) external; 21 | } 22 | -------------------------------------------------------------------------------- /src/modules/fundingManager/rebasing/interfaces/IERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol) 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @dev Interface of the ERC20 standard as defined in the EIP. 7 | * 8 | * @author OpenZeppelin 9 | */ 10 | interface IERC20 { 11 | /** 12 | * @dev Returns the amount of tokens in existence. 13 | */ 14 | function totalSupply() external view returns (uint); 15 | 16 | /** 17 | * @dev Returns the amount of tokens owned by `account`. 18 | */ 19 | function balanceOf(address account) external view returns (uint); 20 | 21 | /** 22 | * @dev Moves `amount` tokens from the caller's account to `to`. 23 | * 24 | * Returns a boolean value indicating whether the operation succeeded. 25 | * 26 | * Emits a {Transfer} event. 27 | */ 28 | function transfer(address to, uint amount) external returns (bool); 29 | 30 | /** 31 | * @dev Returns the remaining number of tokens that `spender` will be 32 | * allowed to spend on behalf of `owner` through {transferFrom}. This is 33 | * zero by default. 34 | * 35 | * This value changes when {approve} or {transferFrom} are called. 36 | */ 37 | function allowance(address owner, address spender) 38 | external 39 | view 40 | returns (uint); 41 | 42 | /** 43 | * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. 44 | * 45 | * Returns a boolean value indicating whether the operation succeeded. 46 | * 47 | * IMPORTANT: Beware that changing an allowance with this method brings the risk 48 | * that someone may use both the old and the new allowance by unfortunate 49 | * transaction ordering. One possible solution to mitigate this race 50 | * condition is to first reduce the spender's allowance to 0 and set the 51 | * desired value afterwards: 52 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 53 | * 54 | * Emits an {Approval} event. 55 | */ 56 | function approve(address spender, uint amount) external returns (bool); 57 | 58 | /** 59 | * @dev Moves `amount` tokens from `from` to `to` using the 60 | * allowance mechanism. `amount` is then deducted from the caller's 61 | * allowance. 62 | * 63 | * Returns a boolean value indicating whether the operation succeeded. 64 | * 65 | * Emits a {Transfer} event. 66 | */ 67 | function transferFrom(address from, address to, uint amount) 68 | external 69 | returns (bool); 70 | 71 | /** 72 | * @dev Emitted when `value` tokens are moved from one account (`from`) to 73 | * another (`to`). 74 | * 75 | * Note that `value` may be zero. 76 | */ 77 | event Transfer(address indexed from, address indexed to, uint value); 78 | 79 | /** 80 | * @dev Emitted when the allowance of a `spender` for an `owner` is set by 81 | * a call to {approve}. `value` is the new allowance. 82 | */ 83 | event Approval(address indexed owner, address indexed spender, uint value); 84 | } 85 | -------------------------------------------------------------------------------- /src/modules/fundingManager/rebasing/interfaces/IERC20Metadata.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) 3 | pragma solidity ^0.8.0; 4 | 5 | import "@fm/rebasing/interfaces/IERC20.sol"; 6 | 7 | /** 8 | * @dev Interface for the optional metadata functions from the ERC20 standard. 9 | * 10 | * _Available since v4.1._ 11 | * 12 | * @author OpenZeppelin 13 | */ 14 | interface IERC20Metadata is IERC20 { 15 | /** 16 | * @dev Returns the name of the token. 17 | */ 18 | function name() external view returns (string memory); 19 | 20 | /** 21 | * @dev Returns the symbol of the token. 22 | */ 23 | function symbol() external view returns (string memory); 24 | 25 | /** 26 | * @dev Returns the decimals places of the token. 27 | */ 28 | function decimals() external view returns (uint8); 29 | } 30 | -------------------------------------------------------------------------------- /src/modules/fundingManager/rebasing/interfaces/IRebasingERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.0; 3 | 4 | import "@fm/rebasing/interfaces/IERC20Metadata.sol"; 5 | 6 | /** 7 | * @title Rebasing ERC20 Interface 8 | * 9 | * @dev Interface definition for Rebasing ERC20 tokens which have an "elastic" 10 | * external balance and "fixed" internal balance. 11 | * Each user's external balance is represented as a product of a "scalar" 12 | * and the user's internal balance. 13 | * 14 | * In regular time intervals the rebase operation updates the scalar, 15 | * which increases or decreases all user balances proportionally. 16 | * 17 | * The standard ERC20 methods are denomintaed in the elastic balance. 18 | * 19 | * @author Buttonwood Foundation 20 | */ 21 | interface IRebasingERC20 is IERC20Metadata { 22 | //-------------------------------------------------------------------------- 23 | // Errors 24 | 25 | /// @notice Self-deposits are not allowed. 26 | error Module__RebasingERC20__CannotSelfDeposit(); 27 | 28 | /// @notice The balance would exceed the cap on deposits. 29 | error Module__RebasingERC20__DepositCapReached(); 30 | 31 | //-------------------------------------------------------------------------- 32 | // Events 33 | 34 | /// @notice Event emitted when a deposit takes place. 35 | /// @param _from The address depositing tokens. 36 | /// @param _for The address that will receive the receipt tokens. 37 | /// @param _amount The amount of tokens deposited. 38 | event Deposit(address indexed _from, address indexed _for, uint _amount); 39 | 40 | /// @notice Event emitted when a withdrawal takes place. 41 | /// @param _from The address supplying the receipt tokens. 42 | /// @param _for The address that will receive the underlying tokens. 43 | /// @param _amount The amount of underlying tokens withdrawn. 44 | event Withdrawal(address indexed _from, address indexed _for, uint _amount); 45 | 46 | //-------------------------------------------------------------------------- 47 | // Functions 48 | 49 | /// @notice Returns the fixed balance of the specified address. 50 | /// @param who The address to query. 51 | function scaledBalanceOf(address who) external view returns (uint); 52 | 53 | /// @notice Returns the total fixed supply. 54 | function scaledTotalSupply() external view returns (uint); 55 | 56 | /// @notice Transfer all of the sender's balance to a specified address. 57 | /// @param to The address to transfer to. 58 | /// @return True on success, false otherwise. 59 | function transferAll(address to) external returns (bool); 60 | 61 | /// @notice Transfer all balance tokens from one address to another. 62 | /// @param from The address to send tokens from. 63 | /// @param to The address to transfer to. 64 | function transferAllFrom(address from, address to) 65 | external 66 | returns (bool); 67 | 68 | /// @notice Triggers the next rebase, if applicable. 69 | function rebase() external; 70 | 71 | /// @notice Event emitted when the balance scalar is updated. 72 | /// @param epoch The number of rebases since inception. 73 | /// @param newScalar The new scalar. 74 | event Rebase(uint indexed epoch, uint newScalar); 75 | } 76 | -------------------------------------------------------------------------------- /src/modules/lib/LibMetadata.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity 0.8.23; 3 | 4 | // Internal Interfaces 5 | import {IModule_v1} from "src/modules/base/IModule_v1.sol"; 6 | 7 | /** 8 | * @title Inverter Metadata Library 9 | * 10 | * @dev Provides common functions for {IModule_v1}'s Metadata type. 11 | * 12 | * @custom:security-contact security@inverter.network 13 | * In case of any concerns or findings, please refer to our Security Policy 14 | * at security.inverter.network or email us directly! 15 | * 16 | * @author Inverter Network 17 | */ 18 | library LibMetadata { 19 | /// @dev Returns the identifier for given metadata. 20 | /// @param metadata The metadata. 21 | /// @return The metadata's identifier. 22 | function identifier(IModule_v1.Metadata memory metadata) 23 | internal 24 | pure 25 | returns (bytes32) 26 | { 27 | return keccak256( 28 | abi.encode(metadata.majorVersion, metadata.url, metadata.title) 29 | ); 30 | } 31 | 32 | /// @dev Returns whether the given metadata is valid. 33 | /// @param metadata The metadata. 34 | /// @return True if metadata valid, false otherwise. 35 | function isValid(IModule_v1.Metadata memory metadata) 36 | internal 37 | pure 38 | returns (bool) 39 | { 40 | // Invalid if url empty. 41 | if (bytes(metadata.url).length == 0) { 42 | return false; 43 | } 44 | 45 | // Invalid if title empty. 46 | if (bytes(metadata.title).length == 0) { 47 | return false; 48 | } 49 | 50 | // Invalid if version is v0.0.0. 51 | if ( 52 | metadata.majorVersion == 0 && metadata.minorVersion == 0 53 | && metadata.patchVersion == 0 54 | ) { 55 | return false; 56 | } 57 | 58 | return true; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/modules/lib/SafeMath.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.23; 2 | 3 | /// @title Aragon SafeMath Library 4 | /// @author https://github.com/AragonBlack/fundraising/blob/master/apps/bancor-formula/contracts/utility/SafeMath.sol 5 | /// @notice The sole modification implemented in the contract involves altering the Solidity version number. 6 | 7 | /* 8 | Library for basic math operations with overflow/underflow protection 9 | */ 10 | library SafeMath { 11 | /** 12 | * @dev returns the sum of _x and _y, reverts if the calculation overflows 13 | * 14 | * @param _x value 1 15 | * @param _y value 2 16 | * 17 | * @return sum 18 | */ 19 | function add(uint _x, uint _y) internal pure returns (uint) { 20 | uint z = _x + _y; 21 | require(z >= _x); 22 | return z; 23 | } 24 | 25 | /** 26 | * @dev returns the difference of _x minus _y, reverts if the calculation underflows 27 | * 28 | * @param _x minuend 29 | * @param _y subtrahend 30 | * 31 | * @return difference 32 | */ 33 | function sub(uint _x, uint _y) internal pure returns (uint) { 34 | require(_x >= _y); 35 | return _x - _y; 36 | } 37 | 38 | /** 39 | * @dev returns the product of multiplying _x by _y, reverts if the calculation overflows 40 | * 41 | * @param _x factor 1 42 | * @param _y factor 2 43 | * 44 | * @return product 45 | */ 46 | function mul(uint _x, uint _y) internal pure returns (uint) { 47 | // gas optimization 48 | if (_x == 0) { 49 | return 0; 50 | } 51 | 52 | uint z = _x * _y; 53 | require(z / _x == _y); 54 | return z; 55 | } 56 | 57 | /** 58 | * @dev Integer division of two numbers truncating the quotient, reverts on division by zero. 59 | * 60 | * @param _x dividend 61 | * @param _y divisor 62 | * 63 | * @return quotient 64 | */ 65 | function div(uint _x, uint _y) internal pure returns (uint) { 66 | require(_y > 0); 67 | uint c = _x / _y; 68 | 69 | return c; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/modules/logicModule/LM_PC_PaymentRouter_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity 0.8.23; 3 | 4 | // Internal Interfaces 5 | import {IOrchestrator_v1} from 6 | "src/orchestrator/interfaces/IOrchestrator_v1.sol"; 7 | import {IAuthorizer_v1} from "@aut/IAuthorizer_v1.sol"; 8 | import {ILM_PC_PaymentRouter_v1} from 9 | "@lm/interfaces/ILM_PC_PaymentRouter_v1.sol"; 10 | import { 11 | IERC20PaymentClientBase_v1, 12 | IPaymentProcessor_v1 13 | } from "@lm/abstracts/ERC20PaymentClientBase_v1.sol"; 14 | 15 | // Internal Dependencies 16 | import { 17 | ERC20PaymentClientBase_v1, 18 | Module_v1 19 | } from "@lm/abstracts/ERC20PaymentClientBase_v1.sol"; 20 | 21 | // External Dependencies 22 | import {ERC165Upgradeable} from 23 | "@oz-up/utils/introspection/ERC165Upgradeable.sol"; 24 | 25 | /** 26 | * @title Inverter Payment Router 27 | * 28 | * @notice This module enables pushing payments directly to the Payment Processor. 29 | * 30 | * @dev Extends {ERC20PaymentClientBase_v1} to integrate payment processing with 31 | * bounty management, supporting dynamic additions, updates, and the locking 32 | * of bounties. Utilizes roles for managing permissions and maintaining robust 33 | * control over bounty operations. 34 | * 35 | * @custom:security-contact security@inverter.network 36 | * In case of any concerns or findings, please refer to our Security Policy 37 | * at security.inverter.network or email us directly! 38 | * 39 | * @author Inverter Network 40 | */ 41 | contract LM_PC_PaymentRouter_v1 is 42 | ILM_PC_PaymentRouter_v1, 43 | ERC20PaymentClientBase_v1 44 | { 45 | /// @inheritdoc ERC165Upgradeable 46 | function supportsInterface(bytes4 interfaceId) 47 | public 48 | view 49 | virtual 50 | override(ERC20PaymentClientBase_v1) 51 | returns (bool) 52 | { 53 | return interfaceId == type(ILM_PC_PaymentRouter_v1).interfaceId 54 | || super.supportsInterface(interfaceId); 55 | } 56 | 57 | //-------------------------------------------------------------------------- 58 | // Storage 59 | 60 | /// @dev The role that allows the pushing of payments. 61 | bytes32 public constant PAYMENT_PUSHER_ROLE = "PAYMENT_PUSHER"; 62 | 63 | //-------------------------------------------------------------------------- 64 | // Mutating Functions 65 | 66 | /// @inheritdoc ILM_PC_PaymentRouter_v1 67 | function pushPayment( 68 | address recipient, 69 | address paymentToken, 70 | uint amount, 71 | uint start, 72 | uint cliff, 73 | uint end 74 | ) public onlyModuleRole(PAYMENT_PUSHER_ROLE) { 75 | _addPaymentOrder( 76 | PaymentOrder( 77 | recipient, 78 | paymentToken, 79 | amount, 80 | start == 0 ? block.timestamp : start, 81 | cliff, 82 | end 83 | ) 84 | ); 85 | 86 | // call PaymentProcessor 87 | __Module_orchestrator.paymentProcessor().processPayments( 88 | IERC20PaymentClientBase_v1(address(this)) 89 | ); 90 | } 91 | 92 | /// @inheritdoc ILM_PC_PaymentRouter_v1 93 | function pushPaymentBatched( 94 | uint8 numOfOrders, 95 | address[] calldata recipients, 96 | address[] calldata paymentTokens, 97 | uint[] calldata amounts, 98 | uint start, 99 | uint cliff, 100 | uint end 101 | ) public onlyModuleRole(PAYMENT_PUSHER_ROLE) { 102 | // Validate all arrays have the same length 103 | if ( 104 | recipients.length != numOfOrders 105 | || paymentTokens.length != numOfOrders 106 | || amounts.length != numOfOrders 107 | ) { 108 | revert Module__ERC20PaymentClientBase__ArrayLengthMismatch(); 109 | } 110 | 111 | // Loop through the arrays and add Payments 112 | for (uint8 i = 0; i < numOfOrders; i++) { 113 | _addPaymentOrder( 114 | PaymentOrder( 115 | recipients[i], 116 | paymentTokens[i], 117 | amounts[i], 118 | start == 0 ? block.timestamp : start, 119 | cliff, 120 | end 121 | ) 122 | ); 123 | } 124 | 125 | // call PaymentProcessor 126 | __Module_orchestrator.paymentProcessor().processPayments( 127 | IERC20PaymentClientBase_v1(address(this)) 128 | ); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/modules/logicModule/abstracts/oracleIntegrations/UMA_OptimisticOracleV3/optimistic-oracle-v3/ClaimData.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0-only 2 | pragma solidity 0.8.23; 3 | 4 | import {AncillaryData as ClaimData} from 5 | "@uma/common/implementation/AncillaryData.sol"; 6 | -------------------------------------------------------------------------------- /src/modules/logicModule/abstracts/oracleIntegrations/UMA_OptimisticOracleV3/optimistic-oracle-v3/interfaces/OptimisticOracleV3CallbackRecipientInterface.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0-only 2 | pragma solidity ^0.8.16; 3 | 4 | /** 5 | * @title Inverter Optimistic Oracle V3 Callback Recipient Interface 6 | * @notice Interface for contracts implementing callbacks to be received from the Optimistic Oracle V3. 7 | */ 8 | interface OptimisticOracleV3CallbackRecipientInterface { 9 | /** 10 | * @notice Callback function that is called by Optimistic Oracle V3 when an assertion is resolved. 11 | * @param assertionId The identifier of the assertion that was resolved. 12 | * @param assertedTruthfully Whether the assertion was resolved as truthful or not. 13 | */ 14 | function assertionResolvedCallback( 15 | bytes32 assertionId, 16 | bool assertedTruthfully 17 | ) external; 18 | 19 | /** 20 | * @notice Callback function that is called by Optimistic Oracle V3 when an assertion is disputed. 21 | * @param assertionId The identifier of the assertion that was disputed. 22 | */ 23 | function assertionDisputedCallback(bytes32 assertionId) external; 24 | } 25 | -------------------------------------------------------------------------------- /src/modules/logicModule/interfaces/IERC20PaymentClientBase_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | // Internal Interfaces 5 | import {IPaymentProcessor_v1} from 6 | "src/modules/paymentProcessor/IPaymentProcessor_v1.sol"; 7 | 8 | interface IERC20PaymentClientBase_v1 { 9 | //-------------------------------------------------------------------------- 10 | // Structs 11 | 12 | /// @notice Struct used to store information about a payment order. 13 | /// @param recipient The recipient of the payment. 14 | /// @param paymentToken The token in which to pay. 15 | /// @param amount The amount of tokens to pay. 16 | /// @param start Timestamp at which the payment should start. 17 | /// @param cliff Duration of the payment cliff. 18 | /// @param end Timestamp at which the payment should be fulfilled. 19 | struct PaymentOrder { 20 | address recipient; 21 | address paymentToken; 22 | uint amount; 23 | uint start; 24 | uint cliff; 25 | uint end; 26 | } 27 | 28 | //-------------------------------------------------------------------------- 29 | // Errors 30 | 31 | /// @notice Function is only callable by authorized address. 32 | error Module__ERC20PaymentClientBase__CallerNotAuthorized(); 33 | 34 | /// @notice ERC20 token transfer failed. 35 | error Module__ERC20PaymentClientBase__TokenTransferFailed(); 36 | 37 | /// @notice Insufficient funds to fulfill the payment. 38 | /// @param token The token in which the payment was made. 39 | error Module__ERC20PaymentClientBase__InsufficientFunds(address token); 40 | 41 | /// @notice Given recipient invalid. 42 | error Module__ERC20PaymentClientBase__InvalidRecipient(); 43 | 44 | /// @notice Given token invalid. 45 | error Module__ERC20PaymentClientBase__InvalidToken(); 46 | 47 | /// @notice Given amount invalid. 48 | error Module__ERC20PaymentClientBase__InvalidAmount(); 49 | 50 | /// @notice Given paymentOrder is invalid. 51 | error Module__ERC20PaymentClientBase__InvalidPaymentOrder(); 52 | 53 | /// @notice Given end invalid. 54 | error Module__ERC20PaymentClientBase__Invalidend(); 55 | 56 | /// @notice Given arrays' length mismatch. 57 | error Module__ERC20PaymentClientBase__ArrayLengthMismatch(); 58 | 59 | //-------------------------------------------------------------------------- 60 | // Events 61 | 62 | /// @notice Added a payment order. 63 | /// @param recipient The address that will receive the payment. 64 | /// @param token The token in which to pay. 65 | /// @param amount The amount of tokens the payment consists of. 66 | event PaymentOrderAdded( 67 | address indexed recipient, address indexed token, uint amount 68 | ); 69 | 70 | //-------------------------------------------------------------------------- 71 | // Functions 72 | 73 | /// @notice Returns the list of outstanding payment orders. 74 | /// @return list of payment orders. 75 | function paymentOrders() external view returns (PaymentOrder[] memory); 76 | 77 | /// @notice Returns the total outstanding token payment amount. 78 | /// @param token The token in which to pay. 79 | /// @return total amount of token to pay. 80 | function outstandingTokenAmount(address token) 81 | external 82 | view 83 | returns (uint); 84 | 85 | /// @notice Collects outstanding payment orders. 86 | /// @dev Marks the orders as completed for the client. 87 | /// @return list of payment orders. 88 | /// @return list of token addresses. 89 | /// @return list of amounts. 90 | function collectPaymentOrders() 91 | external 92 | returns (PaymentOrder[] memory, address[] memory, uint[] memory); 93 | 94 | /// @notice Notifies the PaymentClient, that tokens have been paid out accordingly. 95 | /// @dev Payment Client will reduce the total amount of tokens it will stock up by the given amount. 96 | /// @dev This has to be called by a paymentProcessor. 97 | /// @param token The token in which the payment was made. 98 | /// @param amount amount of tokens that have been paid out. 99 | function amountPaid(address token, uint amount) external; 100 | } 101 | -------------------------------------------------------------------------------- /src/modules/logicModule/interfaces/ILM_PC_PaymentRouter_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | interface ILM_PC_PaymentRouter_v1 { 5 | //-------------------------------------------------------------------------- 6 | // Mutating Functions 7 | 8 | /// @notice Adds a new Payment Order. 9 | /// @dev Reverts if an argument invalid. 10 | /// @param recipient The address that will receive the payment. 11 | /// @param paymentToken The token in which to pay. 12 | /// @param amount The amount of tokens the payment consists of. 13 | /// @param start The timestamp at which the payment SHOULD be fulfilled. 14 | /// @param cliff The duration of the payment cliff. 15 | /// @param end The timestamp at which the payment SHOULD be fulfilled. 16 | function pushPayment( 17 | address recipient, 18 | address paymentToken, 19 | uint amount, 20 | uint start, 21 | uint cliff, 22 | uint end 23 | ) external; 24 | 25 | /// @notice Adds multiple Payment Orders in one batch. These PaymentOrders will share start, 26 | /// cliff and end timestamps. 27 | /// @dev Reverts if an argument invalid. The number of orders to be added in one batch is capped at 255. 28 | /// @param numOfOrders The number of orders to add. 29 | /// @param recipients The addresses that will receive the payments. 30 | /// @param paymentTokens The tokens in which to pay. 31 | /// @param amounts The amounts of tokens the payments consist of. 32 | /// @param start The timestamp at which the payments should start. 33 | /// @param cliff The duration of the payment cliff. 34 | /// @param end The timestamps at which the payments SHOULD be fulfilled. 35 | function pushPaymentBatched( 36 | uint8 numOfOrders, 37 | address[] calldata recipients, 38 | address[] calldata paymentTokens, 39 | uint[] calldata amounts, 40 | uint start, 41 | uint cliff, 42 | uint end 43 | ) external; 44 | } 45 | -------------------------------------------------------------------------------- /src/orchestrator/interfaces/IModuleManagerBase_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | // External Interfaces 5 | import {IERC2771Context} from "src/external/interfaces/IERC2771Context.sol"; 6 | 7 | interface IModuleManagerBase_v1 is IERC2771Context { 8 | //-------------------------------------------------------------------------- 9 | // Structs 10 | 11 | /// @notice The timelock struct to keep track of updating the registered modules. 12 | /// @param timelockActive Is the timelock currently active. 13 | /// @param timelockUntil Timestamp that represents from when the update can be carried out. 14 | struct ModuleUpdateTimelock { 15 | bool timelockActive; 16 | uint timelockUntil; 17 | } 18 | 19 | //-------------------------------------------------------------------------- 20 | // Errors 21 | 22 | /// @notice Function is only callable by authorized address. 23 | error ModuleManagerBase__CallerNotAuthorized(); 24 | 25 | /// @notice Function is only callable by modules. 26 | error ModuleManagerBase__OnlyCallableByModule(); 27 | 28 | /// @notice Given module address invalid. 29 | error ModuleManagerBase__InvalidModuleAddress(); 30 | 31 | /// @notice Given address is a module. 32 | error ModuleManagerBase__IsModule(); 33 | 34 | /// @notice Given address is not a module. 35 | error ModuleManagerBase__IsNotModule(); 36 | 37 | /// @notice The {ModuleManagerBase_v1} has reached the maximum amount of modules. 38 | error ModuleManagerBase__ModuleAmountOverLimits(); 39 | 40 | /// @notice Timelock still active for the given module address. 41 | /// @param _module The module address. 42 | /// @param _timelockUntil The unix timestamp until the timelock is active. 43 | error ModuleManagerBase__ModuleUpdateTimelockStillActive( 44 | address _module, uint _timelockUntil 45 | ); 46 | 47 | /// @notice Module update is already in progress. 48 | error ModuleManagerBase__ModuleUpdateAlreadyStarted(); 49 | 50 | /// @notice Module has not been registered in our factory. 51 | error ModuleManagerBase__ModuleNotRegistered(); 52 | 53 | /// @notice Referenced {ModuleFactory_v1} is invalid. 54 | error ModuleManagerBase__ModuleFactoryInvalid(); 55 | 56 | //-------------------------------------------------------------------------- 57 | // Events 58 | 59 | /// @notice Event emitted when module added. 60 | /// @param module The module's address. 61 | event ModuleAdded(address indexed module); 62 | 63 | /// @notice Event emitted when module removed. 64 | /// @param module The module's address. 65 | event ModuleRemoved(address indexed module); 66 | 67 | /// @notice Event emitted when updating a module is initiated, and the timelock starts;. 68 | /// @param module The module's address. 69 | /// @param timelockUntil The unix timestamp until the timelock is active. 70 | event ModuleTimelockStarted(address module, uint timelockUntil); 71 | 72 | /// @notice Event emitted when a module update is canceled. 73 | /// @param module The module's address. 74 | event ModuleUpdateCanceled(address module); 75 | 76 | //-------------------------------------------------------------------------- 77 | // Functions 78 | 79 | /// @notice Returns whether the address `module` is added as module. 80 | /// @param module The module to check. 81 | /// @return True if module added, false otherwise. 82 | function isModule(address module) external view returns (bool); 83 | 84 | /// @notice Returns the list of all modules. 85 | /// @return List of all modules. 86 | function listModules() external view returns (address[] memory); 87 | 88 | /// @notice Returns the number of modules. 89 | /// @return The number of modules. 90 | function modulesSize() external view returns (uint8); 91 | 92 | //-------------------------------------------------------------------------- 93 | // ERC2771 Context Upgradeable 94 | // @dev We imitate here the EIP2771 Standard to enable metatransactions 95 | 96 | /// @notice Returns wether the given address is the trusted forwarder or not. 97 | /// @dev Exposes the ERC2771 isTrusted Forwarder. 98 | /// @param forwarder The address to check. 99 | /// @return True if the address is the trusted forwarder, false otherwise. 100 | function isTrustedForwarder(address forwarder) 101 | external 102 | view 103 | returns (bool); 104 | 105 | /// @notice Returns the trusted forwarder for metatransactions. 106 | /// @dev Exposes the ERC2771 isTrusted Forwarder. 107 | /// @return The trusted forwarder address. 108 | function trustedForwarder() external view returns (address); 109 | } 110 | -------------------------------------------------------------------------------- /src/proxies/InverterBeaconProxy_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity 0.8.23; 3 | 4 | // Internal Interfaces 5 | import {IInverterBeacon_v1} from "src/proxies/interfaces/IInverterBeacon_v1.sol"; 6 | 7 | // External Dependencies 8 | import {Proxy} from "@oz/proxy/Proxy.sol"; 9 | 10 | /** 11 | * @title Inverter Beacon Proxy 12 | * 13 | * @notice Acts as a proxy for Inverter Network's smart contracts, allowing for upgrades 14 | * to contract implementations without affecting the existing state or contract 15 | * addresses, thereby achieving upgradeable contracts. 16 | * 17 | * @dev Implements the Proxy pattern by referencing the {InverterBeacon_v1}, which holds 18 | * the address of the current implementation to which calls are delegated. 19 | * 20 | * @custom:security-contact security@inverter.network 21 | * In case of any concerns or findings, please refer to our Security Policy 22 | * at security.inverter.network or email us directly! 23 | * 24 | * @author Inverter Network 25 | */ 26 | contract InverterBeaconProxy_v1 is Proxy { 27 | //-------------------------------------------------------------------------- 28 | // Events 29 | 30 | /// @notice Proxy upgraded to new {InverterBeacon_v1} instance. 31 | /// @param beacon The new {InverterBeacon_v1} instance. 32 | event BeaconUpgraded(IInverterBeacon_v1 indexed beacon); 33 | 34 | //-------------------------------------------------------------------------- 35 | // State 36 | 37 | /// @notice {InverterBeacon_v1} instance that points to the implementation. 38 | IInverterBeacon_v1 private immutable _beacon; 39 | 40 | //-------------------------------------------------------------------------- 41 | // Constructor 42 | 43 | /// @notice Constructs the {InverterBeaconProxy_v1}. 44 | /// @dev Sets the {InverterBeacon_v1} instance that contains the implementation address. 45 | /// @param beacon The {InverterBeacon_v1} instance. 46 | constructor(IInverterBeacon_v1 beacon) { 47 | _beacon = beacon; 48 | emit BeaconUpgraded(beacon); 49 | } 50 | 51 | //-------------------------------------------------------------------------- 52 | // Public Functions 53 | 54 | /// @dev This overrides the possible use of a "version" function in the modules that are 55 | /// called via the Proxy Beacon structure. 56 | /// @notice Returns the version of the linked implementation. 57 | /// @return Major version. 58 | /// @return Minor version. 59 | /// @return Patch version. 60 | function version() external view returns (uint, uint, uint) { 61 | return _beacon.version(); 62 | } 63 | 64 | /// @dev Fallback function to delegate calls to the implementation contract 65 | /// even if the call data is empty but msg.value > 0. 66 | receive() external payable virtual { 67 | _fallback(); 68 | } 69 | 70 | //-------------------------------------------------------------------------- 71 | // Internal View Functions 72 | 73 | /// @inheritdoc Proxy 74 | function _implementation() internal view override returns (address) { 75 | return _beacon.implementation(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/proxies/InverterProxyAdmin_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity 0.8.23; 3 | 4 | // Internal Interfaces 5 | import {IInverterProxyAdmin_v1} from 6 | "src/proxies/interfaces/IInverterProxyAdmin_v1.sol"; 7 | import {IInverterTransparentUpgradeableProxy_v1} from 8 | "src/proxies/interfaces/IInverterTransparentUpgradeableProxy_v1.sol"; 9 | 10 | // External Dependencies 11 | import {Ownable} from "@oz/access/Ownable.sol"; 12 | import {Ownable2Step} from "@oz/access/Ownable2Step.sol"; 13 | 14 | /** 15 | * @title Inverter Proxy Admin 16 | * 17 | * @notice Acts as the admin of the {InverterTransparentUpgradeableProxy_v1}s 18 | * and is responsible for upgrading the proxies to the newest version. 19 | * 20 | * @custom:security-contact security@inverter.network 21 | * In case of any concerns or findings, please refer to our Security Policy 22 | * at security.inverter.network or email us directly! 23 | * @author Inverter Network 24 | */ 25 | contract InverterProxyAdmin_v1 is Ownable2Step, IInverterProxyAdmin_v1 { 26 | //-------------------------------------------------------------------------- 27 | // Constructor 28 | 29 | /// @notice Constructs the {InverterProxyAdmin_v1}. 30 | /// @param initialOwner The initial owner of the contract. 31 | constructor(address initialOwner) Ownable(initialOwner) {} 32 | 33 | //-------------------------------------------------------------------------- 34 | // onlyOwner Mutating Functions 35 | 36 | /// @inheritdoc IInverterProxyAdmin_v1 37 | function upgradeToNewestVersion( 38 | IInverterTransparentUpgradeableProxy_v1 proxy 39 | ) external onlyOwner { 40 | proxy.upgradeToNewestVersion(); 41 | } 42 | 43 | /// @inheritdoc IInverterProxyAdmin_v1 44 | function upgradeToNewestVersionBatched( 45 | IInverterTransparentUpgradeableProxy_v1[] calldata proxies 46 | ) external onlyOwner { 47 | for (uint i; i < proxies.length; ++i) { 48 | proxies[i].upgradeToNewestVersion(); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/proxies/interfaces/IInverterBeacon_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | // External Interfaces 5 | import {IBeacon} from "@oz/proxy/beacon/IBeacon.sol"; 6 | 7 | interface IInverterBeacon_v1 is IBeacon { 8 | //-------------------------------------------------------------------------- 9 | // Errors 10 | 11 | /// @notice Given implementation invalid. 12 | error InverterBeacon__InvalidImplementation(); 13 | 14 | /// @notice Given implementation minor and patch version is not higher than previous minor version. 15 | error InverterBeacon__InvalidImplementationMinorOrPatchVersion(); 16 | 17 | //-------------------------------------------------------------------------- 18 | // Events 19 | 20 | /// @notice The {InverterBeacon_v1} was constructed. 21 | /// @param majorVersion The majorVersion of the implementation contract. 22 | event Constructed(uint majorVersion); 23 | 24 | /// @notice The {InverterBeacon_v1} was upgraded to a new implementation address. 25 | /// @param implementation The new implementation address. 26 | /// @param newMinorVersion The new minor version of the implementation contract. 27 | /// @param newPatchVersion The new patch version of the implementation contract. 28 | event Upgraded( 29 | address indexed implementation, 30 | uint newMinorVersion, 31 | uint newPatchVersion 32 | ); 33 | 34 | /// @notice The {InverterBeacon_v1} shutdown was initiated. 35 | event ShutdownInitiated(); 36 | 37 | /// @notice The {InverterBeacon_v1} shutdown was reversed. 38 | event ShutdownReversed(); 39 | 40 | //-------------------------------------------------------------------------- 41 | // Public View Functions 42 | 43 | /// @notice Returns the version of the linked implementation. 44 | /// @return Major version. 45 | /// @return Minor version. 46 | /// @return Patch version. 47 | function version() external view returns (uint, uint, uint); 48 | 49 | /// @notice Returns the {InverterReverter_v1} of the {InverterBeacon_v1}. 50 | /// @return ReverterAddress The address of the reverter contract. 51 | function getReverterAddress() external returns (address); 52 | 53 | /// @notice Returns the implementation address of the {InverterBeacon_v1}. 54 | /// @return ImplementationAddress The address of the implementation. 55 | function getImplementationAddress() external returns (address); 56 | 57 | /// @notice Returns wether the {InverterBeacon_v1} is in emergency mode or not. 58 | /// @return emergencyModeActive Is the beacon in emergency mode. 59 | function emergencyModeActive() external view returns (bool); 60 | 61 | //-------------------------------------------------------------------------- 62 | // onlyOwner Mutating Functions 63 | 64 | /// @notice Upgrades the {InverterBeacon_v1} to a new implementation address. 65 | /// @dev Only callable by owner. 66 | /// @dev `overrideShutdown` Doesnt do anything if {InverterBeacon_v1} is not in emergency mode. 67 | /// @dev Revert if new implementation invalid. 68 | /// @param newImplementation The new implementation address. 69 | /// @param newMinorVersion The new minor version of the implementation contract. 70 | /// @param newPatchVersion The new patch version of the implementation contract. 71 | /// @param overrideShutdown Flag to enable upgradeTo function to override the shutdown. 72 | function upgradeTo( 73 | address newImplementation, 74 | uint newMinorVersion, 75 | uint newPatchVersion, 76 | bool overrideShutdown 77 | ) external; 78 | 79 | //-------------------------------------------------------------------------- 80 | // onlyOwner Intervention Mechanism 81 | 82 | /// @notice Shuts down the {InverterBeacon_v1} and stops the system. 83 | /// @dev Only callable by owner. 84 | /// @dev Changes the implementation address to address(0). 85 | function shutDownImplementation() external; 86 | 87 | /// @notice Restarts the {InverterBeacon_v1} and the system. 88 | /// @dev Only callable by owner. 89 | /// @dev Changes the implementation address from address(0) to the original implementation. 90 | function restartImplementation() external; 91 | } 92 | -------------------------------------------------------------------------------- /src/proxies/interfaces/IInverterProxyAdmin_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | // Internal Interfaces 5 | import {IInverterTransparentUpgradeableProxy_v1} from 6 | "./IInverterTransparentUpgradeableProxy_v1.sol"; 7 | 8 | interface IInverterProxyAdmin_v1 { 9 | /// @notice Upgrades the corresponding {InverterTransparentUpgradeableProxy_v1} to the newest version of the implementation. 10 | /// @dev This contract must be othe admin/owner of the proxy. 11 | /// @param proxy The proxy to upgrade. 12 | function upgradeToNewestVersion( 13 | IInverterTransparentUpgradeableProxy_v1 proxy 14 | ) external; 15 | 16 | /// @notice Upgrades multiple {InverterTransparentUpgradeableProxy_v1}s to the newest version of the implementation. 17 | /// @dev This contract must be othe admin/owner of the proxies. 18 | /// @param proxies The proxies to upgrade. 19 | function upgradeToNewestVersionBatched( 20 | IInverterTransparentUpgradeableProxy_v1[] calldata proxies 21 | ) external; 22 | } 23 | -------------------------------------------------------------------------------- /src/proxies/interfaces/IInverterTransparentUpgradeableProxy_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | // External Interfaces 5 | import {IERC1967} from "@oz/interfaces/IERC1967.sol"; 6 | 7 | interface IInverterTransparentUpgradeableProxy_v1 is IERC1967 { 8 | function upgradeToNewestVersion() external; 9 | } 10 | -------------------------------------------------------------------------------- /test/e2e/ModuleTest_Template.txt: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | import "forge-std/console.sol"; 5 | 6 | // SuT 7 | import {AUT_Roles_v1} from "@aut/role/AUT_Roles_v1.sol"; 8 | 9 | // Internal Dependencies 10 | import { 11 | E2ETest, IOrchestratorFactory_v1, IOrchestrator_v1 12 | } from "test/e2e/E2ETest.sol"; 13 | 14 | // Import modules that are used in this E2E test 15 | 16 | contract RoleAuthorizerE2E is E2ETest { 17 | // Module Configurations for the current E2E test. Should be filled during setUp() call. 18 | IOrchestratorFactory_v1.ModuleConfig[] moduleConfigurations; 19 | 20 | // E2E Test Variables 21 | 22 | function setUp() public override { 23 | // Setup common E2E framework 24 | super.setUp(); 25 | 26 | // Set Up individual Modules the E2E test is going to use and store their configurations: 27 | // NOTE: It's important to store the module configurations in order, since _create_E2E_Orchestrator() will copy from the array. 28 | // The order should be: 29 | // moduleConfigurations[0] => FundingManager 30 | // moduleConfigurations[1] => Authorizer 31 | // moduleConfigurations[2] => PaymentProcessor 32 | // moduleConfigurations[3:] => Additional Logic Modules 33 | 34 | // FundingManager 35 | 36 | // Authorizer 37 | 38 | // PaymentProcessor 39 | 40 | // Additional Logic Modules 41 | } 42 | 43 | function test_e2e_RoleAuthorizer() public { 44 | //-------------------------------------------------------------------------- 45 | // Orchestrator_v1 Initialization 46 | //-------------------------------------------------------------------------- 47 | 48 | IOrchestratorFactory_v1.WorkflowConfig memory workflowConfig = 49 | IOrchestratorFactory_v1.WorkflowConfig({ 50 | independentUpdates: false, 51 | independentUpdateAdmin: address(0) 52 | }); 53 | 54 | IOrchestrator_v1 orchestrator = 55 | _create_E2E_Orchestrator(workflowConfig, moduleConfigurations); 56 | 57 | //-------------------------------------------------------------------------- 58 | // Module E2E Test 59 | //-------------------------------------------------------------------------- 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /test/e2e/README.md: -------------------------------------------------------------------------------- 1 | # End-to-End Tests 2 | 3 | Contains test suite using mocks only for external contracts. 4 | 5 | Can be used as PoCs and living documentation. 6 | -------------------------------------------------------------------------------- /test/external/InverterReverter_v1.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | // SuT 7 | import {InverterReverter_v1} from 8 | "src/external/reverter/InverterReverter_v1.sol"; 9 | 10 | contract InverterReverterV1Test is Test { 11 | // SuT 12 | InverterReverter_v1 reverter; 13 | 14 | function setUp() public { 15 | reverter = new InverterReverter_v1(); 16 | } 17 | 18 | function testRevert(bytes memory data) public { 19 | vm.expectRevert( 20 | InverterReverter_v1.InverterReverter__ContractPaused.selector 21 | ); 22 | 23 | (bool ok,) = address(reverter).call(data); 24 | ok; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/modules/fundingManager/bondingCurve/utils/mocks/BancorFormulaMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | import {IBancorFormula} from "@fm/bondingCurve/interfaces/IBancorFormula.sol"; 4 | import {ERC165} from "@oz/utils/introspection/ERC165.sol"; 5 | 6 | contract BancorFormulaMock is IBancorFormula, ERC165 { 7 | function calculatePurchaseReturn( 8 | uint _supply, 9 | uint _connectorBalance, 10 | uint32 _connectorWeight, 11 | uint _depositAmount 12 | ) public view returns (uint) {} 13 | function calculateSaleReturn( 14 | uint _supply, 15 | uint _connectorBalance, 16 | uint32 _connectorWeight, 17 | uint _sellAmount 18 | ) public view returns (uint) {} 19 | function calculateCrossConnectorReturn( 20 | uint _fromConnectorBalance, 21 | uint32 _fromConnectorWeight, 22 | uint _toConnectorBalance, 23 | uint32 _toConnectorWeight, 24 | uint _amount 25 | ) public view returns (uint) {} 26 | } 27 | -------------------------------------------------------------------------------- /test/modules/fundingManager/bondingCurve/utils/mocks/FM_BC_Bancor_Redeeming_VirtualSupplyV1Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.0; 3 | 4 | import "forge-std/console.sol"; 5 | 6 | // Internal Dependencies 7 | import {IOrchestrator_v1} from 8 | "src/orchestrator/interfaces/IOrchestrator_v1.sol"; 9 | 10 | // SuT 11 | import { 12 | FM_BC_Bancor_Redeeming_VirtualSupply_v1, 13 | IFM_BC_Bancor_Redeeming_VirtualSupply_v1, 14 | FM_BC_Tools 15 | } from "@fm/bondingCurve/FM_BC_Bancor_Redeeming_VirtualSupply_v1.sol"; 16 | import {IBancorFormula} from "@fm/bondingCurve/interfaces/IBancorFormula.sol"; 17 | import {Module_v1} from "src/modules/base/Module_v1.sol"; 18 | 19 | contract FM_BC_Bancor_Redeeming_VirtualSupplyV1Mock is 20 | FM_BC_Bancor_Redeeming_VirtualSupply_v1 21 | { 22 | //-------------------------------------------------------------------------- 23 | // The FM_BC_Bancor_Redeeming_VirtualSupply_v1 is not abstract, so all the necessary functions are already implemented 24 | // The goal of this mock is to provide direct access to internal functions for testing purposes. 25 | 26 | //-------------------------------------------------------------------------- 27 | // Mock access for internal functions 28 | 29 | function call_BPS() external pure returns (uint) { 30 | return BPS; 31 | } 32 | 33 | function call_PPM() external pure returns (uint32) { 34 | return PPM; 35 | } 36 | 37 | function call_reserveRatioForBuying() external view returns (uint32) { 38 | return reserveRatioForBuying; 39 | } 40 | 41 | function call_reserveRatioForSelling() external view returns (uint32) { 42 | return reserveRatioForSelling; 43 | } 44 | 45 | function call_collateralTokenDecimals() external view returns (uint8) { 46 | return collateralTokenDecimals; 47 | } 48 | 49 | function call_issuanceTokenDecimals() external view returns (uint8) { 50 | return issuanceTokenDecimals; 51 | } 52 | 53 | // Since the init calls are not registered for coverage, we call expose setIssuanceToken to get to 100% test coverage. 54 | function call_setIssuanceToken(address _newIssuanceToken) external { 55 | _setIssuanceToken(_newIssuanceToken); 56 | } 57 | 58 | function call_setVirtualIssuanceSupply(uint _newSupply) external { 59 | _setVirtualIssuanceSupply(_newSupply); 60 | } 61 | 62 | function call_convertAmountToRequiredDecimal( 63 | uint _amount, 64 | uint8 _tokenDecimals, 65 | uint8 _requiredDecimals 66 | ) external pure returns (uint) { 67 | return FM_BC_Tools._convertAmountToRequiredDecimal( 68 | _amount, _tokenDecimals, _requiredDecimals 69 | ); 70 | } 71 | 72 | // Note: this function returns the virtual issuance supply in the same format it will be fed to the Bancor formula 73 | function call_getFormulaVirtualIssuanceSupply() 74 | external 75 | view 76 | returns (uint) 77 | { 78 | return FM_BC_Tools._convertAmountToRequiredDecimal( 79 | virtualIssuanceSupply, issuanceTokenDecimals, 18 80 | ); 81 | } 82 | 83 | // Note: this function returns the virtual collateral supply in the same format it will be fed to the Bancor formula 84 | function call_getFormulaVirtualCollateralSupply() 85 | external 86 | view 87 | returns (uint) 88 | { 89 | return FM_BC_Tools._convertAmountToRequiredDecimal( 90 | virtualCollateralSupply, collateralTokenDecimals, 18 91 | ); 92 | } 93 | 94 | function call_calculateNetAndSplitFees( 95 | uint _totalAmount, 96 | uint _protocolFee, 97 | uint _workflowFee 98 | ) 99 | external 100 | pure 101 | returns (uint netAmount, uint protocolFeeAmount, uint workflowFeeAmount) 102 | { 103 | return 104 | _calculateNetAndSplitFees(_totalAmount, _protocolFee, _workflowFee); 105 | } 106 | 107 | function setProjectCollateralFeeCollectedHelper(uint _amount) external { 108 | projectCollateralFeeCollected = _amount; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /test/modules/fundingManager/bondingCurve/utils/mocks/FM_BC_Restricted_Bancor_Redeeming_VirtualSupplyV1Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.0; 3 | 4 | import "forge-std/console.sol"; 5 | 6 | // Internal Dependencies 7 | import {IOrchestrator_v1} from 8 | "src/orchestrator/interfaces/IOrchestrator_v1.sol"; 9 | 10 | // SuT 11 | import {FM_BC_Restricted_Bancor_Redeeming_VirtualSupply_v1} from 12 | "@fm/bondingCurve/FM_BC_Restricted_Bancor_Redeeming_VirtualSupply_v1.sol"; 13 | 14 | import { 15 | FM_BC_Bancor_Redeeming_VirtualSupply_v1, 16 | IFM_BC_Bancor_Redeeming_VirtualSupply_v1, 17 | FM_BC_Tools 18 | } from "@fm/bondingCurve/FM_BC_Bancor_Redeeming_VirtualSupply_v1.sol"; 19 | import {IBancorFormula} from "@fm/bondingCurve/interfaces/IBancorFormula.sol"; 20 | import {Module_v1} from "src/modules/base/Module_v1.sol"; 21 | 22 | contract FM_BC_Restricted_Bancor_Redeeming_VirtualSupplyV1Mock is 23 | FM_BC_Restricted_Bancor_Redeeming_VirtualSupply_v1 24 | { 25 | //-------------------------------------------------------------------------- 26 | // The FM_BC_Restricted_Bancor_Redeeming_VirtualSupply_v1 is not abstract, so all the necessary functions are already implemented 27 | // The goal of this mock is to provide direct access to internal functions for testing purposes. 28 | 29 | //-------------------------------------------------------------------------- 30 | // Mock access for internal functions 31 | 32 | function call_BPS() external pure returns (uint) { 33 | return BPS; 34 | } 35 | 36 | function call_PPM() external pure returns (uint32) { 37 | return PPM; 38 | } 39 | 40 | function call_reserveRatioForBuying() external view returns (uint32) { 41 | return reserveRatioForBuying; 42 | } 43 | 44 | function call_reserveRatioForSelling() external view returns (uint32) { 45 | return reserveRatioForSelling; 46 | } 47 | 48 | function call_collateralTokenDecimals() external view returns (uint8) { 49 | return collateralTokenDecimals; 50 | } 51 | 52 | function call_issuanceTokenDecimals() external view returns (uint8) { 53 | return issuanceTokenDecimals; 54 | } 55 | 56 | // Since the init calls are not registered for coverage, we call expose setIssuanceToken to get to 100% test coverage. 57 | function call_setIssuanceToken(address _newIssuanceToken) external { 58 | _setIssuanceToken(_newIssuanceToken); 59 | } 60 | /* 61 | function call_staticPricePPM( 62 | uint _issuanceSupply, 63 | uint _collateralSupply, 64 | uint32 _reserveRatio 65 | ) external pure returns (uint) { 66 | return 67 | _staticPricePPM(_issuanceSupply, _collateralSupply, _reserveRatio); 68 | } 69 | */ 70 | 71 | function call_convertAmountToRequiredDecimal( 72 | uint _amount, 73 | uint8 _tokenDecimals, 74 | uint8 _requiredDecimals 75 | ) external pure returns (uint) { 76 | return FM_BC_Tools._convertAmountToRequiredDecimal( 77 | _amount, _tokenDecimals, _requiredDecimals 78 | ); 79 | } 80 | 81 | // Note: this function returns the virtual token supply in the same format it will be fed to the Bancor formula 82 | function call_getFormulaVirtualIssuanceSupply() 83 | external 84 | view 85 | returns (uint) 86 | { 87 | uint decimalConvertedVirtualIssuanceSupply = FM_BC_Tools 88 | ._convertAmountToRequiredDecimal( 89 | virtualIssuanceSupply, issuanceTokenDecimals, 18 90 | ); 91 | return decimalConvertedVirtualIssuanceSupply; 92 | } 93 | 94 | function call_setVirtualIssuanceSupply(uint _newSupply) external { 95 | _setVirtualIssuanceSupply(_newSupply); 96 | } 97 | 98 | // Note: this function returns the virtual collateral supply in the same format it will be fed to the Bancor formula 99 | function call_getFormulaVirtualCollateralSupply() 100 | external 101 | view 102 | returns (uint) 103 | { 104 | uint decimalConvertedVirtualCollateralSupply = FM_BC_Tools 105 | ._convertAmountToRequiredDecimal( 106 | virtualCollateralSupply, collateralTokenDecimals, 18 107 | ); 108 | return decimalConvertedVirtualCollateralSupply; 109 | } 110 | 111 | function setProjectCollateralFeeCollectedHelper(uint _amount) external { 112 | projectCollateralFeeCollected = _amount; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /test/modules/fundingManager/bondingCurve/utils/mocks/RedeemingBondingCurveBaseV1Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.0; 3 | 4 | import "forge-std/console.sol"; 5 | 6 | // Internal Dependencies 7 | import {IOrchestrator_v1} from 8 | "src/orchestrator/interfaces/IOrchestrator_v1.sol"; 9 | 10 | // SuT 11 | import { 12 | RedeemingBondingCurveBase_v1, 13 | IRedeemingBondingCurveBase_v1 14 | } from "@fm/bondingCurve/abstracts/RedeemingBondingCurveBase_v1.sol"; 15 | import {BondingCurveBase_v1} from 16 | "@fm/bondingCurve/abstracts/BondingCurveBase_v1.sol"; 17 | 18 | import {IBancorFormula} from "@fm/bondingCurve/interfaces/IBancorFormula.sol"; 19 | import {Module_v1} from "src/modules/base/Module_v1.sol"; 20 | import {IFundingManager_v1} from "@fm/IFundingManager_v1.sol"; 21 | // External Interfaces 22 | import {IERC20} from "@oz/token/ERC20/IERC20.sol"; 23 | 24 | contract RedeemingBondingCurveBaseV1Mock is RedeemingBondingCurveBase_v1 { 25 | IBancorFormula public formula; 26 | 27 | function init( 28 | IOrchestrator_v1 orchestrator_, 29 | Metadata memory metadata, 30 | bytes memory configData 31 | ) external override(Module_v1) initializer { 32 | __Module_init(orchestrator_, metadata); 33 | 34 | ( 35 | address _issuanceToken, 36 | address _formula, 37 | uint _buyFee, 38 | bool _buyIsOpen, 39 | bool _sellIsOpen 40 | ) = abi.decode(configData, (address, address, uint, bool, bool)); 41 | 42 | _setIssuanceToken(_issuanceToken); 43 | 44 | formula = IBancorFormula(_formula); 45 | 46 | _setBuyFee(_buyFee); 47 | 48 | buyIsOpen = _buyIsOpen; 49 | 50 | sellIsOpen = _sellIsOpen; 51 | } 52 | 53 | function _issueTokensFormulaWrapper(uint _depositAmount) 54 | internal 55 | pure 56 | override 57 | returns (uint) 58 | { 59 | // Since this is a mock, we will always mint the same amount of tokens as have been deposited 60 | // Integration tests using the actual Formula can be found in the BancorFormulaFundingManagerTest.t.sol 61 | return _depositAmount; 62 | } 63 | 64 | function _redeemTokensFormulaWrapper(uint _depositAmount) 65 | internal 66 | pure 67 | override(RedeemingBondingCurveBase_v1) 68 | returns (uint) 69 | { 70 | // Since this is a mock, we will always redeem the same amount of tokens as have been deposited 71 | // Integration tests using the actual Formula can be found in the BancorFormulaFundingManagerTest.t.sol 72 | return _depositAmount; 73 | } 74 | 75 | function call_calculateSaleReturn(uint _depositAmount) 76 | external 77 | view 78 | returns (uint) 79 | { 80 | return calculateSaleReturn(_depositAmount); 81 | } 82 | 83 | function getStaticPriceForSelling() 84 | external 85 | view 86 | override(RedeemingBondingCurveBase_v1) 87 | returns (uint) 88 | {} 89 | 90 | function getStaticPriceForBuying() 91 | external 92 | view 93 | override(BondingCurveBase_v1) 94 | returns (uint) 95 | {} 96 | 97 | //-------------------------------------------------------------------------- 98 | // Mock access for internal functions 99 | 100 | function call_BPS() external pure returns (uint) { 101 | return BPS; 102 | } 103 | 104 | function call_sellOrder( 105 | address _receiver, 106 | uint _depositAmount, 107 | uint _minAmountOut 108 | ) 109 | external 110 | returns (uint totalCollateralTokenMovedOut, uint issuanceFeeAmount) 111 | { 112 | return _sellOrder(_receiver, _depositAmount, _minAmountOut); 113 | } 114 | 115 | function call_calculateNetAndSplitFees( 116 | uint _totalAmount, 117 | uint _protocolFee, 118 | uint _workflowFee 119 | ) 120 | external 121 | pure 122 | returns (uint netAmount, uint protocolFeeAmount, uint workflowFeeAmount) 123 | { 124 | return 125 | _calculateNetAndSplitFees(_totalAmount, _protocolFee, _workflowFee); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /test/modules/fundingManager/bondingCurve/utils/mocks/VirtualCollateralSupplyBaseV1Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.0; 3 | 4 | import {VirtualCollateralSupplyBase_v1} from 5 | "@fm/bondingCurve/abstracts/VirtualCollateralSupplyBase_v1.sol"; 6 | 7 | contract VirtualCollateralSupplyBaseV1Mock is VirtualCollateralSupplyBase_v1 { 8 | function setVirtualCollateralSupply(uint _virtualSupply) 9 | external 10 | virtual 11 | override(VirtualCollateralSupplyBase_v1) 12 | { 13 | _setVirtualCollateralSupply(_virtualSupply); 14 | } 15 | 16 | function addVirtualCollateralAmount(uint _amount) external { 17 | super._addVirtualCollateralAmount(_amount); 18 | } 19 | 20 | function subVirtualCollateralAmount(uint _amount) external { 21 | super._subVirtualCollateralAmount(_amount); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/modules/fundingManager/bondingCurve/utils/mocks/VirtualIssuanceSupplyBaseV1Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.0; 3 | 4 | import {VirtualIssuanceSupplyBase_v1} from 5 | "@fm/bondingCurve/abstracts/VirtualIssuanceSupplyBase_v1.sol"; 6 | 7 | contract VirtualIssuanceSupplyBaseV1Mock is VirtualIssuanceSupplyBase_v1 { 8 | function setVirtualIssuanceSupply(uint _virtualSupply) 9 | external 10 | virtual 11 | override(VirtualIssuanceSupplyBase_v1) 12 | { 13 | _setVirtualIssuanceSupply(_virtualSupply); 14 | } 15 | 16 | function addVirtualIssuanceAmount(uint _amount) external { 17 | super._addVirtualIssuanceAmount(_amount); 18 | } 19 | 20 | function subVirtualIssuanceAmount(uint _amount) external { 21 | super._subVirtualIssuanceAmount(_amount); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/modules/fundingManager/depositVault/FM_DepositVault_v1.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | import "forge-std/console.sol"; 5 | 6 | // Mocks 7 | import {ERC20Mock} from "test/utils/mocks/ERC20Mock.sol"; 8 | 9 | // SuT 10 | import {IFundingManager_v1} from "@fm/IFundingManager_v1.sol"; 11 | 12 | import {IFM_DepositVault_v1} from 13 | "@fm/depositVault/interfaces/IFM_DepositVault_v1.sol"; 14 | 15 | import {ERC20PaymentClientBaseV1Mock} from 16 | "test/utils/mocks/modules/paymentClient/ERC20PaymentClientBaseV1Mock.sol"; 17 | import {FM_DepositVault_v1} from "@fm/depositVault/FM_DepositVault_v1.sol"; 18 | 19 | // Internal Dependencies 20 | import { 21 | ModuleTest, 22 | IModule_v1, 23 | IOrchestrator_v1 24 | } from "test/modules/ModuleTest.sol"; 25 | 26 | // Errors 27 | import {OZErrors} from "test/utils/errors/OZErrors.sol"; 28 | 29 | // External Libraries 30 | import {Clones} from "@oz/proxy/Clones.sol"; 31 | 32 | contract FM_DepositVaultV1Test is ModuleTest { 33 | // SuT 34 | FM_DepositVault_v1 vault; 35 | ERC20PaymentClientBaseV1Mock client; 36 | 37 | //-------------------------------------------------------------------------- 38 | // Events 39 | 40 | event Deposit(address indexed _from, uint _amount); 41 | event TransferOrchestratorToken(address indexed _to, uint _amount); 42 | 43 | function setUp() public { 44 | address impl = address(new FM_DepositVault_v1()); 45 | vault = FM_DepositVault_v1(Clones.clone(impl)); 46 | 47 | _setUpOrchestrator(vault); 48 | 49 | // Init Module 50 | vault.init(_orchestrator, _METADATA, abi.encode(address(_token))); 51 | 52 | client = new ERC20PaymentClientBaseV1Mock(); 53 | _addLogicModuleToOrchestrator(address(client)); 54 | } 55 | 56 | function testSupportsInterface() public { 57 | assertTrue( 58 | vault.supportsInterface(type(IFM_DepositVault_v1).interfaceId) 59 | ); 60 | assertTrue( 61 | vault.supportsInterface(type(IFundingManager_v1).interfaceId) 62 | ); 63 | } 64 | 65 | //-------------------------------------------------------------------------- 66 | // Tests: Initialization 67 | 68 | function testInit() public override(ModuleTest) { 69 | assertEq(address(vault.token()), address(_token)); 70 | } 71 | 72 | function testReinitFails() public override(ModuleTest) { 73 | vm.expectRevert(OZErrors.Initializable__InvalidInitialization); 74 | vault.init(_orchestrator, _METADATA, abi.encode()); 75 | } 76 | 77 | //-------------------------------------------------------------------------- 78 | // Tests: Public View Functions 79 | 80 | function testToken() public { 81 | assertEq(address(vault.token()), address(_token)); 82 | } 83 | 84 | //-------------------------------------------------------------------------- 85 | // Public Mutating Functions 86 | 87 | function testDeposit_Works(address user, uint amount) public { 88 | vm.assume( 89 | user != address(0) && user != address(_token) 90 | && user != address(vault) && user != vault.trustedForwarder() 91 | ); 92 | 93 | // Setup 94 | _token.mint(user, amount); 95 | assertEq(_token.balanceOf(user), amount); 96 | vm.prank(user); 97 | _token.approve(address(vault), amount); 98 | 99 | // Deposit 100 | vm.prank(user); 101 | vm.expectEmit(true, true, true, true); 102 | emit Deposit(user, amount); 103 | vault.deposit(amount); 104 | 105 | // Assert balance 106 | assertEq(_token.balanceOf(address(vault)), amount); 107 | assertEq(_token.balanceOf(user), 0); 108 | } 109 | 110 | //-------------------------------------------------------------------------- 111 | // OnlyOrchestrator Mutating Functions 112 | 113 | function testTransferOrchestratorToken(address to, uint amount) public { 114 | vm.assume(to != address(0) && to != address(vault)); 115 | 116 | _token.mint(address(vault), amount); 117 | 118 | vm.expectEmit(true, true, true, true); 119 | emit TransferOrchestratorToken(to, amount); 120 | 121 | vm.prank(address(client)); 122 | vault.transferOrchestratorToken(to, amount); 123 | 124 | assertEq(_token.balanceOf(to), amount); 125 | assertEq(_token.balanceOf(address(vault)), 0); 126 | } 127 | 128 | function testTransferOrchestratorTokenModifierInPosition() public { 129 | vm.expectRevert(IModule_v1.Module__OnlyCallableByPaymentClient.selector); 130 | vault.transferOrchestratorToken(address(this), 0); 131 | 132 | vm.expectRevert(IModule_v1.Module__InvalidAddress.selector); 133 | vm.prank(address(client)); 134 | vault.transferOrchestratorToken(address(0), 0); 135 | } 136 | 137 | // ========================================================================= 138 | } 139 | -------------------------------------------------------------------------------- /test/modules/fundingManager/rebasing/abstracts/Deployment.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.0; 3 | 4 | import 5 | "test/modules/fundingManager/rebasing/abstracts/ElasticReceiptTokenBase_v1.t.sol"; 6 | 7 | /** 8 | * @dev Deployment Tests. 9 | */ 10 | contract Deployment is ElasticReceiptTokenBaseV1Test { 11 | function testInvariants() public { 12 | assertEq(ert.totalSupply(), 0); 13 | assertEq(ert.scaledBalanceOf(address(0)), TOTAL_BITS); 14 | assertEq(ert.scaledTotalSupply(), 0); 15 | } 16 | 17 | function testInitialization() public { 18 | assertEq(ert.underlier(), address(underlier)); 19 | assertEq(ert.name(), NAME); 20 | assertEq(ert.symbol(), SYMBOL); 21 | assertEq(ert.decimals(), uint8(DECIMALS)); 22 | } 23 | 24 | function testInitilizationFailsIfMintAlreadyExecuted( 25 | address user, 26 | uint amount 27 | ) public { 28 | vm.assume(user != address(0)); 29 | vm.assume(user != address(ert)); 30 | amount = bound(amount, 1, MAX_SUPPLY); 31 | 32 | underlier.mint(user, amount); 33 | 34 | vm.startPrank(user); 35 | { 36 | underlier.approve(address(ert), amount); 37 | ert.mint(amount); 38 | } 39 | vm.stopPrank(); 40 | 41 | vm.expectRevert(); 42 | ert.init(_erb_orchestrator, _ERB_METADATA, _erb_configData); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /test/modules/fundingManager/rebasing/abstracts/ElasticReceiptTokenBase_v1.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.0; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | import {Clones} from "@oz/proxy/Clones.sol"; 7 | 8 | import {IModule_v1} from "src/modules/base/IModule_v1.sol"; 9 | 10 | import {TransactionForwarder_v1} from 11 | "src/external/forwarder/TransactionForwarder_v1.sol"; 12 | 13 | import {OrchestratorV1Mock} from 14 | "test/utils/mocks/orchestrator/OrchestratorV1Mock.sol"; 15 | 16 | import {ElasticReceiptTokenBaseV1Mock} from 17 | "test/modules/fundingManager/rebasing/utils/mocks/ElasticReceiptTokenBaseV1Mock.sol"; 18 | 19 | import {ERC20Mock} from 20 | "test/modules/fundingManager/rebasing/utils/mocks/ERC20Mock.sol"; 21 | 22 | /** 23 | * @dev Root contract for ElasticReceiptTokenBase_v1 Test Contracts. 24 | * 25 | * Provides the setUp function, access to common test utils and internal 26 | * constants from the ElasticReceiptTokenBase_v1. 27 | */ 28 | abstract contract ElasticReceiptTokenBaseV1Test is Test { 29 | // SuT 30 | ElasticReceiptTokenBaseV1Mock ert; 31 | 32 | // Mocks 33 | OrchestratorV1Mock _erb_orchestrator; 34 | ERC20Mock underlier; 35 | TransactionForwarder_v1 _forwarder; 36 | 37 | // Constants 38 | string internal constant NAME = "elastic receipt Token"; 39 | string internal constant SYMBOL = "ERT"; 40 | uint internal constant DECIMALS = 9; 41 | 42 | // Constants copied from SuT. 43 | uint internal constant MAX_UINT = type(uint).max; 44 | uint internal constant MAX_SUPPLY = 1_000_000_000_000_000_000e18; 45 | uint internal constant TOTAL_BITS = MAX_UINT - (MAX_UINT % MAX_SUPPLY); 46 | uint internal constant BITS_PER_UNDERLYING = TOTAL_BITS / MAX_SUPPLY; 47 | 48 | // Module Constants 49 | uint constant ERB_MAJOR_VERSION = 1; 50 | uint constant ERB_MINOR_VERSION = 0; 51 | uint constant ERB_PATCH_VERSION = 0; 52 | string constant ERB_URL = 53 | "https://github.com/organization/module/ElasticReceiptTokenBase"; 54 | string constant ERB_TITLE = "Module"; 55 | 56 | IModule_v1.Metadata _ERB_METADATA = IModule_v1.Metadata( 57 | ERB_MAJOR_VERSION, 58 | ERB_MINOR_VERSION, 59 | ERB_PATCH_VERSION, 60 | ERB_URL, 61 | ERB_TITLE 62 | ); 63 | 64 | bytes _erb_configData; 65 | 66 | function setUp() public { 67 | underlier = new ERC20Mock("Test ERC20", "TEST"); 68 | _forwarder = new TransactionForwarder_v1(); 69 | 70 | address impl = address(new OrchestratorV1Mock(address(_forwarder))); 71 | _erb_orchestrator = OrchestratorV1Mock(Clones.clone(impl)); 72 | 73 | impl = address(new ElasticReceiptTokenBaseV1Mock()); 74 | ert = ElasticReceiptTokenBaseV1Mock(Clones.clone(impl)); 75 | 76 | _erb_configData = abi.encode(NAME, SYMBOL, uint8(DECIMALS)); 77 | ert.init(_erb_orchestrator, _ERB_METADATA, _erb_configData); 78 | ert.setUnderlier(address(underlier)); 79 | } 80 | 81 | modifier assumeTestAmount(uint amount) { 82 | vm.assume(amount != 0 && amount <= MAX_SUPPLY); 83 | _; 84 | } 85 | 86 | modifier assumeTestAddress(address who) { 87 | vm.assume(who != address(0)); 88 | vm.assume(who != address(ert)); 89 | _; 90 | } 91 | 92 | function mintToUser(address user, uint erts) public { 93 | underlier.mint(user, erts); 94 | 95 | vm.startPrank(user); 96 | { 97 | underlier.approve(address(ert), type(uint).max); 98 | ert.mint(erts); 99 | } 100 | vm.stopPrank(); 101 | } 102 | 103 | function underflows(uint a, uint b) public pure returns (bool) { 104 | unchecked { 105 | uint x = a - b; 106 | return x > a; 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /test/modules/fundingManager/rebasing/abstracts/MintBurn.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.0; 3 | 4 | import 5 | "test/modules/fundingManager/rebasing/abstracts/ElasticReceiptTokenBase_v1.t.sol"; 6 | 7 | /** 8 | * @dev Mint/Burn Tests. 9 | */ 10 | contract MintBurn is ElasticReceiptTokenBaseV1Test { 11 | function testFailMintMoreThanMaxSupply(address to) public { 12 | vm.assume(to != address(0)); 13 | 14 | // Fails with MaxSupplyReached. 15 | mintToUser(to, MAX_SUPPLY + 1); 16 | } 17 | 18 | function testFailBurnAll(address to, uint erts) public { 19 | vm.assume(to != address(0)); 20 | vm.assume(erts != 0); 21 | 22 | mintToUser(to, erts); 23 | 24 | // Fails with Division by 0. 25 | vm.prank(to); 26 | ert.burn(erts); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/modules/fundingManager/rebasing/utils/mocks/ERC20Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.0; 3 | 4 | import {ERC20} from "@oz/token/ERC20/ERC20.sol"; 5 | 6 | contract ERC20Mock is ERC20 { 7 | constructor(string memory _name, string memory _symbol) 8 | ERC20(_name, _symbol) 9 | { 10 | // NO-OP 11 | } 12 | 13 | function mint(address to, uint value) public virtual { 14 | _mint(to, value); 15 | } 16 | 17 | function burn(address from, uint value) public virtual { 18 | _burn(from, value); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/modules/fundingManager/rebasing/utils/mocks/ElasticReceiptTokenBaseV1Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.0; 3 | 4 | import {ERC20} from "@oz/token/ERC20/ERC20.sol"; 5 | 6 | import { 7 | ElasticReceiptTokenBase_v1, 8 | IOrchestrator_v1 9 | } from "@fm/rebasing/abstracts/ElasticReceiptTokenBase_v1.sol"; 10 | 11 | contract ElasticReceiptTokenBaseV1Mock is ElasticReceiptTokenBase_v1 { 12 | // The token's underlier. 13 | // Is of type ERC20. 14 | address public underlier; 15 | 16 | function setUnderlier(address _underlier) public { 17 | underlier = _underlier; 18 | } 19 | 20 | function public__ElasticReceiptTokenBase_init( 21 | IOrchestrator_v1 orchestrator_, 22 | Metadata memory metadata, 23 | bytes memory configData 24 | ) public { 25 | __ElasticReceiptTokenBase_init(orchestrator_, metadata, configData); 26 | } 27 | 28 | function _supplyTarget() 29 | internal 30 | view 31 | override(ElasticReceiptTokenBase_v1) 32 | returns (uint) 33 | { 34 | return ERC20(underlier).balanceOf(address(this)); 35 | } 36 | 37 | function mint(uint tokens) external { 38 | super._mint(msg.sender, tokens); 39 | ERC20(underlier).transferFrom(msg.sender, address(this), tokens); 40 | } 41 | 42 | function burn(uint erts) external { 43 | erts = super._burn(msg.sender, erts); 44 | ERC20(underlier).transfer(msg.sender, erts); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test/modules/lib/LibMetadata.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | import {Test} from "forge-std/Test.sol"; 5 | 6 | // Internal Libraries 7 | import {LibMetadata} from "src/modules/lib/LibMetadata.sol"; 8 | 9 | // Internal Interfaces 10 | import {IModule_v1} from "src/modules/base/IModule_v1.sol"; 11 | 12 | contract LibMetadataTest is Test { 13 | function setUp() public {} 14 | 15 | /// @dev The identifier is defined as the hash of the major version, url 16 | /// and title. 17 | function testIdentifier(IModule_v1.Metadata memory data) public { 18 | bytes32 got = LibMetadata.identifier(data); 19 | bytes32 want = 20 | keccak256(abi.encode(data.majorVersion, data.url, data.title)); 21 | 22 | assertEq(got, want); 23 | } 24 | 25 | function testMetadataIsValid( 26 | uint majorVersion, 27 | uint minorVersion, 28 | uint patchVersion, 29 | string memory url, 30 | string memory title 31 | ) public { 32 | vm.assume(majorVersion != 0 || minorVersion != 0 || patchVersion != 0); 33 | vm.assume(bytes(url).length != 0); 34 | vm.assume(bytes(title).length != 0); 35 | 36 | IModule_v1.Metadata memory data = IModule_v1.Metadata( 37 | majorVersion, minorVersion, patchVersion, url, title 38 | ); 39 | 40 | assertTrue(LibMetadata.isValid(data)); 41 | } 42 | 43 | function testMetadataInvalidIfURLEmpty( 44 | uint majorVersion, 45 | uint minorVersion, 46 | uint patchVersion 47 | ) public { 48 | vm.assume(majorVersion != 0 || minorVersion != 0 || patchVersion != 0); 49 | IModule_v1.Metadata memory data = IModule_v1.Metadata( 50 | majorVersion, minorVersion, patchVersion, "", "title" 51 | ); 52 | 53 | assertTrue(!LibMetadata.isValid(data)); 54 | } 55 | 56 | function testMetadataInvalidIfTitleEmpty( 57 | uint majorVersion, 58 | uint minorVersion, 59 | uint patchVersion 60 | ) public { 61 | vm.assume(majorVersion != 0 || minorVersion != 0 || patchVersion != 0); 62 | 63 | IModule_v1.Metadata memory data = IModule_v1.Metadata( 64 | majorVersion, minorVersion, patchVersion, "url", "" 65 | ); 66 | 67 | assertTrue(!LibMetadata.isValid(data)); 68 | } 69 | 70 | function testMetadataInvalidIfVersionOnlyZero( 71 | uint majorVersion, 72 | uint minorVersion, 73 | uint patchVersion 74 | ) public { 75 | IModule_v1.Metadata memory data = IModule_v1.Metadata( 76 | majorVersion, minorVersion, patchVersion, "url", "title" 77 | ); 78 | if (majorVersion == 0 && minorVersion == 0 && patchVersion == 0) { 79 | assertFalse(LibMetadata.isValid(data)); 80 | } else { 81 | assertTrue(LibMetadata.isValid(data)); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /test/modules/logicModule/oracle/utils/OptimisiticOracleIntegratorMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity 0.8.23; 3 | 4 | // Internal Dependencies 5 | import {Module_v1} from "src/modules/base/Module_v1.sol"; 6 | 7 | // Internal Interfaces 8 | import {IOrchestrator_v1} from 9 | "src/orchestrator/interfaces/IOrchestrator_v1.sol"; 10 | 11 | import { 12 | OptimisticOracleIntegrator, 13 | IOptimisticOracleIntegrator 14 | } from 15 | "@lm/abstracts/oracleIntegrations/UMA_OptimisticOracleV3/OptimisticOracleIntegrator.sol"; 16 | 17 | // External Dependencies 18 | import {OptimisticOracleV3CallbackRecipientInterface} from 19 | "@lm/abstracts/oracleIntegrations/UMA_OptimisticOracleV3/optimistic-oracle-v3/interfaces/OptimisticOracleV3CallbackRecipientInterface.sol"; 20 | import {OptimisticOracleV3Interface} from 21 | "@lm/abstracts/oracleIntegrations/UMA_OptimisticOracleV3/optimistic-oracle-v3/interfaces/OptimisticOracleV3Interface.sol"; 22 | import {ClaimData} from 23 | "@lm/abstracts/oracleIntegrations/UMA_OptimisticOracleV3/optimistic-oracle-v3/ClaimData.sol"; 24 | 25 | contract OptimisticOracleIntegratorMock is OptimisticOracleIntegrator { 26 | function assertionResolvedCallback( 27 | bytes32 assertionId, 28 | bool assertedTruthfully 29 | ) public override { 30 | super.assertionResolvedCallback(assertionId, assertedTruthfully); 31 | } 32 | 33 | function assertionDisputedCallback(bytes32 assertionId) public override { 34 | // Do nothing 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /test/orchestrator/helper/TypeSanityHelper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | import {Test} from "forge-std/Test.sol"; 5 | 6 | contract TypeSanityHelper is Test { 7 | address private _self; 8 | 9 | constructor(address self) { 10 | _self = self; 11 | } 12 | 13 | //-------------------------------------------------------------------------- 14 | // Helpers 15 | 16 | function assumeElemNotInSet(address[] memory set, address elem) 17 | public 18 | pure 19 | { 20 | for (uint i; i < set.length; ++i) { 21 | vm.assume(elem != set[i]); 22 | } 23 | } 24 | 25 | //-------------------------------------------------------------------------- 26 | // Types for Orchestrator_v1 27 | // Contract: Orchestrator_v1.sol 28 | 29 | function assumeValidOrchestratorId(uint id) public pure { 30 | vm.assume(id != 0); 31 | } 32 | 33 | //-------------------------------------------------------------------------- 34 | // Types for Module 35 | // Contract: base/ModuleManagerBase_v1.sol 36 | 37 | uint8 private constant MAX_MODULES = 128; 38 | 39 | mapping(address => bool) moduleCache; 40 | 41 | function assumeValidModules(address[] memory modules) public { 42 | vm.assume(modules.length <= MAX_MODULES); 43 | for (uint i; i < modules.length; ++i) { 44 | assumeValidModule(modules[i]); 45 | 46 | // Assume module unique. 47 | vm.assume(!moduleCache[modules[i]]); 48 | 49 | // Add module to cache. 50 | moduleCache[modules[i]] = true; 51 | } 52 | } 53 | 54 | function assumeValidModule(address module) public view { 55 | address[] memory invalids = createInvalidModules(); 56 | 57 | for (uint i; i < invalids.length; ++i) { 58 | vm.assume(module != invalids[i]); 59 | } 60 | } 61 | 62 | function createInvalidModules() public view returns (address[] memory) { 63 | address[] memory invalids = new address[](3); 64 | 65 | invalids[0] = address(0); 66 | invalids[1] = _self; 67 | 68 | return invalids; 69 | } 70 | 71 | //-------------------------------------------------------------------------- 72 | // Types for Funder 73 | // Contract: base/FunderManager.sol 74 | 75 | function assumeValidFunders(address[] memory funders) public {} 76 | } 77 | -------------------------------------------------------------------------------- /test/proxies/InverterBeaconProxy_v1.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | // Internal Dependencies 7 | import { 8 | InverterBeacon_v1, 9 | IInverterBeacon_v1 10 | } from "src/proxies/InverterBeacon_v1.sol"; 11 | import {InverterBeaconProxy_v1} from "src/proxies/InverterBeaconProxy_v1.sol"; 12 | 13 | // Mocks 14 | import {InverterBeaconV1Mock} from 15 | "test/utils/mocks/proxies/InverterBeaconV1Mock.sol"; 16 | import {ModuleImplementationV1Mock} from 17 | "test/utils/mocks/proxies/ModuleImplementationV1Mock.sol"; 18 | 19 | contract InverterBeaconProxyV1Test is Test { 20 | // SuT 21 | InverterBeaconProxy_v1 proxy; 22 | 23 | // Mocks 24 | InverterBeaconV1Mock beacon; 25 | ModuleImplementationV1Mock implementation; 26 | 27 | // Events copied from SuT 28 | event BeaconUpgraded(IInverterBeacon_v1 indexed beacon); 29 | 30 | function setUp() public { 31 | beacon = new InverterBeaconV1Mock(); 32 | 33 | implementation = new ModuleImplementationV1Mock(); 34 | beacon.overrideImplementation(address(implementation)); 35 | 36 | proxy = new InverterBeaconProxy_v1(beacon); 37 | } 38 | 39 | function testDeploymentInvariants() public { 40 | vm.expectEmit(true, true, true, true); 41 | emit BeaconUpgraded(beacon); 42 | 43 | InverterBeaconProxy_v1 localProxy = new InverterBeaconProxy_v1(beacon); 44 | 45 | (uint majorVersion, uint minorVersion, uint patchVersion) = 46 | localProxy.version(); 47 | assertEq(majorVersion, 0); 48 | assertEq(minorVersion, 0); 49 | assertEq(patchVersion, 0); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/utils/errors/OZErrors.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | /** 5 | * @dev Library providing error types for OpenZeppelin contracts. 6 | */ 7 | library OZErrors { 8 | // Contract: Initializable 9 | bytes4 public constant Initializable__NotInitializing = 10 | bytes4(keccak256("NotInitializing()")); 11 | bytes4 internal constant Initializable__InvalidInitialization = 12 | bytes4(keccak256("InvalidInitialization()")); 13 | 14 | // Contract: Ownable 15 | bytes4 internal constant Ownable__UnauthorizedAccount = 16 | bytes4(keccak256("OwnableUnauthorizedAccount(address)")); 17 | } 18 | -------------------------------------------------------------------------------- /test/utils/mocks/ERC20Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | import {ERC20} from "@oz/token/ERC20/ERC20.sol"; 5 | 6 | contract ERC20Mock is ERC20 { 7 | mapping(address => bool) blockedAddresses; 8 | bool returnFalse; 9 | 10 | bool reentrancyOnTransfer; 11 | 12 | bytes reentrancyCallData; 13 | 14 | bool public callSuccessful; 15 | 16 | bytes public callData; 17 | 18 | constructor(string memory _name, string memory _symbol) 19 | ERC20(_name, _symbol) 20 | {} 21 | 22 | function mint(address to, uint value) public { 23 | _mint(to, value); 24 | } 25 | 26 | function burn(address from, uint value) public { 27 | _burn(from, value); 28 | } 29 | 30 | function blockAddress(address user) public { 31 | blockedAddresses[user] = true; 32 | } 33 | 34 | function unblockAddress(address user) public { 35 | blockedAddresses[user] = false; 36 | } 37 | 38 | function toggleReturnFalse() public { 39 | returnFalse = !returnFalse; 40 | } 41 | 42 | function setReentrancyOnTransfer(bytes calldata data) public { 43 | reentrancyOnTransfer = true; 44 | reentrancyCallData = data; 45 | } 46 | 47 | function isBlockedAddress(address user) public view returns (bool) { 48 | return blockedAddresses[user]; 49 | } 50 | 51 | function transfer(address to, uint amount) public override returns (bool) { 52 | if (returnFalse) { 53 | return false; 54 | } 55 | require(!isBlockedAddress(to), "address blocked"); 56 | address owner = _msgSender(); 57 | _transfer(owner, to, amount); 58 | 59 | // Quite dirty but this should do the trick of testing attempted reentrancy 60 | if (reentrancyOnTransfer) { 61 | (bool success, bytes memory data) = 62 | msg.sender.call(reentrancyCallData); 63 | callSuccessful = success; 64 | callData = data; 65 | } 66 | 67 | return true; 68 | } 69 | 70 | function decimals() public view virtual override returns (uint8) { 71 | return 18; 72 | } 73 | 74 | function transferFrom(address from, address to, uint amount) 75 | public 76 | override 77 | returns (bool) 78 | { 79 | if (returnFalse) { 80 | return false; 81 | } 82 | require(!isBlockedAddress(to), "address blocked"); 83 | address spender = _msgSender(); 84 | _spendAllowance(from, spender, amount); 85 | _transfer(from, to, amount); 86 | 87 | // Quite dirty but this should do the trick of testing attempted reentrancy 88 | if (reentrancyOnTransfer) { 89 | (bool success, bytes memory data) = 90 | msg.sender.call(reentrancyCallData); 91 | callSuccessful = success; 92 | callData = data; 93 | } 94 | 95 | return true; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /test/utils/mocks/ERC721Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | import {ERC721} from "@oz/token/ERC721/ERC721.sol"; 5 | 6 | contract ERC721Mock is ERC721 { 7 | uint public idCounter; 8 | 9 | mapping(address => bool) blockedAddresses; 10 | 11 | constructor(string memory _name, string memory _symbol) 12 | ERC721(_name, _symbol) 13 | {} 14 | 15 | function mint(address to) public { 16 | _mint(to, idCounter); 17 | idCounter = idCounter + 1; 18 | } 19 | 20 | function burn(uint tokenId) public { 21 | _burn(tokenId); 22 | } 23 | 24 | function blockAddress(address user) public { 25 | blockedAddresses[user] = true; 26 | } 27 | 28 | function unblockAddress(address user) public { 29 | blockedAddresses[user] = false; 30 | } 31 | 32 | function isBlockedAddress(address user) public view returns (bool) { 33 | return blockedAddresses[user]; 34 | } 35 | 36 | function transferFrom(address from, address to, uint tokenId) 37 | public 38 | override 39 | { 40 | require(!isBlockedAddress(to), "address blocked"); 41 | _transfer(from, to, tokenId); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/utils/mocks/external/CallIntercepter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | contract CallIntercepter is Test { 7 | bool isTrusted; 8 | bool public callShouldBreak; 9 | 10 | constructor() { 11 | isTrusted = true; 12 | } 13 | 14 | // ERC2771Context 15 | // @dev Because we want to expose the isTrustedForwarder function from the ERC2771Context Contract in the IOrchestrator_v1 16 | // we have to override it here as the original openzeppelin version doesnt contain a interface that we could use to expose it. 17 | function isTrustedForwarder(address) public view virtual returns (bool) { 18 | return isTrusted; 19 | } 20 | 21 | function flipIsTrusted() external { 22 | isTrusted = !isTrusted; 23 | } 24 | 25 | function flipCallShouldBreak() external { 26 | callShouldBreak = !callShouldBreak; 27 | } 28 | 29 | event CallReceived(address intercepterAddress, bytes data, address sender); 30 | 31 | error CallReceivedButBroke( 32 | address intercepterAddress, bytes data, address sender 33 | ); 34 | 35 | fallback(bytes calldata) external virtual returns (bytes memory) { 36 | if (callShouldBreak) { 37 | revert CallReceivedButBroke(address(this), msg.data, msg.sender); 38 | } 39 | emit CallReceived(address(this), msg.data, msg.sender); 40 | return (abi.encode("Call Successful")); 41 | } 42 | 43 | receive() external payable { 44 | revert(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test/utils/mocks/external/FeeManagerV1Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | import {IFeeManager_v1} from "@ex/fees/interfaces/IFeeManager_v1.sol"; 5 | 6 | contract FeeManagerV1Mock is IFeeManager_v1 { 7 | function BPS() external returns (uint) {} 8 | 9 | //--------------------------- 10 | // Treasuries 11 | 12 | function getDefaultProtocolTreasury() external view returns (address) {} 13 | 14 | function getWorkflowTreasuries(address workflow) 15 | external 16 | view 17 | returns (address) 18 | {} 19 | 20 | //--------------------------- 21 | // Fees 22 | 23 | function getDefaultCollateralFee() external view returns (uint) {} 24 | 25 | function getDefaultIssuanceFee() external view returns (uint) {} 26 | 27 | function getCollateralWorkflowFee( 28 | address workflow, 29 | address module, 30 | bytes4 functionSelector 31 | ) external view returns (uint fee) {} 32 | 33 | function getIssuanceWorkflowFee( 34 | address workflow, 35 | address module, 36 | bytes4 functionSelector 37 | ) external view returns (uint fee) {} 38 | 39 | function getCollateralWorkflowFeeAndTreasury( 40 | address workflow, 41 | address module, 42 | bytes4 functionSelector 43 | ) external view returns (uint fee, address treasury) {} 44 | 45 | function getIssuanceWorkflowFeeAndTreasury( 46 | address workflow, 47 | address module, 48 | bytes4 functionSelector 49 | ) external view returns (uint fee, address treasury) {} 50 | 51 | //-------------------------------------------------------------------------- 52 | // Setter Functions 53 | 54 | //--------------------------- 55 | // MaxFee 56 | 57 | function setMaxFee(uint _maxFee) external {} 58 | 59 | //--------------------------- 60 | // Treasuries 61 | 62 | function setDefaultProtocolTreasury(address _defaultProtocolTreasury) 63 | external 64 | {} 65 | 66 | function setWorkflowTreasury(address workflow, address treasury) external {} 67 | 68 | //--------------------------- 69 | // Fees 70 | 71 | function setDefaultCollateralFee(uint _defaultCollateralFee) external {} 72 | 73 | function setDefaultIssuanceFee(uint _defaultIssuanceFee) external {} 74 | 75 | function setCollateralWorkflowFee( 76 | address workflow, 77 | address module, 78 | bytes4 functionSelector, 79 | bool set, 80 | uint fee 81 | ) external {} 82 | 83 | function setIssuanceWorkflowFee( 84 | address workflow, 85 | address module, 86 | bytes4 functionSelector, 87 | bool set, 88 | uint fee 89 | ) external {} 90 | } 91 | -------------------------------------------------------------------------------- /test/utils/mocks/external/GovernorV1Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | import {IGovernor_v1} from "@ex/governance/interfaces/IGovernor_v1.sol"; 5 | import {IFeeManager_v1} from "@ex/fees/interfaces/IFeeManager_v1.sol"; 6 | 7 | import {IModule_v1} from "src/modules/base/IModule_v1.sol"; 8 | import {IModuleFactory_v1} from "src/factories/interfaces/IModuleFactory_v1.sol"; 9 | 10 | import {IInverterBeacon_v1} from "src/proxies/interfaces/IInverterBeacon_v1.sol"; 11 | 12 | contract GovernorV1Mock is IGovernor_v1 { 13 | address feeManager; 14 | 15 | uint public howManyCalls; 16 | //-------------------------------------------------------------------------- 17 | // Initialization 18 | 19 | function init(address, address, uint, address, address) external {} 20 | 21 | function moduleFactoryInitCallback(IInverterBeacon_v1[] calldata) 22 | external 23 | { 24 | howManyCalls++; 25 | } 26 | 27 | //-------------------------------------------------------------------------- 28 | // Getter Functions 29 | 30 | function getBeaconTimelock(address) 31 | external 32 | view 33 | returns (Timelock memory) 34 | {} 35 | 36 | function getLinkedBeacons() 37 | external 38 | view 39 | returns (IInverterBeacon_v1[] memory) 40 | {} 41 | 42 | //-------------------------------------------------------------------------- 43 | // FeeManager 44 | 45 | function getFeeManager() external view returns (address) { 46 | return feeManager; 47 | } 48 | 49 | function setFeeManager(address newFeeManager) external { 50 | feeManager = newFeeManager; 51 | } 52 | 53 | function getModuleFactory() external pure returns (address) { 54 | return address(0); 55 | } 56 | 57 | function setModuleFactory(address) external {} 58 | 59 | function setFeeManagerMaxFee(uint) external {} 60 | 61 | function setFeeManagerDefaultProtocolTreasury(address) external {} 62 | 63 | function setFeeManagerWorkflowTreasuries(address workflow, address treasury) 64 | external 65 | { 66 | IFeeManager_v1(feeManager).setWorkflowTreasury(workflow, treasury); 67 | } 68 | 69 | function setFeeManagerDefaultCollateralFee(uint) external {} 70 | 71 | function setFeeManagerDefaultIssuanceFee(uint) external {} 72 | 73 | function setFeeManagerCollateralWorkflowFee( 74 | address workflow, 75 | address module, 76 | bytes4 functionSelector, 77 | bool set, 78 | uint fee 79 | ) external { 80 | IFeeManager_v1(feeManager).setCollateralWorkflowFee( 81 | workflow, module, functionSelector, set, fee 82 | ); 83 | } 84 | 85 | function setFeeManagerIssuanceWorkflowFee( 86 | address workflow, 87 | address module, 88 | bytes4 functionSelector, 89 | bool set, 90 | uint fee 91 | ) external { 92 | IFeeManager_v1(feeManager).setIssuanceWorkflowFee( 93 | workflow, module, functionSelector, set, fee 94 | ); 95 | } 96 | 97 | //-------------------------------------------------------------------------- 98 | // Factory Functions 99 | 100 | function registerMetadataInModuleFactory( 101 | IModule_v1.Metadata memory metadata, 102 | IInverterBeacon_v1 beacon 103 | ) external {} 104 | 105 | //-------------------------------------------------------------------------- 106 | // Beacon Functions 107 | 108 | //--------------------------- 109 | // Upgrade 110 | 111 | function upgradeBeaconWithTimelock( 112 | address beacon, 113 | address newImplementation, 114 | uint newMinorVersion, 115 | uint newPatchVersion 116 | ) external {} 117 | 118 | function triggerUpgradeBeaconWithTimelock(address) external {} 119 | 120 | function cancelUpgrade(address) external {} 121 | 122 | function setTimelockPeriod(uint) external {} 123 | 124 | //--------------------------- 125 | // Emergency Shutdown 126 | 127 | function initiateBeaconShutdown(address) external {} 128 | function initiateBeaconShutdownForAllLinkedBeacons() external {} 129 | 130 | function forceUpgradeBeaconAndRestartImplementation( 131 | address, 132 | address, 133 | uint, 134 | uint 135 | ) external {} 136 | 137 | function restartBeaconImplementation(address) external {} 138 | //--------------------------- 139 | // Ownable2Step 140 | 141 | function acceptOwnership(address) external {} 142 | } 143 | -------------------------------------------------------------------------------- /test/utils/mocks/external/TransactionForwarderV1AccessMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | import {TransactionForwarder_v1} from 5 | "src/external/forwarder/TransactionForwarder_v1.sol"; 6 | 7 | contract TransactionForwarderV1AccessMock is TransactionForwarder_v1 { 8 | constructor() TransactionForwarder_v1() {} 9 | 10 | function original_validate(ForwardRequestData calldata request) 11 | external 12 | view 13 | returns ( 14 | bool isTrustedForwarder, 15 | bool active, 16 | bool signerMatch, 17 | address signer 18 | ) 19 | { 20 | return _validate(request); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/utils/mocks/factories/ModuleFactoryV1Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | import {LibMetadata} from "src/modules/lib/LibMetadata.sol"; 5 | 6 | import { 7 | IModuleFactory_v1, 8 | IInverterBeacon_v1, 9 | IModule_v1, 10 | IOrchestrator_v1 11 | } from "src/factories/interfaces/IModuleFactory_v1.sol"; 12 | 13 | import {IOrchestratorFactory_v1} from 14 | "src/factories/interfaces/IOrchestratorFactory_v1.sol"; 15 | import {ModuleV1Mock} from "test/utils/mocks/modules/base/ModuleV1Mock.sol"; 16 | 17 | import {FundingManagerV1Mock} from 18 | "test/utils/mocks/modules/FundingManagerV1Mock.sol"; 19 | import {AuthorizerV1Mock} from "test/utils/mocks/modules/AuthorizerV1Mock.sol"; 20 | import {PaymentProcessorV1Mock} from 21 | "test/utils/mocks/modules/PaymentProcessorV1Mock.sol"; 22 | 23 | import {Clones} from "@oz/proxy/Clones.sol"; 24 | 25 | contract ModuleFactoryV1Mock is IModuleFactory_v1 { 26 | IInverterBeacon_v1 private _beacon; 27 | 28 | uint public howManyCalls; 29 | 30 | address public governor = address(0x999999); 31 | address public reverter = address(0x111111); 32 | 33 | IOrchestratorFactory_v1.WorkflowConfig public givenWorkflowConfig; 34 | 35 | IModule_v1.Metadata fundingManagerMetadata = IModule_v1.Metadata( 36 | 1, 0, 0, "https://fundingmanager.com", "FundingManager" 37 | ); 38 | 39 | IModule_v1.Metadata authorizerMetadata = 40 | IModule_v1.Metadata(1, 0, 0, "https://authorizer.com", "Authorizer"); 41 | 42 | IModule_v1.Metadata paymentProcessorMetadata = IModule_v1.Metadata( 43 | 1, 1, 0, "https://paymentprocessor.com", "PP_Simple_v1" 44 | ); 45 | 46 | function createAndInitModule( 47 | IModule_v1.Metadata memory metadata, 48 | IOrchestrator_v1, 49 | bytes memory, 50 | IOrchestratorFactory_v1.WorkflowConfig memory workflowConfig 51 | ) external returns (address) { 52 | givenWorkflowConfig = workflowConfig; 53 | if ( 54 | LibMetadata.identifier(metadata) 55 | == LibMetadata.identifier(fundingManagerMetadata) 56 | ) { 57 | return address(new FundingManagerV1Mock()); 58 | } else if ( 59 | LibMetadata.identifier(metadata) 60 | == LibMetadata.identifier(authorizerMetadata) 61 | ) { 62 | return address(new AuthorizerV1Mock()); 63 | } else if ( 64 | LibMetadata.identifier(metadata) 65 | == LibMetadata.identifier(paymentProcessorMetadata) 66 | ) { 67 | return address(new PaymentProcessorV1Mock()); 68 | } else { 69 | return address(new ModuleV1Mock()); 70 | } 71 | } 72 | 73 | function createModuleProxy( 74 | IModule_v1.Metadata memory, 75 | IOrchestrator_v1, 76 | IOrchestratorFactory_v1.WorkflowConfig memory 77 | ) external returns (address) { 78 | return Clones.clone(address(new ModuleV1Mock())); 79 | } 80 | 81 | function getBeaconAndId(IModule_v1.Metadata memory metadata) 82 | external 83 | view 84 | returns (IInverterBeacon_v1, bytes32) 85 | { 86 | return (_beacon, LibMetadata.identifier(metadata)); 87 | } 88 | 89 | function getOrchestratorOfProxy(address /*proxy*/ ) 90 | external 91 | view 92 | returns (address) 93 | { 94 | // we return msg.sender here, because this is just a mocked factory. 95 | // this means, that when we are using this, we are not actually testing the 96 | // real functionality of the factory, but of another contract. 97 | // the calling contract (ModuleManager) expects the returned address to be 98 | // itself, if the module proxy was created for it properly. 99 | return msg.sender; 100 | } 101 | 102 | function registerMetadata(IModule_v1.Metadata memory, IInverterBeacon_v1) 103 | external 104 | { 105 | howManyCalls++; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /test/utils/mocks/modules/FundingManagerV1Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | // External Interfaces 5 | import {IERC20} from "@oz/token/ERC20/IERC20.sol"; 6 | 7 | // Internal Dependencies 8 | import { 9 | Module_v1, 10 | IModule_v1, 11 | IOrchestrator_v1 12 | } from "src/modules/base/Module_v1.sol"; 13 | import {IFundingManager_v1} from "@fm/IFundingManager_v1.sol"; 14 | 15 | // External Libraries 16 | import {SafeERC20} from "@oz/token/ERC20/utils/SafeERC20.sol"; 17 | 18 | contract FundingManagerV1Mock is IFundingManager_v1, Module_v1 { 19 | function supportsInterface(bytes4 interfaceId) 20 | public 21 | view 22 | virtual 23 | override(Module_v1) 24 | returns (bool) 25 | { 26 | bytes4 interfaceId_IFundingManager = 27 | type(IFundingManager_v1).interfaceId; 28 | return interfaceId == interfaceId_IFundingManager 29 | || super.supportsInterface(interfaceId); 30 | } 31 | 32 | // using SafeERC20 for IERC20; 33 | 34 | IERC20 private _token; 35 | 36 | function init( 37 | IOrchestrator_v1 orchestrator_, 38 | Metadata memory metadata, 39 | bytes memory 40 | ) public override(Module_v1) initializer { 41 | __Module_init(orchestrator_, metadata); 42 | } 43 | 44 | function setToken(IERC20 newToken) public { 45 | _token = newToken; 46 | } 47 | 48 | function token() public view returns (IERC20) { 49 | return _token; 50 | } 51 | 52 | function deposit(uint amount) external { 53 | // _token.safeTransferFrom(_msgSender(), address(this), amount); 54 | _token.transferFrom(_msgSender(), address(this), amount); 55 | } 56 | 57 | function depositFor(address, uint amount) external { 58 | // _token.safeTransferFrom(_msgSender(), address(this), amount); 59 | _token.transferFrom(_msgSender(), address(this), amount); 60 | } 61 | 62 | function withdraw(uint amount) external { 63 | // _token.safeTransfer(_msgSender(), amount); 64 | _token.transfer(_msgSender(), amount); 65 | } 66 | 67 | function withdrawTo(address to, uint amount) external { 68 | // _token.safeTransfer(to, amount); 69 | _token.transfer(to, amount); 70 | } 71 | 72 | function transferOrchestratorToken(address to, uint amount) external { 73 | // _token.safeTransfer(to, amount); 74 | _token.transfer(to, amount); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /test/utils/mocks/modules/PaymentProcessorV1Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | import {IERC20} from "@oz/token/ERC20/IERC20.sol"; 5 | 6 | import {ERC165} from "@oz/utils/introspection/ERC165.sol"; 7 | 8 | import {IPaymentProcessor_v1} from 9 | "src/modules/paymentProcessor/IPaymentProcessor_v1.sol"; 10 | import {IERC20PaymentClientBase_v1} from 11 | "@lm/interfaces/IERC20PaymentClientBase_v1.sol"; 12 | import {IModule_v1} from "src/modules/base/Module_v1.sol"; 13 | 14 | contract PaymentProcessorV1Mock is IPaymentProcessor_v1, ERC165 { 15 | function supportsInterface(bytes4 interfaceId) 16 | public 17 | view 18 | virtual 19 | override(ERC165) 20 | returns (bool) 21 | { 22 | bytes4 interfaceId_IPaymentProcessor = 23 | type(IPaymentProcessor_v1).interfaceId; 24 | bytes4 interfaceId_IModule = type(IModule_v1).interfaceId; 25 | return interfaceId == interfaceId_IPaymentProcessor 26 | || interfaceId == interfaceId_IModule 27 | || super.supportsInterface(interfaceId); 28 | } 29 | 30 | uint public processPaymentsTriggered; 31 | bool public validOrder = true; 32 | 33 | //-------------------------------------------------------------------------- 34 | // IPaymentProcessor_v1 Functions 35 | 36 | function processPayments(IERC20PaymentClientBase_v1 /*client*/ ) external { 37 | emit PaymentOrderProcessed( 38 | address(0), address(0), address(0), 0, 0, 0, 0 39 | ); 40 | processPaymentsTriggered += 1; 41 | } 42 | 43 | function cancelRunningPayments(IERC20PaymentClientBase_v1) external {} 44 | 45 | function token() external pure returns (IERC20) { 46 | return IERC20(address(0)); 47 | } 48 | 49 | function deleteAllPayments(IERC20PaymentClientBase_v1 client) external { 50 | client.collectPaymentOrders(); 51 | } 52 | 53 | function unclaimable(address, address, address) 54 | external 55 | view 56 | returns (uint) 57 | {} 58 | 59 | function claimPreviouslyUnclaimable(address, address, address) external {} 60 | 61 | function validPaymentOrder(IERC20PaymentClientBase_v1.PaymentOrder memory) 62 | external 63 | view 64 | returns (bool) 65 | { 66 | return validOrder; 67 | } 68 | 69 | // Mock Functions 70 | 71 | function flipValidOrder() external { 72 | validOrder = !validOrder; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /test/utils/mocks/modules/base/ModuleV1Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | import { 5 | Module_v1, 6 | IModule_v1, 7 | IOrchestrator_v1 8 | } from "src/modules/base/Module_v1.sol"; 9 | 10 | contract ModuleV1Mock is Module_v1 { 11 | function init( 12 | IOrchestrator_v1 orchestrator_, 13 | Metadata memory metadata, 14 | bytes memory 15 | ) public virtual override(Module_v1) initializer { 16 | __Module_init(orchestrator_, metadata); 17 | } 18 | 19 | // Note that the `initializer` modifier is missing. 20 | function initNoInitializer( 21 | IOrchestrator_v1 orchestrator_, 22 | Metadata memory metadata, 23 | bytes memory 24 | ) external { 25 | __Module_init(orchestrator_, metadata); 26 | } 27 | 28 | function original_msgSender() 29 | external 30 | view 31 | virtual 32 | returns (address sender) 33 | { 34 | return _msgSender(); 35 | } 36 | 37 | function original_msgData() 38 | external 39 | view 40 | virtual 41 | returns (bytes calldata) 42 | { 43 | return _msgData(); 44 | } 45 | 46 | function original_getFeeManagerCollateralFeeData(bytes4 functionSelector) 47 | external 48 | view 49 | returns (uint, address) 50 | { 51 | return _getFeeManagerCollateralFeeData(functionSelector); 52 | } 53 | 54 | function original_getFeeManagerIssuanceFeeData(bytes4 functionSelector) 55 | external 56 | view 57 | returns (uint, address) 58 | { 59 | return _getFeeManagerIssuanceFeeData(functionSelector); 60 | } 61 | 62 | // Empty function used to test the modifier `onlyPaymentClient` 63 | function modifierOnlyPaymentClientCheck() external view onlyPaymentClient {} 64 | 65 | function modifierOnlyValidAddressCheck(address to) 66 | external 67 | view 68 | validAddress(to) 69 | {} 70 | } 71 | -------------------------------------------------------------------------------- /test/utils/mocks/modules/logicModules/LM_PC_Bounties_v1AccessMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | // Internal Dependencies 5 | import {LM_PC_Bounties_v1} from "@lm/LM_PC_Bounties_v1.sol"; 6 | 7 | contract LM_PC_Bounties_v1AccessMock is LM_PC_Bounties_v1 { 8 | //-------------------------------------------------------------------------- 9 | // Modifier Access 10 | 11 | function validArrayLengthsCheck( 12 | uint minimumPayoutAmountLength, 13 | uint maximumPayoutAmountLength, 14 | uint detailArrayLength 15 | ) 16 | external 17 | pure 18 | validArrayLengths( 19 | minimumPayoutAmountLength, 20 | maximumPayoutAmountLength, 21 | detailArrayLength 22 | ) 23 | {} 24 | 25 | //-------------------------------------------------------------------------- 26 | // Internal Functions 27 | 28 | function direct__validPayoutAmounts( 29 | uint minimumPayoutAmount, 30 | uint maximumPayoutAmount 31 | ) external pure { 32 | _validPayoutAmounts(minimumPayoutAmount, maximumPayoutAmount); 33 | } 34 | 35 | function direct__addBounty( 36 | uint minimumPayoutAmount, 37 | uint maximumPayoutAmount, 38 | bytes calldata details 39 | ) external returns (uint) { 40 | return _addBounty(minimumPayoutAmount, maximumPayoutAmount, details); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/utils/mocks/modules/logicModules/LM_PC_Staking_v1AccessMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | // Internal Dependencies 5 | import {LM_PC_Staking_v1} from "@lm/LM_PC_Staking_v1.sol"; 6 | 7 | contract LM_PC_Staking_v1AccessMock is LM_PC_Staking_v1 { 8 | //-------------------------------------------------------------------------- 9 | // Getter Functions 10 | 11 | function getRewardValue() external view returns (uint) { 12 | return rewardValue; 13 | } 14 | 15 | function getLastUpdate() external view returns (uint) { 16 | return lastUpdate; 17 | } 18 | 19 | function getUserRewardValue(address user) external view returns (uint) { 20 | return userRewardValue[user]; 21 | } 22 | 23 | function getRewards(address user) external view returns (uint) { 24 | return rewards[user]; 25 | } 26 | 27 | //-------------------------------------------------------------------------- 28 | // Setter Functions 29 | 30 | function setRewardRate(uint rR) external { 31 | rewardRate = rR; 32 | } 33 | 34 | function setRewardValue(uint rV) external { 35 | rewardValue = rV; 36 | } 37 | 38 | function setLastUpdate(uint lU) external { 39 | lastUpdate = lU; 40 | } 41 | 42 | function setUserRewardValue(address user, uint rV) external { 43 | userRewardValue[user] = rV; 44 | } 45 | 46 | function setRewardsEnd(uint newRewardsEnd) external { 47 | rewardsEnd = newRewardsEnd; 48 | } 49 | 50 | //-------------------------------------------------------------------------- 51 | // Internal Functions 52 | 53 | function direct_update(address triggerAddress) external { 54 | _update(triggerAddress); 55 | } 56 | 57 | function direct_calculateRewardValue() external view returns (uint) { 58 | return _calculateRewardValue(); 59 | } 60 | 61 | function direct_getRewardDistributionTimestamp() 62 | external 63 | view 64 | returns (uint) 65 | { 66 | return _getRewardDistributionTimestamp(); 67 | } 68 | 69 | function direct_earned(address user, uint providedRewardValue) 70 | external 71 | view 72 | returns (uint) 73 | { 74 | return _earned(user, providedRewardValue); 75 | } 76 | 77 | function direct_distributeRewards(address recipient) external { 78 | _distributeRewards(recipient); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /test/utils/mocks/modules/paymentClient/ERC20PaymentClientBaseV1AccessMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | import {IOrchestrator_v1} from 5 | "src/orchestrator/interfaces/IOrchestrator_v1.sol"; 6 | 7 | import { 8 | Module_v1, 9 | IModule_v1, 10 | IOrchestrator_v1 11 | } from "src/modules/base/Module_v1.sol"; 12 | 13 | // SuT 14 | import { 15 | ERC20PaymentClientBase_v1, 16 | IERC20PaymentClientBase_v1 17 | } from "@lm/abstracts/ERC20PaymentClientBase_v1.sol"; 18 | 19 | // Internal Interfaces 20 | import {IPaymentProcessor_v1} from 21 | "src/modules/paymentProcessor/IPaymentProcessor_v1.sol"; 22 | 23 | // Mocks 24 | import {ERC20Mock} from "test/utils/mocks/ERC20Mock.sol"; 25 | 26 | contract ERC20PaymentClientBaseV1AccessMock is ERC20PaymentClientBase_v1 { 27 | mapping(address => bool) authorized; 28 | 29 | function init( 30 | IOrchestrator_v1 orchestrator_, 31 | Metadata memory metadata, 32 | bytes memory // configData 33 | ) external override(Module_v1) initializer { 34 | __Module_init(orchestrator_, metadata); 35 | } 36 | 37 | //-------------------------------------------------------------------------- 38 | // IERC20PaymentClientBase_v1 Wrapper Functions 39 | 40 | function addPaymentOrder(PaymentOrder memory order) external { 41 | _addPaymentOrder(order); 42 | } 43 | 44 | // add a payment order without checking the arguments 45 | function addPaymentOrderUnchecked(PaymentOrder memory order) external { 46 | // Add order's token amount to current outstanding amount. 47 | _outstandingTokenAmounts[order.paymentToken] += order.amount; 48 | 49 | // Add new order to list of oustanding orders. 50 | _orders.push(order); 51 | 52 | emit PaymentOrderAdded( 53 | order.recipient, order.paymentToken, order.amount 54 | ); 55 | } 56 | 57 | function addPaymentOrders(PaymentOrder[] memory orders) external { 58 | _addPaymentOrders(orders); 59 | } 60 | 61 | // for testing the original functionality of the internal functions I created these placeholders 62 | 63 | function originalEnsureTokenBalance(address token) external { 64 | return _ensureTokenBalance(token); 65 | } 66 | 67 | function originalEnsureTokenAllowance( 68 | IPaymentProcessor_v1 spender, 69 | address token 70 | ) external { 71 | return _ensureTokenAllowance(spender, token); 72 | } 73 | 74 | function originalIsAuthorizedPaymentProcessor( 75 | IPaymentProcessor_v1 processor 76 | ) external view returns (bool) { 77 | return _isAuthorizedPaymentProcessor(processor); 78 | } 79 | 80 | function set_outstandingTokenAmount(address token, uint amount) external { 81 | _outstandingTokenAmounts[token] = amount; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /test/utils/mocks/modules/paymentClient/ERC20PaymentClientBaseV1Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | import {IOrchestrator_v1} from 5 | "src/orchestrator/interfaces/IOrchestrator_v1.sol"; 6 | 7 | // SuT 8 | import { 9 | ERC20PaymentClientBase_v1, 10 | IERC20PaymentClientBase_v1 11 | } from "@lm/abstracts/ERC20PaymentClientBase_v1.sol"; 12 | 13 | // Internal Interfaces 14 | import {IPaymentProcessor_v1} from 15 | "src/modules/paymentProcessor/IPaymentProcessor_v1.sol"; 16 | 17 | // Mocks 18 | import {ERC20Mock} from "test/utils/mocks/ERC20Mock.sol"; 19 | 20 | contract ERC20PaymentClientBaseV1Mock is ERC20PaymentClientBase_v1 { 21 | ERC20Mock token; 22 | 23 | mapping(address => uint) public amountPaidCounter; 24 | mapping(address => bool) authorized; 25 | 26 | //-------------------------------------------------------------------------- 27 | // Mock Functions 28 | 29 | function setIsAuthorized(address who, bool to) external { 30 | authorized[who] = to; 31 | } 32 | 33 | function setOrchestrator(IOrchestrator_v1 orchestrator) external { 34 | __Module_orchestrator = orchestrator; 35 | } 36 | 37 | function setToken(ERC20Mock token_) external { 38 | token = token_; 39 | } 40 | 41 | //-------------------------------------------------------------------------- 42 | // IERC20PaymentClientBase_v1 Wrapper Functions 43 | 44 | function addPaymentOrder(PaymentOrder memory order) external { 45 | _addPaymentOrder(order); 46 | } 47 | 48 | // add a payment order without checking the arguments 49 | function addPaymentOrderUnchecked(PaymentOrder memory order) external { 50 | // Add order's token amount to current outstanding amount. 51 | _outstandingTokenAmounts[order.paymentToken] += order.amount; 52 | 53 | // Add new order to list of oustanding orders. 54 | _orders.push(order); 55 | 56 | emit PaymentOrderAdded( 57 | order.recipient, order.paymentToken, order.amount 58 | ); 59 | } 60 | 61 | function addPaymentOrders(PaymentOrder[] memory orders) external { 62 | _addPaymentOrders(orders); 63 | } 64 | 65 | //-------------------------------------------------------------------------- 66 | // IERC20PaymentClientBase_v1 Overriden Functions 67 | 68 | function _ensureTokenBalance(address _token) 69 | internal 70 | override(ERC20PaymentClientBase_v1) 71 | { 72 | uint amount = _outstandingTokenAmounts[_token]; 73 | 74 | if (ERC20Mock(_token).balanceOf(address(this)) >= amount) { 75 | return; 76 | } else { 77 | uint amtToMint = amount - ERC20Mock(_token).balanceOf(address(this)); 78 | token.mint(address(this), amtToMint); 79 | } 80 | } 81 | 82 | function _ensureTokenAllowance(IPaymentProcessor_v1 spender, address _token) 83 | internal 84 | override(ERC20PaymentClientBase_v1) 85 | { 86 | token.approve(address(spender), _outstandingTokenAmounts[_token]); 87 | } 88 | 89 | function _isAuthorizedPaymentProcessor(IPaymentProcessor_v1) 90 | internal 91 | view 92 | override(ERC20PaymentClientBase_v1) 93 | returns (bool) 94 | { 95 | return authorized[_msgSender()]; 96 | } 97 | 98 | function amountPaid(address _token, uint amount) 99 | external 100 | override(ERC20PaymentClientBase_v1) 101 | { 102 | amountPaidCounter[_token] += amount; 103 | 104 | _outstandingTokenAmounts[_token] -= amount; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /test/utils/mocks/modules/paymentProcessor/PP_Simple_v1AccessMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | // Internal Interfaces 5 | import {IERC20PaymentClientBase_v1} from 6 | "@lm/interfaces/IERC20PaymentClientBase_v1.sol"; 7 | // Internal Dependencies 8 | import {PP_Simple_v1} from "@pp/PP_Simple_v1.sol"; 9 | 10 | contract PP_Simple_v1AccessMock is PP_Simple_v1 { 11 | function original_validPaymentReceiver(address addr) 12 | external 13 | view 14 | returns (bool) 15 | { 16 | return _validPaymentReceiver(addr); 17 | } 18 | 19 | function original__validTotal(uint _total) external pure returns (bool) { 20 | return _validTotal(_total); 21 | } 22 | 23 | function original_validPaymentToken(address _token) 24 | external 25 | returns (bool) 26 | { 27 | return _validPaymentToken(_token); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/utils/mocks/modules/paymentProcessor/PP_Streaming_v1AccessMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | // Internal Interfaces 5 | import {IERC20PaymentClientBase_v1} from 6 | "@lm/interfaces/IERC20PaymentClientBase_v1.sol"; 7 | // Internal Dependencies 8 | import {PP_Streaming_v1} from "@pp/PP_Streaming_v1.sol"; 9 | 10 | contract PP_Streaming_v1AccessMock is PP_Streaming_v1 { 11 | //-------------------------------------------------------------------------- 12 | // Getter Functions 13 | 14 | function getUnclaimableStreams( 15 | address client, 16 | address token, 17 | address sender 18 | ) public view returns (uint[] memory ids) { 19 | return unclaimableStreams[client][token][sender]; 20 | } 21 | 22 | function getUnclaimableAmountForStreams( 23 | address client, 24 | address token, 25 | address sender, 26 | uint id 27 | ) public view returns (uint amount) { 28 | return unclaimableAmountsForStream[client][token][sender][id]; 29 | } 30 | 31 | function original_validPaymentReceiver(address addr) 32 | external 33 | view 34 | returns (bool) 35 | { 36 | return _validPaymentReceiver(addr); 37 | } 38 | 39 | function original__validTotal(uint _total) external pure returns (bool) { 40 | return _validTotal(_total); 41 | } 42 | 43 | function original_validTimes(uint _start, uint _cliff, uint _end) 44 | external 45 | pure 46 | returns (bool) 47 | { 48 | return _validTimes(_start, _cliff, _end); 49 | } 50 | 51 | function original_validPaymentToken(address _token) 52 | external 53 | returns (bool) 54 | { 55 | return _validPaymentToken(_token); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test/utils/mocks/orchestrator/OrchestratorV1AccessMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | import {IOrchestrator_v1} from 5 | "src/orchestrator/interfaces/IOrchestrator_v1.sol"; 6 | 7 | // External Interfaces 8 | import {IERC20} from "@oz/token/ERC20/IERC20.sol"; 9 | 10 | // Internal Interfaces 11 | import {IModuleManagerBase_v1} from 12 | "src/orchestrator/interfaces/IModuleManagerBase_v1.sol"; 13 | import {IFundingManager_v1} from "@fm/IFundingManager_v1.sol"; 14 | import {IAuthorizer_v1} from "@aut/IAuthorizer_v1.sol"; 15 | import {IPaymentProcessor_v1} from 16 | "src/modules/paymentProcessor/IPaymentProcessor_v1.sol"; 17 | import {IGovernor_v1} from "@ex/governance/interfaces/IGovernor_v1.sol"; 18 | 19 | contract OrchestratorV1AccessMock is IOrchestrator_v1 { 20 | IERC20 public token; 21 | IPaymentProcessor_v1 public paymentProcessor; 22 | IFundingManager_v1 public fundingManager; 23 | IGovernor_v1 public governor; 24 | 25 | function cancelAuthorizerUpdate(IAuthorizer_v1 authorizer_) external {} 26 | 27 | function cancelPaymentProcessorUpdate( 28 | IPaymentProcessor_v1 paymentProcessor_ 29 | ) external {} 30 | 31 | function cancelFundingManagerUpdate(IFundingManager_v1 fundingManager_) 32 | external 33 | {} 34 | 35 | function cancelModuleUpdate(address module) external {} 36 | 37 | function initiateAddModuleWithTimelock(address module) external {} 38 | 39 | function initiateRemoveModuleWithTimelock(address module) external {} 40 | 41 | function executeAddModule(address module) external {} 42 | 43 | function executeRemoveModule(address module) external {} 44 | 45 | function isModule(address module) external view returns (bool) {} 46 | 47 | function listModules() external view returns (address[] memory) {} 48 | 49 | function modulesSize() external view returns (uint8) {} 50 | 51 | function grantRole(bytes32 role, address account) external {} 52 | 53 | function revokeRole(bytes32 role, address account) external {} 54 | 55 | function renounceRole(address module, bytes32 role) external {} 56 | 57 | function hasRole(address module, bytes32 role, address account) 58 | external 59 | returns (bool) 60 | {} 61 | 62 | function init( 63 | uint, 64 | address, 65 | address[] calldata, 66 | IFundingManager_v1, 67 | IAuthorizer_v1, 68 | IPaymentProcessor_v1, 69 | IGovernor_v1 70 | ) external {} 71 | 72 | function initiateSetAuthorizerWithTimelock(IAuthorizer_v1 authorizer_) 73 | external 74 | {} 75 | 76 | function initiateSetFundingManagerWithTimelock( 77 | IFundingManager_v1 fundingManager_ 78 | ) external {} 79 | 80 | function initiateSetPaymentProcessorWithTimelock( 81 | IPaymentProcessor_v1 paymentProcessor_ 82 | ) external {} 83 | 84 | function executeSetAuthorizer(IAuthorizer_v1 authorizer_) external {} 85 | 86 | function executeSetFundingManager(IFundingManager_v1 fundingManager_) 87 | external 88 | { 89 | fundingManager = fundingManager_; 90 | } 91 | 92 | function executeSetPaymentProcessor(IPaymentProcessor_v1 paymentProcessor_) 93 | external 94 | { 95 | paymentProcessor = paymentProcessor_; 96 | } 97 | 98 | function orchestratorId() external view returns (uint) {} 99 | 100 | function authorizer() external view returns (IAuthorizer_v1) {} 101 | 102 | function version() external pure returns (string memory) {} 103 | 104 | function manager() external view returns (address) {} 105 | 106 | function verifyAddressIsPaymentProcessor(address paymentProcessorAddress) 107 | external 108 | view 109 | returns (bool) 110 | {} 111 | 112 | function verifyAddressIsRecurringPaymentManager( 113 | address recurringPaymentManager 114 | ) external view returns (bool) {} 115 | 116 | function verifyAddressIsFundingManager(address fundingManagerAddress) 117 | external 118 | view 119 | returns (bool) 120 | {} 121 | 122 | function verifyAddressIsAuthorizerModule(address authModule) 123 | external 124 | view 125 | returns (bool) 126 | {} 127 | 128 | function isTrustedForwarder(address forwarder) 129 | external 130 | view 131 | returns (bool) 132 | {} 133 | 134 | function trustedForwarder() external view returns (address) {} 135 | 136 | //------------------------------------------------------------------- 137 | // Mock Helper Functions 138 | function setToken(IERC20 token_) external { 139 | token = token_; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /test/utils/mocks/orchestrator/OrchestratorV1Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | import { 5 | ModuleManagerBase_v1, 6 | IModuleManagerBase_v1 7 | } from "src/orchestrator/abstracts/ModuleManagerBase_v1.sol"; 8 | import {Orchestrator_v1} from "src/orchestrator/Orchestrator_v1.sol"; 9 | 10 | contract OrchestratorV1Mock is Orchestrator_v1 { 11 | bool connectToTrustedForwarder = false; 12 | bool public interceptData; 13 | 14 | constructor(address _trustedForwarder) Orchestrator_v1(_trustedForwarder) {} 15 | 16 | function flipConnectToTrustedForwarder() external { 17 | connectToTrustedForwarder = !connectToTrustedForwarder; 18 | } 19 | 20 | function isTrustedForwarder(address _forwarder) 21 | public 22 | view 23 | virtual 24 | override(Orchestrator_v1) 25 | returns (bool) 26 | { 27 | if (connectToTrustedForwarder) { 28 | return super.isTrustedForwarder(_forwarder); 29 | } else { 30 | return false; 31 | } 32 | } 33 | 34 | function setInterceptData(bool b) external { 35 | interceptData = b; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/utils/mocks/orchestrator/abstracts/ModuleManagerBaseV1Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | // Internal Dependencies 5 | import { 6 | ModuleManagerBase_v1, 7 | IModuleManagerBase_v1 8 | } from "src/orchestrator/abstracts/ModuleManagerBase_v1.sol"; 9 | 10 | contract ModuleManagerBaseV1Mock is ModuleManagerBase_v1 { 11 | mapping(address => bool) private _authorized; 12 | 13 | bool private _allAuthorized; 14 | bool private _registeredProxyCheckShouldFail; 15 | 16 | constructor(address _trustedForwarder) 17 | ModuleManagerBase_v1(_trustedForwarder) 18 | {} 19 | 20 | function __ModuleManager_setIsAuthorized(address who, bool to) external { 21 | _authorized[who] = to; 22 | } 23 | 24 | function __ModuleManager_setAllAuthorized(bool to) external { 25 | _allAuthorized = to; 26 | } 27 | 28 | function __ModuleManager_setRegisteredProxyCheckShouldFail(bool to) 29 | external 30 | { 31 | _registeredProxyCheckShouldFail = to; 32 | } 33 | 34 | function init(address, /*moduleManager*/ address[] calldata modules) 35 | external 36 | initializer 37 | { 38 | __ModuleManager_init(address(this), modules); 39 | } 40 | 41 | // Note that the `initializer` modifier is missing. 42 | function initNoInitializer( 43 | address, /*moduleManager*/ 44 | address[] calldata modules 45 | ) external { 46 | __ModuleManager_init(address(this), modules); 47 | } 48 | 49 | function unmockedInit(address moduleManager, address[] calldata modules) 50 | external 51 | initializer 52 | { 53 | __ModuleManager_init(moduleManager, modules); 54 | } 55 | 56 | function getOrchestratorOfProxy(address /*proxy*/ ) 57 | external 58 | view 59 | returns (address) 60 | { 61 | return _registeredProxyCheckShouldFail ? address(0) : address(this); 62 | } 63 | 64 | function call_cancelModuleUpdate(address module) external { 65 | _cancelModuleUpdate(module); 66 | } 67 | 68 | function call_initiateAddModuleWithTimelock(address module) external { 69 | _initiateAddModuleWithTimelock(module); 70 | } 71 | 72 | function call_initiateRemoveModuleWithTimelock(address module) external { 73 | _initiateRemoveModuleWithTimelock(module); 74 | } 75 | 76 | function call_executeAddModule(address module) external { 77 | _executeAddModule(module); 78 | } 79 | 80 | function call_executeRemoveModule(address module) external { 81 | _executeRemoveModule(module); 82 | } 83 | 84 | function __ModuleManager_isAuthorized(address who) 85 | internal 86 | view 87 | override(ModuleManagerBase_v1) 88 | returns (bool) 89 | { 90 | return _authorized[who] || _allAuthorized; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /test/utils/mocks/proxies/IModuleImplementationMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | // Internal Interfaces 5 | import {IModule_v1, IOrchestrator_v1} from "src/modules/base/IModule_v1.sol"; 6 | import {IInverterBeacon_v1} from "src/proxies/interfaces/IInverterBeacon_v1.sol"; 7 | 8 | interface IModuleImplementationMock { 9 | /// @dev Returns the Version of the Implementation 10 | function getMockVersion() external pure returns (uint); 11 | } 12 | -------------------------------------------------------------------------------- /test/utils/mocks/proxies/InverterBeaconV1AccessMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | import {InverterBeacon_v1} from "src/proxies/InverterBeacon_v1.sol"; 4 | 5 | contract InverterBeaconV1AccessMock is InverterBeacon_v1 { 6 | bool useOriginal_setImplementation = true; 7 | 8 | constructor( 9 | address reverter, 10 | address owner, 11 | uint _majorVersion, 12 | address _implementation, 13 | uint _minorVersion, 14 | uint _patchVersion 15 | ) 16 | InverterBeacon_v1( 17 | reverter, 18 | owner, 19 | _majorVersion, 20 | _implementation, 21 | _minorVersion, 22 | _patchVersion 23 | ) 24 | {} 25 | 26 | function get_implementation() public view returns (address) { 27 | return _implementationAddress; 28 | } 29 | 30 | // _setImplementation 31 | 32 | function flipUseOriginal_setImplementation() external { 33 | useOriginal_setImplementation = !useOriginal_setImplementation; 34 | } 35 | 36 | function original_setImplementation( 37 | address newImplementation, 38 | bool overrideShutdown 39 | ) public { 40 | _setImplementation(newImplementation, overrideShutdown); 41 | } 42 | 43 | function _setImplementation( 44 | address newImplementation, 45 | bool overrideShutdown 46 | ) internal virtual override { 47 | if (useOriginal_setImplementation) { 48 | super._setImplementation(newImplementation, overrideShutdown); 49 | } else { 50 | // noop 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /test/utils/mocks/proxies/InverterBeaconV1Mock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | import {IInverterBeacon_v1} from "src/proxies/interfaces/IInverterBeacon_v1.sol"; 4 | 5 | import {ERC165} from "@oz/utils/introspection/ERC165.sol"; 6 | 7 | contract InverterBeaconV1Mock is IInverterBeacon_v1, ERC165 { 8 | function supportsInterface(bytes4 interfaceId) 9 | public 10 | view 11 | virtual 12 | override(ERC165) 13 | returns (bool) 14 | { 15 | return interfaceId == type(IInverterBeacon_v1).interfaceId 16 | || super.supportsInterface(interfaceId); 17 | } 18 | 19 | address public reverter; 20 | address public implementation; 21 | 22 | bool public emergencyMode; 23 | 24 | uint public majorVersion; 25 | uint public minorVersion; 26 | uint public patchVersion; 27 | 28 | uint public functionCalled; 29 | bool public forcefulCall; 30 | 31 | function overrideReverter(address newReverter) public { 32 | reverter = newReverter; 33 | } 34 | 35 | function overrideImplementation(address implementation_) public { 36 | implementation = implementation_; 37 | } 38 | 39 | function overrideVersion( 40 | uint majorVersion_, 41 | uint minorVersion_, 42 | uint patchVersion_ 43 | ) public { 44 | majorVersion = majorVersion_; 45 | minorVersion = minorVersion_; 46 | patchVersion = patchVersion_; 47 | } 48 | 49 | function overrideEmergencyMode(bool emergencyMode_) public { 50 | emergencyMode = emergencyMode_; 51 | } 52 | 53 | function version() external view returns (uint, uint, uint) { 54 | return (majorVersion, minorVersion, patchVersion); 55 | } 56 | 57 | function getReverterAddress() external view virtual returns (address) { 58 | return reverter; 59 | } 60 | 61 | function getImplementationAddress() external view returns (address) { 62 | return implementation; 63 | } 64 | 65 | function emergencyModeActive() external view returns (bool) { 66 | return emergencyMode; 67 | } 68 | 69 | function upgradeTo(address impl, uint minor, uint patch, bool force) 70 | external 71 | { 72 | functionCalled++; 73 | implementation = impl; 74 | minorVersion = minor; 75 | patchVersion = patch; 76 | forcefulCall = force; 77 | } 78 | 79 | function shutDownImplementation() external { 80 | functionCalled++; 81 | } 82 | 83 | function restartImplementation() external { 84 | functionCalled++; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /test/utils/mocks/proxies/InverterBeaconV1OwnableMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | import {InverterBeaconV1Mock} from 4 | "test/utils/mocks/proxies/InverterBeaconV1Mock.sol"; 5 | 6 | import {Ownable2Step} from "@oz/access/Ownable2Step.sol"; 7 | import {Context, Ownable} from "@oz/access/Ownable.sol"; 8 | 9 | contract InverterBeaconV1OwnableMock is InverterBeaconV1Mock, Ownable2Step { 10 | constructor(address owner) Ownable(owner) { 11 | // NO-OP 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/utils/mocks/proxies/InverterTransparentUpgradeableProxyV1AccessMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | import {InverterTransparentUpgradeableProxy_v1} from 4 | "src/proxies/InverterTransparentUpgradeableProxy_v1.sol"; 5 | 6 | import {IInverterBeacon_v1} from "src/proxies/interfaces/IInverterBeacon_v1.sol"; 7 | 8 | contract InverterTransparentUpgradeableProxyV1AccessMock is 9 | InverterTransparentUpgradeableProxy_v1 10 | { 11 | bool public upgradeToNewestVersionActive = true; 12 | uint public upgradeToNewestVersionCalledCounter; 13 | 14 | function flipUpgradeToNewestVersionActive() external view { 15 | upgradeToNewestVersionActive != upgradeToNewestVersionActive; 16 | } 17 | 18 | constructor( 19 | IInverterBeacon_v1 beacon, 20 | address initialOwner, 21 | bytes memory _data 22 | ) InverterTransparentUpgradeableProxy_v1(beacon, initialOwner, _data) {} 23 | 24 | function direct__admin() external view returns (address) { 25 | return _admin; 26 | } 27 | 28 | function direct__beacon() external view returns (address) { 29 | return address(_beacon); 30 | } 31 | 32 | function direct__implementation() external view returns (address) { 33 | return _implementation(); 34 | } 35 | 36 | function direct_upgradeToNewestVersion() external { 37 | upgradeToNewestVersion(); 38 | } 39 | 40 | function upgradeToNewestVersion() internal override { 41 | upgradeToNewestVersionCalledCounter++; 42 | if (upgradeToNewestVersionActive) super.upgradeToNewestVersion(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /test/utils/mocks/proxies/ModuleImplementationV1Mock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | import {ModuleV1Mock} from "test/utils/mocks/modules/base/ModuleV1Mock.sol"; 4 | import {IModuleImplementationMock} from 5 | "test/utils/mocks/proxies/IModuleImplementationMock.sol"; 6 | 7 | contract ModuleImplementationV1Mock is 8 | ModuleV1Mock, 9 | IModuleImplementationMock 10 | { 11 | uint public data; 12 | 13 | function initialize(uint _data) external initializer { 14 | data = _data; 15 | } 16 | 17 | function getMockVersion() external pure returns (uint) { 18 | return 1; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/utils/mocks/proxies/ModuleImplementationV2Mock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | import "@oz/proxy/utils/Initializable.sol"; 4 | 5 | import {ModuleV1Mock} from "test/utils/mocks/modules/base/ModuleV1Mock.sol"; 6 | import {IModuleImplementationMock} from 7 | "test/utils/mocks/proxies/IModuleImplementationMock.sol"; 8 | 9 | contract ModuleImplementationV2Mock is 10 | ModuleV1Mock, 11 | IModuleImplementationMock 12 | { 13 | uint public data; 14 | 15 | function initialize(uint data_) external initializer { 16 | data = data_; 17 | } 18 | 19 | function getMockVersion() external pure returns (uint) { 20 | return 2; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /testnet.env: -------------------------------------------------------------------------------- 1 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 | # Testnet Environment Variables 3 | # 4 | # WARNING: This file is part of the git repo. DO NOT INCLUDE SENSITIVE DATA! 5 | # 6 | # The environment variables are read by 7 | # - Solidity scripts in script/ 8 | # - forge commands 9 | # 10 | # Note that the variables need to be exported in order for make to read them 11 | # directly. 12 | # 13 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 14 | 15 | # ------------------------------------------------------------------------------ 16 | # Common 17 | 18 | export RPC_URL="https://rpc.ankr.com/eth_sepolia/83faca2c6ed984789a58e5dfbf9ba75d5b2b5d7c48646f6f51a004cb6cccca29" # Sepolia Node 19 | 20 | # ------------------------------------------------------------------------------ 21 | # Wallets 22 | 23 | # Note that the wallets are anvil's default wallets. 24 | 25 | export WALLET_DEPLOYER=0x9b3eb10672ddd39521b2b5f4ed6956b44f07d4e0 26 | export WALLET_DEPLOYER_PK=0xcc3bf7af19c3ddb251d19b3abe51a7757d7a578c8f3194e06aac8bd238494871 27 | 28 | # ------------------------------------------------------------------------------ 29 | # Deployment Arguments 30 | 31 | # OrchestratorFactory 32 | export DEPLOYMENT_ORCHESTRATOR_FACTORY_BEACON=0x15d6b0b21Fd59dcEBdCd2a36779b06Cd66Adb522 33 | export DEPLOYMENT_ORCHESTRATOR_FACTORY_MODULE_FACTORY=0x7902494DBC5BB00e09B91782e0731cF268eE10D6 34 | 35 | # Orchestrator Factory 0xF35205EDCF1677a32dF799d81FB5539FBFB4f5a9 36 | --------------------------------------------------------------------------------