Centralized contract addresses, constants, and token configurations for Malda Protocol across different environments and blockchain networks.
- 🔒 Type-safe: Full TypeScript support with strict typing
- 🌐 Multi-chain: Support for Mainnet, Arbitrum, Optimism, Base, and Linea
- 🏗️ Multi-environment: Separate production and testnet configurations
- ✅ Runtime validation: Zod schemas for configuration validation
- 🔒 Type-safe ABIs: Full TypeScript inference for viem/wagmi contract interactions
- 🎯 Tree-shakeable: Import only what you need
- 📦 Zero dependencies: Minimal runtime dependencies (viem + zod)
npm install @malda-protocol/protocol-config
# or
yarn add @malda-protocol/protocol-config
# or
pnpm add @malda-protocol/protocol-config
import { PRODUCTION_CONFIG, PRODUCTION_TOKENS } from '@malda-protocol/protocol-config/production'
// Get the production configuration
console.log(PRODUCTION_CONFIG.hostChainId) // 59144 (Linea)
console.log(PRODUCTION_CONFIG.operator) // "0x05bD298c0C3F34B541B42F867BAF6707911BE437"
// Get production tokens
console.log(PRODUCTION_TOKENS) // Array of all production tokens
// Production configuration
import * as production from '@malda-protocol/protocol-config/production'
console.log(production.PRODUCTION_CONFIG)
console.log(production.PRODUCTION_TOKENS)
// Testnet configuration
import * as testnet from '@malda-protocol/protocol-config/testnet'
console.log(testnet.TESTNET_CONFIG)
console.log(testnet.TESTNET_TOKENS)
import { production, testnet } from '@malda-protocol/protocol-config'
// Production tokens
const prodUSDC = production.USDC
const prodWETH = production.WETH
// Testnet tokens
const testUSDC = testnet.USDC
const testWETH = testnet.WETH
import { getMarketsForChain, isMarketSupportedOnChain, TOKENS } from '@malda-protocol/protocol-config'
import { mainnet, base, linea } from '@wagmi/core/chains'
// Get markets available on Base
const baseMarkets = getMarketsForChain(TOKENS, base.id)
// Check if USDC is supported on Linea
const usdcToken = TOKENS.find((t) => t.symbol === 'USDC')
const isSupported = isMarketSupportedOnChain(usdcToken!, linea.id)
import { mainnet, arbitrum, optimism, base, linea } from '@wagmi/core/chains'
import {
getMarketsForChainObject,
isMarketSupportedOnChainObject,
getSupportedChainsForMarket,
getNativeCurrencySymbol,
getProductionChains,
} from '@malda-protocol/protocol-config'
import { PRODUCTION_CONFIG, PRODUCTION_TOKENS } from '@malda-protocol/protocol-config/production'
// Get markets available on Base chain
const baseMarkets = getMarketsForChainObject(PRODUCTION_TOKENS, base)
console.log(`${baseMarkets.length} markets available on ${base.name}`)
// Check if a specific token is supported on a wagmi chain
const usdcToken = PRODUCTION_TOKENS.find((t) => t.symbol === 'USDC')
const isUsdcOnArbitrum = isMarketSupportedOnChainObject(usdcToken!, arbitrum)
// Get all chains that support a specific token
const supportedChains = getSupportedChainsForMarket(
usdcToken,
[mainnet, arbitrum, optimism, base, linea],
PRODUCTION_CONFIG
)
// Access wagmi chain properties
supportedChains.forEach((chain) => {
console.log(`${chain.name}: ${getNativeCurrencySymbol(chain)}`)
console.log(`Block Explorer: ${chain.blockExplorers?.default?.url}`)
console.log(`RPC: ${chain.rpcUrls.default?.http[0]}`)
})
// Filter production chains only
const allChains = [mainnet, arbitrum, optimism, base, linea]
const productionChains = getProductionChains(allChains)
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { useReadContract } from 'wagmi'
import {
ERC20_ABI,
OPERATOR_ABI,
MTOKEN_ABI,
} from '@malda-protocol/protocol-config/abis'
import { PRODUCTION_CONFIG } from '@malda-protocol/protocol-config/production'
// With viem - full type safety!
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
const balance = await client.readContract({
address: '0x...', // USDC address
abi: ERC20_ABI,
functionName: 'balanceOf', // ✅ Autocompleted and type-safe
args: ['0x...'], // ✅ Args are type-checked
})
// With wagmi hooks - also type-safe!
function MyComponent() {
const { data: liquidity } = useReadContract({
address: PRODUCTION_CONFIG.operator,
abi: OPERATOR_ABI,
functionName: 'getAccountLiquidity', // ✅ Type-safe
args: ['0x...'], // ✅ Type-checked
})
return <div>Liquidity: {liquidity?.toString()}</div>
}
// Dynamic ABI loading (for code splitting)
import { getABI } from '@malda-protocol/protocol-config/abis'
const erc20Abi = await getABI('ERC20')
import { schemas, ProtocolConfigSchema } from '@malda-protocol/protocol-config'
// Validate a configuration object
const config = {
/* ... */
}
const result = ProtocolConfigSchema.safeParse(config)
if (result.success) {
console.log('Configuration is valid!')
} else {
console.error('Validation errors:', result.error.issues)
}
interface ProtocolConfig {
hostChainId: number
operator: Address
priceOracle: Address
blocksPerYear: number
batchSubmitter: Address
paymentReceiver: Address
// ... more fields
assets: ProtocolAsset[]
supportedChainIds: number[]
}
interface Token {
name: string
symbol: AssetSymbol
decimals: number
address: Address // mToken address
underlyingAddresses: { [chainId: number]: Address }
supportedChainIds?: number[]
}
-
PRODUCTION_CHAINS
,TESTNET_CHAINS
,ALL_CHAINS
: Wagmi chain objects for supported chains -
ASSET_SYMBOLS
: All supported asset symbols
Use explicit imports for configuration and tokens:
// Production
import { PRODUCTION_CONFIG, PRODUCTION_TOKENS } from '@malda-protocol/protocol-config/production'
// Testnet
import { TESTNET_CONFIG, TESTNET_TOKENS } from '@malda-protocol/protocol-config/testnet'
All ABIs are shared across environments and provide full TypeScript support:
-
ERC20_ABI
: Standard ERC20 token interface -
OPERATOR_ABI
: Malda protocol operator contract -
MTOKEN_ABI
: Malda mToken contract -
MTOKEN_GATEWAY_ABI
: Malda mToken gateway contract -
DELEGATOR_ABI
: Malda delegator contract -
BATCH_SUBMITTER_ABI
: Malda batch submitter contract -
MIGRATOR_ABI
: Malda migrator contract -
PAYMENT_RECEIVER_ABI
: Malda payment receiver contract -
PRICE_ORACLE_ABI
: Malda price oracle contract -
REFERRAL_SIGNING_ABI
: Malda referral signing contract -
USDT_MAINNET_ABI
: USDT mainnet specific ABI -
getABI(name)
: Dynamic ABI loader for code splitting -
ABIS
: Collection of all available ABIs with lazy loading
-
isMarketSupportedOnChainObject(token, chain)
: Check if a token is supported on a wagmi chain -
getMarketsForChainObject(tokens, chain)
: Get all tokens available on a wagmi chain -
getSupportedChainsForMarket(token, allChains, config)
: Get supported wagmi chains for a token -
getUnderlyingAddressForChain(token, chain)
: Get underlying token address for a wagmi chain -
findChainById(chainId, chains)
: Find a wagmi chain object by its ID -
createTokensFromConfig(config)
: Transform protocol assets into simplified token format
-
getNativeCurrencySymbol(chain)
: Get the native currency symbol (e.g., 'ETH') -
getRpcUrl(chain)
: Get the first RPC URL for a chain -
getBlockExplorerUrl(chain)
: Get the block explorer URL for a chain -
isTestnetChain(chain)
: Check if a wagmi chain is a testnet -
getProductionChains()
: Get predefined production (mainnet) chains -
getTestnetChains()
: Get predefined testnet chains
-
isMarketSupportedOnChain(token, chainId)
: Check if a token is supported on a chain ID -
getMarketsForChain(tokens, chainId)
: Get all tokens available on a chain ID -
getUnderlyingAddress(token, chainId)
: Get underlying token address by chain ID
Symbol | Name | Decimals | Networks |
---|---|---|---|
USDC | USD Coin | 6 | All |
WETH | Wrapped Ether | 18 | All |
USDT | USD Tether | 6 | All |
WBTC | Wrapped BTC | 8 | All |
wstETH | Wrapped liquid staked ETH | 18 | All |
ezETH | Renzo Restaked ETH | 18 | Linea only |
weETH | Wrapped eETH | 18 | All |
wrsETH | Wrapped rsETH | 18 | All |
- Ethereum Mainnet (1)
- Arbitrum One (42161)
- Optimism (10)
- Base (8453)
- Linea (59144) - Host Chain
- Sepolia (11155111)
- Linea Sepolia (59141) - Host Chain
- Optimism Sepolia (11155420)
# Install dependencies
pnpm install
# Build the package
pnpm run build
# Type check
pnpm run type-check
# Development mode (watch)
pnpm run dev
# Publishing check
pnpm run publish:check
- All address and constant changes must be submitted via Pull Request
- Changes require mandatory review (see CODEOWNERS)
- Update version using
npm version patch|minor|major
- Follow semantic versioning
This package uses semantic versioning. When making changes:
- Patch (1.0.x): Bug fixes, address updates
- Minor (1.x.0): New features, new assets, new chains
- Major (x.0.0): Breaking changes to the API
# Release a patch version
pnpm run release:patch
# Release a minor version
pnpm run release:minor
# Release a major version
pnpm run release:major
MIT © Malda Protocol