DocumentationOpen App

Compressors

Compressor contracts aggregate on-chain data efficiently. Instead of dozens of individual reads, a single compressor call returns complete protocol state.

Discovering Compressor Addresses

Use AddressProvider to find compressor addresses:

Solidity Usage

Solidity
[address compressor] = addressProvider.getLatestAddressByContractType( AP_MARKET_COMPRESSOR, VERSION_RANGE_310 );

TypeScript Usage

TypeScript
import { AP_MARKET_COMPRESSOR, VERSION_RANGE_310 } from '@gearbox-protocol/sdk'; const [compressor] = sdk.addressProvider.mustGetLatest( AP_MARKET_COMPRESSOR, VERSION_RANGE_310 );

MarketCompressor

The primary data aggregation contract. Returns complete market state including pools, credit managers, and price oracles.

Interface

Solidity
interface IMarketCompressor { function getMarkets(MarketFilter memory filter) external view returns (MarketData[] memory); function getMarketData(address pool) external view returns (MarketData memory); function getPoolState(address pool) external view returns (PoolState memory); }

MarketFilter

Solidity
struct MarketFilter { address[] configurators; // Filter by Risk Curator addresses address[] pools; // Filter by specific pool addresses address underlying; // Filter by underlying token (e.g., USDC) }

Pass empty arrays and address(0) for no filtering.

Solidity Usage

Solidity
import {IMarketCompressor} from "@gearbox-protocol/periphery-v3/contracts/interfaces/IMarketCompressor.sol"; import {MarketData, MarketFilter} from "@gearbox-protocol/periphery-v3/contracts/types/MarketData.sol"; IMarketCompressor compressor = IMarketCompressor(MARKET_COMPRESSOR_ADDRESS); // Get single market MarketData memory data = compressor.getMarketData(poolAddress); // Get all USDC markets MarketFilter memory filter = MarketFilter({ underlying: USDC, configurators: new address[](0), pools: new address[](0) }); MarketData[] memory usdcMarkets = compressor.getMarkets(filter);

TypeScript Usage

TypeScript
import { marketCompressorAbi } from '@gearbox-protocol/sdk'; // Get all markets const markets = await client.readContract({ address: compressorAddress, abi: marketCompressorAbi, functionName: 'getMarkets', args: [{ configurators: [], pools: [], underlying: '0x0000000000000000000000000000000000000000' }], }); // Get specific pool data const marketData = await client.readContract({ address: compressorAddress, abi: marketCompressorAbi, functionName: 'getMarketData', args: [poolAddress], });

MarketData Structure

Solidity
struct MarketData { PoolState pool; // Pool state and rates QuotaKeeperState quotaKeeper; // Quota limits and rates CreditSuiteData[] creditManagers; // All CMs for this market PriceOracleState priceOracle; // Oracle configuration TokenData[] tokens; // Allowed collateral tokens }

Key fields in PoolState:

FieldTypeDescription
baseParams.addraddressPool contract address
availableLiquidityuint256Borrowable liquidity
dieselRateuint256Share price (RAY)
supplyRateuint256Lender APY (RAY)
baseInterestRateuint256Borrower APR (RAY)
totalAssetsuint256Total pool value

Key fields in CreditSuiteData:

FieldTypeDescription
creditManageraddressCredit Manager address
creditFacadeaddressCredit Facade address
creditConfiguratoraddressConfigurator address
debtLimitsDebtLimitsmin/max debt per account
collateralTokensCollateralToken[]Allowed tokens + LTs

CreditAccountCompressor

Reads complete Credit Account state. Deployed at 0x41152394 on every supported chain (see Deployment Addresses).

Get the state of a single Credit Account

If you have a Credit Account address, one call returns everything: getCreditAccountData(creditAccount). No SDK setup and no Credit Manager address needed; the compressor resolves the Credit Manager itself.

The quickest way to try it is the Read Contract tab on Etherscan: paste the account address into getCreditAccountData and query.

The same call from code, with no dependencies beyond viem:

TypeScript
import { createPublicClient, http, parseAbi } from 'viem'; import { mainnet } from 'viem/chains'; const ACCOUNT_COMPRESSOR = '0x4115708Fc8fe6bB392De2e0C21c2C81dA2222394'; const abi = parseAbi([ 'struct TokenInfo { address token; uint256 mask; uint256 balance; uint256 quota; bool success; }', 'struct CreditAccountData { address creditAccount; address creditManager; address creditFacade; address underlying; address owner; uint40 expirationDate; uint256 enabledTokensMask; uint256 debt; uint256 accruedInterest; uint256 accruedFees; uint256 totalDebtUSD; uint256 totalValueUSD; uint256 twvUSD; uint256 totalValue; uint256 healthFactor; bool success; TokenInfo[] tokens; }', 'function getCreditAccountData(address creditAccount) view returns (CreditAccountData)', ]); const client = createPublicClient({ chain: mainnet, transport: http() }); const account = await client.readContract({ address: ACCOUNT_COMPRESSOR, abi, functionName: 'getCreditAccountData', args: ['0x...'], // Credit Account address }); console.log(account.healthFactor, account.debt, account.tokens);

CreditAccountData Structure

Solidity
struct CreditAccountData { address creditAccount; address creditManager; address creditFacade; address underlying; address owner; uint40 expirationDate; uint256 enabledTokensMask; // Bitmask of enabled collateral tokens uint256 debt; // Principal, in underlying uint256 accruedInterest; // Accrued interest, in underlying uint256 accruedFees; // Accrued fees, in underlying uint256 totalDebtUSD; uint256 totalValueUSD; uint256 twvUSD; // Threshold-weighted value, USD uint256 totalValue; // In underlying uint256 healthFactor; // 10000 = 1.0; below 10000 is liquidatable bool success; // False if account state could not be computed TokenInfo[] tokens; } struct TokenInfo { address token; uint256 mask; uint256 balance; uint256 quota; bool success; }

Querying Multiple Accounts

For scanning accounts across Credit Managers (liquidation bots, monitoring), use getCreditAccounts with filters:

Solidity
interface ICreditAccountCompressor { function getCreditAccountData(address creditAccount) external view returns (CreditAccountData memory); function getCreditAccounts( address creditManager, CreditAccountFilter memory caFilter, uint256 offset ) external view returns (CreditAccountData[] memory data, uint256 nextOffset); function getCreditAccounts( CreditManagerFilter memory cmFilter, CreditAccountFilter memory caFilter, uint256 offset ) external view returns (CreditAccountData[] memory data, uint256 nextOffset); function countCreditAccounts( address creditManager, CreditAccountFilter memory caFilter ) external view returns (uint256); }

Both getCreditAccounts variants also have overloads with an extra trailing uint256 limit parameter that caps the number of accounts processed per call.

Filters

Solidity
struct CreditAccountFilter { address owner; // Filter by owner (address(0) = any) bool includeZeroDebt; // Include accounts with no debt uint256 minHealthFactor; // Minimum HF (0 = no min) uint256 maxHealthFactor; // Maximum HF (type(uint256).max = no max) bool reverting; // Only accounts whose state computation reverts } struct CreditManagerFilter { address[] configurators; // Filter by market configurators address[] creditManagers; // Filter by specific Credit Managers address[] pools; // Filter by pools address underlying; // Filter by underlying token (address(0) = any) }

TypeScript Usage

TypeScript
import { creditAccountCompressorAbi } from '@gearbox-protocol/sdk'; // Liquidatable accounts of one Credit Manager (HF < 1.0) const [data, nextOffset] = await client.readContract({ address: ACCOUNT_COMPRESSOR, abi: creditAccountCompressorAbi, functionName: 'getCreditAccounts', args: [ creditManagerAddress, { owner: '0x0000000000000000000000000000000000000000', includeZeroDebt: false, minHealthFactor: 0n, maxHealthFactor: 10000n, reverting: false, }, 0n, // offset ], });

Pagination

Querying functions process as many accounts as they can before approaching the gas limit. A non-zero nextOffset means the call stopped early; repeat the call starting from it:

TypeScript
let offset = 0n; const allAccounts = []; while (true) { const [data, nextOffset] = await client.readContract({ address: ACCOUNT_COMPRESSOR, abi: creditAccountCompressorAbi, functionName: 'getCreditAccounts', args: [creditManagerAddress, filter, offset], }); allAccounts.push(...data); if (nextOffset === 0n) break; offset = nextOffset; }

PriceFeedCompressor

Aggregates price feed state for oracle updates.

Interface

Solidity
interface IPriceFeedCompressor { function getUpdatablePriceFeeds(address priceOracle) external view returns (PriceFeedData[] memory); function loadPriceFeedTree(address priceOracle, address token) external view returns (PriceFeedTreeNode memory); }

TypeScript Usage

TypeScript
// Get all feeds that need updating const feeds = await client.readContract({ address: priceFeedCompressor, abi: priceFeedCompressorAbi, functionName: 'getUpdatablePriceFeeds', args: [priceOracleAddress], }); // Filter for stale feeds const staleFeeds = feeds.filter(f => f.needsUpdate);

When to Use Compressors vs SDK

ScenarioApproach
General market dataSDK marketRegister
Credit account queriesSDK services
One-off account lookupDirect compressor call
Custom filtering logicDirect compressor calls
Liquidation botsDirect compressor (one call, many accounts)
Real-time monitoringDirect compressor with specific filters

The SDK uses compressors internally. Use direct compressor calls when you need:

  • A quick single-account or single-market read without SDK setup
  • Custom filter combinations not exposed by SDK
  • Pagination control

Compressors are view contracts designed for off-chain eth_call reads. They are not gas-optimized, so avoid calling them from on-chain contracts.


Complete Example

TypeScript

TypeScript
import { createPublicClient, http } from 'viem'; import { mainnet } from 'viem/chains'; import { marketCompressorAbi, creditAccountCompressorAbi, } from '@gearbox-protocol/sdk'; const client = createPublicClient({ chain: mainnet, transport: http(), }); // Same on all chains, see /developers/deployments const MARKET_COMPRESSOR = '0x70F1753a765C4df582FFA3B8d96AB492714E8992'; const ACCOUNT_COMPRESSOR = '0x4115708Fc8fe6bB392De2e0C21c2C81dA2222394'; async function getMarketOverview() { const markets = await client.readContract({ address: MARKET_COMPRESSOR, abi: marketCompressorAbi, functionName: 'getMarkets', args: [{ configurators: [], pools: [], underlying: '0x0000000000000000000000000000000000000000' }], }); for (const market of markets) { console.log(`Pool: ${market.pool.baseParams.addr}`); console.log(` Available: ${market.pool.availableLiquidity}`); console.log(` Supply Rate: ${market.pool.supplyRate}`); } } async function findLiquidatableAccounts(creditManager: `0x${string}`) { const [accounts] = await client.readContract({ address: ACCOUNT_COMPRESSOR, abi: creditAccountCompressorAbi, functionName: 'getCreditAccounts', args: [ creditManager, { owner: '0x0000000000000000000000000000000000000000', includeZeroDebt: false, minHealthFactor: 0n, maxHealthFactor: 10000n, // HF < 1.0 reverting: false, }, 0n, ], }); return accounts; }

Solidity

Solidity
function getMarketData(address pool) external view returns (MarketData memory) { return IMarketCompressor(MARKET_COMPRESSOR).getMarketData(pool); } function findLiquidatableAccounts(address creditManager) external view returns (CreditAccountData[] memory) { CreditAccountFilter memory filter = CreditAccountFilter({ owner: address(0), includeZeroDebt: false, minHealthFactor: 0, maxHealthFactor: 10000, reverting: false }); (CreditAccountData[] memory accounts,) = ICreditAccountCompressor(ACCOUNT_COMPRESSOR).getCreditAccounts( creditManager, filter, 0 ); return accounts; }