npm package: @malda-protocol/protocol-config
Description: Centralized contract addresses, constants, and token configurations for Malda Protocol
Author: Malda Protocol
Latest version: 2.0.7

# @malda-protocol/protocol-config

[![npm version](https://badge.fury.io/js/@malda-protocol%2Fprotocol-config.svg)](https://www.npmjs.com/package/@malda-protocol/protocol-config)
[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/)

Centralized contract addresses, constants, and token configurations for Malda Protocol across different environments and blockchain networks.

## Features

- 🔒 **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)

## Installation

```bash
npm install @malda-protocol/protocol-config
# or
yarn add @malda-protocol/protocol-config
# or
pnpm add @malda-protocol/protocol-config
```

## Quick Start

```typescript
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
```

## Usage Examples

### Environment-Specific Imports

```typescript
// 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)
```

### Individual Token Access

```typescript
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
```

### Chain-Specific Operations

```typescript
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)
```

### Using with Wagmi Chains

```typescript
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)
```

### Using ABIs with Viem/Wagmi

```typescript
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { useReadContract } from 'wagmi'
import {
  ERC20_ABI,
  OPERATOR_ABI,
  MTOKEN_ABI,
  GAS_HELPER_ABI,
  JUMP_RATE_MODEL_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')

// Using jump rate models (per-mToken interest rate models)
const usdcAsset = PRODUCTION_CONFIG.assets.find(asset => asset.symbol === 'USDC')!
const borrowRate = await client.readContract({
  address: usdcAsset.jumpRateModel,
  abi: JUMP_RATE_MODEL_ABI,
  functionName: 'getBorrowRate', // ✅ Type-safe
  args: [cash, borrows, reserves], // ✅ Type-checked
})
```

### Runtime Validation

```typescript
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)
}
```

## API Reference

### Core Types

```typescript
interface ProtocolConfig {
  hostChainId: number
  operator: Address
  priceOracle: Address
  blocksPerYear: number
  gasHelper: Address
  // ... more fields
  assets: ProtocolAsset[]
  supportedChainIds: number[]
}

interface ProtocolAsset {
  symbol: AssetSymbol
  name: string
  decimals: number
  addresses: { [chainId: number]: Address } // Underlying token addresses
  mToken: Address // mToken address
  jumpRateModel: Address // Interest rate model for this mToken
  nonGlobalAsset?: boolean
  supportedChainIds?: number[]
}

interface Token {
  name: string
  symbol: AssetSymbol
  decimals: number
  address: Address // mToken address
  underlyingAddresses: { [chainId: number]: Address }
  supportedChainIds?: number[]
}
```

### Constants

- `PRODUCTION_CHAINS`, `TESTNET_CHAINS`, `ALL_CHAINS`: Wagmi chain objects for supported chains
- `ASSET_SYMBOLS`: All supported asset symbols

### Environment-Specific Constants

Use explicit imports for configuration and tokens:

```typescript
// Production
import { PRODUCTION_CONFIG, PRODUCTION_TOKENS } from '@malda-protocol/protocol-config/production'

// Testnet
import { TESTNET_CONFIG, TESTNET_TOKENS } from '@malda-protocol/protocol-config/testnet'
```

### ABIs

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
- `GAS_HELPER_ABI`: Malda gas helper contract
- `MIGRATOR_ABI`: Malda migrator contract
- `PRICE_ORACLE_ABI`: Malda price oracle contract
- `REFERRAL_SIGNING_ABI`: Malda referral signing contract
- `USDT_MAINNET_ABI`: USDT mainnet specific ABI
- `JUMP_RATE_MODEL_ABI`: Malda jump rate model contract (per-mToken)
- `getABI(name)`: Dynamic ABI loader for code splitting
- `ABIS`: Collection of all available ABIs with lazy loading

### Utility Functions

#### Chain Operations (Primary API - supports wagmi Chain objects)

- `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

#### Wagmi Chain Utilities

- `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

#### Legacy Chain ID Operations

- `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

## Supported Assets

| 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        |

## Supported Networks

### Production

- **Ethereum Mainnet** (1)
- **Arbitrum One** (42161)
- **Optimism** (10)
- **Base** (8453)
- **Linea** (59144) - Host Chain

### Testnet

- **Sepolia** (11155111)
- **Linea Sepolia** (59141) - Host Chain
- **Optimism Sepolia** (11155420)

## Development

```bash
# 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
```

## Contributing

1. All address and constant changes must be submitted via Pull Request
2. Changes require mandatory review (see CODEOWNERS)
3. Update version using `npm version patch|minor|major`
4. Follow semantic versioning

## Version Control

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

### Releasing

```bash
# Release a patch version
pnpm run release:patch

# Release a minor version
pnpm run release:minor

# Release a major version
pnpm run release:major
```

## License

MIT © Malda Protocol