This repository contains EVM smart contracts for the Midas protocol.
- Prerequisites
- Repository Structure
- Building and Testing
- Architecture Overview
- Core Contracts
- Crosschain Contracts
- Deployed Contract Addresses
- Deployment
- Upgradeability
- Documentation
- Development
- Node.js: >=22
- Yarn: Berry (check the installation guide)
# Install dependencies
yarn installIn the root of the repo, create a .env file from .env.example
midas-contracts/
├── contracts/ # Smart contract source code
│ ├── abstract/ # Abstract base contracts
│ ├── access/ # Access control contracts
│ ├── feeds/ # Price feed contracts
│ ├── interfaces/ # Contract interfaces
│ ├── libraries/ # Contract libraries
│ ├── misc/ # Miscellaneous contracts (LayerZero, Axelar, Custom price feed adapters)
│ ├── products/ # Individual mToken implementations
│ ├── testers/ # Non-production contracts that are used in tests
│ ├── mocks/ # Mocked contracts used in tests and some testnet deployments
│ ├── *.sol # Core smart contracts
│ └── ...
├── config/ # Configuration files
│ ├── constants/ # Addresses and constants
│ ├── networks/ # Network configurations
│ └── types/ # TypeScript type definitions
├── scripts/ # Deployment and upgrade scripts
│ ├── deploy/ # Deployment scripts
│ └── upgrades/ # Upgrade scripts
├── test/ # Test files
│ ├── unit/ # Unit tests
│ └── integration/ # Integration tests
├── helpers/ # Helper utilities
├── tasks/ # Hardhat tasks
└── docgen/ # Auto-generated documentation
# Clean and compile contracts
yarn build# Run all tests (unit + integration)
yarn test
# Run only unit tests
yarn test:unit
# Run only integration tests
yarn test:integration# Generate coverage report
yarn coverageCoverage reports are generated in the coverage/ directory.
# Run Slither static analysis
yarn slither
# Get summary report
yarn slither:summaryNote: Install Slither separately. See Slither installation guide.
- mTokens: ERC20 tokens (e.g., mTBILL, mBASIS, mBTC)
- Vaults: Smart contracts managing minting (deposits) and redemption processes
- Access Control: Role-based permission system for managing protocol operations
- Price Feeds: Oracle integrations for conversion rates
- Cross-Chain: LayerZero and Axelar integrations for multi-chain operations
- User initiates the deposit
- Vault calculates exchange rate and fees. For exchange rates vault calls data feeds for both payment token and mToken
- Vault transfers payment tokens from user and redirect those funds to fees/proceeds wallets
- For instant deposits (sync): mTokens are minted in the same transaction
- For request deposits (async): Admin approves/rejects the request after off-chain processing
- User initiates the redemption
- Vault calculates exchange rate and fees. For exchange rates vault calls data feeds for both payment token and mToken
- Vault transfers fees from user to the fee recipient and burns the remaining of mTokens
- For instant redemptions (sync): Payment tokens are transferred to user immediately
- For request redemptions (async): Admin fulfills the request after off-chain processing
MidasAccessControl (contracts/access/MidasAccessControl.sol)
Centralized access control contract managing all roles across the protocol
Key Features:
- Role-based access control
- Greenlist/blacklist management
Key Functions:
grantRole()- grants role to a specific address. Can be invoked only by role adminrevokeRole()- revokes role from a specific address. Can be invoked only by role admin
The default role admin for all roles is defaultAdmin. Only exceptions are:
greenlisted- role admin isgreenlistedOperatorblacklisted- role admin isblacklistedOperator
All roles in the system are documented in ROLES.md. This file is auto-generated and contains:
-
Common Roles: Roles shared across all contracts:
defaultAdmin:0x0000000000000000000000000000000000000000000000000000000000000000greenlisted: Allows access to vault operations (if greenlist is enforced)blacklisted: Prevents token transfers and vaults access
-
Token-Specific Roles: Roles for each mToken including:
minter- Can mint tokensburner- Can burn tokenspauser- Can pause/unpause token transferscustomFeedAdmin- Can manage custom price feeds and data feedsdepositVaultAdmin- Can manage deposit vault operationsredemptionVaultAdmin- Can manage redemption vault operations
mToken (contracts/mToken.sol)
Abstract base contract for all mToken implementations
Key Features:
- Minting and burning functionality (role-protected)
- Pausable transfers (inherited from
ERC20PausableUpgradeable) - Blacklist functionality - blacklisted users cannot send or receive any tokens
Key Functions:
mint(address to, uint256 amount)- Mint tokens to any address (requires minter role)burn(address from, uint256 amount)- Burn tokens from any address (requires burner role)pause()/unpause()- Pause/unpause transfers (requires pauser role)
There are 2 types of vaults - Deposit vaults and Redemption vaults. Also each type of vault have different variations (like USTB, Swapper, BUIDL etc.)
Common Key Features:
- Fee calculation and collection
- Multiple payment tokens support
- Greenlist/Blacklist
- Chainalysis sanction list integration
- Minimal mToken amount for instant/request operations
- Daily limits for instant operations
- Vault Allowance - limits the total amount of mTokens that a vault can mint or redeem. It is a risk-control mechanism managed by the vault admin and is independent from token supply caps.
Both vaults support two execution modes:
Instant (Synchronous):
- Fully on-chain
- Atomic mint/burn + transfer
- Subject to daily limits, liquidity, and minimum amounts
Request-Based (Asynchronous):
- Two-step process
- User submits request on-chain
- Admin approves or rejects after off-chain processing
- Used when instant liquidity is insufficient or instant operations are disabled. Also for fiat operations
DepositVault (contracts/DepositVault.sol)
Manages the minting process for mTokens. Users deposit payment tokens to receive mTokens.
Key Features:
- Instant deposits - minting happens atomically
- Request-based deposits - user pays in one transaction and tokens are minted in a second tx initiated by vault admin
- Supply cap management
- Minimal mTokens amount for first mint transaction
Key Functions:
depositInstant()- Instant deposit with atomic mintingdepositRequest()- Create deposit request for admin approvalapproveRequest()- Admin approves deposit requestrejectRequest()- Admin rejects deposit request
Vault Variations:
- USTB (
contracts/DepositVaultWithUSTB.sol) - Automatically invests USDC into USTB tokens before transferring proceeds to the recipient.
RedemptionVault (contracts/RedemptionVault.sol)
Manages the redemption process for mTokens. Burns mTokens from a user and transfers payment tokens in exchange
Key Features:
- Instant redemptions - user receive payment tokens atomically
- Request-based redemptions - tokens are burned from user in one transaction and payment tokens are transferred in a second tx initiated by vault admin
- Fiat redemption support
- Separate liquidity source for request-based operations
Key Functions:
redeemInstant()- Instant redemption with immediate token transferredeemRequest()- Create redemption requestredeemFiatRequest()- Create fiat redemption requestapproveRequest()- Admin fulfills redemption requestrejectRequest()- Admin rejects redemption request
Vault Variations:
- Swapper (
contracts/RedemptionVaultWithSwapper.sol) - Uses an external liquidity source to exchange one mToken for another and redeems the obtained mTokens through a different Midas redemption vault. This flow is activated only when there is insufficient liquidity in the current Redemption Vault. - BUIDL (
contracts/RedemptionVaultWithBUIDL.sol) (deprecated) - Stores pending liquidity as BUIDL tokens. When the vault has insufficient USDC liquidity to fulfill an instant redemption, BUIDL tokens are redeemed for USDC and used to complete the redemption. - USTB (
contracts/RedemptionVaultWithUSTB.sol) - Stores pending liquidity as USTB tokens. When the vault has insufficient USDC liquidity to fulfill an instant redemption, USTB tokens are redeemed for USDC and used to complete the redemption.
DataFeed (contracts/feeds/DataFeed.sol)
Wraps Chainlink AggregatorV3 price feeds, validates the price (max/min/staleness) and converts answers to 18 decimals format
Key Functions:
getDataInBase18()- View function, returns the validated and converted price with 18 decimals. Checks price for min/max allowed values, checks that its not stale
DataFeed Variations:
- CompositeDataFeed (
contracts/feeds/CompositeDataFeed.sol) - computing the ratio of two underlying data feeds (numerator ÷ denominator)
CustomAggregatorV3CompatibleFeed (contracts/feeds/CustomAggregatorV3CompatibleFeed.sol)
Custom price aggregator compatible with Chainlink's AggregatorV3 interface. Used to publish mToken prices on-chain
Key Functions:
setRoundData()- function to push the price on-chainsetRoundDataSafe()- same assetRoundData()but also performs a deviation check by comparing current and new priceslatestRoundData()- View function, returns latest submitted price with submission details (check AggregatorV3Interface.sol)
CustomAggregatorV3CompatibleFeed Variations:
- CustomAggregatorV3CompatibleFeedGrowth (
contracts/feeds/CustomAggregatorV3CompatibleFeedGrowth.sol) - includes a growth parameter that automatically increases the feed price over time
Contracts for LayerZero cross-chain messaging:
MidasLzMintBurnOFTAdapter.sol- OFT adapter that uses native mint/burn on mTokensMidasLzVaultComposerSync.sol- Vault composer for instant-only operations
Contracts for Axelar cross-chain functionality:
MidasAxelarVaultExecutable.sol- Executable contract for cross-chain operations
All deployed contract addresses are stored in config/constants/addresses.ts.
The addresses are organized by network and token. For example:
main: {
accessControl: '0x0312A9D1Ff2372DDEdCBB21e4B6389aFc919aC4B',
timelock: '0xE3EEe3e0D2398799C884a47FC40C029C8e241852',
mTBILL: {
token: '0xDD629E5241CbC5919847783e6C96B2De4754e438',
depositVault: '0x99361435420711723aF805F08187c9E6bF796683',
redemptionVault: '0xF6e51d24F4793Ac5e71e0502213a9BBE3A6d4517',
// ...
},
// ...
}Please fefer to this deployment README
Most contracts in this repository are designed to be upgradeable. We are using OpenZeppelin's TransparentUpgradeableProxy for proxy deployments
Safety measures:
- We use
@openzeppelin/hardhat-upgradespackage which automatically checks for storage layout compatibility - Upgrades are typically executed through a timelock to allow for review before execution
Non-upgradeable contracts:
Some miscellaneous contracts (like adapters and test contracts) are not upgradeable as they don't hold state or manage user funds.
All contracts are documented using NatSpec format. Generated documentation is available in docgen/index.md.
To regenerate documentation:
yarn docgen# Check code style
yarn codestyle
# Fix code style issues
yarn codestyle:fix# Lint TypeScript files
yarn lint:ts
# Lint Solidity files
yarn lint:sol
# Fix linting issues
yarn lint:ts:fix
yarn lint:sol:fix# Check formatting
yarn format:ts
yarn format:sol
# Fix formatting
yarn format:ts:fix
yarn format:sol:fix