This document explains how to add new markets to Moonwell from end to end, leveraging existing tooling in a way that allows integration and governance testing both pre and post-deploy.
Go to mainnetMTokensExample.json
to see what an example mToken JSON configuration looks like. Then, copy and paste that structure into MTokens.json
in the test/proposals/mips/examples/mip-market-listing
folder, replacing all of the values with the correct values for those markets. Initial mint amount, collateral factor, should be set to the correct values and replaced with the actual values the market should have once deployed.
"initialMintAmount": 1e12,
"collateralFactor": 0.75e18,
"reserveFactor": 0.25e18,
"seizeShare": 0.03e18,
"supplyCap": 10500e18,
"borrowCap": 6300e18,
"priceFeedName": "ETH_ORACLE",
"tokenAddressName": "WETH",
"name": "Moonwell WETH",
"symbol": "mWETH",
"addressesString": "MOONWELL_WETH",
"jrm": {
"baseRatePerYear": 0.02e18,
"multiplierPerYear": 0.15e18,
"jumpMultiplierPerYear": 3e18,
"kink": 0.6e18
}
initialMintAmount
amount of tokens to mint during gov proposal, if token has 18 decimals, should be1e12
, if token has 6 decimals, should be1e6
. If token has greater than 18 decimals, decimals should be token decimals - 6 decimals. Temporal Governor must be funded with the initialMintAmount of said tokens before the proposal is executed in order for the proposal to succeed.collateralFactor
the percentage of value of supplied assets that is counted towards an account's collateral value, scaled up by1e18
. Must be less than1e18
to ensure system solvency.reserveFactor
percentage of interest accrued that goes to the Moonwell DAO reserves, scaled up by1e18
.seizeShare
percentage of seized collateral that goes to protocol reserves when a liquidation occurs, scaled up by1e18
.supplyCap
cap of amount of assets that can be supplied for a given market.borrowCap
cap of amount of assets that can be borrowed for a given market.priceFeedName
name of the chainlink aggregator address inAddresses.sol
. Note user must add the address to Addresses.sol on the proper network pre-deployment in order for the price feed to be set correctlytokenAddressName
name of the underlying token address name for the new market, set inAddresses.sol
. Note user must add the underlying token address to Addresses.sol on the proper network pre-deployment in order for the MToken's underlying address to be set correctlyname
name of the Moonwell MToken. Prefixed withMoonwell
.symbol
symbol of the Moonwell MToken. Prefixed withm
.addressesString
name of the address string set inAddresses.sol
.jrm
parameters for the configuration of a JumpRateModel for each MToken.baseRatePerYear
cost to borrow per year as a percentage, scaled by1e18
.multiplierPerYear
multiplier on the base rate, which creates the curve of the rate before kink is hit, as a percentage, scaled by1e18
.jumpMultiplierPerYear
rate multiplier as a percentage, scaled by1e18
after kink is hit.kink
the point on the utilization curve after which the interest rate spikes usingjumpMultiplierPerYear
as a percentage, scaled by1e18
If there are no MTokens being added, the file is still needed, but it should contain an empty array.
Go to mainnetRewardStreams.json
to see what an example reward JSON configuration looks like. Then, copy and paste that structure into RewardStreams.json
in the test/proposals/mips/examples/mip-market-listing
folder, replacing all of the values with the correct values for those markets.
If there are no reward streams, the file is still needed, but it should contain an empty array.
Once the proposal description has been created, copy and paste it into MarketListingDescription.md
, deleting all previous data from this file.
Once both the MarketListingDescription.md
and MTokens.json
file have the necessary contents, environment variables must be set for the script to read in their path. In the example folder, run these commands:
export LISTING_PATH="./test/proposals/mips/examples/mip-market-listing/MarketListingDescription.md"
export MTOKENS_PATH="./test/proposals/mips/examples/mip-market-listing/MTokens.json"
export EMISSION_PATH="./test/proposals/mips/examples/mip-market-listing/RewardStreams.json"
If any errors show up relating to not being able to read in a file, double check the environment variables and make sure the paths are correct.
To deploy these new markets, run DeployMarketCreationProposal.s.sol
using command:
forge script test/proposals/DeployMarketCreationProposal.s.sol:DeployMarketCreationProposal \
-vvvv \
--rpc-url base \
--broadcast
Once the contracts are deployed, copy and paste the _addAddress()
commands the deployment script outputted into the Addresses.sol
file under the proper network section. Now, save these changes and proceed to the next step.
Now that the contracts are deployed, it's time to generate the calldata. If the contracts have not been deployed and added to Addresses.sol yet, generate this calldata by running:
forge test --match-test testPrintNewMarketCalldataDeployMToken -vvv --fork-url base
otherwise, generate the calldata by running:
forge test --match-test testPrintNewMarketCalldataAlreadyDeployedMToken -vvv --fork-url base
Then, scroll up to get the calldata to propose these changes to the DAO. After section "artemis governor queue governance calldata", copy and paste the calldata and send the calldata to the governance contract on moonbase by going to metamask and submitting a transaction to the ArtemisGovernor contract with the calldata the raw hex copied.
Once the calldata is sent, wait for the proposal to finish the voting period, then queue and execute it.
To test the changes introduced by creating these market(s) and ensure the system solvency, modify the PostProposalCheck to add the newMarketDeploy mip to the array of mips tested. This can be done by uncommenting the line that adds it to the mips
address array, and lengthening the array to support 2 active proposals, or if only doing this as a single proposal, write to mips array at index 0 and comment out the other line adds the incorrect MIP.
After PostProposalCheck is modified, the view the HundredFinanceExploit example file, and replicate the structure where the PostProposalCheck contract is imported and inherited, then write the necessary tests for these newly added markets, ensuring supplying, borrowing, repaying all work.