Thank you for your interest in contributing to Moonwell! This guide outlines the process for proposing changes to the Moonwell protocol, which differs from traditional open-source projects due to the nature of smart contract development. Please read through the below guidelines carefully.
- Your go-to resource for understanding the protocol
- Essential security information
- Where protocol development takes place
- Ideal for long form questions, discussion, and ideation
- For quick, practical questions and protocol usage guidance.
The Moonwell protocol is governed by WELL token holders. The GitHub repository is a great place to build code and solicit feedback from the community. We at Moonwell will do our best to keep the main branch in sync with the onchain protocol. That said, we do not control the onchain protocol and deviations may occur. We encourage forking for independent development and remind you to review historical commits for relevant code. Pull requests for governance proposals will not be merged into the main branch until they have been thoroughly reviewed, audited if new code has been created, tested, proposed, and finally executed onchain.
Moonwell is a living cross-chain protocol, not just a repository of code that you pull and run. Commits in the repository represent suggestions for upgrades, subject to approval by WELL holders through our governance system. As such, expect that the process of filing issues, vetting pull requests and merging code may be substantially different from other open source projects that you may have interacted with in the past. These changes are meant to help get your patch approved by the community.
The most important principle in writing code for this project is clarity. Code should be as obvious as possible. We’ll always prefer clear over clever. The following are a list of principles to follow to lead in the right direction for your patch.
- Prefer local context. Try to not do too much in one function. Do not hide complexity by calling into complex sub-routines.
- Variables should be clearly named, even if it makes the name long. You can use Hungarian-like notation for variables like supplyAmountMantissa, here indicating the value is a real number with 18 decimals of precision.
- Your code should be clear without comments, and should have comments to make things crystal clear to other contributors what the intent behind each line of code is.
- Prefer the order “checks, effects then interactions,” and generally avoid cross-contract interactions where possible. Additionally, avoid interspersing computation with effects and interactions (e.g. if you can calculate a value upfront, do so).
- Try to match the code-style that already exists in the repository. Please do not refactor existing code styles.
- Public functions should have NatSpec documentation, including: a notice briefly describing the purpose, what the parameters are, and what the return value is.
- The protocol has several layers of testing: unit testing, integration testing, and formal verification.
- All contributions should have total code coverage. You should use integration tests, unit tests, harnesses, etc. You must test your code as close to the real world as possible. You can see your coverage using the forge coverage command. Note: the accuracy of the coverage tool is not authoritative; if you can show your lines of code were covered, that’s sufficient.
- You may contribute to formal analysis for your patch, but that is not a strict requirement. For complex changes to the protocol, formal verification is recommended.
Unit and integration tests can be found in the /tests directory. The run.sh shell script will run all unit and integration tests in the repository. Several environment variables will need to be set in order for tests to run properly on your local system. See setup guide here.
Every change should be run first on testnet, with source code verified and bytecode matched, just like on mainnet.
All deployed proposals must not have any contracts that are deployed using CREATE2. Any proposal which contains a programmatically deployed contract using the CREATE2 opcode will be rejected as the security risk of accepting such a proposal is too high.
At a high level, a proposal should make a minimal code change to achieve the desired result. Contributors should effectively demonstrate that their code fulfills its intended purpose. It should be possible for anyone to inspect the onchain code and verify that any changes match a particular diff in source control. The bytecode should identically match what is obtained by compiling the changes in this repository or a fork, as of a specific commit. The steps in detail are as follows:
- Develop your code, unit test, scenario test and simulate your changes
- Open a pull request for peer review and community auditing
- See these pull requests for example
- Iterate until all issues are resolved
- Deploy your contracts to mainnet, identically to your testnet deployment
- Verify your contract on Basescan or Moonscan verify using JSON inputs to avoid flattening the source code
- Record deployed contract addresses and deployment arguments
- Simulate the effect of ratifying a proposal with the actual deployed contract using a fork
- Another great place to reach out to us or the community if you have questions on how best to do this.
- The proposal should match exactly the one that will be voted upon
- Craft the proposal on mainnet
- You may need to find a sponsor with sufficient WELL to vouch for and propose your change.
- Simulate after creating, that passing the actual proposal in a fork behaves as expected
- Only then should you propose a mainnet proposal on chain.
We understand there are a lot of steps here, but your patch will have a potentially large impact on many people using the protocol, so we are vigilant to ensure the highest-quality code possible. If you have any questions, feel free to ask here, in Discord, on GitHub or on Twitter. Remember, we all govern Moonwell together, and collaboration is key to maintaining the community’s high standards for development.