The MELD Lending & Borrowing Protocol is a decentralized finance (DeFi) platform that enables users to lend and borrow cryptocurrencies in a secure and efficient manner. Built on the principles of transparency and decentralization, the protocol leverages smart contracts to automate the process of lending and borrowing, ensuring trustless and permissionless interactions. MELD aims to provide users with a seamless experience, offering competitive interest rates, robust security measures, and a variety of supported assets. Whether you're a lender seeking to earn interest on your crypto holdings or a borrower looking for liquidity without selling your assets, the MELD protocol provides a comprehensive solution to meet your financial needs in the ever-evolving DeFi landscape.
Run npm install
or yarn install
to install the dependencies.
The network configuration is in the hardhat.config.ts
file. You can add or modify networks there. There is a .sample.env
file that you can use as a template to create a .env
file with the private keys of the accounts you want to interact with the different networks. You can also configure a different RPC URL for each network.
The protocol configuration is inside the markets
folder. You can add or modify the markets there. Currently there is only one market, 'meld'. Inside it there is one folder for each environment: dev (for local development), kanazawa (for the Kanazawa testnet) and meld (for the MELD mainnet). The configuration for each environment consists of the following files:
index.ts
: The main configuration file. It contains general configuration of the protocol, as well as the supported token addresses, and information for the price oracles.rateStrategies.ts
: The configuration for the rate strategies that are used in the protocol. This is used to determine the borrow rate slopes for variable and stable borrow rates.reserveConfigs.ts
: The configuration for the reserves that are used in the protocol. This is used to determine the reserve factors, the LTV, the interest rate strategies, and the liquidation thresholds for each reserve, supply and borrow cap, determine if the yield boost is enabled, etc.
There are specific scripts to deploy the protocol to each network.
npx deploy:localhost
oryarn deploy:localhost
to deploy the protocol to a local network. It also creates a file with the deployment info indeployments/localhost/protocol.json
npx deploy:kanazawa
oryarn deploy:kanazawa
to deploy the protocol to the Kanazawa testnet. It also creates a file with the deployment info indeployments/kanazawa/protocol.json
. It also verifies the contracts in the Kanazawa explorernpx deploy:meld
oryarn deploy:meld
to deploy the protocol to the MELD mainnet. It also creates a file with the deployment info indeployments/meld/protocol.json
. It also verifies the contracts in the MELD explorer
The deployment scripts use the configuration in the markets
folder to deploy the protocol with the specified configuration. Be sure to have the .env
file with the private keys of the accounts you want to use to deploy the protocol.
Calling these scripts will export three filesin the folder ./deployments/<network>/Protocol/<datetime>/
:
addresses.json
: contains the address of the deployed contractsdeployment.json
: contains the deployment information such as network, chainId, commit hash, datetime and information of every contract (address, transaction hash, abi, args, abi)supportedTokens.json
: contains the addresses of the supported tokens of the protocol, including the address of each token and the addresses of the cloned contracts (MToken, StableDebtToken, VariableDebtToken, YieldBoostStaking, YieldBoostStorage)
The deployed contracts can be verified using the following scripts:
npx verify:kanazawa
oryarn verify:kanazawa
to verify the contracts in the kanazawa testnet in the Kanazawa explorernpx verify:meld
oryarn verify:meld
to verify the contracts in the MELD mainnet in the MELD explorer
The verification scripts use the last deployment info in the deployments
folder to verify the contracts. A specific deployment file can be verified by passing the path to the file as an argument to the script. Example:
yarn verify:kanazawa --deploymentfile ./deployments/kanazawa/Protocol/2024-05-23T15-02-35.727Z/deployment.json
There are other scripts that can be used to interact with the protocol. In the tasks/config.ts
file there are some tasks that can be used to interact with the protocol. These inlcude role management, get reserves and their configuration, and creating new reserves, as well as modifying their configuration.
The architecture of the smart contracts of the protocol is fairly complex and has the following main components that interact with each other:
The Addresses Provider is a contract that stores the addresses of the main contracts of the protocol. The addresses can be updated, except some of them that are immutable.
The Addresses Provider also controls the Pausability of the protocol. From this contract, the protocol can be paused (and unpaused), preventing any interaction with the protocol.
This contract also manages the roles for the protocol, to control who can perform certain actions, using the AccessControlEnumberable from OpenZeppelin. Some of the roles are also immutable, so they can't be changed.
Role | Description | Immutable | Destroyable |
---|---|---|---|
POOL_ADMIN_ROLE |
Used for setting the configuration of the different reserves and protocol, as well as adding support for new reserves | ✘ | ✘ |
LENDING_POOL_CONFIGURATOR_ROLE |
Granted to the LendingPoolConfigurator contract | ✔ | ✘ |
LENDING_POOL_ROLE |
Granted to the LendingPool contract | ✔ | ✘ |
ORACLE_MANAGEMENT_ROLE |
Used to manage the price oracle and rate oracle contracts | ✘ | ✔ |
BNKR_NFT_MINTER_BURNER_ROLE |
Used to mint and burn MeldBanker NFTs | ✘ | ✔ |
YB_REWARDS_SETTER_ROLE |
Used to set rewards in the YieldBoost contracts | ✘ | ✘ |
GENIUS_LOAN_ROLE |
Used to withdraw, borrow and claimed rewards using genius loan | ✘ | ✔ |
PAUSER_ROLE |
Used to pause the protocol | ✘ | ✔ |
UNPAUSER_ROLE |
Used to unpause the protocol | ✘ | ✔ |
DESTROYER_ROLE |
Used to destroy roles to prevent them being used anymore | ✘ | ✘ |
The Lending Pool is the main contract of the protocol. It is the one that users interact with to lend and borrow assets. It also contains some functions to configure the reserves. This is the list of user actions that can be performed in the Lending Pool:
- Deposit: Deposit an asset into the protocol to start earning interest.
- Withdraw: Withdraw an asset from the protocol.
- Borrow: Borrow an asset from the protocol.
- Repay: Repay a borrowed asset.
- Liquidate: Liquidate a position that is below the liquidation threshold.
- FlashLoan: Borrow a list of assets and repay them in the same transaction.
- Use reserve as collateral: The user can set a reserve as collateral to borrow more assets.
- Enable genius loan: The user can enable the genius loan to allow the protocol to borrow and repay assets on behalf of the user.
In order to not get over the contract size limit, most of the logic of the Lending Pool is implemented in libraries.
The LendingPool contract is upgradeable using UUPSUpgradeable from OpenZeppelin so its implementation is accessed through a proxy. Its implementation can be upgraded by the protocol administrators during the first 6 months after deployment. After that, the contract the upgradeability can be disabled and the contract can't be upgraded anymore.
There are several tokens that are created in the protocol, for each supported token (reserve).
- MTokens: These are the tokens that are minted when a user deposits an asset into the protocol. They represent the user's share of the pool. They can be transferred, and are burned when the user withdraws the asset.
- StableDebtTokens: These are the tokens that are minted when a user borrows an asset from the protocol with a stable rate. They represent the user's debt. They cannot be transferred and are burned when the user repays the debt.
- VariableDebtTokens: These are the tokens that are minted when a user borrows an asset from the protocol with a variable rate. They represent the user's debt. They cannot be transferred and are burned when the user repays the debt.
The LendingPoolConfigurator is a contract that is used to create the reserves, configure them and the protocol. This contract is no use for the users, only for the protocol administrators.
The LendingPoolConfigurator contract is upgradeable using UUPSUpgradeable from OpenZeppelin so its implementation is accessed through a proxy. Its implementation can be upgraded by the protocol administrators during the first 6 months after deployment. After that, the contract the upgradeability can be disabled and the contract can't be upgraded anymore.
The MeldProtocolDataProvider is a contract that is used to get the data of the protocol. The contract provides information about the reserves, the users, the configuration of the protocol, the addresses of the tokens, YieldBoost, etc.
The yield boost is a novel mechanism for distributing extra yield to some assets in the protocol. It's an epoch-based distribution system that automatically tracks the balance of assets supplied and borrowed to give the rewards to the users.
The rewards distribution can be influenced by locking a Meld Banker NFT along with your position, giving you some boosts for the distribution of rewards. Only one NFT can be active by the same user at once
The yield comes from staking the assets bridged from other networks into the MELD network, and is distributed depending on the nature of the asset's yield.
Oracles are a key part of the protocol. They are used to have a source of truth for asset price and stable borrow rates.
Our system consists of an agregator for each type of asset (price and rate) that connect to the different providers to fetch the data, ensuring robustness and validity of the data used in the protocol.Each adapter of external protocols transforms the data of said oracle in a common format that gets returned into the main protocol when requested.