# Gearbox Protocol documentation full export > Full text export for agents and retrieval systems. Use https://docs.gearbox.finance/llms.txt for compact routing before loading this file. Source hierarchy and freshness rules: - Static documentation describes protocol mechanics, integration patterns, and operational procedures. - Mutable market facts such as APY, utilization, market availability, supported assets, supported chains, rates, addresses, or live incidents must be verified through Gearbox app, Gearbox Data, governance, security, deployment, or owner-reviewed sources before answering. - Legal, tax, investment, eligibility, suitability, compliance, and privacy questions require Terms, Privacy, Risks, or owner-reviewed materials. Documentation alone is not legal, financial, tax, or investment advice. - URLs shown in each section are canonical docs routes for this exported content. # Protocol concepts Protocol architecture, audiences, core mechanics, economics, governance, and risk references. ## Gearbox Protocol Source: https://docs.gearbox.finance/core/gearbox-protocol File: content/core/gearbox-protocol.mdx Welcome to your team’s developer platform Meet Gearbox ### Permissionless Lending Rails for Onchain Credit At Gearbox, we are making the transition to operating lending businesses onchain frictionless. Purpose built for institutions, asset-issuers and fintechs, our enterprise grade lending stack enables lenders to deploy no-code credit markets instantly. | | | | | Cover image | |---|---|---|---|---| | :toolbox: | Create Permissionless Markets | Build onchain lending businesses on best-in-class infrastructure. | [gearbox-permissionless-for-curators](https://docs.gearbox.finance/core/gearbox-permissionless-for-curators) | [gearboxdocscurate.png](https://docs.gearbox.finance/assets/docs/core/gearbox-permissionless-for-curators/03-gearbox-docs-curate-page.png) | | :money-bill-transfer: | Lend or Borrow | Learn how to make the most of curated opportunities. | [User docs](https://docs.gearbox.finance/core/for-borrowers-farmers) | [gearboxdocsborrow.png](https://docs.gearbox.finance/assets/docs/core/gearbox-permissionless-for-curators/04-gearbox-docs-borrow-page.png) | | :gear-complex: | Understanding Gearbox | Learn about unlocking onchain credit and Gearbox Permissionless. | [About Gearbox](https://docs.gearbox.finance/core/gearbox-protocol) | [gearboxdocsmain.png](https://docs.gearbox.finance/assets/docs/core/gearbox-permissionless-for-curators/01-gearbox-docs-main-page.png) | ![Figure](https://docs.gearbox.finance/assets/docs/core/gearbox-permissionless-for-curators/05-gearbox-docs-use-cases-page.png) #### Learn more about Gearbox's unique usecases RWAs, Vaults, Prediction Markets, Onchain Assets, No-DEX lending. Learn about the opportunities Gearbox unlocks. **Helping Mellow x P2P lrt grow 2x** ## Powered by Credit Accounts Source: https://docs.gearbox.finance/core/powered-by-credit-accounts File: content/core/powered-by-credit-accounts.mdx > Credit Accounts are user-owned smart-contract wallets. Add collateral to unlock a credit line and use that account to trade, invest, or stake across integrated protocols while keeping ownership and portability. The protocol checks solvency on every move so risk stays controlled. ## Fragmented UX vs. Wallet-Native Credit **Pool-based lending** Traditional lending protocols silo users' funds in protocol-global pools, limiting capabilities to actively operate with collateral. ![Figure](https://docs.gearbox.finance/assets/docs/shared/legacy-lending.png) **Credit Accounts** By putting collateral, debt, and execution routes inside a single smart contract wallet, users keep ownership while moving through swaps, farming, or RWA flows without repacking positions. Solvency checks sit behind every action so convenience stays aligned with risk controls. ![Figure](https://docs.gearbox.finance/assets/docs/shared/credit-account-lending.png) ### What Credit Accounts enable * **Wider reach to users for apps and institutions:** Complex multi-transaction operations gate non-professional users. Credit accounts abstract execution allowing to focus on effective use of capital. * **Fees and time saving for investors:** Direct redemptions of semi-liquid tokens preserve months of yield, and batched transactions cut gas cost. * **Largest set of supported collaterals:** redemption receipts or Convex-staked positions become usable in a non-custodial, programmable account instead of being limited to prime broker clients. ## Gearbox Protocol – Monad LP Opportunity Source: https://docs.gearbox.finance/core/gearbox-protocol-monad-lp-opportunity File: content/core/gearbox-protocol-monad-lp-opportunity.mdx ### Overview Gearbox is a composable leverage protocol enabling undercollateralized on-chain borrowing through Credit Accounts. Current focus: yield strategies via Midas-issued collateral. **Two ways to participate:** | | Lending | Leverage | | ------- | -------------------------------------------- | ------------------------------------------- | | APY | 6-9% | Up to 20% | | Role | Passive liquidity provider | Active carry trade | | Risk | Indirect exposure, protected by liquidations | Direct collateral exposure | | Lock-up | None | None (subject to Midas redemption schedule) | *** ### Lending Side (Passive) **How it works:** Deposit USDC into the Gearbox pool. Earn yield from borrowers who use Credit Accounts to execute carry trades, borrowing at pool rates to deploy into higher-yielding RWA collateral. Gearbox solvency guardrails protect against borrower default. **Deposit here:** [Gearbox USDC Pool](https://app.gearbox.finance/pools/143/0x6b343f7b797f1488aa48c49d540690f2b2c89751) *** ### Leverage Side (Active) **How it works:** Open a Credit Account, borrow USDC, and deploy into Midas collaterals. Capture the full carry trade spread with leverage. **Yield source:** Direct exposure to mEDGE yield minus borrow cost. Net APY can reach 20% at max leverage (\~7x). **Zero slippage execution:** Gearbox direct integration allows entry/exit without DEX slippage. Redemptions execute at NAV. → [How Direct Redemptions Work](https://docs.gearbox.finance/core/usecase-direct-redemptions) **Open position here:** [mEDGE Leverage Strategy](https://app.gearbox.finance/strategies/open/143/0x1c8ee940b654bfced403f2a44c1603d5be0f50fa) *** ### Risk Framework #### Collateral Exposure: mEDGE Both sides have exposure to mEDGE (Midas EDGE vault). Current composition: → [View mEDGE Holdings](https://midas.app/medge) #### What happens if mEDGE depegs? | Scenario | Lending Side | Leverage Side | | ----------------- | ------------------------------------------------------- | --------------------------- | | Depeg <13% | Protected: liquidations trigger, borrowers absorb loss. | Position may be liquidated. | | Orderly wind-down | Redemptions via direct integration at NAV | Exit at NAV, no slippage | #### Gearbox Solvency Guardrails * **LTV limits:** Credit Accounts enforce max leverage * **Liquidation threshold:** Positions liquidated before insolvency * **Price feeds:** Oracle-based with sanity checks * **Audits:** [Security repo](https://github.com/Gearbox-protocol/security/tree/main/audits) *** ### Summary | | Lending | Leverage | | --------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | Target LP | Passive yield seekers | Active DeFi users | | APY | 6-9% | Up to 20% | | Risk | Lower (liquidation buffer) | Higher (direct exposure) | | Effort | Deposit & forget | Manage position | | Deposit | [Pool](https://app.gearbox.finance/pools/143/0x6b343f7b797f1488aa48c49d540690f2b2c89751) | [Strategy](https://app.gearbox.finance/strategies/open/143/0x1c8ee940b654bfced403f2a44c1603d5be0f50fa) | *** ## Gearbox LP Demo Day – Blurb **Project:** Gearbox Protocol **Project Description:** Composable leverage protocol with Credit Accounts enabling undercollateralized on-chain borrowing. Two LP opportunities on RWA yield strategies: * **Lending side:** Passive yield from borrower demand (6-9% APY) * **Leverage side:** Active carry trade via Credit Accounts (up to 20% APY) **Max TVL capacity:** 50M USDC in mid-term (nearest month) until considerable yield dilution.\ Further expansion driven by new collaterals addition. **Yield APY:** 6-9% (lending) / up to 20% (leverage) **Source of yield:** Carry trade between Gearbox borrow rates and Midas RWA collateral (mEDGE). Lenders earn borrow interest + MON incentives; leverage users capture full carry. **Duration of deal:** No lock-up **Audit link:** **Your contact:** Telegram - @OxIlya ## Unlocking credit for RWAs Source: https://docs.gearbox.finance/core/unlocking-credit-for-rwas File: content/core/unlocking-credit-for-rwas.mdx Purpose-built for RWAs, Gearbox’s lending infrastructure combines capital efficiency, compliance-aware execution, and institutional-grade leverage in a way no existing onchain lending protocol can. Most lending protocols treat RWAs like any other ERC-20 token. While this enables basic compatibility, it prevents enforcement of issuer-defined rules such as redemption, settlement, withdrawals, and deposits, leaving RWA credit structurally limited. Gearbox is built differently. Credit is extended at the RWA protocol level, not just the token level. Credit Accounts interact directly with issuer contracts, allowing purpose-specific rules to be enforced by design. This enables compliant, programmable leverage optimized for RWAs, without compromising issuer controls or asset mechanics. ## No DEX dependency Gearbox is built to work with RWA-specific on-chain logic. Credit Accounts interact directly with issuer contracts, ensuring leverage respects the asset’s native lifecycle by design. This direct integration allows credit users to mint and redeem RWAs with borrowed capital, bypassing secondary markets like DEXes altogether. **As a result:** * **Issuers save millions of dollars** for bootstrapping and subsidizing DEX liquidity * **Users save months of yield** by always redeeming at face value instead of selling at discount ## Launch faster, focus on distribution Traditional looping methods don’t suit RWA leverage. They fragment UX with multi-step, multi-protocol transactions and become highly capital-inefficient when redemption periods are long. Most lending protocols require 5+ transactions across the lending platform and the asset issuer to take a leverage on RWA token, effectively limiting access to advanced on-chain users only. #### Gearbox's Benefits: * **Zero DEX Liquidity Required:** With Gearbox, leverage can go live on day one. It eliminates the need for DEX liquidity seeding, working at any size. * **Improved distribution:** User can enter leveraged position in one transaction. * **Capital savings worth months of yield:** * Save time up to **8 periods** of native redemption. * Capital requirements are reduced by **10x**. * Save fees equal to a **month of farming yield**. * **Risk Control:** Automated deleverage reduces liquidation risk, capital stays in user-owned segregated wallet minimizing indirect exposure. ## Compliant interaction by Design It is almost impossible to enforce transfer-agent/compliance obligations on-chain in traditional pools-based lendings. Gearbox is designed for compliant access. * **Position Isolation:** Each user's position is fully isolated, preventing the mixing of assets or risk between accounts. * **Access Control:** Supports KYC- and rules-based access control, including per-account whitelists, jurisdiction filters, and configurable limits. * **On-Chain Enforcement:** Built-in position freezing and granular operation controls (what can be traded, where, and when) allows curator to enforce regulatory obligations on-chain. ***If you're building onchain RWA product, reach out to Gearbox to power it with Distribution-focused UX and capital-efficient execution.*** ## Learn in details | | | | Cover image | |---|---|---|---| | Improve UX and Capital EfficiencyUserbase growth without depending on liquidity | | [Usecase: Direct Redemptions](https://docs.gearbox.finance/core/usecase-direct-redemptions) | [gearboxdocsmain.png](https://docs.gearbox.finance/assets/docs/core/gearbox-permissionless-for-curators/01-gearbox-docs-main-page.png) | ## Credit for Prediction Markets Source: https://docs.gearbox.finance/core/credit-for-prediction-markets File: content/core/credit-for-prediction-markets.mdx Prediction-market shares remain an untapped opportunity for credit due to their unique mechanics, collateral behavior, and the need for optimized risk frameworks. Gearbox is built to support such novel use cases by design: Credit Accounts enable modular configuration of execution rules, while Lending Market parameters can be flexibly adjusted to meet evolving market needs. ## Modular execution rules Gearbox’s modular architecture unifies credit and execution, allowing custom logic to run directly within leveraged positions. The core money-market layer provides additional capital while ensuring positions remain fully collateralized, and specialized modules extend this base with any purpose-specific execution rules. ![Figure](https://docs.gearbox.finance/assets/docs/core/credit-for-prediction-markets/01-modular-execution-rules.png) ## Flexible Risk Controls Prediction-market outcome shares require additional risk oversight due to their unique behavior, such as sharp price movements near resolution. Gearbox’s risk framework is built to operate under uncertainty and adapt to market conditions that may not have been seen before. #### **Key challenges with prediction-market dynamics:** **Shallow liquidity:** Vulnerable to short-term price manipulation and arbitrage, though prices tend to stabilize over the medium term. **High volatility near resolution:** Makes pricing and liquidations significantly more difficult. #### **Gearbox provides a robust set of tools to address these challenges:** **Dual-oracle system** * Protects against short-term manipulation by cross-checking with an alternative source (e.g., a longer TWAP). * The primary oracle handles solvency checks and triggers liquidations. * The secondary oracle detects divergence and blocks sensitive operations when prices disagree. **LT ramping** * Gradually reduce exposure as markets approach maturity. * Adjustable slope and duration ensure borrowers deleverage in time, protecting LPs. **Loss policy** * Adds protective logic for liquidations that could create bad debt. * Prevents liquidation cascades and defends LPs against manipulation-driven loss scenarios. **If you’re building credit for prediction markets, reach out to Gearbox for the infrastructure so you can focus on product.** ## Manual Deleveraging When UI Actions Are Unavailable Source: https://docs.gearbox.finance/core/manual-deleveraging-when-ui-actions-are-unavailable File: content/core/manual-deleveraging-when-ui-actions-are-unavailable.mdx If the **Close** or **Swap** action is unavailable or fails, you can exit your position manually by following the steps below. ## Withdraw collateral Withdrawing collateral sends the token to your wallet, where you can swap it freely using external liquidity sources outside of Gearbox. > Withdrawing collateral reduces your position’s **Health Factor**. A large withdrawal may push the position into liquidation risk. \ \ Always check the projected **Health Factor** before each withdrawal.
Withdraw collateral in the UI ![Figure](https://docs.gearbox.finance/assets/docs/core/manual-deleveraging-when-ui-actions-are-unavailable/01-withdraw-collateral.png)
> If your current **Health Factor** does not allow for a safe withdrawal, repay part of your debt first using the Debt Token from your wallet (see **Step 3**). ## Swap collateral into the Debt Token Swap the withdrawn collateral into the Debt Token using external liquidity sources. Recommended options include: * DEX aggregators * Official liquidity venues provided by the collateral issuer ## Repay debt using Debt Token from your wallet > Repay the debt using the **same token the debt is denominated in**, directly from your wallet. > Check whether the updated **Health Factor** allows for further withdrawal.
Repay debt in the UI ![Figure](https://docs.gearbox.finance/assets/docs/core/manual-deleveraging-when-ui-actions-are-unavailable/02-repay-debt-using-debt-token-from-your-wallet.png)
## Repeat Steps 1-3 until your Credit Account reaches the desired state or is fully unwound ## Guide for Asset Issuers Source: https://docs.gearbox.finance/core/guide-for-asset-issuers File: content/core/guide-for-asset-issuers.mdx Most lending protocols treat complex DeFi asset like any other ERC-20 token. While this enables basic compatibility, it prevents enforcement of issuer-defined rules such as redemption, settlement, withdrawals, and deposits. Gearbox is built differently. Credit is extended at the asset's protocol level, not just the token level. Credit Accounts interact directly with issuer contracts, allowing purpose-specific rules to be enforced by design. ## No DEX dependency Gearbox is built to work with asset-specific on-chain logic. Credit Accounts interact directly with issuer contracts, ensuring leverage respects the asset’s native lifecycle by design. This direct integration allows credit users to mint and redeem assets with borrowed capital, bypassing secondary markets like DEXes altogether. This is especially important for assets with longer redemption periods, as DEX liquidity is costly and ineffective there. **As a result:** * **Issuers save millions of dollars** for bootstrapping and subsidizing DEX liquidity * **Users save months of yield** by always redeeming at face value instead of selling at discount ## Launch faster, focus on distribution Traditional looping methods don’t suit leverage for novel assets. They fragment UX with multi-step, multi-protocol transactions and become highly capital-inefficient when redemption periods are long. Most lending protocols require 5+ transactions across the lending platform and the asset issuer to take a leverage on asset, effectively limiting access to advanced on-chain users only. #### Gearbox's Benefits: * **Zero DEX Liquidity Required:** With Gearbox, leverage can go live on day one. It eliminates the need for DEX liquidity seeding, working at any size. * **Improved distribution:** User can enter leveraged position in one transaction. * **Capital savings worth months of yield:** * Save time up to **8 periods** of native redemption. * Capital requirements are reduced by **10x**. * Save fees equal to a **month of farming yield**. * **Risk Control:** Automated deleverage reduces liquidation risk, capital stays in user-owned segregated wallet minimizing indirect exposure. ## Widest collateral support & direct DeFi integration Credit Accounts accept nearly any on-chain position as collateral: LP tokens, staked assets, vault shares, and non-tokenized positions such as redemption receipts. This expands TVL, deepens liquidity, and unlocks leveraged versions of your asset’s native strategies. ***If you want to grow your DeFi product, whether it’s an LRT, vault, or any other productive collateral, reach out to Gearbox to power it with Distribution-focused UX and capital-efficient execution.*** ## Case studies | | | Cover image | |---|---|---| | P2P vault growthHow P2P's mellow LRT has grown from 25k to 45k restaked wstETH | [case-study-mellow-x-p2p-lrt-growth-powered-by-gearbox](https://docs.gearbox.finance/core/case-study-mellow-x-p2p-lrt-growth-powered-by-gearbox) | [gearboxdocsmain.png](https://docs.gearbox.finance/assets/docs/core/gearbox-permissionless-for-curators/01-gearbox-docs-main-page.png) | ## Learn in details | | Cover image | | |---|---|---| | Direct redemptionsUsers save months of yield; Asset issuers - millions on DEX incentives | [gearboxdocscurate.png](https://docs.gearbox.finance/assets/docs/core/gearbox-permissionless-for-curators/03-gearbox-docs-curate-page.png) | [Usecase: Direct Redemptions](https://docs.gearbox.finance/core/usecase-direct-redemptions) | | User-first executionIntegrate leverage into product offering as if it were there by design | [gearboxdocsborrow.png](https://docs.gearbox.finance/assets/docs/core/gearbox-permissionless-for-curators/04-gearbox-docs-borrow-page.png) | [Adapters & Integrations](https://docs.gearbox.finance/core/adapters-integrations) | ## Seamless LP migration Source: https://docs.gearbox.finance/core/seamless-lp-migration File: content/core/seamless-lp-migration.mdx ### Why migrate (what you gain as an LP) **In short:** better incentives and better market coverage. > As Gearbox transitions to the permissionless curation model, rewards and activity shift to the new pools. Old pools will stop receiving rewards and become non-competitive over time. New pools are where curators focus liquidity and opportunities. New Curator pools combine two reward streams: * baseline, time-weighted TVL incentives to bootstrap passive liquidity * performance-based rewards proportional to the Curator’s revenue share. In practice, the aggregate rewards allocated to the permissionless model are about 3x the legacy LM run-rate, with dilution tied more closely to real usage and protocol revenue (supporting buybacks). As a result, effective yield in new pools is expected to be higher than in legacy pools. *** ### Purpose This LP migration contract is designed to allow users migrate liquidity without monitoring the pools for available liquidity: * Designed for the case where immediate migration is not possible due to liquidity constraints. * Users can pre-sign their intention to migrate by granting allowance to the migration contract. * The migration will be executed by the instance owner multisig as soon as liquidity becomes available. In other words, this contract is a safe automation tool: * You lock in your intent to move from the old pool to the new one. * You don’t have to monitor liquidity or time the transaction yourself. * The migration will happen at the first opportunity. *** #### How it Works There are only two functions in the migration contract: 1. User function (allowance setup) * You give the migration contract allowance for your LP tokens in the old pool. * This does not move funds immediately — it only means: > “Whenever possible, please take my LP tokens from the old pool and put them into the new pool.” * After signing, you are done. 2. Instance owner function (execute migration) * Can only be called by the instance owner multisig (chain-specific). However, instance owner can't do anything except for migrating liquidity between the pools specified by user. * Once liquidity becomes available, they trigger the migration: * LP tokens are redeemed from the old pool. * Assets are deposited into the new pool on behalf of the user. * Both *old pool* and *new pool* are fixed parameters of the contract and cannot be changed. *** #### Safety of Allowance * **Immutable destination:** your funds can only move old pool → new pool. * **No arbitrary spending:** allowance is strictly limited to the old pool LP tokens. * **Controlled execution:** the migration logic is minimalistic and fixed in contract. Even if instance owner multisig goes malicious, its actions can't result in user losing money. *** #### Migration Lifecycle 1. User grants allowance * Approves their LP tokens to be used by migration contract. 2. Monitoring phase * Liquidity in old pools may be fully utilized (100%). * Gearbox contributors monitor until withdrawals are possible. 3. Execution phase * Instance owner calls the migration function at the first chance. * Funds are moved automatically on behalf of the user who granted the allowance. 4. Completion * Users now hold LP tokens in the new pool. * Yield continues seamlessly. *** ### Why now (governance & versions) Gearbox is moving from V3.0 to V3.1 to solidify the permissionless governance direction. Under permissionless curation, DAO-approved curators can configure markets and parameters, and the protocol can scale across networks without slow, centralized bottlenecks. **This migration is happening because:** * Maintaining two versions is technically **complex and fragments liquidity.**\ Supporting both legacy pools and new permissionless pools in parallel would complicate operations and potentially reduce yields for everyone. Consolidating liquidity in the new system is safer and more efficient. * Legacy pools had the **DAO as the sole curator - this is changing.**\ In the permissionless model, curators manage markets directly within clear, on-chain constraints. So legacy pools either need to be turned off or migrated to preserve TVL in the ecosystem. * It’s **better for LPs.**\ Rewards and curator attention move to the new pools. Old pools will become non-competitive over time. Specialized curators are expected to maintain attractive rates more consistently than DAO-only governance, because they operate faster and stay deeper in the market. *** #### Batching and timelines To reduce multisig overhead and make the best use of liquidity windows, we process migrations in batches. * **Positions up to $1,000,000.**\ Migrated in full within the nearest suitable batch. * **Positions above $1,000,000.**\ Moved in several chunks. This is normal and helps keep utilization healthy while your position transitions. * **Target batch size.**\ We aim to group requests into roughly $1,000,000 batches to execute efficiently when liquidity allows. * **FIFO queueing.**\ LP requests are processed in chronological order. This keeps the process transparent and predictable. * **Timing.**\ Your migration may wait while a batch fills. The maximum wait time will not exceed 14 days. #### FAQ * **Can the migration contract move my funds anywhere else?**\ No. It can only move LP from the specific old pool to the specific new pool you selected. * **Why would APY be higher in the new pools?**\ New pools stack baseline TVL incentives with performance-based rewards linked to real fee generation. The overall incentive budget for the permissionless phase is roughly 3x legacy LM, with dilution aligned to revenue (supports buybacks), so effective yields are expected to be superior versus legacy pools. * **What if utilization in the old pool is 100% for a while?**\ We keep your request in the FIFO queue and execute at the first safe window. Batching helps reduce delays. * **Do I keep earning yield?**\ Yes. After migration you hold LP in the new pool and continue earning according to its parameters and incentives. ## Credit Account migration Source: https://docs.gearbox.finance/core/credit-account-migration File: content/core/credit-account-migration.mdx ### Why migrate (what you gain as a Borrower) **In short:** incentives, better execution and more favorable rates. **Incentives:** * One-time fixed reward paid in GEAR. Distributed retroactively. **Better execution:** * Improved routing and support for new adapters increases capital efficiency and reduces costs. **Favorable rates:** * Vote-based collateral-specific rate discovery is depreciated in favor of curator-controlled rates. ### Requirements for allowing a migration into your Market 1. All the collaterals of old account should be allowed in a credit manager of target Market 2. The position can be only migrated as a whole, target Market should have appropriate debt limits and capacity. 3. If the underlying token is changed during migration, new market must support swaps from new underlying to old one.\ E.g. you can migrate rstETH from an old wstETH pool to a new WETH pool, but WETH -> wstETH swap must be allowed in the new pool. ### How it works 1. New credit account is opened in a target market 2. Amount of tokens enough to repay old account is borrowed from a new account 3. Newly-borrowed tokens are swapped into underlying tokens of old account 4. Old account's debt is repaid and its collateral is transferred to the new account ## Gearbox Permissionless for Curators Source: https://docs.gearbox.finance/core/gearbox-permissionless-for-curators File: content/core/gearbox-permissionless-for-curators.mdx Gearbox Permissionless provides the operational rails for institutions, asset managers, and fintechs to deploy onchain credit markets. **Curator**, acts as the operator of a standalone lending vertical. This role is designed for entities seeking to retain full ownership of their market's risk parameters and economic model, while leveraging Gearbox’s battle-tested settlement engine to handle execution, solvency, and compliance. This page outlines the operational model and strategic advantages of the Gearbox curation stack. ## Market Curation, Not Fund Management In many onchain lending models, curation requires active capital reallocation, manually moving funds between vaults to chase yield. This creates significant operational burden and can inadvertently classify operators as financial intermediaries or asset managers. **The Gearbox Approach:**\ Curators manage **Parameters**, not **Funds**. * **Non-Custodial:** Curator defines the rules (LTVs, Interest Rate Models), but never possesses or controls user funds. * **Automated Execution:** The protocol automatically allows credit usage within allowed limits and enforces solvency based on pre-defined logic. * **Compliance Benefit:** This passive model allows you to operate a lending business without engaging in active fund management activities. ## Structured Credit Products Standard lending markets are commoditized, offering simple borrowing against collateral. Gearbox enables Curators to structure complex **Credit Products**. * **Strategy Integration:** Deploy markets that offer native access to specific yield strategies (e.g., Leveraged Staking, Basis Trading, or RWA accumulation). * **Capital Efficiency:** By integrating execution directly into the credit account, Curators can offer higher leverage ratios with tighter risk controls than standard over-collateralized lending. ## Institutional-Grade Risk Framework For asset issuers and fund managers, security is the primary constraint. Gearbox provides a multi-layered safety stack designed for high-value deployments. * **Dual-Oracle Architecture:** Markets utilize a primary and secondary oracle source to prevent price manipulation and ensure accurate mark-to-market valuations. * **Automated Insolvency Resolution:** The "Loss Policy" mechanism provides pre-defined logic for handling bad debt events, protecting Liquidity Providers from black swan scenarios. * **Granular Access Control:** Curators can deploy permissioned instances, utilizing allowlists for borrowers or lenders to meet KYC/AML requirements. ***If you’re expanding your product offering, reach out to Gearbox to power your lending vertical with superior UX and a safety-first design.*** ![Figure](https://docs.gearbox.finance/assets/docs/core/gearbox-permissionless-for-curators/01-gearbox-docs-main-page.png) #### Get started Create a market and make first steps towards launching a lending product. **Become a Market Curator** ## Learn in details | | Cover image | | |---|---|---| | Collateral-specific ratesNon-custodial by design. Capital-efficient by default | [gearboxdocsmain.png](https://docs.gearbox.finance/assets/docs/core/gearbox-permissionless-for-curators/01-gearbox-docs-main-page.png) | [Collateral Limits & Specific Rates](https://docs.gearbox.finance/core/collateral-limits-specific-rates) | | Dual-oracle system & bad debt preventionA safety-first mechanisms for LP protection | [gearboxdocscurate.png](https://docs.gearbox.finance/assets/docs/core/gearbox-permissionless-for-curators/03-gearbox-docs-curate-page.png) | [Smart Oracles](https://docs.gearbox.finance/core/smart-oracles) | | Multichain ScalingGrow across ecosystems with ready-to-use infrastructure | [gearboxdocsborrow.png](https://docs.gearbox.finance/assets/docs/core/gearbox-permissionless-for-curators/04-gearbox-docs-borrow-page.png) | [Omni-EVM Architecture](https://docs.gearbox.finance/core/omni-evm-architecture) | | Native integrations for superior UXOffer users best-in-class capital-efficiency | [gearboxdocuses.png](https://docs.gearbox.finance/assets/docs/core/gearbox-permissionless-for-curators/05-gearbox-docs-use-cases-page.png) | [Adapters & Integrations](https://docs.gearbox.finance/core/adapters-integrations) | ## Quota increase fee Source: https://docs.gearbox.finance/core/quota-increase-fee File: content/core/quota-increase-fee.mdx When user increases Quota (Credit Account specific max amount of debt that can be backed by particular collateral), charge a fixed % fee on the quota difference: works like a one-time fee charged on swaps by exchanges. Added to account's Debt. Distributed as a DAO & Curator fee on repayment according to the fee split rules. ## Wallet-native Credit powered by Credit Accounts Abstraction Source: https://docs.gearbox.finance/core/wallet-native-credit-powered-by-credit-accounts-abstraction File: content/core/wallet-native-credit-powered-by-credit-accounts-abstraction.mdx > One Click, Infinite Utility: No more bridging to external dApps. No more locking assets in inaccessible vaults. Your wallet is the protocol. ## Transforming Wallets into Crypto Neobanks Imagine a bank account where you can only store money, not borrow or use credit. That’s what most crypto wallets look like today. Gearbox changes the landscape of decentralized finance by embedding a credit layer directly into wallets, turning them into “Crypto Neobanks”. Users gain access to credit lines against their existing collateral. Gearbox serves as the invisible “credit rails,” while the Wallet Provider acts as the user-facing financial app. ### Native Credit Integration via Account Abstraction The user doesn't see complex smart contract interactions. They simply toggle "Credit Mode" or switch to their "Credit Account" tab, just like switching between a Credit and Savings account ### Seamless DeFi compatibility Unlike traditional lending protocols that lock your assets away, the system recognizes tokens in the wallet as collateral automatically. Users don't just "borrow" funds; they use them. The credit line works across major DeFi protocols (Uniswap, Curve, Pendle). ### Two Modes, One Wallet **For the Spender (The "Crypto Credit Card"):** Integrate with Gnosis Pay/Holyheld or other crypto cards. Users can pay for groceries and daily needs using a stablecoin credit line. **For the Investor (The "DeFi Powerhouse"):** Execute complex strategies (e.g., "Invest into fixed-yield PT token with 5x leverage") directly from the wallet UI. No need for external operational overhead. ## Proof of concept **(Coinbase Wallet Example)** The integration requires no clunky approvals for every action. The wallet recognizes the Credit Account as a native environment, enabling a smooth, "Web2-like" financial experience. []() ***If you’re building wallet-native credit, reach out to Gearbox to power it with seamless execution and a superior UX.*** ## Learn in details | | Cover image | |---|---| | How it works | [gearboxdocsmain.png](https://docs.gearbox.finance/assets/docs/core/gearbox-permissionless-for-curators/01-gearbox-docs-main-page.png) | | | | ## Audits and Bug Bounty Source: https://docs.gearbox.finance/core/audits-and-bug-bounty File: content/core/audits-and-bug-bounty.mdx ## Case Study: Mellow x P2P LRT growth powered by Gearbox Source: https://docs.gearbox.finance/core/case-study-mellow-x-p2p-lrt-growth-powered-by-gearbox File: content/core/case-study-mellow-x-p2p-lrt-growth-powered-by-gearbox.mdx ## Summary The synergy between Gearbox’s distribution-focused UX and its tailored rewards structure enabled the creation of a balanced two-sided market, allowing depositors to boost their wstETH staking yield, while leverage users executed strategies that combined points rewards with realized, liquid returns. *These combined efforts helped the rstETH vault grow from 21k to 45k restaked wstETH.* ## Involved parties [**P2P.org**](https://p2p.org) is the leading institutional-grade staking provider providing a wide line of products for Asset Manager, Wallets, Banks and more. [**Mellow.finance**](https://mellow.finance) is a liquid vaults stack that enables permissionless creation of variety of products, including actively managed tokenized funds, LRTs, distributed validator vaults and more. [**Gearbox.finance**](https://gearbox.finance/) acting as a lending stack powering Deposit Pool for earning boosted wstETH yield and Leverage Strategy allowing to take leveraged exposure on Restaking rewards. ## Key features ### Gearbox's distribution-focused UX An intuitive UI and single-transaction execution let users open leveraged positions without slippage, with routing handled directly through the Mellow vault minting smart contract. Mellow, P2P clients, and broader DeFi participants including funds and individual farmers can access leveraged yield strategies through a simple, secure experience that preserves both security and capital efficiency.
![Image](https://docs.gearbox.finance/assets/docs/core/case-study-mellow-x-p2p-lrt-growth-powered-by-gearbox/01-intuitive-leverage-ui.png)
Intuitive leverage UI
### P2P & Mellow's structured product offering Rather than relying on unsustainable incentives or short-lived points valuations, P2P and Mellow adopted a balanced model that blends Symbiotic and Mellow points exposure with liquid incentives creating an attractive yield profile without sacrificing direct economic benefits. * **Leverage users earned points with a discounted multiplier**\ Instead of receiving 10× points for 10× leverage, users earned 40% of the total points, while the remaining 60% went to addresses supplied by P2P. * **Discounted points were offset with liquid wstETH rewards**\ Each leveraged rstETH position earned a fixed incentive APR paid in liquid tokens, balancing long-term reward exposure with realized profit. All key Gearbox usage metrics are fully transparent on-chain, enabling flexible, data-driven incentive campaigns tailored to real user needs. ## Outcome The campaign brought more than 24k new wstETH deposits into the rstETH vault, demonstrating the effectiveness of Gearbox’s powerful UX and the flexibility of its product engineering. ![Figure](https://docs.gearbox.finance/assets/docs/core/case-study-mellow-x-p2p-lrt-growth-powered-by-gearbox/02-p2p-lrt-growth-tvl.png) P2P LRT growth. TVL contribution is split between Mellow deposits and Gearbox-induced TVL Source query ***If you want to grow your DeFi product, whether it’s an LRT, vault, or any other productive collateral, reach out to Gearbox to power it with Distribution-focused UX and capital-efficient execution.*** ## About Gearbox Source: https://docs.gearbox.finance/core/about-gearbox File: content/core/about-gearbox.mdx Gearbox is onchain credit infrastructure for building lending and leverage products. It connects passive capital in pools with borrowers who use Credit Accounts to take positions across approved partner protocols. The core primitive is simple: a **Credit Account is a wallet with credit**. It can hold collateral, borrow from a pool, and execute approved actions, while every action must keep the account solvent under protocol rules. Gearbox started in 2021 as a protocol for DeFi investing with leverage. It then evolved through V2, V3, and V3.1 from a strategy-focused leverage product into infrastructure for purpose-built credit markets, RWA-backed debt positions, and wallet-native lending products. The current architecture combines two goals: - **Wallet-like UX:** users or products operate through an account that can hold assets, debt, and execution routes in one place. - **Lending-protocol efficiency:** capital is supplied by pools, priced through protocol parameters, and protected by solvency checks, liquidation rules, and debt ceilings. ## Two sides of the system ### Pool side: passive capital A pool is the savings product in Gearbox. Lenders deposit an asset into a pool and earn yield from interest paid by borrowers using that liquidity. The pool does not make strategy decisions for each borrower. It allows borrowing by Credit Accounts under explicit debt ceilings. This keeps passive capital aggregated while limiting how much exposure any one market or strategy can take from the pool. A pool is not a bank deposit or guaranteed yield product. It is an onchain lending position with protocol, market, liquidity, and liquidation risk. ### Credit Account side: wallet with credit A Credit Account is a user-controlled smart-contract account that combines collateral, debt, and approved execution routes. Borrowers do not receive unrestricted funds. They operate inside a Credit Account. The account can interact with approved partner protocols, but each action is checked against collateral values, Liquidation Thresholds, allowed assets, and market-specific rules. This lets a product expose a wallet-like experience while the protocol enforces credit boundaries in the background. ## How capital moves 1. Lenders deposit assets into a pool. 2. The pool allows borrowing by Credit Accounts within configured debt ceilings. 3. Borrowers open or use Credit Accounts. 4. Credit Accounts deploy borrowed liquidity into approved strategies or products. 5. Borrowers pay interest back to the pool. 6. Solvency checks and liquidation rules protect the pool when a Credit Account becomes unsafe. ## What this enables For lenders, Gearbox turns a pool into a passive lending product. The lender does not need to choose every borrower or strategy manually, while risk remains bounded by market configuration. For borrowers, Gearbox turns leverage into an account-level credit line. The borrower can use capital inside a Credit Account without repeatedly moving assets through separate lending, trading, and strategy interfaces. For curators and builders, Gearbox provides the infrastructure to create specialized credit products. A market can define supported assets, debt ceilings, rates, oracle rules, and liquidation parameters for a specific use case. ## Where to go next - [One Pool, Many Markets](https://docs.gearbox.finance/core/one-pool-many-markets): how one passive liquidity source can fund multiple isolated markets. - [Credit Accounts (The Primitive)](https://docs.gearbox.finance/core/credit-accounts-the-primitive): the account model that makes wallet-native credit possible. - [Pool (The Liquidity Vault)](https://docs.gearbox.finance/core/pool-the-liquidity-vault): how passive lending capital is deposited, represented, and used. - [Gearbox Permissionless for Curators](https://docs.gearbox.finance/core/gearbox-permissionless-for-curators): how curators create and operate markets. ## One Pool, Many Markets Source: https://docs.gearbox.finance/core/one-pool-many-markets File: content/core/one-pool-many-markets.mdx Gearbox Protocol separates the source of liquidity from the utilization of liquidity. This architecture allows a single passive liquidity source to fund diverse, isolated lending strategies simultaneously. ![Figure](https://docs.gearbox.finance/assets/docs/core/one-pool-many-markets/01-one-pool-many-markets.png) ### The Wholesale Bank Model To understand the flow of capital, view the architecture through the analogy of a banking system: #### 1. The Pool (The Wholesale Bank) The Liquidity Pool acts as a **Wholesale Bank**. It is a massive, passive reservoir of capital (e.g., USDC, WETH, or DAI). * **Role:** It accepts deposits from lenders and holds the funds securely. * **Mandate:** It does not lend directly to end-users. Instead, it lends capital to "Retail Branches" (Credit Suites) based on strict credit limits. #### 2. Credit Suites (The Retail Branches) Credit Suites (technically "Credit Managers") act as **Retail Branches**. Each branch is a specialized lending product with a specific mandate. * **Role:** They borrow liquidity from the Wholesale Bank (Pool) to fund Credit Accounts for users. * **Mandate:** Each suite defines a specific strategy, such as "Low-Risk Stablecoin Farming" or "High-Leverage ETH Staking." ![Figure](https://docs.gearbox.finance/assets/docs/core/one-pool-many-markets/02-2-credit-suites-the-retail-branches.png) This separation allows the protocol to offer low-risk and high-risk products side-by-side without fragmenting liquidity. ### Risk Isolation (Debt Ceilings) In a monolithic lending protocol, bad debt in one asset can drain the entire pool. Gearbox prevents this via **Risk Isolation**. The Pool assigns a **Debt Ceiling** to each Credit Suite. This is the maximum amount of capital that specific branch can borrow from the bank. * **Scenario:** A Pool holds $100M USDC. * **Allocation:** * $80M is allocated to a "Blue Chip Strategy" (Low Risk). * $10M is allocated to an "Emerging Asset Strategy" (High Risk). * **Isolation:** If the "Emerging Asset Strategy" suffers a catastrophic failure, the maximum loss to the Pool is capped at $10M. The remaining $90M is mathematically isolated from that specific risk vector. This ensures that lenders are protected from the tail risks of specific aggressive strategies, while still benefiting from the higher utilization they generate. ### The Diesel Token (Unified Yield) Lenders interact only with the Pool. When they deposit assets, they receive **Diesel Tokens** (e.g., dUSDC, dWETH). * **Unified Exposure:** The Diesel Token represents a pro-rata share of the entire Wholesale Bank's assets. * **Aggregated Yield:** The yield is generated by the interest paid by *all* connected Credit Suites. Whether the capital is used for staking, farming, or trading, the interest flows back to the Pool and appreciates the value of the Diesel Token. This abstracts the complexity of multiple markets away from the lender. The lender provides liquidity once and earns a blended yield from a diversified basket of on-chain credit strategies. ### Learn More * **Technical Implementation:** How the passive vault handles deposits and withdrawals. * [pool](https://docs.gearbox.finance/core/pool-the-liquidity-vault) * **Market Configuration:** How specific rules and strategies are defined for each branch. * [credit-suite](https://docs.gearbox.finance/developers/credit-suite) ## Credit Accounts (The Primitive) Source: https://docs.gearbox.finance/core/credit-accounts-the-primitive File: content/core/credit-accounts-the-primitive.mdx The Credit Account is the fundamental primitive of the Gearbox Protocol. It functions as a user-owned, isolated smart contract wallet that holds both collateral and borrowed funds, enabling leveraged execution across DeFi protocols. ### Core Concept: Isolated Smart Contract Wallet Unlike traditional lending protocols where user collateral is siloed in a global vault, Gearbox deploys a unique smart contract for each borrower. ![Figure](https://docs.gearbox.finance/assets/docs/shared/legacy-lending.png) The Credit Account serves as a container for the user's entire position. * **Segregated State:** Assets within the Credit Account are legally and technically distinct from the protocol's liquidity pools. * **User Ownership:** The user retains control over the account's operations, subject only to the solvency checks enforced by the Credit Manager. * **Portability:** Because the Credit Account is a standard smart contract, it can interact with external protocols as a distinct entity, preserving the identity of the position. ### Atomic Solvency Check The Credit Account operates on a "Check-on-Exit" architecture. The protocol does not restrict specific actions within a transaction bundle, provided the account remains solvent at the conclusion of the execution trace. Upon the completion of any interaction (e.g., a swap or deposit), the protocol calculates the account's **Health Factor**. * **If Health Factor > 1:** The transaction is finalized and recorded on-chain. * **If Health Factor < 1:** The entire transaction reverts, ensuring no bad debt can be created atomically. This mechanism allows users to perform complex, multi-step operations in a single transaction without requiring the protocol to understand the intermediate states, as long as the final state satisfies the risk parameters. ![Figure](https://docs.gearbox.finance/assets/docs/shared/credit-account-lending.png) ### Composability via Adapters The Credit Account interacts with the external DeFi ecosystem through **Adapters**. These are lightweight contract interfaces that translate generic user intents into protocol-specific function calls. From the perspective of an external protocol, the Credit Account appears as a standard user wallet. This enables: 1. **Native Execution:** Users interact directly with external contracts rather than through a protocol-specific abstraction layer. 2. **Programmable Credit:** Developers can compose credit logic into arbitrary workflows, treating the Credit Account as a programmable leverage module. *** ### Learn More * **Risk Enforcement:** the logic for calculating the Health Factor and enforcing solvency is managed by the Credit Manager and Credit Facade. * [credit-suite](https://docs.gearbox.finance/developers/credit-suite) * **External Interactions:** The mechanism for connecting Credit Accounts to external DeFi protocols is defined by the Adapter system. * [adapters-integrations](https://docs.gearbox.finance/core/adapters-integrations) * **Liquidity Source:** The capital borrowed by the Credit Account is sourced from the passive Liquidity Pool. * [pool](https://docs.gearbox.finance/core/pool-the-liquidity-vault) ## Omni-EVM Architecture Source: https://docs.gearbox.finance/core/omni-evm-architecture File: content/core/omni-evm-architecture.mdx Gearbox Protocol is designed as a **Deployable Primitive** rather than a monolithic cross-chain application. It does not rely on bridges for message passing or state synchronization between chains. Instead, every deployment on a new chain is a standalone, self-contained **Instance**. This architecture ensures that risk is isolated to the specific chain and that the protocol can scale permissionlessly to any EVM-compatible network without waiting for centralized bridge infrastructure. ### Modular Instances An **Instance** is a complete, functional replica of the Gearbox Protocol deployed on a specific blockchain network. * **Independence:** Each Instance operates autonomously. A failure or pause on one chain does not propagate to others. * **No Bridge Dependency:** Core protocol functions (borrowing, lending, liquidations) do not require cross-chain messaging. * **Local Configuration:** Parameters are tuned specifically for the local ecosystem (e.g., block times, gas costs, and available liquidity) rather than inheriting global defaults that may not fit. This modularity allows the protocol to exist natively on high-speed L2s or sidechains while maintaining the security standards established on Mainnet. ### Bytecode Repository (Verifiable Deployment) To ensure security across many independent instances, Gearbox utilizes a **Bytecode Repository**. This acts as an onchain "Source of Truth" for protocol logic. 1. **Global Verification:** The Gearbox DAO votes to approve specific contract versions (e.g., `CreditFacade V3.1`) after audits are completed. 2. **Onchain Storage:** The compiled bytecode of these approved contracts is stored in the Bytecode Repository on the canonical chain. 3. **Trustless Deployment:** When a new Instance is deployed or updated, the factory contracts verify that the code being deployed matches the authorized bytecode in the repository. This mechanism guarantees that every Instance, regardless of who deployed it, runs the exact, audited code approved by the DAO. ### Governance Architecture Because Instances are independent, governance is split into **Global** (Code & IP) and **Local** (Configuration & Risk) layers. This separation of concerns allows for efficient scaling without creating a bottleneck at the DAO level. | Entity | Scope | Responsibility | | ------------------- | ------------------------ | ----------------------------------------------------------------------------------------------------------- | | **Protocol DAO** | Global (All Chains) | Manages the codebase, approves new versions, and governs the Bytecode Repository. | | **Instance Owner** | Local (One Chain) | A technical multisig responsible for chain-specific infrastructure, such as whitelisting local price feeds. | | **Market Curators** | Local (Specific Markets) | Independent operators who deploy lending markets and manage economic risk parameters (LTVs, Rates). | ### Learn More * **Protocol ownership:** How are the token holders' financial interests and the delivery of the core codebase managed? * [protocol-dao](https://docs.gearbox.finance/core/protocol-dao) * **Chain-specific oversight:** Safe operation within a chain. * [instance-owner](https://docs.gearbox.finance/core/instance-owner) * **Markets growth:** Who manages business building and specific risk parameters? * [market-curators](https://docs.gearbox.finance/core/market-curators) ## For Lenders & LPs Source: https://docs.gearbox.finance/core/for-lenders-lps File: content/core/for-lenders-lps.mdx #### Phase 1: Structural Risk Assessment (Mental Model) **User Intent:** Evaluate the fundamental architecture to determine if the risk segregation meets investment mandates. | Key Question | System Answer | Sitemap Component | | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | | **"How is liability vs. asset risk structured?"** | **Segregated Risk Architecture.** The protocol decouples passive liquidity (Pool) from active risk strategies (Credit Managers). A failure in one strategy is contained by its specific debt ceiling, protecting the broader pool. | [one-pool-many-markets](https://docs.gearbox.finance/core/one-pool-many-markets) | | **"Is the deployment canonical?"** | **Omni-EVM Architecture.** Gearbox utilizes a modular deployment model. Each chain operates as an independent, verified instance rather than a bridged dependency. | [omni-evm-architecture](https://docs.gearbox.finance/core/omni-evm-architecture) | #### Phase 2: Yield Mechanics & Liquidity Risk **User Intent:** Analyze the mechanism of yield accrual and the constraints on capital withdrawal. | Key Question | System Answer | Sitemap Component | | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | | **"How does capital accrue interest?"** | **The Liquidity Vault.** Yield accrues via the Diesel Token (ERC-4626), a non-rebasing interest-bearing token. The exchange rate appreciates as interest is paid by borrowers. | [pool](https://docs.gearbox.finance/core/pool-the-liquidity-vault) | | **"What drives APY volatility?"** | **Interest Rate Model.** The base rate is dynamic, driven by the utilization curve. The "Kink" ($U\_{optimal}$) defines the target efficiency range before rates scale exponentially. | [interest-rate-model](https://docs.gearbox.finance/core/interest-rate-model) | | **"What is the liquidity risk?"** | **Utilization Caps.** High utilization can temporarily block withdrawals. The Interest Rate Model is designed to force borrower repayment during these periods to restore exit liquidity. | [interest-rate-model](https://docs.gearbox.finance/core/interest-rate-model) | #### Phase 3: Counterparty Risk & Solvency Enforcement **User Intent:** Assess the creditworthiness of the borrowers and the automated enforcement of debt obligations. | Key Question | System Answer | Sitemap Component | | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **"What prevents fund misappropriation?"** | **Execution Guardrails.** Borrowers cannot access funds directly. They operate through **Credit Accounts** (smart contract wrappers) restricted to whitelisted interactions via Adapters. | [credit-suite](https://docs.gearbox.finance/core/credit-suite-the-strategy-module) \ [adapters-integrations](https://docs.gearbox.finance/core/adapters-integrations) | | **"How is solvency enforced?"** | **Liquidation Dynamics.** Solvency is enforced mathematically via the Health Factor ($H\_f$). If $H\_f < 1$, the protocol incentivizes third-party liquidators to seize collateral and repay debt. | [liquidation-dynamics](https://docs.gearbox.finance/core/liquidation-dynamics) | | **"How are assets valued?"** | **Price Oracle.** Asset valuation relies on normalized price feeds. Understanding the oracle source (Spot vs. TWAP) is critical for modeling liquidation triggers. | [price-oracle](https://docs.gearbox.finance/core/price-oracle) | #### Phase 4: Stress Testing & Failure Modes **User Intent:** Evaluate system resilience under adverse market conditions (Oracle attacks, Liquidity crunches). | Key Question | System Answer | Sitemap Component | | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | | **"Is the system resilient to oracle manipulation?"** | **Smart Oracles.** The protocol employs a Dual-Feed architecture (Main vs. Reserve). Significant deviation between feeds blocks sensitive operations to prevent arbitrage. | [smart-oracles](https://docs.gearbox.finance/core/smart-oracles) | | **"How is concentration risk managed?"** | **Quota Keeper.** The protocol enforces **Asset-Side Limits**. Even if the pool has excess liquidity, exposure to specific volatile assets is capped globally. | [quota-controls](https://docs.gearbox.finance/core/collateral-limits-specific-rates) | | **"What happens if bad debt occurs?"** | **Insolvency Resolution.** The **Loss Policy** defines fallback logic (e.g., switching to fundamental pricing) to prevent selling collateral at distressed prices during flash crashes. | [smart-oracles](https://docs.gearbox.finance/core/smart-oracles) | #### Phase 5: Governance & Parameter Security **User Intent:** Verify that administrative privileges cannot be exploited to expropriate funds. | Key Question | System Answer | Sitemap Component | | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ | | **"Who controls risk parameters?"** | **Market Curators.** Specific entities manage the risk parameters (LTVs, Limits) for their respective markets. | [market-curators](https://docs.gearbox.finance/core/market-curators) | | **"Are there protections against malicious updates?"** | **Timelock Constraints.** Critical parameter changes are subject to a mandatory 24-hour timelock, allowing LPs to withdraw capital before changes take effect. | [risk-configuration-dictionary](https://docs.gearbox.finance/core/risk-configuration-dictionary) | | **"Who controls the technical infrastructure?"** | **Instance Owner.** A chain-specific multisig acts as the technical gatekeeper for the Price Feed Store, ensuring oracle integrity independent of Market Curators. | [instance-owner](https://docs.gearbox.finance/core/instance-owner) | ## For Borrowers & Farmers Source: https://docs.gearbox.finance/core/for-borrowers-farmers File: content/core/for-borrowers-farmers.mdx #### Phase 1: Feasibility & Capacity Analysis **User Intent:** Determine if the protocol can support the target strategy size and complexity. | Key Question | System Answer | Sitemap Component | | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **"What constrains position size?"** | **Liquidity & Exposure Limits.** Capacity is bounded by two distinct factors: 1) Global liquidity availability in the Pool, and 2) Strategy-specific Debt Ceilings defined by the Curator. | [pool](https://docs.gearbox.finance/core/pool-the-liquidity-vault) \ [risk-configuration-dictionary](https://docs.gearbox.finance/core/risk-configuration-dictionary) | | **"What are the primary risk vectors?"** | **Risk Vector Identification.** Borrowers face three primary threats: 1) **Market Risk** (Collateral volatility), 2) **Rate Risk** (Utilization-driven cost spikes), and 3) **Liquidity Risk** (Inability to exit via external DEX liquidity). | [liquidation-dynamics](https://docs.gearbox.finance/core/liquidation-dynamics) | | **"Is the target collateral eligible?"** | **Collateral Allowlist.** Each Credit Manager enforces a strict allowlist of assets. Tokens not explicitly whitelisted cannot be held within the Credit Account. | [credit-suite](https://docs.gearbox.finance/core/credit-suite-the-strategy-module) | #### Phase 2: Cost of Carry Modeling **User Intent:** Model the dynamic cost of capital to project net yield and volatility exposure. | Key Question | System Answer | Sitemap Component | | ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | **"What drives the base rate?"** | **Interest Rate Model.** Rates are dynamic and determined by **Pool Utilization**. Large withdrawals by LPs can cause immediate utilization spikes, increasing the cost of capital. | [interest-rate-model](https://docs.gearbox.finance/core/interest-rate-model) | | **"Are there asset-specific premiums?"** | **Quota Rates.** Illiquid or high-volatility collateral assets may carry an *additional* interest premium (Quota Rate) imposed by the Quota Keeper, independent of the base pool rate. | [quota-controls](https://docs.gearbox.finance/core/collateral-limits-specific-rates) | | **"What is the protocol take rate?"** | **Interest Fee.** The Curator and DAO capture a fixed percentage of the interest paid. This markup is additive to the base rate paid to LPs. | [risk-configuration-dictionary](https://docs.gearbox.finance/core/risk-configuration-dictionary) | #### Phase 3: Solvency & Liquidation Mechanics **User Intent:** Define the liquidation boundary and the economic consequences of insolvency. | Key Question | System Answer | Sitemap Component | | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- | | **"What triggers liquidation?"** | **Liquidation Triggers.** Insolvency can result from: 1) Collateral depreciation, 2) Debt asset appreciation, or 3) **Accrued Interest** (Rate spikes eroding the Health Factor). | [liquidation-dynamics](https://docs.gearbox.finance/core/liquidation-dynamics) | | **"What is the penalty structure?"** | **Liquidation Premium.** Upon liquidation, the borrower forfeits a fixed percentage (e.g., 5%) of the liquidated collateral to the third-party liquidator. | [liquidation-dynamics](https://docs.gearbox.finance/core/liquidation-dynamics) | | **"Are automated mitigations available?"** | **Partial Liquidation & Deleverage.** The protocol supports partial liquidations to restore solvency without full closure. Automated deleveraging tools can be utilized to maintain the Health Factor. | [liquidation-dynamics](https://docs.gearbox.finance/core/liquidation-dynamics) | #### Phase 4: Governance & Parameter Risk **User Intent:** Assess the risk of adverse parameter changes by the market operator. | Key Question | System Answer | Sitemap Component | | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | **"Can parameters change mid-trade?"** | **Parameter Risk.** Yes. Curators can modify Liquidation Thresholds (LTVs). However, these changes are subject to a mandatory **Timelock**, providing a window for borrowers to adjust or exit. | [risk-configuration-dictionary](https://docs.gearbox.finance/core/risk-configuration-dictionary) | | **"What are the operational circuit breakers?"** | **Smart Oracles & Pauses.** 1) Significant deviation between Main and Reserve price feeds will block operations. 2) Admins retain the ability to pause Credit Managers in emergency scenarios. | [smart-oracles](https://docs.gearbox.finance/core/smart-oracles) | | **"Can access be revoked?"** | **Access Control.** Curators can forbid specific tokens or adapters, preventing borrowers from increasing exposure to those assets. | [market-curators](https://docs.gearbox.finance/core/market-curators) | #### Phase 5: Position Unwind & Liquidity Dependencies **User Intent:** Evaluate the reliability of exit mechanisms under stress. | Key Question | System Answer | Sitemap Component | | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | **"What are the execution dependencies?"** | **External Liquidity.** The "Atomic Close" relies on external DEX liquidity (e.g., Curve/Uniswap) to swap collateral for the debt asset. Thin liquidity or high slippage can cause repayment transactions to revert. | [adapters-integrations](https://docs.gearbox.finance/core/adapters-integrations) | | **"What is the contingency procedure?"** | **Manual Unwind.** If atomic execution fails, the borrower must manually withdraw collateral (subject to solvency checks), execute swaps externally, and repay the debt. | [credit-suite](https://docs.gearbox.finance/core/credit-suite-the-strategy-module) | ## For Market Curators Source: https://docs.gearbox.finance/core/for-market-curators File: content/core/for-market-curators.mdx The Market Curator views Gearbox as a **Risk Parameterization Engine**, not a fund management tool. Unlike other lending primitives where curators actively allocate liquidity (e.g., Morpho), Gearbox Curators define the *boundary conditions* (LTVs, Limits, Rates) within which users autonomously execute strategies. #### Phase 1: The Operational Model (Mental Model Alignment) **User Intent:** Understand the legal and operational distinction between "Managing Funds" and "Managing Parameters." | Key Question | System Answer | Sitemap Component | | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | | **"Do I manage the liquidity?"** | **Non-Custodial Curation.** Unlike Morpho, Curators do not actively rebalance funds between vaults. Curators set the *rules* and users/borrowers autonomously utilize the liquidity. This distinction is critical for entities avoiding custodial classification. | [one-pool-many-markets](https://docs.gearbox.finance/core/one-pool-many-markets) | | **"What is the deliverable?"** | **The Lending Product.** The Curator's product is a set of smart contracts with specific risk parameters. The "Product" is the *access* to leverage and earning under these specific terms, not the yield itself. | [credit-suite](https://docs.gearbox.finance/core/credit-suite-the-strategy-module) | | **"Who bears the economic risk?"** | **Risk Liability.** The Curator bears the reputational and economic risk of their configuration. Gearbox Protocol provides the *mechanism* for liquidation, but the *guarantee* of solvency depends entirely on the Curator's parameter selection (LTV vs. Volatility). | [liquidation-dynamics](https://docs.gearbox.finance/core/liquidation-dynamics) | #### Phase 2: Infrastructure Dependencies (The "Full Stack" Reality) **User Intent:** Assess the reliance on Gearbox DAO for critical infrastructure vs. autonomous capabilities. | Key Question | System Answer | Sitemap Component | | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | **"Is it fully permissionless?"** | **Hybrid Governance.** While market creation is permissionless, critical infrastructure is gated. 1) **Chain Activation** requires DAO approval. 2) **Price Feed Whitelisting** is controlled by the Instance Owner multisig (though open to Curator participation). | [instance-owner](https://docs.gearbox.finance/core/instance-owner) | | **"Who runs the interface?"** | **UI & Tooling Dependency.** The official Gearbox App and Curation Interface are maintained by the DAO. While the protocol is onchain, practical operation relies on these offchain services unless the Curator builds their own frontend. | [protocol-dao](https://docs.gearbox.finance/core/protocol-dao) | | **"How are transactions generated?"** | **Operational Complexity.** Configuring a market involves complex transaction batches. Curators rely on the DAO-maintained **Curation Interface** to generate these payloads. Autonomous operation requires significant technical capability to replicate this tooling. | [risk-configuration-dictionary](https://docs.gearbox.finance/core/risk-configuration-dictionary) | #### Phase 3: Product Structuring & Incentives **User Intent:** Define the commercial structure and align incentives with the DAO. | Key Question | System Answer | Sitemap Component | | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | | **"How do I monetize?"** | **Fee Sharing.** Curators capture a configurable percentage of interest and liquidation fees. This revenue stream is programmatic and shared with the Protocol DAO. | [market-curators](https://docs.gearbox.finance/core/market-curators) | | **"Can I get token incentives?"** | **DAO Alignment.** GEAR token incentives are discretionary and voted on by the DAO. There is no programmatic guarantee of incentives; Curators must align their product with the DAO's strategic goals to receive support. | [protocol-dao](https://docs.gearbox.finance/core/protocol-dao) | | **"Can the DAO interfere?"** | **Sovereignty vs. Support.** The DAO cannot alter a Curator's parameters onchain. However, the DAO *can* delist a market from the official UI or cut incentives if the Curator's risk management endangers the protocol's reputation. | [protocol-dao](https://docs.gearbox.finance/core/protocol-dao) | #### Phase 4: Risk Parameterization (The Core Job) **User Intent:** Calibrate the system to balance capital efficiency with solvency protection. | Key Question | System Answer | Sitemap Component | | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- | | **"How is leverage capped?"** | **Liquidation Thresholds.** Curators set the $LT$ for each asset. This is the primary lever for risk management. Setting this too high relative to asset volatility *will* result in bad debt, for which the protocol is not liable. | [liquidation-dynamics](https://docs.gearbox.finance/core/liquidation-dynamics) | | **"How is concentration risk managed?"** | **Quota Limits.** Curators must set global caps on specific collateral assets via the Quota Keeper. This prevents the pool from becoming over-exposed to illiquid tokens. | [quota-controls](https://docs.gearbox.finance/core/collateral-limits-specific-rates) | | **"How are liquidators incentivized?"** | **Liquidation Premium.** Curators configure the premium paid to liquidators. If this is set too low, liquidators will not execute, and the system *will* fail. The protocol does not guarantee liquidation execution. | [liquidation-dynamics](https://docs.gearbox.finance/core/liquidation-dynamics) | #### Phase 5: Operational Governance **User Intent:** Understand the ongoing management and emergency procedures. | Key Question | System Answer | Sitemap Component | | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | **"How are updates executed?"** | **Timelock Constraints.** All critical parameter changes are subject to a 24-hour timelock. Curators must plan updates in advance. | [risk-configuration-dictionary](https://docs.gearbox.finance/core/risk-configuration-dictionary) | | **"What are the emergency powers?"** | **Pause & Loss Policy.** In the event of an exploit or market failure, Curators (or their Emergency Admins) can pause borrowing or trigger the Loss Policy to prevent bad debt accumulation. | [smart-oracles](https://docs.gearbox.finance/core/smart-oracles) | ## For Ecosystems & Chains Source: https://docs.gearbox.finance/core/for-ecosystems-chains File: content/core/for-ecosystems-chains.mdx #### Phase 1: The Value Proposition (Composability Engine) **User Intent:** Understand how Gearbox enriches the existing DeFi ecosystem beyond simple lending. | Key Question | System Answer | Sitemap Component | | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | **"How does this benefit local apps?"** | **Unified Execution Layer.** Gearbox is not a silo. Through **Adapters**, Credit Accounts inject leverage directly into local protocols (e.g., Uniswap, Curve, Pendle). This turns a passive lending market into an active volume generator for the chain's DEXs and yield farms. | [adapters-integrations](https://docs.gearbox.finance/core/adapters-integrations) | | **"Is it compatible with our assets?"** | **Versatile Collateral.** Gearbox supports complex assets like LP tokens, Vault shares, and PTs. This allows the chain to offer leverage on its unique "Productive Assets," not just plain vanilla tokens. | [credit-suite](https://docs.gearbox.finance/core/credit-suite-the-strategy-module) | #### Phase 2: The Operating Model (Roles & Responsibilities) **User Intent:** Clarify the division of labor between the Chain, the Gearbox DAO, and the Market Operators. | Key Question | System Answer | Sitemap Component | | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | | **"Who runs the markets?"** | **Service Provider vs. Operator.** Gearbox DAO provides the *technology stack* (Service Provider). **Curators** (Operators) run the actual business (Risk/Parameters). The Chain can bring its own trusted curators, or Gearbox can help facilitate introductions to existing active curators. | [market-curators](https://docs.gearbox.finance/core/market-curators) | | **"Who guarantees success?"** | **Shared Responsibility.** Gearbox DAO ensures the code functions correctly and provides operational support. However, the economic success of a market is a function of the Curator's strategy and the Chain's underlying liquidity depth. | [protocol-dao](https://docs.gearbox.finance/core/protocol-dao) | | **"Is deployment gated?"** | **Permissionless Architecture.** No. Once the protocol is deployed on the chain, market creation is permissionless. Curators do not need Gearbox DAO approval to launch new markets or list new assets, ensuring rapid integration with the chain's roadmap. | [market-curators](https://docs.gearbox.finance/core/market-curators) | #### Phase 3: Ecosystem Prerequisites (Economic Viability) **User Intent:** Determine the maturity level required to support leveraged markets. | Key Question | System Answer | Sitemap Component | | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | | **"What is required for liquidations?"** | **Liquidity Enables Capacity.** Gearbox relies on swapping collateral on local DEXs. Deeper DEX liquidity allows for higher borrowing limits. We work with chains to identify the most liquid assets suitable for initial markets. | [liquidation-dynamics](https://docs.gearbox.finance/core/liquidation-dynamics) | | **"How are liquidators onboarded?"** | **Collaborative Keeper Network.** Gearbox provides open-source liquidator bot infrastructure. We actively collaborate with the Chain to onboard local MEV searchers and keepers, ensuring a robust liquidation network is established pre-launch. | [liquidation-dynamics](https://docs.gearbox.finance/core/liquidation-dynamics) | | **"What assets work best?"** | **Productive Collateral.** Gearbox shines when there are yield-bearing assets (LSTs, LRTs, Yield Vaults). Leverage on zero-yield assets is less attractive to borrowers in high-rate environments. | [credit-suite](https://docs.gearbox.finance/core/credit-suite-the-strategy-module) | #### Phase 4: Technical Requirements (Deployment Feasibility) **User Intent:** Verify technical compatibility to ensure a smooth launch. | Key Question | System Answer | Sitemap Component | | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | | **"What are the hard constraints?"** | **Block Gas Limit.** Gearbox contracts are sophisticated. To deploy the core infrastructure, the chain should ideally support a Block Gas Limit of **>30 Million**. We can assist in evaluating chain parameters for compatibility. | [omni-evm-architecture](https://docs.gearbox.finance/core/omni-evm-architecture) | | **"What infrastructure is needed?"** | **RPC Reliability.** Robust offchain operations (Interface, Liquidator Bots) require stable RPC providers. Gearbox contributors can assist in testing and verifying infrastructure readiness. | [omni-evm-architecture](https://docs.gearbox.finance/core/omni-evm-architecture) | | **"Are oracles ready?"** | **Oracle Infrastructure.** Reliable oracle providers (Chainlink, Redstone, Pyth, or API3) are required for collateral assets. We can help coordinate with oracle partners to ensure coverage. | [price-oracle](https://docs.gearbox.finance/core/price-oracle) | #### Phase 5: Growth & Incentives (Go-to-Market) **User Intent:** Plan the launch strategy and incentive allocation. | Key Question | System Answer | Sitemap Component | | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | | **"How do we attract liquidity?"** | **Co-Marketing & Grants.** The Chain can offer incentives to Curators to encourage market creation. Gearbox DAO frequently partners with chains to co-market these launches to existing user base. | [market-curators](https://docs.gearbox.finance/core/market-curators) | ## For Asset Issuers & Protocols Source: https://docs.gearbox.finance/core/for-asset-issuers-protocols File: content/core/for-asset-issuers-protocols.mdx #### Phase 1: The Value Proposition (Distribution & Efficiency) **User Intent:** Understand how Gearbox drives growth for the underlying protocol. | Key Question | System Answer | Sitemap Component | | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | **"How does this grow our TVL?"** | **Leverage as a Feature.** Gearbox acts as a multiplier on existing demand. By enabling users to mint/stake assets with leverage, issuers increase capital efficiency, attracting sticky, yield-focused capital that might otherwise go to competitors. | [credit-suite](https://docs.gearbox.finance/core/credit-suite-the-strategy-module) | | **"Does it require DEX liquidity?"** | **Zero-Slippage Execution.** Unlike standard lending markets, Gearbox does not strictly require deep DEX liquidity to enable leverage entry. Through **Direct Integration**, Credit Accounts can mint/redeem directly with protocol contracts, bypassing secondary market slippage entirely. | [adapters-integrations](https://docs.gearbox.finance/core/adapters-integrations) | | **"Can it handle complex flows?"** | **Purpose-Specific Execution.** Gearbox adapts to the asset's mechanics. Whether it's staking, locking, or vesting, the Credit Account executes the logic natively. This allows issuers to offer "Leveraged Staking" or "Leveraged RWA Vaults" as a seamless user experience. | [credit-suite](https://docs.gearbox.finance/core/credit-suite-the-strategy-module) | #### Phase 2: Solving the Liquidity Problem (RWAs & Vaults) **User Intent:** Address the specific friction points of illiquid or semi-liquid assets (RWAs, Private Credit). | Key Question | System Answer | Sitemap Component | | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | **"We have delayed settlement. Does it work?"** | **Async Redemption Support.** Yes. Standard lending protocols fail here, but Gearbox excels. Credit Accounts can initiate a redemption, hold the receipt token through the settlement period, and claim the underlying funds upon finalization—all while maintaining the credit position. | [adapters-integrations](https://docs.gearbox.finance/core/adapters-integrations) | | **"Do we need to pay for incentives?"** | **Capital Efficiency > Incentives.** By allowing users to mint assets at NAV (Net Asset Value) via leverage, issuers reduce the need to spend millions on incentives to deepen Curve/Uniswap pools just to support lending liquidations. | [liquidation-dynamics](https://docs.gearbox.finance/core/liquidation-dynamics) | | **"Can we enforce KYC/Whitelists?"** | **Compliance Compatibility.** Yes. Because the Credit Account is a smart contract wallet, it can be compatible with protocol allowlists or transfer restrictions, ensuring that leveraged users meet compliance requirements. | [credit-suite](https://docs.gearbox.finance/core/credit-suite-the-strategy-module) | #### Phase 3: Technical Integration (Adapters) **User Intent:** Assess the engineering effort required to connect. | Key Question | System Answer | Sitemap Component | | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- | | **"How do we connect?"** | **The Adapter Model.** Integration requires building an **Adapter**—a lightweight wrapper contract that translates Gearbox's safety checks into the protocol's function calls (e.g., `deposit()`, `stake()`, `requestRedemption()`). | [adapters-integrations](https://docs.gearbox.finance/core/adapters-integrations) | | **"Who builds the adapter?"** | **Collaborative Development.** Gearbox DAO maintains a library of standard adapters (ERC-4626, Curve, Uniswap). For custom logic, teams can fork a template or collaborate with Gearbox contributors for guidance. | [adapters-integrations](https://docs.gearbox.finance/core/adapters-integrations) | #### Phase 4: Risk Underwriting (Getting Approved) **User Intent:** Understand how to satisfy the risk requirements of potential Curators. | Key Question | System Answer | Sitemap Component | | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | | **"How is risk assessed?"** | **Curator Due Diligence.** There is no universal formula. Each Curator has a unique risk framework—some prioritize backing transparency, others prioritize secondary liquidity. Issuers should be prepared to provide data on volatility, redemption mechanics, and backing to facilitate this underwriting process. | [liquidation-dynamics](https://docs.gearbox.finance/core/liquidation-dynamics) | | **"How is the asset priced?"** | **Flexible Oracle Architecture.** Gearbox supports diverse pricing models (Spot, TWAP, Fundamental/NAV). The choice depends on what the Curator is comfortable with. Issuers should propose a pricing source that is robust against manipulation to increase the likelihood of listing. | [price-oracle](https://docs.gearbox.finance/core/price-oracle) | | **"How do we ensure solvency?"** | **Shared Assurance.** Curators need to know that liquidations will execute in bad market conditions. Issuers can significantly improve their listing chances by committing to run their own liquidator bots or providing a backstop for collateral liquidation. | [liquidation-dynamics](https://docs.gearbox.finance/core/liquidation-dynamics) | #### Phase 5: Go-to-Market (Decentralized Listing) **User Intent:** Navigate the listing process in a permissionless environment. | Key Question | System Answer | Sitemap Component | | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | | **"Who approves the listing?"** | **Marketplace of Risk.** Gearbox is a neutral infrastructure; there is no central "Listing Committee." Issuers must pitch **Market Curators**—independent operators who manage the liquidity. Curators decide what to list based on their own risk models and incentive requirements. | [market-curators](https://docs.gearbox.finance/core/market-curators) | | **"What drives Curator decisions?"** | **Incentive Alignment.** Different Curators have different mandates. Some prioritize high-yield assets and may require incentives (bribes/points) to list new tokens. Others prioritize safety and require strict audits. Success requires finding the right Curator for the asset profile. | [market-curators](https://docs.gearbox.finance/core/market-curators) | | **"How fast can we launch?"** | **Permissionless Agility.** Once a Curator agrees to underwrite the asset, the listing is permissionless. There is no DAO governance vote required to add a new collateral type to an existing Credit Manager. | [market-curators](https://docs.gearbox.finance/core/market-curators) | ## Pool (The Liquidity Vault) Source: https://docs.gearbox.finance/core/pool-the-liquidity-vault File: content/core/pool-the-liquidity-vault.mdx The **Liquidity Pool** serves as the liability side of the Gearbox Protocol balance sheet. It is a passive, ERC-4626 compliant smart contract where lenders deposit assets (e.g., USDC, WETH) to earn yield. Unlike traditional lending protocols where a pool interacts directly with individual borrowers, the Gearbox Pool operates on a **Wholesale Banking Model**. It does not lend directly to users; instead, it allocates capital to **Credit Suites** (Credit Managers), which act as specialized lending branches with distinct risk configurations. ### Core Mechanics #### 1. Passive Liquidity & ERC-4626 The Pool is strictly passive. It holds the underlying asset and issues **Diesel Tokens** (dTokens) to depositors as a receipt of liquidity provision. * **Standard:** Fully compliant with [ERC-4626](https://www.google.com/url?sa=E\&q=https%3A%2F%2Feips.ethereum.org%2FEIPS%2Feip-4626) (Tokenized Vault Standard). * **Fungibility:** Diesel Tokens are fungible and transferable, allowing them to be used as collateral in other DeFi protocols. * **Liquidity:** Deposits and withdrawals are instant subject to available amount of unborrowed liquidity. #### 2. Diesel Tokens (Non-Rebasing Yield) Yield accrual in Gearbox is reflected through the **Exchange Rate**, not through balance updates. * **Non-Rebasing:** Unlike aTokens (Aave), the wallet balance of Diesel Tokens does not increase over time. * **Value Accrual:** As borrowers pay interest, the amount of underlying assets in the Pool grows while the supply of Diesel Tokens remains constant. Consequently, the exchange rate increases.\ Borrow rates are determined using Utilization-based Interest Rate Model and collateral-specific rates. $$ Exchange\ Rate = \frac{Total\ Assets\ (Principal + Interest)}{Total\ Supply\ of\ dTokens} $$ #### 3. The Branch Model (Wholesale Lending) The Pool delegates the complexity of risk management and borrower interaction to **Credit Suites**. * **The Pool (Wholesale Bank):** Aggregates liquidity from lenders. It has no knowledge of individual borrowers, collateral types, or liquidation logic. Its only function is to lend capital to approved Credit Suites up to a defined limit. * **Credit Suites (Retail Branches):** Borrow liquidity from the Pool to fund Credit Accounts. Each Credit Suite enforces specific risk parameters (LTV, allowed assets, liquidation rules). This separation of concerns ensures that the Pool remains lightweight and secure, while complexity is pushed to the periphery (the Suites). ### Risk Isolation & Allocation A single Pool can fund multiple Credit Suites simultaneously. The Market Curator manages the Pool's risk exposure by setting a **Debt Ceiling** for each connected Credit Suite. * **Allocation Limits:** The Curator defines the maximum capital available to each CreditSuite (e.g., 80% to a Low-Risk Product, 20% to a High-Risk Product). * **Firewalling:** If a specific Strategy (Credit Suite) suffers a failure or bad debt, the loss is contained within that Creit Suite's allocation. The Pool's exposure is limited to the capital lent to that specific branch, protecting the remaining liquidity. ### Automated Insurance mechanism Gearbox V3 implements an automated **First-Loss Capital** buffer to protect Passive Lenders from bad debt. This mechanism prioritizes protocol solvency over profit distribution by strictly retaining revenue within the until specific safety targets are met. ### Learn More * **Yield source:** How is the utilization-driven interest rate calculated? * [interest-rate-model](https://docs.gearbox.finance/core/interest-rate-model) * **Yield optimization & risk control:** How are collateral-specific rates and collateral exposure limits handled? * [quota-controls](https://docs.gearbox.finance/core/collateral-limits-specific-rates) * **Deposits utilization:** Where is the liquidity actually used or lent to? * [credit-suite](https://docs.gearbox.finance/developers/credit-suite) * **Insurance from Bad debt:** Learn how the underlying mechanism works in detail. * [insurance-and-solvency-reserves](https://docs.gearbox.finance/core/insurance-solvency-reserves) ## Credit Suite (The Strategy Module) Source: https://docs.gearbox.finance/core/credit-suite-the-strategy-module File: content/core/credit-suite-the-strategy-module.mdx The Credit Suite is the architectural assembly responsible for managing the asset side of the protocol's balance sheet. While the Liquidity Pool manages passive capital (liabilities), the Credit Suite defines the logic, risk parameters, and execution boundaries for active borrowers (assets). A single Liquidity Pool can be connected to multiple Credit Suites, each representing a distinct **Credit Manager** with unique risk configurations, allowed collateral assets, and borrowing limits. This isolation allows the protocol to compartmentalize risk strategies without fragmenting underlying liquidity. ### Architectural Components The Credit Suite consists of three primary smart contracts, each with distinct responsibilities regarding accounting, execution, and configuration. #### 1. Credit Manager (The Accountant) The Credit Manager is the central logic container and state manager for a specific lending strategy. It acts as the "Accountant" of the system. * **State Management:** It maintains the ledger of all Credit Accounts associated with the strategy, tracking debt amounts and collateral values. * **Adapter Registry:** It stores the list of approved Adapters (integrations) and enforces the "Allowlist" of tokens that can be held as collateral. * **Solvency Logic:** It contains the mathematical logic for calculating the Health Factor (HF). #### 2. Credit Facade (The Entry Point) The Credit Facade serves as the primary entry point for borrower interactions. It abstracts the complexity of the Credit Manager and enforces execution safety. * **Multicall Execution:** The Facade allows users to bundle multiple operations (e.g., `borrow`, `swap`, `deposit_into_vault`) into a single atomic transaction. * **Check-on-Exit Solvency:** The Facade implements the protocol's optimistic execution model. It permits any sequence of whitelisted operations during a transaction but enforces a strict solvency check at the end. * If HF > 1 at the end of the transaction, the state changes are committed. * If HF < 1, the entire transaction reverts. * **Permissions:** It handles user permissions, ensuring that only the owner of a Credit Account can initiate transactions affecting that account. **HF** calculation is based on **Total Weighted Value (TWV)** of collateral. This is not just the market value; it is the market value *discounted* by the Liquidation Threshold (LT). If Account holds $100 of ETH with an LT of 90%, the system values it at $90 for solvency purposes. * [**Deep Dive: Full Liquidation Math & Formulas**](https://docs.gearbox.finance/core/liquidation-dynamics) #### 3. Credit Configurator (The Management Layer) The Credit Configurator provides the administrative interface for Market Curators to manage the Credit Suite. It decouples governance logic from the core accounting logic. * **Parameter Updates:** Curators interact with the Configurator to adjust risk parameters (e.g., Liquidation Thresholds, Fees, Limits) rather than interacting with the Credit Manager directly. * **Validation & Safety:** The Configurator validates inputs to prevent invalid states (e.g., setting a Liquidation Threshold > 100%) before applying changes to the Credit Manager. * **Timelock Enforcement:** It enforces mandatory delays for critical parameter changes, ensuring users have time to react to risk adjustments before they become active. ### Interaction Flow 1. **Configuration:** The Curator sets risk parameters via the **Credit Configurator**. 2. **Execution:** The Borrower submits a multicall transaction to the **Credit Facade**. 3. **Accounting:** The Facade routes instructions to the **Credit Manager**, which updates the Credit Account's state and interacts with the **Pool** or **Adapters**. 4. **Verification:** The Facade requests a final solvency check from the Credit Manager before finalizing the transaction. ### Learn More * **Solvency enforcement:** How liquidations work? * [liquidation-dynamics](https://docs.gearbox.finance/core/liquidation-dynamics) * **Risk controls:** What is the complete list of parameters that define the strategy? * [risk-configuration-dictionary](https://docs.gearbox.finance/core/risk-configuration-dictionary) ## Adapters & Integrations Source: https://docs.gearbox.finance/core/adapters-integrations File: content/core/adapters-integrations.mdx A Credit Account is a secure "Container." By default, it cannot interact with the outside world because the protocol cannot guarantee the safety of external smart contracts. **Adapters** are the solution. They are specialized "Translation Contracts" that allow Credit Accounts to interact with specific DeFi protocols (like Uniswap, Curve, or Lido) while maintaining the strict solvency checks required by Gearbox. ### Modular Execution: Purpose-Optimized UX Gearbox’s modular architecture unifies credit and execution. * **The Core Layer:** Provides the capital and enforces solvency (Health Factor). * **The Adapter Layer:** Extends this base with purpose-specific execution rules. This allows Curators to design Financial Products tailored for specific use cases. One product might be optimized for **Prediction Markets** (interacting with order books), while another is optimized for **Yield Farming** (interacting with vaults). ![Figure](https://docs.gearbox.finance/assets/docs/core/adapters-integrations/01-modular-execution-purpose-optimized-ux.png) ### The Security Problem: Unrestricted Execution A Credit Account holds leveraged funds. If users could interact directly with any smart contract, they could exploit complex DeFi mechanics to bypass solvency checks. **How Adapters Fix This:**\ Adapters act as a **Sanitized Interface**. They restrict interactions to a specific, pre-defined set of functions that have been audited for safety. 1. **Function Whitelisting:** Users cannot call `any` function on Uniswap; they can only call the specific `swap` functions defined in the Adapter. 2. **Result Verification:** The Adapter ensures that the outcome of the trade (the tokens received) matches the protocol's expectations, preventing complex state manipulation attacks. By forcing all interactions through these "Safe Tunnels," Gearbox ensures that the Credit Account's state remains predictable at all times. ### The Router: Intelligent Execution While Adapters provide the *connection*, the **Router** provides the *path*. DeFi strategies are rarely simple. A user might want to "Zap" from USDC directly into a Convex Curve-stETH position. This requires multiple steps: 1. Swap USDC -> WETH (Uniswap) 2. Deposit WETH -> stETH (Lido) 3. Deposit stETH + WETH -> steCRV (Curve) 4. Stake steCRV -> Convex The Gearbox Router calculates the optimal path across all enabled Adapters and bundles these steps into a single **Multicall**. ![Figure](https://docs.gearbox.finance/assets/docs/core/adapters-integrations/02-the-router-intelligent-execution.png) ### Curator Responsibilities As a Curator, the choice of Adapters defines the **Utility** of the market. 1. **Enable Liquidity:** If a market accepts `wstETH` as collateral, the Curator should enable DEX Adapters (e.g., Uniswap or Curve) that support `wstETH` trading. Without it, users cannot swap into the Debt token. Limited allowed adapters will result in high slippage losses. 2. **Enable Yield:** To offer a "Farming Strategy," the Curator must enable the specific Adapter for that farm (e.g., the Convex Adapter or Midas vault adapter). 3. **Risk Management:** If a specific external protocol is hacked or becomes risky, the Curator can **Disable** that specific Adapter instantly via the Emergency Admin, protecting the pool from further exposure. ### Learn More * **Solvency checks:** How accounts are kept overcollateralized after each operation? * [credit-suite](https://docs.gearbox.finance/developers/credit-suite) * **Unique usecases:** How Credit Accounts and adapters unlock new credit interactions. * [direct-redemptions](https://docs.gearbox.finance/core/usecase-direct-redemptions) ## Interest Rate Model Source: https://docs.gearbox.finance/core/interest-rate-model File: content/core/interest-rate-model.mdx The Interest Rate Model (IRM) functions as the protocol's algorithmic central bank. Its primary objective is to balance **capital efficiency** (maximizing yield for lenders) with **liquidity availability** (ensuring lenders can withdraw assets). It achieves this by dynamically adjusting the Base Borrow Rate based on the **Utilization Rate** of the Liquidity Pool. ### The Utilization Curve The cost of borrowing is a function of demand. As the pool becomes more utilized (more funds borrowed), the interest rate rises to incentivize repayments and attract new deposits. Gearbox employs a **Two-Kink Piecewise Linear Model**. This design creates a specific "Optimal Zone" where rates remain stable, preventing volatility during normal market activity while aggressively penalizing over-utilization. #### Mathematical Structure The curve is defined by two utilization thresholds (Kinks), denoted as U\_1 and U\_2, creating three distinct slope zones: 1. **Growth Zone (0% to U\_1):** * **Behavior:** Rates increase slowly. * **Intent:** Incentivize early borrowing and ramp up utilization to efficient levels. 2. **Optimal Zone (U\_1 to U\_2):** * **Behavior:** Rates remain relatively stable or rise moderately. * **Intent:** Create a predictable cost of capital for borrowers while ensuring sufficient yield for lenders. This is the target operating range of the pool. 3. **Liquidity Crunch Zone (> U\_2):** * **Behavior:** Rates spike exponentially (High Slope). * **Intent:** Force immediate deleveraging. When utilization breaches U\_2, the cost of capital exceeds market returns, compelling borrowers to close positions and restoring liquidity for lender withdrawals. #### Formula The Borrow Rate R(U) is calculated as: $$ R(U)= \begin{cases} R\_{\text{base}} + \dfrac{U}{U\_1} R\_{\text{slope1}}, & U \le U\_1 \\\[6pt] R\_{\text{base}} + R\_{\text{slope1}} * \dfrac{U - U\_1}{U\_2 - U\_1} R\_{\text{slope2}}, & U\_1 < U \le U\_2 \\\[6pt] R\_{\text{base}} + R\_{\text{slope1}} + R\_{\text{slope2}} * \dfrac{U - U\_2}{1 - U\_2} R\_{\text{slope3}}, & U > U\_2 \end{cases} $$ Where: * U: Current Utilization Rate (Total Debt / Total Assets). * R\_base: The minimum starting rate (y-intercept). * R\_slope: The rate of change in each zone. ***Reference:*** * [Desmos IRM visualizer](https://www.desmos.com/calculator/d281eeb4a9) ### Liquidity Reservation A critical feature of the Gearbox IRM is the enforcement of **Exit Liquidity**. In standard lending protocols, 100% utilization means lenders cannot withdraw their funds until a borrower repays. Gearbox mitigates this risk through **Liquidity Reservation**. #### The Reservation Cap Curators can configure the market to strictly forbid new borrowing once utilization reaches U\_2. * **Mechanism:** If `isBorrowingMoreU2Forbidden` is enabled, any transaction attempting to increase debt beyond the U\_2 threshold will revert. * **Result:** The remaining liquidity (from U\_2 to 100%) is effectively reserved for lender withdrawals. Even in periods of peak demand, a buffer of liquid assets remains available in the pool. ### Total Cost of Capital The Interest Rate Model determines the **Base Rate** of the pool. The final cost to a borrower includes additional collateral-specific rate. #### Learn More * **Asset-specific risk premiums:** Borrowers holding specific collateral assets may incur an additional Quota Rate on top of the base rate. * [quota-controls](https://docs.gearbox.finance/core/collateral-limits-specific-rates) * **Protocol fees:** A portion of the interest paid is captured as revenue for the Protocol DAO and the Market Curator. * [dao-and-curators-business-model](https://docs.gearbox.finance/core/dao-curators-business-model) ## Collateral Limits & Specific rates Source: https://docs.gearbox.finance/core/collateral-limits-specific-rates File: content/core/collateral-limits-specific-rates.mdx The Quota Control system is the protocol's mechanism for managing concentration risk and pricing asset-specific exposure. While the Liquidity Pool provides a shared source of capital, the Quota system enforces strict limits on how that capital can be allocated toward specific collateral assets and applies additional risk premiums where necessary. ### Asset-Side Caps (Concentration Limits) To protect Liquidity Providers (LPs) from over-exposure to specific assets, the protocol enforces **Quota Limits**. These are hard caps on the total amount of debt that can be collateralized by a specific token across all Credit Managers attached to a pool. #### Mechanism Unlike a global debt ceiling which limits the total size of the pool or Credit Manager limits which define maximum exposure to particular strategies, Quota Limits operate on the **collateral side**. * **Exposure Calculation:** The system tracks the total value of borrowing power currently backed by a specific asset (e.g., $WBTC). * **Enforcement:** If the total exposure reaches the defined Quota Limit, the system blocks any transaction that would further increase exposure to that asset. * New Credit Accounts cannot be opened with that collateral. * Existing accounts cannot increase the amount of debt that is backed by particular token. * Repayments and closures remain enabled to allow deleveraging. This architecture ensures that even if a pool has abundant idle liquidity, it cannot be drained into a single illiquid or high-risk strategy beyond the safety parameters defined by the Curator. ### Quota Rates (Risk Premium) The Quota system decouples the cost of liquidity from the cost of risk. It allows the protocol to charge an additional interest rate—the **Quota Rate**—based specifically on the collateral held by the borrower. #### The Additive Rate Model The total cost of borrowing before fees is the sum of the base cost of capital and the specific risk premium of the collateral. $$ \text{Total APR} = \text{Base Rate} + \text{Quota Rate} $$ * **Base Rate:** Determined by the utilization of the Liquidity Pool. This represents the opportunity cost of the underlying asset (e.g., USDC). * **Quota Rate:** Determined by the specific collateral asset (e.g., a volatile governance token). This represents the risk premium for holding that specific asset. #### Pricing Granularity This separation allows for granular risk pricing within a single pool: * **Low-Risk Collateral:** Borrowers using blue-chip assets (e.g., WETH) may pay only the Base Rate (Quota Rate = 0%). * **High-Risk Collateral:** Borrowers using volatile or less liquid assets must pay the Base Rate plus a significant Quota Rate (e.g., +5%). This ensures that borrowers using safe collateral do not subsidize the risk of those using volatile collateral, improving capital efficiency for low-risk strategies while properly pricing tail risk. #### Learn More * **Base interest calculation:** How does pool utilization determine the underlying cost of capital? * [interest-rate-model](https://docs.gearbox.finance/core/interest-rate-model) * **Parameter configuration:** Who configures these limits and what parameter ranges are allowed? * [risk-configuration-dictionary](https://docs.gearbox.finance/core/risk-configuration-dictionary) * **Protocol fees:** How is interest revenue captured and shared between the Protocol DAO and the Market Curator? * [dao-and-curators-business-model](https://docs.gearbox.finance/core/dao-curators-business-model) ## Liquidation Dynamics Source: https://docs.gearbox.finance/core/liquidation-dynamics File: content/core/liquidation-dynamics.mdx The solvency of a Credit Account is determined deterministically on-chain. If an account's risk-adjusted value falls below its liabilities, the protocol enforces liquidation to protect liquidity providers. ### Solvency Definition: The Health Factor The core metric for solvency is the **Health Factor (HF)**. $$ HF = \frac{TWV}{Total Debt} $$ Where: * **TWV (Total Weighted Value):** The risk-adjusted, quota-limited value of the collateral assets, measured in the underlying token. * **Total Debt:** The total amount of underlying token owed, including principal, accrued interest, and quota interest. #### Total Weighted Value (TWV) TWV represents the maximum debt the current collateral portfolio can support. Unlike standard Net Asset Value, Gearbox discounts collateral based on its **Liquidation Threshold (LT)** and caps it by the **Quota** allocated to that asset. $$ TWV = \frac{\sum\_{i}^{MaxEnabledTokens}{\min{(Quota\_i, Balance\_i \times Price\_i \times LT\_i)}}}{Price\_{underlying}} $$ * **Quota\_i**: The specific portion of the account's debt limit allocated to token i. * **Balance\_i**: The balance of token i in the Credit Account. * **Price\_i**: The current oracle price of token i. * **LT\_i**: The Liquidation Threshold for token i. * **Price\_{underlying}**: The current oracle price of the underlying borrowed asset. > **Note:** The `min` function ensures that a specific collateral asset cannot secure more debt than its allocated Quota allows, regardless of its market value. #### Liquidation Condition An account is liquidatable if: 1. **HF < 1**: The TWV is less than the Total Debt. 2. **Expiration**: The Credit Manager has reached its maturity date (for fixed-term strategies). ### Partial Liquidation (Deleverage) To prevent total loss of user positions during minor market dips, the protocol supports **Partial Liquidation**. This mechanism sells only enough collateral to restore the Health Factor to a safe level, rather than closing the entire position. This process is typically executed by a specialized Deleverage Bot. #### Execution Logic When HF drops below a configured `minHF` (but is typically still > 1), the bot executes a deleveraging transaction: 1. Calculates the amount of collateral required to be sold to raise HF to `targetHF`. 2. Repays a portion of the debt. 3. Charges a reduced premium compared to full liquidation. #### Configuration Parameters | Parameter | Description | | ---------------- | --------------------------------------------------------------------------------------- | | **minHF** | The threshold triggering partial liquidation (e.g., 1.05). | | **maxHF** | The target Health Factor after deleveraging. | | **PremiumScale** | The percentage of the full Liquidation Premium charged (e.g., 50% of standard premium). | ### Full Liquidation If Partial Liquidation is insufficient or if HF drops significantly below 1, a **Full Liquidation** occurs. The liquidator repays the total debt and claims the collateral assets at a discount. #### Total Value Calculation Liquidation math relies on the **Total Value** of the account (undiscounted NAV), measured in the underlying token. $$ Total Value = \frac{\sum\_{i}^{MaxEnabledTokens}{Balance\_i \times Price\_i}}{Price\_{underlying}} $$ #### Liquidator Incentive The liquidator receives the collateral assets valued at a discount (the Liquidation Premium). $$ LiquidatorProfit = TotalValue \times LiquidationPremium - GasCost $$ #### Borrower Loss The borrower loses the collateral used to pay the debt, the premium, and the protocol fee. $$ AccountLoss = \min(TotalValue \times (LiquidationPremium + LiquidationFee), TotalValue - Total Debt) $$ * **Liquidation Premium:** Paid to the liquidator. * **Liquidation Fee:** Paid to the Protocol (Curator & DAO). ### Bad Debt & Socialization **Bad Debt** occurs when a Credit Account is liquidated while its **Total Value** is less than its **Total Debt**. #### Resolution Mechanism 1. **Fee Buffer:** Unclaimed protocol fees (Curator/DAO share) are burned to cover the deficit. 2. **Socialization:** If fees are insufficient, the remaining loss is socialized among Liquidity Providers by reducing the exchange rate of the Diesel Token (LP token). #### Learn More * **Data sources:** How does the protocol obtain asset prices for Total Weighted Value (TWV) calculations? * [price-oracle](https://docs.gearbox.finance/core/price-oracle) * **Parameter control:** Who sets liquidation thresholds (LT), premiums, and fees? * [risk-configuration-dictionary](https://docs.gearbox.finance/core/risk-configuration-dictionary) * **Quota mechanics:** How are quota limits defined and adjusted? * [quota-controls](https://docs.gearbox.finance/core/collateral-limits-specific-rates) ## Deleverage bot Source: https://docs.gearbox.finance/core/deleverage-bot File: content/core/deleverage-bot.mdx ### Deleverage - protection against liquidations The deleverage bot is designed to protect Gearbox users from full liquidations by automatically reducing leverage when an account’s health factor (HF) falls below a safe threshold. It acts as an early warning mechanism selling a small portion of collateral to restore safety before liquidation conditions are met. By doing so, the bot helps maintain protocol stability, safeguards user positions, and ensures smooth, market-driven deleveraging without requiring manual intervention or external subsidies. ### How to connect a bot Any user can connect a bot directly through the UI. From a technical standpoint, bot deployment is fully permissionless, users do not need approval from the DAO or a curator to deploy or connect a bot. However, for a bot to appear and be connectable via the UI, it must first be whitelisted there. ### Bot fees When a deleveraging event occurs, two types of fees are distributed: * **Premium:** Paid to the liquidator (deleverager) who executes the deleverage transaction. This serves as the direct incentive for running a bot and maintaining system safety. * **Fee:** Sent to the protocol treasury as the protocol’s share from the operation. ### Bot parameters | minHF | The threshold at which the bot starts deleveraging. When a user’s HF falls below this value, the bot begins selling part of their collateral to restore stability. | | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | maxHF | The upper limit to which the bot is allowed to increase a user’s HF during a deleveraging operation. The bot will not push the HF above this value. The target HF for each operation lies somewhere between minHF and maxHF, depending on market conditions and the available liquidity. | | PremiumScale | Defines how much of the Credit Manager’s liquidation premium is taken as the deleverage premium. A value of 100% means the bot receives the same premium as a liquidator would. | | FeeScale | Specifies the fraction of the protocol fee applied to deleveraging. Typically set to 100%, aligning it with the standard liquidation fee. | ### **Rationale Behind Selecting Bot Parameters** #### **1. Primary Goal – Prevent Full Liquidations** The main purpose of the deleverage bot is to **protect users from full liquidations**. * The `minHF` (health factor at which deleverage is triggered) should be high enough so that a sudden drop in collateral value doesn’t make an account liquidatable immediately. * This gives the bot a time window to act and deleverage before liquidation occurs. * **Example:** If **WETH** is the collateral and we want to protect users from a **10% short-term price drop**, then: ``` minHF = 1 + 0.10 = 1.1 ``` *** #### **2. Avoid Triggering Under Normal Conditions** Deleveraging should **not** happen during ordinary market fluctuations. * Therefore, `minHF` should be **as low as possible**, ensuring that minor price deviations do not trigger unnecessary deleveraging. *** #### **3. Minimize Collateral Sold Per Event** The amount of collateral sold in a single deleveraging event should be minimized. * To achieve this, `maxHF` should be set **as close as possible to `minHF`**, limiting the size of each operation. *** #### **4. Ensure Organic Profitability** Deleveraging operations should be **naturally profitable** to encourage participation from external bots without requiring subsidies. * Set `PremiumScale` and `FeeScale` to **100%**, meaning the **deleverage premium = liquidation premium**. * The scale defines how much of the Credit Manager’s liquidation premium is allocated to deleveraging. * `maxHF` should be high enough so that both the **liquidation size** and **premium** are meaningful in dollar terms. *** #### **5. Keep Minimal Position Size Reasonable** The minimum position size (Credit Manager’s minimum debt) should not be too large. * The target for the **minimum position size** is around **$10,000**. ## Price Oracle Source: https://docs.gearbox.finance/core/price-oracle File: content/core/price-oracle.mdx The Price Oracle serves as the protocol's central valuation engine. Its primary function is to ingest raw price data from diverse external sources and standardize it into a uniform format that the Credit Manager and Pool contracts can consume mathematically. ### Data Normalization DeFi assets vary significantly in their technical specifications, particularly regarding decimal precision (e.g., USDC uses 6 decimals, WETH uses 18). To prevent calculation errors and complexity within the risk engine, the Price Oracle enforces a strict normalization standard. **The 8-Decimal Standard**\ Regardless of the underlying token's decimals or the external feed's native precision, the Gearbox Price Oracle always returns prices scaled to **8 decimals**. * **Input:** Raw data from Chainlink (8 decimals), Uniswap (18 decimals), or USDC (6 decimals). * **Process:** The Oracle wrapper scales the value up or down mathematically. * **Output:** A standardized USD price where `1.00` is represented as `100,000,000`. This uniformity allows the Credit Manager to perform solvency checks ($HealthFactor > 1$) using a single, consistent formula across all collateral types. ### Staleness Enforcement To ensure solvency calculations reflect current market reality, the Price Oracle enforces strict data freshness constraints. Every price feed is configured with a specific `stalenessPeriod` (measured in seconds), typically derived from the feed provider's heartbeat or update frequency. * **The Check:** Upon every transaction requiring a price (e.g., borrowing, liquidating), the Oracle compares the current `block.timestamp` against the feed's `updatedAt` timestamp. * **The Revert:** If `block.timestamp - updatedAt > stalenessPeriod`, the transaction reverts immediately. This mechanism prevents the protocol from accepting invalid collateral or allowing under-collateralized borrowing during periods of oracle downtime or network congestion. ### Feed Types The protocol supports various data methodologies depending on the asset's liquidity profile and available onchain data. These are categorized into three primary mental models. #### 1. Spot Feeds Spot feeds provide the current market price based on off-chain aggregation or high-frequency on-chain updates. These are typically used for highly liquid "Blue Chip" assets where the price discovery happens on centralized exchanges or deep DEX pools. * **Push Models:** Traditional oracles where nodes push updates onchain at defined intervals or deviation thresholds (e.g., Chainlink, Redstone Push). * **Pull Models:** On-demand oracles where the price update is cryptographically signed off-chain and pushed onchain only when needed by a transaction (e.g., Pyth, Redstone Pull). This model reduces gas costs and allows for higher frequency updates. * **Use Case:** WETH, WBTC, USDC. #### 2. TWAP Feeds (Time-Weighted Average Price) TWAP feeds calculate the average price of an asset over a specific period (e.g., 30 minutes). This methodology dampens volatility and increases the cost of manipulation for assets that rely primarily on decentralized exchange liquidity. * **Mechanism:** Queries the cumulative price accumulator from an AMM (Automated Market Maker) and divides by the time elapsed. * **Use Case:** Curve LP Tokens, Pendle PTs, or long-tail assets where spot liquidity is thin. #### 3. Fundamental Feeds (Derived Value) Fundamental feeds determine value based on the on-chain backing or exchange rate of the asset, rather than secondary market trading activity. These feeds calculate what the asset is "worth" in terms of its underlying reserves. * **Mechanism:** Reads the `convertToAssets` or `getRate` function from the token contract and multiplies it by the underlying asset's USD price. * **Use Case:** ERC-4626 Vault Shares, Liquid Staking Tokens (LSTs), or Stablecoin peg-protection modules. ### Modular Pricing Architecture Beyond standard oracle integrations, Gearbox maintains a library of purpose-specific pricing contracts designed to collateralize complex DeFi positions. These modular feeds allow the protocol to support assets that lack direct secondary market feeds by programmatically deriving their value from the underlying protocol state: * **Curve & Balancer LPs:** Calculates the "Virtual Price" or fair value of the LP token based on the pool's invariant and the prices of the constituent tokens. * **Pendle PTs:** Derives the market price using a TWAP of the PT/SY exchange rate from the Pendle market contract. * **Bounded Feeds:** Wrappers that enforce upper or lower bounds on a price (e.g., capping a stablecoin at $1.00 or an LST at its backing ratio) to prevent manipulation during de-peg events. This architecture enables Curators to list productive assets (Vaults, LPs, Derivatives) as collateral without waiting for centralized oracle providers to support them. *** #### Learn More * **Safety & manipulation resistance:** How does the system protect against oracle manipulation and extreme market conditions? * [dual-oracle-system](https://docs.gearbox.finance/core/dual-oracle-system) ## Smart Oracles Source: https://docs.gearbox.finance/core/smart-oracles File: content/core/smart-oracles.mdx ## Safety-first design Gearbox oracle and solvency checks structure allows creating pricing methods with unique features: * Attract borrowers using hardcoded/ fundamental oracles + protect LPs by always taking market price into account.\ Read more: [dual-oracle-system](https://docs.gearbox.finance/core/dual-oracle-system) * Ensure timely liquidations using market oracles + protect LPs by always taking collateral fundamental value into account.\ Read more: [loss-policy](https://docs.gearbox.finance/core/loss-policy) ## Optimized for DeFi, scalable by default Gearbox supports major price feed providers, including Chainlink, Redstone (both pull and push models), and Pyth. Custom audited smart-contract feeds allow pricing of DeFi assets, including Pendle PT, Curve & Balancer LP tokens and more.\ Read more: [price-oracle](https://docs.gearbox.finance/core/price-oracle) ## Dual-Oracle System Source: https://docs.gearbox.finance/core/dual-oracle-system File: content/core/dual-oracle-system.mdx The Dual-Oracle System is the primary defense layer against price manipulation and oracle failure. By decoupling the valuation source used for liquidations from the source used for user operations, Gearbox ensures that short-term volatility or manipulation in one feed cannot be exploited to drain protocol liquidity. ### Dual-Feed Architecture Every asset in a Gearbox Market is configured with two independent price feeds. The protocol applies distinct logic to each feed depending on the context of the transaction. #### 1. Main Feed (Solvency & Liquidation) The **Main Feed** serves as the authoritative source for the system's internal accounting. * **Role:** Determines the Health Factor ($H\_f$) for liquidation triggers. * **Objective:** To reflect the asset's valuation for long-term solvency. #### 2. Reserve Feed (Safety & Operations) The **Reserve Feed** acts as a sanity check for user-initiated actions. * **Role:** Validates solvency during collateral withdrawals, debt increases, or complex multicall executions. * **Objective:** To prevent users from exploiting temporary price divergences to withdraw more collateral than they are entitled to. ### Pricing Methodologies To understand the utility of the Dual-Oracle system, one must first distinguish between the two primary methodologies for pricing DeFi assets. #### 1. Fundamental Price (Hardcoded / Backing Value) Prices the token based on the reserves that back it or its exchange rate (e.g., `1 stETH = 1 ETH` or `1 Stablecoin = $1`). | Stakeholder | Pros | Cons | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Borrowers** | Stability: Minimal risk of liquidation due to temporary market de-pegs. Accuracy: Reflects true staking appreciation immediately. | — | | **Lenders** | **Manipulation Resistance:** Immune to low-liquidity DEX manipulation. | Insolvency Risk: May overprice assets during real backing failures. Liquidity Lock: Funds may become stuck if the market price drops below the fundamental price, removing incentives for repayment. | #### 2. Secondary Market Price Prices the token based on buy/sell activity on DEXes or CEXes. | Stakeholder | Pros | Cons | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Borrowers** | — | Capital Inefficiency: Must maintain higher Health Factors to buffer against volatility. Liquidation Risk: Susceptible to cascading liquidations during market panic. | | **Lenders** | Pessimistic Pricing: Liquid tokens usually trade at a discount to backing, providing a safety buffer. Reactivity: Fast reaction to real market drops. | Manipulation Risk: Illiquid markets can be pumped to drain pool reserves at inflated valuations. Bad Debt: Liquidation cascades can lead to overselling collateral below debt value. | ### Comparison Logic: The "Safe Price" When a Credit Account executes a transaction that reduces its collateralization (e.g., withdrawing funds or borrowing more), the protocol calculates the account's value using the **Safe Price**. The Safe Price is derived dynamically for every asset in the portfolio: $$ P\_{Safe} = \min(P\_{Main}, P\_{Reserve}) $$ This `min()` logic creates an automatic circuit breaker. If the Main Feed and Reserve Feed diverge, the protocol enforces the lower (more pessimistic) valuation for all user operations, preventing the extraction of value during de-pegs or manipulation events. ### Scenario Analysis: The "Best of Both Worlds" By configuring the **Main Feed** as a Fundamental source and the **Reserve Feed** as a Market source, Gearbox protects lenders from manipulation while preserving capital efficiency for borrowers. The table below illustrates a scenario where a collateral token (e.g., sUSDe or deUSD) is used to borrow a stablecoin (USDC). | Scenario | Dual-Oracle System | Hardcoded Feed Only | Market Feed Only | | ------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Market price drops > 2.5% (Normal Volatility) | ✅ No Liquidations Main feed remains stable. | ✅ **No Liquidations** | ⚠️ Liquidations Triggered Risky positions are closed due to volatility. | | Market price drops > 10% (De-peg / Panic) | ⚠️ No Liquidations ✅ Withdrawals Blocked Safe Price uses the lower Market price ($0.90). Users cannot withdraw the "overvalued" asset, trapping liquidity in the protocol until solvency is resolved. | ⚠️ No Liquidations 🚨 Attack Vector: Attacker buys asset at $0.90, borrows $0.915 against it (at Face Value). Result: Protocol drained; Bad Debt created. | 🚨 Mass Liquidations Major portion of positions liquidated, potentially crashing price further. | | Market price pumps > 2.5% (Normal Volatility) | ✅ **No Liquidations** | ✅ **No Liquidations** | ✅ **No Liquidations** | | Market price pumps > 10% (Illiquid Market Manipulation) | ✅ No Liquidations ✅ Borrowing Blocked Safe Price uses the lower Fundamental price ($1.00). User cannot borrow against the inflated Market price ($1.10). | ✅ **No Liquidations** | ✅ No Liquidations 🚨 Attack Vector: Attacker mints asset at $1.00, pumps market to $1.10, borrows $1.02. Result: Protocol drained due to inflated valuation. | ### Circuit Breakers & Interaction Blocking The Dual-Oracle system enforces logic that effectively forbids interactions when data integrity is compromised. #### Transaction-Level Blocking The system does not require a global pause to stop exploits. It blocks individual transactions based on real-time data divergence: * **Withdrawal Block:** If $P\_{Main} \gg P\_{Reserve}$, the user's borrowing power is constrained by $P\_{Reserve}$. Users cannot withdraw funds based on the inflated Main price. * **Liquidation Protection:** Liquidations rely solely on the **Main Feed**. If the Main Feed is accurate but the Reserve Feed is broken/manipulated, liquidations can still proceed to keep the pool solvent, while user withdrawals (which require Reserve validation) are temporarily blocked to prevent capital flight. #### Divergence Thresholds While the protocol uses the `min()` logic continuously, significant divergence between Main and Reserve feeds serves as an off-chain signal for Risk Curators. * **Soft Breaker:** Small deviations are absorbed by the `min()` logic, simply reducing capital efficiency slightly. * **Hard Breaker:** Large deviations typically indicate a de-peg or oracle failure. In these scenarios, the `min()` logic effectively freezes new borrowing and withdrawals for that specific asset until the feeds converge or the Instance Owner updates the configuration. *** #### Learn More * **Bad debt handling:** How does the protocol handle bad debt if price safety mechanisms fail? * [loss-policy](https://docs.gearbox.finance/core/loss-policy) * **Price feed sources:** Where do the raw Main and Reserve price feeds originate? * [](https://docs.gearbox.finance/core/smart-oracles) ## Loss Policy Source: https://docs.gearbox.finance/core/loss-policy File: content/core/loss-policy.mdx ### The Problem: Market Price Cascades Using market oracles can sometimes trigger liquidation cascades, where a rapid price drop causes mass liquidations and further depresses the asset’s price. An example is the [ezETH cascading liquidations in April 2024](https://www.google.com/url?sa=E\&q=https%3A%2F%2Fprotos.com%2Fdepeg-of-3b-restaking-token-ezeth-causes-over-60m-in-defi-liquidations%2F). ![Figure](https://docs.gearbox.finance/assets/docs/core/loss-policy/01-the-problem-market-price-cascades.png) When prices fall too quickly, liquidators may be unable to react in time. As a result, positions can become insolvent before liquidation completes. In such scenarios, continuing to liquidate at the current market price may actually create bad debt, because collateral can be sold far below its fair or medium-term value. ### The Solution: Aliased Pricing To protect liquidity providers (LPs) in these situations, Gearbox implements a Loss Policy mechanism. **The logic is as follows:** 1. Positions are liquidated using market prices under normal conditions. 2. If a liquidation would create bad debt (Collateral Value < Debt), the protocol reprices the collateral using the **aliased price**, which can be configured to the asset’s fundamental value (e.g., Exchange Rate or 1.00 for stablecoins). 3. If the position is healthy under this fundamental pricing, the liquidation is halted. ![Figure](https://docs.gearbox.finance/assets/docs/core/loss-policy/02-loss-policy-protected-pool-flow.png) ### Execution Flow The Loss Policy acts as a conditional circuit breaker during the liquidation process. 1. **Standard Check:** Is Health Factor < 1 using the **Main Feed** (Market Price)? * **No:** Account is healthy. Do nothing. * **Yes:** Proceed to step 2. 2. **Bad Debt Check:** Does `Collateral Value < Debt`? * **No:** Liquidation proceeds normally. Liquidator repays debt and claims collateral. * **Yes:** The liquidation is flagged as a "Loss Liquidation". Proceed to step 3. 3. **Fundamental Check:** Is Health Factor < 1 using the **Aliased Feed** (Fundamental Price)? * **No:** The protocol assumes the market price is temporarily dislocated (flash crash). Liquidation is blocked to prevent realizing the loss at a distressed price. * **Yes:** The asset is fundamentally insolvent. Liquidation proceeds. #### Learn More * **Bad debt acknowledgment:** What happens when a liquidation proceeds under the Loss Policy and bad debt is realized? * [liquidation-dynamics](https://docs.gearbox.finance/core/liquidation-dynamics) ## DAO & Curators' business model Source: https://docs.gearbox.finance/core/dao-curators-business-model File: content/core/dao-curators-business-model.mdx ### Interest Fee (Revenue from Borrowing) The **Interest Fee** is the primary revenue source for the protocol and curators. It is a percentage markup applied to the borrowing interest paid by users. #### How It Works Unlike some protocols where the protocol fee is subtracted from the yield paid to liquidity providers (a “rake”), Gearbox uses an **additive model**. The fee is added on top of the base interest rate. * **Base & Collateral-specific Rate**\ The rate determined by the Interest Rate Model (IRM) plus any collateral-specific adjustments.\ \&#xNAN;*This portion is paid entirely to Liquidity Providers.* * **Interest Fee**\ A percentage markup applied to the Base Rate.\ \&#xNAN;*This portion is paid to the Market Curator and the Gearbox DAO.* #### Borrower Rate Formula $$ Rate\_{Borrower} = (Rate\_{Base} + Rate\_{Collateral-specific}) \times (1 + Fee\_{Interest}) $$ #### Example Calculation If market conditions dictate a base rate of **5%**, and the Curator has configured an Interest Fee of **20%**: 1. **Liquidity Providers earn:** 5.00% 2. **Protocol markup:** 5.00% x 20% = 1.00% 3. **Borrower pays:** 6.00% *** ### Revenue Split By default, all collected Interest Fees are split: * **50%** → Market Curator * **50%** → Gearbox DAO *** *** ### Liquidation Economics (Revenue from Risk) When a Credit Account becomes insolvent, it is liquidated. During liquidation, penalties are applied to the borrower for two purposes: * Incentivizing liquidators * Generating protocol revenue #### Components | Component | Recipient | Purpose | | ----------------------- | ------------- | -------------------------------------------------- | | **Liquidation Premium** | Liquidator | Incentive (“bounty”) for executing the liquidation | | **Liquidation Fee** | DAO & Curator | Protocol revenue from the liquidation | ## Insurance & Solvency Reserves Source: https://docs.gearbox.finance/core/insurance-solvency-reserves File: content/core/insurance-solvency-reserves.mdx The Gearbox Protocol employs an automated, on-chain reserve system designed to absorb bad debt and protect Passive Lenders. This mechanism functions not as an external insurance policy, but as a **retention buffer** on protocol revenue. Its primary objective is to ensure that the Liquidity Pool remains solvent even if a borrower's position is liquidated below the value of their debt. ### Conceptual Overview In traditional finance, this is analogous to a "First-Loss Capital" tranche. The protocol generates revenue through interest rates and liquidation fees. Rather than distributing 100% of this revenue to the DAO or Market Curators immediately, the system enforces a **mandatory savings threshold**. 1. **Revenue Accumulation:** All protocol fees flow into a specific contract (`TreasurySplitter`). 2. **The Safety Floor:** A target insurance amount is defined (e.g., 100,000 USDC). 3. **Conditional Distribution:** * **Below Target:** If reserves are below the target, **100% of revenue is retained**. No profit is distributed. * **Above Target:** Only the *excess* revenue (surplus) is distributed to the DAO and Curators. This ensures the protocol prioritizes solvency over profit extraction. *** ### Architecture: The Treasury Splitter The core component governing this logic is the `TreasurySplitter` contract. It acts as a gatekeeper between protocol fees and profit recipients. #### The Distribution Logic The `TreasurySplitter` holds assets (typically LP tokens of the pool it protects). When a distribution is attempted, the contract performs a logic check against the `tokenInsuranceAmount`. #### The Asset Composition The Insurance Fund does not sit idle. It is typically held in **LP Shares** (Diesel Tokens) of the pool it insures. This aligns the Treasury's interests with the Lenders' interests and allows the insurance capital to earn yield while waiting to be used. *** ### Bad Debt Coverage Mechanism "Bad Debt" occurs when a Credit Account is liquidated, but the collateral value is insufficient to repay the debt to the pool. Without insurance, this loss would be socialized among all Lenders (reducing the value of their LP tokens). The Insurance mechanism intervenes to prevent this socialization. #### The Coverage Flow 1. **Liquidation Event:** A liquidator closes a non-solvent Credit Account. The remaining collateral is sold, but a deficit remains (e.g., Debt: 100k, Collateral Value: 98k, Deficit: 2k). 2. **Loss Recognition:** The Credit Manager reports the loss to the Pool. 3. **Treasury Absorption:** The Pool burns **LP Shares held by the Treasury** equal to the value of the loss. By burning the Treasury's shares, the total supply of LP shares decreases, while the underlying assets in the pool remain (mostly) constant relative to the remaining Lenders. The Treasury effectively "pays" for the loss by giving up its claim on the pool's liquidity. *** ### On-Chain Verification Market participants can verify the solvency health of a pool by querying the `TreasurySplitter` contract directly. #### 1. Verify the Insurance Target (The Floor) To determine the minimum safety buffer the protocol enforces: * **Function:** `tokenInsuranceAmount(address token)` * **Interpretation:** This is the "water level." The protocol will not allow profit-taking if reserves drop below this value. #### 2. Verify Current Reserves (The Buffer) To determine the actual capital available to absorb losses: * **Function:** `IERC20(token).balanceOf(address treasurySplitter)` * **Interpretation:** * If `Balance > InsuranceAmount`: The pool is fully insured and generating surplus. * If `Balance < InsuranceAmount`: The pool is building reserves; all fees are currently being retained to increase safety. #### 3. Monitor Governance Changes Changes to insurance parameters require a dual-signature process (Curator + DAO). * **Function:** `activeProposals()` * **Interpretation:** Returns pending changes to the insurance floor or distribution logic. This allows Lenders to see if a Curator is attempting to lower safety parameters. *** ## Treasury-insured pools By default, all fees that the DAO receives from the protocol are made in dTokens. However, DAO can manage this by unwrapping part of the funds from the pools (thus, instead of dTokens, DAO will receive the usual underlying asset of the pool aka idle assets). This way, the DAO can limit its earnings from the Reserve Fund exposure. Essentially, the Gearbox dTokens inside this Fee Guard are the Insurance Fund. Anything that is not in dTokens has likely been voted to be unwrapped and kept as non Insurance Fund. Any non-dTokens are not counted towards the Insurance Fund size. And this only applies to V3 contracts. > > > This address holds all the fees accumulated. However, on the topic of the Reserve Fund, only look at the balances of dTokens. No other assets are relevant to the Reserve Fund. This Reserve Fund model doesn't relate to actual software hacks. It specifically covers cases of under-collateralization during liquidations. ### Learn more ## Audits & Bug Bounty Source: https://docs.gearbox.finance/core/audits-bug-bounty File: content/core/audits-bug-bounty.mdx Keep in mind that no number of audits can guarantee full safety. There are always high risks involved in DeFi, as many platforms are composable and depend on each other. There is no guaranteed return on Gearbox - you must **understand the risks involved**. ## Audits ![Figure](https://docs.gearbox.finance/assets/docs/core/audits-bug-bounty/01-gearbox-protocol-gear-audits-abdk-chain-security-sigma-prime.png) Gearbox protocol and its modules have been audited multiple times by top-tier security teams. For the full up-to-date list of contracts and reports please refer to [Bytecode Repository](https://permissionless.gearbox.foundation/bytecode), which acts as a source of truth for verification of each deployed contract. *** ## Bug Bounty The scope of the bug bounty refers to these contracts: []() Rewards are distributed according to the impact of the vulnerability. The final decision on the payout amount will be determined by the Gearbox DAO developers at their discretion. | Severity | Payment in USDC / other stablecoin | | |---|---|---| | Low | $100 - $1K | | | Medium | $1K - $5K | | | High | $5K - $20K | | | Critical | $20K - $200K (+ GEAR) | | For all assets labeled as “Gearbox v1” or "Gearbox v2" and deployed on the Ethereum network, only Critical and High impacts are in-scope. If you have found a bug that you think is within the security interests of the protocol but is outside of the scope of the repository above, please do notify us then anyway. We can decide ad-hoc together with you. 1/1 payouts have been done before based on this. Join the Bug Bounty with Immunefi! Help Gearbox stay safe and be rewarded for it. ![Figure](https://docs.gearbox.finance/assets/docs/core/audits-bug-bounty/02-bug-bounty.png) https://immunefi.com/bounty/gearbox/ If you need more information on the protocol, please check: * Regular protocol docs: [/ ](/) * Developer docs: **NOTE**: for bugs related to the interface which are just referring to typos and non-security related issues, please feel free to report them in a community [Discord](https://discord.gg/5YuHH9tvms) pro bono - and Gearbox community can maybe send nice GIFs your way. In case a bug you found is related to the interface and is outside of the scope, but has serious security concerns, please do report it as well and a bounty can be also decided ad-hoc. Again, you can ask all your questions in [Discord](https://discord.gg/JZgvmaenwn). ### Rules Determinations of eligibility, score and all terms related to an award are at the sole and final discretion of Gearbox Protocol working DAO members. The goal is to make sure the ecosystem is safe, and that proper bug bounty work is rewarded well. In order to be considered for a reward, all bug reports must contain the following: * Description of suspected vulnerability * Steps to reproduce the issue so we can check it * Your name and/or colleagues if you wish to be later recognized * (Optional) A patch and/or suggestions to resolve the vulnerability The following activities are **prohibited** by bug bounty program: * Testing with mainnet or public testnet contracts: all testing should be done on private testnets * Any testing with pricing oracles or third party smart contracts * Attempting phishing or other social engineering attacks against our employees and/or customers * Any testing with third party systems and applications (e.g. browser extensions) as well as websites (e.g. SSO providers, advertising networks) * Any denial of service attacks * Automated testing of services that generates significant amounts of traffic * Public disclosure of an unpatched vulnerability in an embargoed bounty Security is a continuous effort which must always be following protocol growth. As a DAO, it is imperative to constantly dedicate ample resources to ensure safety of funds. ## Market Curators Source: https://docs.gearbox.finance/core/market-curators File: content/core/market-curators.mdx The **Market Curator** is the operator of a specific lending market instance. Unlike traditional asset managers who actively allocate capital, Gearbox Curators act as **Risk Parameter Managers**. They define the boundary conditions—such as Loan-to-Value ratios, interest rate curves, and allowed collateral—under which the market operates. This role is permissionless: any entity can deploy a Market Configurator and launch a lending business on top of the Gearbox Protocol. ### Operational Model: Parameters, Not Funds The Curator does not have custody of user funds. Instead, the Curator manages a set of smart contracts that enforce rules on how funds can be utilized. ![Figure](https://docs.gearbox.finance/assets/docs/core/market-curators/01-operational-model-parameters-not-funds.png) * **No Custody:** Curators cannot withdraw Liquidity Provider (LP) funds or seize Borrower collateral (except via standard liquidation mechanics). * **No Active Allocation:** Curators do not manually move funds between strategies. They set the *eligibility* rules (e.g., "Strategy A is allowed up to $10M debt"), and the protocol automatically manages the flow based on user demand. ### Role Architecture To balance operational agility with security, Curator powers are segregated into distinct roles. These are typically assigned to different multisigs or governance controllers depending on the Curator's internal structure. #### 1. The Administrator (Governance) The ultimate authority for the market. This address controls the **Market Configurator** contract. * **Capabilities:** Can modify all risk parameters (LTVs, Supply Caps, Interest Models, Fee Splits). * **Constraint:** All actions are subject to a mandatory **Timelock** (see below). #### 2. The Emergency Admin (Security) A specialized role designed for crisis response. It has a limited subset of powers that bypass the timelock to prevent bad debt or exploits. * **Capabilities:** * Pause contracts (freeze borrowing/withdrawals). * Set debt limits to zero (stop new borrowing). * Forbid specific adapters or tokens (stop exposure to risky assets). * **Constraint:** Cannot *increase* risk (e.g., cannot raise LTVs or debt limits). Can only restrict operations. #### 3. Operational Roles Granular roles for day-to-day maintenance without full administrative access. * **Pausable/Unpausable Admin:** Can freeze or unfreeze specific market contracts. * **Fee Multisig:** Designated recipient for accrued protocol fees. * **Emergency Liquidator:** Whitelisted address permitted to liquidate positions when the market is paused. ### Safety Constraints: The Timelock To protect users from malicious or erroneous parameter changes, the protocol enforces a **Time-Delayed Execution** model for the Administrator role. * **The Rule:** Any transaction that alters a risk parameter (e.g., changing LTV from 80% to 90%) must be queued in the Timelock contract for a minimum of **24 hours** before execution. * **The Purpose:** This delay guarantees that Lenders and Borrowers have sufficient time to audit pending changes and exit the market if they disagree with the new risk profile. ### Economic Model Curators monetize their markets by configuring specific fee parameters. These fees are programmatic and deducted automatically by the smart contracts. #### Revenue Sources 1. **Interest Fee:** A percentage of the interest paid by borrowers. This is added on top of the base rate paid to Lenders. 2. **Liquidation Fee:** A percentage of the collateral value seized during a liquidation event. #### Fee Sharing The Gearbox Protocol infrastructure takes a share of the revenue generated by Curators to sustain the DAO and core development. * **Default Split:** 50% to the Curator / 50% to the Protocol DAO. * **Configuration:** This split is enforced at the `TreasurySplitter` contract level. #### Learn More * **Parameter reference:** Where can I find a comprehensive dictionary of all configurable risk parameters and their constraints? * [risk-configuration-dictionary](https://docs.gearbox.finance/core/risk-configuration-dictionary) ## Instance Owner Source: https://docs.gearbox.finance/core/instance-owner File: content/core/instance-owner.mdx The Instance Owner is a chain-specific technical multisig responsible for maintaining the integrity of the local Gearbox deployment. It acts as a **technical gatekeeper**, ensuring that critical infrastructure, specifically the Price Feed Store, remains secure, verified, and consistent across networks. Unlike Market Curators, who manage financial risk parameters, the Instance Owner operates under a strict mandate of **business neutrality**. It does not assess the economic viability of assets or strategies but ensures the underlying data feeds function correctly. ### The Neutrality Principle Gearbox enforces a strict separation between **Technical Maintenance** and **Financial Risk Management**. * **Market Curators (Financial Layer):** Responsible for setting LTVs, interest rates, and supply caps. They bear the economic risk of their decisions. * **Instance Owner (Infrastructure Layer):** Responsible for verifying that a price feed contract is technically sound, correctly configured, and secure. The Instance Owner does not gatekeep assets based on quality or volatility. If a Curator wishes to list a volatile asset, the Instance Owner’s sole responsibility is to ensure the requested price feed (e.g., Chainlink, Redstone, or TWAP) is implemented correctly and added to the registry. This prevents technical misconfigurations—such as decimal errors or stale feed pointers—without interfering in the free market of credit strategies. ### Core Responsibilities #### Price Feed Store Management The primary function of the Instance Owner is the management of the **Price Feed Store**, the onchain registry of allowed price sources for a specific network. Before a Curator can list an asset in a Credit Manager, the asset and its corresponding price feed must be whitelisted in the Price Feed Store. The Instance Owner verifies: 1. **Contract Verification:** The feed contract is verified on the block explorer. 2. **Source Integrity:** The feed points to the correct aggregator address (e.g., the official Chainlink or Pyth contract for that chain). 3. **Technical Specification:** The feed returns data in the format required by the Credit Manager (typically 8 decimals). Once verified, the Instance Owner adds the feed to the store, making it available for any Curator to use. * [**See: Price Oracle Architecture**](https://www.google.com/url?sa=E\&q=..%2Feconomics-and-risk%2Fprice-oracle.md) #### Protocol Upgrades & Maintenance While the Protocol DAO votes on global upgrades and new contract versions, the Instance Owner executes the specific transactions required to apply these updates to the local chain instance. This ensures that upgrades are applied atomically and correctly within the context of the specific network environment. ### Multisig Composition To maintain neutrality and prevent censorship, the Instance Owner multisig is composed of a diverse set of ecosystem participants. This structure ensures that no single entity can block a valid technical integration. **Typical Composition:** * **Threshold:** 4-of-12 (Subject to chain-specific configuration) * **Signers:** * Active Market Curators * Chain Foundation Contributors * Security Auditors * Partner Protocol Founders * Gearbox Core Contributors This broad distribution prevents the Instance Owner from becoming a point of centralization while maintaining a high bar for technical competence among signers. ![Figure](https://docs.gearbox.finance/assets/docs/core/instance-owner/01-credit-configurator-graph.png) ## Protocol DAO Source: https://docs.gearbox.finance/core/protocol-dao File: content/core/protocol-dao.mdx Unlike traditional DeFi protocols where the DAO manages risk parameters (like LTVs or Interest Rates) directly, Gearbox delegates these operational responsibilities to **Market Curators**. The DAO focuses on building the rails, while Curators operate the trains. ### Core Responsibilities #### 1. System Upgrades & Versioning The DAO maintains the core smart contracts that define the protocol's logic. It is the only entity capable of authorizing new versions of system components. * **Contract Updates:** The DAO votes to deploy and authorize new implementations of core contracts (e.g., `PoolV3`, `CreditManagerV3`). * **Bytecode Repository:** The DAO manages the onchain registry of verified contract bytecode. This ensures that when Curators deploy new markets, they are using secure, audited code approved by the protocol. #### 2. Chain Activation The DAO controls the expansion of the protocol to new blockchain networks. * **Instance Deployment:** Before Gearbox can operate on a new chain (e.g., Arbitrum, Optimism), the DAO must authorize the deployment of the **Instance Owner** and **Treasury** contracts on that network. * **Canonical Addressing:** The DAO ensures that there is a single, canonical instance of the protocol infrastructure on each supported chain, preventing fragmentation. #### 3. Economic Alignment (GEAR Token) The DAO utilizes the GEAR token to incentivize growth and align the interests of Curators, Liquidity Providers (LPs), and the protocol. * **Incentive Programs:** The DAO can vote to allocate GEAR tokens for liquidity mining or grants to bootstrap specific markets or integrations. * **Fee Split Configuration:** While Curators set the total fees for their markets, the DAO defines the protocol-level **Fee Split** (e.g., 50/50 split between Curator and DAO). Changing this global parameter requires a DAO vote. ### Limits of Authority To preserve the permissionless nature of the protocol, the DAO's power is strictly limited at the smart contract level. * **No Market Interference:** The DAO **cannot** change the risk parameters (LTVs, Liquidation Thresholds, Interest Rates) of a live market managed by a Curator. * **No Asset Management:** The DAO **cannot** seize or reallocate funds deposited into Curator-managed pools. This separation of powers ensures that Curators retain full sovereignty over their lending businesses. #### Learn More * **Risk management & operations:** Who manages risk parameters and oversees day-to-day market operations? * [market-curators](https://docs.gearbox.finance/core/market-curators) ## Protocol audits Source: https://docs.gearbox.finance/core/protocol-audits File: content/core/protocol-audits.mdx The **Bytecode Repository** is a core infrastructure component of Gearbox V3 designed to enable permissionless, multi-chain protocol expansion while maintaining strict security guarantees. It serves as a decentralized, on-chain registry for verified smart contract implementations. #### An On-Chain "GitHub" for Smart Contracts The Bytecode Repository acts as a decentralized version of a code hosting platform like GitHub, but for compiled EVM bytecode rather than source code. * **Versioned Catalog:** Like a GitHub repository with tags, it organizes contracts into **Domains** (e.g., `IRM` for interest rate models) and **Postfixes** (e.g., `_LINEAR`), allowing for semantic versioning (Major/Minor/Patch). * **Public vs. System Domains:** * **System Domains** (Core contracts like Credit Managers) are DAO-governed; updates require an on-chain vote. * **Public Domains** allow any developer to submit "plugins" (e.g., a new yield farming adapter). Once a developer's submission is verified, they "own" that identifier in the repository. * **Immutable Storage:** Instead of a centralized server, the contract uses **SSTORE2** to store the initialization code (init code) directly in the Ethereum state, ensuring it can never be deleted or modified. #### Protecting the Protocol Lifecycle The repository protects the protocol by decoupling the **upload** of code from its **deployment**, introducing a mandatory verification layer. **1. On-Chain Audit Verification** Before a contract can be deployed via the repository, it must be "audited" on-chain. This is not just a social claim; it is a cryptographic requirement: * **Approved Auditors:** The Gearbox DAO maintains a whitelist of approved auditor addresses in the `BytecodeRepository`. * **EIP-712 Attestations:** Auditors sign a specific `bytecodeHash`. This signature is submitted to the repository via `submitAuditReport`. * **Enforced Solvency:** The `deploy` function checks `isBytecodeAudited`. If a bytecode hash does not have a valid signature from an authorized auditor, the protocol will refuse to deploy it, preventing unverified or malicious code from entering the ecosystem. **2. Deterministic and Secure Deployment** The repository uses `CREATE2` to ensure that a contract deployed on Ethereum Mainnet will have the exact same address and code when deployed on L2s like Optimism or Arbitrum. * **Front-running Protection:** It mixes the deployer's address into the salt, preventing malicious actors from "sniping" a contract address before the legitimate user. * **Integrity Checks:** Upon deployment, the repository verifies that the resulting contract's `contractType` and `version` (via the `IVersion` interface) match the registry records. #### Key Security Features * **Init Code Blacklisting:** The DAO can permanently forbid specific `initCode` hashes (via `forbidInitCode`) if a vulnerability is found, effectively "bricking" that version and preventing any further deployments of it. * **Author Signatures:** Only the original author of the bytecode can upload it on Mainnet, preventing others from claiming ownership of a developer's work. * **Token-Specific Logic:** It handles edge cases (like USDT's non-standard transfer behavior) through `tokenSpecificPostfixes`, ensuring the correct specialized implementation is used for specific assets.
Sources * [contracts/global/BytecodeRepository.sol](https://github.com/Gearbox-protocol/permissionless/blob/master/contracts/global/BytecodeRepository.sol) * [specification.md](https://github.com/Gearbox-protocol/permissionless/blob/master/specification.md) * [contracts/interfaces/IBytecodeRepository.sol](https://github.com/Gearbox-protocol/permissionless/blob/master/contracts/interfaces/IBytecodeRepository.sol) * [contracts/traits/DeployerTrait.sol](https://github.com/Gearbox-protocol/permissionless/blob/master/contracts/traits/DeployerTrait.sol) * [script/UploadBytecode.s.sol](https://github.com/Gearbox-protocol/periphery-v3/blob/main/script/UploadBytecode.s.sol)
## V3.0 operational multisigs Source: https://docs.gearbox.finance/core/v3-0-operational-multisigs File: content/core/v3-0-operational-multisigs.mdx Multisig roles were split into a financial-treasury and technical. Both multisigs were created prior to the deployment ceremony by previous initial core members, as contracts needed to know the wallet addresses. Then, multisig members and a signer count requirement were added after **DAO voting procedures**. All this can be verified on-chain and Etherscan in logs of respective contracts. Multisig must execute whatever proposal reaches winning quorum. Given that multisig are members previously enacted by token holders, meaning the DAO, and are semi-public people with big reputation - in *extreme* cases they could voice against implementing some proposal. However, that could breach *trust* in the governance model and require immediate action and restructuring. This must be exercised carefully. ### Technical Guard | 6/12 Executes proposals which have reached quorum related to technical changes and the protocol. Ethereum Address: [0xA7D5DDc1b8557914F158076b228AA91eF613f1D5](https://etherscan.io/address/0xA7D5DDc1b8557914F158076b228AA91eF613f1D5) List of members on the multisig: 1. [zefram.eth](https://twitter.com/boredGenius) - Building [88mphapp](https://twitter.com/88mphapp), sudoswap, and more. Member of MetaCartel. 2. [Ignacio](https://twitter.com/iicc_eth) - Co-Founder of Stakely 3. van0k - Gearbox protocol developer 4. [0xmikko](https://twitter.com/0xmikko_eth) - original inventor of Gearbox \[on behalf of Gearbox Protocol Limited] 5. [Alex Smirnov](https://twitter.com/AlexSmirnov__) - co-founder of [deBridge](https://twitter.com/deBridgeFinance) 6. [MacLane Wilkison](https://twitter.com/MacLaneWilkison) - co-founder of [NuCypher](https://twitter.com/NuCypher) & [Threshold](https://twitter.com/TheTNetwork) 7. [Simone](https://twitter.com/kronosimste) - developer at [DegenScore](https://twitter.com/DegenScore) 8. [Lewi](https://twitter.com/lewifree) - OG degenerate & ESD summoner 9. [Klim](https://twitter.com/milkyklim) - data analytics and [YFI](https://twitter.com/iearnfinance) Maximalist 10. Alex - ex-Neutrino, a lobster and a builder 11. [Alex](https://twitter.com/0xAlexEuler) - CTO of [Mellow Protocol](https://twitter.com/Mellowprotocol) 12. [Lekhovitsky](https://twitter.com/lekhovitsky) - Gearbox protocol developer Transactions related to technical changes and protocol improvements are behind a 2-day timelock, and you can transparently observe every stage and queue in the [Risk Framework](https://risk.gearbox.foundation/updates): []() #### Veto / Unpause role | 4/12 Ethereum Address: [0xbb803559B4D58b75E12dd74641AB955e8B0Df40E](https://etherscan.io/address/0xbb803559B4D58b75E12dd74641AB955e8B0Df40E) A multisig with the same set of singers as the Technical Guard, but a lower 4/12 for faster response. The veto role is related to the ability to circumvent malicious proposals and transactions, it can only say "no" basically, but can't propose or push anything. The unpause role relates to unpausing. The pause function was granted to [2 analytical addresses](https://gov.gearbox.fi/t/gip-17-multisig-reshuffle-pausable-admin/1447) 1/1. They can only pause the protocol, in case their monitoring tools detect issues, in an attempt to stop the protocol from being fully exploited. In case that is possible and the time onchain gives that window. * 0xD5C96E5c1E1C84dFD293473fC195BbE7FC8E4840 * 0x65b384cecb12527da51d52f15b4140ed7fad7308 *** ### Treasury Guard | 5/10 Executes proposals which have reached quorum related to spending, grants, and the treasury overall. Ethereum Address: [0x7b065Fcb0760dF0CEA8CFd144e08554F3CeA73D1](https://etherscan.io/address/0x7b065Fcb0760dF0CEA8CFd144e08554F3CeA73D1) List of members on the multisig: 1. [Stani](https://twitter.com/StaniKulechov) - founder of [Aave](https://twitter.com/AaveAave), venture partner at [Variant Fund](https://twitter.com/VariantFund) 2. [Amplice](https://twitter.com/astr0bas3d) - [lobsterdao](https://twitter.com/10b57e6da0) member & core DAO contributor on marketing 3. [Pepo](https://twitter.com/0xPEPO) - contributor of [Wonderland](https://twitter.com/defi_wonderland) & [DeFi LATAM](https://twitter.com/defi_latam) 4. [Sergey](https://t.me/icodrops_sergey) - founder of [ICODrops](https://twitter.com/ICODrops) 5. [NDW](https://twitter.com/cryptondee) - Castle Capital member and a DeFi degen 6. [apeir99n](https://twitter.com/apeir99n) - original math & product at Gearbox \[on behalf of Gearbox Protocol Limited] 7. [Nikitakle](https://twitter.com/NOstroymov) - core DAO contributor on marketing & community 8. [Amantay](https://twitter.com/amantay_a) - core DAO contributor on risk & analytics 9. [duckdegen.eth](https://twitter.com/DuckDegen) - devrel, ex-Connext \[[GIP-40](https://gov.gearbox.fi/t/gip-40-financial-multisig-reshuffle/2204/5)] 10. [Vadym](https://twitter.com/0x_vadym) - head of product at Kolibrio Spending and grants paid out can be seen in monthly DAO reports: []() #### Fee Temporary Guard 5/10 Ethereum Address: [0x3E965117A51186e41c2BB58b729A1e518A715e5F](https://etherscan.io/address/0x3E965117A51186e41c2BB58b729A1e518A715e5F) A temporary multisig with the same set of singers as the Treasury Guard. It is created to separate funds from the DAO rounds which are used for the development of the protocol. This Fee Guard collects all fees from the protocol and can later on give control over to an initiative which will focus on staking programs, or whatever else the DAO decides to do. It's a holder of fees for now. #### Rewards management Guard 2/3 Executes rewards distribution and sets up temporary incentive campaigns, typically provided by partner protocols. Ethereum address: [0x6f378f36899cEB7C6fB7D293aAE1ca86B0Edbf6D](https://app.safe.global/transactions/history?safe=eth:0x6f378f36899cEB7C6fB7D293aAE1ca86B0Edbf6D) ## Risk Configuration Dictionary Source: https://docs.gearbox.finance/core/risk-configuration-dictionary File: content/core/risk-configuration-dictionary.mdx Flexibility is at the core of Gearbox’s design. Credit Accounts support a wide range of on-chain assets as collateral, which requires a risk framework capable of handling diverse asset properties. Gearbox’s risk controls are built to operate under uncertainty and adapt to any market conditions. Gearbox is a platform for the permissionless creation and curation of lending markets. To participate safely, both Curators and Users must understand the risk-control allowlist: Curators need to know the capabilities it grants, while Users should understand the trust assumptions they accept when engaging in lending activity. ### Curator Roles The Curator utilizes two primary roles to modify market parameters: * **Admin**\ Can modify all configurable parameters, subject to a minimum **24-hour timelock**. * **Emergency Admin**\ Can update a limited set of risk parameters **instantly** (without timelock) to mitigate immediate threats. ### Pool-Level Rules These parameters define the global constraints for the Liquidity Pool. If a user disagrees with these terms, they must select a different pool. #### Definitions * **Total debt limit:** Maximum amount of underlying assets that can be borrowed across the entire pool. * **Collateral limit:** Maximum amount of debt that can be backed by a specific collateral token (Quota Limit). * **Main Price Feed:** Primary price source used for calculating account value and triggering liquidations. * **Reserve Price Feed:** Secondary price source used to run safety checks on operations; can block Credit Account actions to protect LPs. * **Increase Rate:** One-time fee charged whenever exposure to a collateral increases. * **Collateral-specific rate:** Additional interest rate (APR) charged for borrowing against a specific collateral. * **IRM:** The Utilization-based Interest Rate Model contract. * **Loss Policy:** The logic executed when a liquidation results in bad debt. * **Emergency liquidators whitelist:** Addresses authorized to liquidate accounts when the Credit Manager is paused (Default: Permissionless). * **Loss liquidators whitelist:** Addresses authorized to execute liquidations that result in bad debt (Default: Permissionless). #### Permissions Matrix | Parameter | Admin (24h Delay) | Emergency Admin (Instant) | | ----------------------------------- | :---------------: | ------------------------- | | **Total debt limit** | ✅ | ⚠️ Reduce to zero-only | | **Collateral limit** | ✅ | ⚠️ Reduce to zero-only | | **Main Price Feed** | ✅ | ⚠️ Limited choice | | **Loss Policy** | ✅ | ⚠️ Can turn off | | **Loss liquidators whitelist** | ✅ | ⚠️ Can turn off | | **Emergency liquidators whitelist** | ✅ | ⚠️ Can turn off | | **Reserve Price Feed** | ✅ | ❌ | | **Increase Rate** | ✅ | ❌ | | **Collateral-specific rate** | ✅ | ❌ | | **IRM** | ✅ | ❌ | ### Credit Manager-Level Rules These parameters define the strategy for a specific Credit Manager. If a user disagrees with these terms, they can choose another Credit Manager within the same pool. #### Definitions * **Total debt limit:** Maximum aggregate debt of all Credit Accounts created from this Credit Manager. * **MinDebt:** Minimum required debt to open a Credit Account. * **MaxDebt:** Maximum permitted debt per Credit Account. * **Liquidation Premium:** Percentage of collateral value paid to the liquidator as an incentive. * **Liquidation Fee:** Percentage of collateral value paid to the Protocol (Curator & DAO). * **Max Enabled Tokens:** Maximum number of collateral tokens a single account can enable simultaneously. * **Interest Fee:** Percentage of borrowing interest captured as revenue (split between Curator & DAO). * **Collateral's LT:** The Liquidation Threshold (Loan-to-Value ratio). * **Collateral's forbidden status:** Controls whether a token is allowed or forbidden. * **List of allowed adapters:** Restricts which external contracts (e.g., Uniswap, Curve) a Credit Account can interact with. * **Expiration Policy:** Date after which the strategy winds down. After this date, all Credit Accounts become liquidatable regardless of Health Factor. #### Permissions Matrix | Parameter | Admin (24h Delay) | Emergency Admin (Instant) | | ---------------------------- | :---------------: | ------------------------- | | **Total debt limit** | ✅ | ⚠️ Reduce to zero-only | | **List of allowed adapters** | ✅ | ⚠️ Forbid-only | | **Collaterals list** | ✅ | ⚠️ Forbid-only | | **Liquidation Premium** | ✅ | ❌ | | **Liquidation Fee** | ✅ | ❌ | | **Collaterals' LT** | ✅ | ❌ | | **Expiration Policy** | ✅ | ❌ | | **MinDebt** | ❌ | ❌ | | **MaxDebt** | ❌ | ❌ | | **Max Enabled Tokens** | ❌ | ❌ | | **Interest Fee** | ❌ | ❌ | Flexibility is at the core of Gearbox’s design. Credit Accounts support a wide range of on-chain assets as collateral, which requires a risk framework capable of handling diverse asset properties. Gearbox’s risk controls are built to operate under uncertainty and adapt to any market conditions. Gearbox is a platform for the permissionless creation and curation of lending markets. To participate safely, both Curators and Users should understand the risk-control allowlist: Curators need to know the capabilities it grants, while Users should understand the trust assumptions they accept when engaging in lending activity. Curator has 2 main roles to modify markets' parameters: * **Admin** Can modify all configurable parameters, subject to a minimum 24-hour timelock. * **Emergency Admin** Can update a limited set of risk parameters without a timelock in emergency situations. All the rules below will have a specification based on which access those roles have. ## Pool-level rules If a user disagrees with these terms, they need to select another pool. * **Total debt limit:** maximum that can be borrowed across the entire pool * **Collateral limit:** maximum that can be borrowed against each token * **Main Price Feed:** price source for calculating account value and triggering liquidations * **Reserve Price Feed:** runs safety checks on operations and can block Credit Account actions to protect LPs * **Increase Rate:** one-time fee whenever exposure to a collateral increases * **Collateral-specific rate:** extra interest for borrowing against a given collateral * **IRM:** utilization-based interest rate model * **Loss Policy:** additional liquidation logic for cases that create bad debt * **Emergency liquidators whitelist:** when Credit Manager is paused, liquidations are performed in "Emergency" mode which allows to restrict access to liquidations. By default they are permissionless * **Loss liquidators whitelist:** when a liquidation creates bad debt, it's performed in "Loss" mode mode which allows to restrict access to liquidations. By default they are permissionless ### **Credit Manager-level rules** If a user disagrees with these terms, they can choose another Credit Manager within the same pool. * **Total debt limit:** maximum aggregate debt of all Credit Accounts created from this Credit Manager * **MinDebt:** minimum required debt for a Credit Account * **MaxDebt:** maximum permitted debt for a Credit Account * **Liquidation Premium:** portion of collateral value paid to the liquidator during liquidation * **Liquidation Fee:** portion of collateral value paid to the curator and Gearbox DAO during liquidation * **Max Enabled Tokens:** number of different collateral tokens that can count toward account value * **Interest Fee:** extra rate on top of the IRM and collateral-specific rate, split between the curator and DAO * **Collateral's LT** (loan to value) * **Collateral's forbidden status** * **List of allowed adapters:** restricts which external contracts a Credit Account can use * **Expiration Policy:** curator may set an expiration; after the cutoff date, all Credit Accounts become liquidatable regardless of Health Factor with penalties set by the expired liquidation fee and premium parameters. ## Usecase: Direct Redemptions Source: https://docs.gearbox.finance/core/usecase-direct-redemptions File: content/core/usecase-direct-redemptions.mdx ## The problem: constrained instant liquidity ⇒ leverage stops working properly Other lending protocols must treat assets with timelocked liquidity like standard tokens and rely on DEX liquidity to enable leverage. Building and maintaining deep DEX liquidity is hard, leading to thin books and low collateral limits. Furthermore, asset issuers often have to pay to seed and maintain DEX liquidity. **This leads to fragmented UX and capital-inefficiency**, forcing users to wait for weeks or pay months worth of yield for instant liquidity ![Figure](https://docs.gearbox.finance/assets/docs/core/usecase-direct-redemptions/01-problem-constrained-instant-liquidity-leverage-stops-working-properly.png) ## Gearbox's Solution **Zero DEX Liquidity Required:** With Gearbox, leverage can go live on day one. It eliminates the need for DEX liquidity seeding, working at any size. **Direct Integration:** Execution is handled through direct smart-contract integration, allowing deposits and withdrawals at face value. **Benefits for users:** * Save time up to **8 periods** of native redemption. * Capital requirements are reduced by **10x**. * Save fees equal to a **month of farming yield**. ## How it works For simplicity, we refer to the example semi-liquid asset as xVAULT, since vaults are a common example of assets with these properties. The same logic also applies to RWAs, LRTs, and other tokens with time-locked liquidity. ![Figure](https://docs.gearbox.finance/assets/docs/core/usecase-direct-redemptions/02-how-it-works.png) ### Take leverage * User adds USDC to Credit Account and borrows 5x more to get leveraged exposure on xVAULT yield * Credit Account deposits 6x USDC to xVAULT issuance contract and receives the xVAULT ### Undwind position * The Credit Account holds an xVAULT token and has an outstanding USDC debt. * The user starts the redemption process: Credit Account sends the xVAULT token to the redemption contract. * In return, the Credit Account receives a redemption receipt token, which represents a future claim on the underlying asset. * The Credit Account now holds the redemption receipt token and USDC debt. #### After the Redemption Window: * Once the redemption window has passed, the user can finalize the redemption. * The Credit Account burns the redemption receipt token and receives USDC to repay debt. The Credit Account always stays overcollateralized, while collateral transfroms from xRWA into redemption receipt token and eventually into liquid underlying. ## Usecase: Intent-based lending Source: https://docs.gearbox.finance/core/usecase-intent-based-lending File: content/core/usecase-intent-based-lending.mdx Programmable Credit with Predictable Outcomes for Institutional Lenders ### The Problem DeFi lending looks liquid, but behaves like a black box. **Your capital goes into a vault.** Rates move unpredictably. Risks get pooled. When something breaks: MEV, liquidations, curator mistakes — losses are socialized. You find out the hard way it was never really your money. **For regulated institutions, it gets worse:** comingled funds, unknown counterparties, no audit trail. Most compliance frameworks require counterparty identification and fund segregation. Pooled DeFi offers neither. *Legacy finance offers bespoke terms, but with counterparty risk, settlement delays, and opaque execution.* *** ### The Solution **Post your terms. Match with counterparties. Execute on-chain.** You don't "deposit." You define: * Asset, size, duration * Rate: fixed (5% APY) or reference-based (LIBOR + 2%, Aave + 3%) * Accepted collateral and strategies * Compliance requirements Your order is signed and immutable. No curator can change it. No protocol upgrade can rewrite it. When a counterparty matches your terms, the contract executes. Until then, your capital stays productive where it already is. **You own the terms. You own the risk. You own the exit.** *** ### How It Works | | Step | |---|---| | 1️⃣ | Post — Define exact terms: rate, collateral, duration, compliance gates. Sign onchain. | | 2️⃣ | Match — Engine pairs compatible orders with counterparty verification. No gatekeepers. | | 3️⃣ | Execute — Isolated pool + credit account deployed with your exact parameters. | | 4️⃣ | Exit — Sell position on secondary market anytime, or wait for maturity. | No idle capital. No comingled funds. No curator risk. *** ### Why Gearbox | | Capability | Benefit | |---|---|---| | 🎯 | Predictable Rates | Fixed or reference-based (LIBOR, Aave). You define the formula: no utilization roulette. | | 🔗 | Controlled Composability | Lender defines allowed strategies. Borrower executes within boundaries: transparent, on-chain enforced. | | 🏦 | Custom Collateral | Tokenized equities, private credit, real estate. Each deal: own oracle, own risk params. | | 🔄 | Secondary Market | Sell active positions anytime. Turn illiquid terms into liquid exits. | | 🔒 | No Curator Risk | Once matched, the contract is final. No vault-level loss sharing. No surprises. | | 📋 | Regulatory Alignment | No comingled funds, clear audit trails, counterparty-specific compliance. | *** ### Regulatory Alignment Traditional DeFi pools create compliance barriers. Intent-based lending solves them: | | Requirement | ✅ Solution | |---|---|---| | 👤 | Know Your Counterparty | Direct matching. Verifiable filtering of participants. | | 🔒 | No Comingling | Isolated infrastructure per deal. Capital never mixes. | | 📝 | Audit Trail | On-chain record: who, what, when, all transactions. | | ✓ | Compliance Gates | Per-deal KYC/AML, jurisdiction, accreditation checks. | | 🛡️ | Risk Segregation | One default doesn't cascade to other positions. | This structure aligns with emerging regulatory frameworks for institutional DeFi participation. *** ### RWA Collateral | | Collateral Type | Example | |---|---|---| | 📈 | Tokenized Securities | Borrow USDC against S&P 500 ETF tokens | | 💼 | Private Credit | Collateralize with tokenized loan tranches | | 🏠 | Real Estate | Borrow against tokenized property | | 🏛️ | T-Bills | Treasury tokens as pristine collateral | Custom price feeds, LTV ratios, liquidation parameters—negotiated per intent. *** ### Capital Efficiency | | Traditional Pool | Intent-Based | |---|---|---| | 💰 Capital | ❌ Locked on deposit | ✅ Productive until match | | 📊 Rates | ❌ Utilization-driven volatility | ✅ Defined formula (fixed or reference-based) | | 🏦 Collateral | ❌ Single profile | ✅ Custom per agreement | | ⚠️ Risk | ❌ Socialized losses | ✅ Isolated per deal | | 🚪 Exit | ❌ Wait for utilization | ✅ Secondary market anytime | *** ### Product Preview Both sides define their exact terms: asset, rate (fixed or reference-based), duration, LTV, and counterparty compliance requirements (KYC, jurisdiction, institutional status). | Lender View | Borrower View | | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ![](https://docs.gearbox.finance/assets/docs/core/usecase-intent-based-lending/01-intent-lending-lender-ui.png) | ![](https://docs.gearbox.finance/assets/docs/core/usecase-intent-based-lending/02-intent-lending-borrower-ui.png) | *** ### Next Step Interested in institutional-grade DeFi lending with predictable rates, custom collateral, and compliance controls? **Contact the Gearbox team** to discuss pilot programs for intent-based credit markets. ## Usecase: Faster RWA settlement with leverage Source: https://docs.gearbox.finance/core/usecase-faster-rwa-settlement-with-leverage File: content/core/usecase-faster-rwa-settlement-with-leverage.mdx How Gearbox enables faster entry/exit for RWA-backed debt positions with non-atomic settlement, using ACRED leverage as an illustrative go-to-market use case. *** ### The Problem: Slow Settlement Breaks RWA-Backed Debt Positions RWA tokens (tokenized securities, private credit, treasuries) typically do not settle atomically. Deposits (e.g., USDC → ACRED mint) can require hours or days, while redemptions can be materially longer (ACRED can be \~90 days). This settlement profile constrains RWA-backed debt strategies (leverage is the clearest example): * **Limited ability to react to market opportunities** — by the time a deposit matures, market conditions may have changed * **Limited ability to exit during volatility** — positions can remain in redemption queues while prices move * **Lower liquidator participation** — institutional liquidators are reluctant to warehouse long-dated redemption receipts (ACRED: \~90 days) Traditional flash-loan style flows are insufficient because standard ERC20 collateral is unavailable during the waiting period. *** ### The Solution: Up to 10x Faster Entry/Exit for RWA-Backed Debt Positions Gearbox acts as a **prime brokerage layer** that holds positions during transition phases — when assets are pending deposits or redemption receipts, not yet standard ERC20s. **Result:** Partner lending platforms can support RWA-backed debt positions with materially faster entry/exit handling. * **Time to open an RWA-backed debt position:** can be near-immediate (Hour 0), instead of waiting for mint completion. * **Time to unwind credit position backed by RWA:** 1 redemption period, instead of iterative deleverage slowed by multi-day redemptions. *** ### Who Benefits | User | Current Problem | With Gearbox | | ----------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------- | | **Traders** | Miss entry points during multi-day settlement | Get an RWA-backed debt position immediately, then exit when appropriate | | **Liquidators** | Reluctant to take on long-dated redemption risk (ACRED can be \~90 days) | Fast de-risking path (sell/finance receipt), reducing duration exposure | | **Risk Curators** | Limited ability to offer fast credit products on RWAs with delayed settlement | Integration-ready infrastructure with no core protocol changes required | *** ### Exit Speed Comparison (ACRED Redemption) * **Time to de-risk position exposure:** near-immediate with Gearbox vs \~90 days without * **Time to unwind leveraged position into stablecoins:** \~90 days with Gearbox vs >240 days without Gearbox improves liquidity and risk transfer during the waiting period; it does not shorten issuer redemption cycles *** ### How It Works Gearbox acts as a **prime brokerage layer** that holds positions during transition phases — when assets are not yet standard ERC20s but pending deposits or redemption receipts. ``` **What happens:** * User interacts with familiar **Partner UI** * **Partner Market** holds positions when collateral is mature ERC20 * **Gearbox** holds positions during transition (pending deposits, redemption receipts) * **Curator** moves liquidity between Partner Market and Gearbox as positions mature **Result:** Partner lending platforms can offer faster RWA-backed debt products without modifying their core architecture. *** ### Actors & Contracts | Actor | Role | Contracts | | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | | **User** | Borrower opening an RWA-backed debt position | User wallet | | **Partner Market Curator** | Capital allocator. Manages liquidity allocation between Partner vaults and Gearbox pool. Takes lending-side risk. | Partner allocator contracts | | **Gearbox Curator** | Configures collateral types including transition-stage assets. Sets risk parameters for pending deposits and redemption receipts. | Credit Configurator | | **Partner Market** | Lending infrastructure for mature ERC20 positions | Partner market contracts | | **Partner Vault** | Liquidity source. Holds capital allocated by curators. | Partner vault contracts | | **Gearbox** | Transitional venue. Holds positions during deposit/redemption windows. | Pool, Credit Manager, Credit Facade, Credit Account | | **Securitize** | ACRED issuer. Handles mint and redeem operations. | ACRED token, mint contract, redeem contract | #### Curator Relationship Partner Market curators and Gearbox curators are **formally different roles** but can be the same entity. A single party may: * Configure the Partner Vault and allocate to Gearbox * Configure the Gearbox market for transition-stage collateral This alignment simplifies risk management and capital efficiency. *** ### Position Transfer Mechanism When a position matures (pending-deposit → ACRED), it can be migrated from Gearbox to the Partner Market. Two approaches: Migration between Gearbox and Partner Market does not require additional capital because both sides of the position move simultaneously: * **Curator** controls supply-side allocation — moves liquidity between Gearbox Pool and Partner Market * **User** (via Credit Account) controls debt + collateral — repays one venue, borrows from the other When curator and user are coordinated (e.g., via smart contract integration or allocator contracts), supply and debt move together. The financial position stays exactly the same — same collateral, same debt, same health factor. Only the infrastructure changes. This coordination can be implemented at the contract level, but the specifics are integration-dependent. *** ### Entry Flow (Illustrative Use Case): Taking 5x Leverage on ACRED User wants $500 ACRED exposure with $100 own capital. #### Phase 1: User Intent ``` * User opens leveraged position through Partner UI * Transaction triggers Allocator (via adapter) to rebalance capital * Allocator moves USDC from Partner Vault to Gearbox Pool * Capital is now available for the Credit Account to borrow (next phase) #### Phase 2: Transition Setup (Gearbox + Securitize contracts) ``` **Key Points:** * **Credit Account opened** via adapter (same transaction as Phase 1) * User's $100 + borrowed $400 = $500 total position * **Pending-deposit token is valid collateral** (curator-configured) * Position remains overcollateralized during wait #### Phase 3: Waiting ``` * Deposit window passes (hours to days depending on ACRED terms) * Pending-deposit token becomes ACRED * Position still on Gearbox Credit Account #### Phase 4: Migration to Partner Market (Partner + Gearbox contracts) User triggers migration (manual or auto-opt-in): ``` * **Allocator withdraws** liquidity from Gearbox Pool and **supplies** to Partner Market * **Borrow $400 USDC** from Partner Market * **Repay Gearbox debt** with borrowed USDC * **Supply ACRED** to Partner Market as collateral * **Close Credit Account** **Result:** User has overcollateralized ACRED position on Partner Market. $500 ACRED collateral, $400 USDC debt. No additional capital is required — curator's supply-side reallocation and the user's debt migration happen together, so the financial position is unchanged (see [Position Transfer Mechanism](#position-transfer-mechanism)). *** ### Exit Flow: Redeeming ACRED Position User wants to exit a $500 ACRED RWA-backed debt position ($100 equity, $400 debt) and receive USDC. #### Why Exit Speed Matters * **Liquidators avoid long-dated redemption risk** — ACRED redemption can be \~90 days * **Near-immediate de-risking path enables more active liquidation participation** * **Gearbox provides transition liquidity service** for liquidated positions #### Phase 1: User Intent ``` * User exits position through Partner UI * Transaction triggers Allocator (via adapter) to rebalance capital * Allocator moves USDC from Partner Vault to Gearbox Pool #### Phase 2: Transition Setup (Gearbox + Securitize contracts) ``` * **Credit Account opened** via adapter (same transaction as Phase 1) * **Borrow $400 USDC** from Gearbox pool * **Repay Partner Market debt** with borrowed USDC * **Release ACRED** from Partner Market to Credit Account * **Initiate redemption** → Credit Account sends $500 ACRED to Securitize, receives redemption receipt * **Position:** Redemption receipt (collateral) + $400 USDC debt * **Overcollateralized** because Gearbox curator configured redemption receipt as valid collateral **Result:** User has zero position on Partner Market, overcollateralized position on Gearbox (redemption receipt collateral, USDC debt). As with entry migration, this is capital-neutral — supply and debt move together between venues. #### Phase 3: Waiting ``` * Redemption window passes (ACRED can be long-dated, e.g., \~90 days; issuer-dependent) * Redemption receipt matures → USDC received * Position remains on Gearbox Credit Account until final settlement #### Phase 4: Finalization & Close (Gearbox + Partner contracts) User triggers finalization (manual or auto-opt-in): ``` * **Repay $400 debt** to Gearbox pool * **Close Credit Account** * **User receives** net USDC: redemption proceeds minus debt, interest, and fees (plus/minus PnL) * **Allocator rebalances** liquidity from Gearbox Pool back to Partner Market `Net user payout = redemption proceeds - repaid debt - accrued borrow interest - protocol fees ± position PnL` **Result:** Position fully closed. User has USDC in wallet. *** ### Exit Value for Liquidators Gearbox's speed advantage is most valuable during liquidations. #### The Liquidator's Problem When an RWA-backed debt position becomes undercollateralized: 1. Traditional approach: Liquidator takes position, initiates redemption, and often holds the receipt to settlement (ACRED: \~90 days) 2. Problem: Institutional liquidators are reluctant to hold long-dated redemption receipts through volatile periods 3. Result: **Lower liquidation participation can increase bad-debt risk** #### The Gearbox Solution 1. Liquidator takes position in Credit Account 2. Redemption receipt is already there (or can be initiated immediately) 3. Liquidator can hold until redemption matures 4. **Or:** Gearbox curator can provide near-immediate liquidity by buying/financing the receipt at a discount #### Value Proposition | Metric | Traditional | With Gearbox | | ------------------------------------ | ---------------------------------------------------------- | -------------------------------------------------- | | Time to de-risk position exposure | Often tied to full redemption window (\~90 days for ACRED) | Near-immediate if receipt is sold/financed | | Time to final issuer cash settlement | \~90 days (ACRED illustrative) | \~90 days (issuer-dependent; unchanged by Gearbox) | | Liquidator risk | High (duration + market exposure) | Lower (faster de-risking path) | | Protocol health | Lower liquidation participation, higher bad-debt risk | More active liquidation participation | **Key insight:** The same mechanism that helps traders enter fast also helps liquidators de-risk faster, while final settlement remains issuer-timed. This makes the system healthier under stress. *** ## Interest Rate Model Source: https://docs.gearbox.finance/core/interest-rate-model-2 File: content/core/interest-rate-model-2.mdx The Interest Rate Model (IRM) is a critical component of the Gearbox Protocol that determines the cost of borrowing for Credit Accounts. In Gearbox V3, the protocol primarily utilizes a **Two-Point Linear Interest Rate Model** (`IRM::LINEAR`), designed to provide more stable rates and prevent sudden interest spikes during large liquidity fluctuations. ### Pool and IRM Interaction The `PoolV3` contract acts as the primary consumer of the IRM. It does not store interest rate logic internally but instead queries the IRM whenever the pool's state changes. #### Triggering Rate Updates The pool triggers a rate recalculation via the IRM's `calcBorrowRate` function during any operation that affects the pool's utilization: * **Lending Operations**: `deposit`, `mint`, `withdraw`, and `redeem`. * **Borrowing Operations**: `lendCreditAccount` (when a user opens or increases debt) and `repayCreditAccount` (when debt is repaid or an account is liquidated). #### Optimal Borrowing Check A unique feature of the V3 IRM is the `checkOptimalBorrowing` flag. When a Credit Manager attempts to borrow funds via `lendCreditAccount`, it passes `true` to this flag. If the IRM is configured with `isBorrowingMoreU2Forbidden = true`, the call will revert if the new borrowing would push the pool's utilization beyond the U\_2 (steep region) threshold. This ensures a liquidity buffer remains available for lenders to withdraw. ### The Two-Point Linear Model Unlike traditional models that use a single "kink," Gearbox V3 introduces an intermediate region to smooth the transition between low utilization and the "liquidity crunch" (steep) region. | Region | Range | Slope | Description | | ---------------- | --------------- | ------------- | --------------------------------------------------------------------- | | **Obtuse** | $0 \to U\_1$ | $R\_{slope1}$ | Low utilization; rates grow slowly. | | **Intermediate** | $U\_1 \to U\_2$ | $R\_{slope2}$ | Normal operation; provides a buffer before the steep curve. | | **Steep** | $U\_2 \to 100%$ | $R\_{slope3}$ | Emergency region; rates increase aggressively to encourage repayment. | ### Fetching Core Parameters Users and integrators can fetch the parameters influencing their interest rates through multiple layers. #### 1. Direct Contract Queries You can call the IRM contract directly using the `ILinearInterestRateModelV3` interface: * **`getModelParameters()`**: Returns the fixed configuration ($U\_1, U\_2, R\_{base}, R\_{slope1}, R\_{slope2}, R\_{slope3}$) in basis points (1/100th of a percent). * **`isBorrowingMoreU2Forbidden()`**: Returns whether the pool blocks borrowing above $U\_2$. * **`calcBorrowRate(expected, available, check)`**: Returns the current borrow rate in **RAY** ($10^{27}$) based on hypothetical liquidity levels. #### 2. High-Level Pool State The `PoolV3` provides the results of the IRM's calculation: * **`baseInterestRate()`**: Returns the current annual interest rate (in RAY) currently applied to all borrowers. * **`supplyRate()`**: Returns the annual rate earned by LPs, which is the `baseInterestRate` scaled by utilization, plus quota revenue. ```typescript // TypeScript: Reading interest rates from pool const borrowRate = await pool.read.baseInterestRate(); const supplyRate = await pool.read.supplyRate(); // Convert from RAY (27 decimals) to percentage const RAY = 10n ** 27n; const borrowAPR = Number(borrowRate * 10000n / RAY) / 100; // e.g., 5.25% const supplyAPY = Number(supplyRate * 10000n / RAY) / 100; // Reading IRM parameters directly const irm = getContract({ address: irmAddress, abi: linearInterestRateModelAbi, client: publicClient, }); const params = await irm.read.getModelParameters(); // Returns: [U1, U2, Rbase, Rslope1, Rslope2, Rslope3] in basis points ``` ### Security and Risk Considerations * **Utilization Manipulation**: Because the rate is calculated based on `availableLiquidity`, large atomic withdrawals can spike the interest rate. The $U\_1 \to U\_2$ intermediate slope is specifically designed to mitigate the impact of these "jumps." * **Immutable Parameters**: In the standard deployment, IRM parameters are set at construction. However, the `PoolV3` allows the `CONFIGURATOR` to swap the entire IRM contract via `setInterestRateModel` if market conditions shift significantly.
Sources * [contracts/interfaces/ILinearInterestRateModelV3.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/interfaces/ILinearInterestRateModelV3.sol) * [contracts/pool/LinearInterestRateModelV3.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/pool/LinearInterestRateModelV3.sol) * [contracts/pool/PoolV3.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/pool/PoolV3.sol) * [contracts/compressors/MarketCompressor.sol](https://github.com/Gearbox-protocol/periphery-v3/blob/main/contracts/compressors/MarketCompressor.sol) * [contracts/types/MarketData.sol](https://github.com/Gearbox-protocol/periphery-v3/blob/main/contracts/types/MarketData.sol)
# Developer documentation SDK, contracts, Credit Accounts, multicalls, market data, integrations, deployment addresses, and automation guides. ## Overview Source: https://docs.gearbox.finance/developers/intro-overview File: content/developers/intro-overview.mdx Build on Gearbox Protocol — permissionless lending rails for onchain credit. Gearbox provides the infrastructure for creating and operating lending markets. A single liquidity pool funds multiple isolated credit strategies, each managed by independent Market Curators. Developers can integrate at every level: from reading market data and building UIs, to creating new adapters for DeFi protocols, to extending the core protocol itself. ## What You Can Build | Use Case | Description | Start Here | | --- | --- | --- | | **Frontend / Dashboard** | Display market data, account positions, pool stats | [Getting Started: TypeScript](https://docs.gearbox.finance/developers/gm-start-ts) | | **Trading Bot** | Monitor health factors, execute liquidations | [Liquidation Bots Guide](https://docs.gearbox.finance/developers/gm-guide-bots) | | **Analytics Backend** | Index events, track historical rates, build APIs | [Backend Services Guide](https://docs.gearbox.finance/developers/gm-guide-backend) | | **Protocol Integration** | Compose with Credit Accounts from your contracts | [Protocol Integration](https://docs.gearbox.finance/developers/gp-integration) | | **Adapter Development** | Add new DeFi protocol support to Gearbox | [Adapter Development](https://docs.gearbox.finance/developers/gp-adapters) | | **Core Extension** | Custom interest rate models, pool hooks | [Core Extension](https://docs.gearbox.finance/developers/gp-extension) | ## Documentation Structure ### [Gearbox Markets](https://docs.gearbox.finance/developers/gm-overview) The main product. Learn the concepts, get started with the TypeScript SDK, query market data, operate credit accounts, and build multicall transactions. - **Concepts** — How markets, credit accounts, and the multicall system work - **Getting Started** — Install the SDK and make your first call - **Markets** — Query pools, rates, and insurance state - **Credit Accounts** — Open, manage, and close leveraged positions - **Smart Contracts** — Contract reference (methods, events, parameters) - **Guides** — End-to-end tutorials for common use cases ### [Gearbox Permissionless](https://docs.gearbox.finance/developers/gp-overview) The infrastructure layer. Understand how the protocol achieves institutional-grade security while remaining fully permissionless. - **Concepts** — Role separation, Bytecode Repository (BCR), Cross-Chain Multisig (CCM) - **Building** — Create adapters, integrate protocols, extend the core ### [Resources](https://docs.gearbox.finance/developers/res-addresses) Deployment addresses, security & audits, glossary. ## Quick Links | Need | Go to | | --- | --- | | Install SDK | [Getting Started: TypeScript](https://docs.gearbox.finance/developers/gm-start-ts) | | Understand the architecture | [Gearbox 101](https://docs.gearbox.finance/developers/intro-101) | | Find contract addresses | [Deployment Addresses](https://docs.gearbox.finance/developers/res-addresses) | | Build multicalls | [Multicalls](https://docs.gearbox.finance/developers/gm-accounts-multicalls) | | Query credit accounts | [Credit Accounts](https://docs.gearbox.finance/developers/gm-accounts) | | Pool deposit/withdraw | [Pool Operations](https://docs.gearbox.finance/developers/gm-markets-pools) | ## Risks and T&C Source: https://docs.gearbox.finance/developers/risks-and-t-c File: content/developers/risks-and-t-c.mdx ## Risks and T&C Source: https://docs.gearbox.finance/developers/risks-and-t-c-2 File: content/developers/risks-and-t-c-2.mdx ## Risks and T\&C It is important to distinguish between an interface (application) that is operated by a normal web2 company - and the onchain protocol where all the logic is and that is not controlled by anyone. While the company can block its interface and prohibit its use, the protocol is fully in the hands of governance and is not managed by any single person or entity. It's crucial for the DAO to find robust solutions and keep innovating, seeking to improve Gearbox security. You can find more information on such efforts in the [**Audits**](https://docs.gearbox.finance/core/audits-bug-bounty) section. Companies have their own legal disclaimers and risks associated, which you must go through and accept if you use the interface. **For instance, you must understand that an interface not being accessible can become an obstacle to you managing your position. But it doesn't mean that you cannot access your position or assets via smart contract directly or some other interface.** This section is dedicated to explaining risks related to Gearbox Protocol on the contract level and conceptually. **We believe that outlining risks explicitly creates stronger accountability in the community and gives power back to the users of the protocol.** The risks presented below are general across many DeFi protocols. Ask more on [Discord](https://discord.gg/JssNVvxscK). ### **Protocol Technical Disclosure** Some of the disclosures can mimic interface-related concerns below. **Oracle Risk** In its current stage, Gearbox Protocol uses Chainlink Price Feeds, Redstone Price Feeds as well as some composite smart contract oracles. While the industry in general uses the same service, it is imperative to understand that oracles are a crucial point of DeFi infrastructure. An oracle going rogue or reporting incorrect data, may cause cascading liquidations or incorrect protocol operations. This can result in bad debt and loss of user funds. **Sandwich attacks and MEV** No traders on Ethereum are safe from MEV attacks, and this is not something unique to Gearbox Protocol either. The DAO can find solutions and cooperate with protocols who provide MEV protection. Users should exercise trades with caution and watch out for their slippage. And for example, select better RPCs that protect you from being sandwhiched. **De-peg of base assets or stablecoin risks** It can happen that stablecoin issuers introduce boundaries as to who can use them, or freeze accounts. This can cause issues in the way protocols work, and Gearbox Protocol is no exception to that. In the ethos of decentralization, Gearbox DAO should strive to improve its collateral base to limit cases leading to possible bad debt accrual. However, the current version of Gearbox has isolated lending only, in which case the risk is contained within LP pools. **Liquidations and black-swan events** [Liquidations](https://docs.gearbox.finance/core/liquidation-dynamics) do not depend on the protocol or any member involved. Liquidators are third-party workers open to anyone. It can happen that liquidators malfunction or do not perform, despite [economic incentives for liquidators](https://docs.gearbox.finance/core/liquidation-dynamics) being in place. This can under-collateralize the protocol and make [LPs](https://docs.gearbox.finance/core/pool-the-liquidity-vault) lose their capital. To prevent that, DAO can implement token-backed backstops, increase[ Reserve Fund](https://docs.gearbox.finance/core/insurance-solvency-reserves), onboard more professional liquidators, and so on. **Risks of allowed tokens / contracts lists** [AllowedList](https://docs.gearbox.finance/core/risk-configuration-dictionary#credit-manager-level-rules) defines where Gearbox Protocol users can deploy their leverage funds into. Wrong liquidation thresholds or hacks on the side of those assets can result in the insolvency of LP pools. **Can't withdraw capital as LP due to the entire LP pool being in use** While the protocol can remain sane and over-collateralized, if the entire [LP](https://docs.gearbox.finance/core/pool-the-liquidity-vault) pool is borrowed, as an LP you would not be able to pull out your capital in that moment. This is the same scenario that Aave, Compound, or other protocols have in common and is pretty standard. Usually, in DeFi protocols forced liquidation is not implemented. This can lead to cases of insufficient liquidity for a withdrawal operation. To mitigate this risk, the parameters for managing the interest rate curve of the pool are introduced (interest rate depends on utilization ratio of the pool). If the utilization of the pool stays too high, the Governance can further increase these parameters and thereby make lending more expensive. This will encourage borrowers to close loans and thereby make liquidity available. **Issues with wallets and signing transactions** Wallet connection and signing transactions on the user side can be an obstacle to interacting with the protocol, which must be taken into account. **Hacks and Software Issues** Taking advantage of the protocol in ways it is not intended to be, malfunction of the protocol which wasn't originally intended, and other security breaches which disrupt design of the systems. All of these issues can lead to partial or full loss of funds, which every user must understand and accept. **Governance and Multisig** Before governance transitions to full on-chain voting and execution, the execution of snapshot decisions or even on-chain events is still subject to multisig doing its job the right way. There is a timelock in place to prevent rogue multisig transactions. Moreover, multisig needs to make sure it operates well or its misalignment with the DAO [governance](https://docs.gearbox.finance/core/protocol-dao) can lead to users leaving the protocol. This is a model often used, but the risk should be understood nonetheless. ### **Interface Disclosure** **Gearbox App is in its Beta Stage** Gearbox App is in its beta stage, which means that the Gearbox App and all related software, including blockchain software and smart-contracts, are experimental. Gearbox App is provided on an “as is” and “as available” basis, without warranty of any kind, either expressed or implied, including, without limitation, warranties that the Gearbox App or any related software are free of defects, vulnerabilities, merchantable, fit for a particular purpose or non-infringing. **Risk of Software Weaknesses** Although we make reasonable efforts to ensure that the Gearbox App and related software follow the high-security standards, we do not warrant or represent that the Gearbox App or any related software are secure or safe, or protected from fishing, malware or other malicious attacks. Further, the Gearbox App and related software may contain weaknesses, bugs, vulnerabilities, viruses or other defects which may have a material adverse effect on the operation thereof, or may lead to losses and damages for you, other users of Gearbox App, or third persons. **Risk Inherent in the Underlying Blockchain Networks** Gearbox App interacts with the Protocol deployed on the Ethereum Virtual Machine-compatible blockchain network(s) and more. As a result, any malfunction, breakdown or abandonment of such blockchain(s) may have a material adverse effect on the Gearbox App and Protocol. Moreover, advances in cryptography, or technical advances such as the development of quantum computing, could present risks to the Gearbox App and related blockchain software by rendering ineffective the cryptographic consensus mechanism that underpins the blockchain. The smart-contract concept, the underlying software and software platforms, including the blockchain networks, are still in an early development stage and unproven. Although it is very unlikely, the blockchain, as well as any other blockchain, can be attacked which may result in downtime, consensus split, long reorganization of the chain, 51 percent attack, or other adverse outcomes each of which may lead to complete loss of your assets implemented on such blockchain network. **Risk Inherent in the Protocol** Gearbox App interacts with the Protocol and when using the Gearbox App you may be exposed to certain risks related to the operation and functioning of the Protocol. The Protocol is complex, the majority of its components and functional elements are risky and experimental. You should not use or interact with the Protocol unless you fully understand how it works and the consequences of transactions carried out with the use of the Protocol. Gearbox App derives information from the Protocol, related software and underlying blockchain network(s) in an automated manner, which means that such information is not verified. As a result, such information may not be true, complete, timely, accurate, or sufficient. Furthermore, certain functions within the Protocol may be executed by third parties that may not act in a timely or reliable manner, or as expected or intended, or may fail to act, which can lead to partial or complete loss of your digital assets. That is related to untimely or imperfect [liquidations](https://docs.gearbox.finance/core/liquidation-dynamics). **Risk of Flawed Logic of Gearbox App** The underlying logic of the Gearbox App and related software may be flawed, defective or impaired, which can result in smart-contracts operating incorrectly or not as expected, or transactions being executed in violation of logic which underpins the smart-contracts, which can lead to partial or complete loss of digital assets used in the transaction. **Risk of Confusing User Interface** Certain user interface elements or design decisions of the Gearbox App can be confusing or mislead you, which may result in the execution of a different action or transaction than intended or desired, or connection of a wrong digital wallet, account or network. **Risk of Legal Uncertainty** Just like any other business, the intended activities of Gearbox may be subject to various laws and regulations in the countries where it operates or intends to operate. We might be obliged to obtain different licenses or other permissive documents in some or all jurisdictions where we intend to operate our business, therefore, our business in such jurisdictions shall always be subject to obtaining such licenses or permissive documents, if so directed by applicable laws. Furthermore, regulatory actions, orders or inquiries may adversely affect the Gearbox App and Gearbox, or impair our ability to make the Gearbox App available. Additionally, changes in applicable laws or regulations or evolving interpretations of existing law could, in certain circumstances, result in increased compliance costs or capital expenditures, which could affect our ability to carry on the business model and develop the Gearbox App and related software. **Risk of Theft** We make a commercially reasonable effort to ensure that any transactions carried out via the Gearbox App are secure. Notwithstanding the aforesaid, there is no assurance that there will be no theft of the digital assets as a result of hacks, sophisticated cyber-attacks, distributed denials of service or errors, double-spent attacks, flash-loan attacks, vulnerabilities or defects of the Gearbox App or related software, the Ethereum blockchain network or any other blockchain network, or otherwise. Such events may include, for example, flaws in programming or source code leading to exploitation or abuse thereof. Any of the above may lead to partial or complete theft or loss of digital assets used in transactions carried out through the Gearbox App or with the use of related software. ## The Lending Stack Source: https://docs.gearbox.finance/developers/intro-101 File: content/developers/intro-101.mdx Every product built on Gearbox — leveraged farming, margin trading, RWA settlement, structured credit — starts from the same primitive: the **Credit Account**. ## Credit Account: The Primitive A Credit Account is an isolated smart contract wallet that holds both a user's collateral and borrowed funds in one place. Unlike traditional lending protocols where collateral sits in a shared vault, each Gearbox position is a separate contract with its own state. ```mermaid flowchart LR subgraph "Traditional Lending" User1[User A] --> Vault[Shared Vault] User2[User B] --> Vault User3[User C] --> Vault end subgraph "Gearbox" UserA[User A] --> CA1[Credit Account A] UserB[User B] --> CA2[Credit Account B] UserC[User C] --> CA3[Credit Account C] end ``` This isolation is what makes everything else possible: - **Programmable leverage** — the Credit Account can interact with any whitelisted DeFi protocol (Uniswap, Curve, Lido, Aave) as if it were a regular wallet. Borrowed funds never leave the account — they're deployed *inside* it. - **Check-on-exit** — the protocol doesn't restrict what you do within a transaction. It only checks that the account is solvent at the end. This enables complex multi-step strategies (borrow → swap → farm → rebalance) in a single atomic transaction. - **Composability** — external protocols see the Credit Account as a standard EOA-like contract. No special integrations needed from their side. ## Leverage with Delayed Deposits The Credit Account primitive uniquely solves a problem that traditional lending protocols cannot: **leverage on assets with non-atomic settlement**. ### The Looping Problem Many assets — tokenized securities (ACRED), staked positions, RWA deposits — have settlement delays. A deposit of USDC into ACRED might take 2 days to mint. On traditional platforms (Morpho, Aave), building a 10x leveraged position with such a token requires **looping**: deposit collateral → wait 2 days → use the minted token as collateral → borrow more → deposit again → wait 2 more days → repeat. Getting to 10x leverage takes weeks. ### Phantom Tokens: Instant Leverage Gearbox solves this with **phantom tokens** — on-chain representations of pending positions that act as collateral *during* the settlement period. ```mermaid flowchart LR subgraph "Traditional (Looping)" T1["Deposit $100"] -->|"wait 2 days"| T2["Get Token"] T2 -->|"use as collateral"| T3["Borrow $85"] T3 -->|"deposit again"| T4["wait 2 days..."] T4 -->|"repeat 8x"| T5["~3 weeks for 10x"] end subgraph "Gearbox (Instant)" G1["Deposit $100 + Borrow $900"] -->|"same tx"| G2["Send $1000 to mint"] G2 --> G3["Receive phantom token"] G3 --> G4["10x leverage, Day 0"] end ``` How it works: 1. User opens a Credit Account, deposits \$100 collateral, borrows \$900 2. The Credit Account sends \$1,000 to the issuer's deposit contract 3. While the deposit is pending (2 days), the Credit Account receives a **phantom token** — a futures-like representation of the position 4. The phantom token is accepted as collateral by the Credit Manager (configured by the curator), keeping the account solvent 5. When the deposit matures, the phantom token is replaced by the real asset The user gets 10x leverage **on day zero**, not after weeks of looping. The curator configures the phantom token's liquidation threshold to reflect settlement risk. This is why the Credit Account is the right primitive for RWAs and delayed deposits — it holds the entire position (collateral + debt + pending assets) in one isolated contract, making the settlement state visible and manageable at the protocol level. ## The Lending Stack Capital flows through three layers: from liquidity source, through a Credit Manager, into Credit Accounts that interact with DeFi. ```mermaid flowchart LR subgraph "Liquidity Source" Markets["Gearbox Markets\n(Pooled)"] Intent["Intent-Based\n(P2P)"] end subgraph "Credit Manager" CM["Credit Manager\n(Policy Keeper)"] end subgraph "Credit Accounts" CA1["Credit Account"] CA2["Credit Account"] CA3["Credit Account"] end subgraph "DeFi Protocols" Uniswap["Uniswap"] Curve["Curve"] Lido["Lido"] Aave["Aave"] end Markets -->|"lend"| CM Intent -->|"lend"| CM CM --> CA1 CM --> CA2 CM --> CA3 CA1 -->|"via Adapters"| Uniswap CA2 -->|"via Adapters"| Curve CA2 -->|"via Adapters"| Lido CA3 -->|"via Adapters"| Aave ``` ### Layer 1: Liquidity Source Where the capital comes from. Two models, same Credit Account primitive underneath: - **[Gearbox Markets](https://docs.gearbox.finance/developers/gm-overview)** (pooled) — many lenders deposit into a shared Pool. Dynamic rates based on utilization. Quotas limit per-token exposure. - **Intent-Based** (P2P) — one lender matches one borrower directly. Fixed or reference-based rates (LIBOR + 2%). Custom terms per deal. ### Layer 2: Credit Manager The **policy keeper**. Each Credit Manager defines the rules: which collateral tokens are accepted, which DeFi protocols can be used, what leverage is allowed. The Credit Manager borrows from the liquidity source and allocates to Credit Accounts. ### Layer 3: Credit Accounts → DeFi The **execution layer**. Each Credit Account is an isolated contract holding collateral + borrowed funds. Through **Adapters**, it interacts with external DeFi protocols — swap on Uniswap, stake on Lido, deposit on Curve. **Multicalls** batch all operations into a single atomic transaction with a solvency check at the end. ## Zoom Into the Credit Account The Credit Account is the foundation of the entire stack. Everything — markets, P2P lending, leveraged farming, RWA settlement — is built by composing operations on top of this single primitive. Here's what makes it work. ### Multi-Collateral Solvency A Credit Account can hold **many tokens simultaneously** — WETH, USDC, stETH, CRV LP tokens, phantom tokens. The Credit Manager iterates over all of them to compute the account's value: For each token in the account: 1. Get the **price** from a dual oracle — `min(main feed, reserve feed)` — protection against manipulation 2. Apply the **Liquidation Threshold** — e.g., WETH at 90% means \$100 of ETH counts as \$90 3. Cap the contribution by the token's **Quota** — concentration limit per token 4. Sum into the **Total Weighted Value (TWV)** Then: ``` Health Factor = TWV / Total Debt where Total Debt = principal + accrued interest + quota fees ``` If **HF >= 1** → account is solvent. If **HF < 1** → account is liquidatable. ### Check-on-Exit: The Execution Model The Credit Account doesn't check solvency on every operation — only at the end of a multicall. This is the **check-on-exit** model: > **Example: building a leveraged stETH position** > > 1. `addCollateral` — deposit \$100 USDC > 2. `increaseDebt` — borrow \$900 USDC from Pool > 3. `swap` (via Uniswap adapter) — swap \$1,000 USDC → WETH > 4. `stake` (via Lido adapter) — stake WETH → stETH > 5. `deposit` (via Curve adapter) — deposit stETH into Curve pool > 6. **Final check: HF >= 1?** → Yes: TX succeeds. No: entire TX reverts. Between steps 2 and 5, the account is temporarily insolvent — it has \$900 debt but collateral is mid-transformation. This is fine because all operations are **atomic**: if the final check fails, everything reverts as if nothing happened. No bad debt can ever be created. ### The Building Block This is why every product on Gearbox reduces to the same primitive: | Product | What Happens Inside the Credit Account | | --- | --- | | Leveraged Farming | Borrow → swap → deposit into yield vault | | Margin Trading | Borrow → swap to long/short asset | | RWA Settlement | Borrow → deposit with issuer → hold phantom token | | Structured Credit | P2P terms → borrow → deploy into strategy | The Credit Manager defines *which* operations and tokens are allowed. The Credit Account executes them. The solvency check enforces safety. Everything else — pools, quotas, insurance, oracles — exists to support this core loop. ## Deep Dive - [**Credit Accounts**](https://docs.gearbox.finance/developers/gm-concept-accounts) — The Credit Suite architecture (Manager, Facade, Configurator), account lifecycle, and configuration parameters - [**Multicall System**](https://docs.gearbox.finance/developers/gm-concept-multicalls) — All available operations, the diff pattern, safety controls, and bot permissions - [**Health Factor & Risk**](https://docs.gearbox.finance/developers/gm-concept-risk) — TWV formula, Liquidation Thresholds, Quotas, Dual Oracle, Loss Policy, and liquidation mechanics ## What's Next - [**Gearbox Markets**](https://docs.gearbox.finance/developers/gm-overview) — The pooled lending product built on top of this stack - [**Start building**](https://docs.gearbox.finance/developers/gm-start-ts) — Install the SDK and make your first call ## Gearbox Protocol – Monad LP Opportunity Source: https://docs.gearbox.finance/developers/gearbox-protocol-monad-lp-opportunity File: content/developers/gearbox-protocol-monad-lp-opportunity.mdx ### Overview Gearbox is a composable leverage protocol enabling undercollateralized on-chain borrowing through Credit Accounts. Current focus: yield strategies via Midas-issued collateral. **Two ways to participate:** | | Lending | Leverage | | ------- | -------------------------------------------- | ------------------------------------------- | | APY | 6-9% | Up to 20% | | Role | Passive liquidity provider | Active carry trade | | Risk | Indirect exposure, protected by liquidations | Direct collateral exposure | | Lock-up | None | None (subject to Midas redemption schedule) | *** ### Lending Side (Passive) **How it works:** Deposit USDC into the Gearbox pool. Earn yield from borrowers who use Credit Accounts to execute carry trades, borrowing at pool rates to deploy into higher-yielding RWA collateral. Gearbox solvency guardrails protect against borrower default. **Deposit here:** [Gearbox USDC Pool](https://app.gearbox.finance/pools/143/0x6b343f7b797f1488aa48c49d540690f2b2c89751) *** ### Leverage Side (Active) **How it works:** Open a Credit Account, borrow USDC, and deploy into Midas collaterals. Capture the full carry trade spread with leverage. **Yield source:** Direct exposure to mEDGE yield minus borrow cost. Net APY can reach 20% at max leverage (\~7x). **Zero slippage execution:** Gearbox direct integration allows entry/exit without DEX slippage. Redemptions execute at NAV. → [How Direct Redemptions Work](https://docs.gearbox.finance/core/usecase-direct-redemptions) **Open position here:** [mEDGE Leverage Strategy](https://app.gearbox.finance/strategies/open/143/0x1c8ee940b654bfced403f2a44c1603d5be0f50fa) *** ### Risk Framework #### Collateral Exposure: mEDGE Both sides have exposure to mEDGE (Midas EDGE vault). Current composition: → [View mEDGE Holdings](https://midas.app/medge) #### What happens if mEDGE depegs? | Scenario | Lending Side | Leverage Side | | ----------------- | ------------------------------------------------------- | --------------------------- | | Depeg <13% | Protected: liquidations trigger, borrowers absorb loss. | Position may be liquidated. | | Orderly wind-down | Redemptions via direct integration at NAV | Exit at NAV, no slippage | #### Gearbox Solvency Guardrails * **LTV limits:** Credit Accounts enforce max leverage * **Liquidation threshold:** Positions liquidated before insolvency * **Price feeds:** Oracle-based with sanity checks * **Audits:** [Security repo](https://github.com/Gearbox-protocol/security/tree/main/audits) *** ### Summary | | Lending | Leverage | | --------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | Target LP | Passive yield seekers | Active DeFi users | | APY | 6-9% | Up to 20% | | Risk | Lower (liquidation buffer) | Higher (direct exposure) | | Effort | Deposit & forget | Manage position | | Deposit | [Pool](https://app.gearbox.finance/pools/143/0x6b343f7b797f1488aa48c49d540690f2b2c89751) | [Strategy](https://app.gearbox.finance/strategies/open/143/0x1c8ee940b654bfced403f2a44c1603d5be0f50fa) | *** ## Gearbox LP Demo Day – Blurb **Project:** Gearbox Protocol **Project Description:** Composable leverage protocol with Credit Accounts enabling undercollateralized on-chain borrowing. Two LP opportunities on RWA yield strategies: * **Lending side:** Passive yield from borrower demand (6-9% APY) * **Leverage side:** Active carry trade via Credit Accounts (up to 20% APY) **Max TVL capacity:** 50M USDC in mid-term (nearest month) until considerable yield dilution.\ Further expansion driven by new collaterals addition. **Yield APY:** 6-9% (lending) / up to 20% (leverage) **Source of yield:** Carry trade between Gearbox borrow rates and Midas RWA collateral (mEDGE). Lenders earn borrow interest + MON incentives; leverage users capture full carry. **Duration of deal:** No lock-up **Audit link:** **Your contact:** Telegram - @OxIlya ## Manual Deleveraging When UI Actions Are Unavailable Source: https://docs.gearbox.finance/developers/manual-deleveraging-when-ui-actions-are-unavailable File: content/developers/manual-deleveraging-when-ui-actions-are-unavailable.mdx If the **Close** or **Swap** action is unavailable or fails, you can exit your position manually by following the steps below. 1 ## Withdraw collateral Withdrawing collateral sends the token to your wallet, where you can swap it freely using external liquidity sources outside of Gearbox. Withdrawing collateral reduces your position’s **Health Factor**. A large withdrawal may push the position into liquidation risk. \ \ Always check the projected **Health Factor** before each withdrawal.
Withdraw collateral in the UI ![Figure](https://docs.gearbox.finance/assets/docs/core/manual-deleveraging-when-ui-actions-are-unavailable/01-withdraw-collateral.png)
If your current **Health Factor** does not allow for a safe withdrawal, repay part of your debt first using the Debt Token from your wallet (see **Step 3**). 2 ## Swap collateral into the Debt Token Swap the withdrawn collateral into the Debt Token using external liquidity sources. Recommended options include: * DEX aggregators * Official liquidity venues provided by the collateral issuer 3 ## Repay debt using Debt Token from your wallet Repay the debt using the **same token the debt is denominated in**, directly from your wallet. Check whether the updated **Health Factor** allows for further withdrawal.
Repay debt in the UI ![Figure](https://docs.gearbox.finance/assets/docs/core/manual-deleveraging-when-ui-actions-are-unavailable/02-repay-debt-using-debt-token-from-your-wallet.png)
4 ## Repeat Steps 1-3 until your Credit Account reaches the desired state or is fully unwound ## Seamless LP migration Source: https://docs.gearbox.finance/developers/seamless-lp-migration File: content/developers/seamless-lp-migration.mdx ### Why migrate (what you gain as an LP) **In short:** better incentives and better market coverage. As Gearbox transitions to the permissionless curation model, rewards and activity shift to the new pools. Old pools will stop receiving rewards and become non-competitive over time. New pools are where curators focus liquidity and opportunities. New Curator pools combine two reward streams: * baseline, time-weighted TVL incentives to bootstrap passive liquidity * performance-based rewards proportional to the Curator’s revenue share. In practice, the aggregate rewards allocated to the permissionless model are about 3x the legacy LM run-rate, with dilution tied more closely to real usage and protocol revenue (supporting buybacks). As a result, effective yield in new pools is expected to be higher than in legacy pools. *** ### Purpose This LP migration contract is designed to allow users migrate liquidity without monitoring the pools for available liquidity: * Designed for the case where immediate migration is not possible due to liquidity constraints. * Users can pre-sign their intention to migrate by granting allowance to the migration contract. * The migration will be executed by the instance owner multisig as soon as liquidity becomes available. In other words, this contract is a safe automation tool: * You lock in your intent to move from the old pool to the new one. * You don’t have to monitor liquidity or time the transaction yourself. * The migration will happen at the first opportunity. *** #### How it Works There are only two functions in the migration contract: 1. User function (allowance setup) * You give the migration contract allowance for your LP tokens in the old pool. * This does not move funds immediately — it only means: > “Whenever possible, please take my LP tokens from the old pool and put them into the new pool.” * After signing, you are done. 2. Instance owner function (execute migration) * Can only be called by the instance owner multisig (chain-specific). However, instance owner can't do anything except for migrating liquidity between the pools specified by user. * Once liquidity becomes available, they trigger the migration: * LP tokens are redeemed from the old pool. * Assets are deposited into the new pool on behalf of the user. * Both *old pool* and *new pool* are fixed parameters of the contract and cannot be changed. *** #### Safety of Allowance * **Immutable destination:** your funds can only move old pool → new pool. * **No arbitrary spending:** allowance is strictly limited to the old pool LP tokens. * **Controlled execution:** the migration logic is minimalistic and fixed in contract. Even if instance owner multisig goes malicious, its actions can't result in user losing money. *** #### Migration Lifecycle 1. User grants allowance * Approves their LP tokens to be used by migration contract. 2. Monitoring phase * Liquidity in old pools may be fully utilized (100%). * Gearbox contributors monitor until withdrawals are possible. 3. Execution phase * Instance owner calls the migration function at the first chance. * Funds are moved automatically on behalf of the user who granted the allowance. 4. Completion * Users now hold LP tokens in the new pool. * Yield continues seamlessly. *** ### Why now (governance & versions) Gearbox is moving from V3.0 to V3.1 to solidify the permissionless governance direction. Under permissionless curation, DAO-approved curators can configure markets and parameters, and the protocol can scale across networks without slow, centralized bottlenecks. **This migration is happening because:** * Maintaining two versions is technically **complex and fragments liquidity.**\ Supporting both legacy pools and new permissionless pools in parallel would complicate operations and potentially reduce yields for everyone. Consolidating liquidity in the new system is safer and more efficient. * Legacy pools had the **DAO as the sole curator - this is changing.**\ In the permissionless model, curators manage markets directly within clear, on-chain constraints. So legacy pools either need to be turned off or migrated to preserve TVL in the ecosystem. * It’s **better for LPs.**\ Rewards and curator attention move to the new pools. Old pools will become non-competitive over time. Specialized curators are expected to maintain attractive rates more consistently than DAO-only governance, because they operate faster and stay deeper in the market. *** #### Batching and timelines To reduce multisig overhead and make the best use of liquidity windows, we process migrations in batches. * **Positions up to $1,000,000.**\ Migrated in full within the nearest suitable batch. * **Positions above $1,000,000.**\ Moved in several chunks. This is normal and helps keep utilization healthy while your position transitions. * **Target batch size.**\ We aim to group requests into roughly $1,000,000 batches to execute efficiently when liquidity allows. * **FIFO queueing.**\ LP requests are processed in chronological order. This keeps the process transparent and predictable. * **Timing.**\ Your migration may wait while a batch fills. The maximum wait time will not exceed 14 days. #### FAQ * **Can the migration contract move my funds anywhere else?**\ No. It can only move LP from the specific old pool to the specific new pool you selected. * **Why would APY be higher in the new pools?**\ New pools stack baseline TVL incentives with performance-based rewards linked to real fee generation. The overall incentive budget for the permissionless phase is roughly 3x legacy LM, with dilution aligned to revenue (supports buybacks), so effective yields are expected to be superior versus legacy pools. * **What if utilization in the old pool is 100% for a while?**\ We keep your request in the FIFO queue and execute at the first safe window. Batching helps reduce delays. * **Do I keep earning yield?**\ Yes. After migration you hold LP in the new pool and continue earning according to its parameters and incentives. ## Credit Account migration Source: https://docs.gearbox.finance/developers/credit-account-migration File: content/developers/credit-account-migration.mdx ### Why migrate (what you gain as a Borrower) **In short:** incentives, better execution and more favorable rates. **Incentives:** * One-time fixed reward paid in GEAR. Distributed retroactively. **Better execution:** * Improved routing and support for new adapters increases capital efficiency and reduces costs. **Favorable rates:** * Vote-based collateral-specific rate discovery is depreciated in favor of curator-controlled rates. ### Requirements for allowing a migration into your Market 1. All the collaterals of old account should be allowed in a credit manager of target Market 2. The position can be only migrated as a whole, target Market should have appropriate debt limits and capacity. 3. If the underlying token is changed during migration, new market must support swaps from new underlying to old one.\ E.g. you can migrate rstETH from an old wstETH pool to a new WETH pool, but WETH -> wstETH swap must be allowed in the new pool. ### How it works 1. New credit account is opened in a target market 2. Amount of tokens enough to repay old account is borrowed from a new account 3. Newly-borrowed tokens are swapped into underlying tokens of old account 4. Old account's debt is repaid and its collateral is transferred to the new account ## Quota increase fee Source: https://docs.gearbox.finance/developers/quota-increase-fee File: content/developers/quota-increase-fee.mdx When user increases Quota (Credit Account specific max amount of debt that can be backed by particular collateral), charge a fixed % fee on the quota difference: works like a one-time fee charged on swaps by exchanges. Added to account's Debt. Distributed as a DAO & Curator fee on repayment according to the fee split rules. ## Key concepts & system overview Source: https://docs.gearbox.finance/developers/key-concepts-system-overview File: content/developers/key-concepts-system-overview.mdx ## Key concepts and system overview With permissionless architecture Gearbox has became even more composable, evolving into a techical stack that allows growing lending businesses, developing DeFi ecosystems and deploy lending markets on any chain by enyone having interest and capacity to do so. is the entrypoint for no-code deployment, curation and collaboration with Gearbox. #### What is permissionless? Anyone can deploy Market Configurator to create and manage Gearbox Markets without needing governance approval. #### What is Gearbox Market? Gearbox Market is a set of modular contracts allowing to facilitate lending, borrowing and productive usage of collaterals at rules set by Curator.\ Properties of a single market include but are not limited to Underlying Token, its Price Feed, Interest Rate Model, collateral-specific Limits and Additional Rates. #### What is Gearbox Instance? **Instance** = **Chain ID** activated by DAO for deployment + Chain-specific address of **DAO Treasury** + **Instance Owne**r multisig that helps configure chain-specific parameters but can't affect Markets configuration. #### What can curator change? The Curator can adjust all Market parameters, with a mandatory 24-hour timelock enforced at the smart-contract level for any changes. #### What is possible with permissionless curation? Each market consists of tens of contracts, including Pool, Oracle, IRM, Loss policy, Credit Managers and Adapters. Such modular architecture allows creating products with market-best flexibility and granular parametrization making Gearbox Protocol the premier platform for crafting sophisticated financial products that address specific market demands and drive long-term value creation. Below is a diagram of the contracts and parameters that a curator can configure, so you can get an idea of how detailed market configuration can be. ![Figure](https://docs.gearbox.finance/assets/docs/curators/key-concepts-system-overview/01-system.png) ## Curator's operations Source: https://docs.gearbox.finance/developers/curator-s-operations File: content/developers/curator-s-operations.mdx Morpho has pioneered the concept of curated lending markets in DeFi, but its approach differs significantly from Gearbox's model. Below is a clear comparison of how curators function in each protocol: #### Morpho: Active Capital Allocation In Morpho, curators are active capital allocators. They: * Distribute depositors' funds across various yield-generating markets. * Operate within markets defined by immutable parameters, such as Loan-to-Value (LTV) ratios and oracles. #### Gearbox: Risk Parameter Management In Gearbox, curators have a more limited role, focusing solely on risk management. They: * Set risk parameters for markets, such as LTV ratios or liquidation thresholds. * Have no authority to move or allocate depositors' funds, which remain under user or protocol control. | Action | Gearbox | Morpho | | ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Add exposure to new collateral |
  1. Set collateral limit, LTV and oracle for a new token in Market
  2. Borrowers can now use pool's liquidity
|
  1. Add nonzero supply cap for existing market (LTV and oracle are pre-configured)
  2. Deposit vault's funds to the new market
  3. Borrowers can now use vault's liquidity
| | Modify collateral LTV or Price Feed |
  1. Set new price feed
  2. Start ramp of LTV to target value
  3. Feed & LTV for old and new borrowers are changed
|
  1. Deploy a market with needed LTV and oracle and set nonzero supply cap for it
  2. Feed & LTV are changed only for new borrowers
  3. Start withdrawing liquidity from old market & push borrowers out by raising rate
| | Increase/decrease collateral-specific borrow rate |
  1. Set a new collateral-specific rate in addition to IRM utilization rate
|
  1. Move vault's allocation in/out of the Market to move dynamic IRM
| | Enable 1-click leverage for a collateral |
  1. Allow the list of needed adapters in the Market
|
  1. Contact contango or another strategy provider to integrate your collateral
| ## Gearbox Markets Overview Source: https://docs.gearbox.finance/developers/gm-overview File: content/developers/gm-overview.mdx Gearbox Markets is a pooled lending model where multiple lenders deposit into a shared liquidity Pool, and borrowers open Credit Accounts to access leverage. It is one of two lending models built on the Gearbox [Credit Account primitive](https://docs.gearbox.finance/developers/intro-101) — the other being [Intent-Based (P2P) Lending](#alternative-intent-based-p2p-lending). ## The Wholesale Bank Model Think of a Gearbox Market as a wholesale bank: ```mermaid flowchart TD L1[Lender A] -->|"deposit"| Pool["Pool (ERC-4626)\nUSDC, WETH, etc."] L2[Lender B] -->|"deposit"| Pool L3[Lender C] -->|"deposit"| Pool Pool -->|"debt ceiling: 80M"| CM1["Credit Manager A\n(Blue Chip Strategy)"] Pool -->|"debt ceiling: 10M"| CM2["Credit Manager B\n(Emerging Assets)"] CM1 --> CA1[Credit Account] CM1 --> CA2[Credit Account] CM2 --> CA3[Credit Account] ``` 1. **Pool** — a passive ERC-4626 vault. Many lenders deposit into the same Pool and receive **Diesel Tokens** (dUSDC, dWETH) — yield-bearing receipts whose value appreciates as borrowers pay interest. 2. **Credit Managers** — act as policy keepers. Each Credit Manager defines a specific lending strategy: which collateral tokens are accepted, which DeFi protocols can be used, what leverage is allowed. A single Pool can fund multiple Credit Managers, each with an isolated **Debt Ceiling**. 3. **Credit Accounts** — isolated smart contract wallets where borrowers deposit collateral and deploy borrowed funds. All DeFi operations happen inside the Credit Account. The Credit Manager checks solvency after every operation. ## Risk Isolation Unlike monolithic lending protocols where bad debt in one asset drains the entire pool, Gearbox isolates risk via Debt Ceilings: - A Pool holds \$100M USDC - \$80M allocated to a Blue Chip strategy (low risk) - \$10M allocated to an Emerging Assets strategy (high risk) - If the Emerging Assets strategy fails, the loss is capped at \$10M — the remaining \$90M is mathematically isolated Lenders earn blended yield from all strategies but are protected from tail risk of any single one. ## Quotas: Per-Token Risk Pricing Quotas are unique to Gearbox Markets. They solve two problems at once: **Concentration limits** — a hard cap on how much of any single collateral token can back debt across the Pool. This prevents over-concentration in volatile assets. **Risk-priced interest** — each collateral token carries its own **Quota Rate** on top of the base Pool rate. Riskier tokens cost more to use as collateral. ``` Total Borrow APR = Base Rate (from Pool utilization) + Quota Rate (per collateral token) ``` For example, using WETH as collateral might add +1% to the borrow rate, while using a governance token adds +5%. ## Unified Yield for Lenders Lenders don't need to choose which strategy to back. The Diesel Token abstracts everything: - Deposit USDC into the Pool → receive dUSDC - Interest from all Credit Managers flows back to the Pool - dUSDC exchange rate appreciates over time - Withdraw anytime (subject to available liquidity) ## Market Curators Any entity — institution, DAO, individual — can permissionlessly deploy a Credit Manager and become a **Market Curator**. Curators manage *parameters*, not *funds*: - Collateral tokens and liquidation thresholds - Enabled DeFi adapters (Uniswap, Curve, Lido, etc.) - Fee structure and debt limits - Interest rate curve parameters The system is fully non-custodial. See [Gearbox Permissionless](https://docs.gearbox.finance/developers/gp-overview) for how this works. --- ## Alternative: Intent-Based (P2P) Lending Gearbox Markets uses pooled liquidity. But the Credit Account primitive also enables a fundamentally different model: **peer-to-peer lending** where a single lender and a single borrower agree on terms directly. | | Gearbox Markets (Pooled) | Intent-Based (P2P) | | --- | --- | --- | | **Liquidity** | Many lenders → shared Pool | One lender ↔ one borrower | | **Rates** | Dynamic (utilization-based) | Fixed or reference-based (LIBOR + 2%) | | **Risk** | Socialized across Pool LPs | Isolated per deal | | **Collateral** | Curator-defined allowlist | Custom per agreement | | **Best for** | DeFi-native strategies, retail | Institutional, RWA, bespoke terms | In both models, the borrower operates through a Credit Account — the same solvency checks, adapters, and liquidation mechanics apply. The difference is how the capital is sourced. --- ## What's in This Section - [**Concepts**](https://docs.gearbox.finance/developers/gm-concepts) — Markets, Credit Accounts, Multicall System, Health Factor & Risk - [**Getting Started**](https://docs.gearbox.finance/developers/gm-start) — Set up the TypeScript SDK - [**Markets**](https://docs.gearbox.finance/developers/gm-markets) — Query pools, rates, quotas, and insurance state - [**Credit Accounts**](https://docs.gearbox.finance/developers/gm-accounts) — Open, manage, and close positions - [**Smart Contracts**](https://docs.gearbox.finance/developers/gm-contracts) — Contract reference (methods, events, parameters) - [**Guides**](https://docs.gearbox.finance/developers/gm-guides) — Frontend, backend, and bot tutorials ## Concepts Source: https://docs.gearbox.finance/developers/gm-concepts File: content/developers/gm-concepts.mdx Concepts specific to the Gearbox Markets pooled lending model. For foundational concepts (Credit Accounts, Multicalls, Health Factor) see [The Lending Stack](https://docs.gearbox.finance/developers/intro-101). - [**Markets**](https://docs.gearbox.finance/developers/gm-concept-markets) — The Pool → Credit Manager → Credit Account architecture. How a single liquidity vault funds multiple strategies with isolated risk. Debt Ceilings and Diesel Tokens. Topics covered here but not in The Lending Stack: - **Interest Rate Model** — utilization-based rate curves specific to pooled lending - **Market Curators** — the permissionless operator role that configures risk parameters - **Quotas** — per-token concentration limits and risk-priced interest (exist only in Markets, not P2P) ## Tooling for curators Source: https://docs.gearbox.finance/developers/tooling-for-curators File: content/developers/tooling-for-curators.mdx ## Essential tooling for curators Gearbox goes beyond providing just a protocol by offering a complete ecosystem of tools tailored for curators. These tools enable: * **Market Configuration**: Safely set up and manage lending markets with intuitive interfaces. * **Transaction Integrity**: Ensure the accuracy and security of transactions before they are executed onchain. * **Pre-Deployment Testing**: Test changes in a controlled environment to validate configurations and prevent errors. * **Multi-Chain Support**: Operate seamlessly on almost any EVM-compatible blockchain. #### Curation Supply Chain The curation supply chain in Gearbox is supported by a set of specialized tools designed to streamline market deployment and transaction management while prioritizing security and transparency. **Permissionless Interface** * **URL**: * **Purpose**: Enables curators to create transaction batches for market deployment and configuration using human-readable tables. The interface generates transaction data, which is uploaded to IPFS, with the Content Identifier (CID) signed by the GIP creator to prevent phishing. * **Note**: This interface can't modify onchain state directly; it consists both of a frontend and backend maintained by Gearbox contributors. Therefore it shouldn't be perceived as a final source of truth for onchain state or actions. ![Figure](https://docs.gearbox.finance/assets/docs/curators/tooling-for-curators/01-curation-supply-chain.png) **Permissionless Safe** * **URL:** [**https://safe.gearbox.finance/**](https://safe.gearbox.finance/) * **Repository**: * **Purpose**: An open-source, IPFS-hosted version of the Safe Multisig UI designed to review and sign transactions securely in a human-readable format. It eliminates backend dependencies to mitigate risks like Bybit-type attacks and performs checks of IPFS CID signature to prevent phishing. * **Note**: The open-source nature and IPFS hosting ensure users can verify the code's integrity. ![Figure](https://docs.gearbox.finance/assets/docs/curators/tooling-for-curators/02-curation-supply-chain.png) **Anvil Fork-Based Simulations** * **Purpose**: A unique Gearbox service that allows curators to test market configurations and transaction changes on a fork of the blockchain before onchain execution. This ensures the correctness of state changes and supports testing of various Gearbox components, including liquidators, routers, and frontends. ![Figure](https://docs.gearbox.finance/assets/docs/curators/tooling-for-curators/03-curation-supply-chain.png) ## Markets Source: https://docs.gearbox.finance/developers/gm-concept-markets File: content/developers/gm-concept-markets.mdx A Gearbox Market is a pooled lending system: one Pool, multiple Credit Managers, many Credit Accounts. This page explains how these components connect. ## Architecture ```mermaid flowchart TD L1[Lender A] --> Pool L2[Lender B] --> Pool L3[Lender C] --> Pool Pool[Pool - ERC-4626] --> CM1[Credit Manager A] Pool --> CM2[Credit Manager B] CM1 --> CA1[Credit Account] CM1 --> CA2[Credit Account] CM1 --> CA3[Credit Account] CM2 --> CA4[Credit Account] ``` ## Pool The Pool is a passive ERC-4626 vault holding a single underlying asset (USDC, WETH, DAI). It does not lend directly to borrowers — it allocates capital to Credit Managers. **Diesel Tokens** — when lenders deposit, they receive dTokens (dUSDC, dWETH). These are yield-bearing receipt tokens: - Non-rebasing: value accrues through exchange rate increases - Represent a pro-rata share of all Pool assets - Yield comes from interest paid by *all* connected Credit Managers The lender's experience is simple: deposit → hold dToken → withdraw with yield. No need to pick strategies. ## Credit Manager The Credit Manager is the **policy keeper** of a specific lending strategy. It defines: | Parameter | What It Controls | | --- | --- | | **Collateral tokens** | Which tokens can be held in Credit Accounts | | **Liquidation Thresholds** | Per-token discount factors for solvency calculation | | **Adapters** | Which DeFi protocols Credit Accounts can interact with | | **Debt limits** | Min/max debt per account | | **Fees** | Liquidation premium, protocol fee | A single Pool typically has multiple Credit Managers — each representing a different risk profile configured by its Market Curator. ### Debt Ceiling Each Credit Manager has a **Debt Ceiling** — the maximum amount it can borrow from the Pool. This is how risk isolation works: - Credit Manager A (blue chips, LT 85-90%) gets \$80M ceiling - Credit Manager B (emerging tokens, LT 60-75%) gets \$10M ceiling - If B's strategy causes bad debt, the loss is capped at \$10M ## Credit Account The Credit Account is where borrowing happens. When a user opens a Credit Account under a specific Credit Manager: 1. User deposits collateral into the account 2. Credit Manager borrows from the Pool on the account's behalf 3. Borrowed funds are sent directly to the Credit Account 4. User deploys capital via [Multicalls](https://docs.gearbox.finance/developers/gm-concept-multicalls) (swap, farm, stake) 5. Credit Manager checks solvency after every operation The Credit Account is an isolated smart contract — its state (collateral, debt, enabled tokens) is separate from every other account. ## Quotas Quotas exist only in Gearbox Markets (not in P2P lending). They serve two purposes: ### Concentration Limits A hard cap on how much total debt across the Pool can be backed by a specific collateral token. Example: even if there's \$100M in the Pool, at most \$20M of debt can be backed by CRV tokens. This prevents a single volatile asset from dominating pool risk. ### Risk-Priced Interest Each collateral token carries a **Quota Rate** — an additional interest rate charged to borrowers who use that token. Riskier tokens cost more: | Collateral | Quota Rate | Meaning | | --- | --- | --- | | WETH | +0.5% | Low risk, low extra cost | | wstETH | +1% | Liquid staking, moderate | | CRV | +5% | Governance token, volatile | ``` Total Borrow APR = Base Rate + Quota Rate ``` The Base Rate is driven by Pool utilization (supply/demand). The Quota Rate is set by the Curator (or voted via Gauge/Tumbler) based on collateral risk. ## How It All Connects ```mermaid flowchart LR Lender -->|"deposit USDC"| Pool Pool -->|"issue dUSDC"| Lender Pool -->|"lend to CM"| CM[Credit Manager] CM -->|"borrow for account"| CA[Credit Account] Borrower -->|"multicall"| Facade[Credit Facade] Facade -->|"route"| CM CM -->|"check solvency"| Oracle[Price Oracle] Curator -->|"set params"| Config[Credit Configurator] Config -->|"update"| CM ``` - **Lenders** interact with the Pool only - **Borrowers** interact with the Credit Facade → Credit Manager → Credit Account - **Curators** interact with the Credit Configurator → Credit Manager - **Liquidators** interact with the Credit Facade to liquidate unhealthy accounts ## Learn More - [**Credit Accounts**](https://docs.gearbox.finance/developers/gm-concept-accounts) — The Credit Suite architecture in detail - [**Quotas & Interest Rates**](https://docs.gearbox.finance/developers/gm-markets-rates) — Querying rates programmatically - [**Pool Operations**](https://docs.gearbox.finance/developers/gm-markets-pools) — Deposit/withdraw via SDK - [**Gearbox Markets Overview**](https://docs.gearbox.finance/developers/gm-overview) — Including comparison with P2P lending ## Credit Accounts Source: https://docs.gearbox.finance/developers/gm-concept-accounts File: content/developers/gm-concept-accounts.mdx A Credit Account is the core primitive of Gearbox Protocol. It is an isolated smart contract that holds a borrower's collateral and borrowed funds, enabling leveraged interaction with DeFi protocols while maintaining strict solvency guarantees. ## The Credit Suite Each Credit Account belongs to a **Credit Suite** — a trio of tightly coupled contracts: ```mermaid flowchart TD User[User / Bot] Curator[Market Curator] subgraph "Credit Suite" Facade[Credit Facade] Manager[Credit Manager] Config[Credit Configurator] end subgraph "Infrastructure" Pool[Pool V3] Oracle[Price Oracle] Account[Credit Account] end User -->|"multicall"| Facade Curator -->|"configure"| Config Config -->|"updates"| Facade Config -->|"updates"| Manager Facade -->|"validates & routes"| Manager Manager -->|"borrows/repays"| Pool Manager -->|"deploys/manages"| Account Manager -->|"valuation"| Oracle ``` ### Credit Facade (Entry Point) The user-facing contract. Borrowers submit multicall transactions here. The Facade validates requests, routes operations to the Credit Manager, and enforces the final solvency check. ### Credit Manager (Accounting Engine) The core logic contract. It tracks debt, manages collateral, calculates health factors, and interacts with the Pool for borrowing/repayment. The Credit Manager maintains the registry of all Credit Accounts and their state. ### Credit Configurator (Admin Interface) The governance contract. Market Curators use it to manage risk parameters — collateral tokens, liquidation thresholds, adapters, fees, and debt limits. All impactful changes pass through timelocks. ## Account Lifecycle 1. **Open** — User deposits collateral and borrows from the Pool. A Credit Account contract is deployed (or reused from a pool of pre-deployed accounts). 2. **Operate** — User executes multicalls: swap collateral, farm yield, adjust leverage. All operations happen *inside* the Credit Account. The user never directly touches Pool liquidity. 3. **Monitor** — The account's Health Factor (collateral value vs. debt) is continuously assessable. If it drops below 1, the account becomes liquidatable. 4. **Close** — User repays all debt + interest + fees. Remaining collateral is returned to the user's wallet. The Credit Account is returned to the reuse pool. ## Key Properties **Isolation** — Each Credit Account is a separate contract. One account's operations or losses cannot affect another. **Check-on-Exit** — Any sequence of whitelisted operations is allowed within a multicall, but the account must remain solvent (HF >= 1) when the multicall ends. This enables complex strategies that may be temporarily insolvent mid-execution. **Non-Custodial** — Neither the protocol nor the Market Curator can access funds inside a Credit Account. Only the account owner (and authorized bots with explicit permissions) can operate on it. **Composable** — Through Adapters, Credit Accounts can interact with any whitelisted DeFi protocol (Uniswap, Curve, Lido, Aave, etc.) as if they were regular EOA wallets — but with solvency enforcement. ## Configuration Parameters Market Curators define the risk profile for all Credit Accounts in their suite: | Parameter | Description | | --- | --- | | **Liquidation Threshold (LT)** | Per-token discount factor for solvency calculation. LT of 85% means \$100 of ETH counts as \$85 toward collateralization. | | **Collateral Tokens** | Allowed tokens in Credit Accounts. Unlisted tokens are valued at zero. | | **Adapters** | Whitelisted DeFi protocol integrations (Uniswap, Curve, etc.). | | **Debt Limits** | Minimum and maximum debt per account, preventing dust or concentration risk. | | **Fees** | Liquidation fee (to protocol) and liquidation premium (to liquidator). | ## Learn More - **How operations are batched and executed** — [Multicall System](https://docs.gearbox.finance/developers/gm-concept-multicalls) - **How solvency is measured and enforced** — [Health Factor & Risk](https://docs.gearbox.finance/developers/gm-concept-risk) - **Working with Credit Accounts in code** — [Credit Accounts (SDK)](https://docs.gearbox.finance/developers/gm-accounts) ## Multicall System Source: https://docs.gearbox.finance/developers/gm-concept-multicalls File: content/developers/gm-concept-multicalls.mdx The multicall system is the transaction model for all Credit Account operations in Gearbox. It allows complex DeFi strategies — borrowing, swapping, farming, adjusting collateral — to execute atomically in a single transaction with a solvency check at the end. ## Why Multicalls? In traditional lending protocols, each operation (deposit collateral, borrow, swap) is a separate transaction. This creates problems for leveraged positions: - **Mid-execution insolvency** — after borrowing but before deploying capital, the account is technically undercollateralized - **Gas inefficiency** — multiple transactions mean multiple solvency checks - **Sandwich risk** — separate swap transactions are vulnerable to MEV Multicalls solve all three: batch everything into one transaction, check solvency once at the end. ## How It Works ```mermaid flowchart TD User[User / Bot] -->|"multicall(account, calls)"| Facade[Credit Facade] Facade -->|"1. Start"| Loop[Execution Loop] Loop --> Check{Target?} Check -->|"Facade"| Internal[Internal Operation] Check -->|"Adapter"| Adapter[Adapter Contract] Internal -->|"addCollateral, increaseDebt..."| Loop Adapter -->|"swap, deposit, stake..."| Protocol[DeFi Protocol] Protocol --> Loop Loop -->|"2. All calls done"| Security[Security Checks] Security --> HF{Health Factor >= 1?} HF -->|"Yes"| Success[Transaction Success] HF -->|"No"| Revert[Transaction Reverts] ``` 1. **Start** — The Facade begins the multicall and sets the Credit Account as "active" 2. **Execute** — Each call in the array runs sequentially. Calls target either the Facade (internal operations) or an Adapter (external DeFi protocol calls) 3. **Check** — After all calls complete, the Facade performs security checks: slippage verification, forbidden token checks, and a full collateral check (HF >= 1) 4. **Result** — If the account is solvent, the transaction succeeds. If not, the entire transaction reverts — nothing happened. ## Available Operations ### Protocol Operations | Operation | What It Does | | --- | --- | | `addCollateral` | Move tokens from wallet to Credit Account | | `increaseDebt` | Borrow underlying from Pool | | `decreaseDebt` | Repay debt to Pool | | `updateQuota` | Enable/adjust quota for a collateral token | | `withdrawCollateral` | Remove assets from account | ### Safety Controls | Operation | What It Does | | --- | --- | | `onDemandPriceUpdates` | Push fresh price data (must be first call) | | `storeExpectedBalances` | Record balances before swaps for slippage check | | `compareBalances` | Verify balances after swaps meet minimums | | `setFullCheckParams` | Optimize the collateral check with token hints | ### External Calls (via Adapters) Adapters are whitelisted wrappers around DeFi protocols. Each adapter restricts which functions a Credit Account can call and validates outcomes. Through adapters, a Credit Account can: - Swap tokens on Uniswap, Curve, or other DEXes - Deposit into yield vaults (Yearn, ERC-4626) - Stake tokens (Lido, Convex) - Provide liquidity (Curve, Balancer) ## The "Diff" Pattern Adapters implement "diff" functions (e.g., `swapDiff`, `depositDiff`) for handling unknown amounts. Instead of specifying exact input: - **Standard**: needs exact `amountIn` - **Diff**: calculates `amountIn = currentBalance - leftoverAmount` This is essential when the result of a previous operation is unknown — for example, swapping all received tokens from a prior withdrawal. ## Functions That Accept Multicalls All state-changing CreditFacade functions accept a multicall array: | Function | Purpose | | --- | --- | | `openCreditAccount` | Create a new account with initial operations | | `closeCreditAccount` | Close account, return remaining funds | | `multicall` | Execute operations on existing account | | `botMulticall` | Bot-initiated operations (requires permissions) | | `liquidateCreditAccount` | Liquidate unhealthy account | ## Best Practices 1. **Price updates first** — always put `onDemandPriceUpdates` at the start when using pull-based oracles (Pyth, Redstone) 2. **Slippage protection** — use `storeExpectedBalances` before swaps and `compareBalances` after 3. **Dust management** — use `type(uint256).max` in `withdrawCollateral` to empty balances completely 4. **Gas optimization** — use `setFullCheckParams` with token mask hints for accounts with many enabled tokens ## Learn More - **Building multicalls in TypeScript** — [Multicalls (SDK)](https://docs.gearbox.finance/developers/gm-accounts-multicalls) - **Individual operation details** — [Adding Collateral](https://docs.gearbox.finance/developers/gm-mc-collateral), [Debt Management](https://docs.gearbox.finance/developers/gm-mc-debt), [External Calls](https://docs.gearbox.finance/developers/gm-mc-external) - **How solvency is enforced** — [Health Factor & Risk](https://docs.gearbox.finance/developers/gm-concept-risk) ## Verify & Simulate Source: https://docs.gearbox.finance/developers/verify-simulate File: content/developers/verify-simulate.mdx Before executing any transaction on the mainnet (which costs gas, time and operations), it's better to verify that configuration works as intended. Gearbox provides a **Simulation Service** (Fork Testing). The system spins up a temporary "Sandbox" copy of the blockchain, applies your changes, and runs a list of tests. ## Automated Safety Checks The simulation runs a suite of automated checks to ensure your parameters are safe and functional. You should review the output of these tests (typically provided in the GIP report or Interface). | Test Category | What it checks | Why it matters | |---|---|---| | Router Paths | Can the system find a path to swap your new collateral into the underlying asset? | If this fails, users won't be able to open leveraged positions in a single transactions. Atomic liquidations will also be harmed. | | Insolvency | Does Collateral Value * Liquidation Threshold cover the debt? | Ensures there are no errors that allow immediate bad debt. | | Optimistic Liquidation | Can a liquidator actually sell the collateral on a DEX to repay the debt profitably? | If liquidity is too low for the configured parameters, the system will flag it. | | State Diff | Does the simulated blockchain state match your intended configuration? | Verifies that the transaction data you generated actually does what is expected. | ## The "Staging" App (User Experience Test) Automated tests check the math, but they don't check the experience. The simulation service generates a temporary **Staging Frontend** connected to the Sandbox fork. **Action:** Open the Staging App link and act as a user. 1. **Connect Wallet:** Use a test wallet (the fork will impersonate your tokens). 2. **Open a Position:** Try to borrow funds using your new strategy. 3. **Execute a Trade:** Try to swap assets or deposit into a vault via the adapter. 4. **Close/Repay:** Ensure you can exit the position. **After the fork has been created and the tests have passed, you can open the App connected to the test blockchain state.** ![Figure](https://docs.gearbox.finance/assets/docs/curators/verify-simulate/01-the-staging-app-user-experience-test.png) #### Application test walkthrough []() ## Prepare the Main Interface Once the contracts are deployed, they exist on the blockchain, but the official Gearbox Interface (app.gearbox.finance) may not know the imporant data: token icon, collateral APY, the list of points earned by borrowers or suppliers. For the tokens and strategies to be supported by the app, ensure that frontend configuration has all the required data: [listing-a-new-asset-in-the-main-app](https://docs.gearbox.finance/curators/listing-a-new-asset-in-the-main-app "mention") ## Next Steps If the simulations pass and the UI looks correct, you are ready to execute the transactions onchain. ## Health Factor & Risk Source: https://docs.gearbox.finance/developers/gm-concept-risk File: content/developers/gm-concept-risk.mdx The Health Factor is the core solvency metric in Gearbox. It determines whether a Credit Account is healthy, at risk, or liquidatable. Understanding how it's calculated — and the mechanisms that manage risk — is essential for building on the protocol. ## Health Factor The Health Factor (HF) is the ratio of risk-adjusted collateral value to total debt: ``` Health Factor = Total Weighted Value (TWV) / Total Debt ``` - **HF >= 1** — account is solvent - **HF < 1** — account is liquidatable ### Total Weighted Value (TWV) TWV is not simply the market value of collateral. Each token's value is discounted by its **Liquidation Threshold (LT)** and capped by its **Quota**: ``` TWV = Sum( min(Quota_i, Balance_i * Price_i * LT_i) ) / Price_underlying ``` For example, if an account holds \$100 of ETH with an LT of 90%, the system values it at \$90 for solvency purposes. ### Total Debt ``` Total Debt = Principal + Base Interest + Quota Interest + Fees ``` - **Principal** — the amount borrowed from the Pool - **Base Interest** — accrued from the Pool's utilization-based interest rate - **Quota Interest** — additional rate for each collateral token based on its risk profile - **Fees** — quota increase fees and other protocol charges ## Liquidation Thresholds Each collateral token has a Liquidation Threshold (LT) — a percentage that determines how much of its value counts toward solvency: | Token | LT | Meaning | | --- | --- | --- | | WETH | 90% | \$100 of ETH counts as \$90 | | WBTC | 85% | \$100 of BTC counts as \$85 | | CRV | 72% | \$100 of CRV counts as \$72 | Higher LT = more leverage possible. Lower LT = more conservative, safer. LT changes use a **ramping mechanism** — they interpolate linearly over a minimum of 24 hours, preventing sudden liquidation cascades. ## Quota System Quotas are per-token exposure limits that cap how much of each collateral asset counts toward solvency across the system: 1. **Quota Limits** — hard caps on total debt backed by a specific collateral asset. Prevents over-concentration in a single token. 2. **Quota Rates** — additional interest charged based on collateral risk. A volatile governance token might carry +5% quota rate on top of the base rate. ``` Total APR = Base Rate (from Pool utilization) + Quota Rate (from collateral risk) ``` ## Dual Oracle System Every collateral asset has two independent price feeds: - **Main Feed** — used for solvency calculation and liquidation triggers. Often a fundamental/backing price (e.g., exchange rate from the token contract). - **Reserve Feed** — used for safety validation during user operations. Often a market price (e.g., Chainlink spot). The system uses the **safe price** — the minimum of both feeds — for operations like withdrawals and debt increases. This creates an automatic circuit breaker against price manipulation or oracle failures. ``` Safe Price = min(Main Price, Reserve Price) ``` ## Liquidations When HF drops below 1, anyone can liquidate the account: ### Partial Liquidation (Deleverage) - Triggered when HF is below target but account is still partially solvent - Sells only enough collateral to restore HF to a target level - Lower premium than full liquidation - Executed by the Deleverage Bot ### Full Liquidation - Triggered when HF < 1 significantly - Liquidator repays total debt and claims all collateral at a discount - Liquidator profit = collateral value × liquidation premium - gas cost ### Bad Debt If collateral value is less than total debt after liquidation: 1. Unclaimed protocol fees (Treasury LP shares) are burned to cover the shortfall 2. Any remaining loss is socialized across all Pool LPs via Diesel Token exchange rate reduction ## Loss Policy The Loss Policy prevents liquidation cascades during market crashes. Instead of immediately liquidating at distressed market prices: 1. Check if HF < 1 using market price 2. If bad debt would result, recheck using fundamental (aliased) price 3. Only liquidate if the account is fundamentally insolvent This protects against flash crash scenarios while still handling genuine insolvency. ## Learn More - **Monitoring health factor in code** — [Credit Accounts (SDK)](https://docs.gearbox.finance/developers/gm-accounts) - **Insurance mechanism** — [Insurance](https://docs.gearbox.finance/developers/gm-markets-insurance) - **Liquidation bot implementation** — [Liquidation Bots Guide](https://docs.gearbox.finance/developers/gm-guide-bots) ## Overview Source: https://docs.gearbox.finance/developers/sdk-guide File: content/developers/sdk-guide.mdx The Gearbox SDK provides typed access to protocol state and operations. It wraps contract calls, handles encoding, and provides cached market data through a clean TypeScript interface. ## Prerequisites - Node.js 18+ - Basic familiarity with [viem](https://viem.sh/) - Understanding of async/await patterns ## What the SDK Provides | Component | Purpose | | --- | --- | | `GearboxSDK` | Main entry point with `attach()` initialization | | `marketRegister` | Cached market data access | | `addressProvider` | Contract discovery wrapper | | Plugins | Extended functionality (AccountsPlugin, AdaptersPlugin) | | Services | Credit account operations and multicall helpers | ## Guide Structure 1. [**Setup**](https://docs.gearbox.finance/developers/sdk-setup) — Installation, SDK initialization, basic configuration 2. [**Reading Data**](https://docs.gearbox.finance/developers/reading-data) — Market queries, account state, pool data 3. [**Credit Accounts**](https://docs.gearbox.finance/developers/credit-accounts) — Account operations via services 4. [**Multicalls**](https://docs.gearbox.finance/developers/multicalls) — Building and executing multicalls ## When to Use the SDK | Use Case | Recommended | | --- | --- | | Frontend applications | Yes | | Analytics dashboards | Yes | | Liquidation bots | Yes (or direct compressor calls) | | Backend services | Yes | | On-chain contracts | No (use Solidity Guide) | The SDK handles ABI management, type conversions, and caching internally. For on-chain integrations or gas-optimized bot implementations, consider the [Solidity Guide](https://docs.gearbox.finance/developers/overview-2). ## Architecture Understanding For conceptual background on how Gearbox works: - [Credit Suite Architecture](https://docs.gearbox.finance/developers/credit-suite) — How Credit Managers, Facades, and Configurators work together - [Pool Architecture](https://docs.gearbox.finance/developers/pools) — Lending pools and ERC-4626 compliance - [Multicall System](https://docs.gearbox.finance/developers/multicall-system) — How multicalls execute and validate --- ## Detailed Guides ### Multicall Operations Complete reference for each multicall operation with TypeScript examples: | Operation | Description | | --- | --- | | [Adding Collateral](https://docs.gearbox.finance/developers/adding-collateral) | Transfer tokens to credit account | | [Debt Management](https://docs.gearbox.finance/developers/debt-management) | Borrow and repay | | [Updating Quotas](https://docs.gearbox.finance/developers/updating-quotas) | Manage collateral quotas | | [Withdrawing Collateral](https://docs.gearbox.finance/developers/withdrawing-collateral) | Remove tokens from account | | [Controlling Slippage](https://docs.gearbox.finance/developers/controlling-slippage) | Protect against price movement | | [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls) | Interact with DeFi protocols | | [Enabling/Disabling Tokens](https://docs.gearbox.finance/developers/enabling-disabling-tokens) | Manage active collateral | | [Updating Price Feeds](https://docs.gearbox.finance/developers/updating-price-feeds) | On-demand oracle updates | | [Collateral Check Params](https://docs.gearbox.finance/developers/collateral-check-params) | Optimize health checks | | [Revoke Allowances](https://docs.gearbox.finance/developers/revoke-allowances) | Security cleanup | See [Multicalls Overview](https://docs.gearbox.finance/developers/multicalls) for building and executing multicalls. ### Use Case Guides Application-specific guides for common development scenarios: | Building | Guide | Focus | | --- | --- | --- | | Web UI / Dashboard | [Frontend Applications](https://docs.gearbox.finance/developers/frontend-applications) | Data display, real-time updates | | Analytics / Indexer | [Backend Services](https://docs.gearbox.finance/developers/backend-services) | Historical data, event indexing | | Liquidation Bot | [Liquidation Bots](https://docs.gearbox.finance/developers/liquidation-bots) | Monitoring, Router execution | ## Price feeds' configuration Source: https://docs.gearbox.finance/developers/price-feeds-configuration File: content/developers/price-feeds-configuration.mdx The feeds configurations are reviewed at . It requires CID of txs file uploaded to IPFS. ![Figure](https://docs.gearbox.finance/assets/docs/curators/price-feeds-configuration/01-price-feeds-configuration.png) #### TL;DR (Actionable checklist) 1. Txs simulation must pass. Click on Simulate button next to each batch to check. 2. Check the displayed price in the multisig UI to adequatly match current market values 1. Review allowPriceFeed transactions. 2. Grab the token address and verify its price on a DEX aggregator () 3. If not tradable on aggregators, ask the proposer for the correct reference (e.g. Pendle UI for PTs, Curve UI for LP tokens, or the issuer’s app for derivatives/vaults) 4. Zero price feed (always returns $0) can be safely added to any token for compatibility. 3. Check staleness period of the feed 1. Pull feeds → 4 min staleness 2. Push feeds → Heartbeat + 15 min (Ethereum) / Heartbeat + 2 min (L2s & faster chains). 4. Check that the feed contract is verified 1. Confirm verification on the chain’s block explorer. 5. Check that feeds are adequately capped from above: 1. Stablecoin feeds are capped by $1.04 from above 2. PT feeds for dollar-pegged vaults are capped by $1 from above 6. If the feed is deployed from external factory, it should use no Pull feeds as underlying feeds of factory deployment. ⚠️ If any of these criteria aren’t met: don’t sign, ask in chat for clarification. ✅ For a setLimiter transactions it's enough to check that simulation passes. This action updates exchange rate bounds of LP price feeds, and its correctness is checked on a contract level. *** #### 1) Purpose & Scope These Terms & Conditions define the minimum due‑diligence and neutral‑gatekeeping standards for IO signers when **adding, configuring, or allowing** price feeds in the **Price Feed Store (PFS)** on any supported EVM chain. The sole goal is to ensure that, **at the moment of signing**, every configured feed **returns an adequate market price for the intended token, normalized to 8 decimals**, and satisfies staleness / quality constraints. > Scope explicitly excludes any market‑risk, business, or curation decisions. IO signers act only as neutral technical gatekeepers. *** #### 2) Authority, Membership & Neutrality (summary) * **Authority (PFS):** IO may add/remove feeds; set staleness period; attach/detach feeds to tokens; and run feed configuration calls required by integrated providers. * **Neutrality:** IO remains **business-neutral**. Decisions must be based **only on objective technical criteria** below. All valid, safe requests should be processed in a reasonable timeframe. * **Non‑interference with markets:** PFS changes **do not alter behavior of existing Markets by themselves** and **are not auto‑applied** to them. *** #### 3) Definitions & Expectations * **Price Feed Store (PFS):** Chain‑specific registry of tokens and feeds. A token can be used as collateral only after its token entry and at least one allowed feed are present. * **8‑decimal normalization:** All effective Gearbox price feeds **must return USD‑denominated prices with 8 decimals** (`1e8` scale). Signers should verify output scale when checking a feed. * **Staleness Period:** Maximum allowed time since last update before a feed is considered stale and reverts/invalidates. * **Adequate market price:** A price reasonably close to reputable sources at the time of signing. *** #### 4) Pre‑Signing Due‑Diligence (hard requirements) **Signers must complete all checks below before approving the transaction.** If any check fails, **do not sign.** **4.1 Contract & Deployment** 1. **Feed contract is verified** on a reputable explorer (Etherscan/chain explorer). 2. If the feed is not external, it must be deployed from Bytecode Repository. **4.2 Price Output & Decimals** 1. **Price sanity:** Read the feed (via explorer read panel, provider dashboard, or PFS UI). The value must be **within a reasonable range** of one or more of: 1. **CoinGecko** (or equivalent public index), 2. **Trusted DEX/aggregators** (Uniswap/Curve/Balancer; 1inch/Cow/Odos), 3. **Designated platforms** when public indexes are unavailable (e.g., **Pendle markets** for PTs; **Pyth Insights**; **Redstone App**; protocol UIs for ERC4626 vault exchange rate). 2. **Decimals:** Confirm that the effective price value is **normalized to 8 decimals**. **4.3 Staleness** 1. **Staleness period** must be reasonable for the source and chain: 1. **Pull‑type feeds (e.g., Pyth/Redstone pull):** *recommended* `240s` (4 min) unless documented otherwise. 2. **External Aggregator feeds (push/heartbeat):** heartbeat **+ 15 min** (slower chains, e.g. Ethereum) or **+ 2 min** (faster chains, e.g. L2s). **4.4 Asset‑Specific Parameters (when applicable)** 1. **Stablecoin‑to‑USD feeds:** The observed price should be **bounded from above at 1.04**. 2. **Pegged assets feeds (LST-to-ETH, LRT-to-BTC, cbBTC-to-BTC etc.):** The observed ratio should be **bounded from above at 1.04**. *** #### 5) Refusal Policy If **any** requirement in fails or is inconclusive, **do not sign any transactions**. Examples: * Contract not verified; * Output not 8‑decimals normalized; * Price materially diverges from reputable venues; * Staleness period unreasonable for the source/chain; * Asset‑specific parameters missing/incorrect. *** ### Asset classes Asset class is a pair of (token-specific features, price feed methodology) which defines the behavior of collateral in different market scenarios. The same token can have different risks for LPs/Borrowers if priced differently. All of the tokens can be borrow-only or used as collaterals. \ Consider cases of * Correlated debt/collateral pairs * Volatile debt/collateral pairs Describe the policy of setting reserve feeds and aliased loss policy. Take into account that pull feeds providers (pyth and especially redstone) can be less reliable than push Some of the used feeds can be provided by token issuer itself (for example Resolv PoR, midas feeds etc.) and have no strict update frequency (we've seen Resolv update PoR feeds 2 hours later than was initially stated) 1. Stablecoins/ synthetic dollars\ USDT, USDe, USDai, DAI, USDf etc. 2. ETH or BTC equivalents 1. stETH, tBTC etc 3. Yield-bearing vaults\ Stream.finance xUSD, Midas vaults, tETH, LRTs etc. 1. Priced using ERC4626 feeds 2. Priced using composite feeds (prices can be market-based, exchange rate or PoR) 4. Pendle PT tokens 1. TWAP-based pricing or deterministic feeds 5. Curve, Balancer LP tokens 1. For the tokens having rate oracle or erc4626 vault attached in Curve or Balancer pools, oracle price appreciation is automatically displayed in virtual\_price 6. Pendle LP tokens 1. TWAP-based pricing or deterministic feeds 7. Delayed withdrawal phantom tokens 1. Since delayed withdrawal tokens are not liquidatable, the most favorable setting is when the position's HF is high enough not to fall below 1 due to accrued debt while redemption is being processed.\ \ One of the ways to achieve it is to set reserve feed of withdrawal token to be lower than its Main feed by some percentage. This percentage will effectively enforce the minimal health factor for user to have to initiate delayed withdrawal.\ \ Reserve to main price discount of 2% will mean that user has to maintain HF above \~1.02 to initiate full withdrawal of his collateral. ## Getting Started Source: https://docs.gearbox.finance/developers/gm-start File: content/developers/gm-start.mdx Choose how you want to integrate with Gearbox Markets. ## Integration Paths | Path | Best For | Status | | --- | --- | --- | | [**TypeScript (SDK)**](https://docs.gearbox.finance/developers/gm-start-ts) | Frontend apps, bots, analytics dashboards, backend services | Available | | [**GraphQL**](https://docs.gearbox.finance/developers/gm-start-graphql) | Querying indexed data, dashboards, lightweight integrations | Coming soon | ## TypeScript SDK The Gearbox SDK provides typed access to protocol state and operations. It wraps contract calls, handles encoding, and provides cached market data through a clean TypeScript interface. | Component | Purpose | | --- | --- | | `GearboxSDK` | Main entry point with `attach()` initialization | | `marketRegister` | Cached market data access | | `addressProvider` | Contract discovery wrapper | | Plugins | Extended functionality (AccountsPlugin, AdaptersPlugin) | | Services | Credit account operations and multicall helpers | **Prerequisites:** Node.js 18+, basic familiarity with [viem](https://viem.sh/). [Get started with TypeScript](https://docs.gearbox.finance/developers/gm-start-ts) ## SDK Namespaces Source: https://docs.gearbox.finance/developers/gm-start-namespaces File: content/developers/gm-start-namespaces.mdx The SDK vNext organizes its API into purpose-built namespaces. Each namespace groups related methods so you can discover, analyze, and execute without navigating raw contract state. ## Namespace Reference | Namespace | Purpose | | --- | --- | | `sdk.chains` | Multi-chain configuration — list supported chains, resolve RPC endpoints, check chain health | | `sdk.opportunities` | Unified discovery surface — search across all opportunity types (pools, strategies, markets) in one call | | `sdk.pools` | Pool-specific queries — list pools, get detail, check utilization, interest rates, and available liquidity | | `sdk.strategies` | Strategy-specific queries — list strategies, get detail, inspect adapters and leverage ranges | | `sdk.markets` | X-interface style markets — unified market view combining supply and borrow sides, useful for P2P and intent flows | | `sdk.tokens` | Token profiles and market data — prices, metadata, risk parameters, and enrichment info | | `sdk.curators` | Curator profiles and reputation — who manages which Credit Managers, track record, parameters | | `sdk.history` | Metric history time series — APY over time, utilization, TVL, and other historical data points | | `sdk.events` | Parameter changes and governance — feed of configuration updates, rate changes, and governance actions | | `sdk.positions` | Position lifecycle — deposit, open, adjust, close, and monitor Credit Account positions | | `sdk.trades` | Quote and routing — get swap quotes, compare routes, preview trade outcomes | | `sdk.transactions` | Final execution — submit prepared transactions, track confirmation, handle MEV protection | ## Runtime Modes The SDK operates in one of two runtime modes depending on backend availability: **Core-Only** — works without a backend connection. Supports chain reads, transaction building, simulation, execution, and current position status. Limited for history, profiles, APY enrichment, and snapshots. **Enriched** — available when the Gearbox backend is configured and healthy. Adds opportunity surfaces, historical data, curator/token profiles, points and APY enrichment, and fast bootstrap via `startFromCache`. ```ts import { GearboxSDK } from "@gearbox-protocol/sdk/official"; // Enriched mode (default) — uses backend at api.gearbox.fi const sdk = new GearboxSDK(); // Core-only mode — no backend dependency const sdk = new GearboxSDK({ backend: false }); ``` ## Loading Modes Two loading strategies control how aggressively the SDK fetches state: **Lazy (default)** — no heavy state load on startup. Each query fetches only what it needs. Best for frontend screens, agent queries, and partial usage. **Full-State** — loads broad chain state upfront. Best for dense workflows, advanced analysis, and fast repeated navigation after the initial bootstrap. ```ts // Lazy loading (default) await sdk.loadState({ mode: "lazy" }); // Full-state loading await sdk.loadState({ mode: "full-state" }); ``` Both modes coexist — you can start lazy and switch to full-state later if your workflow demands it. ## Learn More - [Getting Started — TypeScript SDK](https://docs.gearbox.finance/developers/gm-start-ts) — installation and bootstrap - [Opportunities](https://docs.gearbox.finance/developers/gm-opportunities) — discover yield across all types - [Lender (Pools)](https://docs.gearbox.finance/developers/gm-lender) — pool queries and deposits - [Positions (Strategies)](https://docs.gearbox.finance/developers/gm-positions) — open and manage leveraged positions ## TypeScript Source: https://docs.gearbox.finance/developers/gm-start-ts File: content/developers/gm-start-ts.mdx Install and initialize the Gearbox SDK, then read your first market data. ## Installation ```bash npm install @gearbox-protocol/sdk viem ``` ## Initialize the SDK ```typescript import { GearboxSDK } from '@gearbox-protocol/sdk'; import { createPublicClient, http } from 'viem'; import { mainnet } from 'viem/chains'; const client = createPublicClient({ chain: mainnet, transport: http(), }); const sdk = await GearboxSDK.attach({ client, marketConfigurators: [], // Empty = auto-discover all markets }); ``` | Parameter | Type | Description | | --- | --- | --- | | `client` | `PublicClient` | viem client instance | | `marketConfigurators` | `Address[]` | Filter to specific configurators, or `[]` for all | ## Read Market Data The SDK exposes markets through `marketRegister`: ```typescript // All markets const markets = sdk.marketRegister.markets; // Find by pool address const market = sdk.marketRegister.findByPool(poolAddress); // Find by credit manager const market = sdk.marketRegister.findByCreditManager(cmAddress); // Access market data const pool = market.pool; console.log(`Underlying: ${pool.underlying.symbol}`); console.log(`Total assets: ${pool.totalAssets}`); console.log(`Available liquidity: ${pool.availableLiquidity}`); ``` ## Read Pool State ```typescript const pool = market.pool; // Interest rates (RAY = 27 decimals) const RAY = 10n ** 27n; const supplyAPY = Number(pool.supplyRate * 10000n / RAY) / 100; const borrowAPR = Number(pool.baseInterestRate * 10000n / RAY) / 100; console.log(`Supply APY: ${supplyAPY}%`); console.log(`Borrow APR: ${borrowAPR}%`); // Share price console.log(`Diesel rate: ${pool.dieselRate}`); ``` ## Read Credit Manager Config ```typescript for (const cm of market.creditManagers) { console.log(`Credit Manager: ${cm.address}`); console.log(`Min debt: ${cm.minDebt}`); console.log(`Max debt: ${cm.maxDebt}`); // Allowed collateral tokens for (const token of cm.collateralTokens) { console.log(` ${token.symbol}: LT ${token.liquidationThreshold}`); } } ``` ## Use Plugins Plugins extend SDK functionality: ```typescript import { AccountsPlugin, AdaptersPlugin } from '@gearbox-protocol/sdk'; sdk.use(new AccountsPlugin()); sdk.use(new AdaptersPlugin()); // Query accounts const accounts = sdk.accounts.byCreditManager(cmAddress); // Query adapters const adapters = sdk.adapters.byProtocol('uniswap-v3'); ``` | Plugin | Purpose | | --- | --- | | `AccountsPlugin` | Credit account indexing and filtering | | `AdaptersPlugin` | Protocol adapter discovery and metadata | ## Address Provider The SDK wraps AddressProvider for contract discovery: ```typescript import { AP_MARKET_COMPRESSOR, VERSION_RANGE_310 } from '@gearbox-protocol/sdk'; const [compressor] = sdk.addressProvider.mustGetLatest( AP_MARKET_COMPRESSOR, VERSION_RANGE_310 ); ``` ## Real-Time Data via Compressors The SDK caches data on initialization. For live data, call compressors directly: ```typescript import { marketCompressorAbi, AP_MARKET_COMPRESSOR, VERSION_RANGE_310 } from '@gearbox-protocol/sdk'; const [compressor] = sdk.addressProvider.mustGetLatest( AP_MARKET_COMPRESSOR, VERSION_RANGE_310 ); const freshData = await client.readContract({ address: compressor, abi: marketCompressorAbi, functionName: 'getMarketData', args: [poolAddress], }); ``` ## Complete Example ```typescript import { GearboxSDK, createCreditAccountService } from '@gearbox-protocol/sdk'; import { createPublicClient, http } from 'viem'; import { mainnet } from 'viem/chains'; async function main() { const client = createPublicClient({ chain: mainnet, transport: http(), }); const sdk = await GearboxSDK.attach({ client, marketConfigurators: [], }); const RAY = 10n ** 27n; for (const market of sdk.marketRegister.markets) { const pool = market.pool; const supplyAPY = Number(pool.supplyRate * 10000n / RAY) / 100; console.log(`\n=== ${pool.underlying.symbol} Market ===`); console.log(`Pool: ${pool.address}`); console.log(`Total assets: ${pool.totalAssets}`); console.log(`Supply APY: ${supplyAPY.toFixed(2)}%`); console.log(`Credit Managers: ${market.creditManagers.length}`); } // Create service for account operations const service = createCreditAccountService(sdk, 310); const usdcMarket = sdk.marketRegister.markets.find( m => m.pool.underlying.symbol === 'USDC' ); if (usdcMarket) { const accounts = await service.getCreditAccounts( { creditManager: usdcMarket.creditManagers[0].address }, sdk.currentBlock ); console.log(`\nFound ${accounts.length} USDC credit accounts`); } } main().catch(console.error); ``` ## Next Steps - [Markets Data](https://docs.gearbox.finance/developers/gm-markets-data) — Query pools, rates, and collateral info - [Credit Accounts](https://docs.gearbox.finance/developers/gm-accounts) — Open and manage leveraged positions - [Multicalls](https://docs.gearbox.finance/developers/gm-accounts-multicalls) — Build and execute operations ## GraphQL Source: https://docs.gearbox.finance/developers/gm-start-graphql File: content/developers/gm-start-graphql.mdx GraphQL integration for querying indexed Gearbox protocol data. > This guide is coming soon. The GraphQL API is currently under development. ## What to Expect The GraphQL API will provide: - Indexed market and pool data with historical snapshots - Credit account state queries with filtering and pagination - Event-based activity feeds (deposits, borrows, liquidations) - Real-time subscriptions for position monitoring ## In the Meantime Use the [TypeScript SDK](https://docs.gearbox.finance/developers/gm-start-ts) for all integrations. It provides: - Cached market data via `marketRegister` - Real-time queries via [Compressors](https://docs.gearbox.finance/developers/gm-ref-compressors) (on-chain data aggregation contracts) - Credit account indexing via `AccountsPlugin` ## Opportunities Source: https://docs.gearbox.finance/developers/gm-opportunities File: content/developers/gm-opportunities.mdx An **Opportunity** is any way to earn yield in Gearbox, presented at the highest level of abstraction. It is the entry point for discovery — before you decide whether to lend or leverage, you search opportunities. ## Unified Discovery `sdk.opportunities.search()` returns a unified list of all opportunity types across all chains and pools. This single call replaces the need to separately query pools, strategies, and markets. ```ts // Search all opportunities const all = await sdk.opportunities.search(); // Filter by criteria const highYield = await sdk.opportunities.search({ minApy: 5, chainId: 1, assetClass: "stablecoin", }); ``` ## Opportunity Types There are two opportunity types available today, with two more planned: ### Available Now | Type | Description | User Role | | --- | --- | --- | | **Lender Opportunity** (`pool`) | Provide liquidity to a Pool, receive Diesel Tokens, earn passive yield | Lender / LP | | **Strategy Opportunity** (`strategy`) | Borrow from a Pool, deploy capital via a Credit Account with leverage | Borrower / Strategist | ### Future Types (Not Yet Implemented) | Type | Description | User Role | | --- | --- | --- | | **Intent Opportunity** (`intent`) | Limit-order style LP with custom terms (P2P supply side) | Lender | | **Intent Strategy** (`intent_strategy`) | P2P leveraged position with bespoke terms | Borrower | ## Opportunity Fields Every opportunity shares a common shape regardless of type: ```ts interface Opportunity { id: string; // Unique identifier chainId: number; // Chain where this opportunity exists type: OpportunityKind; // "pool" | "strategy" | "market" headlineApy: number; // Primary APY figure (supply APY or net strategy APY) depositToken: string; // Token you deposit to enter capacity: bigint; // Available liquidity / remaining capacity access: string; // Access control level curator?: string; // Curator managing this opportunity riskScore?: number; // Backend-enriched risk assessment } ``` Strategy opportunities add fields like `targetToken`, `leverage`, and `adapters`. Pool opportunities add fields like `utilizationRate` and `dieselToken`. ## Learn More - [Lender Opportunities](https://docs.gearbox.finance/developers/gm-opps-lender) — passive yield via Pool deposits - [Strategy Opportunities](https://docs.gearbox.finance/developers/gm-opps-strategy) — leveraged yield via Credit Accounts - [SDK Namespaces](https://docs.gearbox.finance/developers/gm-start-namespaces) — full namespace reference ## Lender Opportunities Source: https://docs.gearbox.finance/developers/gm-opps-lender File: content/developers/gm-opps-lender.mdx Lender opportunities represent the supply side of Gearbox — you deposit tokens into a Pool, receive yield-bearing Diesel Tokens in return, and earn passive yield as borrowers pay interest. ## What They Represent When you enter a lender opportunity, you are depositing into an ERC-4626 Pool. The Pool issues Diesel Tokens (e.g., dUSDC, dWETH) whose exchange rate appreciates over time as interest accrues from borrowers. No active management is required. ## Sub-Types | Sub-Type | Description | Status | | --- | --- | --- | | `pool` | Standard LP in an ERC-4626 Pool — deposit, earn yield, withdraw anytime | Available | | `intent` | Limit-order style LP with custom terms (rate, duration, collateral preferences) | Future | ## Discovering Lender Opportunities Use either the opportunities namespace for unified search or the pools namespace for direct queries: ```ts // Via unified search const lenderOpps = await sdk.opportunities.search({ type: "pool" }); // Via pools namespace directly const pools = await sdk.pools.list(); ``` ## Key Fields | Field | Description | | --- | --- | | `depositToken` | The token you deposit (USDC, WETH, etc.) | | `headlineApy` | Current supply APY — what lenders earn | | `capacity` | Available liquidity remaining in the Pool | | `access` | Access control — permissionless or gated | | `utilizationRate` | Current Pool utilization (higher = more yield, less exit liquidity) | | `dieselToken` | The yield-bearing receipt token you receive | ## Filtering You can filter lender opportunities by asset class, chain, and minimum APY: ```ts // All USDC lender opportunities with APY > 3% const usdcOpps = await sdk.opportunities.search({ type: "pool", depositToken: "USDC", minApy: 3, }); // Stablecoin opportunities on Arbitrum const arbStables = await sdk.opportunities.search({ type: "pool", chainId: 42161, assetClass: "stablecoin", }); ``` ## Example: List High-Yield USDC Pools ```ts import { GearboxSDK } from "@gearbox-protocol/sdk/official"; const sdk = new GearboxSDK(); await sdk.loadState({ mode: "lazy" }); const opps = await sdk.opportunities.search({ type: "pool", depositToken: "USDC", minApy: 3, }); for (const opp of opps) { console.log( `${opp.id} | APY: ${opp.headlineApy.toFixed(2)}% | Capacity: ${opp.capacity}` ); } ``` ## Next Steps - [Pool Operations](https://docs.gearbox.finance/developers/gm-markets-pools) — how to actually deposit and withdraw - [Interest Rates & Quotas](https://docs.gearbox.finance/developers/gm-markets-rates) — how supply APY is calculated - [Strategy Opportunities](https://docs.gearbox.finance/developers/gm-opps-strategy) — the borrower side ## Overview Source: https://docs.gearbox.finance/developers/overview File: content/developers/overview.mdx Build on Gearbox Protocol. Choose your path based on how you'll integrate. ## Choose Your Path ### [SDK Guide (TypeScript)](https://docs.gearbox.finance/developers/sdk-guide) **Best for:** Frontend developers, bot builders, analytics dashboards The SDK provides typed access to Gearbox protocol state and operations. It wraps contract calls, handles encoding, and provides cached market data. * Read market state via `marketRegister` * Query credit accounts via services * Build multicalls with helpers * No Solidity knowledge required ### [Solidity Guide](https://docs.gearbox.finance/developers/overview-2) **Best for:** Smart contract developers, on-chain integrators, adapter builders Integrate directly with Gearbox contracts from your Solidity code. * Discover contracts via AddressProvider * Call CreditFacade operations * Build multicalls in Solidity * Build custom adapters ## Reference * [Concepts](https://github.com/de-snake/docs-knowledge/blob/new-docs-dev-1/concepts/README.md) - Architecture explanations (no code) * [Compressors](https://docs.gearbox.finance/developers/compressors) - Data aggregation contracts * [Automated Insurance](https://docs.gearbox.finance/developers/automated-insurance) - Protocol safety mechanisms * [Interest Rate Model](https://docs.gearbox.finance/core/interest-rate-model) - Utilization curves and rates * [Quota Keeper](https://docs.gearbox.finance/developers/quota-keeper) - Collateral exposure limits ## Quick Links | Need | Go to | | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Install SDK | [SDK Setup](https://docs.gearbox.finance/developers/sdk-setup) | | Find contract addresses | [Credit Accounts](https://docs.gearbox.finance/developers/credit-accounts) | | Understand Credit Suite | [Credit Suite Concepts](https://docs.gearbox.finance/developers/credit-suite) | | Build multicalls | [SDK Multicalls](https://docs.gearbox.finance/developers/multicalls) or [Solidity Multicalls](https://docs.gearbox.finance/developers/multicalls) | | Query credit accounts | [SDK Credit Accounts](https://docs.gearbox.finance/developers/credit-accounts) | | Pool deposit/withdraw | [Pool Operations](https://docs.gearbox.finance/developers/pool-operations) | ## Strategy Opportunities Source: https://docs.gearbox.finance/developers/gm-opps-strategy File: content/developers/gm-opps-strategy.mdx Strategy opportunities represent the borrower side of Gearbox — you borrow from a Pool, deploy capital into DeFi protocols via a Credit Account, and earn leveraged yield minus borrow costs. ## What They Represent When you enter a strategy opportunity, you open a Credit Account, deposit collateral, borrow pool liquidity, and deploy the combined capital through whitelisted DeFi adapters (Uniswap, Curve, Lido, Aave, etc.). The Credit Manager enforces solvency after every operation. ## Sub-Types | Sub-Type | Description | Status | | --- | --- | --- | | `strategy` | Leveraged position via Credit Account + adapters | Available | | `intent_strategy` | P2P leveraged position with custom borrow terms | Future | ## Discovering Strategy Opportunities Use either the opportunities namespace for unified search or the strategies namespace for direct queries: ```ts // Via unified search const strategyOpps = await sdk.opportunities.search({ type: "strategy" }); // Via strategies namespace directly const strategies = await sdk.strategies.list(); ``` ## Key Fields | Field | Description | | --- | --- | | `depositToken` | The collateral token you deposit (ETH, USDC, etc.) | | `targetToken` | The token the strategy targets for yield (stETH, yvUSDC, etc.) | | `headlineApy` | Net yield after borrow costs — what the borrower actually earns | | `leverageRange` | Min and max leverage available (e.g., 2x–10x) | | `adapters` | DeFi protocols available within this strategy | | `borrowRate` | Current cost of borrowing from the underlying Pool | | `capacity` | Remaining borrowable liquidity | ## Filtering You can filter strategy opportunities by asset class, chain, leverage, and minimum APY: ```ts // All ETH strategies with APY > 10% const ethStrats = await sdk.opportunities.search({ type: "strategy", depositToken: "ETH", minApy: 10, }); // High-leverage strategies on mainnet const leveraged = await sdk.opportunities.search({ type: "strategy", chainId: 1, minLeverage: 5, }); ``` ## Example: List High-Yield ETH Strategies ```ts import { GearboxSDK } from "@gearbox-protocol/sdk/official"; const sdk = new GearboxSDK(); await sdk.loadState({ mode: "lazy" }); const opps = await sdk.opportunities.search({ type: "strategy", depositToken: "ETH", minApy: 10, }); for (const opp of opps) { console.log( `${opp.id} | APY: ${opp.headlineApy.toFixed(2)}% | Leverage: ${opp.leverageRange.max}x` ); } ``` ## Next Steps - [Positions (Strategies)](https://docs.gearbox.finance/developers/gm-positions) — how to open, adjust, and close positions - [Multicall System](https://docs.gearbox.finance/developers/gm-accounts-multicalls) — composable operations within Credit Accounts - [Lender Opportunities](https://docs.gearbox.finance/developers/gm-opps-lender) — the supply side ## SDK Setup Source: https://docs.gearbox.finance/developers/sdk-setup File: content/developers/sdk-setup.mdx Install and initialize the Gearbox SDK for TypeScript development. > For Solidity contract discovery, see [Credit Accounts](https://docs.gearbox.finance/developers/credit-accounts). ## Installation ```typescript npm install @gearbox-protocol/sdk viem ``` ## SDK Initialization ```typescript import { GearboxSDK } from '@gearbox-protocol/sdk'; import { createPublicClient, http } from 'viem'; import { mainnet } from 'viem/chains'; const client = createPublicClient({ chain: mainnet, transport: http(), }); const sdk = await GearboxSDK.attach({ client, marketConfigurators: [], // Empty array = auto-discover all markets }); ``` **Parameters:** | Parameter | Type | Description | | --------------------- | -------------- | ------------------------------------------------- | | `client` | `PublicClient` | viem client instance | | `marketConfigurators` | `Address[]` | Filter to specific configurators, or `[]` for all | ## Accessing Markets The SDK exposes markets through `marketRegister`: ```typescript // All markets const markets = sdk.marketRegister.markets; // Find by pool address const market = sdk.marketRegister.findByPool(poolAddress); // Find by credit manager const market = sdk.marketRegister.findByCreditManager(cmAddress); // Market provides typed access const pool = market.pool; // Pool state const creditManagers = market.creditManagers; // Array of CMs const priceOracle = market.priceOracle; ``` ## Using Plugins Plugins extend SDK functionality for specific use cases: ```typescript import { AccountsPlugin, AdaptersPlugin } from '@gearbox-protocol/sdk'; // Attach plugins sdk.use(new AccountsPlugin()); sdk.use(new AdaptersPlugin()); // After loading, access plugin data const accounts = sdk.accounts.byCreditManager(cmAddress); const adapters = sdk.adapters.byProtocol('uniswap-v3'); ``` **Available Plugins:** | Plugin | Purpose | | ---------------- | --------------------------------------- | | `AccountsPlugin` | Credit account indexing and filtering | | `AdaptersPlugin` | Protocol adapter discovery and metadata | ## Address Provider via SDK The SDK wraps AddressProvider for contract discovery: ```typescript import { AP_MARKET_COMPRESSOR, VERSION_RANGE_310 } from '@gearbox-protocol/sdk'; // Get latest compressor address const [compressor] = sdk.addressProvider.mustGetLatest( AP_MARKET_COMPRESSOR, VERSION_RANGE_310 ); // List all registered contracts const contracts = sdk.addressProvider.list(); ``` ## Complete Example ```typescript import { GearboxSDK, createCreditAccountService } from '@gearbox-protocol/sdk'; import { createPublicClient, http } from 'viem'; import { mainnet } from 'viem/chains'; async function main() { const client = createPublicClient({ chain: mainnet, transport: http(), }); // Initialize SDK const sdk = await GearboxSDK.attach({ client, marketConfigurators: [], }); // Find USDC market const usdcMarket = sdk.marketRegister.markets.find( m => m.pool.underlying.symbol === 'USDC' ); if (!usdcMarket) throw new Error('USDC market not found'); // Get credit managers for this market const creditManagers = usdcMarket.creditManagers; console.log(`Found ${creditManagers.length} credit managers`); // Create service for account operations const service = createCreditAccountService(sdk, 310); // Query accounts const accounts = await service.getCreditAccounts( { creditManager: creditManagers[0].address }, sdk.currentBlock ); console.log(`Found ${accounts.length} credit accounts`); } main().catch(console.error); ``` ## Next Steps * [Reading Data](https://docs.gearbox.finance/developers/reading-data) - Query market state and pool data * [Credit Accounts](https://docs.gearbox.finance/developers/credit-accounts) - Account operations via services For architectural background, see [Credit Suite Architecture](https://docs.gearbox.finance/developers/credit-suite). ## Reading Data Source: https://docs.gearbox.finance/developers/reading-data File: content/developers/reading-data.mdx Query market state, pool data, and credit account information using the SDK. > For Solidity pool operations, see [Pool Operations](https://docs.gearbox.finance/developers/pool-operations). ## Market Data via marketRegister The `marketRegister` provides cached access to all Gearbox markets: ```typescript import { GearboxSDK } from '@gearbox-protocol/sdk'; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); // All markets const markets = sdk.marketRegister.markets; // Find specific market const market = sdk.marketRegister.findByPool(poolAddress); // or const market = sdk.marketRegister.findByCreditManager(cmAddress); // Access market components console.log(`Pool: ${market.pool.address}`); console.log(`Available liquidity: ${market.pool.availableLiquidity}`); console.log(`Diesel rate: ${market.pool.dieselRate}`); console.log(`Supply rate: ${market.pool.supplyRate}`); console.log(`Credit managers: ${market.creditManagers.length}`); ``` ## Pool State Access pool data through the market object: ```typescript const market = sdk.marketRegister.findByPool(poolAddress); const pool = market.pool; // Core metrics console.log(`Underlying: ${pool.underlying.symbol}`); console.log(`Total assets: ${pool.totalAssets}`); console.log(`Available liquidity: ${pool.availableLiquidity}`); // Interest rates (RAY = 27 decimals) const RAY = 10n ** 27n; const supplyAPY = Number(pool.supplyRate * 10000n / RAY) / 100; const borrowAPR = Number(pool.baseInterestRate * 10000n / RAY) / 100; console.log(`Supply APY: ${supplyAPY}%`); console.log(`Borrow APR: ${borrowAPR}%`); // Share price const dieselRate = pool.dieselRate; console.log(`Diesel rate: ${dieselRate}`); ``` ## Credit Manager Data Access credit manager configuration: ```typescript const market = sdk.marketRegister.findByCreditManager(cmAddress); for (const cm of market.creditManagers) { console.log(`Credit Manager: ${cm.address}`); console.log(`Credit Facade: ${cm.creditFacade}`); // Debt limits console.log(`Min debt: ${cm.minDebt}`); console.log(`Max debt: ${cm.maxDebt}`); // Allowed tokens for (const token of cm.collateralTokens) { console.log(` ${token.symbol}: LT ${token.liquidationThreshold}`); } } ``` ## Real-Time Data via Compressors The SDK caches data on initialization. For real-time data, use compressors directly: ```typescript import { GearboxSDK, marketCompressorAbi, AP_MARKET_COMPRESSOR, VERSION_RANGE_310, } from '@gearbox-protocol/sdk'; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); // Get compressor address const [compressor] = sdk.addressProvider.mustGetLatest( AP_MARKET_COMPRESSOR, VERSION_RANGE_310 ); // Fetch fresh market data const freshData = await client.readContract({ address: compressor, abi: marketCompressorAbi, functionName: 'getMarketData', args: [poolAddress], }); console.log(`Fresh available liquidity: ${freshData.pool.availableLiquidity}`); ``` ## Filtering Markets Query markets by criteria: ```typescript // All USDC markets const usdcMarkets = sdk.marketRegister.markets.filter( m => m.pool.underlying.symbol === 'USDC' ); // Markets with high liquidity const liquidMarkets = sdk.marketRegister.markets.filter( m => m.pool.availableLiquidity > 1_000_000n * 10n ** 6n // > 1M ); // Markets by configurator const curatedMarkets = sdk.marketRegister.markets.filter( m => m.configurator === curatorAddress ); ``` ## Price Oracle Data Access price information through the market: ```typescript const market = sdk.marketRegister.findByCreditManager(cmAddress); // Price oracle address const priceOracle = market.priceOracle; // Token prices are available through market data for (const token of market.tokens) { console.log(`${token.symbol}: ${token.price} USD`); } ``` ## Complete Example ```typescript import { GearboxSDK } from '@gearbox-protocol/sdk'; import { createPublicClient, http } from 'viem'; import { mainnet } from 'viem/chains'; async function getMarketOverview() { const client = createPublicClient({ chain: mainnet, transport: http(), }); const sdk = await GearboxSDK.attach({ client, marketConfigurators: [], }); const RAY = 10n ** 27n; for (const market of sdk.marketRegister.markets) { const pool = market.pool; console.log(`\n=== ${pool.underlying.symbol} Market ===`); console.log(`Pool: ${pool.address}`); console.log(`Total assets: ${pool.totalAssets}`); console.log(`Available: ${pool.availableLiquidity}`); const supplyAPY = Number(pool.supplyRate * 10000n / RAY) / 100; console.log(`Supply APY: ${supplyAPY.toFixed(2)}%`); console.log(`Credit Managers: ${market.creditManagers.length}`); } } getMarketOverview().catch(console.error); ``` ## Next Steps * [Credit Accounts](https://docs.gearbox.finance/developers/credit-accounts) - Query and manage credit accounts * [Multicalls](https://docs.gearbox.finance/developers/multicalls) - Build and execute multicalls For architectural background, see [Pool Architecture](https://docs.gearbox.finance/developers/pools). ## Credit Accounts Source: https://docs.gearbox.finance/developers/credit-accounts File: content/developers/credit-accounts.mdx Query and manage credit accounts using SDK services. > For Solidity credit operations, see [Credit Accounts](https://docs.gearbox.finance/developers/credit-accounts). ## Creating a Service Use `createCreditAccountService` for credit account operations: ```typescript import { GearboxSDK, createCreditAccountService } from '@gearbox-protocol/sdk'; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); // Create service (310 = V3.1) const service = createCreditAccountService(sdk, 310); ``` ## Querying Credit Accounts ### Get All Accounts for a Credit Manager ```typescript const accounts = await service.getCreditAccounts( { creditManager: cmAddress }, sdk.currentBlock ); for (const account of accounts) { console.log(`Account: ${account.addr}`); console.log(` Owner: ${account.owner}`); console.log(` Debt: ${account.debt}`); console.log(` Health Factor: ${account.healthFactor}`); } ``` ### Filter by Owner ```typescript const myAccounts = await service.getCreditAccounts( { creditManager: cmAddress, owner: myAddress, }, sdk.currentBlock ); ``` ### Account Data Structure Each credit account includes: | Field | Type | Description | | ---------------- | ------------- | --------------------------------- | | `addr` | `address` | Credit Account contract address | | `owner` | `address` | Account owner | | `creditManager` | `address` | Parent Credit Manager | | `debt` | `uint256` | Total debt (principal + interest) | | `healthFactor` | `uint256` | Current HF (10000 = 1.0) | | `tokens` | `TokenInfo[]` | Token balances and values | | `isLiquidatable` | `boolean` | Whether account can be liquidated | ## Reading Account State ### Health Factor ```typescript const account = accounts[0]; // Health factor is scaled by 10000 (10000 = 1.0) const hf = Number(account.healthFactor) / 10000; console.log(`Health Factor: ${hf.toFixed(4)}`); if (account.isLiquidatable) { console.log('Account is liquidatable!'); } ``` ### Token Balances ```typescript for (const token of account.tokens) { console.log(`${token.symbol}:`); console.log(` Balance: ${token.balance}`); console.log(` Value (underlying): ${token.balanceInUnderlying}`); console.log(` LT: ${token.lt / 100}%`); } ``` ### Debt Breakdown ```typescript console.log(`Total Debt: ${account.debt}`); console.log(`Principal: ${account.borrowedAmount}`); console.log(`Accrued Interest: ${account.cumulativeQuotaInterest}`); console.log(`Quota Fees: ${account.quotaFees}`); ``` ## Market Discovery Find the market for a credit manager: ```typescript const market = sdk.marketRegister.findByCreditManager(cmAddress); const creditFacade = market.creditFacade; console.log(`Credit Facade: ${creditFacade.address}`); console.log(`Pool: ${market.pool.address}`); ``` ## Opening a Credit Account ```typescript // Build multicall with SDK helpers const calls = [ service.prepareAddCollateral(usdcAddress, 10000n * 10n ** 6n), service.prepareIncreaseDebt(40000n * 10n ** 6n), ]; // Get credit facade const market = sdk.marketRegister.findByCreditManager(cmAddress); // Open account const hash = await market.creditFacade.write.openCreditAccount([ ownerAddress, calls, 0n, // referralCode ]); ``` ## Closing a Credit Account ```typescript // Build close multicall - typically repay and withdraw const closeCalls = [ service.prepareDecreaseDebt(account.debt), // Repay all debt // Withdraw remaining collateral handled automatically ]; const hash = await market.creditFacade.write.closeCreditAccount([ account.addr, closeCalls, ]); ``` ## Complete Example ```typescript import { GearboxSDK, createCreditAccountService } from '@gearbox-protocol/sdk'; import { createPublicClient, http } from 'viem'; import { mainnet } from 'viem/chains'; async function queryAccounts(cmAddress: `0x${string}`) { const client = createPublicClient({ chain: mainnet, transport: http(), }); const sdk = await GearboxSDK.attach({ client, marketConfigurators: [], }); const service = createCreditAccountService(sdk, 310); // Get all accounts const accounts = await service.getCreditAccounts( { creditManager: cmAddress }, sdk.currentBlock ); console.log(`Found ${accounts.length} credit accounts\n`); for (const account of accounts) { const hf = Number(account.healthFactor) / 10000; console.log(`Account: ${account.addr}`); console.log(` Owner: ${account.owner}`); console.log(` Debt: ${account.debt}`); console.log(` Health Factor: ${hf.toFixed(4)}`); console.log(` Liquidatable: ${account.isLiquidatable}`); // Token breakdown console.log(` Tokens:`); for (const token of account.tokens) { if (token.balance > 0n) { console.log(` ${token.symbol}: ${token.balance}`); } } console.log(''); } } queryAccounts('0x...').catch(console.error); ``` ## Next Steps * [Multicalls](https://docs.gearbox.finance/developers/multicalls) - Build complex operations For architectural background, see [Credit Suite Architecture](https://docs.gearbox.finance/developers/credit-suite). ## Lender (Pools) Source: https://docs.gearbox.finance/developers/gm-lender File: content/developers/gm-lender.mdx This section covers everything from the lender's perspective — how Gearbox pools work, how to deposit and withdraw, how interest rates are determined, and how the insurance mechanism protects depositors. ## Overview Lenders provide liquidity to ERC-4626 Pools and receive Diesel Tokens as yield-bearing receipts. Interest paid by borrowers flows back to the Pool, causing the Diesel Token exchange rate to appreciate over time. Lenders earn passive yield without managing positions or choosing strategies. ## What's in This Section | Page | Covers | | --- | --- | | [Markets Data](https://docs.gearbox.finance/developers/gm-markets-data) | Query pool state, TVL, utilization, and enriched metadata | | [Pool Operations](https://docs.gearbox.finance/developers/gm-markets-pools) | Deposit, withdraw, and preview pool transactions | | [Interest Rates & Quotas](https://docs.gearbox.finance/developers/gm-markets-rates) | How supply/borrow APY is calculated, quota rates, and the interest rate curve | | [History & Events](https://docs.gearbox.finance/developers/gm-markets-insurance) | Historical metrics, parameter changes, and governance event feeds | | [Insurance](https://docs.gearbox.finance/developers/gm-markets-insurance) | Automated insurance fund, bad-debt coverage, and loss distribution | ## SDK Entry Points The primary namespaces for lender operations: ```ts // Discover lender opportunities const pools = await sdk.pools.list(); const detail = await sdk.pools.getDetail(poolId); // Deposit into a pool const tx = await sdk.positions.prepareDeposit({ pool, amount }); const preview = await sdk.positions.previewDeposit(tx); await sdk.transactions.execute(tx); // Check pool status const status = await sdk.pools.getStatus(poolId); // Historical data const apyHistory = await sdk.history.getMetric({ pool: poolId, metric: "supplyApy" }); ``` ## Learn More - [Lender Opportunities](https://docs.gearbox.finance/developers/gm-opps-lender) — discover pools via the unified opportunity search - [Positions (Strategies)](https://docs.gearbox.finance/developers/gm-positions) — the borrower side of the protocol - [SDK Namespaces](https://docs.gearbox.finance/developers/gm-start-namespaces) — full namespace reference ## Markets Source: https://docs.gearbox.finance/developers/gm-markets File: content/developers/gm-markets.mdx A Gearbox market is the fundamental unit of the protocol: a lending pool paired with one or more credit managers, a quota system, and an insurance buffer. This section covers how to query and interact with markets using the TypeScript SDK. ## What is a Market? Each market revolves around a single underlying asset (e.g. USDC, WETH). It contains: | Component | Purpose | |---|---| | **Pool** | ERC-4626 vault that holds liquidity and issues diesel (share) tokens | | **Credit Managers** | Define borrowing parameters, allowed collateral, and adapters | | **Quota Keeper** | Tracks per-token borrowing limits and quota interest rates | | **Interest Rate Model** | Computes base borrow rates from pool utilization | | **Treasury Splitter** | Retains fee revenue as an insurance buffer before distributing surplus | ## Accessing Markets ```typescript import { GearboxSDK } from "@gearbox-protocol/sdk"; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); // Iterate all markets for (const market of sdk.marketRegister.markets) { console.log(`${market.pool.underlying.symbol} — ${market.creditManagers.length} CM(s)`); } ``` ## Section Overview | Page | Description | |---|---| | [Markets Data](https://docs.gearbox.finance/developers/gm-markets-data) | Query pools, credit managers, collateral tokens, and rates | | [Pool Operations](https://docs.gearbox.finance/developers/gm-markets-pools) | Deposit, withdraw, and manage LP positions via ERC-4626 | | [Interest Rates & Quotas](https://docs.gearbox.finance/developers/gm-markets-rates) | Interest rate model parameters, quota rates, and quota limits | | [Insurance Mechanism](https://docs.gearbox.finance/developers/gm-markets-insurance) | TreasurySplitter, revenue retention, and bad debt coverage | ## Next Steps Start with [Markets Data](https://docs.gearbox.finance/developers/gm-markets-data) to learn how to read pool state and credit manager configuration, or jump to [Pool Operations](https://docs.gearbox.finance/developers/gm-markets-pools) if you want to deposit liquidity right away. ## Opportunities Source: https://docs.gearbox.finance/developers/gm-markets-opportunities File: content/developers/gm-markets-opportunities.mdx Discover yield opportunities across Gearbox Markets using the SDK vNext. The unified opportunity surface lets you search pools, leveraged strategies, and markets from a single entry point, across all supported chains. ## Unified Discovery The `sdk.opportunities.search()` method returns a combined list of pools and strategies, ranked and filterable. This is the recommended starting point for any discovery flow. ```typescript import { GearboxSDK } from "@gearbox-protocol/sdk/official"; const sdk = await GearboxSDK.init({ chains: [1, 42161, 10], startFromCache: true, }); // Discover all opportunities across chains const opportunities = await sdk.opportunities.search(); for (const opp of opportunities) { console.log(`${opp.title} — ${opp.type} on chain ${opp.chainId}`); console.log(` APY: ${opp.headlineApy}% Capacity: ${opp.capacity}`); } ``` ## Opportunity Fields Every opportunity — whether pool, strategy, or market — shares a common shape: | Field | Type | Description | |---|---|---| | `id` | `string` | Unique identifier (address or composite key) | | `chainId` | `number` | Chain where the opportunity lives | | `type` | `"pool" \| "strategy" \| "market"` | Kind of opportunity | | `title` | `string` | Human-readable name (e.g. "dUSDC-V3-Tier1") | | `depositToken` | `TokenRef` | Token used to enter the position | | `headlineApy` | `number` | Composite APY (organic + incentives) | | `yieldType` | `string` | Yield source classification (e.g. "lending", "staking_spread") | | `capacity` | `string` | Remaining capacity in underlying token | | `access` | `"permissionless" \| "kyc"` | Whether entry requires KYC verification | | `risk` | `object` | Risk metadata (curator, oracle types, utilization) | | `points` | `object \| null` | Active points programs, if any | ## Pool Discovery Use `sdk.pools.list()` when you specifically want LP deposit opportunities: ```typescript const pools = await sdk.pools.list({ chainId: 1, asset: "STABLE", minApy: 5, minTvl: 1_000_000, }); for (const pool of pools) { console.log(`${pool.title} — APY ${pool.headlineApy}%`); console.log(` TVL: $${pool.tvlUsd} Utilization: ${pool.utilizationRate}%`); } ``` ## Strategy Discovery Use `sdk.strategies.list()` for leveraged strategy opportunities: ```typescript const strategies = await sdk.strategies.list({ chainId: 42161, asset: "ETH", minNetApy: 3, }); for (const s of strategies) { console.log(`${s.title} — Net APY ${s.headlineApy}%`); console.log(` Borrow: ${s.borrowableAmount} Leverage: up to ${s.maxLeverage}x`); } ``` ## Filtering All discovery methods accept a common filter object. Filters compose — pass multiple to narrow results. ### Filter by Chain ```typescript // Single chain const mainnetOpps = await sdk.opportunities.search({ chainId: 1 }); // Multiple chains const multiChain = await sdk.opportunities.search({ chainId: [1, 42161] }); ``` ### Filter by Asset Class The SDK classifies underlying tokens into asset classes for coarse filtering: | Asset Class | Constant | Tokens | |---|---|---| | Stablecoins | `Asset.STABLE` | USDC, USDT, DAI, GHO | | ETH-correlated | `Asset.ETH` | WETH, wstETH, rETH, cbETH | | BTC-correlated | `Asset.BTC` | WBTC, tBTC, sBTC | | Monad native | `Asset.MON` | MON, wMON | ```typescript import { Asset } from "@gearbox-protocol/sdk/official"; // Only stablecoin opportunities const stables = await sdk.opportunities.search({ asset: Asset.STABLE }); // ETH-correlated strategies on Arbitrum const ethStrategies = await sdk.strategies.list({ asset: Asset.ETH, chainId: 42161, }); ``` ### Filter by APY Floor ```typescript // Only opportunities with 5%+ headline APY const highYield = await sdk.opportunities.search({ minApy: 5 }); ``` ### Filter by TVL Minimum ```typescript // Only pools with at least $1M TVL const largePools = await sdk.pools.list({ minTvl: 1_000_000 }); ``` ### Filter by Access ```typescript // Only permissionless opportunities (no KYC) const open = await sdk.opportunities.search({ access: "permissionless" }); // Only KYC-gated opportunities const gated = await sdk.opportunities.search({ access: "kyc" }); ``` ### Combined Filters ```typescript const candidates = await sdk.opportunities.search({ chainId: [1, 42161], asset: Asset.STABLE, minApy: 4, minTvl: 500_000, access: "permissionless", }); ``` ## Multi-Chain Support Every entity in the SDK vNext includes a `chainId` field. The SDK can be initialized with multiple chains and will aggregate results across all of them: ```typescript const sdk = await GearboxSDK.init({ chains: [1, 42161, 10, 8453], startFromCache: true, }); // Results span all configured chains const allOpps = await sdk.opportunities.search(); // Group by chain const byChain = Object.groupBy(allOpps, opp => opp.chainId); ``` ## Freshness Metadata Discovery responses include metadata about data freshness and sources, so you can make trust decisions: ```typescript const result = await sdk.opportunities.search(); console.log(`Data as of: ${result.meta.asOf}`); console.log(`Sources: ${result.meta.sources.join(", ")}`); console.log(`Backend available: ${result.meta.backendAvailable}`); ``` | Meta Field | Type | Description | |---|---|---| | `asOf` | `string` | ISO timestamp of the data snapshot | | `sources` | `string[]` | Data sources used (e.g. `["backend", "onchain"]`) | | `backendAvailable` | `boolean` | Whether the backend enrichment service was reachable | When the backend is unavailable, the SDK falls back to on-chain data. APY enrichment and points data may be missing in this mode. ## Method Signatures | Method | Returns | Description | |---|---|---| | `sdk.opportunities.search(filters?)` | `Opportunity[]` | Unified discovery across pools, strategies, and markets | | `sdk.pools.list(filters?)` | `PoolOpportunity[]` | LP pool discovery | | `sdk.strategies.list(filters?)` | `StrategyOpportunity[]` | Leveraged strategy discovery | | `sdk.pools.getDetail(id)` | `PoolDetail` | Full pool due-diligence data | | `sdk.strategies.getDetail(id)` | `StrategyDetail` | Full strategy due-diligence data | ## Learn More - [Markets Data](https://docs.gearbox.finance/developers/gm-markets-data) — reading pool metrics and credit manager configuration - [History & Events](https://docs.gearbox.finance/developers/gm-markets-history) — historical APY, utilization, and governance changes - [Positions](https://docs.gearbox.finance/developers/gm-accounts-positions) — opening, adjusting, and closing positions - [Pool Operations](https://docs.gearbox.finance/developers/gm-markets-pools) — low-level ERC-4626 pool interactions ## Markets Data Source: https://docs.gearbox.finance/developers/gm-markets-data File: content/developers/gm-markets-data.mdx Read pool metrics, credit manager configuration, collateral tokens, and interest rates using the Gearbox SDK. All data is cached on SDK initialization and can be refreshed via compressors. ## Initialize the SDK ```typescript import { GearboxSDK } from "@gearbox-protocol/sdk"; import { createPublicClient, http } from "viem"; import { mainnet } from "viem/chains"; const client = createPublicClient({ chain: mainnet, transport: http(), }); const sdk = await GearboxSDK.attach({ client, marketConfigurators: [], }); ``` ## Finding Markets The `marketRegister` provides cached access to all Gearbox markets: ```typescript // All markets const markets = sdk.marketRegister.markets; // Find by pool address const market = sdk.marketRegister.findByPool(poolAddress); // Find by credit manager address const market = sdk.marketRegister.findByCreditManager(cmAddress); ``` ## Filtering Markets Query markets by underlying token, liquidity, or configurator: ```typescript // All USDC markets const usdcMarkets = sdk.marketRegister.markets.filter( m => m.pool.underlying.symbol === "USDC" ); // Markets with > 1M available liquidity const liquidMarkets = sdk.marketRegister.markets.filter( m => m.pool.availableLiquidity > 1_000_000n * 10n ** 6n ); // Markets by configurator const curatedMarkets = sdk.marketRegister.markets.filter( m => m.configurator === curatorAddress ); ``` ## Pool State Access core pool metrics through the market object: ```typescript const pool = market.pool; console.log(`Underlying: ${pool.underlying.symbol}`); console.log(`Total assets: ${pool.totalAssets}`); console.log(`Available liquidity: ${pool.availableLiquidity}`); console.log(`Diesel rate (share price): ${pool.dieselRate}`); ``` ### Interest Rates Rates are stored in RAY precision (27 decimals): ```typescript const RAY = 10n ** 27n; const supplyAPY = Number(pool.supplyRate * 10000n / RAY) / 100; const borrowAPR = Number(pool.baseInterestRate * 10000n / RAY) / 100; console.log(`Supply APY: ${supplyAPY.toFixed(2)}%`); console.log(`Borrow APR: ${borrowAPR.toFixed(2)}%`); ``` | Field | Type | Description | |---|---|---| | `supplyRate` | `bigint` | Annual supply rate for LPs (RAY) | | `baseInterestRate` | `bigint` | Annual base borrow rate (RAY) | | `dieselRate` | `bigint` | Current share price (RAY) | | `totalAssets` | `bigint` | Total underlying in pool | | `availableLiquidity` | `bigint` | Underlying available for borrowing | ## Credit Manager Data Each market can have multiple credit managers with different risk profiles: ```typescript for (const cm of market.creditManagers) { console.log(`Credit Manager: ${cm.address}`); console.log(`Credit Facade: ${cm.creditFacade}`); console.log(`Min debt: ${cm.minDebt}`); console.log(`Max debt: ${cm.maxDebt}`); // Allowed collateral tokens and their liquidation thresholds for (const token of cm.collateralTokens) { console.log(` ${token.symbol}: LT ${token.liquidationThreshold}`); } } ``` | Field | Type | Description | |---|---|---| | `minDebt` | `bigint` | Minimum borrowable amount | | `maxDebt` | `bigint` | Maximum borrowable amount | | `collateralTokens` | `array` | Allowed tokens with liquidation thresholds | | `creditFacade` | `Address` | Entry point for user interactions | ## Price Oracle Data Access token prices through the market: ```typescript const priceOracle = market.priceOracle; for (const token of market.tokens) { console.log(`${token.symbol}: ${token.price} USD`); } ``` ## Real-Time Data via Compressors The SDK caches data on initialization. For fresh on-chain data, query compressors directly: ```typescript import { GearboxSDK, marketCompressorAbi, AP_MARKET_COMPRESSOR, VERSION_RANGE_310, } from "@gearbox-protocol/sdk"; // Get compressor address const [compressor] = sdk.addressProvider.mustGetLatest( AP_MARKET_COMPRESSOR, VERSION_RANGE_310 ); // Fetch fresh market data const freshData = await client.readContract({ address: compressor, abi: marketCompressorAbi, functionName: "getMarketData", args: [poolAddress], }); console.log(`Fresh available liquidity: ${freshData.pool.availableLiquidity}`); ``` ## Complete Example ```typescript import { GearboxSDK } from "@gearbox-protocol/sdk"; import { createPublicClient, http } from "viem"; import { mainnet } from "viem/chains"; async function getMarketOverview() { const client = createPublicClient({ chain: mainnet, transport: http(), }); const sdk = await GearboxSDK.attach({ client, marketConfigurators: [], }); const RAY = 10n ** 27n; for (const market of sdk.marketRegister.markets) { const pool = market.pool; console.log(`\n=== ${pool.underlying.symbol} Market ===`); console.log(`Pool: ${pool.address}`); console.log(`Total assets: ${pool.totalAssets}`); console.log(`Available: ${pool.availableLiquidity}`); const supplyAPY = Number(pool.supplyRate * 10000n / RAY) / 100; console.log(`Supply APY: ${supplyAPY.toFixed(2)}%`); console.log(`Credit Managers: ${market.creditManagers.length}`); } } getMarketOverview().catch(console.error); ``` ## Next Steps - [Pool Operations](https://docs.gearbox.finance/developers/gm-markets-pools) -- Deposit and withdraw liquidity - [Interest Rates & Quotas](https://docs.gearbox.finance/developers/gm-markets-rates) -- Understand rate models and quota limits - [Insurance Mechanism](https://docs.gearbox.finance/developers/gm-markets-insurance) -- How protocol revenue protects lenders ## Multicalls Source: https://docs.gearbox.finance/developers/multicalls File: content/developers/multicalls.mdx Build and execute multicalls using SDK service helpers. > For Solidity multicall encoding, see [Multicalls](https://docs.gearbox.finance/developers/multicalls). ## Service Multicall Helpers The SDK provides structured multicall builders via `createCreditAccountService`: ```typescript import { GearboxSDK, createCreditAccountService } from '@gearbox-protocol/sdk'; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); const service = createCreditAccountService(sdk, 310); ``` ## Available Service Methods | Method | Operation | | ---------------------------------------------- | -------------------------- | | `prepareAddCollateral(token, amount)` | Add collateral from wallet | | `prepareIncreaseDebt(amount)` | Borrow from pool | | `prepareDecreaseDebt(amount)` | Repay debt | | `prepareUpdateQuota(token, change, minQuota)` | Adjust token quota | | `prepareWithdrawCollateral(token, amount, to)` | Remove collateral | ## Detailed Operation Guides For comprehensive documentation of each operation: **SDK Helper Operations:** * [Adding Collateral](https://docs.gearbox.finance/developers/adding-collateral) - Transfer tokens with approval patterns * [Debt Management](https://docs.gearbox.finance/developers/debt-management) - Borrowing, repayment, and constraints * [Updating Quotas](https://docs.gearbox.finance/developers/updating-quotas) - Quota mechanics and limits * [Withdrawing Collateral](https://docs.gearbox.finance/developers/withdrawing-collateral) - Safe pricing and health impact **Manual Encoding Operations:** * [Controlling Slippage](https://docs.gearbox.finance/developers/controlling-slippage) - Balance delta protection * [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls) - Adapter interaction patterns * [Enabling/Disabling Tokens](https://docs.gearbox.finance/developers/enabling-disabling-tokens) - Token mask management * [Updating Price Feeds](https://docs.gearbox.finance/developers/updating-price-feeds) - On-demand oracle data * [Collateral Check Params](https://docs.gearbox.finance/developers/collateral-check-params) - Health check optimization * [Revoke Allowances](https://docs.gearbox.finance/developers/revoke-allowances) - Security cleanup ## Building a Multicall ```typescript // Build multicall with SDK helpers const calls = [ // Add 10,000 USDC as collateral service.prepareAddCollateral(usdcAddress, 10_000n * 10n ** 6n), // Borrow 40,000 USDC (5x leverage) service.prepareIncreaseDebt(40_000n * 10n ** 6n), // Set quota for destination token service.prepareUpdateQuota(wethAddress, 50_000n * 10n ** 6n, 50_000n * 10n ** 6n), ]; ``` ## Executing Multicalls ### On Existing Account ```typescript const market = sdk.marketRegister.findByCreditManager(cmAddress); await market.creditFacade.write.multicall([ creditAccountAddress, calls, ]); ``` ### Opening with Multicall ```typescript const hash = await market.creditFacade.write.openCreditAccount([ ownerAddress, calls, 0n, // referralCode ]); ``` ## Combining SDK Helpers with Raw Encoding For adapter calls or custom operations, combine SDK helpers with manual encoding: ```typescript import { encodeFunctionData } from 'viem'; import { iCreditFacadeV300MulticallAbi } from '@gearbox-protocol/sdk'; const calls = [ // SDK helpers for standard operations service.prepareAddCollateral(usdcAddress, 10_000n * 10n ** 6n), service.prepareIncreaseDebt(40_000n * 10n ** 6n), // Manual encoding for adapter calls { target: uniswapV3Adapter, callData: encodeFunctionData({ abi: uniswapV3AdapterAbi, functionName: 'exactInputSingle', args: [{ tokenIn: usdcAddress, tokenOut: wethAddress, fee: 500, recipient: '0x0000000000000000000000000000000000000000', // Adapter overrides deadline: BigInt(Math.floor(Date.now() / 1000) + 3600), amountIn: 50_000n * 10n ** 6n, amountOutMinimum: 0n, sqrtPriceLimitX96: 0n, }], }), }, // SDK helper for quota service.prepareUpdateQuota(wethAddress, 50_000n * 10n ** 6n, 50_000n * 10n ** 6n), ]; ``` ## Slippage Protection Add slippage checks around external calls: ```typescript const calls = [ // Store expected balances before swap { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'storeExpectedBalances', args: [[{ token: wethAddress, amount: minExpectedWeth }]], }), }, // Swap operation { target: uniswapV3Adapter, callData: encodeFunctionData({ abi: uniswapV3AdapterAbi, functionName: 'exactInputSingle', args: [swapParams], }), }, // Compare balances after swap { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'compareBalances', args: [], }), }, ]; ``` ## On-Demand Price Updates If using pull-based oracles, add price updates first: ```typescript const calls = [ // Price updates must be first { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'onDemandPriceUpdates', args: [[{ token: wethAddress, reserve: false, data: priceData }]], }), }, // Then standard operations service.prepareAddCollateral(usdcAddress, amount), service.prepareIncreaseDebt(debtAmount), ]; ``` ## Getting Adapter Addresses Retrieve adapter addresses from the Credit Manager: ```typescript import { getContract } from 'viem'; import { creditManagerAbi } from '@gearbox-protocol/sdk'; const creditManager = getContract({ address: cmAddress, abi: creditManagerAbi, client: publicClient, }); // Get adapter for a protocol (e.g., Uniswap V3 Router) const uniswapV3Adapter = await creditManager.read.contractToAdapter([ UNISWAP_V3_ROUTER, ]); ``` ## Complete Example ```typescript import { GearboxSDK, createCreditAccountService, iCreditFacadeV300MulticallAbi, } from '@gearbox-protocol/sdk'; import { encodeFunctionData, createPublicClient, createWalletClient, http } from 'viem'; import { mainnet } from 'viem/chains'; async function leveragePosition() { const publicClient = createPublicClient({ chain: mainnet, transport: http(), }); const sdk = await GearboxSDK.attach({ client: publicClient, marketConfigurators: [], }); const service = createCreditAccountService(sdk, 310); // Find market const market = sdk.marketRegister.findByCreditManager(cmAddress); // Build multicall const calls = [ // Add collateral service.prepareAddCollateral(usdcAddress, 10_000n * 10n ** 6n), // Borrow service.prepareIncreaseDebt(40_000n * 10n ** 6n), // Set quota for final token service.prepareUpdateQuota(targetToken, 50_000n * 10n ** 6n, 50_000n * 10n ** 6n), ]; // Execute const walletClient = createWalletClient({ chain: mainnet, transport: http(), account: myAccount, }); const hash = await walletClient.writeContract({ address: market.creditFacade.address, abi: creditFacadeAbi, functionName: 'openCreditAccount', args: [myAccount.address, calls, 0n], }); console.log(`Transaction: ${hash}`); } ``` ## Best Practices 1. **Always use slippage protection** when performing swaps 2. **Price updates first** if using pull-based oracles 3. **Set quotas** for tokens you'll hold as collateral 4. **Approve collateral** to Credit Manager (not Facade) before adding For architectural background, see [Multicall System](https://docs.gearbox.finance/developers/multicall-system). ## Operations Reference Source: https://docs.gearbox.finance/developers/operations-reference File: content/developers/operations-reference.mdx Detailed guides for each multicall operation in TypeScript. > For Solidity multicall encoding, see [Multicalls](https://docs.gearbox.finance/developers/multicalls). ## Why This Section? The main [multicalls.md](https://docs.gearbox.finance/developers/multicalls) covers the basics: SDK service helpers, combining with raw encoding, and a complete example. This section goes deeper on each operation - when you need it, complete examples, and what can go wrong. ## Quick Reference | Operation | SDK Helper | When to Use | Guide | | -------------------- | ----------------------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | | Add Collateral | `prepareAddCollateral()` | Deposit tokens to increase health factor | [Adding Collateral](https://docs.gearbox.finance/developers/adding-collateral) | | Increase Debt | `prepareIncreaseDebt()` | Borrow from pool | [Debt Management](https://docs.gearbox.finance/developers/debt-management) | | Decrease Debt | `prepareDecreaseDebt()` | Repay borrowed funds | [Debt Management](https://docs.gearbox.finance/developers/debt-management) | | Update Quota | `prepareUpdateQuota()` | Enable/adjust quota token exposure | [Updating Quotas](https://docs.gearbox.finance/developers/updating-quotas) | | Withdraw Collateral | `prepareWithdrawCollateral()` | Remove tokens from account | [Withdrawing Collateral](https://docs.gearbox.finance/developers/withdrawing-collateral) | | Slippage Control | Manual encoding | Protect swaps from sandwich attacks | [Controlling Slippage](https://docs.gearbox.finance/developers/controlling-slippage) | | External Calls | Manual encoding | Interact with Uniswap, Curve, etc. | [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls) | | Enable/Disable Token | Manual encoding | Explicit collateral management | [Enabling/Disabling Tokens](https://docs.gearbox.finance/developers/enabling-disabling-tokens) | | Price Updates | Manual encoding | Update Pyth/Redstone feeds | [Updating Price Feeds](https://docs.gearbox.finance/developers/updating-price-feeds) | | Check Params | Manual encoding | Optimize gas, set min health factor | [Collateral Check Params](https://docs.gearbox.finance/developers/collateral-check-params) | | Revoke Allowances | Manual encoding | Security measure after suspicious activity | [Revoke Allowances](https://docs.gearbox.finance/developers/revoke-allowances) | ## Page Structure Each operation guide follows the same structure: 1. **Why** - When you need this operation 2. **What** - What it does and how it fits the system 3. **How** - Working TypeScript code 4. **Gotchas** - Common mistakes and edge cases 5. **See Also** - Related operations and Solidity reference ## SDK Helpers vs Manual Encoding **Five operations have SDK helpers** via `createCreditAccountService`: * `prepareAddCollateral(token, amount)` * `prepareIncreaseDebt(amount)` * `prepareDecreaseDebt(amount)` * `prepareUpdateQuota(token, change, minQuota)` * `prepareWithdrawCollateral(token, amount, to)` **Six operations require manual encoding** with viem's `encodeFunctionData`: * `storeExpectedBalances` / `compareBalances` * `enableToken` / `disableToken` * `onDemandPriceUpdate` * `setFullCheckParams` * `revokeAdapterAllowances` All manual encoding uses `iCreditFacadeV300MulticallAbi` from `@gearbox-protocol/sdk`. ## Related * [Multicalls Overview](https://docs.gearbox.finance/developers/multicalls) - Basic patterns and complete example * [Credit Accounts](https://docs.gearbox.finance/developers/credit-accounts) - Account data and services * [Solidity Multicalls](https://docs.gearbox.finance/developers/multicalls) - On-chain implementation details ## Pool Operations Source: https://docs.gearbox.finance/developers/gm-markets-pools File: content/developers/gm-markets-pools.mdx Gearbox pools are ERC-4626 compliant vaults. Liquidity providers deposit underlying assets and receive diesel tokens (shares) that appreciate as borrowers pay interest. This page covers how to interact with pools using the TypeScript SDK and viem. ## Pool Overview | Concept | Description | |---|---| | **Underlying** | The base asset (e.g. USDC, WETH) | | **Diesel token** | The pool's share token (e.g. dUSDC, dWETH) | | **Diesel rate** | Share price in RAY (27 decimals): 1 diesel = `dieselRate / 10^27` underlying | | **ERC-4626** | Standard vault interface for deposit, withdraw, mint, redeem | ## Reading Pool State ```typescript import { GearboxSDK } from "@gearbox-protocol/sdk"; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); const market = sdk.marketRegister.findByPool(poolAddress); const pool = market.pool; console.log(`Underlying: ${pool.underlying.symbol}`); console.log(`Total assets: ${pool.totalAssets}`); console.log(`Available liquidity: ${pool.availableLiquidity}`); console.log(`Diesel rate: ${pool.dieselRate}`); ``` ## Deposit Deposit underlying assets and receive diesel tokens: ```typescript import { erc20Abi } from "viem"; import { iPoolV3Abi } from "@gearbox-protocol/sdk"; // 1. Approve the pool to spend underlying const approveHash = await walletClient.writeContract({ address: underlyingAddress, abi: erc20Abi, functionName: "approve", args: [poolAddress, amount], }); await publicClient.waitForTransactionReceipt({ hash: approveHash }); // 2. Deposit and receive shares const depositHash = await walletClient.writeContract({ address: poolAddress, abi: iPoolV3Abi, functionName: "deposit", args: [amount, receiverAddress], }); const receipt = await publicClient.waitForTransactionReceipt({ hash: depositHash }); ``` ### Deposit with Referral Track referrals on-chain using the Gearbox-specific extension: ```typescript const hash = await walletClient.writeContract({ address: poolAddress, abi: iPoolV3Abi, functionName: "depositWithReferral", args: [amount, receiverAddress, 123n], // referralCode }); ``` ## Preview Operations Check expected shares or assets before executing: ```typescript // How many shares for a given deposit? const expectedShares = await publicClient.readContract({ address: poolAddress, abi: iPoolV3Abi, functionName: "previewDeposit", args: [amount], }); // How many assets needed to mint exact shares? const requiredAssets = await publicClient.readContract({ address: poolAddress, abi: iPoolV3Abi, functionName: "previewMint", args: [shares], }); // How many shares burned on withdraw? const sharesBurned = await publicClient.readContract({ address: poolAddress, abi: iPoolV3Abi, functionName: "previewWithdraw", args: [amount], }); // How many assets received on redeem? const assetsReceived = await publicClient.readContract({ address: poolAddress, abi: iPoolV3Abi, functionName: "previewRedeem", args: [shares], }); ``` ## Withdraw Withdraw exact underlying assets by burning the required shares: ```typescript const hash = await walletClient.writeContract({ address: poolAddress, abi: iPoolV3Abi, functionName: "withdraw", args: [amount, receiverAddress, ownerAddress], }); ``` ## Redeem Burn exact shares and receive underlying assets: ```typescript const hash = await walletClient.writeContract({ address: poolAddress, abi: iPoolV3Abi, functionName: "redeem", args: [shares, receiverAddress, ownerAddress], }); ``` ## Mint Mint exact shares by depositing the required underlying: ```typescript // Preview required assets first const requiredAssets = await publicClient.readContract({ address: poolAddress, abi: iPoolV3Abi, functionName: "previewMint", args: [shares], }); // Approve and mint await walletClient.writeContract({ address: underlyingAddress, abi: erc20Abi, functionName: "approve", args: [poolAddress, requiredAssets], }); await walletClient.writeContract({ address: poolAddress, abi: iPoolV3Abi, functionName: "mint", args: [shares, receiverAddress], }); ``` ## Maximum Operations Query the maximum deposit, withdraw, mint, or redeem for a given address: ```typescript const maxDeposit = await publicClient.readContract({ address: poolAddress, abi: iPoolV3Abi, functionName: "maxDeposit", args: [receiverAddress], }); const maxWithdraw = await publicClient.readContract({ address: poolAddress, abi: iPoolV3Abi, functionName: "maxWithdraw", args: [ownerAddress], }); const maxRedeem = await publicClient.readContract({ address: poolAddress, abi: iPoolV3Abi, functionName: "maxRedeem", args: [ownerAddress], }); const maxMint = await publicClient.readContract({ address: poolAddress, abi: iPoolV3Abi, functionName: "maxMint", args: [receiverAddress], }); ``` ## ERC-4626 Method Summary | Method | Input | Output | Description | |---|---|---|---| | `deposit(assets, receiver)` | Underlying amount | Shares minted | Deposit exact assets | | `mint(shares, receiver)` | Share amount | Assets deposited | Mint exact shares | | `withdraw(assets, receiver, owner)` | Underlying amount | Shares burned | Withdraw exact assets | | `redeem(shares, receiver, owner)` | Share amount | Assets received | Burn exact shares | | `previewDeposit(assets)` | Underlying amount | Expected shares | Preview deposit | | `previewMint(shares)` | Share amount | Required assets | Preview mint | | `previewWithdraw(assets)` | Underlying amount | Shares to burn | Preview withdraw | | `previewRedeem(shares)` | Share amount | Assets to receive | Preview redeem | ## Utilization Calculation Compute pool utilization from available data: ```typescript const market = sdk.marketRegister.findByPool(poolAddress); const pool = market.pool; const totalAssets = pool.totalAssets; const available = pool.availableLiquidity; const borrowed = totalAssets - available; // Utilization in basis points (0-10000) const utilizationBps = totalAssets > 0n ? Number(borrowed * 10000n / totalAssets) : 0; console.log(`Utilization: ${(utilizationBps / 100).toFixed(2)}%`); ``` ## Next Steps - [Interest Rates & Quotas](https://docs.gearbox.finance/developers/gm-markets-rates) -- How borrow rates and quota fees are determined - [Insurance Mechanism](https://docs.gearbox.finance/developers/gm-markets-insurance) -- How protocol revenue protects lenders - [Markets Data](https://docs.gearbox.finance/developers/gm-markets-data) -- Query market state and credit manager config ## Adding Collateral Source: https://docs.gearbox.finance/developers/adding-collateral File: content/developers/adding-collateral.mdx Deposit tokens from your wallet to a Credit Account. > For Solidity implementation, see [Adding Collateral](https://docs.gearbox.finance/developers/multicalls). ## Why You need to add collateral when: * **Opening an account** - Initial deposit to enable borrowing * **Improving health factor** - Account approaching liquidation threshold * **Enabling more borrowing** - Current collateral limits how much you can borrow Adding collateral increases your account's total weighted value (TWV), which improves the health factor and allows larger debt positions. ## What `addCollateral` transfers tokens from your wallet to the Credit Account. On execution: 1. The Credit Manager calls `transferFrom` to move tokens from caller to Credit Account 2. The token is enabled as collateral (if not already enabled) 3. Quoted tokens are NOT auto-enabled - you must set a quota separately **Important:** Approve tokens to the **Credit Manager**, not the Credit Facade. The Credit Manager is the contract that actually executes the transfer. ## How ```typescript import { GearboxSDK, createCreditAccountService } from '@gearbox-protocol/sdk'; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); const service = createCreditAccountService(sdk, 310); // Build the multicall const calls = [ service.prepareAddCollateral(usdcAddress, 10_000n * 10n ** 6n), ]; // First, approve to Credit Manager (not Facade!) const market = sdk.marketRegister.findByCreditManager(cmAddress); await usdcContract.write.approve([ market.creditManager.address, 10_000n * 10n ** 6n, ]); // Execute on existing account await market.creditFacade.write.multicall([creditAccountAddress, calls]); // Or open new account with collateral await market.creditFacade.write.openCreditAccount([ ownerAddress, calls, 0n, // referralCode ]); ``` ### Using Permit (No Separate Approval) For EIP-2612 compatible tokens, you can avoid the separate approval transaction: ```typescript import { encodeFunctionData } from 'viem'; import { iCreditFacadeV300MulticallAbi } from '@gearbox-protocol/sdk'; // Sign permit message (details depend on your wallet setup) const { v, r, s, deadline } = await signPermit(/* ... */); const calls = [ { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'addCollateralWithPermit', args: [tokenAddress, amount, deadline, v, r, s], }), }, ]; ``` ## Gotchas ### Approve to Credit Manager, Not Facade The most common mistake. The Credit Manager executes the `transferFrom`, so it needs the approval: ```typescript // CORRECT await token.write.approve([creditManager.address, amount]); // WRONG - will fail await token.write.approve([creditFacade.address, amount]); ``` ### Quoted Tokens Need Quota Adding a quoted token as collateral does NOT automatically enable it. You must also call `updateQuota`: ```typescript const calls = [ service.prepareAddCollateral(quotedTokenAddress, amount), service.prepareUpdateQuota(quotedTokenAddress, quotaAmount, minQuota), ]; ``` ### Direct Transfers Don't Enable Sending tokens directly to a Credit Account (via `transfer`) does NOT enable them as collateral. You still need a multicall with `enableToken` to count them in the health factor. ### Invalid Collateral Tokens Only tokens recognized by the Credit Manager can be used as collateral. Transferring unrecognized tokens to a Credit Account may result in them being stuck (only governance can recover). Check if a token is valid: ```typescript // This reverts if token is not valid collateral const mask = await creditManager.read.getTokenMaskOrRevert([tokenAddress]); ``` ## See Also * [Withdrawing Collateral](https://docs.gearbox.finance/developers/withdrawing-collateral) - The reverse operation * [Debt Management](https://docs.gearbox.finance/developers/debt-management) - Often combined with adding collateral * [Updating Quotas](https://docs.gearbox.finance/developers/updating-quotas) - Required for quoted tokens ## Interest Rates & Quotas Source: https://docs.gearbox.finance/developers/gm-markets-rates File: content/developers/gm-markets-rates.mdx Gearbox uses a two-part interest model: a **base interest rate** driven by pool utilization, and **quota rates** that add per-token fees for collateral exposure. Together they determine the total borrowing cost for credit accounts. ## Base Interest Rate Model The base rate follows a linear kinked model with three slopes, similar to Aave/Compound. Parameters are set per pool. | Parameter | Description | |---|---| | `U1` | First utilization kink (basis points) | | `U2` | Second utilization kink (basis points) | | `Rbase` | Base rate at 0% utilization | | `Rslope1` | Rate slope between 0 and U1 | | `Rslope2` | Rate slope between U1 and U2 | | `Rslope3` | Rate slope above U2 (steep penalty zone) | ### Reading Model Parameters ```typescript import { iLinearInterestRateModelV3Abi } from "@gearbox-protocol/sdk"; // Get the IRM address from the pool const irmAddress = await publicClient.readContract({ address: poolAddress, abi: iPoolV3Abi, functionName: "interestRateModel", }); // Query model parameters const params = await publicClient.readContract({ address: irmAddress, abi: iLinearInterestRateModelV3Abi, functionName: "getModelParameters", }); const [U1, U2, Rbase, Rslope1, Rslope2, Rslope3] = params; console.log(`Kink 1: ${U1} bps, Kink 2: ${U2} bps`); console.log(`Slopes: ${Rbase} / ${Rslope1} / ${Rslope2} / ${Rslope3}`); ``` ### Current Rates via SDK ```typescript const market = sdk.marketRegister.findByPool(poolAddress); const pool = market.pool; const RAY = 10n ** 27n; const supplyAPY = Number(pool.supplyRate * 10000n / RAY) / 100; const borrowAPR = Number(pool.baseInterestRate * 10000n / RAY) / 100; console.log(`Supply APY: ${supplyAPY.toFixed(2)}%`); console.log(`Base Borrow APR: ${borrowAPR.toFixed(2)}%`); ``` ## Quota System Quotas regulate how much pool capital can be exposed to specific collateral tokens. Each quoted token carries its own interest rate on top of the base borrow rate. ### How Quotas Work - A credit account's "quota" for a token is the amount of debt backed by that collateral. - Quota interest is **additive** (linear), not compounding. The PoolQuotaKeeper tracks a `cumulativeIndex` per token. - If `totalQuoted` reaches the `limit` for a token, any transaction that increases that quota reverts with `QuotaIsOutOfBoundsException`. ### Reading Quota Parameters ```typescript import { getContract } from "viem"; import { poolQuotaKeeperV3Abi } from "@gearbox-protocol/sdk"; // Get the QuotaKeeper address const quotaKeeperAddress = await publicClient.readContract({ address: poolAddress, abi: iPoolV3Abi, functionName: "poolQuotaKeeper", }); const quotaKeeper = getContract({ address: quotaKeeperAddress, abi: poolQuotaKeeperV3Abi, client: publicClient, }); // Get global quota parameters for a token const tokenParams = await quotaKeeper.read.getTokenQuotaParams([tokenAddress]); ``` The returned object contains: | Field | Type | Description | |---|---|---| | `rate` | `uint16` | Annual interest rate in basis points | | `cumulativeIndex` | `uint192` | Accumulated interest index | | `quotaIncreaseFee` | `uint16` | One-time fee on quota increases (basis points) | | `totalQuoted` | `uint96` | Total quota across all credit accounts | | `limit` | `uint96` | Maximum allowed `totalQuoted` | | `isActive` | `bool` | Whether the token is actively quoted | ### Checking Available Quota ```typescript const tokenParams = await quotaKeeper.read.getTokenQuotaParams([tokenAddress]); const availableQuota = tokenParams.limit - tokenParams.totalQuoted; console.log(`Total quoted: ${tokenParams.totalQuoted}`); console.log(`Limit: ${tokenParams.limit}`); console.log(`Available: ${availableQuota}`); console.log(`Rate: ${tokenParams.rate} bps`); ``` ### Per-Account Quota and Interest Query how much quota an individual credit account is consuming: ```typescript const [quoted, outstandingInterest] = await quotaKeeper.read.getQuotaAndOutstandingInterest([ creditAccountAddress, tokenAddress, ]); console.log(`Account quota: ${quoted}`); console.log(`Outstanding interest: ${outstandingInterest}`); ``` ## Rate Setting: Gauge vs. Tumbler Quota rates are set by an external contract implementing `IRateKeeper`. There are two models: ### GaugeV3 (Voting Model) Used in the core protocol. GEAR token stakers vote to move rates between a `minRate` and `maxRate` for each token. ### TumblerV3 (Curator Model) Used in the permissionless ecosystem. Curators set exact rates directly. | Function | Description | |---|---| | `setRate(address token, uint16 rate)` | Set rate in basis points | | `updateRates()` | Apply pending rate changes | | `epochLength` | Minimum time between rate updates | Rates set via Tumbler only take effect after `updateRates()` is called, and the Tumbler enforces an `epochLength` to prevent frequent manipulation. ## Total Borrowing Cost The total interest rate for a credit account is: ``` Total Rate = Base Borrow Rate + Sum(Quota Rate_i * Quota_i / Debt) ``` Where each quoted token contributes its quota rate proportional to the quota amount relative to total debt. ## Next Steps - [Insurance Mechanism](https://docs.gearbox.finance/developers/gm-markets-insurance) -- How fees fund the insurance buffer - [Pool Operations](https://docs.gearbox.finance/developers/gm-markets-pools) -- Deposit and withdraw liquidity - [Markets Data](https://docs.gearbox.finance/developers/gm-markets-data) -- Query pool and credit manager state ## Debt Management Source: https://docs.gearbox.finance/developers/debt-management File: content/developers/debt-management.mdx Borrow from or repay to the pool. > For Solidity implementation, see [Debt Management](https://docs.gearbox.finance/developers/multicalls). ## Why You manage debt when: * **Increasing leverage** - Borrow more to amplify exposure * **Taking profit** - Repay debt while keeping collateral positions * **Reducing risk** - Lower debt to improve health factor * **Closing account** - Repay all debt before withdrawal Debt operations affect your health factor: borrowing decreases it, repaying increases it. ## What ### Increase Debt `increaseDebt` borrows the underlying asset from the pool to your Credit Account: 1. Pool transfers underlying to Credit Account 2. Debt parameters (principal + interest) are recalculated 3. Health factor decreases ### Decrease Debt `decreaseDebt` repays debt from Credit Account's underlying balance: 1. Underlying is transferred from Credit Account to pool 2. Debt parameters are recalculated 3. Health factor increases **Repayment order** (when not paying full debt): 1. Quota-related fees (quota increase fees) 2. Accrued quota interest 3. Interest + interest fee (split pro-rata if partial) 4. Principal This means partial payments may not reduce your principal at all. ## How ### Borrow More ```typescript import { GearboxSDK, createCreditAccountService } from '@gearbox-protocol/sdk'; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); const service = createCreditAccountService(sdk, 310); const market = sdk.marketRegister.findByCreditManager(cmAddress); const calls = [ service.prepareIncreaseDebt(40_000n * 10n ** 6n), // Borrow 40,000 USDC ]; await market.creditFacade.write.multicall([creditAccountAddress, calls]); ``` ### Repay Debt ```typescript const calls = [ service.prepareDecreaseDebt(10_000n * 10n ** 6n), // Repay 10,000 USDC ]; await market.creditFacade.write.multicall([creditAccountAddress, calls]); ``` ### Repay All Debt Pass `type(uint256).max` equivalent to repay everything: ```typescript const MAX_UINT256 = 2n ** 256n - 1n; const calls = [ // Zero all quotas FIRST (required before full repayment) service.prepareUpdateQuota(quotedToken1, BigInt.asIntN(96, -1n * 2n ** 95n), 0n), service.prepareUpdateQuota(quotedToken2, BigInt.asIntN(96, -1n * 2n ** 95n), 0n), // Then repay all debt service.prepareDecreaseDebt(MAX_UINT256), ]; await market.creditFacade.write.multicall([creditAccountAddress, calls]); ``` ### Common Pattern: Add Collateral + Borrow ```typescript const calls = [ // First add collateral service.prepareAddCollateral(usdcAddress, 10_000n * 10n ** 6n), // Then borrow (5x leverage) service.prepareIncreaseDebt(40_000n * 10n ** 6n), // Set quota for destination token service.prepareUpdateQuota(wethAddress, 50_000n * 10n ** 6n, 50_000n * 10n ** 6n), ]; // Don't forget approval to Credit Manager! await usdcContract.write.approve([market.creditManager.address, 10_000n * 10n ** 6n]); await market.creditFacade.write.openCreditAccount([ownerAddress, calls, 0n]); ``` ## Gotchas ### One Debt Update Per Block You cannot increase AND decrease debt in the same block. This constraint prevents manipulation: ```typescript // WRONG - will revert on second operation const calls = [ service.prepareIncreaseDebt(amount1), service.prepareDecreaseDebt(amount2), // Reverts! ]; // CORRECT - one multicall, one debt operation const calls = [ service.prepareIncreaseDebt(netAmount), ]; ``` ### Zero All Quotas Before Full Repayment Non-zero quotas with zero debt is an invalid state. Zero your quotas BEFORE the final debt repayment: ```typescript const INT96_MIN = BigInt.asIntN(96, -1n * 2n ** 95n); const calls = [ // Zero quotas first service.prepareUpdateQuota(token1, INT96_MIN, 0n), service.prepareUpdateQuota(token2, INT96_MIN, 0n), // Then full repayment service.prepareDecreaseDebt(MAX_UINT256), ]; ``` ### Debt Must Stay in Range After any debt change, the principal must be either: * Zero (fully repaid), OR * Within `[minDebt, maxDebt]` range You cannot have debt between 0 and `minDebt`. ### Forbidden Tokens Block Borrowing If your account has forbidden tokens enabled as collateral, you cannot increase debt. Disable them first. ### Interest Accrues Continuously When repaying "the full amount", the debt may have grown since you read it. Add a buffer: ```typescript // Read current total debt const accountData = await service.getCreditAccountData(creditAccountAddress); const totalDebt = accountData.debt; // Add 0.1% buffer for interest accrual const repayAmount = totalDebt + (totalDebt / 1000n); // Or just use MAX_UINT256 to repay whatever the current amount is const calls = [service.prepareDecreaseDebt(MAX_UINT256)]; ``` ### Cannot Decrease on Open / Increase on Close * `decreaseDebt` is prohibited when opening an account * `increaseDebt` is prohibited when closing an account This prevents gaming the system by borrowing during liquidation or repaying during account creation. ## See Also * [Updating Quotas](https://docs.gearbox.finance/developers/updating-quotas) - Quota interest affects total debt * [Adding Collateral](https://docs.gearbox.finance/developers/adding-collateral) - Often combined with borrowing * [Withdrawing Collateral](https://docs.gearbox.finance/developers/withdrawing-collateral) - Often combined with repaying ## History & Events Source: https://docs.gearbox.finance/developers/gm-markets-history File: content/developers/gm-markets-history.mdx Query historical time-series data and track parameter changes across Gearbox Markets using the SDK vNext. History and event feeds require the backend enrichment service but degrade gracefully when it is unavailable. ## Historical Metrics Use `sdk.history.getMetric()` to retrieve time-series data for any pool or strategy metric. ```typescript import { GearboxSDK } from "@gearbox-protocol/sdk/official"; const sdk = await GearboxSDK.init({ chains: [1, 42161], startFromCache: true, }); // APY history for a pool over the last 90 days const apyHistory = await sdk.history.getMetric({ entity: poolAddress, chainId: 1, metric: "apy", period: "90d", }); for (const point of apyHistory.data) { console.log(`${point.date}: ${point.value}%`); } ``` ### Available Metrics | Metric | Entity Type | Description | |---|---|---| | `"apy"` | Pool | Composite supply APY (organic + incentives) | | `"utilization"` | Pool | Pool utilization rate (0-1) | | `"tvl"` | Pool | Total value locked in underlying token | | `"borrow_rate"` | Pool | Current borrow rate for the pool | | `"share_price"` | Pool | Diesel token price in underlying — drops indicate bad debt | | `"oracle_price"` | Token | Oracle price history for a collateral token | ### Parameters | Parameter | Type | Required | Description | |---|---|---|---| | `entity` | `string` | Yes | Pool address, strategy ID, or token address | | `chainId` | `number` | Yes | Chain ID for the entity | | `metric` | `string` | Yes | One of the metrics listed above | | `period` | `string` | No | Time window: `"7d"`, `"30d"`, `"90d"`, `"1y"`. Default `"90d"` | | `resolution` | `string` | No | Data point interval: `"1h"`, `"1d"`, `"1w"`. Default `"1d"` | ### Multi-Metric Query Fetch several metrics at once for a single entity: ```typescript const [apy, utilization, tvl] = await Promise.all([ sdk.history.getMetric({ entity: poolAddress, chainId: 1, metric: "apy", period: "90d" }), sdk.history.getMetric({ entity: poolAddress, chainId: 1, metric: "utilization", period: "90d" }), sdk.history.getMetric({ entity: poolAddress, chainId: 1, metric: "tvl", period: "90d" }), ]); ``` ### Share Price Monitoring Share price is the primary indicator for bad debt socialization. A drop in share price means losses were distributed to LPs: ```typescript const sharePrice = await sdk.history.getMetric({ entity: poolAddress, chainId: 1, metric: "share_price", period: "90d", resolution: "1d", }); // Detect any drops for (let i = 1; i < sharePrice.data.length; i++) { const prev = sharePrice.data[i - 1].value; const curr = sharePrice.data[i].value; if (curr < prev) { console.warn(`Share price dropped on ${sharePrice.data[i].date}: ${prev} → ${curr}`); } } ``` ## Event Feed Use `sdk.events.getFeed()` to retrieve a log of parameter changes — both past governance actions and pending scheduled changes. ```typescript const feed = await sdk.events.getFeed({ entity: poolAddress, chainId: 1, since: "2025-01-01T00:00:00Z", }); for (const event of feed.events) { console.log(`[${event.timestamp}] ${event.type}: ${event.description}`); } ``` ### Event Types | Event Type | Description | |---|---| | `"collateral_added"` | New collateral token added to a credit manager | | `"collateral_removed"` | Token forbidden or removed | | `"lt_changed"` | Liquidation threshold updated | | `"debt_limit_changed"` | Credit manager debt limit adjusted | | `"irm_updated"` | Interest rate model parameters changed | | `"cm_added"` | New credit manager connected to pool | | `"quota_rate_changed"` | Token quota rate adjusted | | `"curator_changed"` | Pool curator address updated | | `"oracle_changed"` | Oracle feed updated for a collateral token | ### Feed Parameters | Parameter | Type | Required | Description | |---|---|---|---| | `entity` | `string` | Yes | Pool address or credit manager address | | `chainId` | `number` | Yes | Chain ID | | `since` | `string` | No | ISO timestamp — only events after this time | | `includeProjected` | `boolean` | No | Include pending/scheduled changes. Default `true` | ## State Projections Instead of abstract event labels, the SDK provides concrete before/after snapshots through State Projections. This lets you see exactly how a pending governance change will affect parameters. ### PoolStateProjection ```typescript const projection = await sdk.events.getProjection({ entity: poolAddress, chainId: 1, }); // Current state console.log("Current parameters:", projection.current); // Projected state after pending changes if (projection.projected) { console.log("Projected parameters:", projection.projected); // See individual parameter diffs for (const diff of projection.changes) { console.log(`${diff.parameter}: ${diff.from} → ${diff.to} (ETA: ${diff.eta})`); } } ``` ### Projection Fields | Field | Type | Description | |---|---|---| | `current` | `ParameterSnapshot` | Current on-chain parameter values | | `projected` | `ParameterSnapshot \| null` | Parameters after all pending changes apply. `null` when backend unavailable | | `changes` | `ParameterDiff[]` | List of individual parameter diffs | ### ParameterDiff Each diff in `changes` is a concrete before/after comparison: | Field | Type | Description | |---|---|---| | `parameter` | `string` | Parameter name (e.g. `"quotaRate"`, `"debtLimit"`, `"liquidationThreshold"`) | | `token` | `string \| null` | Affected token address, if parameter is token-scoped | | `from` | `string \| number` | Current value | | `to` | `string \| number` | Value after change applies | | `eta` | `string` | ISO timestamp when the change takes effect | | `status` | `"pending" \| "queued" \| "executed"` | Current status of the change | ### Example: Quota Rate Change ```typescript const projection = await sdk.events.getProjection({ entity: poolAddress, chainId: 1, }); // Find quota rate changes const quotaChanges = projection.changes.filter(d => d.parameter === "quotaRate"); for (const change of quotaChanges) { console.log( `${change.token} quota rate: ${change.from}% → ${change.to}% (ETA: ${change.eta})` ); // Output: "USDC quota rate: 3% → 4% (ETA: 2025-04-20T12:00:00Z)" } ``` ## Graceful Degradation History and event data come from the Gearbox backend (`GET /v2/history/:metric`, `GET /v2/events`). When the backend is unavailable, the SDK degrades gracefully: | Feature | Backend Available | Backend Unavailable | |---|---|---| | `sdk.history.getMetric()` | Full time-series data | Throws or returns empty `data[]` | | `sdk.events.getFeed()` | Past + pending events | On-chain events only, no pending | | `projection.projected` | Concrete snapshot | `null` | | `projection.changes` | Full diff list | `[]` (empty array) | Check backend availability before relying on enriched data: ```typescript const result = await sdk.history.getMetric({ entity: poolAddress, chainId: 1, metric: "apy", }); if (!result.meta.backendAvailable) { console.warn("Backend unavailable — historical data may be incomplete"); } ``` ## Backend Endpoints The SDK vNext communicates with these backend endpoints for history and events: | Endpoint | SDK Method | Description | |---|---|---| | `GET /v2/history/:metric` | `sdk.history.getMetric()` | Time-series metric data | | `GET /v2/events` | `sdk.events.getFeed()` | Parameter change feed | ## Learn More - [Opportunities](https://docs.gearbox.finance/developers/gm-markets-opportunities) — discovering yield opportunities - [Markets Data](https://docs.gearbox.finance/developers/gm-markets-data) — reading current pool metrics and credit manager state - [Interest Rates](https://docs.gearbox.finance/developers/gm-markets-rates) — understanding the interest rate model - [Positions](https://docs.gearbox.finance/developers/gm-accounts-positions) — managing positions with prepare/preview/execute ## Insurance Mechanism Source: https://docs.gearbox.finance/developers/gm-markets-insurance File: content/developers/gm-markets-insurance.mdx The Gearbox insurance mechanism is a liquidity buffer held in the `TreasurySplitter` contract. It acts as first-loss protection for lenders by retaining protocol revenue before distributing surplus to curators and the DAO. ## How It Works The `TreasurySplitter` collects fees from interest payments and liquidations. Before any fees can be claimed, the contract checks whether its balance exceeds the configured `tokenInsuranceAmount`: - **Balance < Insurance Amount:** Distribution is blocked. All funds remain in the contract. - **Balance >= Insurance Amount:** Only the surplus (`balance - insuranceAmount`) is distributed. The insurance floor stays locked. This guarantees a pool of liquid assets is always available to cover unexpected losses. ## Fee Flow ``` Protocol Fees (interest + liquidations) | v TreasurySplitter | +--- Balance < Insurance Target? ---> Retain all (buffer building) | +--- Balance >= Insurance Target? ---> Distribute surplus to Curator / DAO ``` ## Covering Bad Debt When a liquidation results in bad debt (collateral value < debt), the protocol covers the shortfall: 1. A liquidator calls `liquidateCreditAccount`. Collateral proceeds are insufficient to repay the full debt. 2. The Credit Manager calls `pool.repayCreditAccount(...)` with the loss amount. 3. The Pool burns LP shares held by the Treasury address to cover the loss. 4. The TreasurySplitter's accumulated LP tokens serve as the recapitalization source. ## Reading Insurance State ### Check Insurance Target The minimum retained amount before any distribution occurs: ```typescript import { getContract } from "viem"; import { iTreasurySplitterAbi } from "@gearbox-protocol/sdk"; const treasurySplitter = getContract({ address: treasurySplitterAddress, abi: iTreasurySplitterAbi, client: publicClient, }); const insuranceTarget = await treasurySplitter.read.tokenInsuranceAmount([tokenAddress]); console.log(`Insurance target: ${insuranceTarget}`); ``` ### Check Current Buffer Status Compare the actual token balance to the target: ```typescript import { erc20Abi } from "viem"; const target = await treasurySplitter.read.tokenInsuranceAmount([tokenAddress]); const balance = await publicClient.readContract({ address: tokenAddress, abi: erc20Abi, functionName: "balanceOf", args: [treasurySplitterAddress], }); const fullyInsured = balance >= target; const surplus = balance > target ? balance - target : 0n; const deficit = balance < target ? target - balance : 0n; console.log(`Target: ${target}`); console.log(`Balance: ${balance}`); console.log(`Fully insured: ${fullyInsured}`); console.log(`Surplus: ${surplus}`); console.log(`Deficit: ${deficit}`); ``` ### Query Fee Distribution Config Understand how surplus fees are split between receivers: ```typescript // Default split configuration const defaultSplit = await treasurySplitter.read.defaultSplit(); // Token-specific split (overrides default if set) const tokenSplit = await treasurySplitter.read.tokenSplits([tokenAddress]); // Returns: { receivers: address[], proportions: uint256[] } ``` ### Monitor Governance Changes Insurance parameter changes require dual signatures (Curator + DAO): ```typescript const proposals = await treasurySplitter.read.activeProposals(); for (const proposal of proposals) { console.log("Pending proposal:", proposal); } ``` ## Insurance Health Summary Build a quick health check across all pools: ```typescript import { GearboxSDK } from "@gearbox-protocol/sdk"; import { erc20Abi, getContract } from "viem"; async function checkInsuranceHealth(sdk: GearboxSDK) { const splitter = getContract({ address: treasurySplitterAddress, abi: iTreasurySplitterAbi, client: publicClient, }); for (const market of sdk.marketRegister.markets) { const token = market.pool.underlying; const target = await splitter.read.tokenInsuranceAmount([token.address]); const balance = await publicClient.readContract({ address: token.address, abi: erc20Abi, functionName: "balanceOf", args: [treasurySplitterAddress], }); const ratio = target > 0n ? Number(balance * 10000n / target) / 100 : 0; console.log(`${token.symbol}: ${ratio.toFixed(1)}% funded (${balance} / ${target})`); } } ``` ## Key Points | Aspect | Detail | |---|---| | **Buffer type** | Liquid underlying tokens held in TreasurySplitter | | **Distribution rule** | Surplus above insurance target is distributable | | **Bad debt coverage** | Pool burns Treasury LP shares to absorb losses | | **Governance** | Insurance amount changes require dual Curator + DAO approval | ## Next Steps - [Markets Data](https://docs.gearbox.finance/developers/gm-markets-data) -- Query pool and credit manager state - [Pool Operations](https://docs.gearbox.finance/developers/gm-markets-pools) -- Deposit and withdraw liquidity - [Interest Rates & Quotas](https://docs.gearbox.finance/developers/gm-markets-rates) -- Rate models and quota limits ## Updating Quotas Source: https://docs.gearbox.finance/developers/updating-quotas File: content/developers/updating-quotas.mdx Enable or adjust exposure to quota-based collateral tokens. > For Solidity implementation, see [Updating Quotas](https://docs.gearbox.finance/developers/multicalls). ## Why You update quotas when: * **Enabling a quota token** - Required before that token counts as collateral * **Increasing exposure** - Need more of a token to count toward health factor * **Reducing exposure** - Lower quota to reduce quota interest costs * **Closing positions** - Zero quotas before full debt repayment Quotas control how much of a token's value counts as collateral. Without a quota, even holding a quota token contributes zero to your health factor. ## What `updateQuota` changes your quota for a specific token: 1. If increasing from zero, the token is enabled as collateral 2. If decreasing to zero, the token is disabled as collateral 3. Quota increase may be limited by global capacity (per-pool limits) 4. Quota interest accrues based on your quota amount **Key parameters:** * `token` - The quota token address * `quotaChange` - Delta to apply (positive = increase, negative = decrease) * `minQuota` - Minimum acceptable resulting quota (prevents partial fills) The `minQuota` parameter protects you: if the pool can only give you 80% of your requested quota, and you set `minQuota` to 100% of your request, the transaction reverts instead of accepting partial quota. ## How ```typescript import { GearboxSDK, createCreditAccountService } from '@gearbox-protocol/sdk'; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); const service = createCreditAccountService(sdk, 310); const market = sdk.marketRegister.findByCreditManager(cmAddress); // Request 50,000 USDC worth of quota const quotaAmount = 50_000n * 10n ** 6n; const calls = [ service.prepareUpdateQuota(wethAddress, quotaAmount, quotaAmount), ]; await market.creditFacade.write.multicall([creditAccountAddress, calls]); ``` ### Decrease Quota ```typescript // Decrease quota by 20,000 (negative change) const decrease = -20_000n * 10n ** 6n; const calls = [ service.prepareUpdateQuota(wethAddress, decrease, 0n), ]; ``` ### Zero Quota Entirely Pass `type(int96).min` to disable quota completely: ```typescript // int96 minimum value const INT96_MIN = BigInt.asIntN(96, -1n * 2n ** 95n); const calls = [ service.prepareUpdateQuota(wethAddress, INT96_MIN, 0n), ]; ``` ### Common Pattern: Enable Quota After Swap After swapping into a quota token, you need to enable quota for it to count: ```typescript const calls = [ // Swap USDC to WETH via adapter { target: uniswapV3Adapter, callData: encodeFunctionData({ abi: uniswapV3AdapterAbi, functionName: 'exactInputSingle', args: [swapParams], }), }, // Enable quota for the received WETH service.prepareUpdateQuota(wethAddress, quotaAmount, quotaAmount), ]; ``` ## Gotchas ### Check Quota Limits Before Requesting Each quota token has a pool-wide limit. If the limit is reached, your request fails (or gets partial fill): ```typescript // Check available quota capacity const quotaKeeper = market.quotaKeeper; const quotaInfo = await quotaKeeper.read.getQuotaInfo([wethAddress]); const available = quotaInfo.limit - quotaInfo.totalQuoted; if (requested > available) { console.log(`Only ${available} quota available, requested ${requested}`); } ``` ### minQuota Prevents Partial Fills If you need exactly 100 units of quota: ```typescript // SAFE - reverts if less than 100 available service.prepareUpdateQuota(token, 100n, 100n); // RISKY - accepts partial fill service.prepareUpdateQuota(token, 100n, 0n); ``` ### Per-Account Quota Maximum Each account has an implicit max quota of `8 * maxDebt` per asset. You cannot exceed this even if pool capacity exists. ### Zero Quotas Before Zero Debt You cannot have active quotas with zero debt. When closing an account: ```typescript const INT96_MIN = BigInt.asIntN(96, -1n * 2n ** 95n); const MAX_UINT256 = 2n ** 256n - 1n; const calls = [ // Zero ALL quotas first service.prepareUpdateQuota(token1, INT96_MIN, 0n), service.prepareUpdateQuota(token2, INT96_MIN, 0n), // Then repay debt service.prepareDecreaseDebt(MAX_UINT256), ]; ``` ### Cannot Update Quotas on Zero-Debt Account If your account has zero debt, quota updates fail. You must have active debt to hold quotas. ### Quota Tokens vs Non-Quota Tokens Not all tokens are quota tokens. Non-quota tokens: * Are enabled/disabled via `enableToken`/`disableToken` * Don't require quota to count as collateral * Have different risk parameters Check if a token is quota-based by examining the Credit Manager configuration. ### Forbidden Tokens Block Quota Increases If your account has forbidden tokens enabled, you cannot increase any quotas. Disable forbidden tokens first. ## See Also * [Debt Management](https://docs.gearbox.finance/developers/debt-management) - Quotas require active debt * [Adding Collateral](https://docs.gearbox.finance/developers/adding-collateral) - Often combined with quota updates * [Enabling/Disabling Tokens](https://docs.gearbox.finance/developers/enabling-disabling-tokens) - For non-quota tokens ## Withdrawing Collateral Source: https://docs.gearbox.finance/developers/withdrawing-collateral File: content/developers/withdrawing-collateral.mdx Remove tokens from your Credit Account. > For Solidity implementation, see [Withdrawing Collateral](https://docs.gearbox.finance/developers/multicalls). ## Why You withdraw collateral when: * **Taking profit** - Extract gains while keeping the position open * **Rebalancing** - Move assets between Credit Account and wallet * **Closing positions** - Extract remaining value after repaying debt * **Emergency exit** - Quickly reduce exposure Withdrawals decrease your health factor since you're removing value from the account. ## What `withdrawCollateral` transfers tokens from Credit Account to a specified address: 1. Token is transferred from Credit Account to `to` address 2. If balance goes to zero, token is auto-disabled 3. **Safe pricing** is triggered for the final collateral check **Safe pricing** is critical to understand: when any withdrawal occurs in a multicall, the final health check uses `min(mainPrice, reservePrice)` for ALL collateral. This can cause withdrawals to fail even when the account looks healthy based on main prices alone. ## How ```typescript import { GearboxSDK, createCreditAccountService } from '@gearbox-protocol/sdk'; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); const service = createCreditAccountService(sdk, 310); const market = sdk.marketRegister.findByCreditManager(cmAddress); // Withdraw 5,000 USDC to your wallet const calls = [ service.prepareWithdrawCollateral( usdcAddress, 5_000n * 10n ** 6n, myWalletAddress, ), ]; await market.creditFacade.write.multicall([creditAccountAddress, calls]); ``` ### Withdraw Entire Balance Pass max uint256 to withdraw all of a token: ```typescript const MAX_UINT256 = 2n ** 256n - 1n; const calls = [ service.prepareWithdrawCollateral(usdcAddress, MAX_UINT256, myWalletAddress), ]; ``` ### Withdraw to Different Address The `to` parameter can be any address: ```typescript const calls = [ service.prepareWithdrawCollateral( usdcAddress, amount, recipientAddress, // Can be different from caller ), ]; ``` ### Common Pattern: Repay + Withdraw After repaying debt, withdraw remaining funds: ```typescript const MAX_UINT256 = 2n ** 256n - 1n; const INT96_MIN = BigInt.asIntN(96, -1n * 2n ** 95n); const calls = [ // Zero quotas service.prepareUpdateQuota(wethAddress, INT96_MIN, 0n), // Repay all debt service.prepareDecreaseDebt(MAX_UINT256), // Withdraw remaining collateral service.prepareWithdrawCollateral(usdcAddress, MAX_UINT256, myWalletAddress), service.prepareWithdrawCollateral(wethAddress, MAX_UINT256, myWalletAddress), ]; ``` ## Gotchas ### Safe Pricing Can Block Withdrawals This is the biggest surprise for developers. When you withdraw, ALL collateral is valued at `min(mainPrice, reservePrice)`: ``` Regular check: collateral valued at main price Withdrawal: collateral valued at min(main, reserve) ``` An account that looks healthy at main prices may fail the withdrawal check at safe prices. **Example:** * Main price: $100 * Reserve price: $80 * Regular health check uses $100 * Withdrawal health check uses $80 Your account might have HF 1.2 normally but only HF 0.96 under safe pricing. **Workaround:** Add extra collateral buffer or reduce debt before withdrawing if you're close to the threshold. ### Forbidden Tokens Block Withdrawals If your account has forbidden tokens enabled, withdrawals are prohibited. You must disable forbidden tokens first (usually by swapping them away). ### Token Auto-Disables at Zero Balance When you withdraw the entire balance of a token: * Non-quota tokens are auto-disabled * Quota tokens remain enabled until quota is zeroed This is usually what you want, but be aware if you're tracking enabled tokens. ### Reserve Price May Be Zero Some tokens have a reserve price of zero (untrusted tokens). Any withdrawal will fail if such tokens are enabled, because their value becomes zero under safe pricing. Check the price feed configuration before withdrawing: ```typescript // If reserve price is 0, safe pricing makes this collateral worthless const priceFeed = await priceOracle.read.priceFeedsRaw([tokenAddress, true]); ``` ### Withdrawal Doesn't Auto-Disable Quota Tokens Unlike non-quota tokens, quota tokens remain enabled even at zero balance. You must explicitly zero the quota: ```typescript const MAX_UINT256 = 2n ** 256n - 1n; const INT96_MIN = BigInt.asIntN(96, -1n * 2n ** 95n); const calls = [ // Zero quota first service.prepareUpdateQuota(wethAddress, INT96_MIN, 0n), // Then withdraw service.prepareWithdrawCollateral(wethAddress, MAX_UINT256, myWalletAddress), ]; ``` ### Can't Withdraw Below Minimum Debt After withdrawal, your account must still satisfy debt constraints. If withdrawal would leave you with debt between 0 and `minDebt`, it fails. ## See Also * [Adding Collateral](https://docs.gearbox.finance/developers/adding-collateral) - The reverse operation * [Debt Management](https://docs.gearbox.finance/developers/debt-management) - Often combined with withdrawals * [Updating Quotas](https://docs.gearbox.finance/developers/updating-quotas) - Zero quotas before withdrawing quota tokens ## Controlling Slippage Source: https://docs.gearbox.finance/developers/controlling-slippage File: content/developers/controlling-slippage.mdx Protect swaps from sandwich attacks and price movement. > For Solidity implementation, see [Controlling Slippage](https://docs.gearbox.finance/developers/multicalls). ## Why You need slippage protection when: * **Swapping tokens** - DEX prices can move between quote and execution * **Multi-step operations** - Swap + deposit combos need end-to-end protection * **Large trades** - Bigger trades have higher slippage impact * **Protecting against MEV** - Sandwich bots exploit unprotected swaps Without slippage protection, you might receive significantly fewer tokens than expected. Gearbox provides native slippage controls that work across any sequence of operations. ## What Gearbox uses a two-step pattern: 1. **`storeExpectedBalances`** - Record expected minimum balances BEFORE operations 2. **`compareBalances`** - Verify actual balances meet expectations AFTER operations If the final balance is less than expected, the entire multicall reverts. **Why not use DEX slippage parameters?** * Multi-step operations (swap → deposit) can't use single slippage value * Some protocols (ERC4626 vaults) have no built-in slippage protection * Gearbox slippage works at the account level, across any operation sequence ## How ```typescript import { encodeFunctionData } from 'viem'; import { iCreditFacadeV300MulticallAbi } from '@gearbox-protocol/sdk'; // Calculate minimum expected output with 0.5% slippage tolerance const expectedOutput = 25n * 10n ** 18n; // 25 WETH const slippageBps = 50n; // 0.5% const minExpected = expectedOutput - (expectedOutput * slippageBps / 10000n); const calls = [ // 1. Store expected balance BEFORE swap { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'storeExpectedBalances', args: [[{ token: wethAddress, amount: minExpected }]], }), }, // 2. Perform the swap { target: uniswapV3Adapter, callData: encodeFunctionData({ abi: uniswapV3AdapterAbi, functionName: 'exactInputSingle', args: [swapParams], }), }, // 3. Verify slippage AFTER swap { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'compareBalances', args: [], }), }, ]; ``` ### Multiple Tokens Check slippage on multiple output tokens: ```typescript const calls = [ // Store expectations for both tokens { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'storeExpectedBalances', args: [[ { token: wethAddress, amount: minWethExpected }, { token: usdcAddress, amount: minUsdcExpected }, ]], }), }, // Multiple swaps... { /* swap 1 */ }, { /* swap 2 */ }, // Single compare covers all stored expectations { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'compareBalances', args: [], }), }, ]; ``` ### Negative Deltas (Expected to Spend) You can also specify tokens you expect to decrease: ```typescript // Expect to spend at most 50,000 USDC const maxSpend = 50_000n * 10n ** 6n; const calls = [ { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'storeExpectedBalances', args: [[ { token: usdcAddress, amount: -maxSpend }, // Negative = expect decrease { token: wethAddress, amount: minWethExpected }, ]], }), }, // ... ]; ``` ## Gotchas ### Keep Slippage Checks Close to Operations Place `storeExpectedBalances` immediately before the first external call, and `compareBalances` immediately after the last: ```typescript // CORRECT - slippage checks wrap the swap tightly const calls = [ service.prepareAddCollateral(usdcAddress, amount), // Internal op storeExpectedBalances, // Right before swap swap, // External call compareBalances, // Right after swap service.prepareUpdateQuota(wethAddress, quota, quota), // Internal op ]; // WRONG - addCollateral between store and compare affects balances const calls = [ storeExpectedBalances, swap, service.prepareAddCollateral(usdcAddress, amount), // Changes balances! compareBalances, // May fail incorrectly ]; ``` ### compareBalances Fails Without storeExpectedBalances Calling `compareBalances` without a prior `storeExpectedBalances` in the same multicall reverts. ### Auto-Compare at Multicall End If you call `storeExpectedBalances` but forget `compareBalances`, the check happens automatically at the end of the multicall. However, it's better to be explicit. ### BalanceDelta Type The `amount` in `BalanceDelta` is the **change** you expect, not the final balance: ```typescript // Current WETH balance: 10 // Swap adds 25 WETH // Final balance: 35 // CORRECT - amount is the delta (change) { token: wethAddress, amount: 25n * 10n ** 18n } // WRONG - this would require 35 WETH increase { token: wethAddress, amount: 35n * 10n ** 18n } ``` ### Slippage Check Works on balanceOf The check reads actual token balances via `balanceOf`. This means: * Internal transfers (like `addCollateral`) affect the balance * Token rebases affect the balance * Any balance change, regardless of source, is included ### Cannot Reuse Stored Balances After `compareBalances` runs, the stored expectations are cleared. For multiple swap sequences, call `storeExpectedBalances` again: ```typescript const calls = [ // First swap storeExpectedBalances1, swap1, compareBalances, // Clears stored values // Second swap needs new store storeExpectedBalances2, // Must call again swap2, compareBalances, ]; ``` ## See Also * [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls) - Adapter calls that need slippage protection * [Multicalls Overview](https://docs.gearbox.finance/developers/multicalls) - Basic slippage example * [Price Updates](https://docs.gearbox.finance/developers/updating-price-feeds) - Stale prices can cause unexpected slippage ## Making External Calls Source: https://docs.gearbox.finance/developers/making-external-calls File: content/developers/making-external-calls.mdx Interact with external protocols (Uniswap, Curve, Yearn, etc.) from your Credit Account. > For Solidity implementation, see [Making External Calls](https://docs.gearbox.finance/developers/multicalls). ## Why You make external calls when: * **Swapping tokens** - Trade via Uniswap, Curve, or other DEXs * **Depositing to vaults** - Stake in Yearn, Lido, or yield strategies * **Managing LP positions** - Add/remove liquidity on various protocols * **Executing complex strategies** - Chain multiple protocol interactions Credit Accounts interact with external protocols through **adapters** - whitelisted contracts that translate your calls into safe operations. ## What External calls flow through adapters: 1. You encode a call targeting an adapter address 2. Credit Facade routes the call to the adapter 3. Adapter builds the actual calldata for the external protocol 4. Adapter requests token approvals if needed 5. Credit Manager executes the call from the Credit Account 6. Credit Account acts as the "user" from the external protocol's perspective 7. Adapter returns which tokens to enable/disable based on the operation **Key insight:** The Credit Account makes the actual call, so it receives the output tokens directly. You never touch the funds - they stay in the Credit Account. ## How ### Step 1: Get Adapter Address ```typescript import { getContract } from 'viem'; import { creditManagerAbi } from '@gearbox-protocol/sdk'; const creditManager = getContract({ address: cmAddress, abi: creditManagerAbi, client: publicClient, }); // Get adapter for a protocol (e.g., Uniswap V3 Router) const uniswapV3Adapter = await creditManager.read.contractToAdapter([ UNISWAP_V3_ROUTER, ]); // Returns 0x0 if no adapter exists for this protocol if (uniswapV3Adapter === '0x0000000000000000000000000000000000000000') { throw new Error('No adapter for this protocol'); } ``` ### Step 2: Encode the Adapter Call ```typescript import { encodeFunctionData } from 'viem'; import { uniswapV3AdapterAbi } from '@gearbox-protocol/integrations-v3'; const swapParams = { tokenIn: usdcAddress, tokenOut: wethAddress, fee: 500, recipient: '0x0000000000000000000000000000000000000000', // Adapter overrides this deadline: BigInt(Math.floor(Date.now() / 1000) + 3600), amountIn: 50_000n * 10n ** 6n, amountOutMinimum: 24n * 10n ** 18n, // Slippage protection sqrtPriceLimitX96: 0n, }; const calls = [ { target: uniswapV3Adapter, callData: encodeFunctionData({ abi: uniswapV3AdapterAbi, functionName: 'exactInputSingle', args: [swapParams], }), }, ]; ``` ### Complete Example: Swap with Slippage Protection ```typescript import { encodeFunctionData } from 'viem'; import { GearboxSDK, createCreditAccountService, iCreditFacadeV300MulticallAbi, } from '@gearbox-protocol/sdk'; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); const service = createCreditAccountService(sdk, 310); const market = sdk.marketRegister.findByCreditManager(cmAddress); // Get adapter const uniswapV3Adapter = await market.creditManager.read.contractToAdapter([ UNISWAP_V3_ROUTER, ]); const calls = [ // Add collateral (SDK helper) service.prepareAddCollateral(usdcAddress, 50_000n * 10n ** 6n), // Borrow (SDK helper) service.prepareIncreaseDebt(200_000n * 10n ** 6n), // Slippage protection start { target: market.creditFacade.address, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'storeExpectedBalances', args: [[{ token: wethAddress, amount: 99n * 10n ** 18n }]], // Expect ~100 WETH }), }, // Swap via adapter (manual encoding) { target: uniswapV3Adapter, callData: encodeFunctionData({ abi: uniswapV3AdapterAbi, functionName: 'exactInputSingle', args: [swapParams], }), }, // Slippage protection end { target: market.creditFacade.address, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'compareBalances', args: [], }), }, // Set quota for received token (SDK helper) service.prepareUpdateQuota(wethAddress, 250_000n * 10n ** 6n, 250_000n * 10n ** 6n), ]; // Approve collateral to Credit Manager await usdcContract.write.approve([market.creditManager.address, 50_000n * 10n ** 6n]); // Execute await market.creditFacade.write.openCreditAccount([ownerAddress, calls, 0n]); ``` ### Diff Functions Many adapters have `_diff` variants that operate on "entire balance minus 1": ```typescript // Instead of specifying exact amount... { functionName: 'deposit', args: [exactAmount] } // Use diff to deposit all USDC (minus 1 wei) { functionName: 'depositDiff', args: [1n] } ``` This is useful when you don't know the exact balance after previous operations. ## Gotchas ### Adapter ABIs Need Separate Import SDK exports core ABIs, but adapter ABIs often need separate import: ```typescript // Core ABIs from SDK import { iCreditFacadeV300MulticallAbi } from '@gearbox-protocol/sdk'; // Adapter ABIs from integrations package import { uniswapV3AdapterAbi } from '@gearbox-protocol/integrations-v3'; ``` Check what's available in `@gearbox-protocol/integrations-v3`. ### Not All Protocols Have Adapters An adapter must exist for each protocol you want to interact with. Check with `contractToAdapter`: ```typescript const adapter = await creditManager.read.contractToAdapter([protocolAddress]); if (adapter === '0x0000000000000000000000000000000000000000') { // No adapter - this protocol isn't integrated throw new Error('Protocol not supported'); } ``` ### Recipient Parameter is Overridden Many DEX functions have a `recipient` parameter. Adapters override this to ensure tokens go to the Credit Account, not an arbitrary address: ```typescript // You can pass any address here - adapter ignores it const swapParams = { recipient: '0x0000000000000000000000000000000000000000', // Will be overridden // ... }; ``` ### Always Use Slippage Protection External calls are vulnerable to sandwich attacks. Always wrap swaps with slippage checks: ```typescript const calls = [ storeExpectedBalances, adapterSwapCall, compareBalances, ]; ``` ### Adapter Function Signatures May Differ Adapter functions may have slightly different signatures than the underlying protocol: ```typescript // Uniswap Router: exactInputSingle(params) returns (uint256) // Adapter: exactInputSingle(params) -> also enables output token // Yearn Vault: deposit(amount) returns (shares) // Adapter: depositDiff(leftoverAmount) -> deposits all balance minus leftoverAmount ``` Read the adapter interface documentation for exact signatures. ### Token Enable/Disable is Automatic After adapter calls, tokens are automatically enabled/disabled based on balance changes: * Balance goes from 0 to non-zero: Token enabled * Balance goes from non-zero to 0: Token disabled You usually don't need manual `enableToken`/`disableToken` after adapter calls. ## See Also * [Controlling Slippage](https://docs.gearbox.finance/developers/controlling-slippage) - Protect your swaps * [Multicalls Overview](https://docs.gearbox.finance/developers/multicalls) - Combining SDK helpers with manual encoding * [Enabling/Disabling Tokens](https://docs.gearbox.finance/developers/enabling-disabling-tokens) - Manual token management ## Enabling/Disabling Tokens Source: https://docs.gearbox.finance/developers/enabling-disabling-tokens File: content/developers/enabling-disabling-tokens.mdx Explicitly manage which tokens count as collateral. > For Solidity implementation, see [Enabling and Disabling Tokens](https://docs.gearbox.finance/developers/multicalls). ## Why You manually enable/disable tokens when: * **Direct transfers** - Tokens sent directly to Credit Account aren't auto-enabled * **Gas optimization** - Disable unused tokens to reduce collateral check cost * **Risk management** - Prevent certain tokens from counting in health factor * **Edge cases** - Override automatic enable/disable behavior Most of the time you don't need this - tokens auto-enable/disable based on balance changes. But sometimes manual control is necessary. ## What Non-quoted tokens have automatic enable/disable behavior: | Balance Change | Action | | -------------- | ------------ | | 0/1 to > 1 | Auto-enable | | > 1 to 0/1 | Auto-disable | `enableToken` and `disableToken` let you override this when needed. **Important:** These functions only work on **non-quoted tokens**. Quota tokens can only be enabled/disabled via `updateQuota`. ## How ### Enable a Token ```typescript import { encodeFunctionData } from 'viem'; import { iCreditFacadeV300MulticallAbi } from '@gearbox-protocol/sdk'; const calls = [ { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'enableToken', args: [tokenAddress], }), }, ]; ``` ### Disable a Token ```typescript const calls = [ { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'disableToken', args: [tokenAddress], }), }, ]; ``` ### Enable Token After Direct Transfer If someone sends tokens directly to your Credit Account: ```typescript // Token was transferred directly to Credit Account // It won't count as collateral until enabled const calls = [ { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'enableToken', args: [directlyTransferredToken], }), }, ]; await market.creditFacade.write.multicall([creditAccountAddress, calls]); ``` ### Disable Unused Tokens to Save Gas Each enabled token requires a price oracle call during collateral check. Disable tokens with zero balance: ```typescript // Check which tokens have zero balance const accountData = await service.getCreditAccountData(creditAccountAddress); const tokensToDisable = accountData.tokens .filter(t => t.balance <= 1n && t.isEnabled) .map(t => t.token); const calls = tokensToDisable.map(token => ({ target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'disableToken', args: [token], }), })); ``` ## Gotchas ### No-Op for Quota Tokens Calling `enableToken` or `disableToken` on a quota token does nothing: ```typescript // This does nothing - quota tokens use updateQuota { functionName: 'enableToken', args: [quotaTokenAddress], // No effect } // Use this instead for quota tokens service.prepareUpdateQuota(quotaTokenAddress, quotaAmount, minQuota); ``` ### Cannot Enable Forbidden Tokens Some tokens are marked as "forbidden" and cannot be enabled: ```typescript // This will revert { functionName: 'enableToken', args: [forbiddenTokenAddress], // Reverts! } ``` Forbidden tokens must be swapped away, not disabled. ### Auto-Enable Usually Works Adapter calls and standard operations auto-enable tokens when balance increases: ```typescript // This swap auto-enables WETH { target: uniswapAdapter, callData: encodeSwap(/* USDC → WETH */), } // No need to call enableToken(wethAddress) after ``` You only need manual enable when: * Tokens are transferred directly to Credit Account (not via adapter) * You want to enable a zero-balance token preemptively ### Max Enabled Tokens Limit Each Credit Manager has a maximum number of enabled tokens per account. Exceeding this reverts the multicall: ```typescript // Check the limit const maxTokens = await creditManager.read.maxEnabledTokens(); // Count currently enabled tokens const enabledCount = accountData.tokens.filter(t => t.isEnabled).length; if (enabledCount >= maxTokens) { // Must disable some tokens before enabling new ones } ``` ### Disabled Tokens Still on Account Disabling a token doesn't remove it from the account - it just excludes it from health factor calculation. The balance remains: ```typescript // Token is disabled but balance stays disableToken(wethAddress); // Balance is still there, just not counted as collateral // Liquidators can claim disabled token balances as bonus! ``` **Warning:** Don't keep significant value in disabled tokens. During liquidation, liquidators can withdraw disabled tokens on top of their normal premium. ### Balance of 1 is "Zero" Gearbox treats balance of 0 and 1 the same (due to ERC20 rounding issues). Auto-disable triggers at balance <= 1: ```typescript // These are equivalent from Gearbox perspective balance = 0n // Disabled balance = 1n // Also disabled // This is enabled balance = 2n ``` ## See Also * [Updating Quotas](https://docs.gearbox.finance/developers/updating-quotas) - How to enable/disable quota tokens * [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls) - Auto-enable behavior with adapters * [Collateral Check Params](https://docs.gearbox.finance/developers/collateral-check-params) - Optimize checks for enabled tokens ## Credit Accounts Source: https://docs.gearbox.finance/developers/gm-accounts File: content/developers/gm-accounts.mdx Query and manage Gearbox credit accounts using the SDK. Credit accounts are isolated smart contracts that hold collateral and debt positions on behalf of users. ## Creating a Service Use `createCreditAccountService` for credit account operations: ```typescript import { GearboxSDK, createCreditAccountService } from '@gearbox-protocol/sdk'; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); // Create service (310 = V3.1) const service = createCreditAccountService(sdk, 310); ``` ## Querying Credit Accounts ### Get All Accounts for a Credit Manager ```typescript const accounts = await service.getCreditAccounts( { creditManager: cmAddress }, sdk.currentBlock ); for (const account of accounts) { console.log(`Account: ${account.addr}`); console.log(` Owner: ${account.owner}`); console.log(` Debt: ${account.debt}`); console.log(` Health Factor: ${account.healthFactor}`); } ``` ### Filter by Owner ```typescript const myAccounts = await service.getCreditAccounts( { creditManager: cmAddress, owner: myAddress, }, sdk.currentBlock ); ``` ### Account Data Structure Each credit account includes: | Field | Type | Description | | ---------------- | ------------- | --------------------------------- | | `addr` | `address` | Credit Account contract address | | `owner` | `address` | Account owner | | `creditManager` | `address` | Parent Credit Manager | | `debt` | `uint256` | Total debt (principal + interest) | | `healthFactor` | `uint256` | Current HF (10000 = 1.0) | | `tokens` | `TokenInfo[]` | Token balances and values | | `isLiquidatable` | `boolean` | Whether account can be liquidated | ## Reading Account State ### Health Factor ```typescript const account = accounts[0]; // Health factor is scaled by 10000 (10000 = 1.0) const hf = Number(account.healthFactor) / 10000; console.log(`Health Factor: ${hf.toFixed(4)}`); if (account.isLiquidatable) { console.log('Account is liquidatable!'); } ``` ### Token Balances ```typescript for (const token of account.tokens) { console.log(`${token.symbol}:`); console.log(` Balance: ${token.balance}`); console.log(` Value (underlying): ${token.balanceInUnderlying}`); console.log(` LT: ${token.lt / 100}%`); } ``` ### Debt Breakdown ```typescript console.log(`Total Debt: ${account.debt}`); console.log(`Principal: ${account.borrowedAmount}`); console.log(`Accrued Interest: ${account.cumulativeQuotaInterest}`); console.log(`Quota Fees: ${account.quotaFees}`); ``` ## Market Discovery Find the market for a credit manager: ```typescript const market = sdk.marketRegister.findByCreditManager(cmAddress); const creditFacade = market.creditFacade; console.log(`Credit Facade: ${creditFacade.address}`); console.log(`Pool: ${market.pool.address}`); ``` ## Opening a Credit Account ```typescript // Build multicall with SDK helpers const calls = [ service.prepareAddCollateral(usdcAddress, 10000n * 10n ** 6n), service.prepareIncreaseDebt(40000n * 10n ** 6n), ]; // Get credit facade const market = sdk.marketRegister.findByCreditManager(cmAddress); // Open account const hash = await market.creditFacade.write.openCreditAccount([ ownerAddress, calls, 0n, // referralCode ]); ``` ## Closing a Credit Account ```typescript // Build close multicall - typically repay and withdraw const closeCalls = [ service.prepareDecreaseDebt(account.debt), // Repay all debt // Withdraw remaining collateral handled automatically ]; const hash = await market.creditFacade.write.closeCreditAccount([ account.addr, closeCalls, ]); ``` ## Complete Example ```typescript import { GearboxSDK, createCreditAccountService } from '@gearbox-protocol/sdk'; import { createPublicClient, http } from 'viem'; import { mainnet } from 'viem/chains'; async function queryAccounts(cmAddress: `0x${string}`) { const client = createPublicClient({ chain: mainnet, transport: http(), }); const sdk = await GearboxSDK.attach({ client, marketConfigurators: [], }); const service = createCreditAccountService(sdk, 310); // Get all accounts const accounts = await service.getCreditAccounts( { creditManager: cmAddress }, sdk.currentBlock ); console.log(`Found ${accounts.length} credit accounts\n`); for (const account of accounts) { const hf = Number(account.healthFactor) / 10000; console.log(`Account: ${account.addr}`); console.log(` Owner: ${account.owner}`); console.log(` Debt: ${account.debt}`); console.log(` Health Factor: ${hf.toFixed(4)}`); console.log(` Liquidatable: ${account.isLiquidatable}`); // Token breakdown console.log(` Tokens:`); for (const token of account.tokens) { if (token.balance > 0n) { console.log(` ${token.symbol}: ${token.balance}`); } } console.log(''); } } queryAccounts('0x...').catch(console.error); ``` ## Learn More * [Account Operations](https://docs.gearbox.finance/developers/gm-accounts-ops) - Reference table of all operations * [KYC'd Accounts](https://docs.gearbox.finance/developers/gm-accounts-kyc) - Permissioned credit accounts * [Multicalls](https://docs.gearbox.finance/developers/gm-accounts-multicalls) - Build complex operations * [Liquidations](https://docs.gearbox.finance/developers/gm-liquidations) - Liquidation mechanics ## Positions (Strategies) Source: https://docs.gearbox.finance/developers/gm-positions File: content/developers/gm-positions.mdx This section covers opening and managing leveraged positions via Credit Accounts. A "position" in Gearbox is a Credit Account with active debt and collateral — it is the fundamental unit of leveraged activity in the protocol. ## Overview To enter a strategy, you open a Credit Account, deposit collateral, borrow from a Pool, and deploy capital through whitelisted DeFi adapters. The Credit Manager checks solvency after every operation. When you are done, you close the position by repaying debt and withdrawing remaining collateral. The position lifecycle is: **open, adjust, monitor, close**. ## What's in This Section | Page | Covers | | --- | --- | | [Account Operations](https://docs.gearbox.finance/developers/gm-accounts-ops) | Open, adjust, and close Credit Account positions | | [Positions](https://docs.gearbox.finance/developers/gm-accounts) | Query active positions, health factor, collateral breakdown | | [Multicalls](https://docs.gearbox.finance/developers/gm-accounts-multicalls) | Composable batched operations within a single transaction | | [Add Collateral](https://docs.gearbox.finance/developers/gm-mc-collateral) | Multicall operation: add collateral tokens | | [Manage Debt](https://docs.gearbox.finance/developers/gm-mc-debt) | Multicall operation: increase or decrease debt | | [Withdraw](https://docs.gearbox.finance/developers/gm-mc-withdraw) | Multicall operation: withdraw collateral | | [External Calls](https://docs.gearbox.finance/developers/gm-mc-external) | Multicall operation: interact with external DeFi protocols | | [Manage Quotas](https://docs.gearbox.finance/developers/gm-mc-quotas) | Multicall operation: update quota allocations | | [Token Management](https://docs.gearbox.finance/developers/gm-mc-tokens) | Multicall operation: enable/disable collateral tokens | | [Safety & Slippage](https://docs.gearbox.finance/developers/gm-mc-safety) | Multicall operation: slippage protection and health checks | | [Liquidations](https://docs.gearbox.finance/developers/gm-liquidations) | How liquidations work, thresholds, and partial liquidations | | [Bot System](https://docs.gearbox.finance/developers/gm-bots) | Automated position management, keeper bots, and monitoring | ## SDK Entry Points The primary namespaces for position management: ```ts // Open a position const tx = await sdk.positions.prepareOpen({ strategy, amount, leverage }); const preview = await sdk.positions.previewOpen(tx); await sdk.transactions.execute(tx); // Check position status const status = await sdk.positions.getStatus(positionId); // Adjust an existing position const adjustTx = await sdk.positions.prepareAdjust({ position, changes }); const adjustPreview = await sdk.positions.previewAdjust(adjustTx); await sdk.transactions.execute(adjustTx); // Close a position const closeTx = await sdk.positions.prepareClose({ position }); const closePreview = await sdk.positions.previewClose(closeTx); await sdk.transactions.execute(closeTx); ``` ## Learn More - [Strategy Opportunities](https://docs.gearbox.finance/developers/gm-opps-strategy) — discover strategies via the unified opportunity search - [Lender (Pools)](https://docs.gearbox.finance/developers/gm-lender) — the lender side of the protocol - [SDK Namespaces](https://docs.gearbox.finance/developers/gm-start-namespaces) — full namespace reference ## Updating Price Feeds Source: https://docs.gearbox.finance/developers/updating-price-feeds File: content/developers/updating-price-feeds.mdx Push fresh price data for on-demand oracles (Pyth, Redstone). > For Solidity implementation, see [Updating On-Demand Price Feeds](https://docs.gearbox.finance/developers/multicalls). ## Why You update price feeds when: * **Using on-demand oracles** - Pyth and Redstone require fresh data with each transaction * **Multicalls fail** - "Stale price" errors indicate missing price updates * **Withdrawals** - Reserve price feeds may also need updates under safe pricing Some tokens use "pull-based" oracles that don't update automatically. You must push fresh price data before operations that need it. ## What `onDemandPriceUpdate` pushes oracle data to the price feed: 1. You obtain signed price data from the oracle provider (off-chain) 2. You include the price update as the FIRST call in your multicall 3. Credit Facade forwards the data to the price feed contract 4. The price feed validates the signature and updates **Critical rule:** All price updates must be at the **beginning** of the calls array. Any `onDemandPriceUpdate` after another call type will revert. ## How ```typescript import { encodeFunctionData } from 'viem'; import { iCreditFacadeV300MulticallAbi } from '@gearbox-protocol/sdk'; // Get price data from oracle provider (e.g., Pyth) const priceData = await pythClient.getPriceUpdateData([feedId]); const calls = [ // Price update MUST be first { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'onDemandPriceUpdate', args: [ tokenAddress, // Token to update price for false, // reserve: false = main feed, true = reserve feed priceData, // Signed price data from oracle ], }), }, // Now other operations service.prepareAddCollateral(usdcAddress, amount), service.prepareIncreaseDebt(debtAmount), ]; ``` ### Multiple Price Updates Update several tokens at once (all must be at the start): ```typescript const calls = [ // All price updates first { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'onDemandPriceUpdate', args: [token1, false, priceData1], }), }, { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'onDemandPriceUpdate', args: [token2, false, priceData2], }), }, // Then other operations // ... ]; ``` ### Updating Reserve Feed (For Withdrawals) Withdrawals trigger safe pricing, which uses both main and reserve feeds: ```typescript const calls = [ // Main feed update { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'onDemandPriceUpdate', args: [tokenAddress, false, mainPriceData], // reserve = false }), }, // Reserve feed update { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'onDemandPriceUpdate', args: [tokenAddress, true, reservePriceData], // reserve = true }), }, // Now the withdrawal will work with safe pricing service.prepareWithdrawCollateral(otherToken, amount, recipient), ]; ``` ### Detecting Which Feeds Need Updates ```typescript import { priceFeedCompressorAbi } from '@gearbox-protocol/sdk'; const feedInfo = await client.readContract({ address: priceFeedCompressorAddress, abi: priceFeedCompressorAbi, functionName: 'getUpdatablePriceFeeds', args: [creditManagerAddress], }); // feedInfo contains tokens that need on-demand updates const tokensNeedingUpdate = feedInfo.filter(f => f.needsUpdate); ``` ## Gotchas ### Price Updates MUST Be First This is the most common mistake. Price updates after any other call type revert: ```typescript // WRONG - price update after addCollateral const calls = [ service.prepareAddCollateral(token, amount), onDemandPriceUpdate, // Reverts! ]; // CORRECT - price update first const calls = [ onDemandPriceUpdate, service.prepareAddCollateral(token, amount), ]; ``` ### Fresh Data Required Price data has a short validity window (usually a few minutes). Generate fresh data right before the transaction: ```typescript // Get price data immediately before building transaction const priceData = await pythClient.getPriceUpdateData([feedId]); // Use it right away const calls = [ onDemandPriceUpdate(token, false, priceData), // ... ]; // DON'T cache price data for later ``` ### Not All Tokens Need Updates Only tokens with on-demand price feeds need updates. Tokens using Chainlink or other push-based oracles don't need `onDemandPriceUpdate`: ```typescript // Check if token uses on-demand feed const priceFeed = await priceOracle.read.priceFeedsRaw([tokenAddress, false]); const feedType = priceFeed.feedType; // Only PYTH and REDSTONE feeds need updates if (feedType === 'PYTH' || feedType === 'REDSTONE') { // Include price update } ``` ### Disabled Tokens Don't Need Updates If a token will be disabled by the end of the multicall, you don't need to update its price: ```typescript // weth is getting swapped entirely (will be disabled) const calls = [ // No need for WETH price update since it's being disabled service.prepareAddCollateral(usdcAddress, amount), adapterSwap(weth, usdc, entireBalance), // WETH will auto-disable after swap ]; ``` ### Off-Chain Data Retrieval You need to fetch price data from the oracle's API before building your transaction. This is protocol-specific: ```typescript // Pyth example const pythConnection = new PriceServiceConnection("https://hermes.pyth.network"); const priceUpdateData = await pythConnection.getPriceFeedsUpdateData([feedId]); // Redstone example (simplified) const redstonePayload = await getRedstonePayload([tokenSymbol]); ``` Your contract or frontend must handle this off-chain step. ### Contracts Need Price Data Input If you're building a contract that interacts with Gearbox, it must accept price data as an input parameter: ```typescript // Your contract function signature function executeWithGearbox( bytes[] calldata priceUpdates, // Must be passed from frontend // other params ) external { // Build multicall with price updates first } ``` Contracts cannot fetch price data themselves - it must come from off-chain. ## See Also * [Controlling Slippage](https://docs.gearbox.finance/developers/controlling-slippage) - Stale prices can cause slippage issues * [Withdrawing Collateral](https://docs.gearbox.finance/developers/withdrawing-collateral) - May need reserve feed updates * [Collateral Check Params](https://docs.gearbox.finance/developers/collateral-check-params) - Related to price feed behavior ## Account Operations Source: https://docs.gearbox.finance/developers/gm-accounts-ops File: content/developers/gm-accounts-ops.mdx A reference of all operations available on credit accounts. Each operation can be included as a call within a multicall. ## Quick Reference | Operation | SDK Helper | When to Use | Guide | | -------------------- | ----------------------------- | ------------------------------------------ | ---------------------------------------------------- | | Add Collateral | `prepareAddCollateral()` | Deposit tokens to increase health factor | [Adding Collateral](https://docs.gearbox.finance/developers/gm-mc-collateral) | | Increase Debt | `prepareIncreaseDebt()` | Borrow from pool | [Debt Management](https://docs.gearbox.finance/developers/gm-mc-debt) | | Decrease Debt | `prepareDecreaseDebt()` | Repay borrowed funds | [Debt Management](https://docs.gearbox.finance/developers/gm-mc-debt) | | Update Quota | `prepareUpdateQuota()` | Enable/adjust quota token exposure | [Updating Quotas](https://docs.gearbox.finance/developers/gm-mc-quotas) | | Withdraw Collateral | `prepareWithdrawCollateral()` | Remove tokens from account | [Withdrawing Collateral](https://docs.gearbox.finance/developers/gm-mc-withdraw) | | Slippage Control | Manual encoding | Protect swaps from sandwich attacks | [Slippage & Safety](https://docs.gearbox.finance/developers/gm-mc-safety) | | External Calls | Manual encoding | Interact with Uniswap, Curve, etc. | [External Calls](https://docs.gearbox.finance/developers/gm-mc-external) | | Enable/Disable Token | Manual encoding | Explicit collateral management | [Token Management](https://docs.gearbox.finance/developers/gm-mc-tokens) | | Price Updates | Manual encoding | Update Pyth/Redstone feeds | [Slippage & Safety](https://docs.gearbox.finance/developers/gm-mc-safety) | | Check Params | Manual encoding | Optimize gas, set min health factor | [Slippage & Safety](https://docs.gearbox.finance/developers/gm-mc-safety) | | Revoke Allowances | Manual encoding | Security measure after suspicious activity | [Token Management](https://docs.gearbox.finance/developers/gm-mc-tokens) | ## SDK Helpers vs Manual Encoding **Five operations have SDK helpers** via `createCreditAccountService`: * `prepareAddCollateral(token, amount)` * `prepareIncreaseDebt(amount)` * `prepareDecreaseDebt(amount)` * `prepareUpdateQuota(token, change, minQuota)` * `prepareWithdrawCollateral(token, amount, to)` **Six operations require manual encoding** with viem's `encodeFunctionData`: * `storeExpectedBalances` / `compareBalances` * `enableToken` / `disableToken` * `onDemandPriceUpdate` * `setFullCheckParams` * `revokeAdapterAllowances` All manual encoding uses `iCreditFacadeV300MulticallAbi` from `@gearbox-protocol/sdk`. ## Page Structure Each operation guide covers: 1. **Why** - When you need this operation 2. **What** - What it does and how it fits the system 3. **How** - Working TypeScript code 4. **Gotchas** - Common mistakes and edge cases ## Learn More * [Multicalls](https://docs.gearbox.finance/developers/gm-accounts-multicalls) - How to build and execute multicalls * [Credit Accounts](https://docs.gearbox.finance/developers/gm-accounts) - Account data and services ## Collateral Check Params Source: https://docs.gearbox.finance/developers/collateral-check-params File: content/developers/collateral-check-params.mdx Optimize gas and set minimum health factor for collateral checks. > For Solidity implementation, see [Setting Collateral Check Params](https://docs.gearbox.finance/developers/multicalls). ## Why You set collateral check params when: * **Optimizing gas** - Hint which tokens cover the debt to skip unnecessary oracle calls * **Risk management** - Enforce a minimum health factor above 1.0 * **Large accounts** - Many enabled tokens make default checks expensive * **Automated systems** - Bots can benefit from consistent gas costs The collateral check iterates through enabled tokens, summing value until it exceeds debt. Hints tell it which tokens to check first, potentially skipping expensive oracle calls. ## What `setFullCheckParams` configures two things: 1. **Collateral hints** - Token masks to prioritize during the check 2. **Min health factor** - Minimum acceptable HF (in basis points, 10000 = 1.0) If you know your USDC and WETH cover the debt, pass their masks as hints. The check evaluates them first and may stop early without checking other tokens. ## How ### Basic Usage with Hints ```typescript import { encodeFunctionData } from 'viem'; import { iCreditFacadeV300MulticallAbi, creditManagerAbi } from '@gearbox-protocol/sdk'; import { getContract } from 'viem'; const creditManager = getContract({ address: cmAddress, abi: creditManagerAbi, client: publicClient, }); // Get token masks (each token has a unique bitmask) const usdcMask = await creditManager.read.getTokenMaskOrRevert([usdcAddress]); const wethMask = await creditManager.read.getTokenMaskOrRevert([wethAddress]); const calls = [ // Set hints at the start of multicall { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'setFullCheckParams', args: [ [usdcMask, wethMask], // Check these tokens first 10000, // minHealthFactor: 1.0 (10000 bps) ], }), }, // Rest of your multicall service.prepareAddCollateral(usdcAddress, amount), // ... ]; ``` ### Setting Higher Min Health Factor Require account to maintain at least 1.2 HF: ```typescript const MIN_HF_120 = 12000; // 1.2 in basis points const calls = [ { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'setFullCheckParams', args: [ [], // No hints MIN_HF_120, ], }), }, // Operations... ]; ``` ### Complete Example: Gas-Optimized Multicall ```typescript import { encodeFunctionData, getContract } from 'viem'; import { GearboxSDK, createCreditAccountService, iCreditFacadeV300MulticallAbi, creditManagerAbi, } from '@gearbox-protocol/sdk'; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); const service = createCreditAccountService(sdk, 310); const market = sdk.marketRegister.findByCreditManager(cmAddress); const creditManager = getContract({ address: market.creditManager.address, abi: creditManagerAbi, client: publicClient, }); // Get masks for tokens that will cover the debt const usdcMask = await creditManager.read.getTokenMaskOrRevert([usdcAddress]); const calls = [ // Hints first - USDC will cover most of debt { target: market.creditFacade.address, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'setFullCheckParams', args: [ [usdcMask], // USDC covers debt, check it first 10500, // Require 1.05 HF minimum ], }), }, service.prepareAddCollateral(usdcAddress, 100_000n * 10n ** 6n), service.prepareIncreaseDebt(200_000n * 10n ** 6n), // Swap some USDC to WETH { target: uniswapAdapter, callData: encodeSwap(/* ... */), }, ]; ``` ## Gotchas ### Masks, Not Addresses The hints array takes token **masks**, not addresses: ```typescript // WRONG - passing addresses args: [[usdcAddress, wethAddress], 10000] // CORRECT - passing masks const usdcMask = await creditManager.read.getTokenMaskOrRevert([usdcAddress]); args: [[usdcMask], 10000] ``` ### Hints Are Optimization, Not Guarantee The check still validates ALL enabled tokens - hints just change the order. If hints don't cover the debt, it continues with remaining tokens. ```typescript // If USDC hint doesn't cover debt, WETH and other tokens are still checked // Hints just potentially skip some oracle calls ``` ### Min Health Factor Must Be >= 10000 You cannot set a health factor below 1.0: ```typescript // WRONG - less than 10000 reverts args: [[], 9500] // Reverts! // CORRECT - must be >= 10000 args: [[], 10000] // Exactly 1.0 args: [[], 11000] // 1.1 ``` ### Hints Don't Help Small Accounts For accounts with few enabled tokens (< 5), hints add gas overhead without saving much. Only use for accounts with many tokens. ### Order Matters in Hints Array Tokens are checked in the order you provide: ```typescript // Check WETH first, then USDC args: [[wethMask, usdcMask], 10000] // Check USDC first, then WETH args: [[usdcMask, wethMask], 10000] ``` Put your highest-value collateral first for best gas savings. ### Each Check Calls Oracle Once Without hints, the check iterates through all enabled tokens by mask order until TWV >= debt. With hints: 1. Check hinted tokens first 2. If TWV >= debt, stop early 3. If not, continue with remaining tokens Best case: hints cover debt, skip other oracle calls. Worst case: hints don't help, all tokens checked anyway. ### Params Reset After Multicall `setFullCheckParams` only affects the current multicall's final check. Next multicall uses defaults again. ### Computing Token Masks Token masks are powers of 2, assigned sequentially when tokens are added to the Credit Manager: ```typescript // First token: mask = 1 (2^0) // Second token: mask = 2 (2^1) // Third token: mask = 4 (2^2) // etc. // Always use getTokenMaskOrRevert to get the correct mask const mask = await creditManager.read.getTokenMaskOrRevert([tokenAddress]); ``` ### Can Combine with Other Params Use hints for gas optimization AND min HF for risk management: ```typescript args: [ [primaryCollateralMask, secondaryCollateralMask], // Gas optimization 11000, // Risk management: require 1.1 HF ] ``` ## See Also * [Enabling/Disabling Tokens](https://docs.gearbox.finance/developers/enabling-disabling-tokens) - Affects which tokens are checked * [Price Updates](https://docs.gearbox.finance/developers/updating-price-feeds) - Oracle calls that hints can skip * [Debt Management](https://docs.gearbox.finance/developers/debt-management) - Debt determines what TWV must cover ## KYC'd Accounts Source: https://docs.gearbox.finance/developers/gm-accounts-kyc File: content/developers/gm-accounts-kyc.mdx Some Gearbox credit markets require identity verification before users can open or manage credit accounts. These permissioned markets use on-chain access control to restrict operations to whitelisted addresses. ## How It Works Permissioned credit managers use a **whitelist contract** that gates access to core operations. When KYC is enabled on a market: * Only whitelisted addresses can call `openCreditAccount` * Existing account owners retain access to manage their positions * Liquidations remain permissionless (anyone can liquidate unhealthy accounts) ## Checking Access Before attempting to open an account on a permissioned market, verify that your address is whitelisted: ```typescript import { getContract } from 'viem'; import { creditFacadeV3Abi } from '@gearbox-protocol/sdk'; const creditFacade = getContract({ address: facadeAddress, abi: creditFacadeV3Abi, client: publicClient, }); // Check if the facade has access restrictions const isDegenMode = await creditFacade.read.degenNFT(); const hasExpiration = await creditFacade.read.expirationDate(); // If degenNFT is set, the market requires a special NFT for access if (isDegenMode !== '0x0000000000000000000000000000000000000000') { console.log('This market requires a DegenNFT for access'); } ``` ## DegenNFT Gating The most common permissioning mechanism is the **DegenNFT**. Markets configured with a DegenNFT address require callers to hold that NFT to open accounts: * Each NFT grants a limited number of account opens * NFTs are distributed through governance or KYC providers * The NFT balance is decremented on each `openCreditAccount` call ```typescript import { erc721Abi } from 'viem'; const degenNFT = getContract({ address: degenNFTAddress, abi: erc721Abi, client: publicClient, }); const balance = await degenNFT.read.balanceOf([myAddress]); console.log(`Available account opens: ${balance}`); ``` ## Implications for Developers When building integrations against permissioned markets: * **Check access first** - Query the whitelist or NFT balance before constructing transactions * **Handle rejections gracefully** - Provide clear error messages when access is denied * **Liquidation bots work normally** - No KYC is needed for liquidation operations * **Multicalls are unaffected** - Once an account is open, all multicall operations work identically to permissionless markets ## Learn More * [Credit Accounts](https://docs.gearbox.finance/developers/gm-accounts) - General account management * [Account Operations](https://docs.gearbox.finance/developers/gm-accounts-ops) - Full operation reference * [Multicalls](https://docs.gearbox.finance/developers/gm-accounts-multicalls) - Building multicalls ## Positions Source: https://docs.gearbox.finance/developers/gm-accounts-positions File: content/developers/gm-accounts-positions.mdx Manage positions — open, adjust, close, and monitor — using the SDK vNext. The SDK builds transactions but never signs them. Your agent or wallet client handles signing and submission. ## Transaction Lifecycle Every position action follows the same five-step flow: | Step | Method | What Happens | |---|---|---| | **Prepare** | `prepareDeposit()` / `prepareOpen()` | Build a `RawTx` with calldata | | **Preview** | `previewDeposit()` / `previewOpen()` | Simulate the transaction against current state | | **Validate** | Check preview result | Verify HF, slippage, warnings | | **Execute** | `walletClient.sendTransaction(rawTx)` | Sign and submit on-chain | | **Monitor** | `sdk.accounts.getStatus()` | Track position health post-execution | ## The RawTx Type All prepare methods return a `RawTx` — a ready-to-sign transaction object: ```typescript interface RawTx { to: `0x${string}`; // Target contract address calldata: `0x${string}`; // Encoded function call value: bigint; // ETH value (usually 0n) } ``` The SDK builds, never signs. You submit the transaction using your wallet client: ```typescript const txHash = await walletClient.sendTransaction({ to: rawTx.to, data: rawTx.calldata, value: rawTx.value, }); ``` ## Depositing into a Pool ### Prepare a Deposit ```typescript import { GearboxSDK } from "@gearbox-protocol/sdk/official"; const sdk = await GearboxSDK.init({ chains: [1], startFromCache: true, }); const rawTx = await sdk.positions.prepareDeposit({ pool: poolAddress, chainId: 1, amount: 10_000n * 10n ** 6n, // 10,000 USDC receiver: walletAddress, }); ``` ### Preview a Deposit Before submitting, simulate to verify expected outcomes: ```typescript const preview = await sdk.positions.previewDeposit({ pool: poolAddress, chainId: 1, amount: 10_000n * 10n ** 6n, receiver: walletAddress, }); console.log(`Shares received: ${preview.sharesReceived}`); console.log(`Share price: ${preview.sharePrice}`); console.log(`Breakeven: ${preview.breakevenDays} days`); console.log(`Warnings: ${preview.warnings.join(", ") || "none"}`); ``` ### Full Deposit Flow ```typescript // 1. Prepare const rawTx = await sdk.positions.prepareDeposit({ pool: poolAddress, chainId: 1, amount: depositAmount, receiver: walletAddress, }); // 2. Preview const preview = await sdk.positions.previewDeposit({ pool: poolAddress, chainId: 1, amount: depositAmount, receiver: walletAddress, }); // 3. Validate if (!preview.success || preview.warnings.length > 0) { console.error("Deposit preview failed:", preview.warnings); return; } // 4. Execute (SDK builds, you sign) const txHash = await walletClient.sendTransaction({ to: rawTx.to, data: rawTx.calldata, value: rawTx.value, }); await publicClient.waitForTransactionReceipt({ hash: txHash }); ``` ## Opening a Leveraged Position ### Prepare an Open ```typescript const rawTx = await sdk.positions.prepareOpen({ creditManager: cmAddress, chainId: 1, collateralToken: wstETHAddress, collateralAmount: 10n * 10n ** 18n, // 10 wstETH targetLeverage: 3.0, }); ``` ### Preview an Open ```typescript const preview = await sdk.positions.previewOpen({ creditManager: cmAddress, chainId: 1, collateralToken: wstETHAddress, collateralAmount: 10n * 10n ** 18n, targetLeverage: 3.0, }); console.log(`Health Factor: ${preview.healthFactor}`); console.log(`Net APY: ${preview.netApy}%`); console.log(`Actual leverage: ${preview.actualLeverage}x`); console.log(`Debt: ${preview.debtAmount}`); console.log(`Swap impact: ${preview.swapImpactBps} bps`); ``` ### Full Open Flow ```typescript // 1. Prepare the transaction const rawTx = await sdk.positions.prepareOpen({ creditManager: cmAddress, chainId: 1, collateralToken: wstETHAddress, collateralAmount: collateralAmount, targetLeverage: 3.0, }); // 2. Preview and validate const preview = await sdk.positions.previewOpen({ creditManager: cmAddress, chainId: 1, collateralToken: wstETHAddress, collateralAmount: collateralAmount, targetLeverage: 3.0, }); if (!preview.success) { console.error("Position open failed simulation"); return; } if (preview.healthFactor < 1.5) { console.warn(`Health factor ${preview.healthFactor} is below safety threshold`); return; } if (preview.warnings.length > 0) { console.warn("Warnings:", preview.warnings); } // 3. Execute const txHash = await walletClient.sendTransaction({ to: rawTx.to, data: rawTx.calldata, value: rawTx.value, }); const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash }); console.log(`Position opened: ${receipt.transactionHash}`); ``` ## Universal Transaction Preview Use `sdk.previewTransaction()` to simulate any raw transaction against current chain state. This works for transactions built outside the SDK as well. ```typescript const result = await sdk.previewTransaction({ to: targetAddress, calldata: encodedCalldata, value: 0n, }, { chainId: 1, from: walletAddress, }); console.log(`Success: ${result.success}`); console.log(`Health factor: ${result.healthFactor}`); console.log(`Actions: ${result.actions.map(a => a.type).join(", ")}`); console.log(`Balance changes:`, result.balanceChanges); console.log(`Warnings: ${result.warnings.join(", ") || "none"}`); ``` ### Preview Result Fields | Field | Type | Description | |---|---|---| | `success` | `boolean` | Whether the simulation succeeded | | `healthFactor` | `number \| null` | Projected health factor after execution | | `actions` | `Action[]` | Decoded actions the transaction performs | | `balanceChanges` | `BalanceChange[]` | Token balance deltas | | `warnings` | `string[]` | Human-readable risk warnings | ## Listing Credit Accounts Retrieve all credit accounts owned by a wallet: ```typescript const accounts = await sdk.accounts.list({ owner: walletAddress, chainId: 1, }); for (const account of accounts) { console.log(`Account: ${account.address}`); console.log(` CM: ${account.creditManager}`); console.log(` Health Factor: ${account.healthFactor}`); console.log(` Total Value: $${account.totalValueUsd}`); } ``` ## Position Health and Status Get detailed status for a specific credit account: ```typescript const status = await sdk.accounts.getStatus({ account: creditAccountAddress, chainId: 1, }); console.log(`Health Factor: ${status.healthFactor}`); console.log(`Leverage: ${status.leverage}x`); console.log(`Total Value: $${status.totalValueUsd}`); console.log(`Total Debt: $${status.totalDebtUsd}`); // Token composition for (const token of status.tokens) { console.log(` ${token.symbol}: ${token.balance} ($${token.valueUsd})`); } // Active bots for (const bot of status.bots) { console.log(` Bot: ${bot.address} — ${bot.permissions.join(", ")}`); } ``` ### Status Fields | Field | Type | Description | |---|---|---| | `healthFactor` | `number` | Current HF. Below 1 means liquidatable | | `totalValueUsd` | `number` | Position total value in USD | | `totalDebtUsd` | `number` | Outstanding debt in USD | | `leverage` | `number` | Current leverage ratio | | `tokens` | `TokenPosition[]` | Per-token balances, values, and LT info | | `bots` | `BotInfo[]` | Attached bots and their permissions | | `isPaused` | `boolean` | Whether the credit manager is paused | | `expirationDate` | `string \| null` | Account expiration, if applicable | ## Monitoring Alerts Use `sdk.monitor.getAlerts()` to check for active warnings on your positions: ```typescript const alerts = await sdk.monitor.getAlerts({ owner: walletAddress, chainId: 1, }); for (const alert of alerts) { console.log(`[${alert.severity}] ${alert.account}: ${alert.message}`); } ``` ### Alert Types | Severity | Condition | Suggested Action | |---|---|---| | `"warning"` | Health factor below 1.3 | Add collateral or reduce debt | | `"critical"` | Health factor below 1.1 | Immediate deleveraging or exit | | `"info"` | LT ramp active | Plan scheduled adjustment | | `"info"` | Account nearing expiration | Close or migrate before deadline | ## Position Lifecycle Example A complete flow from discovery through monitoring: ```typescript import { GearboxSDK, Asset } from "@gearbox-protocol/sdk/official"; // 1. Initialize const sdk = await GearboxSDK.init({ chains: [1], startFromCache: true }); // 2. Discover const strategies = await sdk.strategies.list({ chainId: 1, asset: Asset.ETH, minNetApy: 3, }); const strategy = strategies[0]; // 3. Prepare const rawTx = await sdk.positions.prepareOpen({ creditManager: strategy.id, chainId: 1, collateralToken: wstETHAddress, collateralAmount: 10n * 10n ** 18n, targetLeverage: 3.0, }); // 4. Preview const preview = await sdk.positions.previewOpen({ creditManager: strategy.id, chainId: 1, collateralToken: wstETHAddress, collateralAmount: 10n * 10n ** 18n, targetLeverage: 3.0, }); if (!preview.success || preview.healthFactor < 1.5) { throw new Error("Preview failed safety checks"); } // 5. Execute (you sign) const txHash = await walletClient.sendTransaction({ to: rawTx.to, data: rawTx.calldata, value: rawTx.value, }); await publicClient.waitForTransactionReceipt({ hash: txHash }); // 6. Monitor const accounts = await sdk.accounts.list({ owner: walletAddress, chainId: 1 }); const status = await sdk.accounts.getStatus({ account: accounts[0].address, chainId: 1, }); console.log(`Position HF: ${status.healthFactor}`); ``` ## Method Reference | Method | Returns | Description | |---|---|---| | `sdk.positions.prepareDeposit(params)` | `RawTx` | Build a pool deposit transaction | | `sdk.positions.previewDeposit(params)` | `DepositPreview` | Simulate a pool deposit | | `sdk.positions.prepareOpen(params)` | `RawTx` | Build a leveraged position open | | `sdk.positions.previewOpen(params)` | `OpenPreview` | Simulate a position open | | `sdk.previewTransaction(rawTx, opts)` | `TransactionPreview` | Universal simulation for any raw tx | | `sdk.accounts.list(params)` | `CreditAccount[]` | List credit accounts for a wallet | | `sdk.accounts.getStatus(params)` | `AccountStatus` | Full position health and composition | | `sdk.monitor.getAlerts(params)` | `Alert[]` | Active warnings across positions | ## Learn More - [Opportunities](https://docs.gearbox.finance/developers/gm-markets-opportunities) — discovering pools and strategies - [History & Events](https://docs.gearbox.finance/developers/gm-markets-history) — historical data and parameter change tracking - [Account Operations](https://docs.gearbox.finance/developers/gm-accounts-ops) — low-level multicall operations reference - [Multicalls](https://docs.gearbox.finance/developers/gm-accounts-multicalls) — building complex multi-step transactions ## Revoke Allowances Source: https://docs.gearbox.finance/developers/revoke-allowances File: content/developers/revoke-allowances.mdx Revoke Credit Account's token approvals to external contracts. > For Solidity implementation, see [Revoke Allowances](https://docs.gearbox.finance/developers/multicalls). ## Why You revoke allowances when: * **Security incident** - Third-party contract may be compromised * **Legacy cleanup** - Old accounts may have stale approvals from previous Gearbox versions * **Defense in depth** - Proactively remove unnecessary approvals Current Gearbox V3 automatically resets allowances to 1 after each interaction. However, older accounts from V2.1 may still have active allowances to external protocols. ## What `revokeAdapterAllowances` resets token approvals from your Credit Account to specified contracts: 1. You specify which (spender, token) pairs to revoke 2. Credit Account sets allowance to 1 for each pair 3. External contracts can no longer spend those tokens **Note:** Allowance is set to 1, not 0, due to gas optimization (writing non-zero to non-zero is cheaper than writing zero). ## How ```typescript import { encodeFunctionData } from 'viem'; import { iCreditFacadeV300MulticallAbi } from '@gearbox-protocol/sdk'; // Define which approvals to revoke const revocations = [ { spender: uniswapRouterAddress, token: usdcAddress, }, { spender: curvePoolAddress, token: daiAddress, }, ]; const calls = [ { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'revokeAdapterAllowances', args: [revocations], }), }, ]; await market.creditFacade.write.multicall([creditAccountAddress, calls]); ``` ### Check Existing Allowances Before revoking, you might want to see what allowances exist: ```typescript import { erc20Abi, getContract } from 'viem'; const token = getContract({ address: tokenAddress, abi: erc20Abi, client: publicClient, }); // Check allowance from Credit Account to a spender const allowance = await token.read.allowance([ creditAccountAddress, spenderAddress, ]); if (allowance > 1n) { console.log(`Credit Account has ${allowance} allowance to ${spenderAddress}`); } ``` ### Revoke All Known Adapters If you want to revoke all adapter allowances for a token: ```typescript // Get all adapters from Credit Manager const adapters = await creditManager.read.adapters(); // Build revocations for all adapters const revocations = adapters.map(adapter => ({ spender: adapter, token: tokenAddress, })); const calls = [ { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'revokeAdapterAllowances', args: [revocations], }), }, ]; ``` ## Gotchas ### Usually Not Needed in V3 Gearbox V3 automatically resets allowances after each adapter interaction. This function exists mainly for: 1. Legacy accounts migrated from V2.1 2. Paranoid security posture 3. Specific incident response If you're using a fresh V3 account, allowances are already minimal. ### Revocation Struct Format The `RevocationPair` struct has two fields: ```typescript interface RevocationPair { spender: Address; // Contract that has the allowance token: Address; // Token that was approved } ``` Both must be valid addresses. Invalid addresses may cause the call to revert or have no effect. ### Sets to 1, Not 0 For gas efficiency, allowances are set to 1 instead of 0: ```typescript // Before revocation: allowance = 1000000000000000000 (1 token) // After revocation: allowance = 1 (essentially zero for practical purposes) ``` An allowance of 1 wei is functionally zero for any realistic token amount. ### Can't Revoke Non-Existent Allowances Revoking an allowance that doesn't exist (already 0 or 1) is a no-op - it won't revert, but wastes gas. ### Adapter vs External Contract Revocations target the **spender** (usually an adapter), not the underlying protocol: ```typescript // The adapter has the allowance, not Uniswap directly const revocations = [ { spender: uniswapAdapter, // Adapter address, not Uniswap Router token: usdcAddress, }, ]; ``` Adapters are what actually interact with your Credit Account's tokens. ### Batch Multiple Revocations You can revoke multiple (spender, token) pairs in one call: ```typescript // Efficient - single call const revocations = [ { spender: adapter1, token: usdc }, { spender: adapter1, token: dai }, { spender: adapter2, token: usdc }, ]; args: [revocations] // Less efficient - multiple calls [ { args: [[{ spender: adapter1, token: usdc }]] }, { args: [[{ spender: adapter1, token: dai }]] }, { args: [[{ spender: adapter2, token: usdc }]] }, ] ``` ### When to Actually Use This Real scenarios where revocation makes sense: 1. **Third-party exploit:** A protocol Gearbox integrates with gets hacked. Revoke allowances to that protocol's adapter as a precaution. 2. **Account migration:** Moving from V2.1 account with old allowances to ensure clean state. 3. **Compliance requirement:** Some regulatory frameworks require revoking unused approvals. 4. **Personal security policy:** You want explicit control over all approvals. For normal operations, V3's automatic reset is sufficient. ## See Also * [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls) - How adapters use allowances * [Enabling/Disabling Tokens](https://docs.gearbox.finance/developers/enabling-disabling-tokens) - Related account management * [Credit Accounts](https://docs.gearbox.finance/developers/credit-accounts) - Account overview and management ## Multicalls Source: https://docs.gearbox.finance/developers/gm-accounts-multicalls File: content/developers/gm-accounts-multicalls.mdx Build and execute multicalls to perform multiple operations on a credit account atomically. Multicalls are the primary way to interact with credit accounts. ## Service Multicall Helpers The SDK provides structured multicall builders via `createCreditAccountService`: ```typescript import { GearboxSDK, createCreditAccountService } from '@gearbox-protocol/sdk'; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); const service = createCreditAccountService(sdk, 310); ``` ## Available Service Methods | Method | Operation | | ---------------------------------------------- | -------------------------- | | `prepareAddCollateral(token, amount)` | Add collateral from wallet | | `prepareIncreaseDebt(amount)` | Borrow from pool | | `prepareDecreaseDebt(amount)` | Repay debt | | `prepareUpdateQuota(token, change, minQuota)` | Adjust token quota | | `prepareWithdrawCollateral(token, amount, to)` | Remove collateral | ## Building a Multicall ```typescript // Build multicall with SDK helpers const calls = [ // Add 10,000 USDC as collateral service.prepareAddCollateral(usdcAddress, 10_000n * 10n ** 6n), // Borrow 40,000 USDC (5x leverage) service.prepareIncreaseDebt(40_000n * 10n ** 6n), // Set quota for destination token service.prepareUpdateQuota(wethAddress, 50_000n * 10n ** 6n, 50_000n * 10n ** 6n), ]; ``` ## Executing Multicalls ### On Existing Account ```typescript const market = sdk.marketRegister.findByCreditManager(cmAddress); await market.creditFacade.write.multicall([ creditAccountAddress, calls, ]); ``` ### Opening with Multicall ```typescript const hash = await market.creditFacade.write.openCreditAccount([ ownerAddress, calls, 0n, // referralCode ]); ``` ## Combining SDK Helpers with Raw Encoding For adapter calls or custom operations, combine SDK helpers with manual encoding: ```typescript import { encodeFunctionData } from 'viem'; import { iCreditFacadeV300MulticallAbi } from '@gearbox-protocol/sdk'; const calls = [ // SDK helpers for standard operations service.prepareAddCollateral(usdcAddress, 10_000n * 10n ** 6n), service.prepareIncreaseDebt(40_000n * 10n ** 6n), // Manual encoding for adapter calls { target: uniswapV3Adapter, callData: encodeFunctionData({ abi: uniswapV3AdapterAbi, functionName: 'exactInputSingle', args: [{ tokenIn: usdcAddress, tokenOut: wethAddress, fee: 500, recipient: '0x0000000000000000000000000000000000000000', // Adapter overrides deadline: BigInt(Math.floor(Date.now() / 1000) + 3600), amountIn: 50_000n * 10n ** 6n, amountOutMinimum: 0n, sqrtPriceLimitX96: 0n, }], }), }, // SDK helper for quota service.prepareUpdateQuota(wethAddress, 50_000n * 10n ** 6n, 50_000n * 10n ** 6n), ]; ``` ## Getting Adapter Addresses Retrieve adapter addresses from the Credit Manager: ```typescript import { getContract } from 'viem'; import { creditManagerAbi } from '@gearbox-protocol/sdk'; const creditManager = getContract({ address: cmAddress, abi: creditManagerAbi, client: publicClient, }); // Get adapter for a protocol (e.g., Uniswap V3 Router) const uniswapV3Adapter = await creditManager.read.contractToAdapter([ UNISWAP_V3_ROUTER, ]); ``` ## Complete Example ```typescript import { GearboxSDK, createCreditAccountService, iCreditFacadeV300MulticallAbi, } from '@gearbox-protocol/sdk'; import { encodeFunctionData, createPublicClient, createWalletClient, http } from 'viem'; import { mainnet } from 'viem/chains'; async function leveragePosition() { const publicClient = createPublicClient({ chain: mainnet, transport: http(), }); const sdk = await GearboxSDK.attach({ client: publicClient, marketConfigurators: [], }); const service = createCreditAccountService(sdk, 310); // Find market const market = sdk.marketRegister.findByCreditManager(cmAddress); // Build multicall const calls = [ // Add collateral service.prepareAddCollateral(usdcAddress, 10_000n * 10n ** 6n), // Borrow service.prepareIncreaseDebt(40_000n * 10n ** 6n), // Set quota for final token service.prepareUpdateQuota(targetToken, 50_000n * 10n ** 6n, 50_000n * 10n ** 6n), ]; // Execute const walletClient = createWalletClient({ chain: mainnet, transport: http(), account: myAccount, }); const hash = await walletClient.writeContract({ address: market.creditFacade.address, abi: creditFacadeAbi, functionName: 'openCreditAccount', args: [myAccount.address, calls, 0n], }); console.log(`Transaction: ${hash}`); } ``` ## Best Practices 1. **Always use slippage protection** when performing swaps 2. **Price updates first** if using pull-based oracles 3. **Set quotas** for tokens you'll hold as collateral 4. **Approve collateral** to Credit Manager (not Facade) before adding ## Learn More * [Adding Collateral](https://docs.gearbox.finance/developers/gm-mc-collateral) - Transfer tokens with approval patterns * [Debt Management](https://docs.gearbox.finance/developers/gm-mc-debt) - Borrowing, repayment, and constraints * [Updating Quotas](https://docs.gearbox.finance/developers/gm-mc-quotas) - Quota mechanics and limits * [Withdrawing Collateral](https://docs.gearbox.finance/developers/gm-mc-withdraw) - Safe pricing and health impact * [External Calls](https://docs.gearbox.finance/developers/gm-mc-external) - Adapter interaction patterns * [Slippage & Safety](https://docs.gearbox.finance/developers/gm-mc-safety) - Balance protection, price feeds, and check params * [Token Management](https://docs.gearbox.finance/developers/gm-mc-tokens) - Token enable/disable and allowance revocation ## Use Cases Source: https://docs.gearbox.finance/developers/use-cases File: content/developers/use-cases.mdx The SDK guide shows you how to use individual methods. This section shows you how to combine them to build real applications. ## Choose Your Path | If you're building... | Start here | You'll learn | | --------------------------------- | -------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | | Web dashboard, portfolio UI | [Frontend Applications](https://docs.gearbox.finance/developers/frontend-applications) | Data fetching patterns, display mapping, real-time updates | | Indexer, analytics, data pipeline | [Backend Services](https://docs.gearbox.finance/developers/backend-services) | Historical snapshots, event indexing, state tracking | | Liquidation bot | [Liquidation Bots](https://docs.gearbox.finance/developers/liquidation-bots) | Account monitoring, health factor filtering, execution patterns | | Health monitoring | [Health Factor Monitoring](https://docs.gearbox.finance/developers/health-factor-monitoring) | Track HF over time, alerts, risk analysis | ## Quick Decision Guide **Need to display data to users in real-time?** Start with [Frontend Applications](https://docs.gearbox.finance/developers/frontend-applications). You'll use `marketRegister` for cached data and compressors for fresh queries. **Need to collect and analyze historical data?** Start with [Backend Services](https://docs.gearbox.finance/developers/backend-services). You'll index events and snapshot state at specific blocks. **Need to monitor accounts and execute on-chain actions?** Start with [Liquidation Bots](https://docs.gearbox.finance/developers/liquidation-bots). You'll filter accounts by health factor and use the Router for execution. **Need to track account health and alert on risk?** Start with [Health Factor Monitoring](https://docs.gearbox.finance/developers/health-factor-monitoring). You'll poll compressors, classify risk levels, and build alerting. ## Prerequisites Before diving into use-case guides, complete: 1. [**Setup**](https://docs.gearbox.finance/developers/sdk-setup) - Install the SDK and initialize `GearboxSDK` 2. [**Reading Data**](https://docs.gearbox.finance/developers/reading-data) - Understand `marketRegister` and basic queries ## Common Foundation: Compressors All use cases rely on compressors for efficient data fetching. Compressors aggregate on-chain data into single calls, reducing RPC overhead. | Compressor | Use Case | | ------------------------- | --------------------------------------------- | | `MarketCompressor` | Pool state, credit manager config, token data | | `CreditAccountCompressor` | Account queries with filtering and pagination | | `PriceFeedCompressor` | Oracle status and update requirements | See [Compressors Reference](https://docs.gearbox.finance/developers/compressors) for the complete API. ## Relationship to Other Guides ``` SDK Guide ├── setup.md # Installation and initialization ├── reading-data.md # Basic queries ├── credit-accounts.md # Account operations ├── multicalls.md # Operation overview ├── multicalls/ # Individual operation docs │ └── [10 operation pages] └── use-cases/ # <-- You are here ├── frontend-applications.md ├── backend-services.md ├── liquidation-bots.md └── health-factor-monitoring.md ``` The **multicalls/** directory documents individual operations (add collateral, manage debt, etc.). The **use-cases/** directory shows how to combine those operations with data fetching to build complete applications. ## Adding Collateral Source: https://docs.gearbox.finance/developers/gm-mc-collateral File: content/developers/gm-mc-collateral.mdx Deposit tokens from your wallet to a credit account to increase its health factor and enable borrowing. ## Why You need to add collateral when: * **Opening an account** - Initial deposit to enable borrowing * **Improving health factor** - Account approaching liquidation threshold * **Enabling more borrowing** - Current collateral limits how much you can borrow Adding collateral increases your account's total weighted value (TWV), which improves the health factor and allows larger debt positions. ## What `addCollateral` transfers tokens from your wallet to the Credit Account. On execution: 1. The Credit Manager calls `transferFrom` to move tokens from caller to Credit Account 2. The token is enabled as collateral (if not already enabled) 3. Quoted tokens are NOT auto-enabled - you must set a quota separately **Important:** Approve tokens to the **Credit Manager**, not the Credit Facade. The Credit Manager is the contract that actually executes the transfer. ## How ```typescript import { GearboxSDK, createCreditAccountService } from '@gearbox-protocol/sdk'; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); const service = createCreditAccountService(sdk, 310); // Build the multicall const calls = [ service.prepareAddCollateral(usdcAddress, 10_000n * 10n ** 6n), ]; // First, approve to Credit Manager (not Facade!) const market = sdk.marketRegister.findByCreditManager(cmAddress); await usdcContract.write.approve([ market.creditManager.address, 10_000n * 10n ** 6n, ]); // Execute on existing account await market.creditFacade.write.multicall([creditAccountAddress, calls]); // Or open new account with collateral await market.creditFacade.write.openCreditAccount([ ownerAddress, calls, 0n, // referralCode ]); ``` ### Using Permit (No Separate Approval) For EIP-2612 compatible tokens, you can avoid the separate approval transaction: ```typescript import { encodeFunctionData } from 'viem'; import { iCreditFacadeV300MulticallAbi } from '@gearbox-protocol/sdk'; // Sign permit message (details depend on your wallet setup) const { v, r, s, deadline } = await signPermit(/* ... */); const calls = [ { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'addCollateralWithPermit', args: [tokenAddress, amount, deadline, v, r, s], }), }, ]; ``` ## Gotchas ### Approve to Credit Manager, Not Facade The most common mistake. The Credit Manager executes the `transferFrom`, so it needs the approval: ```typescript // CORRECT await token.write.approve([creditManager.address, amount]); // WRONG - will fail await token.write.approve([creditFacade.address, amount]); ``` ### Quoted Tokens Need Quota Adding a quoted token as collateral does NOT automatically enable it. You must also call `updateQuota`: ```typescript const calls = [ service.prepareAddCollateral(quotedTokenAddress, amount), service.prepareUpdateQuota(quotedTokenAddress, quotaAmount, minQuota), ]; ``` ### Direct Transfers Don't Enable Sending tokens directly to a Credit Account (via `transfer`) does NOT enable them as collateral. You still need a multicall with `enableToken` to count them in the health factor. ### Invalid Collateral Tokens Only tokens recognized by the Credit Manager can be used as collateral. Transferring unrecognized tokens to a Credit Account may result in them being stuck (only governance can recover). Check if a token is valid: ```typescript // This reverts if token is not valid collateral const mask = await creditManager.read.getTokenMaskOrRevert([tokenAddress]); ``` ## Learn More * [Withdrawing Collateral](https://docs.gearbox.finance/developers/gm-mc-withdraw) - The reverse operation * [Debt Management](https://docs.gearbox.finance/developers/gm-mc-debt) - Often combined with adding collateral * [Updating Quotas](https://docs.gearbox.finance/developers/gm-mc-quotas) - Required for quoted tokens ## Frontend Applications Source: https://docs.gearbox.finance/developers/frontend-applications File: content/developers/frontend-applications.mdx Build dashboards, portfolio trackers, and trading UIs that display Gearbox protocol data and let users manage positions. ## Overview Frontend applications typically need to: 1. Display pool and market data 2. Show collateral exposure and limits 3. Monitor credit account health 4. Enable position management This guide maps each requirement to specific SDK methods. *** ## Pool Display **WHY:** Users want to see pool health, yields, and utilization before depositing or borrowing. ### Data Requirements | Display | SDK Source | Field | | ------------------- | ------------- | -------------------------------------------------- | | Underlying token | `market.pool` | `underlying.symbol`, `underlying.address` | | Total supplied | `market.pool` | `totalAssets` | | Available liquidity | `market.pool` | `availableLiquidity` | | Utilization | Calculated | `(totalAssets - availableLiquidity) / totalAssets` | | Supply APY | `market.pool` | `supplyRate` (RAY scaled) | | Borrow APR | `market.pool` | `baseInterestRate` (RAY scaled) | | Share price | `market.pool` | `dieselRate` (RAY scaled) | ### How to Fetch ```typescript import { GearboxSDK } from '@gearbox-protocol/sdk'; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); // Find market by pool address const market = sdk.marketRegister.findByPool(poolAddress); const pool = market.pool; // Display data const RAY = 10n ** 27n; console.log(`Underlying: ${pool.underlying.symbol}`); console.log(`Total Supplied: ${pool.totalAssets}`); console.log(`Available: ${pool.availableLiquidity}`); // Calculate utilization const borrowed = pool.totalAssets - pool.availableLiquidity; const utilization = Number(borrowed * 10000n / pool.totalAssets) / 100; console.log(`Utilization: ${utilization.toFixed(2)}%`); // Convert RAY rates to percentages const supplyAPY = Number(pool.supplyRate * 10000n / RAY) / 100; const borrowAPR = Number(pool.baseInterestRate * 10000n / RAY) / 100; console.log(`Supply APY: ${supplyAPY.toFixed(2)}%`); console.log(`Borrow APR: ${borrowAPR.toFixed(2)}%`); ``` ### Where Data Comes From The SDK caches market data on initialization via `GearboxSDK.attach()`. This data comes from the `MarketCompressor` contract. For real-time updates, either: * Re-initialize the SDK periodically * Call compressors directly (see [Real-Time Updates](#real-time-updates)) *** ## Collateral Exposure **WHY:** Users want to see what collaterals the pool is exposed to and current utilization against limits. ### Data Requirements | Display | SDK Source | Field | | --------------------- | ------------------------ | ------------------- | | Quoted tokens | `MarketData.quotaKeeper` | `tokens[]` | | Token quota limit | `quotaKeeper.tokens[]` | `limit` | | Current quoted amount | `quotaKeeper.tokens[]` | `totalQuoted` | | Quota rate | `quotaKeeper.tokens[]` | `rate` (RAY scaled) | ### How to Fetch For quota data, use the `MarketCompressor` directly: ```typescript import { marketCompressorAbi, AP_MARKET_COMPRESSOR, VERSION_RANGE_310, } from '@gearbox-protocol/sdk'; // Get compressor address const [compressor] = sdk.addressProvider.mustGetLatest( AP_MARKET_COMPRESSOR, VERSION_RANGE_310 ); // Fetch market data with quota keeper const marketData = await client.readContract({ address: compressor, abi: marketCompressorAbi, functionName: 'getMarketData', args: [poolAddress], }); // QuotaKeeper token data for (const token of marketData.quotaKeeper.tokens) { const utilizationPct = Number(token.totalQuoted * 10000n / token.limit) / 100; console.log(`Token: ${token.token}`); console.log(` Limit: ${token.limit}`); console.log(` Quoted: ${token.totalQuoted}`); console.log(` Utilization: ${utilizationPct.toFixed(2)}%`); console.log(` Rate: ${token.rate}`); // RAY scaled } ``` ### Gotcha: Quota Limits Before letting users open positions with a specific collateral, check that `totalQuoted < limit`. If the limit is reached, new positions with that collateral will fail. *** ## Credit Manager Configuration **WHY:** Users need to know debt limits, collateral requirements, and fees before opening positions. ### Data Requirements | Display | SDK Source | Field | | --------------------- | -------------------- | ------------------------------------- | | Min debt | `creditManager` | `minDebt` | | Max debt | `creditManager` | `maxDebt` | | Collateral tokens | `creditManager` | `collateralTokens[]` | | Liquidation threshold | `collateralTokens[]` | `liquidationThreshold` (basis points) | | Fees | `creditManager` | `fees` | | Liquidation premium | `creditManager` | `liquidationPremium` | ### How to Fetch ```typescript const market = sdk.marketRegister.findByCreditManager(cmAddress); for (const cm of market.creditManagers) { console.log(`Credit Manager: ${cm.address}`); console.log(`Credit Facade: ${cm.creditFacade}`); // Debt limits console.log(`Min Debt: ${cm.minDebt}`); console.log(`Max Debt: ${cm.maxDebt}`); // Collateral configuration console.log('Allowed Collaterals:'); for (const token of cm.collateralTokens) { // LT is in basis points (10000 = 100%) const ltPct = Number(token.liquidationThreshold) / 100; console.log(` ${token.symbol}: LT ${ltPct.toFixed(1)}%`); } } ``` ### Understanding Liquidation Threshold The liquidation threshold (LT) determines how much each collateral contributes to the weighted collateral value: ``` Weighted Value = Token Balance * Token Price * LT Health Factor = Total Weighted Value / Total Debt ``` A lower LT means the protocol values that collateral more conservatively. *** ## Credit Account Monitoring **WHY:** Users need to track their position health, collateral values, and accrued interest. ### Data Requirements | Display | SDK Source | Field | | ---------------- | ------------------- | ---------------------------- | | Account address | `CreditAccountData` | `addr` | | Owner | `CreditAccountData` | `owner` | | Total debt | `CreditAccountData` | `debt` | | Health factor | `CreditAccountData` | `healthFactor` (10000 = 1.0) | | Is liquidatable | `CreditAccountData` | `isLiquidatable` | | Token balances | `CreditAccountData` | `tokens[]` | | Token values | `tokens[]` | `balanceInUnderlying` | | Accrued interest | `CreditAccountData` | `cumulativeQuotaInterest` | | Quota fees | `CreditAccountData` | `quotaFees` | ### How to Fetch ```typescript import { createCreditAccountService } from '@gearbox-protocol/sdk'; const service = createCreditAccountService(sdk, 310); // Get user's accounts const accounts = await service.getCreditAccounts( { creditManager: cmAddress, owner: userAddress, }, sdk.currentBlock ); for (const account of accounts) { // Health factor: 10000 = 1.0 const hf = Number(account.healthFactor) / 10000; console.log(`Account: ${account.addr}`); console.log(`Health Factor: ${hf.toFixed(4)}`); console.log(`Liquidatable: ${account.isLiquidatable}`); // Debt breakdown console.log(`Total Debt: ${account.debt}`); console.log(`Accrued Interest: ${account.cumulativeQuotaInterest}`); console.log(`Quota Fees: ${account.quotaFees}`); // Token positions console.log('Positions:'); for (const token of account.tokens) { if (token.balance > 0n) { console.log(` ${token.symbol}:`); console.log(` Balance: ${token.balance}`); console.log(` Value (underlying): ${token.balanceInUnderlying}`); console.log(` LT: ${token.lt / 100}%`); } } } ``` ### Interest Breakdown Credit account debt consists of: * **Principal:** Original borrowed amount * **Base interest:** Accrues on principal based on pool utilization * **Quota interest:** Per-collateral rate for non-underlying tokens * **Quota fees:** Fixed fee component for quotas ```typescript // Total debt = principal + base interest + quota interest + quota fees const principal = account.borrowedAmount; const quotaInterest = account.cumulativeQuotaInterest; const quotaFees = account.quotaFees; const baseInterest = account.debt - principal - quotaInterest - quotaFees; ``` ### Health Factor Thresholds Display appropriate warnings based on health factor: ```typescript function getHealthStatus(hf: number): string { if (hf < 1.0) return 'LIQUIDATABLE'; if (hf < 1.05) return 'CRITICAL'; if (hf < 1.1) return 'WARNING'; return 'HEALTHY'; } const status = getHealthStatus(Number(account.healthFactor) / 10000); ``` *** ## Price Feed Information **WHY:** Users want to understand which oracles determine their collateral values. ### How to Fetch ```typescript import { priceFeedCompressorAbi, AP_PRICE_FEED_COMPRESSOR, VERSION_RANGE_310, } from '@gearbox-protocol/sdk'; // Get price feed compressor const [priceFeedCompressor] = sdk.addressProvider.mustGetLatest( AP_PRICE_FEED_COMPRESSOR, VERSION_RANGE_310 ); // Get all price feeds for a price oracle const feeds = await client.readContract({ address: priceFeedCompressor, abi: priceFeedCompressorAbi, functionName: 'getUpdatablePriceFeeds', args: [priceOracleAddress], }); for (const feed of feeds) { console.log(`Token: ${feed.token}`); console.log(` Feed: ${feed.priceFeed}`); console.log(` Needs Update: ${feed.needsUpdate}`); } ``` *** ## Position Management **WHY:** Users take actions on their positions (add collateral, borrow, repay, etc.). ### Linking to Operations Position management uses multicalls. Link to the appropriate operation guide: | User Action | Operation Guide | | ------------------ | ---------------------------------------------------------------------------------------------------------------------------- | | Deposit collateral | [Adding Collateral](https://docs.gearbox.finance/developers/adding-collateral) | | Borrow more | [Debt Management](https://docs.gearbox.finance/developers/debt-management) | | Repay debt | [Debt Management](https://docs.gearbox.finance/developers/debt-management) | | Update quota | [Updating Quotas](https://docs.gearbox.finance/developers/updating-quotas) | | Withdraw | [Withdrawing Collateral](https://docs.gearbox.finance/developers/withdrawing-collateral) | | Swap collateral | [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls) | ### Pre-Operation Data Checks Before letting users perform operations, validate: ```typescript // Before addCollateral: Check token is allowed const isAllowed = market.creditManagers[0].collateralTokens .some(t => t.address === tokenAddress); // Before increaseDebt: Check against max debt const newDebt = account.debt + borrowAmount; const isWithinLimit = newDebt <= cm.maxDebt; // Before updateQuota: Check quota capacity const quotaToken = marketData.quotaKeeper.tokens .find(t => t.token === tokenAddress); const hasCapacity = quotaToken && quotaToken.totalQuoted < quotaToken.limit; // Before any operation: Estimate health factor impact // (Use simulation or calculate locally) ``` *** ## Real-Time Updates **WHY:** UI needs to stay current as blockchain state changes. ### Option 1: Poll Compressors For most dashboards, polling every few seconds is sufficient: ```typescript const POLL_INTERVAL = 5000; // 5 seconds async function pollMarketData() { const marketData = await client.readContract({ address: compressor, abi: marketCompressorAbi, functionName: 'getMarketData', args: [poolAddress], }); // Update UI state setPoolData(marketData.pool); setQuotaData(marketData.quotaKeeper); } // Start polling setInterval(pollMarketData, POLL_INTERVAL); ``` ### Option 2: Watch Events For specific state changes, watch contract events: ```typescript import { parseAbiItem } from 'viem'; // Watch for credit account state changes const unwatch = client.watchContractEvent({ address: creditManagerAddress, abi: creditManagerAbi, eventName: 'ExecuteOrder', onLogs: (logs) => { // Refresh account data for affected accounts for (const log of logs) { refreshAccountData(log.args.creditAccount); } }, }); // Cleanup on unmount return () => unwatch(); ``` ### Recommendation Use **polling** for: * General market data * Pool state (rates, liquidity) * Quota utilization Use **events** for: * User's own account changes * Critical health factor alerts *** ## Complete Example: Dashboard Component ```typescript import { GearboxSDK, createCreditAccountService, marketCompressorAbi } from '@gearbox-protocol/sdk'; import { createPublicClient, http } from 'viem'; import { mainnet } from 'viem/chains'; interface DashboardData { pool: { underlying: string; totalAssets: bigint; availableLiquidity: bigint; supplyAPY: number; borrowAPR: number; }; userAccounts: Array<{ address: string; healthFactor: number; debt: bigint; isLiquidatable: boolean; }>; } async function fetchDashboardData( poolAddress: `0x${string}`, cmAddress: `0x${string}`, userAddress: `0x${string}` ): Promise { const client = createPublicClient({ chain: mainnet, transport: http(), }); const sdk = await GearboxSDK.attach({ client, marketConfigurators: [], }); const RAY = 10n ** 27n; // Pool data const market = sdk.marketRegister.findByPool(poolAddress); const pool = market.pool; // User accounts const service = createCreditAccountService(sdk, 310); const accounts = await service.getCreditAccounts( { creditManager: cmAddress, owner: userAddress }, sdk.currentBlock ); return { pool: { underlying: pool.underlying.symbol, totalAssets: pool.totalAssets, availableLiquidity: pool.availableLiquidity, supplyAPY: Number(pool.supplyRate * 10000n / RAY) / 100, borrowAPR: Number(pool.baseInterestRate * 10000n / RAY) / 100, }, userAccounts: accounts.map(a => ({ address: a.addr, healthFactor: Number(a.healthFactor) / 10000, debt: a.debt, isLiquidatable: a.isLiquidatable, })), }; } ``` *** ## Next Steps * [Multicall Operations](https://docs.gearbox.finance/developers/multicalls) - Implement position management * [Backend Services](https://docs.gearbox.finance/developers/backend-services) - If you also need historical data * [Compressors Reference](https://docs.gearbox.finance/developers/compressors) - Complete compressor API ## Backend Services Source: https://docs.gearbox.finance/developers/backend-services File: content/developers/backend-services.mdx Build indexers, analytics pipelines, and data warehouses that track Gearbox protocol state over time. ## Overview Backend services typically need to: 1. Capture historical snapshots at specific blocks 2. Index events for efficient state reconstruction 3. Track rates, values, and utilization over time 4. Store and query historical data This guide shows patterns for each requirement. *** ## Historical Snapshots **WHY:** Track how protocol state changes over time for analytics, reporting, and historical queries. ### What to Snapshot | Data | Source | Change Frequency | | -------------------- | ------------------- | ------------------------- | | Pool rates | `PoolState` | Every block with activity | | Pool liquidity | `PoolState` | Every deposit/borrow | | Quota utilization | `QuotaKeeperState` | Every position change | | Credit account state | `CreditAccountData` | Every account operation | | Token prices | `PriceOracle` | External feed updates | ### How to Query at Specific Blocks Compressors support querying at historical blocks using viem's `blockTag` or `blockNumber`: ```typescript import { marketCompressorAbi, AP_MARKET_COMPRESSOR, VERSION_RANGE_310, } from '@gearbox-protocol/sdk'; const [compressor] = sdk.addressProvider.mustGetLatest( AP_MARKET_COMPRESSOR, VERSION_RANGE_310 ); // Query at specific block const historicalData = await client.readContract({ address: compressor, abi: marketCompressorAbi, functionName: 'getMarketData', args: [poolAddress], blockNumber: 19000000n, // Specific block }); console.log(`Pool state at block 19000000:`); console.log(` Available liquidity: ${historicalData.pool.availableLiquidity}`); console.log(` Supply rate: ${historicalData.pool.supplyRate}`); ``` ### Archive Node Requirements Historical queries require an archive node. Standard nodes only keep recent state (\~128 blocks). **RPC providers with archive access:** * Alchemy (archive add-on) * Infura (archive add-on) * QuickNode (archive plans) * Self-hosted Erigon/Reth ### Snapshot Pattern ```typescript interface PoolSnapshot { blockNumber: bigint; timestamp: number; availableLiquidity: bigint; totalAssets: bigint; supplyRate: bigint; borrowRate: bigint; } async function capturePoolSnapshot( blockNumber: bigint ): Promise { const block = await client.getBlock({ blockNumber }); const marketData = await client.readContract({ address: compressor, abi: marketCompressorAbi, functionName: 'getMarketData', args: [poolAddress], blockNumber, }); return { blockNumber, timestamp: Number(block.timestamp), availableLiquidity: marketData.pool.availableLiquidity, totalAssets: marketData.pool.totalAssets, supplyRate: marketData.pool.supplyRate, borrowRate: marketData.pool.baseInterestRate, }; } // Capture hourly snapshots const BLOCKS_PER_HOUR = 300n; // ~12 second blocks let currentBlock = startBlock; while (currentBlock <= endBlock) { const snapshot = await capturePoolSnapshot(currentBlock); await saveToDatabase(snapshot); currentBlock += BLOCKS_PER_HOUR; } ``` *** ## Event Indexing **WHY:** Events provide efficient tracking of specific state changes without polling. ### Key Events Credit Facade emits events for all account operations: | Event | When Emitted | Key Data | | ------------------------ | ------------------ | ----------------------------------------- | | `OpenCreditAccount` | Account opened | owner, creditAccount, borrowAmount | | `CloseCreditAccount` | Account closed | creditAccount | | `LiquidateCreditAccount` | Account liquidated | creditAccount, liquidator, remainingFunds | | `StartMultiCall` | Multicall begins | creditAccount | | `FinishMultiCall` | Multicall ends | creditAccount | Pool emits events for liquidity changes: | Event | When Emitted | Key Data | | ---------- | ---------------------- | ----------------------------------- | | `Deposit` | LP deposits | sender, owner, assets, shares | | `Withdraw` | LP withdraws | sender, receiver, assets, shares | | `Borrow` | Credit Manager borrows | creditAccount, amount | | `Repay` | Debt repaid | creditAccount, amount, profit, loss | ### Watching Events with viem ```typescript import { parseAbiItem } from 'viem'; // Watch for new credit accounts const unwatchOpen = client.watchContractEvent({ address: creditFacadeAddress, abi: creditFacadeAbi, eventName: 'OpenCreditAccount', onLogs: async (logs) => { for (const log of logs) { console.log(`New account: ${log.args.creditAccount}`); console.log(` Owner: ${log.args.owner}`); console.log(` Initial debt: ${log.args.borrowAmount}`); await indexCreditAccount(log); } }, }); // Watch for liquidations const unwatchLiquidate = client.watchContractEvent({ address: creditFacadeAddress, abi: creditFacadeAbi, eventName: 'LiquidateCreditAccount', onLogs: async (logs) => { for (const log of logs) { console.log(`Liquidated: ${log.args.creditAccount}`); console.log(` Liquidator: ${log.args.liquidator}`); await recordLiquidation(log); } }, }); ``` ### Fetching Historical Events For backfilling, fetch events in block ranges: ```typescript async function fetchHistoricalEvents( fromBlock: bigint, toBlock: bigint ) { // Fetch in chunks to avoid RPC limits const CHUNK_SIZE = 10000n; let current = fromBlock; while (current <= toBlock) { const chunkEnd = current + CHUNK_SIZE > toBlock ? toBlock : current + CHUNK_SIZE; const logs = await client.getContractEvents({ address: creditFacadeAddress, abi: creditFacadeAbi, eventName: 'OpenCreditAccount', fromBlock: current, toBlock: chunkEnd, }); for (const log of logs) { await processEvent(log); } current = chunkEnd + 1n; } } ``` *** ## State Tracking **WHY:** Build complete account or pool history over time by combining events and snapshots. ### Credit Account Lifecycle Track an account from open to close: ```typescript interface AccountHistory { creditAccount: string; owner: string; openBlock: bigint; closeBlock: bigint | null; operations: AccountOperation[]; } interface AccountOperation { blockNumber: bigint; txHash: string; type: 'open' | 'multicall' | 'liquidate' | 'close'; healthFactorAfter?: bigint; } async function trackAccountLifecycle(creditAccount: string): Promise { // Find open event const openEvents = await client.getContractEvents({ address: creditFacadeAddress, abi: creditFacadeAbi, eventName: 'OpenCreditAccount', args: { creditAccount }, fromBlock: 0n, toBlock: 'latest', }); const openEvent = openEvents[0]; // Find all multicall events const multicallEvents = await client.getContractEvents({ address: creditFacadeAddress, abi: creditFacadeAbi, eventName: 'FinishMultiCall', args: { creditAccount }, fromBlock: openEvent.blockNumber, toBlock: 'latest', }); // Find close event (if any) const closeEvents = await client.getContractEvents({ address: creditFacadeAddress, abi: creditFacadeAbi, eventName: 'CloseCreditAccount', args: { creditAccount }, fromBlock: openEvent.blockNumber, toBlock: 'latest', }); return { creditAccount, owner: openEvent.args.owner, openBlock: openEvent.blockNumber, closeBlock: closeEvents[0]?.blockNumber ?? null, operations: [ { blockNumber: openEvent.blockNumber, txHash: openEvent.transactionHash, type: 'open' }, ...multicallEvents.map(e => ({ blockNumber: e.blockNumber, txHash: e.transactionHash, type: 'multicall' as const, })), ...(closeEvents[0] ? [{ blockNumber: closeEvents[0].blockNumber, txHash: closeEvents[0].transactionHash, type: 'close' as const, }] : []), ].sort((a, b) => Number(a.blockNumber - b.blockNumber)), }; } ``` ### Combining Events and Snapshots For complete state reconstruction: ```typescript async function reconstructAccountStateAtBlock( creditAccount: string, targetBlock: bigint ): Promise { // Check if account existed at this block const history = await trackAccountLifecycle(creditAccount); if (history.openBlock > targetBlock) { return null; // Account didn't exist yet } if (history.closeBlock && history.closeBlock <= targetBlock) { return null; // Account was closed } // Query compressor at target block const [accountData] = await client.readContract({ address: accountCompressor, abi: creditAccountCompressorAbi, functionName: 'getCreditAccountData', args: [creditManagerAddress, creditAccount], blockNumber: targetBlock, }); return accountData; } ``` *** ## Rate History **WHY:** Analytics on yield, utilization trends, and rate changes over time. ### Rates to Track | Rate | Source | Notes | | --------------- | --------------------------- | -------------------------------------------------- | | Supply APY | `pool.supplyRate` | RAY scaled (10^27) | | Base borrow APR | `pool.baseInterestRate` | RAY scaled | | Quota rates | `quotaKeeper.tokens[].rate` | Per-token, RAY scaled | | Utilization | Calculated | `(totalAssets - availableLiquidity) / totalAssets` | ### Polling Pattern ```typescript interface RateSnapshot { blockNumber: bigint; timestamp: number; supplyRate: bigint; borrowRate: bigint; utilization: number; quotaRates: Map; } async function pollRates(): Promise { const block = await client.getBlock({ blockTag: 'latest' }); const marketData = await client.readContract({ address: compressor, abi: marketCompressorAbi, functionName: 'getMarketData', args: [poolAddress], }); const pool = marketData.pool; const borrowed = pool.totalAssets - pool.availableLiquidity; const utilization = pool.totalAssets > 0n ? Number(borrowed * 10000n / pool.totalAssets) / 100 : 0; const quotaRates = new Map(); for (const token of marketData.quotaKeeper.tokens) { quotaRates.set(token.token, token.rate); } return { blockNumber: block.number, timestamp: Number(block.timestamp), supplyRate: pool.supplyRate, borrowRate: pool.baseInterestRate, utilization, quotaRates, }; } // Poll every minute setInterval(async () => { const snapshot = await pollRates(); await saveRateSnapshot(snapshot); }, 60_000); ``` ### Rate Conversion Convert RAY-scaled rates to annual percentages: ```typescript const RAY = 10n ** 27n; function rayToAnnualPercent(rayRate: bigint): number { // rate is per-second, annualize it const SECONDS_PER_YEAR = 365n * 24n * 60n * 60n; const annualRate = rayRate * SECONDS_PER_YEAR; return Number(annualRate * 10000n / RAY) / 100; } const supplyAPY = rayToAnnualPercent(pool.supplyRate); console.log(`Supply APY: ${supplyAPY.toFixed(2)}%`); ``` *** ## Complete Example: Simple Indexer ```typescript import { createPublicClient, http } from 'viem'; import { mainnet } from 'viem/chains'; import { GearboxSDK, marketCompressorAbi, creditAccountCompressorAbi, AP_MARKET_COMPRESSOR, VERSION_RANGE_310, } from '@gearbox-protocol/sdk'; interface IndexerState { lastIndexedBlock: bigint; pools: Map; accounts: Map; } async function runIndexer( startBlock: bigint, poolAddress: `0x${string}`, creditManagerAddress: `0x${string}` ) { const client = createPublicClient({ chain: mainnet, transport: http(process.env.ARCHIVE_RPC_URL), }); const sdk = await GearboxSDK.attach({ client, marketConfigurators: [], }); const [marketCompressor] = sdk.addressProvider.mustGetLatest( AP_MARKET_COMPRESSOR, VERSION_RANGE_310 ); let currentBlock = startBlock; while (true) { const latestBlock = await client.getBlockNumber(); while (currentBlock <= latestBlock) { // Snapshot pool state const marketData = await client.readContract({ address: marketCompressor, abi: marketCompressorAbi, functionName: 'getMarketData', args: [poolAddress], blockNumber: currentBlock, }); await savePoolSnapshot(currentBlock, marketData.pool); // Index events in this block range const events = await client.getContractEvents({ address: creditManagerAddress, abi: creditFacadeAbi, fromBlock: currentBlock, toBlock: currentBlock + 100n, }); for (const event of events) { await processEvent(event); } currentBlock += 100n; } // Wait for new blocks await sleep(12_000); } } function sleep(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)); } ``` *** ## Next Steps * [Liquidation Bots](https://docs.gearbox.finance/developers/liquidation-bots) - If you need to act on indexed data * [Compressors Reference](https://docs.gearbox.finance/developers/compressors) - Complete compressor API * [Frontend Applications](https://docs.gearbox.finance/developers/frontend-applications) - If you also need real-time display ## Debt Management Source: https://docs.gearbox.finance/developers/gm-mc-debt File: content/developers/gm-mc-debt.mdx Borrow from or repay to the pool. Debt operations directly affect your credit account's health factor. ## Why You manage debt when: * **Increasing leverage** - Borrow more to amplify exposure * **Taking profit** - Repay debt while keeping collateral positions * **Reducing risk** - Lower debt to improve health factor * **Closing account** - Repay all debt before withdrawal ## What ### Increase Debt `increaseDebt` borrows the underlying asset from the pool to your Credit Account: 1. Pool transfers underlying to Credit Account 2. Debt parameters (principal + interest) are recalculated 3. Health factor decreases ### Decrease Debt `decreaseDebt` repays debt from Credit Account's underlying balance: 1. Underlying is transferred from Credit Account to pool 2. Debt parameters are recalculated 3. Health factor increases **Repayment order** (when not paying full debt): 1. Quota-related fees (quota increase fees) 2. Accrued quota interest 3. Interest + interest fee (split pro-rata if partial) 4. Principal This means partial payments may not reduce your principal at all. ## How ### Borrow More ```typescript import { GearboxSDK, createCreditAccountService } from '@gearbox-protocol/sdk'; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); const service = createCreditAccountService(sdk, 310); const market = sdk.marketRegister.findByCreditManager(cmAddress); const calls = [ service.prepareIncreaseDebt(40_000n * 10n ** 6n), // Borrow 40,000 USDC ]; await market.creditFacade.write.multicall([creditAccountAddress, calls]); ``` ### Repay Debt ```typescript const calls = [ service.prepareDecreaseDebt(10_000n * 10n ** 6n), // Repay 10,000 USDC ]; await market.creditFacade.write.multicall([creditAccountAddress, calls]); ``` ### Repay All Debt Pass `type(uint256).max` equivalent to repay everything: ```typescript const MAX_UINT256 = 2n ** 256n - 1n; const calls = [ // Zero all quotas FIRST (required before full repayment) service.prepareUpdateQuota(quotedToken1, BigInt.asIntN(96, -1n * 2n ** 95n), 0n), service.prepareUpdateQuota(quotedToken2, BigInt.asIntN(96, -1n * 2n ** 95n), 0n), // Then repay all debt service.prepareDecreaseDebt(MAX_UINT256), ]; await market.creditFacade.write.multicall([creditAccountAddress, calls]); ``` ### Common Pattern: Add Collateral + Borrow ```typescript const calls = [ // First add collateral service.prepareAddCollateral(usdcAddress, 10_000n * 10n ** 6n), // Then borrow (5x leverage) service.prepareIncreaseDebt(40_000n * 10n ** 6n), // Set quota for destination token service.prepareUpdateQuota(wethAddress, 50_000n * 10n ** 6n, 50_000n * 10n ** 6n), ]; // Don't forget approval to Credit Manager! await usdcContract.write.approve([market.creditManager.address, 10_000n * 10n ** 6n]); await market.creditFacade.write.openCreditAccount([ownerAddress, calls, 0n]); ``` ## Gotchas ### One Debt Update Per Block You cannot increase AND decrease debt in the same block. This constraint prevents manipulation: ```typescript // WRONG - will revert on second operation const calls = [ service.prepareIncreaseDebt(amount1), service.prepareDecreaseDebt(amount2), // Reverts! ]; // CORRECT - one multicall, one debt operation const calls = [ service.prepareIncreaseDebt(netAmount), ]; ``` ### Zero All Quotas Before Full Repayment Non-zero quotas with zero debt is an invalid state. Zero your quotas BEFORE the final debt repayment: ```typescript const INT96_MIN = BigInt.asIntN(96, -1n * 2n ** 95n); const calls = [ // Zero quotas first service.prepareUpdateQuota(token1, INT96_MIN, 0n), service.prepareUpdateQuota(token2, INT96_MIN, 0n), // Then full repayment service.prepareDecreaseDebt(MAX_UINT256), ]; ``` ### Debt Must Stay in Range After any debt change, the principal must be either: * Zero (fully repaid), OR * Within `[minDebt, maxDebt]` range You cannot have debt between 0 and `minDebt`. ### Forbidden Tokens Block Borrowing If your account has forbidden tokens enabled as collateral, you cannot increase debt. Disable them first. ### Interest Accrues Continuously When repaying "the full amount", the debt may have grown since you read it. Add a buffer: ```typescript // Read current total debt const accountData = await service.getCreditAccountData(creditAccountAddress); const totalDebt = accountData.debt; // Add 0.1% buffer for interest accrual const repayAmount = totalDebt + (totalDebt / 1000n); // Or just use MAX_UINT256 to repay whatever the current amount is const calls = [service.prepareDecreaseDebt(MAX_UINT256)]; ``` ### Cannot Decrease on Open / Increase on Close * `decreaseDebt` is prohibited when opening an account * `increaseDebt` is prohibited when closing an account ## Learn More * [Updating Quotas](https://docs.gearbox.finance/developers/gm-mc-quotas) - Quota interest affects total debt * [Adding Collateral](https://docs.gearbox.finance/developers/gm-mc-collateral) - Often combined with borrowing * [Withdrawing Collateral](https://docs.gearbox.finance/developers/gm-mc-withdraw) - Often combined with repaying ## Liquidation Bots Source: https://docs.gearbox.finance/developers/liquidation-bots File: content/developers/liquidation-bots.mdx Build bots that monitor credit accounts and execute profitable liquidations. ## Overview Liquidation bots need to: 1. Find accounts with low health factors 2. Filter for liquidatable accounts 3. Compute optimal liquidation paths 4. Execute liquidations profitably This guide covers each step with verified SDK patterns. *** ## Understanding Liquidation **WHY:** Know what you're building before writing code. ### When Accounts Become Liquidatable An account becomes liquidatable when its health factor drops below 1.0: ``` Health Factor = Total Weighted Collateral Value / Total Debt Where: - Weighted Value = Sum of (Token Balance * Price * Liquidation Threshold) - Total Debt = Principal + Accrued Interest + Quota Fees ``` Health factor is scaled by 10000, so `healthFactor < 10000` means liquidatable. ### The Liquidation Process 1. **Liquidator calls** `creditFacade.liquidateCreditAccount()` 2. **Protocol converts** collateral to underlying token 3. **Debt is repaid** from converted collateral 4. **Liquidator receives** premium (configured per Credit Manager) 5. **Remaining funds** go to account owner (if any) The liquidator provides the multicall that handles collateral conversion. This is where profit comes from - efficient routing means better conversion rates. *** ## Finding Liquidatable Accounts **WHY:** Efficiently scan all accounts to find opportunities. ### Using CreditAccountCompressor The `CreditAccountCompressor` has built-in health factor filtering: ```typescript import { creditAccountCompressorAbi, AP_CREDIT_ACCOUNT_COMPRESSOR, VERSION_RANGE_310, } from '@gearbox-protocol/sdk'; const [accountCompressor] = sdk.addressProvider.mustGetLatest( AP_CREDIT_ACCOUNT_COMPRESSOR, VERSION_RANGE_310 ); // Find accounts with HF < 1.0 (10000 in basis points) const [accounts, total] = await client.readContract({ address: accountCompressor, abi: creditAccountCompressorAbi, functionName: 'getCreditAccounts', args: [ creditManagerAddress, { owner: '0x0000000000000000000000000000000000000000', // Any owner minHealthFactor: 0n, maxHealthFactor: 10000n, // HF < 1.0 includeZeroDebt: false, reverting: false, }, 0n, // offset ], }); console.log(`Found ${accounts.length} accounts with HF < 1.0`); ``` ### Filter by isLiquidatable The `isLiquidatable` field accounts for additional protocol checks: ```typescript const liquidatable = accounts.filter(a => a.isLiquidatable); console.log(`${liquidatable.length} are actually liquidatable`); for (const account of liquidatable) { console.log(`Account: ${account.addr}`); console.log(` Health Factor: ${Number(account.healthFactor) / 10000}`); console.log(` Debt: ${account.debt}`); console.log(` Collaterals:`); for (const token of account.tokens) { if (token.balance > 0n) { console.log(` ${token.symbol}: ${token.balance}`); } } } ``` ### Pagination for Large Result Sets The compressor returns paginated results. Iterate through all pages: ```typescript async function getAllLiquidatableAccounts( creditManager: `0x${string}` ): Promise { const filter = { owner: '0x0000000000000000000000000000000000000000' as const, minHealthFactor: 0n, maxHealthFactor: 10000n, includeZeroDebt: false, reverting: false, }; let offset = 0n; let allAccounts: CreditAccountData[] = []; while (true) { const [accounts, total] = await client.readContract({ address: accountCompressor, abi: creditAccountCompressorAbi, functionName: 'getCreditAccounts', args: [creditManager, filter, offset], }); const liquidatable = accounts.filter(a => a.isLiquidatable); allAccounts.push(...liquidatable); offset += BigInt(accounts.length); if (offset >= total) break; } return allAccounts; } ``` *** ## Account Analysis **WHY:** Understand an account's composition before liquidating. ### Collateral Breakdown ```typescript interface CollateralPosition { token: string; symbol: string; balance: bigint; valueInUnderlying: bigint; liquidationThreshold: number; } function analyzeCollateral(account: CreditAccountData): CollateralPosition[] { return account.tokens .filter(t => t.balance > 0n) .map(t => ({ token: t.token, symbol: t.symbol, balance: t.balance, valueInUnderlying: t.balanceInUnderlying, liquidationThreshold: Number(t.lt) / 100, })) .sort((a, b) => Number(b.valueInUnderlying - a.valueInUnderlying)); } const positions = analyzeCollateral(account); console.log('Collateral by value:'); for (const pos of positions) { console.log(` ${pos.symbol}: ${pos.valueInUnderlying} (LT: ${pos.liquidationThreshold}%)`); } ``` ### Estimating Profit ```typescript interface LiquidationEstimate { totalCollateralValue: bigint; debt: bigint; liquidationPremium: bigint; estimatedProfit: bigint; } function estimateLiquidation( account: CreditAccountData, premiumBps: number // e.g., 400 = 4% ): LiquidationEstimate { const totalValue = account.tokens.reduce( (sum, t) => sum + t.balanceInUnderlying, 0n ); const premium = totalValue * BigInt(premiumBps) / 10000n; // Simplified: assumes perfect conversion const estimatedProfit = totalValue - account.debt; return { totalCollateralValue: totalValue, debt: account.debt, liquidationPremium: premium, estimatedProfit: estimatedProfit > 0n ? estimatedProfit : 0n, }; } ``` *** ## Building the Liquidation Multicall **WHY:** The multicall handles collateral conversion and determines profit. ### Basic Structure A liquidation multicall typically: 1. Updates stale price feeds (if needed) 2. Swaps collateral tokens to underlying 3. Repays debt (handled by protocol) ```typescript import { encodeFunctionData } from 'viem'; import { iCreditFacadeV300MulticallAbi } from '@gearbox-protocol/sdk'; // Build liquidation multicall const calls: Array<{ target: `0x${string}`; callData: `0x${string}` }> = []; // 1. Update any stale price feeds first for (const feed of stalePriceFeeds) { calls.push({ target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'onDemandPriceUpdate', args: [feed.token, feed.reserve, feed.data], }), }); } // 2. Swap collateral to underlying via adapters for (const collateral of collateralToSwap) { const adapter = await creditManager.read.contractToAdapter([ collateral.protocol, ]); calls.push({ target: adapter, callData: encodeFunctionData({ abi: adapterAbi, functionName: 'swap', args: [collateral.swapParams], }), }); } ``` ### Using Slippage Protection Always protect against sandwich attacks: ```typescript // Store expected minimum output calls.push({ target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'storeExpectedBalances', args: [[{ token: underlyingToken, amount: minExpectedOutput }]], }), }); // Perform swap calls.push({ target: adapter, callData: encodeFunctionData({ abi: adapterAbi, functionName: 'swap', args: [swapParams], }), }); // Verify slippage calls.push({ target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'compareBalances', args: [], }), }); ``` See [Controlling Slippage](https://docs.gearbox.finance/developers/controlling-slippage) for details. *** ## Executing Liquidation **WHY:** Actually perform the liquidation and capture profit. ### The liquidateCreditAccount Call ```typescript // Get credit facade for the account's credit manager const market = sdk.marketRegister.findByCreditManager(account.creditManager); // Execute liquidation const hash = await walletClient.writeContract({ address: market.creditFacade.address, abi: creditFacadeAbi, functionName: 'liquidateCreditAccount', args: [ account.addr, // Credit account to liquidate receiverAddress, // Where to send remaining funds calls, // Liquidation multicall ], }); console.log(`Liquidation submitted: ${hash}`); // Wait for confirmation const receipt = await client.waitForTransactionReceipt({ hash }); console.log(`Liquidation ${receipt.status === 'success' ? 'succeeded' : 'failed'}`); ``` ### Handling Partial Liquidation In some configurations, partial liquidation is possible. Check the Credit Manager configuration: ```typescript // Full liquidation only if account is deeply underwater // Partial liquidation may be allowed above certain HF threshold ``` *** ## Bot Architecture **WHY:** Production bots need proper design for reliability and competitiveness. ### Monitoring Loop ```typescript async function monitoringLoop() { const POLL_INTERVAL = 3000; // 3 seconds while (true) { try { // Scan all credit managers for (const cm of creditManagers) { const accounts = await getAllLiquidatableAccounts(cm); for (const account of accounts) { // Analyze opportunity const estimate = estimateLiquidation(account, liquidationPremiumBps); if (estimate.estimatedProfit > minProfitThreshold) { await attemptLiquidation(account); } } } } catch (error) { console.error('Monitoring error:', error); } await sleep(POLL_INTERVAL); } } ``` ### Simulation Before Execution Always simulate before sending transactions: ```typescript async function attemptLiquidation(account: CreditAccountData) { const calls = buildLiquidationMulticall(account); // Simulate first try { await client.simulateContract({ address: creditFacadeAddress, abi: creditFacadeAbi, functionName: 'liquidateCreditAccount', args: [account.addr, receiverAddress, calls], account: liquidatorAddress, }); } catch (error) { console.log(`Simulation failed for ${account.addr}:`, error); return; } // Simulation passed, execute try { const hash = await walletClient.writeContract({ address: creditFacadeAddress, abi: creditFacadeAbi, functionName: 'liquidateCreditAccount', args: [account.addr, receiverAddress, calls], }); console.log(`Liquidation tx: ${hash}`); } catch (error) { console.error(`Execution failed:`, error); } } ``` ### Competition Considerations Liquidation is competitive. Other bots are scanning the same accounts. **Strategies:** * **Speed:** Use faster RPC endpoints, optimize code paths * **Gas:** Pay higher gas for priority (use `maxPriorityFeePerGas`) * **Efficiency:** Better swap routing means higher profit, can afford more gas * **Flashbots:** Use MEV-protected submission to avoid frontrunning ```typescript // Higher priority fee for competitive liquidations const hash = await walletClient.writeContract({ address: creditFacadeAddress, abi: creditFacadeAbi, functionName: 'liquidateCreditAccount', args: [account.addr, receiverAddress, calls], maxPriorityFeePerGas: parseGwei('3'), // Higher tip }); ``` *** ## Complete Example: Simple Liquidation Bot ```typescript import { createPublicClient, createWalletClient, http, parseGwei } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; import { mainnet } from 'viem/chains'; import { GearboxSDK, creditAccountCompressorAbi, AP_CREDIT_ACCOUNT_COMPRESSOR, VERSION_RANGE_310, } from '@gearbox-protocol/sdk'; const MIN_PROFIT_USD = 100n * 10n ** 6n; // $100 minimum profit async function runLiquidationBot(creditManagerAddress: `0x${string}`) { const client = createPublicClient({ chain: mainnet, transport: http(), }); const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`); const walletClient = createWalletClient({ account, chain: mainnet, transport: http(), }); const sdk = await GearboxSDK.attach({ client, marketConfigurators: [], }); const [accountCompressor] = sdk.addressProvider.mustGetLatest( AP_CREDIT_ACCOUNT_COMPRESSOR, VERSION_RANGE_310 ); const market = sdk.marketRegister.findByCreditManager(creditManagerAddress); console.log(`Monitoring ${market.creditManagers[0].address}`); console.log(`Liquidator: ${account.address}`); while (true) { try { // Find liquidatable accounts const [accounts] = await client.readContract({ address: accountCompressor, abi: creditAccountCompressorAbi, functionName: 'getCreditAccounts', args: [ creditManagerAddress, { owner: '0x0000000000000000000000000000000000000000', minHealthFactor: 0n, maxHealthFactor: 10000n, includeZeroDebt: false, reverting: false, }, 0n, ], }); const liquidatable = accounts.filter(a => a.isLiquidatable); if (liquidatable.length > 0) { console.log(`Found ${liquidatable.length} liquidatable accounts`); for (const target of liquidatable) { const totalValue = target.tokens.reduce( (sum, t) => sum + t.balanceInUnderlying, 0n ); const estimatedProfit = totalValue - target.debt; if (estimatedProfit > MIN_PROFIT_USD) { console.log(`Profitable opportunity: ${target.addr}`); console.log(` Debt: ${target.debt}`); console.log(` Value: ${totalValue}`); console.log(` Est. Profit: ${estimatedProfit}`); // Build and execute liquidation // (simplified - real bot would compute optimal swaps) const calls = buildLiquidationCalls(target, market); try { // Simulate await client.simulateContract({ address: market.creditFacade.address, abi: creditFacadeAbi, functionName: 'liquidateCreditAccount', args: [target.addr, account.address, calls], account: account.address, }); // Execute const hash = await walletClient.writeContract({ address: market.creditFacade.address, abi: creditFacadeAbi, functionName: 'liquidateCreditAccount', args: [target.addr, account.address, calls], maxPriorityFeePerGas: parseGwei('2'), }); console.log(`Liquidation submitted: ${hash}`); } catch (error) { console.log(`Failed to liquidate ${target.addr}:`, error); } } } } } catch (error) { console.error('Loop error:', error); } // Poll every 3 seconds await new Promise(resolve => setTimeout(resolve, 3000)); } } function buildLiquidationCalls( account: CreditAccountData, market: MarketData ): Array<{ target: `0x${string}`; callData: `0x${string}` }> { const calls: Array<{ target: `0x${string}`; callData: `0x${string}` }> = []; const creditFacade = market.creditFacade.address; const underlying = market.pool.underlying.address; // 1. Swap each non-underlying collateral token to underlying via adapter for (const token of account.tokens) { if (token.balance <= 1n) continue; // skip dust if (token.token === underlying) continue; // skip underlying itself // Use Uniswap V3 adapter for swaps (simplified: hardcoded router) const uniswapAdapter = market.adapters?.['UNISWAP_V3_ROUTER']; if (!uniswapAdapter) continue; // exactAllInputSingle swaps entire balance minus 1 wei calls.push({ target: uniswapAdapter, callData: encodeFunctionData({ abi: uniswapV3AdapterAbi, functionName: 'exactAllInputSingle', args: [{ tokenIn: token.token, tokenOut: underlying, fee: 3000, // 0.3% pool (use 500 for stablecoin pairs) deadline: BigInt(Math.floor(Date.now() / 1000) + 3600), rateMinRAY: 0n, // No slippage protection (simplified) sqrtPriceLimitX96: 0n, }], }), }); } return calls; } ``` *** ## Gotchas ### Price Updates Must Come First If any price feeds are stale, update them at the start of your multicall: ```typescript // WRONG: Swap first, then update prices (will fail) // CORRECT: Update prices first, then swap const calls = [ ...priceUpdateCalls, ...swapCalls, ]; ``` See [Updating Price Feeds](https://docs.gearbox.finance/developers/updating-price-feeds). ### Account State Can Change Between scanning and executing, another bot may liquidate the account: ```typescript try { await walletClient.writeContract({ ... }); } catch (error) { if (error.message.includes('account not liquidatable')) { console.log('Account already liquidated by another bot'); } } ``` ### Gas Estimation Liquidation gas costs vary based on: * Number of collateral tokens * Complexity of swaps * Price feed updates needed Always estimate gas before calculating profitability. *** ## Next Steps * [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls) - Swap patterns via adapters * [Controlling Slippage](https://docs.gearbox.finance/developers/controlling-slippage) - Protect against MEV * [Updating Price Feeds](https://docs.gearbox.finance/developers/updating-price-feeds) - Required for stale oracles * [Compressors Reference](https://docs.gearbox.finance/developers/compressors) - Complete filter options ## Updating Quotas Source: https://docs.gearbox.finance/developers/gm-mc-quotas File: content/developers/gm-mc-quotas.mdx Enable or adjust exposure to quota-based collateral tokens. Without a quota, even holding a quota token contributes zero to your health factor. ## Why You update quotas when: * **Enabling a quota token** - Required before that token counts as collateral * **Increasing exposure** - Need more of a token to count toward health factor * **Reducing exposure** - Lower quota to reduce quota interest costs * **Closing positions** - Zero quotas before full debt repayment ## What `updateQuota` changes your quota for a specific token: 1. If increasing from zero, the token is enabled as collateral 2. If decreasing to zero, the token is disabled as collateral 3. Quota increase may be limited by global capacity (per-pool limits) 4. Quota interest accrues based on your quota amount **Key parameters:** | Parameter | Type | Description | | ------------- | -------- | --------------------------------------------------- | | `token` | `address`| The quota token address | | `quotaChange` | `int96` | Delta to apply (positive = increase, negative = decrease) | | `minQuota` | `uint96` | Minimum acceptable resulting quota (prevents partial fills) | The `minQuota` parameter protects you: if the pool can only give you 80% of your requested quota, and you set `minQuota` to 100% of your request, the transaction reverts instead of accepting partial quota. ## How ```typescript import { GearboxSDK, createCreditAccountService } from '@gearbox-protocol/sdk'; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); const service = createCreditAccountService(sdk, 310); const market = sdk.marketRegister.findByCreditManager(cmAddress); // Request 50,000 USDC worth of quota const quotaAmount = 50_000n * 10n ** 6n; const calls = [ service.prepareUpdateQuota(wethAddress, quotaAmount, quotaAmount), ]; await market.creditFacade.write.multicall([creditAccountAddress, calls]); ``` ### Decrease Quota ```typescript // Decrease quota by 20,000 (negative change) const decrease = -20_000n * 10n ** 6n; const calls = [ service.prepareUpdateQuota(wethAddress, decrease, 0n), ]; ``` ### Zero Quota Entirely Pass `type(int96).min` to disable quota completely: ```typescript // int96 minimum value const INT96_MIN = BigInt.asIntN(96, -1n * 2n ** 95n); const calls = [ service.prepareUpdateQuota(wethAddress, INT96_MIN, 0n), ]; ``` ### Common Pattern: Enable Quota After Swap After swapping into a quota token, you need to enable quota for it to count: ```typescript const calls = [ // Swap USDC to WETH via adapter { target: uniswapV3Adapter, callData: encodeFunctionData({ abi: uniswapV3AdapterAbi, functionName: 'exactInputSingle', args: [swapParams], }), }, // Enable quota for the received WETH service.prepareUpdateQuota(wethAddress, quotaAmount, quotaAmount), ]; ``` ## Gotchas ### Check Quota Limits Before Requesting Each quota token has a pool-wide limit. If the limit is reached, your request fails (or gets partial fill): ```typescript // Check available quota capacity const quotaKeeper = market.quotaKeeper; const quotaInfo = await quotaKeeper.read.getQuotaInfo([wethAddress]); const available = quotaInfo.limit - quotaInfo.totalQuoted; if (requested > available) { console.log(`Only ${available} quota available, requested ${requested}`); } ``` ### minQuota Prevents Partial Fills If you need exactly 100 units of quota: ```typescript // SAFE - reverts if less than 100 available service.prepareUpdateQuota(token, 100n, 100n); // RISKY - accepts partial fill service.prepareUpdateQuota(token, 100n, 0n); ``` ### Per-Account Quota Maximum Each account has an implicit max quota of `8 * maxDebt` per asset. You cannot exceed this even if pool capacity exists. ### Zero Quotas Before Zero Debt You cannot have active quotas with zero debt. When closing an account: ```typescript const INT96_MIN = BigInt.asIntN(96, -1n * 2n ** 95n); const MAX_UINT256 = 2n ** 256n - 1n; const calls = [ // Zero ALL quotas first service.prepareUpdateQuota(token1, INT96_MIN, 0n), service.prepareUpdateQuota(token2, INT96_MIN, 0n), // Then repay debt service.prepareDecreaseDebt(MAX_UINT256), ]; ``` ### Cannot Update Quotas on Zero-Debt Account If your account has zero debt, quota updates fail. You must have active debt to hold quotas. ### Quota Tokens vs Non-Quota Tokens Not all tokens are quota tokens. Non-quota tokens are enabled/disabled via `enableToken`/`disableToken` and don't require quota to count as collateral. Check if a token is quota-based by examining the Credit Manager configuration. ### Forbidden Tokens Block Quota Increases If your account has forbidden tokens enabled, you cannot increase any quotas. Disable forbidden tokens first. ## Learn More * [Debt Management](https://docs.gearbox.finance/developers/gm-mc-debt) - Quotas require active debt * [Adding Collateral](https://docs.gearbox.finance/developers/gm-mc-collateral) - Often combined with quota updates * [Token Management](https://docs.gearbox.finance/developers/gm-mc-tokens) - For non-quota token enable/disable ## Health Factor Monitoring Source: https://docs.gearbox.finance/developers/health-factor-monitoring File: content/developers/health-factor-monitoring.mdx Track credit account health factors over time and alert on liquidation risk. ## Overview Health factor monitoring needs to: 1. Query current health factor for accounts 2. Track changes over time 3. Alert when accounts approach liquidation 4. Provide actionable data for position management This guide covers each step with SDK patterns. *** ## Understanding Health Factor **WHY:** Know what you're measuring before building monitoring. ### The Formula ``` Health Factor = Total Weighted Value / Total Debt Where: - Weighted Value = Sum of (Token Balance * Price * Liquidation Threshold) - Total Debt = Principal + Accrued Interest + Quota Fees ``` Health factor is scaled by 10000 in the protocol. `healthFactor = 10000` means HF = 1.0. ### Risk Thresholds | Health Factor | Status | Action | | ----------------------- | ------------ | ------------------------------------- | | > 1.5 (15000) | Healthy | No action needed | | 1.1 - 1.5 (11000-15000) | Moderate | Monitor more frequently | | 1.0 - 1.1 (10000-11000) | Critical | Alert user, suggest adding collateral | | < 1.0 (< 10000) | Liquidatable | Account can be liquidated | ### What Moves Health Factor Health factor changes when: * **Token prices change** (most common) - market moves affect collateral values * **Interest accrues** - debt grows over time, reducing HF * **Quota fees accumulate** - adds to total debt * **User actions** - adding/removing collateral, borrowing/repaying *** ## Querying Current Health Factor **WHY:** Get a snapshot of account health for display or alerting. ### Single Account ```typescript import { creditAccountCompressorAbi, AP_CREDIT_ACCOUNT_COMPRESSOR, VERSION_RANGE_310, } from '@gearbox-protocol/sdk'; const [accountCompressor] = sdk.addressProvider.mustGetLatest( AP_CREDIT_ACCOUNT_COMPRESSOR, VERSION_RANGE_310 ); // Get specific account data const [accounts] = await client.readContract({ address: accountCompressor, abi: creditAccountCompressorAbi, functionName: 'getCreditAccounts', args: [ creditManagerAddress, { owner: userAddress, minHealthFactor: 0n, maxHealthFactor: 65535n, // All HF values includeZeroDebt: false, reverting: false, }, 0n, ], }); for (const account of accounts) { const hf = Number(account.healthFactor) / 10000; console.log(`Account ${account.addr}: HF = ${hf.toFixed(4)}`); } ``` ### All Accounts at Risk Filter for accounts approaching liquidation: ```typescript // Accounts with HF between 1.0 and 1.1 (at risk but not yet liquidatable) const [atRiskAccounts] = await client.readContract({ address: accountCompressor, abi: creditAccountCompressorAbi, functionName: 'getCreditAccounts', args: [ creditManagerAddress, { owner: '0x0000000000000000000000000000000000000000', minHealthFactor: 10000n, // HF >= 1.0 maxHealthFactor: 11000n, // HF < 1.1 includeZeroDebt: false, reverting: false, }, 0n, ], }); console.log(`${atRiskAccounts.length} accounts in critical range`); ``` *** ## Continuous Monitoring **WHY:** Health factors change with every block as prices move and interest accrues. ### Polling Pattern ```typescript interface HealthSnapshot { account: string; healthFactor: number; debt: bigint; totalValue: bigint; timestamp: number; } async function monitorAccounts( creditManager: `0x${string}`, owner: `0x${string}`, onAlert: (snapshot: HealthSnapshot) => void ) { const POLL_INTERVAL = 5000; // 5 seconds const ALERT_THRESHOLD = 1.1; // Alert when HF < 1.1 while (true) { try { const [accounts] = await client.readContract({ address: accountCompressor, abi: creditAccountCompressorAbi, functionName: 'getCreditAccounts', args: [ creditManager, { owner, minHealthFactor: 0n, maxHealthFactor: 65535n, includeZeroDebt: false, reverting: false, }, 0n, ], }); for (const account of accounts) { const hf = Number(account.healthFactor) / 10000; const totalValue = account.tokens.reduce( (sum, t) => sum + t.balanceInUnderlying, 0n ); const snapshot: HealthSnapshot = { account: account.addr, healthFactor: hf, debt: account.debt, totalValue, timestamp: Date.now(), }; if (hf < ALERT_THRESHOLD) { onAlert(snapshot); } } } catch (error) { console.error('Monitor error:', error); } await new Promise(resolve => setTimeout(resolve, POLL_INTERVAL)); } } ``` ### Event-Driven Updates For more efficient monitoring, watch for events that affect health factor: ```typescript // Watch for multicall completions (position changes) const unwatchMulticall = client.watchContractEvent({ address: creditFacadeAddress, abi: creditFacadeAbi, eventName: 'FinishMultiCall', onLogs: async (logs) => { for (const log of logs) { // Refresh HF for affected account await refreshHealthFactor(log.args.creditAccount); } }, }); // Watch for liquidations const unwatchLiquidation = client.watchContractEvent({ address: creditFacadeAddress, abi: creditFacadeAbi, eventName: 'LiquidateCreditAccount', onLogs: async (logs) => { for (const log of logs) { console.log(`Account ${log.args.creditAccount} was liquidated`); } }, }); ``` *** ## Health Factor Breakdown **WHY:** Understanding why HF is low helps users take the right corrective action. ### Decomposing Health Factor ```typescript interface HealthBreakdown { healthFactor: number; totalWeightedValue: bigint; totalDebt: bigint; principal: bigint; accruedInterest: bigint; quotaFees: bigint; topCollaterals: Array<{ symbol: string; balance: bigint; valueInUnderlying: bigint; liquidationThreshold: number; weightedContribution: bigint; }>; } function analyzeHealthFactor(account: CreditAccountData): HealthBreakdown { const tokens = account.tokens .filter(t => t.balance > 0n) .map(t => ({ symbol: t.symbol, balance: t.balance, valueInUnderlying: t.balanceInUnderlying, liquidationThreshold: Number(t.lt) / 10000, weightedContribution: t.balanceInUnderlying * BigInt(t.lt) / 10000n, })) .sort((a, b) => Number(b.weightedContribution - a.weightedContribution)); const totalWeightedValue = tokens.reduce( (sum, t) => sum + t.weightedContribution, 0n ); const quotaInterest = account.cumulativeQuotaInterest; const quotaFees = account.quotaFees; const baseInterest = account.debt - account.borrowedAmount - quotaInterest - quotaFees; return { healthFactor: Number(account.healthFactor) / 10000, totalWeightedValue, totalDebt: account.debt, principal: account.borrowedAmount, accruedInterest: baseInterest, quotaFees, topCollaterals: tokens, }; } // Usage const breakdown = analyzeHealthFactor(account); console.log(`Health Factor: ${breakdown.healthFactor.toFixed(4)}`); console.log(`Debt: ${breakdown.totalDebt} (principal: ${breakdown.principal})`); console.log(`Interest: ${breakdown.accruedInterest}, Quota fees: ${breakdown.quotaFees}`); console.log('Collateral contributions:'); for (const col of breakdown.topCollaterals) { console.log(` ${col.symbol}: ${col.weightedContribution} (LT: ${(col.liquidationThreshold * 100).toFixed(1)}%)`); } ``` *** ## Alerting Strategies **WHY:** Different users need different alert thresholds and delivery methods. ### Tiered Alerts ```typescript type AlertLevel = 'info' | 'warning' | 'critical' | 'liquidatable'; function classifyRisk(healthFactor: number): AlertLevel { if (healthFactor < 1.0) return 'liquidatable'; if (healthFactor < 1.05) return 'critical'; if (healthFactor < 1.1) return 'warning'; return 'info'; } interface AlertConfig { account: `0x${string}`; creditManager: `0x${string}`; thresholds: { warning: number; // e.g. 1.2 critical: number; // e.g. 1.1 }; cooldown: number; // milliseconds between repeat alerts } const lastAlertTime = new Map(); function shouldAlert( account: string, level: AlertLevel, config: AlertConfig ): boolean { if (level === 'info') return false; const key = `${account}-${level}`; const lastTime = lastAlertTime.get(key) ?? 0; const now = Date.now(); if (now - lastTime < config.cooldown) return false; lastAlertTime.set(key, now); return true; } ``` ### Suggested Actions per Level ```typescript function suggestAction(breakdown: HealthBreakdown, level: AlertLevel): string { switch (level) { case 'warning': return 'Consider adding collateral or reducing debt'; case 'critical': return `Add at least ${formatValue(breakdown.totalDebt / 10n)} collateral immediately`; case 'liquidatable': return 'Account is liquidatable. Add collateral or repay debt NOW'; default: return 'Position is healthy'; } } ``` *** ## Complete Example: Health Monitor Service ```typescript import { createPublicClient, http } from 'viem'; import { mainnet } from 'viem/chains'; import { GearboxSDK, creditAccountCompressorAbi, AP_CREDIT_ACCOUNT_COMPRESSOR, VERSION_RANGE_310, } from '@gearbox-protocol/sdk'; const WARNING_HF = 1.15; const CRITICAL_HF = 1.05; const POLL_INTERVAL = 10_000; // 10 seconds async function runHealthMonitor( creditManagerAddress: `0x${string}`, ownerAddress: `0x${string}` ) { const client = createPublicClient({ chain: mainnet, transport: http(), }); const sdk = await GearboxSDK.attach({ client, marketConfigurators: [], }); const [accountCompressor] = sdk.addressProvider.mustGetLatest( AP_CREDIT_ACCOUNT_COMPRESSOR, VERSION_RANGE_310 ); let previousHFs = new Map(); while (true) { try { const [accounts] = await client.readContract({ address: accountCompressor, abi: creditAccountCompressorAbi, functionName: 'getCreditAccounts', args: [ creditManagerAddress, { owner: ownerAddress, minHealthFactor: 0n, maxHealthFactor: 65535n, includeZeroDebt: false, reverting: false, }, 0n, ], }); for (const account of accounts) { const hf = Number(account.healthFactor) / 10000; const prevHF = previousHFs.get(account.addr); previousHFs.set(account.addr, hf); // Determine direction const direction = prevHF !== undefined ? (hf > prevHF ? 'improving' : hf < prevHF ? 'declining' : 'stable') : 'initial'; // Classify and alert if (hf < 1.0) { console.log(`LIQUIDATABLE: ${account.addr} HF=${hf.toFixed(4)} [${direction}]`); } else if (hf < CRITICAL_HF) { console.log(`CRITICAL: ${account.addr} HF=${hf.toFixed(4)} [${direction}]`); } else if (hf < WARNING_HF) { console.log(`WARNING: ${account.addr} HF=${hf.toFixed(4)} [${direction}]`); } else if (direction !== 'stable') { console.log(`OK: ${account.addr} HF=${hf.toFixed(4)} [${direction}]`); } } } catch (error) { console.error('Monitor error:', error); } await new Promise(resolve => setTimeout(resolve, POLL_INTERVAL)); } } runHealthMonitor('0x...', '0x...').catch(console.error); ``` *** ## Gotchas ### Stale Price Feeds If on-demand price feeds (Pyth, Redstone) haven't been updated recently, the health factor from compressors may not reflect current market prices. For accurate monitoring: ```typescript // Check if any feeds need updating const feeds = await client.readContract({ address: priceFeedCompressor, abi: priceFeedCompressorAbi, functionName: 'getUpdatablePriceFeeds', args: [priceOracleAddress], }); const staleFeeds = feeds.filter(f => f.needsUpdate); if (staleFeeds.length > 0) { console.log(`Warning: ${staleFeeds.length} price feeds are stale`); } ``` ### Health Factor Precision Health factor is an integer scaled by 10000. Small changes (e.g., 10001 to 10000) can cross the liquidation boundary. Always use precise comparison: ```typescript // WRONG: floating point comparison if (hf < 1.0) { ... } // CORRECT: compare raw values if (account.healthFactor < 10000n) { ... } ``` ### Interest Accumulation Health factor decreases over time even without price changes, because interest accrues continuously. Factor this into alert timing - an account at HF 1.05 today may be liquidatable tomorrow purely from interest. *** ## Next Steps * [Frontend Applications](https://docs.gearbox.finance/developers/frontend-applications) - Display health data in a UI * [Liquidation Bots](https://docs.gearbox.finance/developers/liquidation-bots) - Act on liquidatable accounts * [Compressors Reference](https://docs.gearbox.finance/developers/compressors) - Full compressor API * [Debt Management](https://docs.gearbox.finance/developers/debt-management) - Repay debt to improve health * [Adding Collateral](https://docs.gearbox.finance/developers/adding-collateral) - Add collateral to improve health ## Withdrawing Collateral Source: https://docs.gearbox.finance/developers/gm-mc-withdraw File: content/developers/gm-mc-withdraw.mdx Remove tokens from your credit account. Withdrawals decrease your health factor since you are removing value from the account. ## Why You withdraw collateral when: * **Taking profit** - Extract gains while keeping the position open * **Rebalancing** - Move assets between Credit Account and wallet * **Closing positions** - Extract remaining value after repaying debt * **Emergency exit** - Quickly reduce exposure ## What `withdrawCollateral` transfers tokens from Credit Account to a specified address: 1. Token is transferred from Credit Account to `to` address 2. If balance goes to zero, token is auto-disabled 3. **Safe pricing** is triggered for the final collateral check **Safe pricing** is critical to understand: when any withdrawal occurs in a multicall, the final health check uses `min(mainPrice, reservePrice)` for ALL collateral. This can cause withdrawals to fail even when the account looks healthy based on main prices alone. ## How ```typescript import { GearboxSDK, createCreditAccountService } from '@gearbox-protocol/sdk'; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); const service = createCreditAccountService(sdk, 310); const market = sdk.marketRegister.findByCreditManager(cmAddress); // Withdraw 5,000 USDC to your wallet const calls = [ service.prepareWithdrawCollateral( usdcAddress, 5_000n * 10n ** 6n, myWalletAddress, ), ]; await market.creditFacade.write.multicall([creditAccountAddress, calls]); ``` ### Withdraw Entire Balance Pass max uint256 to withdraw all of a token: ```typescript const MAX_UINT256 = 2n ** 256n - 1n; const calls = [ service.prepareWithdrawCollateral(usdcAddress, MAX_UINT256, myWalletAddress), ]; ``` ### Withdraw to Different Address The `to` parameter can be any address: ```typescript const calls = [ service.prepareWithdrawCollateral( usdcAddress, amount, recipientAddress, // Can be different from caller ), ]; ``` ### Common Pattern: Repay + Withdraw After repaying debt, withdraw remaining funds: ```typescript const MAX_UINT256 = 2n ** 256n - 1n; const INT96_MIN = BigInt.asIntN(96, -1n * 2n ** 95n); const calls = [ // Zero quotas service.prepareUpdateQuota(wethAddress, INT96_MIN, 0n), // Repay all debt service.prepareDecreaseDebt(MAX_UINT256), // Withdraw remaining collateral service.prepareWithdrawCollateral(usdcAddress, MAX_UINT256, myWalletAddress), service.prepareWithdrawCollateral(wethAddress, MAX_UINT256, myWalletAddress), ]; ``` ## Gotchas ### Safe Pricing Can Block Withdrawals When you withdraw, ALL collateral is valued at `min(mainPrice, reservePrice)`: ``` Regular check: collateral valued at main price Withdrawal: collateral valued at min(main, reserve) ``` An account that looks healthy at main prices may fail the withdrawal check at safe prices. For example, if main price is \$100 and reserve price is \$80, your account might have HF 1.2 normally but only HF 0.96 under safe pricing. **Workaround:** Add extra collateral buffer or reduce debt before withdrawing if you're close to the threshold. ### Forbidden Tokens Block Withdrawals If your account has forbidden tokens enabled, withdrawals are prohibited. You must disable forbidden tokens first (usually by swapping them away). ### Token Auto-Disables at Zero Balance When you withdraw the entire balance of a token: * Non-quota tokens are auto-disabled * Quota tokens remain enabled until quota is zeroed ### Reserve Price May Be Zero Some tokens have a reserve price of zero (untrusted tokens). Any withdrawal will fail if such tokens are enabled, because their value becomes zero under safe pricing. ### Withdrawal Doesn't Auto-Disable Quota Tokens Unlike non-quota tokens, quota tokens remain enabled even at zero balance. You must explicitly zero the quota: ```typescript const MAX_UINT256 = 2n ** 256n - 1n; const INT96_MIN = BigInt.asIntN(96, -1n * 2n ** 95n); const calls = [ // Zero quota first service.prepareUpdateQuota(wethAddress, INT96_MIN, 0n), // Then withdraw service.prepareWithdrawCollateral(wethAddress, MAX_UINT256, myWalletAddress), ]; ``` ### Can't Withdraw Below Minimum Debt After withdrawal, your account must still satisfy debt constraints. If withdrawal would leave you with debt between 0 and `minDebt`, it fails. ## Learn More * [Adding Collateral](https://docs.gearbox.finance/developers/gm-mc-collateral) - The reverse operation * [Debt Management](https://docs.gearbox.finance/developers/gm-mc-debt) - Often combined with withdrawals * [Updating Quotas](https://docs.gearbox.finance/developers/gm-mc-quotas) - Zero quotas before withdrawing quota tokens ## External Calls Source: https://docs.gearbox.finance/developers/gm-mc-external File: content/developers/gm-mc-external.mdx Interact with external protocols (Uniswap, Curve, Yearn, etc.) from your credit account through whitelisted adapter contracts. ## Why You make external calls when: * **Swapping tokens** - Trade via Uniswap, Curve, or other DEXs * **Depositing to vaults** - Stake in Yearn, Lido, or yield strategies * **Managing LP positions** - Add/remove liquidity on various protocols * **Executing complex strategies** - Chain multiple protocol interactions ## What External calls flow through adapters: 1. You encode a call targeting an adapter address 2. Credit Facade routes the call to the adapter 3. Adapter builds the actual calldata for the external protocol 4. Adapter requests token approvals if needed 5. Credit Manager executes the call from the Credit Account 6. Credit Account acts as the "user" from the external protocol's perspective 7. Adapter returns which tokens to enable/disable based on the operation **Key insight:** The Credit Account makes the actual call, so it receives the output tokens directly. You never touch the funds - they stay in the Credit Account. ## How ### Step 1: Get Adapter Address ```typescript import { getContract } from 'viem'; import { creditManagerAbi } from '@gearbox-protocol/sdk'; const creditManager = getContract({ address: cmAddress, abi: creditManagerAbi, client: publicClient, }); // Get adapter for a protocol (e.g., Uniswap V3 Router) const uniswapV3Adapter = await creditManager.read.contractToAdapter([ UNISWAP_V3_ROUTER, ]); // Returns 0x0 if no adapter exists for this protocol if (uniswapV3Adapter === '0x0000000000000000000000000000000000000000') { throw new Error('No adapter for this protocol'); } ``` ### Step 2: Encode the Adapter Call ```typescript import { encodeFunctionData } from 'viem'; import { uniswapV3AdapterAbi } from '@gearbox-protocol/integrations-v3'; const swapParams = { tokenIn: usdcAddress, tokenOut: wethAddress, fee: 500, recipient: '0x0000000000000000000000000000000000000000', // Adapter overrides this deadline: BigInt(Math.floor(Date.now() / 1000) + 3600), amountIn: 50_000n * 10n ** 6n, amountOutMinimum: 24n * 10n ** 18n, // Slippage protection sqrtPriceLimitX96: 0n, }; const calls = [ { target: uniswapV3Adapter, callData: encodeFunctionData({ abi: uniswapV3AdapterAbi, functionName: 'exactInputSingle', args: [swapParams], }), }, ]; ``` ### Complete Example: Swap with Slippage Protection ```typescript import { encodeFunctionData } from 'viem'; import { GearboxSDK, createCreditAccountService, iCreditFacadeV300MulticallAbi, } from '@gearbox-protocol/sdk'; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); const service = createCreditAccountService(sdk, 310); const market = sdk.marketRegister.findByCreditManager(cmAddress); // Get adapter const uniswapV3Adapter = await market.creditManager.read.contractToAdapter([ UNISWAP_V3_ROUTER, ]); const calls = [ // Add collateral (SDK helper) service.prepareAddCollateral(usdcAddress, 50_000n * 10n ** 6n), // Borrow (SDK helper) service.prepareIncreaseDebt(200_000n * 10n ** 6n), // Slippage protection start { target: market.creditFacade.address, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'storeExpectedBalances', args: [[{ token: wethAddress, amount: 99n * 10n ** 18n }]], }), }, // Swap via adapter (manual encoding) { target: uniswapV3Adapter, callData: encodeFunctionData({ abi: uniswapV3AdapterAbi, functionName: 'exactInputSingle', args: [swapParams], }), }, // Slippage protection end { target: market.creditFacade.address, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'compareBalances', args: [], }), }, // Set quota for received token (SDK helper) service.prepareUpdateQuota(wethAddress, 250_000n * 10n ** 6n, 250_000n * 10n ** 6n), ]; // Approve collateral to Credit Manager await usdcContract.write.approve([market.creditManager.address, 50_000n * 10n ** 6n]); // Execute await market.creditFacade.write.openCreditAccount([ownerAddress, calls, 0n]); ``` ### Diff Functions Many adapters have `_diff` variants that operate on "entire balance minus 1": ```typescript // Instead of specifying exact amount... { functionName: 'deposit', args: [exactAmount] } // Use diff to deposit all USDC (minus 1 wei) { functionName: 'depositDiff', args: [1n] } ``` This is useful when you don't know the exact balance after previous operations. ## Gotchas ### Adapter ABIs Need Separate Import SDK exports core ABIs, but adapter ABIs often need a separate import: ```typescript // Core ABIs from SDK import { iCreditFacadeV300MulticallAbi } from '@gearbox-protocol/sdk'; // Adapter ABIs from integrations package import { uniswapV3AdapterAbi } from '@gearbox-protocol/integrations-v3'; ``` ### Not All Protocols Have Adapters An adapter must exist for each protocol you want to interact with. Check with `contractToAdapter` - it returns the zero address if no adapter exists. ### Recipient Parameter is Overridden Many DEX functions have a `recipient` parameter. Adapters override this to ensure tokens go to the Credit Account, not an arbitrary address. You can pass any value. ### Always Use Slippage Protection External calls are vulnerable to sandwich attacks. Always wrap swaps with slippage checks using `storeExpectedBalances` / `compareBalances`. ### Token Enable/Disable is Automatic After adapter calls, tokens are automatically enabled/disabled based on balance changes. You usually don't need manual `enableToken`/`disableToken` after adapter calls. ## Learn More * [Slippage & Safety](https://docs.gearbox.finance/developers/gm-mc-safety) - Protect your swaps * [Multicalls](https://docs.gearbox.finance/developers/gm-accounts-multicalls) - Combining SDK helpers with manual encoding * [Token Management](https://docs.gearbox.finance/developers/gm-mc-tokens) - Manual token management ## Overview Source: https://docs.gearbox.finance/developers/overview-2 File: content/developers/overview-2.mdx Integrate directly with Gearbox contracts from your Solidity code. This guide covers on-chain integration patterns for smart contract developers. ## Prerequisites * Solidity 0.8.x experience * Familiarity with interface-based contract interaction * Understanding of ERC-20 and common DeFi patterns ## What You'll Learn | Topic | Description | | ------------------ | ------------------------------------------------------------ | | Credit Accounts | Contract discovery, CreditFacade, CreditManager interactions | | Multicall Encoding | Build and execute multicalls in Solidity | | Pool Operations | Deposit, withdraw, and read pool state | ## Guide Structure 1. [**Credit Accounts**](https://docs.gearbox.finance/developers/credit-accounts) - Contract discovery, ICreditFacadeV3, ICreditManagerV3 interfaces 2. [**Multicalls**](https://docs.gearbox.finance/developers/multicalls) - MultiCall struct encoding, adapter calls 3. [**Pool Operations**](https://docs.gearbox.finance/developers/pool-operations) - IPoolV3 deposit/withdraw, ERC-4626 functions Note: Contract discovery patterns (AddressProvider, ContractsRegister) are covered in the Credit Accounts guide. ## Key Interfaces ```solidity // Core interfaces you'll use import {IAddressProviderV3} from "@gearbox-protocol/core-v3/contracts/interfaces/IAddressProviderV3.sol"; import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; import {IPoolV3} from "@gearbox-protocol/core-v3/contracts/interfaces/IPoolV3.sol"; ``` ## When to Use Solidity Integration | Use Case | Recommended | | ----------------------------- | ------------------ | | On-chain protocol integration | Yes | | Building adapters | Yes | | Composable strategies | Yes | | Backend services | No (use SDK Guide) | | Frontend applications | No (use SDK Guide) | For TypeScript/JavaScript applications, see the [SDK Guide](https://docs.gearbox.finance/developers/overview). ## Architecture Understanding For conceptual background on how Gearbox works: * [Credit Suite Architecture](https://docs.gearbox.finance/developers/credit-suite) - How Credit Managers, Facades, and Configurators work together * [Pool Architecture](https://docs.gearbox.finance/developers/pools) - Lending pools and ERC-4626 compliance * [Multicall System](https://docs.gearbox.finance/developers/multicall-system) - How multicalls execute and validate *** ## Detailed Guides ### Multicall Operations Complete reference for each multicall operation with Solidity examples: | Operation | Description | | ---------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- | | [Adding Collateral](https://docs.gearbox.finance/developers/adding-collateral) | Transfer tokens to credit account | | [Debt Management](https://docs.gearbox.finance/developers/debt-management) | Borrow and repay | | [Updating Quotas](https://docs.gearbox.finance/developers/updating-quotas) | Manage collateral quotas | | [Withdrawing Collateral](https://docs.gearbox.finance/developers/withdrawing-collateral) | Remove tokens from account | | [Controlling Slippage](https://docs.gearbox.finance/developers/controlling-slippage) | Protect against price movement | | [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls) | Interact with DeFi protocols via adapters | | [Enabling/Disabling Tokens](https://docs.gearbox.finance/developers/enabling-disabling-tokens) | Manage active collateral | | [Updating Price Feeds](https://docs.gearbox.finance/developers/updating-price-feeds) | On-demand oracle updates (Pyth, Redstone) | | [Collateral Check Params](https://docs.gearbox.finance/developers/collateral-check-params) | Optimize health checks with hints | | [Revoke Allowances](https://docs.gearbox.finance/developers/revoke-allowances) | Security cleanup | See [Multicalls Overview](https://docs.gearbox.finance/developers/multicalls) for the diff pattern and complete encoding examples. ### Use Case Guides Integration-specific guides for common development scenarios: | Building | Guide | Focus | | -------------------- | ------------------------------------------------------------------------------------------------------ | ----------------------------------------------------- | | New DeFi Adapter | [Adapter Development](https://docs.gearbox.finance/developers/adapter-development) | AbstractAdapter, security patterns, diff functions | | Strategy Contract | [Protocol Integration](https://docs.gearbox.finance/developers/protocol-integration) | Multicall building, access control, automation | | Core Extensions | [Core Extension](https://docs.gearbox.finance/developers/core-extension) | Extending core contracts, advanced customizations | | Liquidation Contract | [Liquidation Bots](https://docs.gearbox.finance/developers/liquidation-bots) | On-chain liquidation, flash loans, keeper integration | ## Credit Accounts Source: https://docs.gearbox.finance/developers/credit-accounts-2 File: content/developers/credit-accounts-2.mdx Manage leveraged positions on Gearbox from Solidity. This guide covers discovering markets, opening accounts, managing positions, and monitoring health. > For SDK credit account operations, see [Credit Accounts](https://docs.gearbox.finance/developers/credit-accounts). ## Discovering Markets Find credit managers and their facades programmatically using ContractsRegister: ```solidity import {IAddressProviderV3} from "@gearbox-protocol/core-v3/contracts/interfaces/IAddressProviderV3.sol"; import {IContractsRegister} from "@gearbox-protocol/core-v3/contracts/interfaces/IContractsRegister.sol"; import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; IAddressProviderV3 ap = IAddressProviderV3(ADDRESS_PROVIDER); address cr = ap.getAddressOrRevert("CONTRACTS_REGISTER", 3_10); // Get all credit managers address[] memory allCMs = IContractsRegister(cr).getCreditManagers(); ``` **Example:** Find USDC credit managers ```solidity function findUSDCCreditManagers(address addressProvider, address usdc) external view returns (address[] memory facades) { IAddressProviderV3 ap = IAddressProviderV3(addressProvider); address cr = ap.getAddressOrRevert("CONTRACTS_REGISTER", 3_10); address[] memory allCMs = IContractsRegister(cr).getCreditManagers(); uint256 count; for (uint256 i = 0; i < allCMs.length; i++) { if (ICreditManagerV3(allCMs[i]).underlying() == usdc) count++; } facades = new address[](count); uint256 j; for (uint256 i = 0; i < allCMs.length; i++) { ICreditManagerV3 cm = ICreditManagerV3(allCMs[i]); if (cm.underlying() == usdc) { facades[j++] = cm.creditFacade(); } } } ``` ## Opening a Credit Account Open a leveraged position by providing collateral and borrowing funds through the CreditFacade: ```solidity import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; function openCreditAccount( address onBehalfOf, MultiCall[] calldata calls, uint256 referralCode ) external payable returns (address creditAccount); ``` **Example:** ```solidity ICreditFacadeV3 facade = ICreditFacadeV3(facadeAddress); ICreditManagerV3 creditManager = ICreditManagerV3(facade.creditManager()); address underlying = creditManager.underlying(); // Build initial multicall: add collateral + increase debt MultiCall[] memory calls = new MultiCall[](2); calls[0] = MultiCall({ target: facadeAddress, callData: abi.encodeCall( ICreditFacadeV3Multicall.addCollateral, (underlying, 10_000e6) ) }); calls[1] = MultiCall({ target: facadeAddress, callData: abi.encodeCall( ICreditFacadeV3Multicall.increaseDebt, (40_000e6) ) }); // Approve collateral to Credit Manager (not Facade!) IERC20(underlying).approve(address(creditManager), 10_000e6); // Open account address creditAccount = facade.openCreditAccount( msg.sender, // onBehalfOf calls, // initial operations 0 // referralCode ); ``` ### Debt Limits Check borrowing constraints before opening: ```solidity // Get min and max debt allowed (uint128 minDebt, uint128 maxDebt) = facade.debtLimits(); require(borrowAmount >= minDebt && borrowAmount <= maxDebt, "Invalid debt"); ``` ## Managing Active Positions Execute operations on existing credit accounts using multicalls: ```solidity function multicall( address creditAccount, MultiCall[] calldata calls ) external payable; ``` ### Adding Collateral Deposit additional tokens to improve health factor: ```solidity MultiCall[] memory calls = new MultiCall[](1); calls[0] = MultiCall({ target: address(facade), callData: abi.encodeCall( ICreditFacadeV3Multicall.addCollateral, (tokenAddress, amount) ) }); // Approve to Credit Manager first IERC20(tokenAddress).approve(address(creditManager), amount); facade.multicall(creditAccount, calls); ``` ### Increasing Debt Borrow more funds from the pool: ```solidity MultiCall[] memory calls = new MultiCall[](1); calls[0] = MultiCall({ target: address(facade), callData: abi.encodeCall( ICreditFacadeV3Multicall.increaseDebt, (additionalDebt) ) }); facade.multicall(creditAccount, calls); ``` ### Executing Swaps via Adapters Trade collateral through whitelisted protocols. First, discover the adapter: ```solidity // Get adapter for target protocol address uniswapAdapter = creditManager.contractToAdapter(UNISWAP_V3_ROUTER); require(uniswapAdapter != address(0), "Protocol not allowed"); ``` **Example:** Swap using Uniswap V3 adapter ```solidity MultiCall[] memory calls = new MultiCall[](1); calls[0] = MultiCall({ target: uniswapAdapter, callData: abi.encodeCall( ISwapRouter.exactInputSingle, ISwapRouter.ExactInputSingleParams({ tokenIn: usdc, tokenOut: weth, fee: 3000, recipient: creditAccount, deadline: block.timestamp, amountIn: 10_000e6, amountOutMinimum: 3e18, sqrtPriceLimitX96: 0 }) ) }); facade.multicall(creditAccount, calls); ``` ### Withdrawing Collateral Remove excess collateral while maintaining health: ```solidity MultiCall[] memory calls = new MultiCall[](1); calls[0] = MultiCall({ target: address(facade), callData: abi.encodeCall( ICreditFacadeV3Multicall.withdrawCollateral, (tokenAddress, amount, msg.sender) ) }); facade.multicall(creditAccount, calls); ``` ## Monitoring Account Health Calculate health factor to check liquidation risk: ```solidity import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; enum CollateralCalcTask { GENERIC_PARAMS, // Basic info (debt, cumulative index) DEBT_ONLY, // Detailed debt (base + quota interest) FULL_COLLATERAL_CHECK_LAZY, // Internal use DEBT_COLLATERAL, // Full debt + Total Value (for Health Factor) DEBT_COLLATERAL_SAFE_PRICES // Uses safe pricing } function calcDebtAndCollateral( address creditAccount, CollateralCalcTask task ) external view returns (CollateralDebtData memory cdd); ``` **Example:** ```solidity ICreditManagerV3 cm = ICreditManagerV3(creditManagerAddress); CollateralDebtData memory cdd = cm.calcDebtAndCollateral( creditAccount, CollateralCalcTask.DEBT_COLLATERAL ); // Health factor: 10000 = 100% = HF of 1.0 uint256 healthFactor = (cdd.twvUSD * 10000) / cdd.totalDebtUSD; // Account is liquidatable if HF < 10000 bool liquidatable = healthFactor < 10000; // Account has buffer if HF > 10100 (1% above liquidation) bool safe = healthFactor > 10100; ``` ### CollateralDebtData Structure ```solidity struct CollateralDebtData { uint256 totalDebtUSD; // Total debt in USD uint256 twvUSD; // Total Weighted Value in USD uint256 enabledTokensMask; // Bitmask of enabled tokens uint256 quotedTokensMask; // Bitmask of tokens with quota address[] quotedTokens; // Addresses of quoted tokens address _poolQuotaKeeper; // Pool quota keeper address } ``` ## Closing Positions Close account and return remaining funds after repaying debt: ```solidity function closeCreditAccount( address creditAccount, MultiCall[] calldata calls ) external payable; ``` **Example:** Unwind position and close ```solidity // Build multicall to: // 1. Swap all tokens back to underlying // 2. Repay remaining debt // 3. Withdraw leftover to owner MultiCall[] memory calls = new MultiCall[](3); // Swap collateral token to underlying via adapter calls[0] = MultiCall({ target: uniswapAdapter, callData: abi.encodeCall( ISwapRouter.exactInputSingle, ISwapRouter.ExactInputSingleParams({ tokenIn: weth, tokenOut: underlying, fee: 3000, recipient: creditAccount, deadline: block.timestamp, amountIn: wethBalance, amountOutMinimum: minUnderlyingOut, sqrtPriceLimitX96: 0 }) ) }); // Decrease debt to zero (protocol calculates exact amount) calls[1] = MultiCall({ target: address(facade), callData: abi.encodeCall( ICreditFacadeV3Multicall.decreaseDebt, (type(uint256).max) // max = full repayment ) }); // Withdraw remaining underlying calls[2] = MultiCall({ target: address(facade), callData: abi.encodeCall( ICreditFacadeV3Multicall.withdrawCollateral, (underlying, type(uint256).max, msg.sender) ) }); facade.closeCreditAccount(creditAccount, calls); ``` ## Configuration and Limits Query market parameters and restrictions: ### Debt Limits ```solidity // Min and max borrowable amount (uint128 minDebt, uint128 maxDebt) = facade.debtLimits(); ``` ### Liquidation Thresholds ```solidity // Get liquidation threshold for specific token (basis points) uint16 lt = creditManager.liquidationThresholds(tokenAddress); // LT of 8000 = 80% = token contributes 80% of value to collateral ``` ### Forbidden Tokens ```solidity // Bitmask of forbidden tokens uint256 forbiddenMask = facade.forbiddenTokenMask(); // Check if specific token mask is forbidden bool isForbidden = (forbiddenMask & tokenMask) != 0; ``` ### Collateral Tokens Enumerate all allowed collateral: ```solidity uint8 tokenCount = creditManager.collateralTokensCount(); for (uint8 i = 0; i < tokenCount; i++) { uint256 mask = 1 << i; (address token, uint16 lt) = creditManager.collateralTokenByMask(mask); // token address and liquidation threshold } ``` ### Fee Configuration ```solidity ( uint16 feeInterest, // Interest fee (bp) uint16 feeLiquidation, // Liquidation fee (bp) uint16 liquidationPremium, // Liquidator premium (bp) uint16 feeLiquidationExpired, // Expired liquidation fee (bp) uint16 liquidationPremiumExpired // Expired liquidator premium (bp) ) = creditManager.fees(); ``` ## Complete Example Full integration showing position lifecycle: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {CollateralDebtData, CollateralCalcTask} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; contract LeveragedTrading { ICreditFacadeV3 public immutable facade; ICreditManagerV3 public immutable creditManager; address public immutable underlying; constructor(address _facade) { facade = ICreditFacadeV3(_facade); creditManager = ICreditManagerV3(facade.creditManager()); underlying = creditManager.underlying(); } function openPosition( uint256 collateral, uint256 leverage ) external returns (address creditAccount) { // Calculate debt for desired leverage uint256 borrowAmount = (collateral * (leverage - 1)); // Validate against limits (uint128 minDebt, uint128 maxDebt) = facade.debtLimits(); require(borrowAmount >= minDebt && borrowAmount <= maxDebt, "Invalid debt"); // Build multicall: add collateral + increase debt MultiCall[] memory calls = new MultiCall[](2); calls[0] = MultiCall({ target: address(facade), callData: abi.encodeCall( ICreditFacadeV3Multicall.addCollateral, (underlying, collateral) ) }); calls[1] = MultiCall({ target: address(facade), callData: abi.encodeCall( ICreditFacadeV3Multicall.increaseDebt, (borrowAmount) ) }); // Transfer collateral from user IERC20(underlying).transferFrom(msg.sender, address(this), collateral); // Approve to credit manager IERC20(underlying).approve(address(creditManager), collateral); // Open account creditAccount = facade.openCreditAccount(msg.sender, calls, 0); } function getHealthFactor(address creditAccount) external view returns (uint256 healthFactor, bool liquidatable) { CollateralDebtData memory cdd = creditManager.calcDebtAndCollateral( creditAccount, CollateralCalcTask.DEBT_COLLATERAL ); healthFactor = (cdd.twvUSD * 10000) / cdd.totalDebtUSD; liquidatable = healthFactor < 10000; } function addCollateralToPosition( address creditAccount, uint256 amount ) external { MultiCall[] memory calls = new MultiCall[](1); calls[0] = MultiCall({ target: address(facade), callData: abi.encodeCall( ICreditFacadeV3Multicall.addCollateral, (underlying, amount) ) }); // Transfer from user and approve IERC20(underlying).transferFrom(msg.sender, address(this), amount); IERC20(underlying).approve(address(creditManager), amount); facade.multicall(creditAccount, calls); } function closePosition(address creditAccount) external { // Build multicall to repay debt and withdraw MultiCall[] memory calls = new MultiCall[](2); calls[0] = MultiCall({ target: address(facade), callData: abi.encodeCall( ICreditFacadeV3Multicall.decreaseDebt, (type(uint256).max) // full repayment ) }); calls[1] = MultiCall({ target: address(facade), callData: abi.encodeCall( ICreditFacadeV3Multicall.withdrawCollateral, (underlying, type(uint256).max, msg.sender) ) }); facade.closeCreditAccount(creditAccount, calls); } } ``` For architectural background, see [Credit Suite Architecture](https://docs.gearbox.finance/developers/credit-suite). ## Slippage & Safety Source: https://docs.gearbox.finance/developers/gm-mc-safety File: content/developers/gm-mc-safety.mdx Control slippage, update on-demand price feeds, and optimize collateral checks. These safety mechanisms protect your multicalls from unexpected losses. ## Slippage Protection ### Why You need slippage protection when performing swaps or multi-step operations. Without it, sandwich bots can exploit unprotected transactions and you may receive significantly fewer tokens than expected. ### How It Works Gearbox uses a two-step pattern: 1. **`storeExpectedBalances`** - Record expected minimum balances BEFORE operations 2. **`compareBalances`** - Verify actual balances meet expectations AFTER operations If the final balance is less than expected, the entire multicall reverts. ### Basic Usage ```typescript import { encodeFunctionData } from 'viem'; import { iCreditFacadeV300MulticallAbi } from '@gearbox-protocol/sdk'; // Calculate minimum expected output with 0.5% slippage tolerance const expectedOutput = 25n * 10n ** 18n; // 25 WETH const slippageBps = 50n; // 0.5% const minExpected = expectedOutput - (expectedOutput * slippageBps / 10000n); const calls = [ // 1. Store expected balance BEFORE swap { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'storeExpectedBalances', args: [[{ token: wethAddress, amount: minExpected }]], }), }, // 2. Perform the swap { target: uniswapV3Adapter, callData: encodeFunctionData({ abi: uniswapV3AdapterAbi, functionName: 'exactInputSingle', args: [swapParams], }), }, // 3. Verify slippage AFTER swap { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'compareBalances', args: [], }), }, ]; ``` ### Multiple Tokens Check slippage on multiple output tokens in a single store/compare pair: ```typescript const calls = [ // Store expectations for both tokens { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'storeExpectedBalances', args: [[ { token: wethAddress, amount: minWethExpected }, { token: usdcAddress, amount: minUsdcExpected }, ]], }), }, // Multiple swaps... { /* swap 1 */ }, { /* swap 2 */ }, // Single compare covers all stored expectations { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'compareBalances', args: [], }), }, ]; ``` ### Slippage Gotchas * **Keep checks close to operations** - Place `storeExpectedBalances` immediately before swaps, and `compareBalances` immediately after. Internal operations like `addCollateral` between them can affect balances unexpectedly. * **`compareBalances` without `storeExpectedBalances` reverts** - You must always call store first. * **Auto-compare at multicall end** - If you forget `compareBalances`, the check happens automatically, but explicit is better. * **Amount is a delta, not final balance** - The `amount` in `BalanceDelta` is the change you expect, not the resulting balance. * **Cannot reuse stored balances** - After `compareBalances`, stored expectations are cleared. Call `storeExpectedBalances` again for subsequent swaps. --- ## On-Demand Price Updates ### Why Some tokens use pull-based oracles (Pyth, Redstone) that don't update automatically. You must push fresh price data before operations that depend on accurate pricing. ### How It Works `onDemandPriceUpdate` pushes oracle data to the price feed. You obtain signed price data from the oracle provider off-chain, then include the update as the FIRST call in your multicall. **Critical rule:** All price updates must be at the **beginning** of the calls array. Any `onDemandPriceUpdate` after another call type will revert. ### Basic Usage ```typescript import { encodeFunctionData } from 'viem'; import { iCreditFacadeV300MulticallAbi } from '@gearbox-protocol/sdk'; // Get price data from oracle provider (e.g., Pyth) const priceData = await pythClient.getPriceUpdateData([feedId]); const calls = [ // Price update MUST be first { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'onDemandPriceUpdate', args: [ tokenAddress, // Token to update price for false, // reserve: false = main feed, true = reserve feed priceData, // Signed price data from oracle ], }), }, // Now other operations service.prepareAddCollateral(usdcAddress, amount), service.prepareIncreaseDebt(debtAmount), ]; ``` ### Reserve Feed Updates (For Withdrawals) Withdrawals trigger safe pricing, which uses both main and reserve feeds: ```typescript const calls = [ // Main feed update { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'onDemandPriceUpdate', args: [tokenAddress, false, mainPriceData], // reserve = false }), }, // Reserve feed update { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'onDemandPriceUpdate', args: [tokenAddress, true, reservePriceData], // reserve = true }), }, // Now the withdrawal will work with safe pricing service.prepareWithdrawCollateral(otherToken, amount, recipient), ]; ``` ### Detecting Which Feeds Need Updates ```typescript import { priceFeedCompressorAbi } from '@gearbox-protocol/sdk'; const feedInfo = await client.readContract({ address: priceFeedCompressorAddress, abi: priceFeedCompressorAbi, functionName: 'getUpdatablePriceFeeds', args: [creditManagerAddress], }); // feedInfo contains tokens that need on-demand updates const tokensNeedingUpdate = feedInfo.filter(f => f.needsUpdate); ``` ### Price Update Gotchas * **Price updates MUST be first** - Any price update after a non-price-update call reverts. * **Fresh data required** - Price data has a short validity window (usually a few minutes). Generate it right before the transaction. * **Not all tokens need updates** - Only Pyth and Redstone feeds need on-demand updates. Chainlink feeds update automatically. * **Disabled tokens don't need updates** - If a token will be disabled by the end of the multicall, skip its price update. --- ## Collateral Check Parameters ### Why You set collateral check params to optimize gas or enforce a minimum health factor above 1.0. The collateral check iterates through enabled tokens, summing value until it exceeds debt. Hints tell it which tokens to check first, potentially skipping expensive oracle calls. ### How It Works `setFullCheckParams` configures two things: 1. **Collateral hints** - Token masks to prioritize during the check 2. **Min health factor** - Minimum acceptable HF (in basis points, 10000 = 1.0) ### Basic Usage ```typescript import { encodeFunctionData } from 'viem'; import { iCreditFacadeV300MulticallAbi, creditManagerAbi } from '@gearbox-protocol/sdk'; import { getContract } from 'viem'; const creditManager = getContract({ address: cmAddress, abi: creditManagerAbi, client: publicClient, }); // Get token masks (each token has a unique bitmask) const usdcMask = await creditManager.read.getTokenMaskOrRevert([usdcAddress]); const wethMask = await creditManager.read.getTokenMaskOrRevert([wethAddress]); const calls = [ // Set hints at the start of multicall { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'setFullCheckParams', args: [ [usdcMask, wethMask], // Check these tokens first 10000, // minHealthFactor: 1.0 (10000 bps) ], }), }, // Rest of your multicall service.prepareAddCollateral(usdcAddress, amount), ]; ``` ### Setting Higher Min Health Factor Require the account to maintain at least 1.2 HF: ```typescript const MIN_HF_120 = 12000; // 1.2 in basis points const calls = [ { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'setFullCheckParams', args: [ [], // No hints MIN_HF_120, ], }), }, // Operations... ]; ``` ### Check Params Gotchas * **Use masks, not addresses** - The hints array takes token masks from `getTokenMaskOrRevert`, not token addresses. * **Hints are optimization, not guarantee** - All enabled tokens are still validated; hints just change the evaluation order. * **Min health factor must be >= 10000** - You cannot set a health factor below 1.0. * **Params reset after multicall** - `setFullCheckParams` only affects the current multicall's final check. The next multicall uses defaults. * **Small accounts don't benefit** - For accounts with fewer than 5 enabled tokens, hints add overhead without meaningful gas savings. * **Order matters** - Put your highest-value collateral first in the hints array for the best gas savings. ## Learn More * [External Calls](https://docs.gearbox.finance/developers/gm-mc-external) - Adapter calls that need slippage protection * [Multicalls](https://docs.gearbox.finance/developers/gm-accounts-multicalls) - Building and executing multicalls * [Withdrawing Collateral](https://docs.gearbox.finance/developers/gm-mc-withdraw) - May need reserve feed updates ## Multicalls Source: https://docs.gearbox.finance/developers/multicalls-2 File: content/developers/multicalls-2.mdx Build and execute multicalls in Solidity. > For SDK multicall helpers, see [Multicalls](https://docs.gearbox.finance/developers/multicalls). ## Detailed Operation Guides For comprehensive documentation of each operation: * [Adding Collateral](https://docs.gearbox.finance/developers/adding-collateral) - Transfer tokens with approval patterns * [Debt Management](https://docs.gearbox.finance/developers/debt-management) - Borrowing, repayment, and constraints * [Updating Quotas](https://docs.gearbox.finance/developers/updating-quotas) - Quota mechanics and limits * [Withdrawing Collateral](https://docs.gearbox.finance/developers/withdrawing-collateral) - Safe pricing and health impact * [Controlling Slippage](https://docs.gearbox.finance/developers/controlling-slippage) - Balance delta protection * [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls) - Adapter interaction patterns * [Enabling/Disabling Tokens](https://docs.gearbox.finance/developers/enabling-disabling-tokens) - Token mask management * [Updating Price Feeds](https://docs.gearbox.finance/developers/updating-price-feeds) - On-demand oracle data * [Collateral Check Params](https://docs.gearbox.finance/developers/collateral-check-params) - Health check optimization * [Revoke Allowances](https://docs.gearbox.finance/developers/revoke-allowances) - Security cleanup ## The MultiCall Structure ```solidity struct MultiCall { address target; // CreditFacade or allowed Adapter bytes callData; // Encoded function call } ``` ## ICreditFacadeV3Multicall Operations All multicall operations are defined in `ICreditFacadeV3Multicall`: ```solidity import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; ``` ### Protocol Operations | Function | Signature | | ------------------------- | ---------------------------------------------------------------------------------- | | `addCollateral` | `(address token, uint256 amount)` | | `addCollateralWithPermit` | `(address token, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s)` | | `withdrawCollateral` | `(address token, uint256 amount, address to)` | | `increaseDebt` | `(uint256 amount)` | | `decreaseDebt` | `(uint256 amount)` | | `updateQuota` | `(address token, int96 quotaChange, uint96 minQuota)` | ### Safety Operations | Function | Signature | | ----------------------- | ------------------------------------------- | | `onDemandPriceUpdate` | `(address token, bool reserve, bytes data)` | | `storeExpectedBalances` | `(BalanceDelta[] deltas)` | | `compareBalances` | `()` | | `setFullCheckParams` | `(uint256[] hints, uint16 minHF)` | | `setBotPermissions` | `(address bot, uint192 permissions)` | ## Encoding Multicalls Use `abi.encodeCall` for type-safe encoding: ```solidity MultiCall[] memory calls = new MultiCall[](3); // Add collateral calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.addCollateral, (usdc, 10_000 * 10**6) ) }); // Borrow calls[1] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.increaseDebt, (40_000 * 10**6) ) }); // Set quota calls[2] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.updateQuota, (weth, 50_000 * 10**6, 50_000 * 10**6) ) }); ``` ## Adapter Calls External protocol calls go through adapters. Get the adapter address from Credit Manager: ```solidity // Get adapter for Uniswap V3 address uniswapV3Adapter = ICreditManagerV3(creditManager).contractToAdapter(UNISWAP_V3_ROUTER); require(uniswapV3Adapter != address(0), "Adapter not found"); // Encode adapter call calls[4] = MultiCall({ target: uniswapV3Adapter, callData: abi.encodeCall( IUniswapV3Adapter.exactInputSingle, (ISwapRouter.ExactInputSingleParams({ tokenIn: usdc, tokenOut: weth, fee: 500, recipient: address(0), // Adapter overrides to credit account deadline: block.timestamp + 3600, amountIn: 50_000 * 10**6, amountOutMinimum: 0, // Using Gearbox slippage check instead sqrtPriceLimitX96: 0 })) ) }); ``` ## Complete Multicall Example 8-call strategy: price update, collateral, borrow, slippage setup, swap, deposit, slippage check, quota: ```solidity address accountOwner; address creditManager; address creditFacade; address usdc; address weth; address yvWETH; address uniswapV3Router; bytes memory yvWETH_priceData; // Assume exchange rate: 2000 USDC/yvWETH MultiCall[] memory calls = new MultiCall[](8); // 1. On-demand price update (must be first) calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.onDemandPriceUpdate, (yvWETH, false, yvWETH_priceData) ) }); // 2. Add collateral calls[1] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.addCollateral, (usdc, 10_000 * 10**6) ) }); // 3. Borrow calls[2] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.increaseDebt, (40_000 * 10**6) ) }); // 4. Store expected balances for slippage check // Min output: (50000 / 2000) * 0.995 = 24.875 yvWETH BalanceDelta[] memory deltas = new BalanceDelta[](1); deltas[0] = BalanceDelta({ token: yvWETH, amount: (25 * 10**18) * 995 / 1000 }); calls[3] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.storeExpectedBalances, (deltas) ) }); // 5. Swap via Uniswap address uniswapV3Adapter = ICreditManagerV3(creditManager).contractToAdapter(uniswapV3Router); ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({ tokenIn: usdc, tokenOut: weth, fee: 500, recipient: address(0), // Adapter overrides deadline: block.timestamp + 3600, amountIn: 50_000 * 10**6, amountOutMinimum: 0, // Using Gearbox slippage check sqrtPriceLimitX96: 0 }); calls[4] = MultiCall({ target: uniswapV3Adapter, callData: abi.encodeCall(IUniswapV3Adapter.exactInputSingle, (params)) }); // 6. Deposit to Yearn using diff pattern address yvWETHAdapter = ICreditManagerV3(creditManager).contractToAdapter(yvWETH); calls[5] = MultiCall({ target: yvWETHAdapter, callData: abi.encodeCall(IYearnV2Adapter.depositDiff, (1)) // Leave 1 wei }); // 7. Compare balances (slippage check) calls[6] = MultiCall({ target: creditFacade, callData: abi.encodeCall(ICreditFacadeV3Multicall.compareBalances, ()) }); // 8. Set quota for yvWETH calls[7] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.updateQuota, (yvWETH, 50_000 * 10**6, 50_000 * 10**6) ) }); // Approve collateral to Credit Manager (not Facade!) IERC20(usdc).approve(creditManager, 10_000 * 10**6); // Execute ICreditFacadeV3(creditFacade).openCreditAccount(accountOwner, calls, 0); ``` ## The "Diff" Pattern Adapters implement `*_diff` functions for handling unknown amounts: * **Standard function**: Requires exact `amountIn` * **Diff function**: Calculates `amountIn = currentBalance - leftoverAmount` This is essential when the exact output of a previous operation is unknown. ```solidity // After a swap, deposit all WETH except 1 wei to Yearn calls[5] = MultiCall({ target: yvWETHAdapter, callData: abi.encodeCall(IYearnV2Adapter.depositDiff, (1)) }); ``` ## Best Practices 1. **Price updates first**: Always put `onDemandPriceUpdates` at the start if using pull-based oracles 2. **Slippage protection**: Always use `storeExpectedBalances` before swaps and `compareBalances` after 3. **Approve to Credit Manager**: Token approvals go to Credit Manager, not Credit Facade 4. **Gas optimization**: Use `setFullCheckParams` with hints for accounts with many tokens 5. **Dust management**: Use `type(uint256).max` in `withdrawCollateral` to empty balances ## Next Steps * [Multicall Operations](https://docs.gearbox.finance/developers/multicalls) - Individual operation guides * [Use Cases](https://docs.gearbox.finance/developers/use-cases) - Adapter development and protocol integration * [Pool Operations](https://docs.gearbox.finance/developers/pool-operations) - Direct pool interaction For architectural background, see [Multicall System](https://docs.gearbox.finance/developers/multicall-system). ## Token Management Source: https://docs.gearbox.finance/developers/gm-mc-tokens File: content/developers/gm-mc-tokens.mdx Manage which tokens count as collateral and revoke unnecessary token allowances on your credit account. ## Enabling and Disabling Tokens ### Why You manually enable/disable tokens when: * **Direct transfers** - Tokens sent directly to a Credit Account aren't auto-enabled * **Gas optimization** - Disable unused tokens to reduce collateral check cost * **Risk management** - Prevent certain tokens from counting in health factor Most of the time you don't need this - tokens auto-enable/disable based on balance changes from adapter calls. Manual control is only necessary in edge cases. ### Auto-Enable/Disable Behavior Non-quoted tokens have automatic behavior: | Balance Change | Action | | -------------- | ------------ | | 0/1 to > 1 | Auto-enable | | > 1 to 0/1 | Auto-disable | **Important:** These functions only work on **non-quoted tokens**. Quota tokens can only be enabled/disabled via `updateQuota`. ### Enable a Token ```typescript import { encodeFunctionData } from 'viem'; import { iCreditFacadeV300MulticallAbi } from '@gearbox-protocol/sdk'; const calls = [ { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'enableToken', args: [tokenAddress], }), }, ]; ``` ### Disable a Token ```typescript const calls = [ { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'disableToken', args: [tokenAddress], }), }, ]; ``` ### Disable Unused Tokens to Save Gas Each enabled token requires a price oracle call during collateral check. Disable tokens with zero balance: ```typescript // Check which tokens have zero balance const accountData = await service.getCreditAccountData(creditAccountAddress); const tokensToDisable = accountData.tokens .filter(t => t.balance <= 1n && t.isEnabled) .map(t => t.token); const calls = tokensToDisable.map(token => ({ target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'disableToken', args: [token], }), })); ``` ### Enable/Disable Gotchas * **No-op for quota tokens** - Calling `enableToken` or `disableToken` on a quota token does nothing. Use `updateQuota` instead. * **Cannot enable forbidden tokens** - Forbidden tokens will revert. They must be swapped away. * **Max enabled tokens limit** - Each Credit Manager has a maximum number of enabled tokens per account. Check with `creditManager.read.maxEnabledTokens()`. * **Disabled tokens still on account** - Disabling doesn't remove the balance, it just excludes the token from the health factor calculation. During liquidation, liquidators can claim disabled token balances as bonus. * **Balance of 1 is "zero"** - Gearbox treats balances of 0 and 1 the same (due to ERC20 rounding). Auto-disable triggers at balance <= 1. --- ## Revoking Allowances ### Why You revoke allowances when: * **Security incident** - A third-party contract may be compromised * **Legacy cleanup** - Old accounts from V2.1 may have stale approvals * **Defense in depth** - Proactively remove unnecessary approvals Current Gearbox V3 automatically resets allowances to 1 after each interaction, so this is mainly needed for legacy accounts or incident response. ### How It Works `revokeAdapterAllowances` resets token approvals from your Credit Account to specified contracts. Allowance is set to 1 (not 0) due to gas optimization. ### Basic Usage ```typescript import { encodeFunctionData } from 'viem'; import { iCreditFacadeV300MulticallAbi } from '@gearbox-protocol/sdk'; // Define which approvals to revoke const revocations = [ { spender: uniswapRouterAddress, token: usdcAddress, }, { spender: curvePoolAddress, token: daiAddress, }, ]; const calls = [ { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'revokeAdapterAllowances', args: [revocations], }), }, ]; await market.creditFacade.write.multicall([creditAccountAddress, calls]); ``` ### Check Existing Allowances ```typescript import { erc20Abi, getContract } from 'viem'; const token = getContract({ address: tokenAddress, abi: erc20Abi, client: publicClient, }); // Check allowance from Credit Account to a spender const allowance = await token.read.allowance([ creditAccountAddress, spenderAddress, ]); if (allowance > 1n) { console.log(`Credit Account has ${allowance} allowance to ${spenderAddress}`); } ``` ### Revoke All Known Adapters ```typescript // Get all adapters from Credit Manager const adapters = await creditManager.read.adapters(); // Build revocations for all adapters const revocations = adapters.map(adapter => ({ spender: adapter, token: tokenAddress, })); const calls = [ { target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'revokeAdapterAllowances', args: [revocations], }), }, ]; ``` ### Revocation Gotchas * **Usually not needed in V3** - Gearbox V3 automatically resets allowances after each adapter interaction. * **Sets to 1, not 0** - For gas efficiency, allowances are set to 1 instead of 0. An allowance of 1 wei is functionally zero. * **Target the adapter, not the protocol** - Revocations target the spender (adapter address), not the underlying protocol. * **Batch multiple revocations** - Pass multiple `(spender, token)` pairs in a single `revokeAdapterAllowances` call for efficiency. ### When to Actually Revoke Real scenarios where revocation makes sense: 1. **Third-party exploit** - A protocol Gearbox integrates with gets hacked 2. **Account migration** - Moving from V2.1 account with old allowances 3. **Compliance requirement** - Regulatory frameworks requiring revoked unused approvals 4. **Personal security policy** - Explicit control over all approvals ## Learn More * [External Calls](https://docs.gearbox.finance/developers/gm-mc-external) - How adapters use allowances * [Updating Quotas](https://docs.gearbox.finance/developers/gm-mc-quotas) - How to enable/disable quota tokens * [Slippage & Safety](https://docs.gearbox.finance/developers/gm-mc-safety) - Related safety controls ## Liquidations Source: https://docs.gearbox.finance/developers/gm-liquidations File: content/developers/gm-liquidations.mdx Liquidations close undercollateralized positions to ensure protocol solvency. Gearbox V3 supports both full liquidations (complete account closure) and partial liquidations (debt reduction while keeping the account open). ## When Liquidations Occur An account becomes liquidatable when: - **Health Factor < 1.0** (undercollateralized) - **Account has expired** (past the configured expiration timestamp) Anyone can liquidate an unhealthy account - there is no whitelist. ## Full Liquidation ### Liquidation Parameters | Parameter | Description | | ---------------- | ------------------------------------------ | | `creditAccount` | The account to liquidate | | `to` | Where liquidator receives remaining assets | | `calls` | Multicall array for converting collateral | | `lossPolicyData` | Custom data for loss handling | ### Liquidation Math | Parameter | Description | | ------------------------ | ------------------------------------------------ | | **Liquidation Premium** | % of account value liquidator receives as reward | | **Liquidation Discount** | % used to cover debt and fees (100% - Premium) | ### Outcomes **Solvent Liquidation** (totalFunds > liabilities): - Pool repaid in full - DAO receives liquidation fee - Remaining funds go to original borrower **Bad Debt** (totalFunds < liabilities): - DAO profit reduced first - If insufficient, loss reported to Pool - Pool burns Treasury shares to cover - If Treasury empty: "uncovered loss" (socialized across LPs) ### Executing a Full Liquidation ```typescript // Liquidation bot example const calls = [ // Swap collateral tokens to underlying via adapters { target: uniswapAdapterAddress, callData: encodeFunctionData({ abi: uniswapAdapterAbi, functionName: "exactAllInputSingle", args: [{ tokenIn: wbtcAddress, tokenOut: usdcAddress /* ... */ }], }), }, // Additional swaps as needed... ]; await creditFacade.write.liquidateCreditAccount([ creditAccountAddress, liquidatorAddress, // receives remaining assets calls, "0x", // lossPolicyData ]); ``` ### Internal Execution Steps 1. Calculate payments via `CreditLogic.calcLiquidationPayments` 2. Execute multicall (convert collateral to underlying) 3. Transfer `amountToPool` to the Pool 4. Remove active quotas via PoolQuotaKeeper ### Fee Types | Fee Type | Description | | ---------------------------- | --------------------------------- | | `feeLiquidation` | Standard liquidation fee to DAO | | `feeLiquidationExpired` | Higher fee for expired accounts | | `liquidationDiscount` | Discount for healthy liquidations | | `liquidationDiscountExpired` | Discount for expired liquidations | Expired accounts have higher fees to incentivize timely liquidation. --- ## Partial Liquidation Partial liquidation reduces debt while keeping the account open. This is useful when market liquidity is insufficient for full conversion or a "deleverage" strategy is preferred. ### Constraints - Account must remain open after liquidation - Must pass collateral check post-liquidation (HF >= 1) - Cannot leave "dust" debt below `minDebt` ### Executing a Partial Liquidation ```typescript const seizedAmount = await creditFacade.write.partiallyLiquidateCreditAccount([ creditAccountAddress, wbtcAddress, // token to seize parseUnits("1000", 6), // repaid USDC amount parseUnits("0.03", 8), // min BTC to receive liquidatorAddress, [], // price updates ]); ``` ### Health Factor Thresholds **Protocol Level:** - **Liquidation Trigger**: HF < 1.0 - **Post-Liquidation**: HF >= 1.0 (enforced) **Bot-Specific** (configurable in `PartialLiquidationBotV3`): - `minHealthFactor`: HF threshold for intervention - `maxHealthFactor`: Maximum HF after partial liquidation (prevents over-liquidation) --- ## RWA Liquidations RWA-backed positions use the same liquidation entrypoints as permissionless collateral, but liquidators face different capital, compliance, and unwind constraints. ### On-Chain Flow A liquidation is a swap between RWA collateral and the market underlying: the liquidator supplies underlying to repay debt and receives RWA tokens (typically to the `to` address on full liquidation, or directly on partial liquidation). There is no DEX conversion step inside the credit account. | Step | What happens | | --------------------- | ------------------------------------------------------------------------------------ | | **Liquidation tx** | Liquidator repays debt with underlying; protocol transfers RWA to the liquidator | | **After liquidation** | Liquidator redeems or disposes of RWA outside Gearbox (issuer redemption, OTC, etc.) | Redemption cannot be performed on the credit account. The liquidator must hold the RWA in their own wallet and complete issuer flows off-protocol. ### Liquidator Requirements - **Upfront capital**: Underlying must be available before the liquidation tx; debt is repaid immediately and RWA is received in the same transaction - **No market liquidity**: RWA tokens generally lack deep secondary-market liquidity, so exit timing depends on issuer redemption or other off-protocol disposal - **Duration risk**: Capital is locked until the RWA is unwound; economics depend on issuer timelines and terms, not spot DEX prices - **KYC** (if applicable): Many RWAs are permissioned; the liquidator may need issuer onboarding before they can hold or redeem the specific asset ### Entrypoints Otherwise the interface matches permissionless tokens: - Full liquidation: `liquidateCreditAccount` (often with an empty or minimal `calls` array — no adapter swaps) - Partial liquidation: `partiallyLiquidateCreditAccount` ### Additional Liquidation Flows Some RWA integrations expose helper contracts for positions that do not fit the standard RWA ↔ underlying swap. The Securitize integration is the primary example today. #### Securitize: Pending Redemption Liquidations Securitize offramp is asynchronous: when a credit account redeems DS tokens, each request is held in a dedicated `SecuritizeRedeemer` clone while Securitize processes the redemption. Stablecoins settle to the redeemer address later; until then, pending value is reflected as phantom-token collateral on the account. If the account is liquidatable but **immediate liquid balances are insufficient to cover debt** — wrapper underlying, stablecoin on the account, and stablecoin already received on redeemers (after liquidation discount) — use `SecuritizeLiquidator` instead of calling `liquidateCreditAccount` directly. That path transfers **unclaimed redeemers** to the liquidator and closes the account in one transaction. | Condition | Use | | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | | Discounted liquid balances on account + redeemers ≥ total debt | Standard `liquidateCreditAccount` | | Liquid balances < total debt, but collateral (including pending redemptions at **current NAV**) supports closure | `SecuritizeLiquidator.liquidatePendingRedemption` | **What the liquidator receives** - Ownership of each unclaimed `SecuritizeRedeemer` (transferred to `msg.sender` via the redemption gateway adapter) - Any DS token balance withdrawn from the credit account - Stablecoin on redeemers can be claimed later through normal Securitize flows once settlement arrives The liquidator still supplies **upfront underlying** (computed from collateral value and liquidation discount). The helper pulls it from the caller, adds it as collateral, and invokes `liquidateCreditAccount` with a composed multicall. Pending redemption value in this path uses **current NAV** (not the conservative `min(starting, current)` cap used for passive collateral), so liquidation pricing reflects the NAV at liquidation time. ```typescript const phantomToken = getContract({ address: redemptionPhantomTokenAddress, abi: securitizeRedemptionPhantomTokenAbi, client: publicClient, }); const redemptionGatewayAddress = await phantomToken.read.redemptionGateway(); const redemptionGateway = getContract({ address: redemptionGatewayAddress, abi: securitizeRedemptionGatewayAbi, client: publicClient, }); const securitizeLiquidator = getContract({ address: await redemptionGateway.read.transferMaster(), abi: securitizeLiquidatorAbi, client: walletClient, }); await securitizeLiquidator.write.liquidatePendingRedemption([ creditAccountAddress, redemptionGatewayAddress, priceUpdates, // optional PriceFeedStore updates "0x", // lossPolicyData ]); ``` The liquidator can then claim the settled redemption via `SecuritizeRedeemer.claim` (called through the redemption gateway once stablecoin has arrived on the redeemer clones): ```typescript const redeemers = await redemptionGateway.read.getUnclaimedRedeemers([ liquidatorAddress, ]); const stableCoin = getContract({ address: await redemptionGateway.read.stableCoinToken(), abi: erc20Abi, client: publicClient, }); const settledRedeemers: Address[] = []; for (const redeemer of redeemers) { const balance = await stableCoin.read.balanceOf([redeemer]); if (balance > 0n) settledRedeemers.push(redeemer); } await redemptionGateway.write.claim([settledRedeemers]); ``` **Liquidator requirements** - Securitize **KYC / wallet allowlisting** for the address that receives redeemers (`msg.sender` must be an approved Securitize investor wallet) - **Upfront underlying** approved to `SecuritizeLiquidator` for the computed `underlyingAmount` - **Duration risk** on redeemers until Securitize settles stablecoins to them; the liquidator claims via the redemption gateway after settlement - Market must use the Securitize collateral set (wrapper underlying, stablecoin, DS token, redemption phantom token) with a single configured redemption gateway --- ## Emergency Liquidations ### Regular vs Emergency | Type | When | Who | | ------------- | ----------------------------- | -------------------------------- | | **Regular** | Protocol functioning normally | Anyone | | **Emergency** | Protocol/Facade paused | `EMERGENCY_LIQUIDATOR` role only | Emergency liquidations ensure positions can be closed even during protocol pause, preventing bad debt accumulation. ### Treasury Backstop The `TreasuryLiquidator` contract allows the DAO treasury to provide emergency liquidity when external liquidators are absent, acting as a backstop during extreme market conditions. --- ## Checking If an Account Is Liquidatable ```typescript const creditFacade = getContract({ address: facadeAddress, abi: creditFacadeV3Abi, client: publicClient, }); const creditManager = getContract({ address: cmAddress, abi: creditManagerV3Abi, client: publicClient, }); // Get health factor const debtData = await creditManager.read.calcDebtAndCollateral([ creditAccount, 2, // DEBT_COLLATERAL ]); const hf = (debtData.twvUSD * 10000n) / debtData.totalDebtUSD; // Check expiration const expirationDate = await creditFacade.read.expirationDate(); const isExpired = BigInt(Math.floor(Date.now() / 1000)) > expirationDate; const isLiquidatable = hf < 10000n || isExpired; console.log(`Liquidatable: ${isLiquidatable}, HF: ${Number(hf) / 100}%`); ``` ## Learn More - [Credit Accounts](https://docs.gearbox.finance/developers/gm-accounts) - Account data and querying - [External Calls](https://docs.gearbox.finance/developers/gm-mc-external) - Adapter calls used during liquidation multicalls - [Slippage & Safety](https://docs.gearbox.finance/developers/gm-mc-safety) - Price feeds and collateral checks ## Operations Reference Source: https://docs.gearbox.finance/developers/operations-reference-2 File: content/developers/operations-reference-2.mdx Detailed guides for encoding each multicall operation in Solidity. > For TypeScript/SDK implementation, see [Multicalls](https://docs.gearbox.finance/developers/multicalls). ## Why This Section? The main [multicalls.md](https://docs.gearbox.finance/developers/multicalls) covers the fundamentals: MultiCall struct encoding, call order, and the diff pattern. This section goes deeper on each operation - when you need it, complete Solidity examples, and what can go wrong. ## Quick Reference | Operation | Function | When to Use | Guide | | -------------------- | ------------------------------------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- | | Add Collateral | `addCollateral` | Deposit tokens to increase health factor | [Adding Collateral](https://docs.gearbox.finance/developers/adding-collateral) | | Increase Debt | `increaseDebt` | Borrow from pool | [Debt Management](https://docs.gearbox.finance/developers/debt-management) | | Decrease Debt | `decreaseDebt` | Repay borrowed funds | [Debt Management](https://docs.gearbox.finance/developers/debt-management) | | Update Quota | `updateQuota` | Enable/adjust quota token exposure | [Updating Quotas](https://docs.gearbox.finance/developers/updating-quotas) | | Withdraw Collateral | `withdrawCollateral` | Remove tokens from account | [Withdrawing Collateral](https://docs.gearbox.finance/developers/withdrawing-collateral) | | Slippage Control | `storeExpectedBalances` / `compareBalances` | Protect swaps from sandwich attacks | [Controlling Slippage](https://docs.gearbox.finance/developers/controlling-slippage) | | External Calls | Adapter-specific | Interact with Uniswap, Curve, etc. | [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls) | | Enable/Disable Token | `enableToken` / `disableToken` | Explicit collateral management | [Enabling/Disabling Tokens](https://docs.gearbox.finance/developers/enabling-disabling-tokens) | | Price Updates | `onDemandPriceUpdate` | Update Pyth/Redstone feeds | [Updating Price Feeds](https://docs.gearbox.finance/developers/updating-price-feeds) | | Check Params | `setFullCheckParams` | Optimize gas, set min health factor | [Collateral Check Params](https://docs.gearbox.finance/developers/collateral-check-params) | | Revoke Allowances | `revokeAdapterAllowances` | Security measure after suspicious activity | [Revoke Allowances](https://docs.gearbox.finance/developers/revoke-allowances) | ## Page Structure Each operation guide follows the same structure: 1. **Why** - When you need this operation 2. **What** - What it does and how it fits the system 3. **How** - Working Solidity code 4. **Gotchas** - Common mistakes and edge cases 5. **See Also** - Related operations and SDK reference ## Core Encoding Pattern All multicall operations use the same encoding pattern: ```solidity import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; MultiCall[] memory calls = new MultiCall[](1); calls[0] = MultiCall({ target: creditFacade, // or adapter address for external calls callData: abi.encodeCall( ICreditFacadeV3Multicall.functionName, (param1, param2, ...) ) }); ICreditFacadeV3(creditFacade).multicall(creditAccount, calls); ``` ## Call Order Requirements Some operations have strict ordering rules: 1. **Price updates (`onDemandPriceUpdate`)** - Must be first in the calls array 2. **Collateral check params (`setFullCheckParams`)** - Should be early, affects final check 3. **External calls** - Can be anywhere after price updates 4. **Slippage checks** - `storeExpectedBalances` before swaps, `compareBalances` after ## Import Patterns Standard imports for multicall operations: ```solidity // Core interfaces import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; // For slippage protection import {BalanceDelta} from "@gearbox-protocol/core-v3/contracts/libraries/BalancesLogic.sol"; // For allowance revocation import {RevocationPair} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; // Adapter interfaces (examples) import {IUniswapV3Adapter} from "@gearbox-protocol/integrations-v3/contracts/interfaces/uniswap/IUniswapV3Adapter.sol"; import {IYearnV2Adapter} from "@gearbox-protocol/integrations-v3/contracts/interfaces/yearn/IYearnV2Adapter.sol"; ``` ## Related * [Multicalls Overview](https://docs.gearbox.finance/developers/multicalls) - Fundamentals and the diff pattern * [Credit Manager](https://docs.gearbox.finance/developers/credit-manager) - Underlying execution layer * [SDK Multicalls](https://docs.gearbox.finance/developers/multicalls) - TypeScript implementation ## Adding Collateral Source: https://docs.gearbox.finance/developers/adding-collateral-2 File: content/developers/adding-collateral-2.mdx Deposit tokens from an external address to a Credit Account. > For SDK implementation, see [Adding Collateral](https://docs.gearbox.finance/developers/adding-collateral). ## Why You need to add collateral when: * **Opening an account** - Initial deposit to enable borrowing * **Improving health factor** - Account approaching liquidation threshold * **Enabling more borrowing** - Current collateral limits how much you can borrow Adding collateral increases your account's total weighted value (TWV), which improves the health factor and allows larger debt positions. ## What `addCollateral` transfers tokens from the caller to the Credit Account. On execution: 1. The Credit Manager calls `transferFrom` to move tokens from caller to Credit Account 2. The token is enabled as collateral (if not already enabled) 3. Quoted tokens are NOT auto-enabled - you must set a quota separately **Important:** Approve tokens to the **Credit Manager**, not the Credit Facade. The Credit Manager is the contract that actually executes the transfer. ## How ```solidity import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; address creditFacade; address creditManager; address usdc; address creditAccount; address owner; MultiCall[] memory calls = new MultiCall[](1); // Add 10,000 USDC as collateral calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.addCollateral, (usdc, 10_000 * 10**6) ) }); // First, approve tokens to Credit Manager (not Facade!) IERC20(usdc).approve(creditManager, 10_000 * 10**6); // Execute on existing account ICreditFacadeV3(creditFacade).multicall(creditAccount, calls); // Or open new account with collateral ICreditFacadeV3(creditFacade).openCreditAccount(owner, calls, 0); ``` ### Using Permit (No Separate Approval) For EIP-2612 compatible tokens, avoid the separate approval transaction: ```solidity // Sign permit off-chain, then use addCollateralWithPermit calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.addCollateralWithPermit, (usdc, 10_000 * 10**6, deadline, v, r, s) ) }); ``` ## Gotchas ### Approve to Credit Manager, Not Facade The most common mistake. The Credit Manager executes the `transferFrom`, so it needs the approval: ```solidity // CORRECT IERC20(token).approve(creditManager, amount); // WRONG - will fail IERC20(token).approve(creditFacade, amount); ``` ### Quoted Tokens Need Quota Adding a quoted token as collateral does NOT automatically enable it. You must also call `updateQuota`: ```solidity MultiCall[] memory calls = new MultiCall[](2); calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.addCollateral, (quotedToken, amount) ) }); calls[1] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.updateQuota, (quotedToken, int96(quotaAmount), uint96(minQuota)) ) }); ``` ### Direct Transfers Don't Enable Sending tokens directly to a Credit Account (via `transfer`) does NOT enable them as collateral. You still need a multicall with the proper operation to count them in the health factor. ### Invalid Collateral Tokens Only tokens recognized by the Credit Manager can be used as collateral. Transferring unrecognized tokens to a Credit Account may result in them being stuck (only governance can recover). Check if a token is valid: ```solidity // This reverts if token is not valid collateral uint256 mask = ICreditManagerV3(creditManager).getTokenMaskOrRevert(token); ``` ## See Also * [Withdrawing Collateral](https://docs.gearbox.finance/developers/withdrawing-collateral) - The reverse operation * [Debt Management](https://docs.gearbox.finance/developers/debt-management) - Often combined with adding collateral * [Updating Quotas](https://docs.gearbox.finance/developers/updating-quotas) - Required for quoted tokens ## Bot System Source: https://docs.gearbox.finance/developers/gm-bots File: content/developers/gm-bots.mdx Gearbox features a granular bot permission system that allows automated management of Credit Accounts. Bots can execute operations on behalf of account owners with specific, revocable permissions. ## Architecture | Component | Description | | --- | --- | | **BotListV3** | Registry storing `(bot, creditManager, creditAccount) → permissions` | | **IBot interface** | Bots implement `requiredPermissions()` to declare needed permissions | | **CreditFacadeV3** | Entry point for bot execution via `botMulticall` | ## Permission Model Permissions are stored as a `uint192` bitmask. Account owners grant specific permissions to specific bots: | Permission | Operation | | --- | --- | | `ADD_COLLATERAL` | Add funds to account | | `INCREASE_DEBT` | Borrow more from pool | | `DECREASE_DEBT` | Repay debt | | `WITHDRAW_COLLATERAL` | Withdraw assets | | `UPDATE_QUOTA` | Change token quotas | | `SET_BOT_PERMISSIONS` | Manage other bots | | `EXTERNAL_CALLS` | Execute adapter calls | ## Granting Permissions Account owners grant permissions via a multicall operation: ```typescript const calls = [ service.setBotPermissions( creditAccount, botAddress, ADD_COLLATERAL_PERMISSION | EXTERNAL_CALLS_PERMISSION ), ]; await facade.multicall(creditAccount, calls); ``` ## Bot Execution Bots execute via `botMulticall` on the Credit Facade: ```typescript // Bot calls botMulticall with the account and operations await facade.botMulticall(creditAccount, [ service.addCollateral(creditAccount, tokenAddress, amount), // ... other permitted operations ]); ``` The Facade checks the bot's permissions before each operation. If a bot attempts an unpermitted action, the transaction reverts. ## Safety Model - **Isolation** — each permission grant is scoped to a specific `(bot, creditManager, creditAccount)` tuple - **Immutability** — bots cannot modify their own permissions - **DAO forbid list** — the DAO can globally forbid malicious bots - **Collateral check** — bot multicalls undergo the same solvency check as user multicalls ## Revoking Permissions ```typescript // Revoke all permissions for a bot await facade.multicall(creditAccount, [ service.setBotPermissions(creditAccount, botAddress, 0), ]); ``` ## Learn More - [Liquidation Bots Guide](https://docs.gearbox.finance/developers/gm-guide-bots) — Building a complete liquidation bot - [Credit Accounts](https://docs.gearbox.finance/developers/gm-accounts) — Account lifecycle and operations - [Multicalls](https://docs.gearbox.finance/developers/gm-accounts-multicalls) — Building multicall transactions ## Debt Management Source: https://docs.gearbox.finance/developers/debt-management-2 File: content/developers/debt-management-2.mdx Borrow and repay the underlying token. > For SDK implementation, see [Debt Management](https://docs.gearbox.finance/developers/debt-management). ## Why Debt management enables leveraged positions: * **Increase debt** - Borrow to deploy capital into DeFi strategies * **Decrease debt** - Repay to reduce interest costs or close position * **Partial repayment** - Reduce exposure while keeping position open Debt directly affects your health factor. Higher debt lowers health factor; lower debt raises it. ## What Two operations manage debt: | Operation | Description | | -------------- | ------------------------------------- | | `increaseDebt` | Borrow underlying token from the pool | | `decreaseDebt` | Repay underlying token to the pool | ### Increase Debt Flow 1. Pool transfers underlying to Credit Account 2. Debt counter incremented 3. Interest starts accruing immediately ### Decrease Debt Flow 1. Underlying transferred from Credit Account to pool 2. Debt counter decremented 3. Full repayment enables special "zero debt" mode ## How ### Borrowing ```solidity import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; address creditFacade; address creditAccount; MultiCall[] memory calls = new MultiCall[](1); // Borrow 40,000 USDC calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.increaseDebt, (40_000 * 10**6) ) }); ICreditFacadeV3(creditFacade).multicall(creditAccount, calls); ``` ### Repaying ```solidity // Repay 10,000 USDC calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.decreaseDebt, (10_000 * 10**6) ) }); // Or repay everything calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.decreaseDebt, (type(uint256).max) // Full repayment ) }); ``` ### Combined Strategy: Add Collateral + Borrow Typical account opening pattern: ```solidity MultiCall[] memory calls = new MultiCall[](2); // 1. Add initial collateral calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.addCollateral, (usdc, 10_000 * 10**6) // 10k USDC as collateral ) }); // 2. Borrow against it calls[1] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.increaseDebt, (40_000 * 10**6) // Borrow 40k USDC (4x leverage) ) }); // Approve collateral to Credit Manager first IERC20(usdc).approve(creditManager, 10_000 * 10**6); // Open account with collateral and debt ICreditFacadeV3(creditFacade).openCreditAccount(owner, calls, 0); ``` ## Gotchas ### Same-Block Restriction Debt cannot be increased AND decreased in the same block: ```solidity // Block N: increase debt ICreditFacadeV3(creditFacade).multicall(account, increaseCalls); // Block N: try to decrease - REVERTS! ICreditFacadeV3(creditFacade).multicall(account, decreaseCalls); // Block N+1: now decrease works ICreditFacadeV3(creditFacade).multicall(account, decreaseCalls); ``` ### Debt Limits The resulting debt must be within configured limits: ```solidity (uint128 minDebt, uint128 maxDebt) = ICreditFacadeV3(creditFacade).debtLimits(); // Debt after operation must satisfy: // 0 (for full closure) OR minDebt <= debt <= maxDebt ``` ### Per-Block Borrowing Limit Total borrowing in a block is limited: ```solidity uint8 multiplier = ICreditFacadeV3(creditFacade).maxDebtPerBlockMultiplier(); // maxDebtPerBlock = maxDebt * multiplier // If block limit reached, increaseDebt reverts ``` ### Forbidden Tokens Block Borrowing If account has forbidden tokens enabled as collateral, borrowing is blocked: ```solidity // This reverts if account has forbidden tokens ICreditFacadeV3Multicall.increaseDebt(amount); ``` Solution: Swap forbidden tokens to allowed ones first. ### Zero Debt Mode Full repayment (`decreaseDebt(type(uint256).max)`) enables zero debt mode: * Collateral checks are skipped * All quotas must be disabled (zero) * Account can be closed without collateral check ```solidity MultiCall[] memory calls = new MultiCall[](2); // 1. Disable all quotas first calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.updateQuota, (quotedToken, type(int96).min, 0) // Disable quota ) }); // 2. Full repayment calls[1] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.decreaseDebt, (type(uint256).max) ) }); ``` ### Opening vs Closing Restrictions | Operation | On Open | On Close | | -------------- | ---------- | ---------- | | `increaseDebt` | Allowed | Prohibited | | `decreaseDebt` | Prohibited | Allowed | ```solidity // Opening: can only borrow openCreditAccount(owner, [increaseDebtCall], 0); // OK openCreditAccount(owner, [decreaseDebtCall], 0); // REVERTS // Closing: can only repay closeCreditAccount(account, [decreaseDebtCall]); // OK closeCreditAccount(account, [increaseDebtCall]); // REVERTS ``` ## See Also * [Adding Collateral](https://docs.gearbox.finance/developers/adding-collateral) - Add before borrowing * [Updating Quotas](https://docs.gearbox.finance/developers/updating-quotas) - Enable quoted tokens as collateral * [Controlling Slippage](https://docs.gearbox.finance/developers/controlling-slippage) - Protect borrowed funds during swaps ## Updating Quotas Source: https://docs.gearbox.finance/developers/updating-quotas-2 File: content/developers/updating-quotas-2.mdx Manage collateral quotas for quoted tokens. > For SDK implementation, see [Updating Quotas](https://docs.gearbox.finance/developers/updating-quotas). ## Why Quotas are required for non-underlying tokens to count as collateral: * **Enable collateral** - Purchase quota to enable a token as collateral * **Increase exposure** - Raise quota limit to hold more of a token * **Reduce fees** - Lower quota to reduce ongoing quota fees * **Disable collateral** - Set quota to zero to disable token Without a quota, holding a token on a Credit Account with debt risks losing it to liquidators since it doesn't count toward your health factor. ## What `updateQuota` changes the quota for a specific token. On execution: 1. Quota change is applied (can be positive or negative) 2. If quota goes from zero to positive, token is enabled as collateral 3. If quota goes to zero, token is disabled as collateral 4. Quota fees are applied based on the change | Parameter | Type | Description | | ------------- | ------- | ---------------------------------------------- | | `token` | address | The quoted token (cannot be underlying) | | `quotaChange` | int96 | Delta in underlying units (negative to reduce) | | `minQuota` | uint96 | Minimum resulting quota to not revert | ## How ### Enable a Token as Collateral ```solidity import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; address creditFacade; address creditAccount; address weth; MultiCall[] memory calls = new MultiCall[](1); // Enable WETH with 50,000 USDC quota calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.updateQuota, (weth, int96(50_000 * 10**6), uint96(50_000 * 10**6)) ) }); ICreditFacadeV3(creditFacade).multicall(creditAccount, calls); ``` ### Increase Existing Quota ```solidity // Add 25,000 USDC to existing quota calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.updateQuota, (weth, int96(25_000 * 10**6), uint96(75_000 * 10**6)) // minQuota = expected total ) }); ``` ### Decrease Quota ```solidity // Reduce quota by 20,000 USDC calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.updateQuota, (weth, int96(-20_000 * 10**6), uint96(0)) // minQuota = 0 (any remaining is fine) ) }); ``` ### Disable Token Completely Use `type(int96).min` to fully disable: ```solidity // Completely disable WETH as collateral calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.updateQuota, (weth, type(int96).min, uint96(0)) ) }); ``` ### Combined: Add Token + Set Quota When adding a quoted token as collateral, always pair with quota update: ```solidity MultiCall[] memory calls = new MultiCall[](2); // 1. Add the token calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.addCollateral, (quotedToken, amount) ) }); // 2. Enable it with quota calls[1] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.updateQuota, (quotedToken, int96(quotaAmount), uint96(quotaAmount)) ) }); ``` ## Gotchas ### Account Must Have Debt Quotas can only be updated when the account has non-zero debt: ```solidity // This reverts if debt == 0 ICreditFacadeV3Multicall.updateQuota(token, change, minQuota); ``` For zero-debt accounts, first borrow, then update quotas. ### Forbidden Tokens Cannot Increase If a token is forbidden, you cannot increase its quota: ```solidity // Reverts if WETH is forbidden updateQuota(weth, int96(1000 * 10**6), 0); // But you CAN decrease or disable updateQuota(weth, int96(-1000 * 10**6), 0); // OK updateQuota(weth, type(int96).min, 0); // OK ``` ### Quota Limits Each market has per-account quota limits: ```solidity // Check the limit uint96 maxQuota = IPoolQuotaKeeperV3(quotaKeeper).getQuotaLimit(token); // Resulting quota must be <= maxQuota ``` ### Quota Fees Quotas incur ongoing fees: * **Increase fee**: One-time fee on quota increase * **Quota rate**: Ongoing rate (similar to interest) on quota amount Check rates before setting large quotas: ```solidity (uint16 rate, uint192 cumulativeIndexLU, uint96 quotaIncreaseFee) = IPoolQuotaKeeperV3(quotaKeeper).getQuotaRate(token); ``` ### minQuota Parameter Use `minQuota` to prevent front-running: ```solidity // If someone reduces your quota before your tx, this reverts instead of accepting less updateQuota(token, int96(50_000e6), uint96(50_000e6)); // With minQuota = 0, any resulting quota is accepted (more gas efficient but risky) updateQuota(token, int96(50_000e6), uint96(0)); ``` ### Zero Debt Closure Requirement Before closing with zero debt, all quotas must be disabled: ```solidity MultiCall[] memory calls = new MultiCall[](3); // 1. Disable all quotas calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.updateQuota, (quotedToken1, type(int96).min, 0) ) }); calls[1] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.updateQuota, (quotedToken2, type(int96).min, 0) ) }); // 2. Repay all debt calls[2] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.decreaseDebt, (type(uint256).max) ) }); ``` ## See Also * [Adding Collateral](https://docs.gearbox.finance/developers/adding-collateral) - Add tokens before setting quota * [Debt Management](https://docs.gearbox.finance/developers/debt-management) - Debt required for quota updates * [Enabling/Disabling Tokens](https://docs.gearbox.finance/developers/enabling-disabling-tokens) - Token state management ## Withdrawing Collateral Source: https://docs.gearbox.finance/developers/withdrawing-collateral-2 File: content/developers/withdrawing-collateral-2.mdx Remove tokens from a Credit Account to an external address. > For SDK implementation, see [Withdrawing Collateral](https://docs.gearbox.finance/developers/withdrawing-collateral). ## Why You need to withdraw collateral when: * **Taking profits** - Remove excess collateral while maintaining healthy position * **Rebalancing** - Move funds between accounts or protocols * **Closing account** - Extract all remaining tokens before closing Withdrawing collateral decreases your account's total weighted value (TWV), which lowers the health factor. ## What `withdrawCollateral` transfers tokens from the Credit Account to a specified recipient. On execution: 1. Tokens are transferred from the Credit Account to the recipient 2. If withdrawing the full balance, the token may be disabled as collateral 3. Safe pricing is activated for the collateral check (uses min of main and reserve price feeds) **Important:** Withdrawals trigger stricter collateral checks using safe prices, so ensure sufficient buffer above the liquidation threshold. ## How ```solidity import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; address creditFacade; address usdc; address creditAccount; address recipient; MultiCall[] memory calls = new MultiCall[](1); // Withdraw 5,000 USDC calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.withdrawCollateral, (usdc, 5_000 * 10**6, recipient) ) }); ICreditFacadeV3(creditFacade).multicall(creditAccount, calls); ``` ### Withdraw Full Balance Use `type(uint256).max` to withdraw the entire token balance: ```solidity // Withdraw all USDC from the account calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.withdrawCollateral, (usdc, type(uint256).max, recipient) ) }); ``` ### Withdraw During Closure When closing an account, you can withdraw all tokens to yourself: ```solidity MultiCall[] memory calls = new MultiCall[](2); // Repay all debt first calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.decreaseDebt, (type(uint256).max) ) }); // Withdraw all collateral calls[1] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.withdrawCollateral, (token, type(uint256).max, recipient) ) }); ICreditFacadeV3(creditFacade).closeCreditAccount(creditAccount, calls); ``` ## Gotchas ### Safe Prices Are Used After withdrawal, collateral checks use safe pricing (minimum of main and reserve feeds). This means: * Your effective collateral value may be lower than expected * Maintain buffer above liquidation threshold * Check safe prices before withdrawing large amounts ### Forbidden Tokens Block Withdrawal If any forbidden token is enabled as collateral on the account, withdrawals are blocked in multicalls: ```solidity // This will revert if the account has forbidden tokens enabled ICreditFacadeV3(creditFacade).multicall(creditAccount, withdrawCalls); ``` Solution: First swap forbidden tokens to allowed ones, then withdraw. ### Phantom Token Unwrapping If the token being withdrawn is a phantom token (e.g., staked position token), it's automatically unwrapped: 1. Phantom token is withdrawn from the vault/pool 2. The underlying deposited token is sent to the recipient 3. No slippage protection - assumed to happen at non-manipulatable rate ### Dust Handling For clean account closure, use `type(uint256).max` to handle dust amounts: ```solidity // This handles any remaining wei callData: abi.encodeCall( ICreditFacadeV3Multicall.withdrawCollateral, (token, type(uint256).max, recipient) ) ``` ### Recipient Validation The recipient address must be a valid address. Common patterns: ```solidity // Withdraw to account owner withdrawCollateral(token, amount, owner); // Withdraw to another protocol/contract withdrawCollateral(token, amount, anotherContract); // NEVER use address(0) - tokens will be lost! ``` ## See Also * [Adding Collateral](https://docs.gearbox.finance/developers/adding-collateral) - The reverse operation * [Debt Management](https://docs.gearbox.finance/developers/debt-management) - Repay debt before large withdrawals * [Enabling/Disabling Tokens](https://docs.gearbox.finance/developers/enabling-disabling-tokens) - Token state management ## Controlling Slippage Source: https://docs.gearbox.finance/developers/controlling-slippage-2 File: content/developers/controlling-slippage-2.mdx Protect against price movement during swaps and other operations. > For SDK implementation, see [Controlling Slippage](https://docs.gearbox.finance/developers/controlling-slippage). ## Why Slippage protection is critical for: * **Swaps** - Ensure minimum output from DEX trades * **Deposits/Withdrawals** - Protect against unfavorable rates * **Multi-step strategies** - Verify final position matches expectations Without slippage protection, MEV bots can sandwich your transactions, extracting value through price manipulation. ## What Two operations work together for slippage control: | Operation | Description | | ----------------------- | -------------------------------------------------------- | | `storeExpectedBalances` | Record expected token balances (current + delta) | | `compareBalances` | Verify current balances meet expectations, revert if not | The pattern: Store expectations before swaps, compare after swaps. ## How ### Basic Slippage Check ```solidity import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; import {BalanceDelta} from "@gearbox-protocol/core-v3/contracts/libraries/BalancesLogic.sol"; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; address creditFacade; address creditAccount; address usdc; address weth; address uniswapAdapter; // Calculate minimum expected output (with 0.5% slippage tolerance) // If swapping 50,000 USDC at rate of 2000 USDC/ETH: // Expected: 25 ETH, with 0.5% slippage: 24.875 ETH int256 minWethOut = int256(24.875 ether); MultiCall[] memory calls = new MultiCall[](3); // 1. Store expected balance (current + delta) BalanceDelta[] memory deltas = new BalanceDelta[](1); deltas[0] = BalanceDelta({ token: weth, amount: minWethOut // Can be negative for tokens spent }); calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.storeExpectedBalances, (deltas) ) }); // 2. Perform swap via adapter calls[1] = MultiCall({ target: uniswapAdapter, callData: abi.encodeCall( IUniswapV3Adapter.exactInputSingle, (swapParams) ) }); // 3. Compare balances - reverts if WETH balance < expected calls[2] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.compareBalances, () ) }); ICreditFacadeV3(creditFacade).multicall(creditAccount, calls); ``` ### Multiple Token Checks Check multiple tokens in one comparison: ```solidity BalanceDelta[] memory deltas = new BalanceDelta[](2); // Expect to receive WETH deltas[0] = BalanceDelta({ token: weth, amount: int256(minWethOut) }); // Expect to spend USDC (negative delta) deltas[1] = BalanceDelta({ token: usdc, amount: -int256(maxUsdcIn) }); calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.storeExpectedBalances, (deltas) ) }); ``` ### Complete Strategy with Slippage Protection 8-step leveraged yield farming with full slippage protection: ```solidity MultiCall[] memory calls = new MultiCall[](8); // 1. Price update (if using pull oracles) calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.onDemandPriceUpdate, (yvWETH, false, priceData) ) }); // 2. Add collateral calls[1] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.addCollateral, (usdc, 10_000 * 10**6) ) }); // 3. Borrow calls[2] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.increaseDebt, (40_000 * 10**6) ) }); // 4. Store expected: min yvWETH output after swap + deposit // 50k USDC -> ~25 WETH -> ~25 yvWETH, minus 0.5% slippage BalanceDelta[] memory deltas = new BalanceDelta[](1); deltas[0] = BalanceDelta({ token: yvWETH, amount: int256(24.875 ether) }); calls[3] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.storeExpectedBalances, (deltas) ) }); // 5. Swap USDC -> WETH calls[4] = MultiCall({ target: uniswapAdapter, callData: abi.encodeCall(IUniswapV3Adapter.exactInputSingle, (swapParams)) }); // 6. Deposit WETH -> yvWETH (using diff pattern) calls[5] = MultiCall({ target: yearnAdapter, callData: abi.encodeCall(IYearnV2Adapter.depositDiff, (1)) // Leave 1 wei }); // 7. Compare balances - CRITICAL slippage check calls[6] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.compareBalances, () ) }); // 8. Set quota for yvWETH calls[7] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.updateQuota, (yvWETH, int96(50_000 * 10**6), uint96(50_000 * 10**6)) ) }); ``` ## Gotchas ### Expected Balances Must Not Already Be Set `storeExpectedBalances` reverts if already called without a `compareBalances`: ```solidity // First store - OK storeExpectedBalances(deltas1); // Second store without compare - REVERTS storeExpectedBalances(deltas2); // Correct pattern: storeExpectedBalances(deltas1); // ... operations ... compareBalances(); storeExpectedBalances(deltas2); // Now OK ``` ### Compare Reverts If Not Stored `compareBalances` reverts if no expected balances were stored: ```solidity // This reverts - nothing to compare against compareBalances(); ``` ### Delta Calculation The delta is added to CURRENT balance, not starting balance: ```solidity // If account has 10 WETH and you set delta = +5 // Expected balance = 10 + 5 = 15 WETH // For spending tokens, use negative delta // If spending up to 1000 USDC: BalanceDelta({token: usdc, amount: -1000 * 10**6}) ``` ### Available in All Multicalls Unlike most operations, slippage checks work in: * `openCreditAccount` * `multicall` * `closeCreditAccount` * `botMulticall` * `liquidateCreditAccount` ### Gas Optimization For simple swaps, you can rely on the DEX's slippage parameter: ```solidity // Uniswap's amountOutMinimum is often sufficient ISwapRouter.ExactInputSingleParams({ // ... amountOutMinimum: minWethOut, // Built-in slippage protection // ... }) ``` Use `storeExpectedBalances`/`compareBalances` for: * Multi-hop routes where intermediate tokens aren't checked * Complex strategies with multiple operations * When you need to check multiple tokens atomically ## See Also * [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls) - Swap via adapters * [Updating Price Feeds](https://docs.gearbox.finance/developers/updating-price-feeds) - Price updates before operations * [The Diff Pattern](https://docs.gearbox.finance/developers/overview-2) - Handling unknown amounts ## Making External Calls Source: https://docs.gearbox.finance/developers/making-external-calls-2 File: content/developers/making-external-calls-2.mdx Interact with DeFi protocols through adapters. > For SDK implementation, see [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls). ## Why External calls enable Credit Accounts to: * **Swap tokens** - Trade via Uniswap, Curve, Balancer * **Provide liquidity** - Add to LP pools * **Stake** - Deposit into yield protocols (Yearn, Convex, Aura) * **Leverage farm** - Build complex DeFi strategies All external interactions go through adapters - specialized contracts that translate Credit Account calls to protocol-specific formats. ## What Adapters wrap external protocol contracts. On execution: 1. Credit Account calls adapter (not the protocol directly) 2. Adapter translates the call and executes on the target protocol 3. Adapter routes output tokens back to Credit Account 4. Token states are updated automatically **Important:** Never call external protocols directly from a Credit Account. Only use registered adapters. ## How ### Finding Adapters Get the adapter address for a target protocol: ```solidity address uniswapRouter = 0x...; // Target protocol contract address uniswapAdapter = ICreditManagerV3(creditManager).contractToAdapter(uniswapRouter); require(uniswapAdapter != address(0), "Adapter not found"); ``` ### Basic Swap via Uniswap ```solidity import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {ISwapRouter} from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol"; import {IUniswapV3Adapter} from "@gearbox-protocol/integrations-v3/contracts/interfaces/uniswap/IUniswapV3Adapter.sol"; address creditFacade; address creditAccount; address creditManager; address usdc; address weth; // Get the Uniswap V3 adapter address uniswapRouter = 0xE592427A0AEce92De3Edee1F18E0157C05861564; address uniswapAdapter = ICreditManagerV3(creditManager).contractToAdapter(uniswapRouter); MultiCall[] memory calls = new MultiCall[](1); // Encode the swap params ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({ tokenIn: usdc, tokenOut: weth, fee: 500, // 0.05% pool recipient: address(0), // Adapter overrides to credit account deadline: block.timestamp + 3600, amountIn: 50_000 * 10**6, amountOutMinimum: 0, // Use Gearbox slippage check instead sqrtPriceLimitX96: 0 }); calls[0] = MultiCall({ target: uniswapAdapter, callData: abi.encodeCall(IUniswapV3Adapter.exactInputSingle, (params)) }); ICreditFacadeV3(creditFacade).multicall(creditAccount, calls); ``` ### Using the Diff Pattern When you don't know the exact input amount (e.g., after a previous swap), use diff functions: ```solidity // After swapping to WETH, deposit all but 1 wei to Yearn address yearnVault = 0x...; // yvWETH address address yearnAdapter = ICreditManagerV3(creditManager).contractToAdapter(yearnVault); calls[1] = MultiCall({ target: yearnAdapter, callData: abi.encodeCall( IYearnV2Adapter.depositDiff, (1) // Leave 1 wei of WETH, deposit the rest ) }); ``` ### Multi-Protocol Strategy Swap on Uniswap, then stake in Convex: ```solidity MultiCall[] memory calls = new MultiCall[](3); // 1. Swap USDC -> WETH on Uniswap calls[0] = MultiCall({ target: uniswapAdapter, callData: abi.encodeCall(IUniswapV3Adapter.exactInputSingle, (swapParams)) }); // 2. Swap WETH -> stETH on Curve calls[1] = MultiCall({ target: curveAdapter, callData: abi.encodeCall( ICurveV1Adapter.exchange, (0, 1, wethAmount, minStethOut) ) }); // 3. Deposit stETH to Convex (using diff) calls[2] = MultiCall({ target: convexBoosterAdapter, callData: abi.encodeCall( IConvexV1BoosterAdapter.depositDiff, (convexPoolId, 1, true) // Leave 1 wei, stake = true ) }); ``` ### Balancer Multi-Hop Swap ```solidity import {IBalancerV2VaultAdapter, SingleSwap, SwapKind} from "..."; SingleSwap memory singleSwap = SingleSwap({ poolId: balancerPoolId, kind: SwapKind.GIVEN_IN, assetIn: IAsset(usdc), assetOut: IAsset(weth), amount: 50_000 * 10**6, userData: "" }); calls[0] = MultiCall({ target: balancerAdapter, callData: abi.encodeCall( IBalancerV2VaultAdapter.swap, (singleSwap, fundManagement, 0, block.timestamp + 3600) ) }); ``` ## Gotchas ### Recipient is Always Credit Account Adapters override the recipient parameter: ```solidity // Even if you specify a different recipient... params.recipient = someOtherAddress; // ...the adapter routes output to the Credit Account // This is a security feature - you can't extract funds via adapters ``` ### Approvals are Handled Automatically Adapters manage token approvals internally. You don't need to approve tokens to the adapter or target protocol. ### Only Allowed Adapters Work The Credit Manager only accepts calls to registered adapters: ```solidity // This reverts if the adapter isn't registered ICreditFacadeV3(creditFacade).multicall(account, [ MultiCall({target: unregisteredAdapter, callData: ...}) ]); ``` ### Check Adapter Type Different adapter versions have different interfaces: ```solidity bytes32 adapterType = IAdapter(adapter).contractType(); // e.g., "ADAPTER::UNISWAP_V3_ROUTER" // "ADAPTER::CURVE_V1_STABLE_NG" // "ADAPTER::CVX_V1_BOOSTER" ``` ### Diff Functions Require Balance Diff functions calculate: `amountIn = currentBalance - leftoverAmount` If the balance is less than `leftoverAmount`, the operation will fail: ```solidity // If WETH balance is 0.5 ETH and you call: depositDiff(1 ether); // REVERTS - not enough balance // Correct: leave less than current balance depositDiff(1); // Deposits 0.5 ETH - 1 wei ``` ### External Calls Set Permission Flag The first adapter call sets `EXTERNAL_CONTRACT_WAS_CALLED_FLAG`: ```solidity // This flag affects: // - Additional validation in collateral checks // - Gas estimation for health factor calculation ``` ### Token Enabling Adapters automatically enable output tokens. After a swap: * Output token mask is set on the Credit Account * Token counts toward collateral (if it has quota or is underlying) ## See Also * [Controlling Slippage](https://docs.gearbox.finance/developers/controlling-slippage) - Protect swap outputs * [Enabling/Disabling Tokens](https://docs.gearbox.finance/developers/enabling-disabling-tokens) - Token state management * [Updating Quotas](https://docs.gearbox.finance/developers/updating-quotas) - Enable output tokens as collateral ## Enabling/Disabling Tokens Source: https://docs.gearbox.finance/developers/enabling-disabling-tokens-2 File: content/developers/enabling-disabling-tokens-2.mdx Explicitly manage which tokens count as collateral. > For SDK implementation, see [Enabling and Disabling Tokens](https://docs.gearbox.finance/developers/enabling-disabling-tokens). ## Why You manually enable/disable tokens when: * **Direct transfers** - Tokens sent directly to Credit Account aren't auto-enabled * **Gas optimization** - Disable unused tokens to reduce collateral check cost * **Risk management** - Prevent certain tokens from counting in health factor * **Edge cases** - Override automatic enable/disable behavior Most of the time you don't need this - tokens auto-enable/disable based on balance changes. But sometimes manual control is necessary. ## What Non-quoted tokens have automatic enable/disable behavior: | Balance Change | Action | | -------------- | ------------ | | 0/1 to > 1 | Auto-enable | | > 1 to 0/1 | Auto-disable | `enableToken` and `disableToken` let you override this when needed. **Important:** These functions only work on **non-quoted tokens**. Quota tokens can only be enabled/disabled via `updateQuota`. ## How ### Enable a Token ```solidity import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; address creditFacade; address creditAccount; address tokenToEnable; MultiCall[] memory calls = new MultiCall[](1); calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.enableToken, (tokenToEnable) ) }); ICreditFacadeV3(creditFacade).multicall(creditAccount, calls); ``` ### Disable a Token ```solidity // Disable a token to reduce collateral check gas cost calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.disableToken, (tokenToDisable) ) }); ``` ### Enable Token After Direct Transfer If tokens are sent directly to your Credit Account (not through an adapter): ```solidity // Token was transferred directly - won't count as collateral until enabled // First, some external contract sends tokens: // IERC20(token).transfer(creditAccount, amount); // Now enable it to count as collateral MultiCall[] memory calls = new MultiCall[](1); calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.enableToken, (directlyTransferredToken) ) }); ICreditFacadeV3(creditFacade).multicall(creditAccount, calls); ``` ### Disable Multiple Unused Tokens Reduce gas costs by disabling tokens with zero balance: ```solidity // Get enabled token mask from credit manager uint256 enabledTokensMask = ICreditManagerV3(creditManager).enabledTokensMaskOf(creditAccount); // Build calls to disable each zero-balance token // This is a simplified example - in practice, iterate through mask MultiCall[] memory calls = new MultiCall[](2); calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.disableToken, (unusedToken1) ) }); calls[1] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.disableToken, (unusedToken2) ) }); ``` ## Gotchas ### No-Op for Quota Tokens Calling `enableToken` or `disableToken` on a quota token does nothing: ```solidity // This does nothing - quota tokens use updateQuota MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.enableToken, (quotaTokenAddress) // No effect! ) }); // Use this instead for quota tokens MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.updateQuota, (quotaTokenAddress, int96(quotaAmount), uint96(minQuota)) ) }); ``` ### Cannot Enable Forbidden Tokens Some tokens are marked as "forbidden" and cannot be enabled: ```solidity // This will revert MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.enableToken, (forbiddenTokenAddress) // Reverts! ) }); ``` Forbidden tokens must be swapped away, not disabled. ### Auto-Enable Usually Works Adapter calls automatically enable tokens when balance increases: ```solidity // This swap auto-enables WETH - no need to call enableToken MultiCall({ target: uniswapAdapter, callData: abi.encodeCall( IUniswapV3Adapter.exactInputSingle, (swapParams) // Swaps USDC -> WETH ) }); // WETH is now enabled automatically ``` You only need manual enable when: * Tokens are transferred directly to Credit Account (not via adapter) * You want to enable a zero-balance token preemptively ### Max Enabled Tokens Limit Each Credit Manager has a maximum number of enabled tokens per account: ```solidity // Check the limit uint8 maxTokens = ICreditManagerV3(creditManager).maxEnabledTokens(); // Check current count via enabled mask popcount uint256 enabledMask = ICreditManagerV3(creditManager).enabledTokensMaskOf(creditAccount); // Count set bits in enabledMask to get current token count // Exceeding limit reverts the multicall ``` ### Disabled Tokens Still on Account Disabling a token doesn't remove it from the account - just excludes it from health factor: ```solidity // Token is disabled but balance stays disableToken(wethAddress); // Balance remains, just not counted as collateral // WARNING: Liquidators can claim disabled token balances as bonus! ``` **Warning:** Don't keep significant value in disabled tokens. During liquidation, liquidators can withdraw disabled tokens on top of their normal premium. ### Balance of 1 is "Zero" Gearbox treats balance of 0 and 1 the same (due to ERC20 rounding issues). Auto-disable triggers at balance <= 1: ```solidity // These are equivalent from Gearbox perspective // balance = 0 -> Disabled // balance = 1 -> Also disabled // This is enabled // balance = 2 ``` ## See Also * [Updating Quotas](https://docs.gearbox.finance/developers/updating-quotas) - How to enable/disable quota tokens * [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls) - Auto-enable behavior with adapters * [Collateral Check Params](https://docs.gearbox.finance/developers/collateral-check-params) - Optimize checks for enabled tokens ## Updating Price Feeds Source: https://docs.gearbox.finance/developers/updating-price-feeds-2 File: content/developers/updating-price-feeds-2.mdx Push fresh price data for on-demand oracles (Pyth, Redstone). > For SDK implementation, see [Updating Price Feeds](https://docs.gearbox.finance/developers/updating-price-feeds). ## Why You update price feeds when: * **Using on-demand oracles** - Pyth and Redstone require fresh data with each transaction * **Multicalls fail** - "Stale price" errors indicate missing price updates * **Withdrawals** - Reserve price feeds may also need updates under safe pricing Some tokens use "pull-based" oracles that don't update automatically. You must push fresh price data before operations that need it. ## What `onDemandPriceUpdate` pushes oracle data to the price feed: 1. You obtain signed price data from the oracle provider (off-chain) 2. You include the price update as the FIRST call in your multicall 3. Credit Facade forwards the data to the price feed contract 4. The price feed validates the signature and updates **Critical rule:** All price updates must be at the **beginning** of the calls array. Any `onDemandPriceUpdate` after another call type will revert. ## How ### Basic Price Update ```solidity import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; address creditFacade; address creditAccount; address tokenWithPythFeed; bytes memory priceData; // Obtained off-chain from Pyth/Redstone MultiCall[] memory calls = new MultiCall[](2); // Price update MUST be first calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.onDemandPriceUpdate, ( tokenWithPythFeed, // Token to update price for false, // reserve: false = main feed, true = reserve feed priceData // Signed price data from oracle ) ) }); // Now other operations calls[1] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.addCollateral, (usdc, amount) ) }); ICreditFacadeV3(creditFacade).multicall(creditAccount, calls); ``` ### Multiple Price Updates Update several tokens at once (all must be at the start): ```solidity MultiCall[] memory calls = new MultiCall[](4); // All price updates first calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.onDemandPriceUpdate, (token1, false, priceData1) ) }); calls[1] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.onDemandPriceUpdate, (token2, false, priceData2) ) }); // Then other operations calls[2] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.addCollateral, (usdc, amount) ) }); calls[3] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.increaseDebt, (debtAmount) ) }); ``` ### Updating Reserve Feed (For Withdrawals) Withdrawals trigger safe pricing, which uses both main and reserve feeds: ```solidity MultiCall[] memory calls = new MultiCall[](3); // Main feed update calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.onDemandPriceUpdate, (tokenAddress, false, mainPriceData) // reserve = false ) }); // Reserve feed update calls[1] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.onDemandPriceUpdate, (tokenAddress, true, reservePriceData) // reserve = true ) }); // Now the withdrawal will work with safe pricing calls[2] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.withdrawCollateral, (otherToken, amount, recipient) ) }); ``` ### Contract Architecture for Price Updates Your contract must accept price data as a parameter since it cannot fetch oracle data on-chain: ```solidity contract MyGearboxStrategy { address public creditFacade; address public creditAccount; function executeStrategy( bytes[] calldata priceUpdates, // Must be passed from frontend uint256 amount ) external { uint256 numUpdates = priceUpdates.length; MultiCall[] memory calls = new MultiCall[](numUpdates + 1); // Build price update calls first for (uint256 i = 0; i < numUpdates; i++) { (address token, bool reserve, bytes memory data) = abi.decode(priceUpdates[i], (address, bool, bytes)); calls[i] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.onDemandPriceUpdate, (token, reserve, data) ) }); } // Then add strategy operations calls[numUpdates] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.addCollateral, (usdc, amount) ) }); ICreditFacadeV3(creditFacade).multicall(creditAccount, calls); } } ``` ## Gotchas ### Price Updates MUST Be First This is the most common mistake. Price updates after any other call type revert: ```solidity // WRONG - price update after addCollateral MultiCall[] memory calls = new MultiCall[](2); calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall(ICreditFacadeV3Multicall.addCollateral, (token, amount)) }); calls[1] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.onDemandPriceUpdate, (token, false, priceData) // REVERTS! ) }); // CORRECT - price update first calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.onDemandPriceUpdate, (token, false, priceData) ) }); calls[1] = MultiCall({ target: creditFacade, callData: abi.encodeCall(ICreditFacadeV3Multicall.addCollateral, (token, amount)) }); ``` ### Fresh Data Required Price data has a short validity window (usually a few minutes). Fetch fresh data right before the transaction: ```solidity // Off-chain (e.g., in your frontend or bot): // 1. Fetch price data from Pyth/Redstone API // 2. Immediately use it in transaction // 3. DON'T cache price data for later ``` ### Not All Tokens Need Updates Only tokens with on-demand price feeds need updates. Tokens using Chainlink or other push-based oracles don't need `onDemandPriceUpdate`: ```solidity // Check feed type in your integration: // - PYTH feeds: need onDemandPriceUpdate // - REDSTONE feeds: need onDemandPriceUpdate // - Chainlink feeds: no update needed // - Other push oracles: no update needed ``` ### Disabled Tokens Don't Need Updates If a token will be disabled by the end of the multicall, you don't need to update its price: ```solidity // WETH is getting swapped entirely (will be disabled) MultiCall[] memory calls = new MultiCall[](2); // No need for WETH price update since it's being fully swapped calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall(ICreditFacadeV3Multicall.addCollateral, (usdc, amount)) }); calls[1] = MultiCall({ target: uniswapAdapter, callData: abi.encodeCall( IUniswapV3Adapter.exactInputSingle, (swapAllWethToUsdc) // WETH will auto-disable after swap ) }); ``` ### Contracts Cannot Fetch Price Data The oracle's API must be called off-chain. Your smart contract receives price data as a parameter: ```solidity // Your contract CANNOT do this: // bytes memory priceData = pythOracle.fetchPrice(feedId); // Not possible on-chain! // Your contract MUST receive price data from caller: function myFunction(bytes calldata priceData) external { // Use priceData in multicall } ``` ## See Also * [Controlling Slippage](https://docs.gearbox.finance/developers/controlling-slippage) - Stale prices can cause slippage issues * [Withdrawing Collateral](https://docs.gearbox.finance/developers/withdrawing-collateral) - May need reserve feed updates * [Collateral Check Params](https://docs.gearbox.finance/developers/collateral-check-params) - Related to price feed behavior ## Collateral Check Params Source: https://docs.gearbox.finance/developers/collateral-check-params-2 File: content/developers/collateral-check-params-2.mdx Optimize gas and set minimum health factor for collateral checks. > For SDK implementation, see [Collateral Check Params](https://docs.gearbox.finance/developers/collateral-check-params). ## Why You set collateral check params when: * **Optimizing gas** - Hint which tokens cover the debt to skip unnecessary oracle calls * **Risk management** - Enforce a minimum health factor above 1.0 * **Large accounts** - Many enabled tokens make default checks expensive * **Automated systems** - Bots can benefit from consistent gas costs The collateral check iterates through enabled tokens, summing value until it exceeds debt. Hints tell it which tokens to check first, potentially skipping expensive oracle calls. ## What `setFullCheckParams` configures two things: 1. **Collateral hints** - Token masks to prioritize during the check 2. **Min health factor** - Minimum acceptable HF (in basis points, 10000 = 1.0) If you know your USDC and WETH cover the debt, pass their masks as hints. The check evaluates them first and may stop early without checking other tokens. ## How ### Basic Usage with Hints ```solidity import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; address creditFacade; address creditAccount; address creditManager; address usdc; address weth; // Get token masks (each token has a unique bitmask) uint256 usdcMask = ICreditManagerV3(creditManager).getTokenMaskOrRevert(usdc); uint256 wethMask = ICreditManagerV3(creditManager).getTokenMaskOrRevert(weth); // Build hints array uint256[] memory hints = new uint256[](2); hints[0] = usdcMask; hints[1] = wethMask; MultiCall[] memory calls = new MultiCall[](2); // Set hints at the start of multicall calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.setFullCheckParams, ( hints, // Check these tokens first 10000 // minHealthFactor: 1.0 (10000 bps) ) ) }); // Rest of your multicall operations calls[1] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.addCollateral, (usdc, 100_000 * 10**6) ) }); ICreditFacadeV3(creditFacade).multicall(creditAccount, calls); ``` ### Setting Higher Min Health Factor Require account to maintain at least 1.2 HF: ```solidity uint256 MIN_HF_120 = 12000; // 1.2 in basis points uint256[] memory hints = new uint256[](0); // No hints MultiCall[] memory calls = new MultiCall[](2); calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.setFullCheckParams, (hints, MIN_HF_120) ) }); // Operations that must maintain 1.2 HF... calls[1] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.increaseDebt, (borrowAmount) ) }); ``` ### Complete Gas-Optimized Strategy ```solidity address creditManager; address usdc; address uniswapAdapter; // Get mask for primary collateral token uint256 usdcMask = ICreditManagerV3(creditManager).getTokenMaskOrRevert(usdc); uint256[] memory hints = new uint256[](1); hints[0] = usdcMask; MultiCall[] memory calls = new MultiCall[](4); // 1. Hints first - USDC will cover most of debt calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.setFullCheckParams, (hints, 10500) // Require 1.05 HF minimum ) }); // 2. Add collateral calls[1] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.addCollateral, (usdc, 100_000 * 10**6) ) }); // 3. Borrow calls[2] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.increaseDebt, (200_000 * 10**6) ) }); // 4. Swap some USDC to WETH calls[3] = MultiCall({ target: uniswapAdapter, callData: abi.encodeCall( IUniswapV3Adapter.exactInputSingle, (swapParams) ) }); ICreditFacadeV3(creditFacade).multicall(creditAccount, calls); ``` ## Gotchas ### Masks, Not Addresses The hints array takes token **masks**, not addresses: ```solidity // WRONG - passing addresses uint256[] memory hints = new uint256[](2); hints[0] = uint256(uint160(usdcAddress)); // Wrong! hints[1] = uint256(uint160(wethAddress)); // Wrong! // CORRECT - passing masks hints[0] = ICreditManagerV3(creditManager).getTokenMaskOrRevert(usdc); hints[1] = ICreditManagerV3(creditManager).getTokenMaskOrRevert(weth); ``` ### Hints Are Optimization, Not Guarantee The check still validates ALL enabled tokens - hints just change the order. If hints don't cover the debt, it continues with remaining tokens: ```solidity // If USDC hint doesn't fully cover debt, // WETH and other tokens are still checked // Hints just potentially skip some oracle calls ``` ### Min Health Factor Must Be >= 10000 You cannot set a health factor below 1.0: ```solidity // WRONG - less than 10000 reverts calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.setFullCheckParams, (hints, 9500) // Reverts! ) }); // CORRECT - must be >= 10000 calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.setFullCheckParams, (hints, 10000) // Exactly 1.0 - OK ) }); ``` ### Hints Don't Help Small Accounts For accounts with few enabled tokens (< 5), hints add gas overhead without saving much. Only use for accounts with many tokens. ### Order Matters in Hints Array Tokens are checked in the order you provide: ```solidity // Check WETH first, then USDC hints[0] = wethMask; hints[1] = usdcMask; // Check USDC first, then WETH hints[0] = usdcMask; hints[1] = wethMask; ``` Put your highest-value collateral first for best gas savings. ### Token Mask Calculation Token masks are powers of 2, assigned sequentially when tokens are added to the Credit Manager: ```solidity // First token: mask = 1 (2^0) // Second token: mask = 2 (2^1) // Third token: mask = 4 (2^2) // etc. // Always use getTokenMaskOrRevert to get the correct mask uint256 mask = ICreditManagerV3(creditManager).getTokenMaskOrRevert(tokenAddress); ``` ### Params Reset After Multicall `setFullCheckParams` only affects the current multicall's final check. Next multicall uses defaults again: ```solidity // Multicall 1 - with hints ICreditFacadeV3(creditFacade).multicall(account, callsWithHints); // Multicall 2 - back to default (no hints) ICreditFacadeV3(creditFacade).multicall(account, callsWithoutHints); ``` ### Combine Hints and Min HF Use hints for gas optimization AND min HF for risk management: ```solidity uint256[] memory hints = new uint256[](2); hints[0] = primaryCollateralMask; // Gas optimization hints[1] = secondaryCollateralMask; calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.setFullCheckParams, (hints, 11000) // Risk management: require 1.1 HF ) }); ``` ## See Also * [Enabling/Disabling Tokens](https://docs.gearbox.finance/developers/enabling-disabling-tokens) - Affects which tokens are checked * [Updating Price Feeds](https://docs.gearbox.finance/developers/updating-price-feeds) - Oracle calls that hints can skip * [Debt Management](https://docs.gearbox.finance/developers/debt-management) - Debt determines what TWV must cover ## Smart Contracts Source: https://docs.gearbox.finance/developers/gm-contracts File: content/developers/gm-contracts.mdx The Gearbox V3 protocol is composed of several interconnected Solidity contracts. This section provides a contract-level reference organized by **Write Methods**, **View Methods**, and **Events** for each core contract. ## Contract Architecture The Credit Suite handles leveraged positions through three tightly coupled contracts: - **[Credit Manager](https://docs.gearbox.finance/developers/gm-ref-cm)** -- Core accounting engine. Tracks debt, collateral, and health factors for all Credit Accounts. - **[Credit Facade](https://docs.gearbox.finance/developers/gm-ref-cf)** -- User-facing entry point. Handles multicall execution, access control, and debt limit enforcement. - **[Credit Configurator](https://docs.gearbox.finance/developers/gm-ref-cc)** -- Administrative gateway. Validates and propagates parameter changes to the Credit Manager and Facade. The Pool layer manages liquidity and risk parameters: - **[Pool (PoolV3)](https://docs.gearbox.finance/developers/gm-ref-pool)** -- ERC-4626 vault that holds underlying assets. Credit Managers borrow from it; LPs deposit into it. - **[Quota Keeper](https://docs.gearbox.finance/developers/gm-ref-qk)** -- Manages per-token quota limits and interest rates. Controls collateral exposure at the pool level. Data aggregation is handled by periphery contracts: - **[Compressors](https://docs.gearbox.finance/developers/gm-ref-compressors)** -- Read-only contracts that aggregate on-chain state into single calls. Used by the SDK, bots, and on-chain integrations. ## How to Use This Reference Each contract page lists method signatures, parameter tables, return values, and emitted events. Methods are grouped into: | Section | Description | | --- | --- | | **Write Methods** | State-changing functions (transactions) | | **View Methods** | Read-only functions (free calls) | | **Events** | Emitted log entries for indexing and monitoring | For conceptual guides and tutorials, see the main [Developers](/developers) section. ## Credit Manager Source: https://docs.gearbox.finance/developers/gm-ref-cm File: content/developers/gm-ref-cm.mdx The **CreditManagerV3** is the core accounting engine of the Gearbox Protocol. It manages Credit Account lifecycle, tracks debt and collateral, calculates health factors, and enforces risk parameters. All Credit Account state is stored and managed through this contract. ## Core Data Structures ### CreditAccountInfo Every Credit Account's state is tracked in a `CreditAccountInfo` struct: | Field | Type | Description | | --- | --- | --- | | `debt` | `uint256` | Principal amount borrowed from the pool | | `cumulativeIndexLastUpdate` | `uint256` | Pool's interest index at last debt update | | `cumulativeQuotaInterest` | `uint128` | Accrued quota interest not yet added to debt | | `quotaFees` | `uint128` | Quota fees owed | | `enabledTokensMask` | `uint256` | Bitmask of currently enabled collateral tokens | | `flags` | `uint16` | Account state flags (e.g., `BOT_PERMISSIONS_SET_FLAG`) | | `lastDebtUpdate` | `uint64` | Timestamp of last debt change (flash-loan protection) | | `borrower` | `address` | Current account owner | ### Collateral Calculation Modes | Mode | Use Case | | --- | --- | | `DEBT_ONLY` | Calculate debt + interest without collateral | | `DEBT_COLLATERAL` | Full TWV + HF calculation | | `FULL_COLLATERAL_CHECK_LAZY` | Optimized: stops early when HF exceeds threshold | --- ## Write Methods ### openCreditAccount Opens a new Credit Account for a borrower. ```solidity function openCreditAccount(address onBehalfOf) external returns (address creditAccount); ``` | Parameter | Type | Description | | --- | --- | --- | | `onBehalfOf` | `address` | Address that will own the Credit Account | **Returns:** Address of the newly created Credit Account. **Access:** CreditFacade only. --- ### closeCreditAccount Closes a Credit Account and settles all debt. ```solidity function closeCreditAccount(address creditAccount) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `creditAccount` | `address` | Address of the Credit Account to close | **Access:** CreditFacade only. Repays pool debt and returns remaining assets to the borrower. --- ### liquidateCreditAccount Liquidates an unhealthy Credit Account. ```solidity function liquidateCreditAccount( address creditAccount, uint256 collateralDebtData, address to ) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `creditAccount` | `address` | Account to liquidate | | `collateralDebtData` | `uint256` | Pre-computed collateral and debt data | | `to` | `address` | Address to receive remaining assets | **Access:** CreditFacade only. Settles debt with pool, reports profit/loss, and distributes remaining collateral. --- ### manageDebt Increases or decreases the debt of a Credit Account. ```solidity function manageDebt( address creditAccount, uint256 amount, uint256 enabledTokensMask, ManageDebtAction action ) external returns (uint256 newDebt, uint256 tokensToEnable, uint256 tokensToDisable); ``` | Parameter | Type | Description | | --- | --- | --- | | `creditAccount` | `address` | Target Credit Account | | `amount` | `uint256` | Amount to increase or decrease | | `enabledTokensMask` | `uint256` | Current enabled tokens mask | | `action` | `ManageDebtAction` | `INCREASE_DEBT` or `DECREASE_DEBT` | **Returns:** New debt amount and token mask changes. **Access:** CreditFacade only. Flash-loan protection prevents multiple debt changes in the same block. --- ### addCollateral Adds collateral tokens to a Credit Account. ```solidity function addCollateral( address payer, address creditAccount, address token, uint256 amount ) external returns (uint256 tokensToEnable); ``` | Parameter | Type | Description | | --- | --- | --- | | `payer` | `address` | Address providing the tokens | | `creditAccount` | `address` | Receiving Credit Account | | `token` | `address` | Token to add | | `amount` | `uint256` | Amount to transfer | **Returns:** Token mask to enable. **Access:** CreditFacade only. --- ### withdrawCollateral Withdraws collateral tokens from a Credit Account. ```solidity function withdrawCollateral( address creditAccount, address token, uint256 amount, address to ) external returns (uint256 tokensToDisable); ``` | Parameter | Type | Description | | --- | --- | --- | | `creditAccount` | `address` | Source Credit Account | | `token` | `address` | Token to withdraw | | `amount` | `uint256` | Amount to withdraw | | `to` | `address` | Recipient address | **Returns:** Token mask to disable (if balance reaches zero). **Access:** CreditFacade only. --- ### setActiveCreditAccount Sets the active Credit Account for adapter execution during multicalls. ```solidity function setActiveCreditAccount(address creditAccount) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `creditAccount` | `address` | Account to set as active | **Access:** CreditFacade only. --- ### execute Executes an external call from a Credit Account through a whitelisted adapter. ```solidity function execute(bytes calldata data) external returns (bytes memory); ``` | Parameter | Type | Description | | --- | --- | --- | | `data` | `bytes` | Encoded function call to execute | **Returns:** Return data from the adapter call. **Access:** Credit Account (via adapter) only. --- ### fullCollateralCheck Performs a full collateral check on a Credit Account after operations. ```solidity function fullCollateralCheck( address creditAccount, uint256 enabledTokensMask, uint256[] calldata collateralHints, uint16 minHealthFactor, bool useSafePrices ) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `creditAccount` | `address` | Account to check | | `enabledTokensMask` | `uint256` | Current enabled tokens mask | | `collateralHints` | `uint256[]` | Hints for optimized collateral iteration | | `minHealthFactor` | `uint16` | Minimum acceptable HF (typically 10000) | | `useSafePrices` | `bool` | Whether to use safe (conservative) prices | **Access:** CreditFacade only. Reverts if health factor is below minimum. --- ## View Methods ### calcDebtAndCollateral Calculates debt, interest, and collateral values for a Credit Account. ```solidity function calcDebtAndCollateral( address creditAccount, CollateralCalcTask task ) external view returns (CollateralDebtData memory); ``` | Parameter | Type | Description | | --- | --- | --- | | `creditAccount` | `address` | Account to calculate for | | `task` | `CollateralCalcTask` | Calculation mode (see Collateral Calculation Modes) | **Returns:** `CollateralDebtData` struct with `debt`, `accruedInterest`, `accruedFees`, `totalDebtUSD`, `totalValue`, `twvUSD`, `enabledTokensMask`. --- ### creditAccountInfo Returns the full state struct for a Credit Account. ```solidity function creditAccountInfo(address creditAccount) external view returns (CreditAccountInfo memory); ``` --- ### enabledTokensMaskOf Returns the bitmask of enabled collateral tokens for an account. ```solidity function enabledTokensMaskOf(address creditAccount) external view returns (uint256); ``` --- ### flagsOf Returns the flags for a Credit Account. ```solidity function flagsOf(address creditAccount) external view returns (uint16); ``` --- ### getBorrowerOrRevert Returns the borrower address of a Credit Account, reverting if not found. ```solidity function getBorrowerOrRevert(address creditAccount) external view returns (address); ``` --- ### getTokenMaskOrRevert Returns the bitmask for a given token address, reverting if not registered. ```solidity function getTokenMaskOrRevert(address token) external view returns (uint256); ``` --- ### getTokenByMask Returns the token address for a given bitmask. ```solidity function getTokenByMask(uint256 tokenMask) external view returns (address); ``` --- ### collateralTokenByMask Returns collateral token data including liquidation threshold parameters. ```solidity function collateralTokenByMask(uint256 tokenMask) external view returns (address token, uint16 ltInitial, uint16 ltFinal, uint40 timestampRampStart, uint24 rampDuration); ``` --- ### forbiddenTokenMask Returns the bitmask of forbidden tokens. ```solidity function forbiddenTokenMask() external view returns (uint256); ``` --- ### contractToAdapter / adapterToContract Returns the adapter for a target contract, or vice versa. ```solidity function contractToAdapter(address targetContract) external view returns (address); function adapterToContract(address adapter) external view returns (address); ``` --- ### adapters Returns all registered adapter addresses. ```solidity function adapters() external view returns (address[] memory); ``` --- ### creditFacade / creditConfigurator / pool / underlying Returns addresses of associated contracts. ```solidity function creditFacade() external view returns (address); function creditConfigurator() external view returns (address); function pool() external view returns (address); function underlying() external view returns (address); ``` --- ## Events ### OpenCreditAccount ```solidity event OpenCreditAccount(address indexed creditAccount, address indexed onBehalfOf); ``` Emitted when a new Credit Account is opened. ### CloseCreditAccount ```solidity event CloseCreditAccount(address indexed creditAccount, address indexed borrower); ``` Emitted when a Credit Account is closed. ### LiquidateCreditAccount ```solidity event LiquidateCreditAccount( address indexed creditAccount, address indexed liquidator, address to, uint256 remainingFunds ); ``` Emitted when a Credit Account is liquidated. ### ManageDebt ```solidity event ManageDebt(address indexed creditAccount, uint256 amount, ManageDebtAction action); ``` Emitted when debt is increased or decreased. ### AddCollateral ```solidity event AddCollateral(address indexed creditAccount, address indexed token, uint256 amount); ``` Emitted when collateral is added to an account. ### WithdrawCollateral ```solidity event WithdrawCollateral(address indexed creditAccount, address indexed token, uint256 amount, address to); ``` Emitted when collateral is withdrawn from an account. --- ## Related Pages - [Credit Facade](https://docs.gearbox.finance/developers/gm-ref-cf) -- User-facing interface for Credit Account operations - [Credit Configurator](https://docs.gearbox.finance/developers/gm-ref-cc) -- Administrative parameter management - [Pool (PoolV3)](https://docs.gearbox.finance/developers/gm-ref-pool) -- Liquidity pool that Credit Manager borrows from - [Smart Contracts Overview](https://docs.gearbox.finance/developers/gm-contracts) -- Full contract architecture ## Revoke Allowances Source: https://docs.gearbox.finance/developers/revoke-allowances-2 File: content/developers/revoke-allowances-2.mdx Revoke Credit Account's token approvals to external contracts. > For SDK implementation, see [Revoke Allowances](https://docs.gearbox.finance/developers/revoke-allowances). ## Why You revoke allowances when: * **Security incident** - Third-party contract may be compromised * **Legacy cleanup** - Old accounts may have stale approvals from previous Gearbox versions * **Defense in depth** - Proactively remove unnecessary approvals Current Gearbox V3 automatically resets allowances to 1 after each interaction. However, older accounts from V2.1 may still have active allowances to external protocols. ## What `revokeAdapterAllowances` resets token approvals from your Credit Account to specified contracts: 1. You specify which (spender, token) pairs to revoke 2. Credit Account sets allowance to 1 for each pair 3. External contracts can no longer spend those tokens **Note:** Allowance is set to 1, not 0, due to gas optimization (writing non-zero to non-zero is cheaper than writing zero). ## How ### Basic Revocation ```solidity import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {RevocationPair} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; address creditFacade; address creditAccount; address uniswapAdapter; address curveAdapter; address usdc; address dai; // Define which approvals to revoke RevocationPair[] memory revocations = new RevocationPair[](2); revocations[0] = RevocationPair({ spender: uniswapAdapter, token: usdc }); revocations[1] = RevocationPair({ spender: curveAdapter, token: dai }); MultiCall[] memory calls = new MultiCall[](1); calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.revokeAdapterAllowances, (revocations) ) }); ICreditFacadeV3(creditFacade).multicall(creditAccount, calls); ``` ### Check Existing Allowances Before revoking, check what allowances exist: ```solidity import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; // Check allowance from Credit Account to a spender uint256 allowance = IERC20(tokenAddress).allowance(creditAccount, spenderAddress); if (allowance > 1) { // Credit Account has active allowance to this spender // Consider revoking it } ``` ### Revoke All Adapter Allowances for a Token ```solidity // Get all adapters from Credit Manager address[] memory adapters = ICreditManagerV3(creditManager).adapters(); // Build revocations for all adapters RevocationPair[] memory revocations = new RevocationPair[](adapters.length); for (uint256 i = 0; i < adapters.length; i++) { revocations[i] = RevocationPair({ spender: adapters[i], token: tokenAddress }); } MultiCall[] memory calls = new MultiCall[](1); calls[0] = MultiCall({ target: creditFacade, callData: abi.encodeCall( ICreditFacadeV3Multicall.revokeAdapterAllowances, (revocations) ) }); ICreditFacadeV3(creditFacade).multicall(creditAccount, calls); ``` ### Emergency Revocation Pattern For security incidents, revoke immediately: ```solidity contract EmergencyRevoke { ICreditFacadeV3 public creditFacade; function emergencyRevokeAll( address creditAccount, address compromisedAdapter, address[] calldata tokens ) external { RevocationPair[] memory revocations = new RevocationPair[](tokens.length); for (uint256 i = 0; i < tokens.length; i++) { revocations[i] = RevocationPair({ spender: compromisedAdapter, token: tokens[i] }); } MultiCall[] memory calls = new MultiCall[](1); calls[0] = MultiCall({ target: address(creditFacade), callData: abi.encodeCall( ICreditFacadeV3Multicall.revokeAdapterAllowances, (revocations) ) }); creditFacade.multicall(creditAccount, calls); } } ``` ## Gotchas ### Usually Not Needed in V3 Gearbox V3 automatically resets allowances after each adapter interaction. This function exists mainly for: 1. Legacy accounts migrated from V2.1 2. Paranoid security posture 3. Specific incident response If you're using a fresh V3 account, allowances are already minimal. ### RevocationPair Struct Format The struct has two fields: ```solidity struct RevocationPair { address spender; // Contract that has the allowance address token; // Token that was approved } ``` Both must be valid addresses. Invalid addresses may cause the call to revert or have no effect. ### Sets to 1, Not 0 For gas efficiency, allowances are set to 1 instead of 0: ```solidity // Before revocation: allowance = 1000000000000000000 (1 token) // After revocation: allowance = 1 (essentially zero for practical purposes) ``` An allowance of 1 wei is functionally zero for any realistic token amount. ### Can't Revoke Non-Existent Allowances Revoking an allowance that doesn't exist (already 0 or 1) is a no-op - it won't revert, but wastes gas: ```solidity // If allowance is already 0 or 1, this does nothing but costs gas revocations[0] = RevocationPair({ spender: adapterWithNoAllowance, token: token }); ``` ### Adapter vs External Contract Revocations target the **spender** (usually an adapter), not the underlying protocol: ```solidity // The adapter has the allowance, not Uniswap directly RevocationPair({ spender: uniswapAdapter, // Adapter address, not Uniswap Router token: usdcAddress }); ``` Adapters are what actually interact with your Credit Account's tokens. ### Batch Multiple Revocations You can revoke multiple (spender, token) pairs in one call: ```solidity // Efficient - single call with multiple revocations RevocationPair[] memory revocations = new RevocationPair[](3); revocations[0] = RevocationPair({spender: adapter1, token: usdc}); revocations[1] = RevocationPair({spender: adapter1, token: dai}); revocations[2] = RevocationPair({spender: adapter2, token: usdc}); // Less efficient - multiple multicalls // Don't do this if you can batch them together ``` ### When to Actually Use This Real scenarios where revocation makes sense: 1. **Third-party exploit:** A protocol Gearbox integrates with gets hacked. Revoke allowances to that protocol's adapter as a precaution. 2. **Account migration:** Moving from V2.1 account with old allowances to ensure clean state. 3. **Compliance requirement:** Some regulatory frameworks require revoking unused approvals. 4. **Personal security policy:** You want explicit control over all approvals. For normal operations, V3's automatic reset is sufficient. ## See Also * [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls) - How adapters use allowances * [Enabling/Disabling Tokens](https://docs.gearbox.finance/developers/enabling-disabling-tokens) - Related account management ## Credit Facade Source: https://docs.gearbox.finance/developers/gm-ref-cf File: content/developers/gm-ref-cf.mdx The **CreditFacadeV3** is the primary user-facing interface for Credit Account operations. It implements atomic multicall batching, enforces debt limits, manages bot permissions, and ensures all operations complete with a healthy account state. ## Core Data Structures ### MultiCall ```solidity struct MultiCall { address target; // Facade itself or whitelisted adapter bytes callData; // Function selector + encoded arguments } ``` ### DebtLimits ```solidity struct DebtLimits { uint128 minDebt; // Minimum principal (except 0) uint128 maxDebt; // Maximum principal } ``` ### Bot Permissions Bot permissions are stored as a `uint192` bitmask: | Permission | Value | Operation | | --- | --- | --- | | `ADD_COLLATERAL_PERMISSION` | `1 << 0` | Add funds to account | | `INCREASE_DEBT_PERMISSION` | `1 << 1` | Borrow more from pool | | `DECREASE_DEBT_PERMISSION` | `1 << 2` | Repay debt | | `WITHDRAW_COLLATERAL_PERMISSION` | `1 << 5` | Withdraw assets | | `UPDATE_QUOTA_PERMISSION` | `1 << 6` | Change token quotas | | `EXTERNAL_CALLS_PERMISSION` | `1 << 16` | Execute adapter calls | --- ## Write Methods ### openCreditAccount Creates a new Credit Account with initial operations executed atomically. ```solidity function openCreditAccount( MultiCall[] calldata calls, address onBehalfOf ) external returns (address creditAccount); ``` | Parameter | Type | Description | | --- | --- | --- | | `calls` | `MultiCall[]` | Initial operations (add collateral, increase debt, etc.) | | `onBehalfOf` | `address` | Owner of the new Credit Account | **Returns:** Address of the created Credit Account. **Access:** Anyone. A full collateral check is performed after all calls execute. --- ### closeCreditAccount Closes a Credit Account, repaying all debt and returning remaining assets. ```solidity function closeCreditAccount( address creditAccount, MultiCall[] calldata calls ) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `creditAccount` | `address` | Account to close | | `calls` | `MultiCall[]` | Operations to execute before closing (e.g., swap to underlying) | **Access:** Account owner only (`creditAccountOwnerOnly`). --- ### multicall Executes a batch of operations on an existing Credit Account. ```solidity function multicall( address creditAccount, MultiCall[] calldata calls ) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `creditAccount` | `address` | Target account | | `calls` | `MultiCall[]` | Operations to execute | **Access:** Account owner only. Full collateral check after execution. --- ### botMulticall Executes a batch of operations initiated by an authorized bot. ```solidity function botMulticall( address creditAccount, MultiCall[] calldata calls ) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `creditAccount` | `address` | Target account | | `calls` | `MultiCall[]` | Operations to execute | **Access:** Authorized bot only. Each operation is checked against the bot's permission bitmask. --- ### liquidateCreditAccount Liquidates an unhealthy Credit Account (HF < 1.0). ```solidity function liquidateCreditAccount( address creditAccount, address to, MultiCall[] calldata calls ) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `creditAccount` | `address` | Account to liquidate | | `to` | `address` | Recipient of remaining funds | | `calls` | `MultiCall[]` | Operations to execute during liquidation | **Access:** Anyone (account must be liquidatable). --- ### setBotPermissions Grants or revokes bot permissions for a Credit Account. ```solidity function setBotPermissions( address creditAccount, address bot, uint192 permissions ) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `creditAccount` | `address` | Target account | | `bot` | `address` | Bot address to authorize | | `permissions` | `uint192` | Permission bitmask (0 to revoke) | **Access:** Account owner only. --- ## Multicall-Only Methods These methods can only be called as part of a `MultiCall` array (encoded in `callData` with the Facade as `target`). ### addCollateral ```solidity function addCollateral(address token, uint256 amount) external; ``` Transfers tokens from the caller to the Credit Account. ### increaseDebt ```solidity function increaseDebt(uint256 amount) external; ``` Borrows additional funds from the pool. Subject to debt limits and per-block caps. ### decreaseDebt ```solidity function decreaseDebt(uint256 amount) external; ``` Repays debt to the pool. ### withdrawCollateral ```solidity function withdrawCollateral(address token, uint256 amount, address to) external; ``` Withdraws collateral from the Credit Account to the specified address. ### updateQuota ```solidity function updateQuota(address token, int96 quotaChange, uint96 minQuota) external; ``` Adjusts the quota for a specific token on the Credit Account. ### storeExpectedBalances / compareBalances ```solidity function storeExpectedBalances(BalanceWithMask[] calldata balances) external; function compareBalances() external; ``` Slippage protection pair: store expected balances before swaps, then verify after. --- ## View Methods ### debtLimits Returns the min/max debt bounds for this Credit Facade. ```solidity function debtLimits() external view returns (uint128 minDebt, uint128 maxDebt); ``` --- ### maxDebtPerBlockMultiplier Returns the per-block borrowing multiplier. Value of 0 means borrowing is disabled. ```solidity function maxDebtPerBlockMultiplier() external view returns (uint8); ``` --- ### creditManager Returns the associated Credit Manager address. ```solidity function creditManager() external view returns (address); ``` --- ### canLiquidate Checks whether a Credit Account is liquidatable. ```solidity function canLiquidate(address creditAccount) external view returns (bool); ``` --- ### botPermissions Returns the permission bitmask for a bot on a specific Credit Account. ```solidity function botPermissions(address creditAccount, address bot) external view returns (uint192); ``` --- ### expirable / expirationDate Returns whether this Facade has an expiration date and what it is. ```solidity function expirable() external view returns (bool); function expirationDate() external view returns (uint40); ``` --- ## Events ### StartMultiCall ```solidity event StartMultiCall(address indexed creditAccount, address indexed caller); ``` Emitted at the start of a multicall execution. ### FinishMultiCall ```solidity event FinishMultiCall(); ``` Emitted when a multicall completes successfully. ### OpenCreditAccount ```solidity event OpenCreditAccount( address indexed creditAccount, address indexed onBehalfOf, address indexed caller ); ``` Emitted when a Credit Account is opened through the Facade. ### CloseCreditAccount ```solidity event CloseCreditAccount(address indexed creditAccount, address indexed caller); ``` Emitted when a Credit Account is closed. ### LiquidateCreditAccount ```solidity event LiquidateCreditAccount( address indexed creditAccount, address indexed liquidator, address indexed to, uint256 remainingFunds ); ``` Emitted when a Credit Account is liquidated. ### SetBotPermissions ```solidity event SetBotPermissions( address indexed creditAccount, address indexed bot, uint192 permissions ); ``` Emitted when bot permissions are updated. --- ## Related Pages - [Credit Manager](https://docs.gearbox.finance/developers/gm-ref-cm) -- Core accounting engine - [Credit Configurator](https://docs.gearbox.finance/developers/gm-ref-cc) -- Administrative configuration - [Pool (PoolV3)](https://docs.gearbox.finance/developers/gm-ref-pool) -- Liquidity pool - [Smart Contracts Overview](https://docs.gearbox.finance/developers/gm-contracts) -- Full contract architecture ## Pool Operations Source: https://docs.gearbox.finance/developers/pool-operations File: content/developers/pool-operations.mdx Interact with Gearbox pools directly from Solidity. Pools are ERC-4626 compliant vaults. > For SDK data reading, see [Reading Data](https://docs.gearbox.finance/developers/reading-data). ## IPoolV3 ```solidity import {IPoolV3} from "@gearbox-protocol/core-v3/contracts/interfaces/IPoolV3.sol"; IPoolV3 pool = IPoolV3(poolAddress); ``` ## ERC-4626 Standard Functions Gearbox pools implement the full ERC-4626 tokenized vault standard: ### Deposit Deposit underlying assets and receive diesel tokens (shares): ```solidity function deposit(uint256 assets, address receiver) external returns (uint256 shares); ``` **Example:** ```solidity // Approve underlying first IERC20(underlying).approve(address(pool), assets); // Deposit and receive shares uint256 shares = pool.deposit(assets, msg.sender); // Preview how many shares you'd receive uint256 expectedShares = pool.previewDeposit(assets); ``` ### Deposit with Referral Track referrals on-chain: ```solidity function depositWithReferral( uint256 assets, address receiver, uint256 referralCode ) external returns (uint256 shares); ``` **Example:** ```solidity IERC20(underlying).approve(address(pool), assets); uint256 shares = pool.depositWithReferral(assets, msg.sender, 123); ``` ### Mint Mint exact shares, depositing required assets: ```solidity function mint(uint256 shares, address receiver) external returns (uint256 assets); ``` **Example:** ```solidity // Preview required assets uint256 requiredAssets = pool.previewMint(shares); // Approve and mint IERC20(underlying).approve(address(pool), requiredAssets); uint256 assets = pool.mint(shares, msg.sender); ``` ### Withdraw Withdraw exact assets, burning required shares: ```solidity function withdraw( uint256 assets, address receiver, address owner ) external returns (uint256 shares); ``` **Example:** ```solidity // Withdraw exact assets uint256 sharesBurned = pool.withdraw(assets, msg.sender, msg.sender); // Preview how many shares would be burned uint256 expectedShares = pool.previewWithdraw(assets); ``` ### Redeem Burn exact shares, receiving assets: ```solidity function redeem( uint256 shares, address receiver, address owner ) external returns (uint256 assets); ``` **Example:** ```solidity // Redeem shares for underlying uint256 assets = pool.redeem(shares, msg.sender, msg.sender); // Preview how many assets you'd receive uint256 expectedAssets = pool.previewRedeem(shares); ``` ## Gearbox Extensions ### Diesel Rate (Share Price) ```solidity // Get current share price (in RAY - 27 decimals) uint256 rate = pool.dieselRate(); // 1 diesel token = rate / 10^27 underlying tokens ``` ### Interest Rates ```solidity // Annual supply rate for lenders (RAY) uint256 supplyRate = pool.supplyRate(); // Annual borrow rate for Credit Accounts (RAY) uint256 borrowRate = pool.baseInterestRate(); // Convert to percentage uint256 supplyAPY = supplyRate * 10000 / 10**27; // basis points ``` ### Liquidity State ```solidity // Total assets in pool uint256 totalAssets = pool.totalAssets(); // Available for borrowing uint256 available = pool.availableLiquidity(); // Total supply of diesel tokens uint256 totalSupply = pool.totalSupply(); // Calculate utilization uint256 utilization = ((totalAssets - available) * 10000) / totalAssets; // basis points ``` ### Underlying Asset ```solidity // Get underlying token address address underlying = pool.asset(); // Pool decimals (matches underlying) uint8 decimals = pool.decimals(); // Pool name and symbol (e.g., "diesel USDC", "dUSDC") string memory name = pool.name(); string memory symbol = pool.symbol(); ``` ### Maximum Operations ```solidity // Maximum depositable assets uint256 maxDeposit = pool.maxDeposit(receiver); // Maximum mintable shares uint256 maxMint = pool.maxMint(receiver); // Maximum withdrawable assets uint256 maxWithdraw = pool.maxWithdraw(owner); // Maximum redeemable shares uint256 maxRedeem = pool.maxRedeem(owner); ``` ## Credit Manager Interaction Only whitelisted Credit Managers can borrow. Regular users cannot call these: ```solidity // Credit Manager borrows from pool (CM-only) function lendCreditAccount(uint256 borrowedAmount, address creditAccount) external; // Credit Manager repays to pool (CM-only) function repayCreditAccount(uint256 repaidAmount, uint256 profit, uint256 loss) external; ``` ## Related Contracts ### Quota Keeper ```solidity // Get quota keeper address address quotaKeeper = pool.poolQuotaKeeper(); // Query quota parameters IPoolQuotaKeeperV3 qk = IPoolQuotaKeeperV3(quotaKeeper); (uint16 rate, , , uint96 totalQuoted, uint96 limit, bool isActive) = qk.getTokenQuotaParams(tokenAddress); ``` ### Interest Rate Model ```solidity // Get IRM address address irm = pool.interestRateModel(); // Query model parameters ILinearInterestRateModelV3 model = ILinearInterestRateModelV3(irm); (uint16 U1, uint16 U2, uint16 Rbase, uint16 Rslope1, uint16 Rslope2, uint16 Rslope3) = model.getModelParameters(); ``` ## Complete Example ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import {IPoolV3} from "@gearbox-protocol/core-v3/contracts/interfaces/IPoolV3.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; contract PoolInteraction { IPoolV3 public immutable pool; address public immutable underlying; constructor(address _pool) { pool = IPoolV3(_pool); underlying = pool.asset(); } function depositAndGetState(uint256 amount) external returns ( uint256 shares, uint256 supplyAPY, uint256 utilization ) { // Transfer underlying from user IERC20(underlying).transferFrom(msg.sender, address(this), amount); // Approve and deposit IERC20(underlying).approve(address(pool), amount); shares = pool.deposit(amount, msg.sender); // Read state uint256 supplyRate = pool.supplyRate(); supplyAPY = supplyRate * 10000 / 10**27; // basis points uint256 totalAssets = pool.totalAssets(); uint256 available = pool.availableLiquidity(); utilization = ((totalAssets - available) * 10000) / totalAssets; } function redeemAll(address owner) external returns (uint256 assets) { uint256 shares = pool.balanceOf(owner); require(shares > 0, "No shares"); // Transfer shares from owner IERC20(address(pool)).transferFrom(owner, address(this), shares); // Redeem assets = pool.redeem(shares, owner, address(this)); } } ``` For architectural background, see [Pool Architecture](https://docs.gearbox.finance/developers/pools). ## Credit Configurator Source: https://docs.gearbox.finance/developers/gm-ref-cc File: content/developers/gm-ref-cc.mdx The **CreditConfiguratorV3** is the administrative gateway for the Credit Suite. It validates parameter changes and propagates them to the Credit Manager and Credit Facade. It does not store configuration state itself -- it acts as a validation and access-control layer. ``` User/DAO -> CreditConfiguratorV3 (validation) -> CreditManagerV3/CreditFacadeV3 (state) ``` --- ## Write Methods ### Token & Collateral Management #### addCollateralToken Registers a new collateral token with an initial liquidation threshold. ```solidity function addCollateralToken(address token, uint16 liquidationThreshold) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `token` | `address` | ERC-20 token to add | | `liquidationThreshold` | `uint16` | Initial LT in basis points (e.g., 8500 = 85%) | **Validation:** Token must have a price feed in PriceOracle, be quoted in PoolQuotaKeeper, and LT cannot exceed the underlying token's LT. **Access:** Configurator role only. --- #### setLiquidationThreshold Sets the liquidation threshold for a collateral token immediately. ```solidity function setLiquidationThreshold(address token, uint16 liquidationThreshold) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `token` | `address` | Collateral token | | `liquidationThreshold` | `uint16` | New LT in basis points | **Access:** Configurator role only. --- #### rampLiquidationThreshold Gradually changes a token's liquidation threshold over time to prevent sudden liquidation cascades. ```solidity function rampLiquidationThreshold( address token, uint16 ltFinal, uint40 rampStart, uint24 rampDuration ) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `token` | `address` | Collateral token | | `ltFinal` | `uint16` | Target LT after ramping completes | | `rampStart` | `uint40` | Timestamp when ramping begins | | `rampDuration` | `uint24` | Duration of linear interpolation (seconds) | **Access:** Configurator role only. The current LT is linearly interpolated between the initial and final values over the ramp period. --- #### forbidToken Marks a token as forbidden (high-risk). Forbidden tokens still count toward collateral (with safe pricing) but quota increases and balance increases are restricted. ```solidity function forbidToken(address token) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `token` | `address` | Token to forbid | **Access:** Pausable Admin (no DAO vote required). --- #### allowToken Restores normal status to a previously forbidden token. ```solidity function allowToken(address token) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `token` | `address` | Token to allow | **Access:** Configurator role only. --- ### Fee Management #### setFees Configures liquidation fees and premiums. ```solidity function setFees( uint16 feeLiquidation, uint16 liquidationPremium, uint16 feeLiquidationExpired, uint16 liquidationPremiumExpired ) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `feeLiquidation` | `uint16` | DAO fee on standard liquidations (bps) | | `liquidationPremium` | `uint16` | Reward for liquidators (bps) | | `feeLiquidationExpired` | `uint16` | DAO fee for expired account liquidations (bps) | | `liquidationPremiumExpired` | `uint16` | Liquidator reward for expired accounts (bps) | **Constraints:** `feeLiquidation <= liquidationPremium`, `feeLiquidationExpired <= feeLiquidation`, and `liquidationPremium + feeLiquidation < 100%`. **Access:** Configurator role only. --- ### Debt Limits #### setDebtLimits Sets the minimum and maximum debt bounds per Credit Account. ```solidity function setDebtLimits(uint128 newMinDebt, uint128 newMaxDebt) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `newMinDebt` | `uint128` | Minimum principal (must have non-zero USD value) | | `newMaxDebt` | `uint128` | Maximum principal | **Validation:** `minDebt <= maxDebt`. Safety ratio ensures min debt is large enough to make liquidation economical. **Access:** Configurator role only. --- #### setMaxDebtPerBlockMultiplier Sets the per-block borrowing cap multiplier. ```solidity function setMaxDebtPerBlockMultiplier(uint8 multiplier) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `multiplier` | `uint8` | Multiplier applied to maxDebt for per-block limit | **Access:** Configurator role only. --- #### forbidBorrowing Emergency action that immediately halts all new borrowing by setting the per-block multiplier to 0. ```solidity function forbidBorrowing() external; ``` **Access:** Pausable Admin (no DAO vote required). --- ### Adapter Management #### allowAdapter Registers an adapter for a target DeFi protocol. ```solidity function allowAdapter(address adapter) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `adapter` | `address` | Adapter contract address | **Validation:** Adapter must implement `creditManager()` returning this Credit Manager and `targetContract()` returning the DeFi protocol. Cannot target the Facade or Manager itself. **Access:** Configurator role only. --- #### forbidAdapter Removes a registered adapter. ```solidity function forbidAdapter(address adapter) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `adapter` | `address` | Adapter to remove | **Access:** Configurator role only. --- ### System Upgrades #### setPriceOracle Switches to a new price oracle implementation. ```solidity function setPriceOracle(address newPriceOracle) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `newPriceOracle` | `address` | New PriceOracle contract | **Access:** Configurator role only. New oracle must support all configured collateral tokens. --- #### setCreditFacade Migrates to a new Credit Facade, optionally copying existing parameters. ```solidity function setCreditFacade(address newCreditFacade, bool migrateParams) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `newCreditFacade` | `address` | New CreditFacade contract | | `migrateParams` | `bool` | Whether to copy debt limits and other parameters | **Access:** Configurator role only. --- #### upgradeCreditConfigurator Transfers the configurator role to a new contract. ```solidity function upgradeCreditConfigurator(address newCreditConfigurator) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `newCreditConfigurator` | `address` | New CreditConfigurator contract | **Access:** Configurator role only. --- ## View Methods ### creditManager Returns the Credit Manager this configurator manages. ```solidity function creditManager() external view returns (address); ``` --- ### creditFacade Returns the current Credit Facade address. ```solidity function creditFacade() external view returns (address); ``` --- ### underlying Returns the underlying token address. ```solidity function underlying() external view returns (address); ``` --- ## Events ### AddCollateralToken ```solidity event AddCollateralToken(address indexed token, uint16 liquidationThreshold); ``` Emitted when a new collateral token is registered. ### SetLiquidationThreshold ```solidity event SetLiquidationThreshold(address indexed token, uint16 liquidationThreshold); ``` Emitted when a token's LT is changed immediately. ### RampLiquidationThreshold ```solidity event RampLiquidationThreshold( address indexed token, uint16 ltFinal, uint40 rampStart, uint24 rampDuration ); ``` Emitted when a gradual LT change is initiated. ### ForbidToken ```solidity event ForbidToken(address indexed token); ``` Emitted when a token is marked as forbidden. ### AllowToken ```solidity event AllowToken(address indexed token); ``` Emitted when a forbidden token is restored. ### SetFees ```solidity event SetFees( uint16 feeLiquidation, uint16 liquidationPremium, uint16 feeLiquidationExpired, uint16 liquidationPremiumExpired ); ``` Emitted when liquidation fees are updated. ### SetDebtLimits ```solidity event SetDebtLimits(uint128 minDebt, uint128 maxDebt); ``` Emitted when debt bounds are changed. ### AllowAdapter ```solidity event AllowAdapter(address indexed adapter, address indexed targetContract); ``` Emitted when an adapter is registered. ### ForbidAdapter ```solidity event ForbidAdapter(address indexed adapter); ``` Emitted when an adapter is removed. ### SetCreditFacade ```solidity event SetCreditFacade(address indexed creditFacade); ``` Emitted when the Credit Facade is upgraded. ### SetPriceOracle ```solidity event SetPriceOracle(address indexed priceOracle); ``` Emitted when the price oracle is changed. ### UpgradeCreditConfigurator ```solidity event UpgradeCreditConfigurator(address indexed creditConfigurator); ``` Emitted when the configurator itself is upgraded. --- ## Access Control | Role | Capabilities | | --- | --- | | **Configurator** | All structural changes: tokens, fees, adapters, debt limits, upgrades | | **Pausable Admin** | Emergency actions: `forbidToken`, `forbidBorrowing` (no DAO vote required) | The Credit Manager and Facade verify all configuration calls originate from the registered Configurator via the `creditConfiguratorOnly` modifier. --- ## Related Pages - [Credit Manager](https://docs.gearbox.finance/developers/gm-ref-cm) -- Core accounting engine - [Credit Facade](https://docs.gearbox.finance/developers/gm-ref-cf) -- User-facing interface - [Pool (PoolV3)](https://docs.gearbox.finance/developers/gm-ref-pool) -- Liquidity pool - [Smart Contracts Overview](https://docs.gearbox.finance/developers/gm-contracts) -- Full contract architecture ## Use Cases Source: https://docs.gearbox.finance/developers/use-cases-2 File: content/developers/use-cases-2.mdx Practical guides for common Solidity integration patterns with Gearbox. ## Available Guides | Use Case | Description | Guide | | -------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | Adapter Development | Build adapters to integrate new DeFi protocols with Gearbox | [Adapter Development](https://docs.gearbox.finance/developers/adapter-development) | | Protocol Integration | Build protocols that compose with Gearbox Credit Accounts | [Protocol Integration](https://docs.gearbox.finance/developers/protocol-integration) | | Core Extension | Extend Gearbox core contracts (advanced) | [Core Extension](https://docs.gearbox.finance/developers/core-extension) | | Liquidation Bots | Build on-chain liquidation contracts with keeper automation | [Liquidation Bots](https://docs.gearbox.finance/developers/liquidation-bots) | ## Choosing Your Path ### Adapter Development Choose this path if you want to: * Add a new DeFi protocol (DEX, lending, yield) to Gearbox * Enable Credit Accounts to interact with your protocol * Become part of the Gearbox ecosystem Adapters are the bridge between Credit Accounts and external protocols. They enforce security constraints while translating calls to protocol-specific interfaces. ### Protocol Integration Choose this path if you want to: * Build a smart contract that uses Gearbox Credit Accounts * Create automated strategies on top of Gearbox * Compose Gearbox with your own protocol logic Protocol integrations call Gearbox from the outside, building multicalls and executing operations programmatically. ### Core Extension Choose this path if you want to: * Extend Gearbox core functionality (CreditManager, Pool, etc.) * Build custom contract logic that inherits from core contracts * Implement advanced customizations requiring deep protocol knowledge This is an advanced path requiring thorough understanding of Gearbox internals, security considerations, and upgrade patterns. ## Prerequisites All paths require: * Solidity 0.8.x experience * Understanding of the [Multicall System](https://docs.gearbox.finance/developers/multicall-system) * Familiarity with [Credit Accounts](https://docs.gearbox.finance/developers/credit-accounts) ## Related * [Multicalls](https://docs.gearbox.finance/developers/multicalls) - Core encoding patterns * [Multicall Operations](https://docs.gearbox.finance/developers/multicalls) - Individual operation guides * [Credit Accounts](https://docs.gearbox.finance/developers/credit-accounts) - Contract discovery and core interfaces ## Adapter Development Source: https://docs.gearbox.finance/developers/adapter-development File: content/developers/adapter-development.mdx Build adapters to integrate new DeFi protocols with Gearbox Credit Accounts. ## When to Build an Adapter Build an adapter when you want to enable Credit Accounts to interact with a new DeFi protocol. Consider these options: | Approach | When to Use | | ------------------------ | ----------------------------------------------------------------------------------------------------------------- | | **Build an Adapter** | The protocol is mature, has significant TVL, and you want it available across all Gearbox Credit Managers | | **Protocol Integration** | You're building a protocol that wants to accept Credit Accounts as users (e.g., a DEX accepting leveraged trades) | | **Direct Contract** | Your use case doesn't need leverage or margin trading features | Adapters make sense for: * DEX protocols (Uniswap, Curve, Balancer) * Yield vaults (Yearn, ERC-4626 vaults) * Liquid staking protocols (Lido, Rocket Pool) * Lending protocols (Aave, Compound) Do not build adapters for: * Protocols with admin keys that can rug users * Protocols without audits or battle-testing * Highly experimental or unproven contracts ## Architecture Overview Adapters sit between Credit Accounts and external protocols: ``` User -> CreditFacade -> CreditAccount -> Adapter -> Target Protocol | | | +-> Security enforcement | +-> Token state updates | +-> Approval management | +-> Receives output tokens ``` The adapter's job is to: 1. Accept calls from the CreditFacade (not users directly) 2. Translate the call to the target protocol's interface 3. Override recipient addresses to always be the Credit Account 4. Manage token approvals safely 5. Update token states (enable outputs, optionally disable inputs) For architectural background, see [Multicall System](https://docs.gearbox.finance/developers/multicall-system). ## Building Your First Adapter ### Step 1: Inherit AbstractAdapter All adapters extend `AbstractAdapter`: ```solidity import {AbstractAdapter} from "@gearbox-protocol/core-v3/contracts/adapters/AbstractAdapter.sol"; contract MyVaultAdapter is AbstractAdapter { constructor( address _creditManager, address _targetContract ) AbstractAdapter(_creditManager, _targetContract) {} } ``` **Example:** ```solidity // Adapter for an ERC-4626 vault contract ERC4626Adapter is AbstractAdapter { constructor(address _creditManager, address _vault) AbstractAdapter(_creditManager, _vault) {} } ``` ### Step 2: Implement Core Functions Add wrapper functions that call the target protocol: ```solidity function deposit(uint256 assets) external creditFacadeOnly returns (uint256 shares) { address creditAccount = _creditAccount(); // Get token addresses address asset = IERC4626(targetContract).asset(); address vault = targetContract; // Build the call bytes memory callData = abi.encodeCall( IERC4626.deposit, (assets, creditAccount) // Override recipient to creditAccount ); // Execute with safe approval pattern shares = abi.decode( _executeSwapSafeApprove(asset, vault, callData, false), (uint256) ); } ``` **Example:** ```solidity // Withdraw function - burn shares, receive assets function redeem(uint256 shares) external creditFacadeOnly returns (uint256 assets) { address creditAccount = _creditAccount(); address vault = targetContract; address asset = IERC4626(vault).asset(); bytes memory callData = abi.encodeCall( IERC4626.redeem, (shares, creditAccount, creditAccount) ); assets = abi.decode( _executeSwapSafeApprove(vault, asset, callData, false), (uint256) ); } ``` ### Step 3: Implement Diff Functions Diff functions calculate the input amount from the current balance: ```solidity // Standard: requires exact amount function deposit(uint256 assets) external creditFacadeOnly returns (uint256); // Diff: calculates amount as (balance - leftoverAmount) function depositDiff(uint256 leftoverAmount) external creditFacadeOnly returns (uint256); ``` **Example:** ```solidity function depositDiff(uint256 leftoverAmount) external creditFacadeOnly returns (uint256 shares) { address creditAccount = _creditAccount(); address asset = IERC4626(targetContract).asset(); // Calculate actual deposit amount uint256 balance = IERC20(asset).balanceOf(creditAccount); uint256 amount = balance - leftoverAmount; // Call the standard deposit function return deposit(amount); } ``` **Why diff functions exist:** When chaining operations, you often don't know exact amounts: * After a swap, you don't know exact output until execution * After partial withdrawals, remaining balance is variable * Diff functions say "use everything except X" instead of "use exactly Y" ### Step 4: Add Security Modifiers Every external function must use `creditFacadeOnly`: ```solidity // WRONG - allows anyone to call function deposit(uint256 amount) external returns (uint256) { ... } // CORRECT - only CreditFacade can call function deposit(uint256 amount) external creditFacadeOnly returns (uint256) { ... } ``` **Example:** ```solidity // All user-facing functions need the modifier function deposit(uint256 assets) external creditFacadeOnly returns (uint256 shares) { ... } function depositDiff(uint256 leftover) external creditFacadeOnly returns (uint256 shares) { ... } function redeem(uint256 shares) external creditFacadeOnly returns (uint256 assets) { ... } function redeemDiff(uint256 leftover) external creditFacadeOnly returns (uint256 assets) { ... } ``` ## Complete Example: ERC-4626 Vault Adapter Here's a complete adapter for an ERC-4626 vault with all essential patterns: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import {AbstractAdapter} from "@gearbox-protocol/core-v3/contracts/adapters/AbstractAdapter.sol"; import {AdapterType} from "@gearbox-protocol/core-v3/contracts/interfaces/IAdapter.sol"; import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; contract ERC4626Adapter is AbstractAdapter { AdapterType public constant override _gearboxAdapterType = AdapterType.VAULT; constructor(address _creditManager, address _vault) AbstractAdapter(_creditManager, _vault) {} // Deposit assets, receive shares function deposit(uint256 assets) external creditFacadeOnly returns (uint256 shares) { address creditAccount = _creditAccount(); address asset = IERC4626(targetContract).asset(); bytes memory callData = abi.encodeCall( IERC4626.deposit, (assets, creditAccount) ); shares = abi.decode( _executeSwapSafeApprove(asset, targetContract, callData, false), (uint256) ); } // Deposit all assets except leftoverAmount function depositDiff(uint256 leftoverAmount) external creditFacadeOnly returns (uint256 shares) { address creditAccount = _creditAccount(); address asset = IERC4626(targetContract).asset(); uint256 balance = IERC20(asset).balanceOf(creditAccount); return deposit(balance - leftoverAmount); } // Redeem shares, receive assets function redeem(uint256 shares) external creditFacadeOnly returns (uint256 assets) { address creditAccount = _creditAccount(); address asset = IERC4626(targetContract).asset(); bytes memory callData = abi.encodeCall( IERC4626.redeem, (shares, creditAccount, creditAccount) ); assets = abi.decode( _executeSwapSafeApprove(targetContract, asset, callData, false), (uint256) ); } // Redeem all shares except leftoverAmount function redeemDiff(uint256 leftoverAmount) external creditFacadeOnly returns (uint256 assets) { address creditAccount = _creditAccount(); uint256 balance = IERC20(targetContract).balanceOf(creditAccount); return redeem(balance - leftoverAmount); } } ``` ## Security Patterns Deep Dive ### Why creditFacadeOnly Matters Without this modifier, an attacker could call adapter functions directly: **Attack scenario without creditFacadeOnly:** 1. Attacker calls `adapter.deposit(1000)` directly 2. Adapter tries to pull tokens from "current" Credit Account 3. Without CreditFacade context, `_creditAccount()` returns address(0) or wrong account 4. Tokens could be pulled from wrong account or transaction reverts unpredictably **With creditFacadeOnly:** 1. Only CreditFacade can call the adapter 2. CreditFacade sets the active Credit Account before calling 3. Adapter correctly identifies which account to operate on 4. No unauthorized access possible ```solidity // The modifier checks that msg.sender is the CreditFacade modifier creditFacadeOnly() { if (msg.sender != creditFacade) revert CallerNotCreditFacadeException(); _; } ``` ### Recipient Override Pattern Always hardcode the recipient as the Credit Account. Never accept user-specified recipients. **Attack scenario without recipient override:** ```solidity // DANGEROUS - user controls recipient function withdraw(uint256 shares, address recipient) external creditFacadeOnly { IVault(targetContract).redeem(shares, recipient, _creditAccount()); } // Attacker multicall: // 1. Deposit 100 ETH to vault // 2. Call withdraw(shares, attackerAddress) // 3. Funds sent to attacker instead of Credit Account // 4. Credit Account has no collateral, but debt remains ``` **Safe pattern:** ```solidity // CORRECT - recipient is always the Credit Account function withdraw(uint256 shares) external creditFacadeOnly { address creditAccount = _creditAccount(); IVault(targetContract).redeem(shares, creditAccount, creditAccount); } ``` ### Safe Approval Pattern Approvals are reset to 1 (not 0) after each operation. This prevents: * Approval racing attacks * Gas waste from 0 -> N transitions * Front-running of approval transactions ```solidity // _executeSwapSafeApprove does this internally: // 1. Approve tokenIn to target contract // 2. Execute the call // 3. Set approval to 1 (not 0) // 4. Enable tokenOut // 5. Optionally disable tokenIn if balance is 1 wei _executeSwapSafeApprove( tokenIn, // Token being spent tokenOut, // Token being received callData, // The encoded call false // Don't disable tokenIn if non-zero balance remains ); ``` **Why reset to 1 instead of 0:** * ERC-20 standard: 0 -> N costs more gas than 1 -> N * Prevents approval race conditions * Future operations don't need expensive zero-to-nonzero transition ### Token State Management Adapters automatically update which tokens are "enabled" on the Credit Account: ```solidity // After a swap USDC -> WETH: // - WETH mask is enabled (counts toward collateral) // - USDC mask disabled if balance = 1 wei and disableTokenIn = true // If disableTokenIn = false: // - USDC remains enabled even with low balance // - Useful for partial swaps or when you'll receive more USDC later ``` ## Testing with Foundry Test adapters using Foundry fork tests: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import {Test} from "forge-std/Test.sol"; import {ERC4626Adapter} from "../adapters/ERC4626Adapter.sol"; import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; contract ERC4626AdapterTest is Test { ERC4626Adapter adapter; address creditManager = 0x...; // Existing CM on mainnet address vault = 0x...; // Target vault function setUp() public { // Fork mainnet vm.createSelectFork(vm.envString("ETH_RPC_URL")); // Deploy adapter adapter = new ERC4626Adapter(creditManager, vault); } function test_deposit() public { // Setup: get a credit account with assets address creditAccount = _openCreditAccount(); // Execute deposit via CreditFacade uint256 assets = 100e18; uint256 shares = adapter.deposit(assets); // Assertions assertGt(shares, 0, "Should receive shares"); assertEq(IERC20(vault).balanceOf(creditAccount), shares); } function test_depositDiff() public { address creditAccount = _openCreditAccount(); uint256 initialBalance = 100e18; uint256 leftover = 1; uint256 shares = adapter.depositDiff(leftover); assertEq(shares, adapter.previewDeposit(initialBalance - leftover)); } function test_cannotCallDirectly() public { vm.expectRevert(); // CallerNotCreditFacadeException adapter.deposit(100e18); } } ``` **Key test patterns:** 1. **Fork testing** - Test against real protocols on mainnet/testnet 2. **Access control** - Verify creditFacadeOnly works 3. **Balance checks** - Assert correct token transfers 4. **Diff functions** - Verify correct amount calculation 5. **Edge cases** - Test with zero amounts, max values, etc. ## Deployment and Whitelisting After writing and testing your adapter: 1. **Deploy the adapter** - Deploy to mainnet with CreditManager and target addresses 2. **Submit governance proposal** - Request adapter whitelisting via Gearbox governance 3. **Governance vote** - DAO votes on adding adapter to Credit Manager(s) 4. **Adapter registration** - If approved, adapter is added to allowedAdapters mapping **Governance process:** * Submit proposal on Gearbox governance forum * Include audit report (required for new adapters) * Specify which Credit Manager(s) should whitelist it * DAO votes on proposal * If passed, adapter becomes available for Credit Accounts **Note:** Each Credit Manager has its own adapter whitelist. An adapter approved for one Credit Manager isn't automatically available on others. For architectural background, see [Multicall System](https://docs.gearbox.finance/developers/multicall-system). ## Best Practices 1. **Keep it simple** - Adapters should be thin wrappers, not business logic 2. **No state** - Adapters should be stateless (except immutables) 3. **Comprehensive diff** - Implement diff functions for all variable-amount operations 4. **Always override recipients** - Never let users specify where funds go 5. **Test thoroughly** - Test both success and failure paths 6. **Document clearly** - Write NatSpec comments explaining each function 7. **Declare adapter type** - Set `_gearboxAdapterType` for proper categorization ## Key Inherited Functions AbstractAdapter provides these helper functions: | Function | Description | | ------------------------------ | --------------------------------------- | | `_creditAccount()` | Returns current Credit Account address | | `_creditManager()` | Returns Credit Manager address | | `_creditFacade()` | Returns Credit Facade address | | `_getMaskOrRevert(token)` | Gets token mask, reverts if not allowed | | `_execute(callData)` | Executes call on target contract | | `_executeSwapSafeApprove(...)` | Executes call with approval management | | `targetContract` | Immutable address of wrapped protocol | ## Related * [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls) - Using adapters in multicalls * [Multicall System](https://docs.gearbox.finance/developers/multicall-system) - Architectural overview ## Pool (PoolV3) Source: https://docs.gearbox.finance/developers/gm-ref-pool File: content/developers/gm-ref-pool.mdx **PoolV3** is the central vault for a specific underlying asset (e.g., USDC, WETH). It implements the ERC-4626 tokenized vault standard, allowing users to deposit assets and receive Diesel Tokens (LP shares). Only whitelisted Credit Managers can borrow from the pool. --- ## Write Methods ### ERC-4626 Standard #### deposit Deposits underlying assets and receives diesel tokens (shares). ```solidity function deposit(uint256 assets, address receiver) external returns (uint256 shares); ``` | Parameter | Type | Description | | --- | --- | --- | | `assets` | `uint256` | Amount of underlying tokens to deposit | | `receiver` | `address` | Address to receive the minted shares | **Returns:** Number of shares minted. --- #### mint Mints an exact number of shares, depositing the required underlying assets. ```solidity function mint(uint256 shares, address receiver) external returns (uint256 assets); ``` | Parameter | Type | Description | | --- | --- | --- | | `shares` | `uint256` | Exact number of shares to mint | | `receiver` | `address` | Address to receive the minted shares | **Returns:** Amount of underlying assets deposited. --- #### withdraw Withdraws an exact amount of underlying assets, burning the required shares. ```solidity function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); ``` | Parameter | Type | Description | | --- | --- | --- | | `assets` | `uint256` | Exact amount of underlying to withdraw | | `receiver` | `address` | Address to receive the assets | | `owner` | `address` | Address whose shares are burned | **Returns:** Number of shares burned. Reverts if pool is paused or insufficient liquidity. --- #### redeem Burns an exact number of shares and receives underlying assets. ```solidity function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); ``` | Parameter | Type | Description | | --- | --- | --- | | `shares` | `uint256` | Exact number of shares to burn | | `receiver` | `address` | Address to receive the assets | | `owner` | `address` | Address whose shares are burned | **Returns:** Amount of underlying assets received. --- ### Gearbox Extensions #### depositWithReferral Deposits underlying assets with on-chain referral tracking. ```solidity function depositWithReferral(uint256 assets, address receiver, uint256 referralCode) external returns (uint256 shares); ``` | Parameter | Type | Description | | --- | --- | --- | | `assets` | `uint256` | Amount of underlying tokens to deposit | | `receiver` | `address` | Address to receive the minted shares | | `referralCode` | `uint256` | Referral code for tracking | **Returns:** Number of shares minted. --- #### lendCreditAccount Lends underlying assets to a Credit Account. Called by the Credit Manager during debt increase. ```solidity function lendCreditAccount(uint256 borrowedAmount, address creditAccount) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `borrowedAmount` | `uint256` | Amount to lend | | `creditAccount` | `address` | Receiving Credit Account | **Access:** Whitelisted Credit Manager only. --- #### repayCreditAccount Repays borrowed assets from a Credit Account. Called by the Credit Manager during debt decrease, closure, or liquidation. ```solidity function repayCreditAccount(uint256 repaidAmount, uint256 profit, uint256 loss) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `repaidAmount` | `uint256` | Amount being repaid | | `profit` | `uint256` | Profit amount (added to treasury) | | `loss` | `uint256` | Loss amount (may burn treasury shares or socialize) | **Access:** Whitelisted Credit Manager only. --- ## View Methods ### ERC-4626 Standard #### totalAssets Returns the total value of underlying assets held by the pool. ```solidity function totalAssets() external view returns (uint256); ``` --- #### convertToShares / convertToAssets Preview conversion between assets and shares. ```solidity function convertToShares(uint256 assets) external view returns (uint256 shares); function convertToAssets(uint256 shares) external view returns (uint256 assets); ``` --- #### previewDeposit / previewMint / previewWithdraw / previewRedeem Preview the result of deposit, mint, withdraw, or redeem operations. ```solidity function previewDeposit(uint256 assets) external view returns (uint256 shares); function previewMint(uint256 shares) external view returns (uint256 assets); function previewWithdraw(uint256 assets) external view returns (uint256 shares); function previewRedeem(uint256 shares) external view returns (uint256 assets); ``` --- #### maxDeposit / maxMint / maxWithdraw / maxRedeem Returns the maximum amount that can be deposited, minted, withdrawn, or redeemed. ```solidity function maxDeposit(address receiver) external view returns (uint256); function maxMint(address receiver) external view returns (uint256); function maxWithdraw(address owner) external view returns (uint256); function maxRedeem(address owner) external view returns (uint256); ``` --- #### asset Returns the underlying token address. ```solidity function asset() external view returns (address); ``` --- ### Gearbox-Specific Views #### availableLiquidity Returns the amount of underlying tokens available for borrowing. ```solidity function availableLiquidity() external view returns (uint256); ``` --- #### dieselRate Returns the current share price in RAY (27 decimals). Starts at `10^27` and increases as interest accrues. ```solidity function dieselRate() external view returns (uint256); ``` --- #### supplyRate Returns the annualized supply rate for lenders in RAY. ```solidity function supplyRate() external view returns (uint256); ``` --- #### baseInterestRate Returns the annualized borrow rate for Credit Accounts in RAY. ```solidity function baseInterestRate() external view returns (uint256); ``` --- #### baseInterestIndex Returns the cumulative interest index used for debt tracking. ```solidity function baseInterestIndex() external view returns (uint256); ``` --- #### poolQuotaKeeper Returns the address of the associated PoolQuotaKeeper. ```solidity function poolQuotaKeeper() external view returns (address); ``` --- #### interestRateModel Returns the address of the Interest Rate Model contract. ```solidity function interestRateModel() external view returns (address); ``` --- ## Events ### Deposit ```solidity event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); ``` Emitted on deposit or mint (ERC-4626 standard). ### Withdraw ```solidity event Withdraw( address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares ); ``` Emitted on withdraw or redeem (ERC-4626 standard). ### Borrow ```solidity event Borrow(address indexed creditManager, address indexed creditAccount, uint256 amount); ``` Emitted when a Credit Manager borrows from the pool. ### Repay ```solidity event Repay(address indexed creditManager, uint256 borrowedAmount, uint256 profit, uint256 loss); ``` Emitted when a Credit Manager repays to the pool. --- ## Related Pages - [Quota Keeper](https://docs.gearbox.finance/developers/gm-ref-qk) -- Manages per-token quota limits and rates - [Credit Manager](https://docs.gearbox.finance/developers/gm-ref-cm) -- Borrows from the pool on behalf of Credit Accounts - [Compressors](https://docs.gearbox.finance/developers/gm-ref-compressors) -- Aggregated pool data reading - [Smart Contracts Overview](https://docs.gearbox.finance/developers/gm-contracts) -- Full contract architecture ## Protocol Integration Source: https://docs.gearbox.finance/developers/protocol-integration File: content/developers/protocol-integration.mdx Build smart contracts that compose with Gearbox Credit Accounts. ## Overview Protocol integration means building contracts that: * Call Gearbox Credit Accounts from external contracts * Create automated strategies using multicalls * Compose Gearbox with your own protocol logic Unlike adapters (which are called BY Credit Accounts), protocol integrations CALL Credit Accounts from outside. ## Architecture ``` Your Contract -> CreditFacade -> Credit Account -> Adapters -> DeFi Protocols | +-> Multicall execution +-> Collateral checks +-> Access control ``` ## Basic Integration Pattern ### 1. Find the Right Market ```solidity import {IAddressProviderV3} from "@gearbox-protocol/core-v3/contracts/interfaces/IAddressProviderV3.sol"; import {IContractsRegister} from "@gearbox-protocol/core-v3/contracts/interfaces/IContractsRegister.sol"; import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; contract MyStrategy { IAddressProviderV3 public constant ADDRESS_PROVIDER = IAddressProviderV3(0x9ea7b04Da02a5373317D745c1571c84aaD03321D); ICreditFacadeV3 public creditFacade; address public creditManager; function initialize(address _creditManager) external { creditManager = _creditManager; // Get CreditFacade from CreditManager creditFacade = ICreditFacadeV3( ICreditManagerV3(_creditManager).creditFacade() ); } } ``` ### 2. Build and Execute Multicalls ```solidity import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; function depositToStrategy( address creditAccount, address token, uint256 amount ) external { MultiCall[] memory calls = new MultiCall[](1); calls[0] = MultiCall({ target: address(creditFacade), callData: abi.encodeCall( ICreditFacadeV3Multicall.addCollateral, (token, amount) ) }); // Caller must approve creditManager first creditFacade.multicall(creditAccount, calls); } ``` ## Common Integration Patterns ### Automated Strategy Contract A contract that executes predefined strategies: ```solidity // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.17; import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {IUniswapV3Adapter} from "@gearbox-protocol/integrations-v3/contracts/interfaces/uniswap/IUniswapV3Adapter.sol"; import {ISwapRouter} from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; contract LeveragedYieldStrategy { ICreditFacadeV3 public immutable creditFacade; ICreditManagerV3 public immutable creditManager; address public immutable underlying; address public immutable targetAsset; address public immutable uniswapAdapter; address public immutable yieldAdapter; constructor( address _creditManager, address _targetAsset, address _yieldVault ) { creditManager = ICreditManagerV3(_creditManager); creditFacade = ICreditFacadeV3(creditManager.creditFacade()); underlying = creditManager.underlying(); targetAsset = _targetAsset; // Find adapters uniswapAdapter = creditManager.contractToAdapter( 0xE592427A0AEce92De3Edee1F18E0157C05861564 // Uniswap V3 Router ); yieldAdapter = creditManager.contractToAdapter(_yieldVault); require(uniswapAdapter != address(0), "Uniswap adapter not found"); require(yieldAdapter != address(0), "Yield adapter not found"); } /// @notice Open leveraged yield position /// @param collateralAmount Initial collateral /// @param leverage Leverage multiplier (e.g., 4 for 4x) /// @param minYieldTokens Minimum yield tokens to receive function openPosition( uint256 collateralAmount, uint256 leverage, uint256 minYieldTokens ) external returns (address creditAccount) { require(leverage >= 1 && leverage <= 10, "Invalid leverage"); uint256 borrowAmount = collateralAmount * (leverage - 1); MultiCall[] memory calls = new MultiCall[](4); // 1. Add collateral calls[0] = MultiCall({ target: address(creditFacade), callData: abi.encodeCall( ICreditFacadeV3Multicall.addCollateral, (underlying, collateralAmount) ) }); // 2. Borrow calls[1] = MultiCall({ target: address(creditFacade), callData: abi.encodeCall( ICreditFacadeV3Multicall.increaseDebt, (borrowAmount) ) }); // 3. Swap to target asset uint256 totalAmount = collateralAmount + borrowAmount; ISwapRouter.ExactInputSingleParams memory swapParams = ISwapRouter.ExactInputSingleParams({ tokenIn: underlying, tokenOut: targetAsset, fee: 500, recipient: address(0), deadline: block.timestamp + 3600, amountIn: totalAmount, amountOutMinimum: 0, // Using yield token check instead sqrtPriceLimitX96: 0 }); calls[2] = MultiCall({ target: uniswapAdapter, callData: abi.encodeCall( IUniswapV3Adapter.exactInputSingle, (swapParams) ) }); // 4. Deposit to yield vault using diff pattern calls[3] = MultiCall({ target: yieldAdapter, callData: abi.encodeCall( IYearnV2Adapter.depositDiff, (1) // Leave 1 wei ) }); // Approve and open IERC20(underlying).transferFrom(msg.sender, address(this), collateralAmount); IERC20(underlying).approve(address(creditManager), collateralAmount); creditAccount = creditFacade.openCreditAccount(msg.sender, calls, 0); } } ``` ### Strategy with Price Updates When using Pyth or Redstone oracles, your contract must accept and forward price data: ```solidity /// @notice Execute strategy with price updates /// @param creditAccount Target Credit Account /// @param priceUpdates Array of (token, reserve, data) for on-demand oracles /// @param strategyParams Your strategy-specific parameters function executeWithPriceUpdates( address creditAccount, bytes[] calldata priceUpdates, StrategyParams calldata strategyParams ) external { uint256 numUpdates = priceUpdates.length; // Build calls with price updates first MultiCall[] memory calls = new MultiCall[](numUpdates + strategyParams.numCalls); // Add all price updates at the beginning for (uint256 i = 0; i < numUpdates; i++) { (address token, bool reserve, bytes memory data) = abi.decode(priceUpdates[i], (address, bool, bytes)); calls[i] = MultiCall({ target: address(creditFacade), callData: abi.encodeCall( ICreditFacadeV3Multicall.onDemandPriceUpdate, (token, reserve, data) ) }); } // Add strategy calls after price updates _buildStrategyCalls(calls, numUpdates, strategyParams); creditFacade.multicall(creditAccount, calls); } ``` ### Keeper/Bot Integration For automated position management: ```solidity contract PositionKeeper { ICreditFacadeV3 public immutable creditFacade; address public keeper; mapping(address => bool) public managedAccounts; modifier onlyKeeper() { require(msg.sender == keeper, "Not keeper"); _; } /// @notice Rebalance position when health factor is low function rebalance( address creditAccount, address tokenToSell, uint256 sellAmount, uint256 minRepay ) external onlyKeeper { require(managedAccounts[creditAccount], "Not managed"); MultiCall[] memory calls = new MultiCall[](2); // 1. Swap collateral for underlying calls[0] = MultiCall({ target: uniswapAdapter, callData: abi.encodeCall( IUniswapV3Adapter.exactInputSingle, (swapParams) ) }); // 2. Repay debt using diff pattern calls[1] = MultiCall({ target: address(creditFacade), callData: abi.encodeCall( ICreditFacadeV3Multicall.decreaseDebt, (minRepay) ) }); // Execute as bot (requires bot permissions on account) creditFacade.botMulticall(creditAccount, calls); } } ``` ## Access Control Considerations ### Account Ownership Only the account owner (or approved bots) can execute multicalls: ```solidity // This will revert if msg.sender is not account owner creditFacade.multicall(creditAccount, calls); // For keeper/bot access, the owner must grant permissions first // This is done via setBotPermissions in a multicall ``` ### Bot Permissions To allow external contracts to manage accounts: ```solidity // Owner grants bot permissions MultiCall[] memory calls = new MultiCall[](1); calls[0] = MultiCall({ target: address(creditFacade), callData: abi.encodeCall( ICreditFacadeV3Multicall.setBotPermissions, ( botAddress, uint192(1 << 0 | 1 << 1) // Permission flags for allowed operations ) ) }); creditFacade.multicall(creditAccount, calls); ``` Then the bot can use `botMulticall`: ```solidity // Bot executes with limited permissions creditFacade.botMulticall(creditAccount, calls); ``` ## Error Handling ### Reading Account State Before Operations ```solidity function getAccountHealth(address creditAccount) external view returns (uint256) { ( uint256 debt, uint256 cumulativeIndexLastUpdate, uint128 cumulativeQuotaInterest, uint128 quotaFees, uint256 enabledTokensMask, uint16 flags, uint64 lastDebtUpdate, address borrower ) = creditManager.creditAccountInfo(creditAccount); // Calculate health factor using collateral values // ... } ``` ### Handling Reverts ```solidity function safeExecute( address creditAccount, MultiCall[] memory calls ) external returns (bool success) { try creditFacade.multicall(creditAccount, calls) { success = true; } catch Error(string memory reason) { emit ExecutionFailed(creditAccount, reason); success = false; } } ``` ## Gas Optimization ### Use Collateral Hints For accounts with many tokens, provide hints to reduce oracle calls: ```solidity // Get token masks for primary collateral uint256 usdcMask = creditManager.getTokenMaskOrRevert(usdc); uint256 wethMask = creditManager.getTokenMaskOrRevert(weth); uint256[] memory hints = new uint256[](2); hints[0] = usdcMask; hints[1] = wethMask; // Add setFullCheckParams as first non-price-update call calls[0] = MultiCall({ target: address(creditFacade), callData: abi.encodeCall( ICreditFacadeV3Multicall.setFullCheckParams, (hints, 10000) // 1.0 min health factor ) }); ``` ### Batch Operations Combine related operations in single multicalls rather than multiple transactions: ```solidity // GOOD - single multicall MultiCall[] memory calls = new MultiCall[](4); calls[0] = addCollateralCall; calls[1] = borrowCall; calls[2] = swapCall; calls[3] = depositCall; creditFacade.multicall(account, calls); // BAD - multiple transactions (more gas, atomicity issues) creditFacade.multicall(account, [addCollateralCall]); creditFacade.multicall(account, [borrowCall]); creditFacade.multicall(account, [swapCall]); ``` ## Testing ### Foundry Setup ```solidity import {Test} from "forge-std/Test.sol"; contract StrategyTest is Test { LeveragedYieldStrategy strategy; address user = address(0x1); function setUp() public { // Fork mainnet vm.createSelectFork("mainnet"); // Deploy strategy strategy = new LeveragedYieldStrategy( CREDIT_MANAGER, TARGET_ASSET, YIELD_VAULT ); } function test_openPosition() public { // Setup deal(USDC, user, 10_000e6); vm.startPrank(user); IERC20(USDC).approve(address(strategy), 10_000e6); // Execute address account = strategy.openPosition(10_000e6, 4, 0); // Verify assertTrue(account != address(0)); assertGt(IERC20(YIELD_TOKEN).balanceOf(account), 0); vm.stopPrank(); } } ``` ## Security Considerations 1. **Reentrancy** - Multicalls are atomic, but be careful with callbacks 2. **Slippage** - Always use `storeExpectedBalances`/`compareBalances` for swaps 3. **Access control** - Verify account ownership before operations 4. **Oracle manipulation** - Use safe pricing for withdrawals 5. **Flash loan attacks** - Consider same-block restrictions on debt changes ## Related * [Multicalls](https://docs.gearbox.finance/developers/multicalls) - Core encoding patterns * [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls) - Using adapters * [Controlling Slippage](https://docs.gearbox.finance/developers/controlling-slippage) - Protecting operations * [Adapter Development](https://docs.gearbox.finance/developers/adapter-development) - Building adapters ## Quota Keeper Source: https://docs.gearbox.finance/developers/gm-ref-qk File: content/developers/gm-ref-qk.mdx The **PoolQuotaKeeperV3** regulates how much pool capital can be exposed to specific collateral types and at what cost. It tracks per-token quota limits, interest rates, and cumulative indices. Unlike the base debt which compounds, quota interest is additive (linear). --- ## Write Methods ### updateQuota Updates the quota for a specific token on a Credit Account. Called by the Credit Manager during multicall execution. ```solidity function updateQuota( address creditAccount, address token, int96 quotaChange, uint96 minQuota ) external returns (uint256 tokensToEnable, uint256 tokensToDisable); ``` | Parameter | Type | Description | | --- | --- | --- | | `creditAccount` | `address` | Credit Account to update | | `token` | `address` | Token whose quota is being changed | | `quotaChange` | `int96` | Amount to increase (positive) or decrease (negative) | | `minQuota` | `uint96` | Minimum quota to maintain (reverts if result is below this and non-zero) | **Returns:** Token masks to enable/disable based on quota state. **Access:** Credit Manager only. Reverts with `QuotaIsOutOfBoundsException` if `totalQuoted` would exceed the token's limit. --- ### setTokenLimit Sets the maximum aggregate quota for a specific token across all Credit Accounts. ```solidity function setTokenLimit(address token, uint96 limit) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `token` | `address` | Collateral token | | `limit` | `uint96` | Maximum total quota allowed | **Access:** Configurator only. Prevents over-exposure to any single asset. --- ### setTokenQuotaIncreaseFee Sets the fee charged when a quota is increased. ```solidity function setTokenQuotaIncreaseFee(address token, uint16 fee) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `token` | `address` | Collateral token | | `fee` | `uint16` | Fee in basis points | **Access:** Configurator only. --- ### addQuotaToken Registers a new token for quota tracking. ```solidity function addQuotaToken(address token) external; ``` | Parameter | Type | Description | | --- | --- | --- | | `token` | `address` | Token to register | **Access:** Configurator only. --- ### updateRates Syncs quota interest rates from the Gauge/Tumbler (rate keeper). Must be called for rate changes to take effect. ```solidity function updateRates() external; ``` **Access:** Rate keeper (Gauge or Tumbler) only. --- ## View Methods ### getTokenQuotaParams Returns the global quota parameters for a token. ```solidity function getTokenQuotaParams(address token) external view returns ( uint16 rate, uint192 cumulativeIndex, uint16 quotaIncreaseFee, uint96 totalQuoted, uint96 limit, bool isActive ); ``` | Return Value | Type | Description | | --- | --- | --- | | `rate` | `uint16` | Annual interest rate in basis points | | `cumulativeIndex` | `uint192` | Cumulative index for interest calculation | | `quotaIncreaseFee` | `uint16` | Fee charged on quota increases (bps) | | `totalQuoted` | `uint96` | Total quota across all Credit Accounts | | `limit` | `uint96` | Maximum allowed total quota | | `isActive` | `bool` | Whether the token is currently active | --- ### getQuotaAndOutstandingInterest Returns the quota and accrued interest for a specific Credit Account and token. ```solidity function getQuotaAndOutstandingInterest( address creditAccount, address token ) external view returns (uint96 quoted, uint128 outstandingInterest); ``` | Return Value | Type | Description | | --- | --- | --- | | `quoted` | `uint96` | Amount of quota held by the account | | `outstandingInterest` | `uint128` | Accrued interest not yet added to debt | --- ### quotedTokens Returns the list of all tokens registered for quota tracking. ```solidity function quotedTokens() external view returns (address[] memory); ``` --- ### pool Returns the associated pool address. ```solidity function pool() external view returns (address); ``` --- ### gauge Returns the rate keeper (Gauge or Tumbler) address. ```solidity function gauge() external view returns (address); ``` --- ## Events ### UpdateQuota ```solidity event UpdateQuota( address indexed creditAccount, address indexed token, int96 quotaChange ); ``` Emitted when a Credit Account's quota is changed. ### SetTokenLimit ```solidity event SetTokenLimit(address indexed token, uint96 limit); ``` Emitted when a token's quota limit is updated. ### SetTokenQuotaIncreaseFee ```solidity event SetTokenQuotaIncreaseFee(address indexed token, uint16 fee); ``` Emitted when a quota increase fee is set. ### AddQuotaToken ```solidity event AddQuotaToken(address indexed token); ``` Emitted when a new token is registered for quota tracking. ### UpdateRates ```solidity event UpdateRates(); ``` Emitted when quota rates are synced from the rate keeper. --- ## Rate Keeper Models The QuotaKeeper relies on an external rate keeper to provide interest rates: | Model | Description | | --- | --- | | **GaugeV3** | Decentralized voting model where GEAR stakers vote to set rates between `minRate` and `maxRate` | | **TumblerV3** | Curator-controlled model with direct rate setting via `setRate(token, rate)` and epoch-based updates | --- ## Related Pages - [Pool (PoolV3)](https://docs.gearbox.finance/developers/gm-ref-pool) -- The vault that QuotaKeeper is associated with - [Credit Manager](https://docs.gearbox.finance/developers/gm-ref-cm) -- Calls `updateQuota` during multicall execution - [Credit Configurator](https://docs.gearbox.finance/developers/gm-ref-cc) -- Manages quota parameters through the configurator role - [Smart Contracts Overview](https://docs.gearbox.finance/developers/gm-contracts) -- Full contract architecture ## Compressors Source: https://docs.gearbox.finance/developers/gm-ref-compressors File: content/developers/gm-ref-compressors.mdx Compressor contracts are read-only data aggregation contracts. Instead of dozens of individual calls, a single compressor call returns complete protocol state. The SDK uses compressors internally. ## Discovering Compressor Addresses Use `AddressProvider` to find compressor addresses: ```solidity address compressor = addressProvider.getLatestAddressByContractType( AP_MARKET_COMPRESSOR, VERSION_RANGE_310 ); ``` ```typescript const [compressor] = sdk.addressProvider.mustGetLatest( AP_MARKET_COMPRESSOR, VERSION_RANGE_310 ); ``` --- ## MarketCompressor Aggregates complete market state including pools, credit managers, and price oracles. ### View Methods #### getMarkets Returns market data for all markets matching the filter. ```solidity function getMarkets(MarketFilter memory filter) external view returns (MarketData[] memory); ``` | Parameter | Type | Description | | --- | --- | --- | | `filter` | `MarketFilter` | Filter criteria (see below) | **Returns:** Array of `MarketData` structs. --- #### getMarketData Returns complete data for a single market identified by its pool address. ```solidity function getMarketData(address pool) external view returns (MarketData memory); ``` | Parameter | Type | Description | | --- | --- | --- | | `pool` | `address` | Pool address identifying the market | --- #### getPoolState Returns the pool state for a given pool. ```solidity function getPoolState(address pool) external view returns (PoolState memory); ``` | Parameter | Type | Description | | --- | --- | --- | | `pool` | `address` | Pool address | --- ### Data Structures #### 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. #### MarketData ```solidity struct MarketData { PoolState pool; QuotaKeeperState quotaKeeper; CreditSuiteData[] creditManagers; PriceOracleState priceOracle; TokenData[] tokens; } ``` #### PoolState (key fields) | Field | Type | Description | | --- | --- | --- | | `baseParams.addr` | `address` | Pool contract address | | `availableLiquidity` | `uint256` | Borrowable liquidity | | `dieselRate` | `uint256` | Share price (RAY) | | `supplyRate` | `uint256` | Lender APY (RAY) | | `baseInterestRate` | `uint256` | Borrower APR (RAY) | | `totalAssets` | `uint256` | Total pool value | #### CreditSuiteData (key fields) | Field | Type | Description | | --- | --- | --- | | `creditManager` | `address` | Credit Manager address | | `creditFacade` | `address` | Credit Facade address | | `creditConfigurator` | `address` | Configurator address | | `debtLimits` | `DebtLimits` | Min/max debt per account | | `collateralTokens` | `CollateralToken[]` | Allowed tokens + LTs | --- ## CreditAccountCompressor Fetches credit account data with filtering and pagination. ### View Methods #### getCreditAccounts Returns credit accounts matching the filter with pagination support. ```solidity function getCreditAccounts( address creditManager, CreditAccountFilter memory filter, uint256 offset ) external view returns (CreditAccountData[] memory accounts, uint256 total); ``` | Parameter | Type | Description | | --- | --- | --- | | `creditManager` | `address` | Credit Manager to query | | `filter` | `CreditAccountFilter` | Filter criteria (see below) | | `offset` | `uint256` | Pagination offset | **Returns:** Matching accounts and total count. --- #### countCreditAccounts Returns the count of credit accounts matching the filter. ```solidity function countCreditAccounts( address creditManager, CreditAccountFilter memory filter ) external view returns (uint256); ``` --- #### getCreditAccountData Returns complete data for a single credit account. ```solidity function getCreditAccountData( address creditManager, address creditAccount ) external view returns (CreditAccountData memory); ``` | Parameter | Type | Description | | --- | --- | --- | | `creditManager` | `address` | Parent Credit Manager | | `creditAccount` | `address` | Account to query | --- ### Data Structures #### CreditAccountFilter ```solidity struct CreditAccountFilter { address owner; // Filter by owner (address(0) = any) uint256 minHealthFactor; // Minimum HF (0 = no min) uint256 maxHealthFactor; // Maximum HF (type(uint256).max = no max) bool includeZeroDebt; // Include accounts with no debt bool reverting; // Include reverting accounts } ``` #### CreditAccountData (key fields) | Field | Type | Description | | --- | --- | --- | | `addr` | `address` | Credit Account address | | `owner` | `address` | Account owner | | `creditManager` | `address` | Parent Credit Manager | | `debt` | `uint256` | Total debt (principal + interest) | | `enabledTokensMask` | `uint256` | Bitmask of enabled tokens | | `healthFactor` | `uint256` | Current HF (10000 = 1.0) | | `tokens` | `TokenInfo[]` | Token balances and values | | `isLiquidatable` | `bool` | Whether account can be liquidated | --- ## PriceFeedCompressor Aggregates price feed state for oracle monitoring and updates. ### View Methods #### getUpdatablePriceFeeds Returns all price feeds that may need updating for a given price oracle. ```solidity function getUpdatablePriceFeeds(address priceOracle) external view returns (PriceFeedData[] memory); ``` | Parameter | Type | Description | | --- | --- | --- | | `priceOracle` | `address` | PriceOracle contract to query | **Returns:** Array of price feed data including staleness information. --- #### loadPriceFeedTree Returns the full price feed dependency tree for a specific token. ```solidity function loadPriceFeedTree(address priceOracle, address token) external view returns (PriceFeedTreeNode memory); ``` | Parameter | Type | Description | | --- | --- | --- | | `priceOracle` | `address` | PriceOracle contract | | `token` | `address` | Token to query | --- ## When to Use Compressors vs SDK | Scenario | Approach | | --- | --- | | General market data | SDK `marketRegister` | | Credit account queries | SDK services | | Custom filtering logic | Direct compressor calls | | Liquidation bots | Direct compressor (gas-optimized) | | On-chain integration | Direct compressor (no SDK in contracts) | | Real-time monitoring | Direct compressor with specific filters | --- ## Related Pages - [Pool (PoolV3)](https://docs.gearbox.finance/developers/gm-ref-pool) -- Pool state returned by MarketCompressor - [Credit Manager](https://docs.gearbox.finance/developers/gm-ref-cm) -- Credit accounts queried by CreditAccountCompressor - [Quota Keeper](https://docs.gearbox.finance/developers/gm-ref-qk) -- Quota data included in MarketData - [Smart Contracts Overview](https://docs.gearbox.finance/developers/gm-contracts) -- Full contract architecture ## Core Extension Source: https://docs.gearbox.finance/developers/core-extension File: content/developers/core-extension.mdx Advanced patterns for extending Gearbox protocol contracts beyond standard adapter integration. > This is advanced material. For standard integrations, see [Adapter Development](https://docs.gearbox.finance/developers/adapter-development) or [Protocol Integration](https://docs.gearbox.finance/developers/protocol-integration). ## When to Extend vs Integrate Different levels of integration require different approaches: | Approach | Complexity | When to Use | | ------------------------ | ---------- | -------------------------------------------------------------------- | | **Adapter** | Low | Wrap existing DeFi protocols for Credit Account access | | **Protocol Integration** | Medium | Build contracts that compose with Credit Accounts externally | | **Core Extension** | High | Modify Credit Manager/Pool behavior, create protocol-specific spokes | Examples by approach: **Adapter:** Wrapping Uniswap, Curve, Yearn for Credit Account users **Protocol Integration:** Strategy vaults that open/manage Credit Accounts **Core Extension:** Custom Credit Manager for protocol-specific accounting, custom interest rate models, pool hooks for fee distribution Build a core extension when you need to: * Modify how debt/collateral calculations work * Change liquidity flow patterns between pools and Credit Managers * Implement protocol-specific Credit Manager variants ("spokes") * Create custom interest rate logic beyond linear models * Add lifecycle hooks to pool operations ## Understanding Money Flows Core extensions require deep understanding of how liquidity moves through the protocol. ### The Fundamental Flow ``` Lenders → Pool → Credit Manager → Credit Account → DeFi Protocols (ERC-4626) | | | +-> Holds collateral +-> Tracks debt ``` **Key invariants:** 1. Pool lends only to whitelisted Credit Managers 2. Credit Managers borrow on behalf of Credit Accounts 3. Credit Accounts hold all collateral and debt 4. All value flows are tracked via indexed interest and quota systems ### Detailed Liquidity Flow **When borrowing:** ```solidity // 1. User opens Credit Account via CreditFacade CreditFacade.openCreditAccount(owner, calls, referralCode) | v // 2. Facade instructs Manager to borrow CreditManager.openCreditAccount(debt, onBehalfOf) | v // 3. Manager requests liquidity from Pool Pool.lendCreditAccount(borrowedAmount, creditAccount) | v // 4. Pool transfers underlying directly to Credit Account IERC20(underlying).transfer(creditAccount, borrowedAmount) ``` **When repaying:** ```solidity // 1. User closes account via CreditFacade CreditFacade.closeCreditAccount(creditAccount, calls) | v // 2. Manager calculates total debt totalDebt = principal + accruedInterest + quotaInterest + fees | v // 3. Underlying transfers from Credit Account to Pool IERC20(underlying).transferFrom(creditAccount, pool, totalDebt) | v // 4. Manager reports repayment to Pool Pool.repayCreditAccount(repaidAmount, profit, loss) ``` **Critical detail:** The Credit Manager never holds funds. It orchestrates transfers between Pool and Credit Account while maintaining accounting state. ## Pool Extension Patterns ### Custom Interest Rate Models The pool queries an external IRM contract for interest rates. You can implement custom logic by deploying a new IRM. **IInterestRateModel interface:** ```solidity interface ILinearInterestRateModelV3 { function calcBorrowRate( uint256 expectedLiquidity, uint256 availableLiquidity, bool checkOptimalBorrowing ) external view returns (uint256 borrowRate); function getModelParameters() external view returns ( uint16 U_1, uint16 U_2, uint16 R_base, uint16 R_slope1, uint16 R_slope2, uint16 R_slope3 ); } ``` **Example: Time-weighted interest model** ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import {ILinearInterestRateModelV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ILinearInterestRateModelV3.sol"; contract TimeWeightedIRM is ILinearInterestRateModelV3 { uint16 public immutable U_1 = 7000; // 70% uint16 public immutable U_2 = 9000; // 90% uint16 public immutable R_base = 100; // 1% uint16 public immutable R_slope1 = 200; // 2% uint16 public immutable R_slope2 = 500; // 5% // Time-based slope adjustment uint16 public immutable peakHourMultiplier = 150; // 1.5x during peak hours function calcBorrowRate( uint256 expectedLiquidity, uint256 availableLiquidity, bool checkOptimalBorrowing ) external view returns (uint256 borrowRate) { uint256 utilizationBps = (expectedLiquidity - availableLiquidity) * 10_000 / expectedLiquidity; // Apply time-based multiplier during peak hours (12-18 UTC) uint256 hour = (block.timestamp / 3600) % 24; uint16 multiplier = (hour >= 12 && hour < 18) ? peakHourMultiplier : 100; // Standard linear calculation with time adjustment uint256 baseRate = R_base; if (utilizationBps <= U_1) { borrowRate = baseRate + (R_slope1 * utilizationBps * multiplier) / 10_000 / 100; } else if (utilizationBps <= U_2) { borrowRate = baseRate + (R_slope2 * utilizationBps * multiplier) / 10_000 / 100; } else { borrowRate = baseRate + (R_slope3 * utilizationBps * multiplier) / 10_000 / 100; } // Convert to RAY (27 decimals) borrowRate = borrowRate * 10**27 / 10_000; } function getModelParameters() external view returns ( uint16, uint16, uint16, uint16, uint16, uint16 ) { // Return adjusted slope based on current time uint256 hour = (block.timestamp / 3600) % 24; uint16 adjustedSlope1 = (hour >= 12 && hour < 18) ? R_slope1 * peakHourMultiplier / 100 : R_slope1; return (U_1, U_2, R_base, adjustedSlope1, R_slope2, R_slope3); } } ``` **Deploying custom IRM:** Custom IRMs can be set via governance: ```solidity // Only CONFIGURATOR can update IRM IPoolV3(pool).setInterestRateModel(newIRMAddress); ``` ### Pool Withdrawal Hooks Pools in V3 support withdrawal fees. These are not "hooks" in the callback sense, but configurable parameters: ```solidity // Read current withdrawal fee uint16 withdrawFee = IPoolV3(pool).withdrawFee(); // basis points // Fee is applied during withdraw/redeem uint256 assets = pool.withdraw(amount, receiver, owner); // Actual received = amount - (amount * withdrawFee / 10000) ``` For custom fee distribution logic, you would typically: 1. Deploy a fee collector contract 2. Configure the pool's treasury address to your collector 3. Implement distribution logic in your collector ## Credit Manager Extension Patterns ### Spoke Development Concept A "spoke" is a specialized Credit Manager variant designed for protocol-specific use cases. Unlike standard Credit Managers, spokes extend core functionality for unique accounting or liquidity patterns. **When to build a spoke:** * Your protocol needs custom collateral valuation logic * You're integrating Credit Accounts as a core protocol primitive * You need specialized debt/liquidation mechanics * You want to modify how positions are opened/closed **Example use case:** A derivatives protocol where Credit Accounts are used as margin accounts with custom position tracking. ### Spoke Architecture Pattern ```solidity import {CreditManagerV3} from "@gearbox-protocol/core-v3/contracts/credit/CreditManagerV3.sol"; contract DerivativesSpoke is CreditManagerV3 { // Custom state for protocol-specific tracking mapping(address => PositionData) public positions; struct PositionData { uint256 longExposure; uint256 shortExposure; int256 unrealizedPnL; } constructor( address _pool, address _addressProvider ) CreditManagerV3(_pool, _addressProvider) {} // Override collateral calculation to include unrealized PnL function calcDebtAndCollateral( address creditAccount, CollateralCalcTask task ) public view override returns ( CollateralDebtData memory cdd ) { // Call parent implementation cdd = super.calcDebtAndCollateral(creditAccount, task); // Adjust TWV based on unrealized PnL PositionData memory pos = positions[creditAccount]; if (pos.unrealizedPnL > 0) { // Add unrealized profit to collateral cdd.twvUSD += uint256(pos.unrealizedPnL); } else { // Subtract unrealized loss from collateral cdd.twvUSD -= uint256(-pos.unrealizedPnL); } } // Protocol-specific function to update position state function updatePosition( address creditAccount, uint256 longExposure, uint256 shortExposure, int256 pnl ) external { // Only allow calls from authorized adapters require( adapterToContract[msg.sender] != address(0), "Not authorized adapter" ); positions[creditAccount] = PositionData({ longExposure: longExposure, shortExposure: shortExposure, unrealizedPnL: pnl }); } } ``` ### Custom Collateral Valuation Extend collateral calculations for protocol-specific assets: ```solidity // Override token price resolution function priceOracle() public view override returns (IPriceOracleV3) { return IPriceOracleV3(customOracleAddress); } // Implement custom oracle with protocol-specific pricing contract CustomOracle is IPriceOracleV3 { function convertToUSD( uint256 amount, address token ) external view override returns (uint256) { if (token == protocolSpecificToken) { // Custom valuation logic return amount * getCustomPrice() / 10**tokenDecimals; } return defaultOracle.convertToUSD(amount, token); } } ``` ### Extending Liquidation Logic Custom liquidation premiums based on collateral type: ```solidity contract CustomLiquidationCM is CreditManagerV3 { mapping(address => uint16) public tokenLiquidationPremiums; function liquidateCreditAccount( address creditAccount, address to, MultiCall[] calldata calls ) external override { // Calculate custom premium based on collateral composition uint256 enabledMask = enabledTokensMaskOf(creditAccount); uint16 premium = _calculatePremium(enabledMask); // Set premium temporarily uint16 oldPremium = liquidationPremium; liquidationPremium = premium; // Execute standard liquidation super.liquidateCreditAccount(creditAccount, to, calls); // Restore liquidationPremium = oldPremium; } function _calculatePremium(uint256 mask) internal view returns (uint16) { uint16 maxPremium = 0; for (uint256 i = 0; i < 256; i++) { if (mask & (1 << i) != 0) { address token = getTokenByMask(1 << i); if (tokenLiquidationPremiums[token] > maxPremium) { maxPremium = tokenLiquidationPremiums[token]; } } } return maxPremium; } } ``` ## Working with Configurators The CreditConfigurator provides governance interface for Credit Manager parameters. When building spokes, you typically extend the configurator as well. ### Standard Configurator Usage ```solidity import {ICreditConfiguratorV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditConfiguratorV3.sol"; ICreditConfiguratorV3 configurator = ICreditConfiguratorV3(configuratorAddress); // Add new collateral token configurator.addCollateralToken( tokenAddress, 8500 // liquidationThreshold (85% = 8500 basis points) ); // Add adapter configurator.allowAdapter(adapterAddress); // Set fees configurator.setFees( 500, // feeInterest (5%) 150, // feeLiquidation (1.5%) 500, // liquidationPremium (5%) 100, // feeLiquidationExpired (1%) 500 // liquidationPremiumExpired (5%) ); ``` ### Custom Configurator for Spokes ```solidity import {CreditConfiguratorV3} from "@gearbox-protocol/core-v3/contracts/credit/CreditConfiguratorV3.sol"; contract DerivativesSpokeConfigurator is CreditConfiguratorV3 { DerivativesSpoke public immutable spoke; constructor( address _creditManager, address _creditFacade ) CreditConfiguratorV3(_creditManager, _creditFacade) { spoke = DerivativesSpoke(_creditManager); } // Protocol-specific configuration function setPositionLimits( uint256 maxLongExposure, uint256 maxShortExposure ) external configuratorOnly { spoke.setPositionLimits(maxLongExposure, maxShortExposure); } function setCustomLiquidationPremium( address token, uint16 premium ) external configuratorOnly { spoke.setTokenLiquidationPremium(token, premium); } } ``` ### Governance Integration For production deployments, configurator changes should go through governance: ```solidity // Propose change via governance forum // After approval, execute via timelock // Example: Adding new collateral token bytes memory data = abi.encodeCall( ICreditConfiguratorV3.addCollateralToken, (newTokenAddress, 8000) ); // Submit to governance contract governance.propose( configuratorAddress, 0, // value data, "Add NEWTOKEN as collateral with 80% LT" ); ``` **Key patterns demonstrated:** 1. **State extension**: Added `Position` tracking on top of base Credit Manager 2. **Collateral override**: Modified TWV calculation to include unrealized PnL 3. **Protocol-specific logic**: Market management and position tracking 4. **Governance integration**: `configuratorOnly` modifier for admin functions For architectural background, see [Credit Suite Architecture](https://docs.gearbox.finance/developers/credit-suite) and [Pool Architecture](https://docs.gearbox.finance/developers/pools). ## Security Considerations When extending core contracts: 1. **Preserve invariants** - Never break core protocol assumptions (debt tracking, collateral checks) 2. **Test extensively** - Fork mainnet and test against real pools/Credit Managers 3. **Audit thoroughly** - Core extensions require professional audits 4. **Consider upgrade paths** - Plan for parameter changes and emergency controls 5. **Monitor gas costs** - Overrides affect every user operation 6. **Validate inputs** - Custom logic must not allow manipulation of debt/collateral calculations ## Deployment Checklist * [ ] Core contracts audited by reputable firm * [ ] Fork tests against production Gearbox contracts * [ ] Governance proposal prepared with detailed specification * [ ] Documentation for users and integrators * [ ] Emergency pause mechanisms tested * [ ] Oracle manipulation scenarios analyzed * [ ] Gas profiling completed for all overridden functions * [ ] Upgradeability plan documented ## Related * [Adapter Development](https://docs.gearbox.finance/developers/adapter-development) - Standard integration path * [Protocol Integration](https://docs.gearbox.finance/developers/protocol-integration) - Building on top of Credit Accounts * [Credit Suite Architecture](https://docs.gearbox.finance/developers/credit-suite) - Core architecture reference * [Pool Architecture](https://docs.gearbox.finance/developers/pools) - Pool mechanics reference ## Liquidation Bots Source: https://docs.gearbox.finance/developers/liquidation-bots-2 File: content/developers/liquidation-bots-2.mdx Build on-chain liquidation contracts that can be triggered by keepers or automation services. > For SDK-based liquidation bots (recommended for most use cases), see [Liquidation Bots (SDK)](https://docs.gearbox.finance/developers/liquidation-bots). ## Overview On-chain liquidation contracts are useful when you need: * Atomicity with flash loans or other on-chain operations * Integration with existing keeper infrastructure (Gelato, Chainlink Automation) * Custom liquidation logic that must execute trustlessly * Protocol-owned liquidation capability Most liquidation bots use the SDK for monitoring and multicall building, then submit transactions off-chain. This guide covers the less common but important pattern of on-chain liquidation contracts. *** ## Understanding On-Chain Liquidation **WHY:** Know when to build a contract vs. use the SDK. ### When to Use On-Chain Contracts | Approach | Best For | | --------------------- | -------------------------------------------------------------------------- | | **SDK bot** | Most liquidators - flexible routing, off-chain simulation, rapid iteration | | **On-chain contract** | Flash loan liquidations, keeper automation, protocol-owned backstop | ### The Liquidation Entry Point ```solidity function liquidateCreditAccount( address creditAccount, address to, MultiCall[] calldata calls, bytes memory lossPolicyData ) external; ``` The liquidator provides: * `creditAccount` - the account to liquidate * `to` - where remaining funds go after debt repayment * `calls` - multicall array that converts collateral to underlying * `lossPolicyData` - custom data for loss handling *** ## Checking Liquidatability **WHY:** Don't waste gas on accounts that can't be liquidated. ### Health Factor Check ```solidity import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; import {CollateralDebtData, CollateralCalcTask} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; function isLiquidatable( address creditManager, address creditAccount ) public view returns (bool, uint256 healthFactor) { CollateralDebtData memory cdd = ICreditManagerV3(creditManager) .calcDebtAndCollateral( creditAccount, CollateralCalcTask.DEBT_COLLATERAL ); healthFactor = (cdd.twvUSD * 10000) / cdd.totalDebtUSD; return (healthFactor < 10000, healthFactor); } ``` ### Expiration Check ```solidity import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; function isExpired(address creditFacade) public view returns (bool) { uint40 expirationDate = ICreditFacadeV3(creditFacade).expirationDate(); return expirationDate != 0 && block.timestamp > expirationDate; } ``` *** ## Building Liquidation Multicalls **WHY:** The multicall converts collateral tokens to underlying. Efficient routing means higher profit. ### Basic Swap Pattern For a single collateral token, swap it to underlying via the adapter: ```solidity import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; function buildSwapCalls( address creditManager, address creditFacade, address tokenIn, address tokenOut, address dexRouter ) internal view returns (MultiCall[] memory calls) { // Get adapter for DEX address adapter = ICreditManagerV3(creditManager).contractToAdapter(dexRouter); require(adapter != address(0), "No adapter"); calls = new MultiCall[](1); // Use diff function to swap entire balance minus 1 wei calls[0] = MultiCall({ target: adapter, callData: abi.encodeCall( ISwapAdapter.exactAllInputSingle, ISwapAdapter.ExactAllInputSingleParams({ tokenIn: tokenIn, tokenOut: tokenOut, fee: 3000, deadline: block.timestamp, rateMinRAY: 0, // Simplified: no slippage protection sqrtPriceLimitX96: 0 }) ) }); } ``` ### Multi-Collateral Pattern When an account has multiple collateral tokens: ```solidity function buildLiquidationCalls( address creditManager, address creditFacade, address underlying, address[] memory collateralTokens, address dexRouter ) internal view returns (MultiCall[] memory calls) { address adapter = ICreditManagerV3(creditManager).contractToAdapter(dexRouter); require(adapter != address(0), "No adapter"); // One swap per non-underlying collateral token uint256 swapCount; for (uint256 i = 0; i < collateralTokens.length; i++) { if (collateralTokens[i] != underlying) swapCount++; } calls = new MultiCall[](swapCount); uint256 callIdx; for (uint256 i = 0; i < collateralTokens.length; i++) { if (collateralTokens[i] == underlying) continue; calls[callIdx] = MultiCall({ target: adapter, callData: abi.encodeCall( ISwapAdapter.exactAllInputSingle, ISwapAdapter.ExactAllInputSingleParams({ tokenIn: collateralTokens[i], tokenOut: underlying, fee: 3000, deadline: block.timestamp, rateMinRAY: 0, sqrtPriceLimitX96: 0 }) ) }); callIdx++; } } ``` *** ## Simple Liquidation Contract **WHY:** A complete working example you can deploy and test. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {CollateralDebtData, CollateralCalcTask} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; contract SimpleLiquidator { address public owner; address public immutable creditFacade; address public immutable creditManager; address public immutable underlying; address public immutable dexRouter; constructor( address _creditFacade, address _dexRouter ) { owner = msg.sender; creditFacade = _creditFacade; creditManager = ICreditFacadeV3(_creditFacade).creditManager(); underlying = ICreditManagerV3(creditManager).underlying(); dexRouter = _dexRouter; } modifier onlyOwner() { require(msg.sender == owner, "Not owner"); _; } /// @notice Liquidate an account, swapping specified tokens to underlying /// @param creditAccount The account to liquidate /// @param tokensToSwap Collateral tokens to swap (excluding underlying) function liquidate( address creditAccount, address[] calldata tokensToSwap ) external onlyOwner { // Build multicall: swap each collateral token to underlying address adapter = ICreditManagerV3(creditManager) .contractToAdapter(dexRouter); require(adapter != address(0), "No adapter for DEX"); MultiCall[] memory calls = new MultiCall[](tokensToSwap.length); for (uint256 i = 0; i < tokensToSwap.length; i++) { calls[i] = MultiCall({ target: adapter, callData: abi.encodeCall( ISwapAdapter.exactAllInputSingle, ISwapAdapter.ExactAllInputSingleParams({ tokenIn: tokensToSwap[i], tokenOut: underlying, fee: 3000, deadline: block.timestamp, rateMinRAY: 0, sqrtPriceLimitX96: 0 }) ) }); } // Execute liquidation - remaining funds sent to this contract ICreditFacadeV3(creditFacade).liquidateCreditAccount( creditAccount, address(this), // Receive remaining funds here calls, "" // lossPolicyData ); } /// @notice Check if liquidation would be profitable function estimateProfit( address creditAccount ) external view returns (bool profitable, uint256 healthFactor) { CollateralDebtData memory cdd = ICreditManagerV3(creditManager) .calcDebtAndCollateral( creditAccount, CollateralCalcTask.DEBT_COLLATERAL ); healthFactor = (cdd.twvUSD * 10000) / cdd.totalDebtUSD; // Profitable if account is liquidatable and has excess value profitable = healthFactor < 10000 && cdd.twvUSD > cdd.totalDebtUSD; } /// @notice Withdraw profits function withdraw(address token) external onlyOwner { uint256 balance = IERC20(token).balanceOf(address(this)); if (balance > 0) { IERC20(token).transfer(owner, balance); } } } ``` *** ## Flash Loan Liquidation **WHY:** Flash loans let you liquidate without upfront capital. For partial liquidations, the liquidator must provide underlying tokens. Flash loans make this capital-free: ```solidity import {IFlashLoanReceiver} from "@aave/v3-core/contracts/flashloan/base/FlashLoanSimpleReceiverBase.sol"; contract FlashLiquidator is IFlashLoanReceiver { address public immutable creditFacade; address public immutable creditManager; address public immutable underlying; address public immutable aavePool; function flashLiquidate( address creditAccount, address token, uint256 repaidAmount ) external { // Initiate flash loan for repaidAmount of underlying bytes memory params = abi.encode(creditAccount, token, repaidAmount); IPool(aavePool).flashLoanSimple( address(this), underlying, repaidAmount, params, 0 // referralCode ); } function executeOperation( address asset, uint256 amount, uint256 premium, address initiator, bytes calldata params ) external returns (bool) { require(msg.sender == aavePool, "Not pool"); (address creditAccount, address token, uint256 repaidAmount) = abi.decode(params, (address, address, uint256)); // Approve underlying to credit manager IERC20(underlying).approve(creditManager, repaidAmount); // Execute partial liquidation uint256 seized = ICreditFacadeV3(creditFacade) .partiallyLiquidateCreditAccount( creditAccount, token, repaidAmount, 0, // minSeizedAmount (simplified) address(this), new PriceUpdate[](0) ); // Repay flash loan (amount + premium) uint256 amountOwed = amount + premium; IERC20(asset).approve(aavePool, amountOwed); // Profit = seized token value - flash loan cost return true; } } ``` *** ## Gotchas ### Approve to Credit Manager, Not Facade For partial liquidations where you provide underlying: ```solidity // WRONG IERC20(underlying).approve(creditFacade, amount); // CORRECT IERC20(underlying).approve(creditManager, amount); ``` ### Gas Costs Scale with Token Count Liquidation gas depends on: * Number of collateral tokens to swap * Complexity of DEX routes * Price feed updates needed Estimate gas before submitting to ensure profitability. ### Race Conditions Multiple liquidators compete for the same accounts. On-chain contracts are at a disadvantage vs. off-chain bots that can use Flashbots/MEV protection. Consider: * Using higher priority fees for competitive scenarios * Targeting accounts that off-chain bots may skip (complex collateral compositions) * Bundling with Flashbots Protect for MEV protection ### exactAllInputSingle vs exactInputSingle Use `exactAllInputSingle` (the "diff" pattern) for liquidation swaps. It swaps the entire balance minus dust, which is what you want when converting all collateral: ```solidity // WRONG: Requires knowing exact balance abi.encodeCall(ISwapAdapter.exactInputSingle, (...)) // CORRECT: Swaps entire balance automatically abi.encodeCall(ISwapAdapter.exactAllInputSingle, (...)) ``` *** ## Next Steps * [Liquidation Bots (SDK)](https://docs.gearbox.finance/developers/liquidation-bots) - SDK-based approach (recommended for most cases) * [Liquidations Reference](https://docs.gearbox.finance/developers/liquidations) - Full liquidation mechanics * [Bot System Reference](https://docs.gearbox.finance/developers/bot-system) - Permission system for authorized bots * [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls) - Adapter patterns for swaps * [Protocol Integration](https://docs.gearbox.finance/developers/protocol-integration) - General patterns for building on Gearbox ## Credit Suite Source: https://docs.gearbox.finance/developers/credit-suite File: content/developers/credit-suite.mdx The Credit Suite is the foundational unit that enables leverage in Gearbox Protocol. It acts as an isolated environment where borrowers interact with DeFi protocols using borrowed funds while ensuring lender safety. ## Component Overview A Credit Suite consists of three tightly coupled smart contracts deployed together: ## Credit Manager (Logic Layer) The Credit Manager is the "brain" of the suite. It maintains the registry of Credit Accounts, connects to the underlying Pool, and calculates account solvency via the Price Oracle. **Key Responsibilities:** | Function | Purpose | | ------------------ | ------------------------------------------------------ | | Debt tracking | Maintains total debt and collateral tokens per account | | Pool interaction | Borrows and repays via PoolV3 | | Quota management | Coordinates with PoolQuotaKeeper for token limits | | Health calculation | Computes Health Factors via `calcDebtAndCollateral` | The Credit Manager is generally not accessed directly by users but by the Facade or Adapters. ## Credit Facade (Access Layer) The Credit Facade is the "face" of the suite. It serves as the primary entry point for users and implements the multicall logic, allowing complex DeFi operations to happen in a single transaction. **Key Responsibilities:** | Function | Purpose | | --------------------- | ---------------------------------------------------------------- | | Multicall execution | Iterates through user-provided calls, routing to Credit Account | | Security checks | Performs collateral check (Health Factor > 1) at transaction end | | Permission management | Manages BotList permissions for approved bots | | Access control | Enforces minDebt, maxDebt, and forbiddenTokenMask limits | ## Credit Configurator (Governance Layer) The Credit Configurator provides a secure interface for Risk Curators (or the DAO) to manage the suite without direct contract upgrades. **Key Responsibilities:** | Function | Purpose | | ---------------------- | --------------------------------- | | Collateral tokens | Adding/removing allowed tokens | | Liquidation thresholds | Setting LT per token | | Adapters | Configuring protocol integrations | | Fees and limits | Adjusting fee parameters | ## Configuration Parameters Risk Curators utilize the Credit Configurator to define the risk profile: | Parameter | Description | | ------------------------------ | ----------------------------------------------------------------------- | | **Liquidation Threshold (LT)** | Maximum leverage for a token. LT of 8500 (85%) implies \~6.6x leverage. | | **Collateral Tokens** | Allowed tokens in Credit Accounts. Unlisted tokens value at 0. | | **Adapters** | Whitelisted protocol integrations (e.g., Uniswap, Curve). | | **Debt Limits** | minDebt and maxDebt per account to prevent dust or concentration risk. | | **Fees** | feeLiquidation (to protocol) and liquidationPremium (to liquidator). | ## Borrowing and Repayment Flow ### Borrowing 1. User calls CreditFacade (open account or increase debt) 2. Facade validates request against debt limits 3. Facade instructs Manager to borrow 4. Manager calls Pool.lendCreditAccount(amount, creditAccount) 5. Pool transfers underlying directly to Credit Account 6. Pool updates interest rate based on new utilization ### Repayment 1. User calls CreditFacade (close account or decrease debt) 2. Manager calculates principal + interest + quota fees 3. Underlying transfers to Pool (from user or Credit Account) 4. Manager calls Pool.repayCreditAccount 5. Pool burns treasury shares (if loss) or mints treasury shares (if profit) ## Health Factor The Health Factor determines account solvency: **Health Factor = Total Weighted Value / Total Debt** * Total Weighted Value: Sum of (asset value \* liquidation threshold) for all collateral * Total Debt: Principal + accrued interest + quota fees When Health Factor drops below 1.0, the account becomes liquidatable. ## Implementation For implementation details, see: * **TypeScript/SDK:** [SDK Credit Accounts](https://docs.gearbox.finance/developers/credit-accounts) * **Solidity:** [Credit Accounts](https://docs.gearbox.finance/developers/credit-accounts) ## Pools Source: https://docs.gearbox.finance/developers/pools File: content/developers/pools.mdx PoolV3 is the central vault for a specific underlying asset (e.g., USDC, WETH). It follows the ERC-4626 tokenized vault standard, allowing users to deposit assets and receive Diesel Tokens (LP tokens) representing their share. ## Core Design Principles Unlike standard lending protocols, users do not borrow directly from the pool. Instead, whitelisted Credit Managers borrow liquidity on behalf of Credit Accounts to execute leveraged strategies. This separation ensures: * All borrowed funds flow through Credit Accounts with proper collateral checks * Lenders earn passive yield without exposure to leverage decisions * Risk is isolated at the Credit Manager level ## ERC-4626 Compliance PoolV3 implements the full ERC-4626 tokenized vault standard. Any tooling built for ERC-4626 vaults works with Gearbox pools. **Standard Functions:** | Function | Purpose | | ----------------------------------- | ------------------------------------------ | | `deposit(assets, receiver)` | Deposit underlying, receive shares | | `mint(shares, receiver)` | Mint exact shares, deposit required assets | | `withdraw(assets, receiver, owner)` | Withdraw exact assets, burn shares | | `redeem(shares, receiver, owner)` | Burn exact shares, receive assets | | `convertToShares(assets)` | Preview shares for asset amount | | `convertToAssets(shares)` | Preview assets for share amount | **Gearbox Extensions:** | Function | Purpose | | --------------------- | -------------------------------- | | `depositWithReferral` | On-chain referral tracking | | `lendCreditAccount` | Credit Manager-only borrowing | | `repayCreditAccount` | Credit Manager-only repayment | | `dieselRate()` | Share price in RAY (27 decimals) | ## Diesel Rate (Share Price) The diesel rate represents how many underlying tokens each diesel token (share) is worth. It starts at 1 RAY (10^27) and increases as interest accrues. **Calculation:** * 1 diesel token = dieselRate / 10^27 underlying tokens * The rate grows over time as borrowers pay interest * Lenders profit as their shares become worth more underlying ## Yield Sources Lenders provide liquidity to earn passive yield from two sources: 1. **Base Interest:** Paid by borrowers on the principal debt 2. **Quota Revenue:** Paid by borrowers for the right to hold specific collateral tokens The combined yield is reflected in the `supplyRate()` function. ## Withdrawal Mechanics Withdrawals in Gearbox V3 are subject to a withdrawal fee. This fee is taken from the interest earned, keeping the capital principal intact when possible. **Key considerations:** * Withdrawals revert if the pool is paused * Available liquidity limits maximum withdrawal * Fee calculation happens automatically during redeem/withdraw ## Credit Manager Interaction Only whitelisted Credit Managers can borrow from the pool: | Function | Access | Purpose | | ------------------------------------------ | ------- | ---------------- | | `lendCreditAccount(amount, creditAccount)` | CM only | Borrow from pool | | `repayCreditAccount(repaid, profit, loss)` | CM only | Repay to pool | Regular users cannot call these functions. All borrowing flows through the Credit Suite. ## Pool State Key state variables for monitoring pool health: | Field | Description | | -------------------- | ------------------------- | | `totalAssets` | Total value held by pool | | `availableLiquidity` | Borrowable amount | | `dieselRate` | Current share price (RAY) | | `supplyRate` | Lender APY (RAY) | | `baseInterestRate` | Borrower APR (RAY) | ## Interest Rate Determination The pool does not store interest rate logic. It queries the Interest Rate Model (IRM) whenever state changes. See the Interest Rate Model reference for the utilization curve mechanics. ## Implementation For implementation details, see: * **TypeScript/SDK:** [Reading Data](https://docs.gearbox.finance/developers/reading-data) * **Solidity:** [Pool Operations](https://docs.gearbox.finance/developers/pool-operations) ## Guides Source: https://docs.gearbox.finance/developers/gm-guides File: content/developers/gm-guides.mdx End-to-end tutorials for common Gearbox integration scenarios. | Guide | Best For | What You'll Build | | --- | --- | --- | | [**Frontend Applications**](https://docs.gearbox.finance/developers/gm-guide-frontend) | UI developers | Dashboard displaying pool data, account positions, real-time updates | | [**Backend Services**](https://docs.gearbox.finance/developers/gm-guide-backend) | Backend engineers | Event indexer, historical data tracker, analytics API | | [**Liquidation Bots**](https://docs.gearbox.finance/developers/gm-guide-bots) | Bot builders | Monitoring service that detects and executes liquidations | Each guide includes a complete working example with the Gearbox SDK. ## Multicall System Source: https://docs.gearbox.finance/developers/multicall-system File: content/developers/multicall-system.mdx The multicall system allows complex DeFi operations to execute in a single transaction. It is orchestrated by the CreditFacadeV3, with a mandatory collateral check at the end to ensure account solvency. ## The MultiCall Structure A multicall is an array of operations, each specifying a target contract and encoded function call: | Field | Type | Description | | ---------- | --------- | --------------------------------------- | | `target` | `address` | CreditFacade or allowed Adapter address | | `callData` | `bytes` | Encoded function call | ## Execution Flow ``` ### Step-by-Step Process 1. **Start MultiCall:** Facade emits StartMultiCall event 2. **Execution Loop:** Facade iterates through calls array * If target is Facade: executes internal protocol logic * If target is Adapter: routes call to whitelisted adapter 3. **End MultiCall:** Facade unsets active account status 4. **Security Checks:** * Slippage verification against stored expected balances * Forbidden token balance checks * Full collateral check (Health Factor > 1) ## Available Operations Operations available within a multicall fall into categories: ### Protocol Logic | Operation | Purpose | | -------------------- | ----------------------------------------- | | `addCollateral` | Move tokens from wallet to Credit Account | | `increaseDebt` | Borrow underlying from Pool | | `decreaseDebt` | Repay debt to Pool | | `updateQuota` | Purchase quota for collateral token | | `withdrawCollateral` | Remove assets from account | ### Safety Controls | Operation | Purpose | | ----------------------- | ------------------------------------------ | | `onDemandPriceUpdates` | Push fresh price data (must be first call) | | `storeExpectedBalances` | Record balances for slippage check | | `compareBalances` | Trigger slippage verification | | `setFullCheckParams` | Optimize collateral check with hints | ### External Calls External calls go through Adapters - whitelisted contracts that translate Gearbox calls to target protocol calls. Each Credit Manager has its own set of allowed adapters. ## Multicall-Supporting Functions All CreditFacade functions that modify state accept a multicall array: | Function | Purpose | | ------------------------ | ------------------------------------------- | | `openCreditAccount` | Create account with initial operations | | `closeCreditAccount` | Close account, return remaining funds | | `multicall` | Execute operations on existing account | | `botMulticall` | Bot-initiated operations (with permissions) | | `liquidateCreditAccount` | Liquidate unhealthy account | This allows all account management to happen in one transaction, minimizing gas overhead by batching under a single collateral check. ## Security Mechanisms ### Slippage Protection Use `storeExpectedBalances` before swaps and `compareBalances` after to prevent sandwich attacks. The protocol compares actual balances against expected minimums. ### Forbidden Token Handling Some tokens may be marked "forbidden" - their balances cannot increase during a multicall. The Facade checks forbidden token balances before and after execution. ### Collateral Check Every multicall (except close/liquidate) ends with a collateral check: * Total Weighted Value must exceed Total Debt * Health Factor = TWV / Debt must be > 1.0 * Failed check reverts the entire transaction ## The "Diff" Pattern Adapters implement `*_diff` functions (e.g., `swapDiff`, `depositDiff`) for handling unknown amounts. Instead of specifying exact input amounts: * Standard: needs exact `amountIn` * Diff: calculates `amountIn = currentBalance - leftoverAmount` This is essential when the exact result of a previous operation is unknown. ## Bot Permissions Multicalls enforce granular permissions via bitmask: | Permission | Purpose | | --------------------- | ------------------------- | | `ADD_COLLATERAL` | Move funds into account | | `INCREASE_DEBT` | Borrow more from pool | | `UPDATE_QUOTA` | Modify quota settings | | `EXTERNAL_CALLS` | Call external adapters | | `WITHDRAW_COLLATERAL` | Remove funds from account | A user can delegate specific permissions to bots while protecting against unauthorized withdrawals. ## Best Practices 1. **Price updates first:** Always put `onDemandPriceUpdates` at the start if using pull-based oracles 2. **Slippage protection:** Always use `storeExpectedBalances` when performing swaps 3. **Dust management:** Use `type(uint256).max` in `withdrawCollateral` to empty balances (subtracts 1 wei automatically) 4. **Gas optimization:** Use `setFullCheckParams` with hints for accounts with many tokens ## Implementation For implementation details, see: * **TypeScript/SDK:** [SDK Multicalls](https://docs.gearbox.finance/developers/multicalls) * **Solidity:** [Solidity Multicalls](https://docs.gearbox.finance/developers/multicalls) ## Credit Manager Source: https://docs.gearbox.finance/developers/credit-manager File: content/developers/credit-manager.mdx The **CreditManagerV3** is the core accounting engine of the Gearbox Protocol. It manages Credit Account lifecycle, tracks debt and collateral, calculates health factors, and enforces risk parameters. All Credit Account state is stored and managed through this contract. ## Core State: CreditAccountInfo Every Credit Account's state is tracked in a `CreditAccountInfo` struct: | Field | Type | Description | | --------------------------- | --------- | ------------------------------------------------------ | | `debt` | `uint256` | Principal amount borrowed from the pool | | `cumulativeIndexLastUpdate` | `uint256` | Pool's interest index at last debt update | | `cumulativeQuotaInterest` | `uint128` | Accrued quota interest not yet added to debt | | `quotaFees` | `uint128` | Quota fees owed | | `enabledTokensMask` | `uint256` | Bitmask of currently enabled collateral tokens | | `flags` | `uint16` | Account state flags (e.g., `BOT_PERMISSIONS_SET_FLAG`) | | `lastDebtUpdate` | `uint64` | Timestamp of last debt change (flash-loan protection) | | `borrower` | `address` | Current account owner | *** ## Debt Tracking Architecture ### Indexed Interest Accrual The Credit Manager uses an indexed interest model rather than storing accrued interest directly. This approach is gas-efficient because it doesn't require per-block updates. **Formula:** ``` accruedInterest = debt * (currentIndex - lastIndex) / lastIndex totalDebt = principal + accruedInterest + quotaInterest + fees ``` The `cumulativeIndexLastUpdate` is snapshotted whenever debt changes, allowing the contract to calculate exact interest at any time by comparing against the Pool's current `baseInterestIndex()`. ### Flash-Loan Protection The `lastDebtUpdate` timestamp prevents multiple debt changes in the same block. This protects against flash-loan attacks where an attacker could: 1. Borrow heavily 2. Manipulate prices 3. Close position profitably Any second debt change in the same block will revert. *** ## Collateral Management ### Token Masking System Every collateral token has a unique `uint256` mask (power of 2). An account's `enabledTokensMask` is the bitwise OR of all enabled token masks. **Benefits:** * **O(enabled\_tokens) iteration**: Health checks only iterate over enabled tokens, not all possible collateral * **Gas efficiency**: Single storage slot tracks all enabled/disabled states * **Atomic updates**: Enable/disable multiple tokens in one operation ```typescript // TypeScript: Checking enabled tokens const enabledMask = await creditManager.read.enabledTokensMaskOf([creditAccount]); // Get all enabled token addresses const collateralTokens = []; for (let i = 0; i < 256; i++) { if (enabledMask & (1n << BigInt(i))) { const tokenData = await creditManager.read.getTokenByMask([1n << BigInt(i)]); collateralTokens.push(tokenData); } } ``` ### Liquidation Thresholds (LT) Each collateral token has a Liquidation Threshold determining how much of its value counts toward collateralization: | Parameter | Description | | -------------------- | ------------------------------------ | | `ltInitial` | Starting LT value (e.g., 8500 = 85%) | | `ltFinal` | Final LT after ramping | | `timestampRampStart` | When LT ramping begins | | `rampDuration` | Duration of linear interpolation | **LT Ramping** allows gradual changes to risk parameters without sudden liquidation cascades. The current LT is linearly interpolated between `ltInitial` and `ltFinal` over the ramp period. ### Phantom Tokens Phantom tokens are virtual representations of staked/LP positions (e.g., staked Curve LP tokens). They implement `IPhantomToken.getPhantomTokenInfo()` which returns the underlying deposited token. During health factor calculations, phantom tokens are resolved to their underlying value, ensuring proper collateral accounting for wrapped positions. *** ## Health Factor Calculation ### TWV Formula The Health Factor determines whether an account is solvent: ``` TWV (Threshold Weighted Value) = Sum(Balance_i * Price_i * LT_i) TotalDebt = principal + baseInterest + quotaInterest + fees HealthFactor = TWV / TotalDebt ``` An account is: * **Healthy**: HF >= 1.0 (10000 in basis points) * **Liquidatable**: HF < 1.0 ### Collateral Calculation Modes The Credit Manager supports different calculation modes for gas optimization: | Mode | Use Case | | ---------------------------- | ------------------------------------------------ | | `DEBT_ONLY` | Calculate debt + interest without collateral | | `DEBT_COLLATERAL` | Full TWV + HF calculation | | `FULL_COLLATERAL_CHECK_LAZY` | Optimized: stops early when HF exceeds threshold | The lazy mode is used during multicalls where we only need to verify HF > 1, not calculate the exact value. ```typescript // TypeScript: Reading account health import { getContract } from 'viem'; const creditManager = getContract({ address: creditManagerAddress, abi: creditManagerV3Abi, client: publicClient, }); // Get full debt breakdown const debtData = await creditManager.read.calcDebtAndCollateral([ creditAccount, 2 // CollateralCalcTask.DEBT_COLLATERAL ]); // debtData returns: { debt, accruedInterest, accruedFees, totalDebtUSD, // totalValue, twvUSD, enabledTokensMask, ... } const healthFactor = debtData.twvUSD * 10000n / debtData.totalDebtUSD; console.log(`Health Factor: ${Number(healthFactor) / 100}%`); ``` *** ## Pool and Oracle Coordination ### Pool Interaction The Credit Manager coordinates with PoolV3 for all debt operations: | Operation | Pool Function | | ----------------- | --------------------------------------------- | | Borrow | `pool.lendCreditAccount(debt, creditAccount)` | | Repay | `pool.repayCreditAccount(debt, profit, loss)` | | Interest tracking | `pool.baseInterestIndex()` | On liquidation with loss, the Credit Manager reports the loss to the Pool, which may burn Treasury shares or incur "uncovered loss" that's socialized across LPs. ### Oracle Interaction Price data comes from `PriceOracleV3`: | Function | Description | | ----------------------------- | ------------------------------------------------- | | `convertToUSD(amount, token)` | Convert token amount to USD value | | `getPrice(token)` | Get token price (respects `USE_SAFE_PRICES_FLAG`) | **Dual Price Safety**: When `USE_SAFE_PRICES_FLAG` is set (for forbidden tokens), the oracle returns `min(primaryPrice, reservePrice)` to protect against price manipulation. *** ## Access Control The Credit Manager restricts sensitive operations: | Caller | Allowed Operations | | ---------------------------- | ----------------------------------------------- | | `CreditFacadeV3` | All account operations (open, close, multicall) | | `CreditConfiguratorV3` | Parameter updates (tokens, adapters, fees) | | Credit Account (via execute) | Adapter calls during multicall | External contracts cannot directly manipulate Credit Account state - all operations must flow through the Facade.
Sources * [contracts/credit/CreditManagerV3.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/credit/CreditManagerV3.sol) * [contracts/interfaces/ICreditManagerV3.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/interfaces/ICreditManagerV3.sol) * [contracts/libraries/CreditLogic.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/libraries/CreditLogic.sol) * [contracts/libraries/CollateralLogic.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/libraries/CollateralLogic.sol)
## Frontend Applications Source: https://docs.gearbox.finance/developers/gm-guide-frontend File: content/developers/gm-guide-frontend.mdx Build dashboards, portfolio trackers, and trading UIs that display Gearbox protocol data and let users manage positions. ## Overview Frontend applications typically need to: 1. Display pool and market data 2. Show collateral exposure and limits 3. Monitor credit account health 4. Enable position management This guide maps each requirement to specific SDK methods. *** ## Pool Display **WHY:** Users want to see pool health, yields, and utilization before depositing or borrowing. ### Data Requirements | Display | SDK Source | Field | | ------------------- | ------------- | -------------------------------------------------- | | Underlying token | `market.pool` | `underlying.symbol`, `underlying.address` | | Total supplied | `market.pool` | `totalAssets` | | Available liquidity | `market.pool` | `availableLiquidity` | | Utilization | Calculated | `(totalAssets - availableLiquidity) / totalAssets` | | Supply APY | `market.pool` | `supplyRate` (RAY scaled) | | Borrow APR | `market.pool` | `baseInterestRate` (RAY scaled) | | Share price | `market.pool` | `dieselRate` (RAY scaled) | ### How to Fetch ```typescript import { GearboxSDK } from '@gearbox-protocol/sdk'; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); // Find market by pool address const market = sdk.marketRegister.findByPool(poolAddress); const pool = market.pool; // Display data const RAY = 10n ** 27n; console.log(`Underlying: ${pool.underlying.symbol}`); console.log(`Total Supplied: ${pool.totalAssets}`); console.log(`Available: ${pool.availableLiquidity}`); // Calculate utilization const borrowed = pool.totalAssets - pool.availableLiquidity; const utilization = Number(borrowed * 10000n / pool.totalAssets) / 100; console.log(`Utilization: ${utilization.toFixed(2)}%`); // Convert RAY rates to percentages const supplyAPY = Number(pool.supplyRate * 10000n / RAY) / 100; const borrowAPR = Number(pool.baseInterestRate * 10000n / RAY) / 100; console.log(`Supply APY: ${supplyAPY.toFixed(2)}%`); console.log(`Borrow APR: ${borrowAPR.toFixed(2)}%`); ``` ### Where Data Comes From The SDK caches market data on initialization via `GearboxSDK.attach()`. This data comes from the `MarketCompressor` contract. For real-time updates, either: * Re-initialize the SDK periodically * Call compressors directly (see [Real-Time Updates](#real-time-updates)) *** ## Collateral Exposure **WHY:** Users want to see what collaterals the pool is exposed to and current utilization against limits. ### Data Requirements | Display | SDK Source | Field | | --------------------- | ------------------------ | ------------------- | | Quoted tokens | `MarketData.quotaKeeper` | `tokens[]` | | Token quota limit | `quotaKeeper.tokens[]` | `limit` | | Current quoted amount | `quotaKeeper.tokens[]` | `totalQuoted` | | Quota rate | `quotaKeeper.tokens[]` | `rate` (RAY scaled) | ### How to Fetch For quota data, use the `MarketCompressor` directly: ```typescript import { marketCompressorAbi, AP_MARKET_COMPRESSOR, VERSION_RANGE_310, } from '@gearbox-protocol/sdk'; // Get compressor address const [compressor] = sdk.addressProvider.mustGetLatest( AP_MARKET_COMPRESSOR, VERSION_RANGE_310 ); // Fetch market data with quota keeper const marketData = await client.readContract({ address: compressor, abi: marketCompressorAbi, functionName: 'getMarketData', args: [poolAddress], }); // QuotaKeeper token data for (const token of marketData.quotaKeeper.tokens) { const utilizationPct = Number(token.totalQuoted * 10000n / token.limit) / 100; console.log(`Token: ${token.token}`); console.log(` Limit: ${token.limit}`); console.log(` Quoted: ${token.totalQuoted}`); console.log(` Utilization: ${utilizationPct.toFixed(2)}%`); console.log(` Rate: ${token.rate}`); // RAY scaled } ``` ### Gotcha: Quota Limits Before letting users open positions with a specific collateral, check that `totalQuoted < limit`. If the limit is reached, new positions with that collateral will fail. *** ## Credit Manager Configuration **WHY:** Users need to know debt limits, collateral requirements, and fees before opening positions. ### Data Requirements | Display | SDK Source | Field | | --------------------- | -------------------- | ------------------------------------- | | Min debt | `creditManager` | `minDebt` | | Max debt | `creditManager` | `maxDebt` | | Collateral tokens | `creditManager` | `collateralTokens[]` | | Liquidation threshold | `collateralTokens[]` | `liquidationThreshold` (basis points) | | Fees | `creditManager` | `fees` | | Liquidation premium | `creditManager` | `liquidationPremium` | ### How to Fetch ```typescript const market = sdk.marketRegister.findByCreditManager(cmAddress); for (const cm of market.creditManagers) { console.log(`Credit Manager: ${cm.address}`); console.log(`Credit Facade: ${cm.creditFacade}`); // Debt limits console.log(`Min Debt: ${cm.minDebt}`); console.log(`Max Debt: ${cm.maxDebt}`); // Collateral configuration console.log('Allowed Collaterals:'); for (const token of cm.collateralTokens) { // LT is in basis points (10000 = 100%) const ltPct = Number(token.liquidationThreshold) / 100; console.log(` ${token.symbol}: LT ${ltPct.toFixed(1)}%`); } } ``` ### Understanding Liquidation Threshold The liquidation threshold (LT) determines how much each collateral contributes to the weighted collateral value: ``` Weighted Value = Token Balance * Token Price * LT Health Factor = Total Weighted Value / Total Debt ``` A lower LT means the protocol values that collateral more conservatively. *** ## Credit Account Monitoring **WHY:** Users need to track their position health, collateral values, and accrued interest. ### Data Requirements | Display | SDK Source | Field | | ---------------- | ------------------- | ---------------------------- | | Account address | `CreditAccountData` | `addr` | | Owner | `CreditAccountData` | `owner` | | Total debt | `CreditAccountData` | `debt` | | Health factor | `CreditAccountData` | `healthFactor` (10000 = 1.0) | | Is liquidatable | `CreditAccountData` | `isLiquidatable` | | Token balances | `CreditAccountData` | `tokens[]` | | Token values | `tokens[]` | `balanceInUnderlying` | | Accrued interest | `CreditAccountData` | `cumulativeQuotaInterest` | | Quota fees | `CreditAccountData` | `quotaFees` | ### How to Fetch ```typescript import { createCreditAccountService } from '@gearbox-protocol/sdk'; const service = createCreditAccountService(sdk, 310); // Get user's accounts const accounts = await service.getCreditAccounts( { creditManager: cmAddress, owner: userAddress, }, sdk.currentBlock ); for (const account of accounts) { // Health factor: 10000 = 1.0 const hf = Number(account.healthFactor) / 10000; console.log(`Account: ${account.addr}`); console.log(`Health Factor: ${hf.toFixed(4)}`); console.log(`Liquidatable: ${account.isLiquidatable}`); // Debt breakdown console.log(`Total Debt: ${account.debt}`); console.log(`Accrued Interest: ${account.cumulativeQuotaInterest}`); console.log(`Quota Fees: ${account.quotaFees}`); // Token positions console.log('Positions:'); for (const token of account.tokens) { if (token.balance > 0n) { console.log(` ${token.symbol}:`); console.log(` Balance: ${token.balance}`); console.log(` Value (underlying): ${token.balanceInUnderlying}`); console.log(` LT: ${token.lt / 100}%`); } } } ``` ### Interest Breakdown Credit account debt consists of: * **Principal:** Original borrowed amount * **Base interest:** Accrues on principal based on pool utilization * **Quota interest:** Per-collateral rate for non-underlying tokens * **Quota fees:** Fixed fee component for quotas ```typescript // Total debt = principal + base interest + quota interest + quota fees const principal = account.borrowedAmount; const quotaInterest = account.cumulativeQuotaInterest; const quotaFees = account.quotaFees; const baseInterest = account.debt - principal - quotaInterest - quotaFees; ``` ### Health Factor Thresholds Display appropriate warnings based on health factor: ```typescript function getHealthStatus(hf: number): string { if (hf < 1.0) return 'LIQUIDATABLE'; if (hf < 1.05) return 'CRITICAL'; if (hf < 1.1) return 'WARNING'; return 'HEALTHY'; } const status = getHealthStatus(Number(account.healthFactor) / 10000); ``` *** ## Price Feed Information **WHY:** Users want to understand which oracles determine their collateral values. ### How to Fetch ```typescript import { priceFeedCompressorAbi, AP_PRICE_FEED_COMPRESSOR, VERSION_RANGE_310, } from '@gearbox-protocol/sdk'; // Get price feed compressor const [priceFeedCompressor] = sdk.addressProvider.mustGetLatest( AP_PRICE_FEED_COMPRESSOR, VERSION_RANGE_310 ); // Get all price feeds for a price oracle const feeds = await client.readContract({ address: priceFeedCompressor, abi: priceFeedCompressorAbi, functionName: 'getUpdatablePriceFeeds', args: [priceOracleAddress], }); for (const feed of feeds) { console.log(`Token: ${feed.token}`); console.log(` Feed: ${feed.priceFeed}`); console.log(` Needs Update: ${feed.needsUpdate}`); } ``` *** ## Position Management **WHY:** Users take actions on their positions (add collateral, borrow, repay, etc.). ### Linking to Operations Position management uses multicalls. Link to the appropriate operation guide: | User Action | Operation Guide | | ------------------ | ---------------------------------------------------------------------------------------------------------------------------- | | Deposit collateral | [Adding Collateral](https://docs.gearbox.finance/developers/adding-collateral) | | Borrow more | [Debt Management](https://docs.gearbox.finance/developers/debt-management) | | Repay debt | [Debt Management](https://docs.gearbox.finance/developers/debt-management) | | Update quota | [Updating Quotas](https://docs.gearbox.finance/developers/updating-quotas) | | Withdraw | [Withdrawing Collateral](https://docs.gearbox.finance/developers/withdrawing-collateral) | | Swap collateral | [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls) | ### Pre-Operation Data Checks Before letting users perform operations, validate: ```typescript // Before addCollateral: Check token is allowed const isAllowed = market.creditManagers[0].collateralTokens .some(t => t.address === tokenAddress); // Before increaseDebt: Check against max debt const newDebt = account.debt + borrowAmount; const isWithinLimit = newDebt <= cm.maxDebt; // Before updateQuota: Check quota capacity const quotaToken = marketData.quotaKeeper.tokens .find(t => t.token === tokenAddress); const hasCapacity = quotaToken && quotaToken.totalQuoted < quotaToken.limit; // Before any operation: Estimate health factor impact // (Use simulation or calculate locally) ``` *** ## Real-Time Updates **WHY:** UI needs to stay current as blockchain state changes. ### Option 1: Poll Compressors For most dashboards, polling every few seconds is sufficient: ```typescript const POLL_INTERVAL = 5000; // 5 seconds async function pollMarketData() { const marketData = await client.readContract({ address: compressor, abi: marketCompressorAbi, functionName: 'getMarketData', args: [poolAddress], }); // Update UI state setPoolData(marketData.pool); setQuotaData(marketData.quotaKeeper); } // Start polling setInterval(pollMarketData, POLL_INTERVAL); ``` ### Option 2: Watch Events For specific state changes, watch contract events: ```typescript import { parseAbiItem } from 'viem'; // Watch for credit account state changes const unwatch = client.watchContractEvent({ address: creditManagerAddress, abi: creditManagerAbi, eventName: 'ExecuteOrder', onLogs: (logs) => { // Refresh account data for affected accounts for (const log of logs) { refreshAccountData(log.args.creditAccount); } }, }); // Cleanup on unmount return () => unwatch(); ``` ### Recommendation Use **polling** for: * General market data * Pool state (rates, liquidity) * Quota utilization Use **events** for: * User's own account changes * Critical health factor alerts *** ## Complete Example: Dashboard Component ```typescript import { GearboxSDK, createCreditAccountService, marketCompressorAbi } from '@gearbox-protocol/sdk'; import { createPublicClient, http } from 'viem'; import { mainnet } from 'viem/chains'; interface DashboardData { pool: { underlying: string; totalAssets: bigint; availableLiquidity: bigint; supplyAPY: number; borrowAPR: number; }; userAccounts: Array<{ address: string; healthFactor: number; debt: bigint; isLiquidatable: boolean; }>; } async function fetchDashboardData( poolAddress: `0x${string}`, cmAddress: `0x${string}`, userAddress: `0x${string}` ): Promise { const client = createPublicClient({ chain: mainnet, transport: http(), }); const sdk = await GearboxSDK.attach({ client, marketConfigurators: [], }); const RAY = 10n ** 27n; // Pool data const market = sdk.marketRegister.findByPool(poolAddress); const pool = market.pool; // User accounts const service = createCreditAccountService(sdk, 310); const accounts = await service.getCreditAccounts( { creditManager: cmAddress, owner: userAddress }, sdk.currentBlock ); return { pool: { underlying: pool.underlying.symbol, totalAssets: pool.totalAssets, availableLiquidity: pool.availableLiquidity, supplyAPY: Number(pool.supplyRate * 10000n / RAY) / 100, borrowAPR: Number(pool.baseInterestRate * 10000n / RAY) / 100, }, userAccounts: accounts.map(a => ({ address: a.addr, healthFactor: Number(a.healthFactor) / 10000, debt: a.debt, isLiquidatable: a.isLiquidatable, })), }; } ``` *** ## Next Steps * [Multicall Operations](https://docs.gearbox.finance/developers/gm-accounts-multicalls) - Implement position management * [Backend Services](https://docs.gearbox.finance/developers/gm-guide-backend) - If you also need historical data * [Compressors Reference](https://docs.gearbox.finance/developers/compressors) - Complete compressor API ## Backend Services Source: https://docs.gearbox.finance/developers/gm-guide-backend File: content/developers/gm-guide-backend.mdx Build indexers, analytics pipelines, and data warehouses that track Gearbox protocol state over time. ## Overview Backend services typically need to: 1. Capture historical snapshots at specific blocks 2. Index events for efficient state reconstruction 3. Track rates, values, and utilization over time 4. Store and query historical data This guide shows patterns for each requirement. *** ## Historical Snapshots **WHY:** Track how protocol state changes over time for analytics, reporting, and historical queries. ### What to Snapshot | Data | Source | Change Frequency | | -------------------- | ------------------- | ------------------------- | | Pool rates | `PoolState` | Every block with activity | | Pool liquidity | `PoolState` | Every deposit/borrow | | Quota utilization | `QuotaKeeperState` | Every position change | | Credit account state | `CreditAccountData` | Every account operation | | Token prices | `PriceOracle` | External feed updates | ### How to Query at Specific Blocks Compressors support querying at historical blocks using viem's `blockTag` or `blockNumber`: ```typescript import { marketCompressorAbi, AP_MARKET_COMPRESSOR, VERSION_RANGE_310, } from '@gearbox-protocol/sdk'; const [compressor] = sdk.addressProvider.mustGetLatest( AP_MARKET_COMPRESSOR, VERSION_RANGE_310 ); // Query at specific block const historicalData = await client.readContract({ address: compressor, abi: marketCompressorAbi, functionName: 'getMarketData', args: [poolAddress], blockNumber: 19000000n, // Specific block }); console.log(`Pool state at block 19000000:`); console.log(` Available liquidity: ${historicalData.pool.availableLiquidity}`); console.log(` Supply rate: ${historicalData.pool.supplyRate}`); ``` ### Archive Node Requirements Historical queries require an archive node. Standard nodes only keep recent state (~128 blocks). **RPC providers with archive access:** * Alchemy (archive add-on) * Infura (archive add-on) * QuickNode (archive plans) * Self-hosted Erigon/Reth ### Snapshot Pattern ```typescript interface PoolSnapshot { blockNumber: bigint; timestamp: number; availableLiquidity: bigint; totalAssets: bigint; supplyRate: bigint; borrowRate: bigint; } async function capturePoolSnapshot( blockNumber: bigint ): Promise { const block = await client.getBlock({ blockNumber }); const marketData = await client.readContract({ address: compressor, abi: marketCompressorAbi, functionName: 'getMarketData', args: [poolAddress], blockNumber, }); return { blockNumber, timestamp: Number(block.timestamp), availableLiquidity: marketData.pool.availableLiquidity, totalAssets: marketData.pool.totalAssets, supplyRate: marketData.pool.supplyRate, borrowRate: marketData.pool.baseInterestRate, }; } // Capture hourly snapshots const BLOCKS_PER_HOUR = 300n; // ~12 second blocks let currentBlock = startBlock; while (currentBlock <= endBlock) { const snapshot = await capturePoolSnapshot(currentBlock); await saveToDatabase(snapshot); currentBlock += BLOCKS_PER_HOUR; } ``` *** ## Event Indexing **WHY:** Events provide efficient tracking of specific state changes without polling. ### Key Events Credit Facade emits events for all account operations: | Event | When Emitted | Key Data | | ------------------------ | ------------------ | ----------------------------------------- | | `OpenCreditAccount` | Account opened | owner, creditAccount, borrowAmount | | `CloseCreditAccount` | Account closed | creditAccount | | `LiquidateCreditAccount` | Account liquidated | creditAccount, liquidator, remainingFunds | | `StartMultiCall` | Multicall begins | creditAccount | | `FinishMultiCall` | Multicall ends | creditAccount | Pool emits events for liquidity changes: | Event | When Emitted | Key Data | | ---------- | ---------------------- | ----------------------------------- | | `Deposit` | LP deposits | sender, owner, assets, shares | | `Withdraw` | LP withdraws | sender, receiver, assets, shares | | `Borrow` | Credit Manager borrows | creditAccount, amount | | `Repay` | Debt repaid | creditAccount, amount, profit, loss | ### Watching Events with viem ```typescript import { parseAbiItem } from 'viem'; // Watch for new credit accounts const unwatchOpen = client.watchContractEvent({ address: creditFacadeAddress, abi: creditFacadeAbi, eventName: 'OpenCreditAccount', onLogs: async (logs) => { for (const log of logs) { console.log(`New account: ${log.args.creditAccount}`); console.log(` Owner: ${log.args.owner}`); console.log(` Initial debt: ${log.args.borrowAmount}`); await indexCreditAccount(log); } }, }); // Watch for liquidations const unwatchLiquidate = client.watchContractEvent({ address: creditFacadeAddress, abi: creditFacadeAbi, eventName: 'LiquidateCreditAccount', onLogs: async (logs) => { for (const log of logs) { console.log(`Liquidated: ${log.args.creditAccount}`); console.log(` Liquidator: ${log.args.liquidator}`); await recordLiquidation(log); } }, }); ``` ### Fetching Historical Events For backfilling, fetch events in block ranges: ```typescript async function fetchHistoricalEvents( fromBlock: bigint, toBlock: bigint ) { // Fetch in chunks to avoid RPC limits const CHUNK_SIZE = 10000n; let current = fromBlock; while (current <= toBlock) { const chunkEnd = current + CHUNK_SIZE > toBlock ? toBlock : current + CHUNK_SIZE; const logs = await client.getContractEvents({ address: creditFacadeAddress, abi: creditFacadeAbi, eventName: 'OpenCreditAccount', fromBlock: current, toBlock: chunkEnd, }); for (const log of logs) { await processEvent(log); } current = chunkEnd + 1n; } } ``` *** ## State Tracking **WHY:** Build complete account or pool history over time by combining events and snapshots. ### Credit Account Lifecycle Track an account from open to close: ```typescript interface AccountHistory { creditAccount: string; owner: string; openBlock: bigint; closeBlock: bigint | null; operations: AccountOperation[]; } interface AccountOperation { blockNumber: bigint; txHash: string; type: 'open' | 'multicall' | 'liquidate' | 'close'; healthFactorAfter?: bigint; } async function trackAccountLifecycle(creditAccount: string): Promise { // Find open event const openEvents = await client.getContractEvents({ address: creditFacadeAddress, abi: creditFacadeAbi, eventName: 'OpenCreditAccount', args: { creditAccount }, fromBlock: 0n, toBlock: 'latest', }); const openEvent = openEvents[0]; // Find all multicall events const multicallEvents = await client.getContractEvents({ address: creditFacadeAddress, abi: creditFacadeAbi, eventName: 'FinishMultiCall', args: { creditAccount }, fromBlock: openEvent.blockNumber, toBlock: 'latest', }); // Find close event (if any) const closeEvents = await client.getContractEvents({ address: creditFacadeAddress, abi: creditFacadeAbi, eventName: 'CloseCreditAccount', args: { creditAccount }, fromBlock: openEvent.blockNumber, toBlock: 'latest', }); return { creditAccount, owner: openEvent.args.owner, openBlock: openEvent.blockNumber, closeBlock: closeEvents[0]?.blockNumber ?? null, operations: [ { blockNumber: openEvent.blockNumber, txHash: openEvent.transactionHash, type: 'open' }, ...multicallEvents.map(e => ({ blockNumber: e.blockNumber, txHash: e.transactionHash, type: 'multicall' as const, })), ...(closeEvents[0] ? [{ blockNumber: closeEvents[0].blockNumber, txHash: closeEvents[0].transactionHash, type: 'close' as const, }] : []), ].sort((a, b) => Number(a.blockNumber - b.blockNumber)), }; } ``` ### Combining Events and Snapshots For complete state reconstruction: ```typescript async function reconstructAccountStateAtBlock( creditAccount: string, targetBlock: bigint ): Promise { // Check if account existed at this block const history = await trackAccountLifecycle(creditAccount); if (history.openBlock > targetBlock) { return null; // Account didn't exist yet } if (history.closeBlock && history.closeBlock <= targetBlock) { return null; // Account was closed } // Query compressor at target block const [accountData] = await client.readContract({ address: accountCompressor, abi: creditAccountCompressorAbi, functionName: 'getCreditAccountData', args: [creditManagerAddress, creditAccount], blockNumber: targetBlock, }); return accountData; } ``` *** ## Rate History **WHY:** Analytics on yield, utilization trends, and rate changes over time. ### Rates to Track | Rate | Source | Notes | | --------------- | --------------------------- | -------------------------------------------------- | | Supply APY | `pool.supplyRate` | RAY scaled (10^27) | | Base borrow APR | `pool.baseInterestRate` | RAY scaled | | Quota rates | `quotaKeeper.tokens[].rate` | Per-token, RAY scaled | | Utilization | Calculated | `(totalAssets - availableLiquidity) / totalAssets` | ### Polling Pattern ```typescript interface RateSnapshot { blockNumber: bigint; timestamp: number; supplyRate: bigint; borrowRate: bigint; utilization: number; quotaRates: Map; } async function pollRates(): Promise { const block = await client.getBlock({ blockTag: 'latest' }); const marketData = await client.readContract({ address: compressor, abi: marketCompressorAbi, functionName: 'getMarketData', args: [poolAddress], }); const pool = marketData.pool; const borrowed = pool.totalAssets - pool.availableLiquidity; const utilization = pool.totalAssets > 0n ? Number(borrowed * 10000n / pool.totalAssets) / 100 : 0; const quotaRates = new Map(); for (const token of marketData.quotaKeeper.tokens) { quotaRates.set(token.token, token.rate); } return { blockNumber: block.number, timestamp: Number(block.timestamp), supplyRate: pool.supplyRate, borrowRate: pool.baseInterestRate, utilization, quotaRates, }; } // Poll every minute setInterval(async () => { const snapshot = await pollRates(); await saveRateSnapshot(snapshot); }, 60_000); ``` ### Rate Conversion Convert RAY-scaled rates to annual percentages: ```typescript const RAY = 10n ** 27n; function rayToAnnualPercent(rayRate: bigint): number { // rate is per-second, annualize it const SECONDS_PER_YEAR = 365n * 24n * 60n * 60n; const annualRate = rayRate * SECONDS_PER_YEAR; return Number(annualRate * 10000n / RAY) / 100; } const supplyAPY = rayToAnnualPercent(pool.supplyRate); console.log(`Supply APY: ${supplyAPY.toFixed(2)}%`); ``` *** ## Complete Example: Simple Indexer ```typescript import { createPublicClient, http } from 'viem'; import { mainnet } from 'viem/chains'; import { GearboxSDK, marketCompressorAbi, creditAccountCompressorAbi, AP_MARKET_COMPRESSOR, VERSION_RANGE_310, } from '@gearbox-protocol/sdk'; interface IndexerState { lastIndexedBlock: bigint; pools: Map; accounts: Map; } async function runIndexer( startBlock: bigint, poolAddress: `0x${string}`, creditManagerAddress: `0x${string}` ) { const client = createPublicClient({ chain: mainnet, transport: http(process.env.ARCHIVE_RPC_URL), }); const sdk = await GearboxSDK.attach({ client, marketConfigurators: [], }); const [marketCompressor] = sdk.addressProvider.mustGetLatest( AP_MARKET_COMPRESSOR, VERSION_RANGE_310 ); let currentBlock = startBlock; while (true) { const latestBlock = await client.getBlockNumber(); while (currentBlock <= latestBlock) { // Snapshot pool state const marketData = await client.readContract({ address: marketCompressor, abi: marketCompressorAbi, functionName: 'getMarketData', args: [poolAddress], blockNumber: currentBlock, }); await savePoolSnapshot(currentBlock, marketData.pool); // Index events in this block range const events = await client.getContractEvents({ address: creditManagerAddress, abi: creditFacadeAbi, fromBlock: currentBlock, toBlock: currentBlock + 100n, }); for (const event of events) { await processEvent(event); } currentBlock += 100n; } // Wait for new blocks await sleep(12_000); } } function sleep(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)); } ``` *** ## Next Steps * [Liquidation Bots](https://docs.gearbox.finance/developers/gm-guide-bots) - If you need to act on indexed data * [Compressors Reference](https://docs.gearbox.finance/developers/compressors) - Complete compressor API * [Frontend Applications](https://docs.gearbox.finance/developers/gm-guide-frontend) - If you also need real-time display ## Credit Facade Source: https://docs.gearbox.finance/developers/credit-facade File: content/developers/credit-facade.mdx The **CreditFacadeV3** is the primary user-facing interface for Credit Account operations. It implements atomic multicall batching, enforces debt limits, manages bot permissions, and ensures all operations complete with a healthy account state. ## Multicall Execution Flow All Credit Account operations are executed through multicalls - batched transactions that execute atomically. ### Entry Points | Function | Caller | Description | | -------------------------------------------------- | -------------- | ------------------------------------------ | | `openCreditAccount(calls, onBehalfOf)` | Anyone | Create new account with initial operations | | `closeCreditAccount(creditAccount, calls)` | Owner | Close account, repay all debt | | `multicall(creditAccount, calls)` | Owner | Execute operations on existing account | | `botMulticall(creditAccount, calls)` | Authorized bot | Bot-initiated operations | | `liquidateCreditAccount(creditAccount, to, calls)` | Anyone | Liquidate unhealthy account | ### MultiCall Structure ```solidity struct MultiCall { address target; // Facade itself or whitelisted adapter bytes callData; // Function selector + encoded arguments } ``` ### Four Execution Phases **Phase 1: Initialization** * Emit `StartMultiCall` event * Snapshot forbidden token balances * Set flags (e.g., `REVERT_ON_FORBIDDEN_TOKENS_FLAG`) **Phase 2: Iterative Dispatch** ```solidity for (uint256 i = 0; i < calls.length; ++i) { if (target == address(this)) { _processFacadeCall(callData); // Internal operations } else { creditManager.setActiveCreditAccount(creditAccount); creditAccount.execute(target, callData); // External adapter } } ``` **Phase 3: Balance Tracking (Optional)** * `storeExpectedBalances(balances[])`: Store expected amounts * `compareBalances()`: Verify slippage protection **Phase 4: Final Validation** * Unset active account * Full collateral check (HF must be >= 1) * Verify forbidden token balances didn't increase *** ## Security Checks ### Access Control | Modifier | Effect | | ------------------------ | --------------------------------------- | | `creditAccountOwnerOnly` | Only account owner can call | | `nonReentrant` | Prevents reentrancy attacks | | `whenNotPaused` | Blocks operations when paused | | `whenNotExpired` | After expiration, only closures allowed | ### Bot Permission System Bots operate with granular permissions stored as a `uint192` bitmask: | Permission | Value | Operation | | -------------------------------- | --------- | --------------------- | | `ADD_COLLATERAL_PERMISSION` | `1 << 0` | Add funds to account | | `INCREASE_DEBT_PERMISSION` | `1 << 1` | Borrow more from pool | | `DECREASE_DEBT_PERMISSION` | `1 << 2` | Repay debt | | `WITHDRAW_COLLATERAL_PERMISSION` | `1 << 5` | Withdraw assets | | `UPDATE_QUOTA_PERMISSION` | `1 << 6` | Change token quotas | | `EXTERNAL_CALLS_PERMISSION` | `1 << 16` | Execute adapter calls | Each multicall operation checks against the caller's permission mask: ```solidity function _revertIfNoPermission(uint256 flags, uint256 permission) internal pure { if (flags & permission == 0) { revert NoPermissionException(permission); } } ``` *** ## Debt Limits Enforcement ### Global Limits Every Credit Facade enforces min/max debt bounds: ```solidity struct DebtLimits { uint128 minDebt; // Minimum principal (except 0) uint128 maxDebt; // Maximum principal } ``` **Validation:** ```solidity require(newDebt == 0 || (newDebt >= minDebt && newDebt <= maxDebt)); ``` Zero debt is always allowed (closing accounts), but any non-zero debt must fall within bounds. ### Per-Block Limit To prevent flash-loan exploits and rate manipulation: ```solidity uint8 maxDebtPerBlockMultiplier; uint256 limit = maxDebt * maxDebtPerBlockMultiplier; require(totalBorrowedInBlock[block.number] + amount <= limit); ``` This caps the total new debt that can be created in a single block across all Credit Accounts. ### Loss Policy When bad debt occurs during liquidation: 1. `maxDebtPerBlockMultiplier` is set to 0 2. All new borrowing is halted 3. Governance must intervene to restore normal operation This circuit breaker protects the protocol from cascading losses. ```typescript // TypeScript: Checking debt limits const facade = getContract({ address: facadeAddress, abi: creditFacadeV3Abi, client: publicClient, }); const [minDebt, maxDebt] = await facade.read.debtLimits(); const multiplier = await facade.read.maxDebtPerBlockMultiplier(); // Check if borrowing is allowed if (multiplier === 0) { console.log('Borrowing is currently disabled'); } console.log(`Debt range: ${minDebt} - ${maxDebt}`); console.log(`Per-block limit: ${maxDebt * BigInt(multiplier)}`); ``` *** ## Forbidden Tokens Logic Forbidden tokens are high-risk assets that require special handling. They still count toward collateral value but have restrictions. ### Protection Flags | Flag | Effect | | --------------------------------- | ----------------------------------------------- | | `REVERT_ON_FORBIDDEN_TOKENS_FLAG` | Revert if forbidden tokens are enabled | | `USE_SAFE_PRICES_FLAG` | Use `min(primary, reserve)` price for valuation | ### Rules 1. **Cannot increase quota** for forbidden tokens 2. **Balance must NOT increase** during multicall 3. **Safe pricing** is used during collateral checks This incentivizes users to reduce exposure to forbidden tokens while protecting the protocol from manipulation. ```typescript // TypeScript: Checking for forbidden tokens const creditManager = getContract({ address: cmAddress, abi: creditManagerV3Abi, client: publicClient, }); const forbiddenMask = await creditManager.read.forbiddenTokenMask(); const enabledMask = await creditManager.read.enabledTokensMaskOf([creditAccount]); const hasForbidden = (enabledMask & forbiddenMask) !== 0n; if (hasForbidden) { console.log('Account has forbidden tokens - consider reducing exposure'); } ``` *** ## Account Lifecycle ### Opening an Account ``` User -> CreditFacade.openCreditAccount(calls, onBehalfOf) -> CreditManager.openCreditAccount(borrower, onBehalfOf) -> AccountFactory.takeCreditAccount(debt) -> Pool.lendCreditAccount(debt, account) -> _multicall(account, calls) -> CreditManager.fullCollateralCheck() ``` ### Multicall with Adapter ``` User -> CreditFacade.multicall([{target: adapter, callData}]) -> CreditManager.setActiveCreditAccount(account) -> CreditAccount.execute(adapter, callData) -> Adapter.someFunction(params) -> _execute(protocolCallData) -> CreditAccount -> DeFiProtocol.targetFunction() -> CreditManager.fullCollateralCheck() ``` ### Closing an Account ``` User -> CreditFacade.closeCreditAccount(account, calls) -> _multicall(account, calls) // Convert to underlying -> CreditManager.closeCreditAccount(account) -> Pool.repayCreditAccount(debt, profit, 0) -> Transfer remaining funds to user ```
Sources * [contracts/credit/CreditFacadeV3.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/credit/CreditFacadeV3.sol) * [contracts/interfaces/ICreditFacadeV3.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/interfaces/ICreditFacadeV3.sol) * [contracts/interfaces/ICreditFacadeV3Multicall.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/interfaces/ICreditFacadeV3Multicall.sol)
## Credit Configurator Source: https://docs.gearbox.finance/developers/credit-configurator File: content/developers/credit-configurator.mdx The **CreditConfiguratorV3** is the administrative gateway for the Credit Suite. It validates parameter changes and propagates them to the Credit Manager and Credit Facade. Importantly, it does not store configuration state itself - it acts as a validation layer. ## Architecture ``` User/DAO -> CreditConfiguratorV3 (validation) -> CreditManagerV3/CreditFacadeV3 (state) ``` The Configurator ensures all changes are valid before forwarding them to the appropriate contract. This separation allows for: * Centralized validation logic * Consistent access control * Audit trail through events *** ## Token & Risk Management ### Adding Collateral Tokens ```solidity function addCollateralToken(address token, uint16 liquidationThreshold); ``` **Validation:** * Token must be valid ERC-20 * Must have price feed in PriceOracle * Must be quoted in PoolQuotaKeeper * LT cannot exceed underlying's LT **For Phantom Tokens:** * The deposited (underlying) token must already exist as collateral * Phantom token represents staked/wrapped position ### Adjusting Liquidation Thresholds ```solidity // Immediate change function setLiquidationThreshold(address token, uint16 liquidationThreshold); // Gradual change (ramping) function rampLiquidationThreshold( address token, uint16 ltFinal, uint40 rampStart, uint24 rampDuration ); ``` **Ramping** allows gradual LT changes over time, preventing sudden liquidation cascades when risk parameters are adjusted. ### Forbidding/Allowing Tokens | Function | Access | Use Case | | ---------------------------- | --------------- | ------------------------------ | | `forbidToken(address token)` | Pausable Admins | Emergency: mark token as risky | | `allowToken(address token)` | Configurator | Restore normal token status | Forbidden tokens still count toward collateral (with safe pricing) but have restrictions on quota increases and balance changes. ```typescript // TypeScript: Reading token configuration const creditManager = getContract({ address: cmAddress, abi: creditManagerV3Abi, client: publicClient, }); // Get collateral token data const tokenMask = await creditManager.read.getTokenMaskOrRevert([tokenAddress]); const tokenData = await creditManager.read.collateralTokenByMask([tokenMask]); // Returns: { token, ltInitial, ltFinal, timestampRampStart, rampDuration } // Check if token is forbidden const forbiddenMask = await creditManager.read.forbiddenTokenMask(); const isForbidden = (tokenMask & forbiddenMask) !== 0n; ``` *** ## Fee Management ### Configurable Fees ```solidity function setFees( uint16 feeLiquidation, uint16 liquidationPremium, uint16 feeLiquidationExpired, uint16 liquidationPremiumExpired ); ``` | Parameter | Description | | --------------------------- | -------------------------------------- | | `feeLiquidation` | DAO fee on standard liquidations | | `liquidationPremium` | Reward for liquidators | | `feeLiquidationExpired` | Higher DAO fee for expired accounts | | `liquidationPremiumExpired` | Higher reward for expired liquidations | **Constraints:** * `feeLiquidation <= liquidationPremium` * `feeLiquidationExpired <= feeLiquidation` * `liquidationPremium + feeLiquidation < 100%` * Fee sum must remain constant (prevents sudden changes) The relationship ensures liquidators are always incentivized and the protocol takes a smaller cut than the liquidator reward. *** ## Borrowing Limits ### Debt Bounds ```solidity function setDebtLimits(uint128 newMinDebt, uint128 newMaxDebt); ``` **Validation:** * `minDebt <= maxDebt` * `maxDebt * maxEnabledTokens <= minDebt * 100` (safety ratio) * USD value of minDebt must be non-zero The safety ratio ensures accounts aren't opened with tiny debt that would be uneconomical to liquidate. ### Per-Block Multiplier ```solidity function setMaxDebtPerBlockMultiplier(uint8 multiplier); function forbidBorrowing(); // Sets multiplier to 0 ``` **`forbidBorrowing()`** is an emergency action available to Pausable Admins. It immediately halts all new borrowing without requiring a DAO vote. *** ## Adapter Management ### Allowing Adapters ```solidity function allowAdapter(address adapter); function forbidAdapter(address adapter); ``` **Validation:** * Adapter must implement `creditManager()` returning this Credit Manager * Adapter must implement `targetContract()` returning the DeFi protocol * Cannot target the Facade or Manager itself **Registration:** * Creates bidirectional mapping: `adapter <-> targetContract` * Credit Account can only call whitelisted adapters * Each target protocol has exactly one adapter ```typescript // TypeScript: Checking adapter status const creditManager = getContract({ address: cmAddress, abi: creditManagerV3Abi, client: publicClient, }); // Get adapter for a target protocol const adapterAddress = await creditManager.read.contractToAdapter([uniswapRouterAddress]); if (adapterAddress === '0x0000000000000000000000000000000000000000') { console.log('No adapter registered for this protocol'); } else { console.log(`Adapter: ${adapterAddress}`); } // Get all adapters const adaptersData = await creditManager.read.adapters(); ``` *** ## System Upgrades ### Oracle Updates ```solidity function setPriceOracle(address newPriceOracle); ``` Allows switching to a new price oracle implementation. The new oracle must support all currently configured collateral tokens. ### Facade Migration ```solidity function setCreditFacade(address newCreditFacade, bool migrateParams); ``` When `migrateParams` is true, debt limits and other Facade parameters are copied to the new contract. This enables upgrading the user-facing interface while preserving configuration. ### Configurator Upgrade ```solidity function upgradeCreditConfigurator(address newCreditConfigurator); ``` Transfers configurator role to a new contract. Used when the validation logic itself needs updating. *** ## Access Control Model ### Role Hierarchy | Role | Capabilities | | ------------------ | -------------------------------------------------------------------------- | | **Configurator** | All structural changes: tokens, fees, adapters, debt limits, upgrades | | **Pausable Admin** | Emergency actions: `forbidToken`, `forbidBorrowing` (no DAO vote required) | ### Cross-Contract Verification The Credit Manager and Facade verify that configuration calls come from the registered Configurator: ```solidity modifier creditConfiguratorOnly() { require(msg.sender == creditConfigurator); _; } ``` This prevents unauthorized parameter changes even if an attacker gains access to admin keys for other contracts. ```typescript // TypeScript: Reading configurator address const creditManager = getContract({ address: cmAddress, abi: creditManagerV3Abi, client: publicClient, }); const configuratorAddress = await creditManager.read.creditConfigurator(); console.log(`Configurator: ${configuratorAddress}`); // Check access control roles (from ACL contract) const acl = getContract({ address: aclAddress, abi: aclAbi, client: publicClient, }); const isPausableAdmin = await acl.read.isPausableAdmin([someAddress]); const isConfigurator = await acl.read.isConfigurator([someAddress]); ```
Sources * [contracts/credit/CreditConfiguratorV3.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/credit/CreditConfiguratorV3.sol) * [contracts/interfaces/ICreditConfiguratorV3.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/interfaces/ICreditConfiguratorV3.sol) * [contracts/core/ACL.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/core/ACL.sol)
## Liquidation Bots Source: https://docs.gearbox.finance/developers/gm-guide-bots File: content/developers/gm-guide-bots.mdx Build bots that monitor credit accounts and execute profitable liquidations. ## Overview Liquidation bots need to: 1. Find accounts with low health factors 2. Filter for liquidatable accounts 3. Compute optimal liquidation paths 4. Execute liquidations profitably This guide covers each step with verified SDK patterns. *** ## Understanding Liquidation **WHY:** Know what you're building before writing code. ### When Accounts Become Liquidatable An account becomes liquidatable when its health factor drops below 1.0: ``` Health Factor = Total Weighted Collateral Value / Total Debt Where: - Weighted Value = Sum of (Token Balance * Price * Liquidation Threshold) - Total Debt = Principal + Accrued Interest + Quota Fees ``` Health factor is scaled by 10000, so `healthFactor < 10000` means liquidatable. ### The Liquidation Process 1. **Liquidator calls** `creditFacade.liquidateCreditAccount()` 2. **Protocol converts** collateral to underlying token 3. **Debt is repaid** from converted collateral 4. **Liquidator receives** premium (configured per Credit Manager) 5. **Remaining funds** go to account owner (if any) The liquidator provides the multicall that handles collateral conversion. This is where profit comes from - efficient routing means better conversion rates. *** ## Finding Liquidatable Accounts **WHY:** Efficiently scan all accounts to find opportunities. ### Using CreditAccountCompressor The `CreditAccountCompressor` has built-in health factor filtering: ```typescript import { creditAccountCompressorAbi, AP_CREDIT_ACCOUNT_COMPRESSOR, VERSION_RANGE_310, } from '@gearbox-protocol/sdk'; const [accountCompressor] = sdk.addressProvider.mustGetLatest( AP_CREDIT_ACCOUNT_COMPRESSOR, VERSION_RANGE_310 ); // Find accounts with HF < 1.0 (10000 in basis points) const [accounts, total] = await client.readContract({ address: accountCompressor, abi: creditAccountCompressorAbi, functionName: 'getCreditAccounts', args: [ creditManagerAddress, { owner: '0x0000000000000000000000000000000000000000', // Any owner minHealthFactor: 0n, maxHealthFactor: 10000n, // HF < 1.0 includeZeroDebt: false, reverting: false, }, 0n, // offset ], }); console.log(`Found ${accounts.length} accounts with HF < 1.0`); ``` ### Filter by isLiquidatable The `isLiquidatable` field accounts for additional protocol checks: ```typescript const liquidatable = accounts.filter(a => a.isLiquidatable); console.log(`${liquidatable.length} are actually liquidatable`); for (const account of liquidatable) { console.log(`Account: ${account.addr}`); console.log(` Health Factor: ${Number(account.healthFactor) / 10000}`); console.log(` Debt: ${account.debt}`); console.log(` Collaterals:`); for (const token of account.tokens) { if (token.balance > 0n) { console.log(` ${token.symbol}: ${token.balance}`); } } } ``` ### Pagination for Large Result Sets The compressor returns paginated results. Iterate through all pages: ```typescript async function getAllLiquidatableAccounts( creditManager: `0x${string}` ): Promise { const filter = { owner: '0x0000000000000000000000000000000000000000' as const, minHealthFactor: 0n, maxHealthFactor: 10000n, includeZeroDebt: false, reverting: false, }; let offset = 0n; let allAccounts: CreditAccountData[] = []; while (true) { const [accounts, total] = await client.readContract({ address: accountCompressor, abi: creditAccountCompressorAbi, functionName: 'getCreditAccounts', args: [creditManager, filter, offset], }); const liquidatable = accounts.filter(a => a.isLiquidatable); allAccounts.push(...liquidatable); offset += BigInt(accounts.length); if (offset >= total) break; } return allAccounts; } ``` *** ## Account Analysis **WHY:** Understand an account's composition before liquidating. ### Collateral Breakdown ```typescript interface CollateralPosition { token: string; symbol: string; balance: bigint; valueInUnderlying: bigint; liquidationThreshold: number; } function analyzeCollateral(account: CreditAccountData): CollateralPosition[] { return account.tokens .filter(t => t.balance > 0n) .map(t => ({ token: t.token, symbol: t.symbol, balance: t.balance, valueInUnderlying: t.balanceInUnderlying, liquidationThreshold: Number(t.lt) / 100, })) .sort((a, b) => Number(b.valueInUnderlying - a.valueInUnderlying)); } const positions = analyzeCollateral(account); console.log('Collateral by value:'); for (const pos of positions) { console.log(` ${pos.symbol}: ${pos.valueInUnderlying} (LT: ${pos.liquidationThreshold}%)`); } ``` ### Estimating Profit ```typescript interface LiquidationEstimate { totalCollateralValue: bigint; debt: bigint; liquidationPremium: bigint; estimatedProfit: bigint; } function estimateLiquidation( account: CreditAccountData, premiumBps: number // e.g., 400 = 4% ): LiquidationEstimate { const totalValue = account.tokens.reduce( (sum, t) => sum + t.balanceInUnderlying, 0n ); const premium = totalValue * BigInt(premiumBps) / 10000n; // Simplified: assumes perfect conversion const estimatedProfit = totalValue - account.debt; return { totalCollateralValue: totalValue, debt: account.debt, liquidationPremium: premium, estimatedProfit: estimatedProfit > 0n ? estimatedProfit : 0n, }; } ``` *** ## Building the Liquidation Multicall **WHY:** The multicall handles collateral conversion and determines profit. ### Basic Structure A liquidation multicall typically: 1. Updates stale price feeds (if needed) 2. Swaps collateral tokens to underlying 3. Repays debt (handled by protocol) ```typescript import { encodeFunctionData } from 'viem'; import { iCreditFacadeV300MulticallAbi } from '@gearbox-protocol/sdk'; // Build liquidation multicall const calls: Array<{ target: `0x${string}`; callData: `0x${string}` }> = []; // 1. Update any stale price feeds first for (const feed of stalePriceFeeds) { calls.push({ target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'onDemandPriceUpdate', args: [feed.token, feed.reserve, feed.data], }), }); } // 2. Swap collateral to underlying via adapters for (const collateral of collateralToSwap) { const adapter = await creditManager.read.contractToAdapter([ collateral.protocol, ]); calls.push({ target: adapter, callData: encodeFunctionData({ abi: adapterAbi, functionName: 'swap', args: [collateral.swapParams], }), }); } ``` ### Using Slippage Protection Always protect against sandwich attacks: ```typescript // Store expected minimum output calls.push({ target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'storeExpectedBalances', args: [[{ token: underlyingToken, amount: minExpectedOutput }]], }), }); // Perform swap calls.push({ target: adapter, callData: encodeFunctionData({ abi: adapterAbi, functionName: 'swap', args: [swapParams], }), }); // Verify slippage calls.push({ target: creditFacadeAddress, callData: encodeFunctionData({ abi: iCreditFacadeV300MulticallAbi, functionName: 'compareBalances', args: [], }), }); ``` See [Controlling Slippage](https://docs.gearbox.finance/developers/controlling-slippage) for details. *** ## Executing Liquidation **WHY:** Actually perform the liquidation and capture profit. ### The liquidateCreditAccount Call ```typescript // Get credit facade for the account's credit manager const market = sdk.marketRegister.findByCreditManager(account.creditManager); // Execute liquidation const hash = await walletClient.writeContract({ address: market.creditFacade.address, abi: creditFacadeAbi, functionName: 'liquidateCreditAccount', args: [ account.addr, // Credit account to liquidate receiverAddress, // Where to send remaining funds calls, // Liquidation multicall ], }); console.log(`Liquidation submitted: ${hash}`); // Wait for confirmation const receipt = await client.waitForTransactionReceipt({ hash }); console.log(`Liquidation ${receipt.status === 'success' ? 'succeeded' : 'failed'}`); ``` ### Handling Partial Liquidation In some configurations, partial liquidation is possible. Check the Credit Manager configuration: ```typescript // Full liquidation only if account is deeply underwater // Partial liquidation may be allowed above certain HF threshold ``` *** ## Bot Architecture **WHY:** Production bots need proper design for reliability and competitiveness. ### Monitoring Loop ```typescript async function monitoringLoop() { const POLL_INTERVAL = 3000; // 3 seconds while (true) { try { // Scan all credit managers for (const cm of creditManagers) { const accounts = await getAllLiquidatableAccounts(cm); for (const account of accounts) { // Analyze opportunity const estimate = estimateLiquidation(account, liquidationPremiumBps); if (estimate.estimatedProfit > minProfitThreshold) { await attemptLiquidation(account); } } } } catch (error) { console.error('Monitoring error:', error); } await sleep(POLL_INTERVAL); } } ``` ### Simulation Before Execution Always simulate before sending transactions: ```typescript async function attemptLiquidation(account: CreditAccountData) { const calls = buildLiquidationMulticall(account); // Simulate first try { await client.simulateContract({ address: creditFacadeAddress, abi: creditFacadeAbi, functionName: 'liquidateCreditAccount', args: [account.addr, receiverAddress, calls], account: liquidatorAddress, }); } catch (error) { console.log(`Simulation failed for ${account.addr}:`, error); return; } // Simulation passed, execute try { const hash = await walletClient.writeContract({ address: creditFacadeAddress, abi: creditFacadeAbi, functionName: 'liquidateCreditAccount', args: [account.addr, receiverAddress, calls], }); console.log(`Liquidation tx: ${hash}`); } catch (error) { console.error(`Execution failed:`, error); } } ``` ### Competition Considerations Liquidation is competitive. Other bots are scanning the same accounts. **Strategies:** * **Speed:** Use faster RPC endpoints, optimize code paths * **Gas:** Pay higher gas for priority (use `maxPriorityFeePerGas`) * **Efficiency:** Better swap routing means higher profit, can afford more gas * **Flashbots:** Use MEV-protected submission to avoid frontrunning ```typescript // Higher priority fee for competitive liquidations const hash = await walletClient.writeContract({ address: creditFacadeAddress, abi: creditFacadeAbi, functionName: 'liquidateCreditAccount', args: [account.addr, receiverAddress, calls], maxPriorityFeePerGas: parseGwei('3'), // Higher tip }); ``` *** ## Complete Example: Simple Liquidation Bot ```typescript import { createPublicClient, createWalletClient, http, parseGwei } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; import { mainnet } from 'viem/chains'; import { GearboxSDK, creditAccountCompressorAbi, AP_CREDIT_ACCOUNT_COMPRESSOR, VERSION_RANGE_310, } from '@gearbox-protocol/sdk'; const MIN_PROFIT_USD = 100n * 10n ** 6n; // \$100 minimum profit async function runLiquidationBot(creditManagerAddress: `0x${string}`) { const client = createPublicClient({ chain: mainnet, transport: http(), }); const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`); const walletClient = createWalletClient({ account, chain: mainnet, transport: http(), }); const sdk = await GearboxSDK.attach({ client, marketConfigurators: [], }); const [accountCompressor] = sdk.addressProvider.mustGetLatest( AP_CREDIT_ACCOUNT_COMPRESSOR, VERSION_RANGE_310 ); const market = sdk.marketRegister.findByCreditManager(creditManagerAddress); console.log(`Monitoring ${market.creditManagers[0].address}`); console.log(`Liquidator: ${account.address}`); while (true) { try { // Find liquidatable accounts const [accounts] = await client.readContract({ address: accountCompressor, abi: creditAccountCompressorAbi, functionName: 'getCreditAccounts', args: [ creditManagerAddress, { owner: '0x0000000000000000000000000000000000000000', minHealthFactor: 0n, maxHealthFactor: 10000n, includeZeroDebt: false, reverting: false, }, 0n, ], }); const liquidatable = accounts.filter(a => a.isLiquidatable); if (liquidatable.length > 0) { console.log(`Found ${liquidatable.length} liquidatable accounts`); for (const target of liquidatable) { const totalValue = target.tokens.reduce( (sum, t) => sum + t.balanceInUnderlying, 0n ); const estimatedProfit = totalValue - target.debt; if (estimatedProfit > MIN_PROFIT_USD) { console.log(`Profitable opportunity: ${target.addr}`); console.log(` Debt: ${target.debt}`); console.log(` Value: ${totalValue}`); console.log(` Est. Profit: ${estimatedProfit}`); // Build and execute liquidation const calls = buildLiquidationCalls(target, market); try { // Simulate await client.simulateContract({ address: market.creditFacade.address, abi: creditFacadeAbi, functionName: 'liquidateCreditAccount', args: [target.addr, account.address, calls], account: account.address, }); // Execute const hash = await walletClient.writeContract({ address: market.creditFacade.address, abi: creditFacadeAbi, functionName: 'liquidateCreditAccount', args: [target.addr, account.address, calls], maxPriorityFeePerGas: parseGwei('2'), }); console.log(`Liquidation submitted: ${hash}`); } catch (error) { console.log(`Failed to liquidate ${target.addr}:`, error); } } } } } catch (error) { console.error('Loop error:', error); } // Poll every 3 seconds await new Promise(resolve => setTimeout(resolve, 3000)); } } function buildLiquidationCalls( account: CreditAccountData, market: MarketData ): Array<{ target: `0x${string}`; callData: `0x${string}` }> { const calls: Array<{ target: `0x${string}`; callData: `0x${string}` }> = []; const creditFacade = market.creditFacade.address; const underlying = market.pool.underlying.address; // Swap each non-underlying collateral token to underlying via adapter for (const token of account.tokens) { if (token.balance <= 1n) continue; // skip dust if (token.token === underlying) continue; // skip underlying itself // Use Uniswap V3 adapter for swaps (simplified: hardcoded router) const uniswapAdapter = market.adapters?.['UNISWAP_V3_ROUTER']; if (!uniswapAdapter) continue; // exactAllInputSingle swaps entire balance minus 1 wei calls.push({ target: uniswapAdapter, callData: encodeFunctionData({ abi: uniswapV3AdapterAbi, functionName: 'exactAllInputSingle', args: [{ tokenIn: token.token, tokenOut: underlying, fee: 3000, // 0.3% pool (use 500 for stablecoin pairs) deadline: BigInt(Math.floor(Date.now() / 1000) + 3600), rateMinRAY: 0n, // No slippage protection (simplified) sqrtPriceLimitX96: 0n, }], }), }); } return calls; } ``` *** ## Gotchas ### Price Updates Must Come First If any price feeds are stale, update them at the start of your multicall: ```typescript // WRONG: Swap first, then update prices (will fail) // CORRECT: Update prices first, then swap const calls = [ ...priceUpdateCalls, ...swapCalls, ]; ``` See [Updating Price Feeds](https://docs.gearbox.finance/developers/updating-price-feeds). ### Account State Can Change Between scanning and executing, another bot may liquidate the account: ```typescript try { await walletClient.writeContract({ ... }); } catch (error) { if (error.message.includes('account not liquidatable')) { console.log('Account already liquidated by another bot'); } } ``` ### Gas Estimation Liquidation gas costs vary based on: * Number of collateral tokens * Complexity of swaps * Price feed updates needed Always estimate gas before calculating profitability. *** ## Next Steps * [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls) - Swap patterns via adapters * [Controlling Slippage](https://docs.gearbox.finance/developers/controlling-slippage) - Protect against MEV * [Updating Price Feeds](https://docs.gearbox.finance/developers/updating-price-feeds) - Required for stale oracles * [Compressors Reference](https://docs.gearbox.finance/developers/compressors) - Complete filter options ## Liquidations Source: https://docs.gearbox.finance/developers/liquidations File: content/developers/liquidations.mdx Liquidations are the mechanism that ensures protocol solvency by closing undercollateralized positions. Gearbox V3 supports both **full liquidations** (complete account closure) and **partial liquidations** (debt reduction while keeping account open). ## Full Liquidation Flow ### When Liquidations Occur An account becomes liquidatable when: * **Health Factor < 1.0** (undercollateralized) * **Account has expired** (past the configured expiration timestamp) Anyone can liquidate an unhealthy account - there's no whitelist. ### Entry Point ```solidity function liquidateCreditAccount( address creditAccount, address to, MultiCall[] calldata calls, bytes memory lossPolicyData ) ``` | Parameter | Description | | ---------------- | ------------------------------------------ | | `creditAccount` | The account to liquidate | | `to` | Where liquidator receives remaining assets | | `calls` | Multicall array for converting collateral | | `lossPolicyData` | Custom data for loss handling | *** ## Liquidation Math ### Core Parameters | Parameter | Description | | ------------------------ | ------------------------------------------------ | | **Liquidation Premium** | % of account value liquidator receives as reward | | **Liquidation Discount** | % used to cover debt and fees (100% - Premium) | ### Fund Distribution Formula ```solidity uint256 totalFunds = totalValue * liquidationDiscount / PERCENTAGE_FACTOR; ``` **Liabilities** = Total Debt (Principal + Interest + Quota Fees) + DAO Liquidation Fee ### Outcomes **1. Solvent Liquidation** (`totalFunds > liabilities`) * Pool repaid in full * DAO receives liquidation fee * Remaining funds go to original borrower **2. Bad Debt** (`totalFunds < liabilities`) * DAO profit reduced first * If insufficient, loss reported to Pool * Pool burns Treasury shares to cover * If Treasury empty: "uncovered loss" (socialized across LPs) * Emergency: `maxDebtPerBlockMultiplier` set to 0 to halt borrowing *** ## Step-by-Step Execution ### 1. Trigger and Multicall Liquidator identifies account with HF < 1 and constructs multicall: ```typescript // TypeScript: Liquidation bot example const calls = [ // Swap collateral tokens to underlying via adapters { target: uniswapAdapterAddress, callData: encodeFunctionData({ abi: uniswapAdapterAbi, functionName: 'exactAllInputSingle', args: [{ tokenIn: wbtcAddress, tokenOut: usdcAddress, ... }] }) }, // Additional swaps as needed... ]; await creditFacade.write.liquidateCreditAccount([ creditAccountAddress, liquidatorAddress, // receives remaining assets calls, '0x' // lossPolicyData ]); ``` ### 2. Internal Execution 1. Calculate payments via `CreditLogic.calcLiquidationPayments` 2. Execute multicall (convert collateral to underlying) 3. Transfer `amountToPool` to PoolV3 4. Remove active quotas via PoolQuotaKeeper ### 3. Pool Distribution **Profits:** * Pool mints shares to Treasury **Losses:** * Burns Treasury shares * If Treasury empty: emits `IncurUncoveredLoss` * Triggers emergency borrowing halt ### 4. Remaining Funds 1. **Borrower's Share**: `minRemainingFunds` (if any) 2. **Liquidator's Share**: Everything else (includes premium) *** ## Fee Distribution ```solidity function _calcPartialLiquidationPayments( uint256 amount, address token, bool isExpired ) returns ( uint256 repaidAmount, uint256 feeAmount, uint256 seizedAmount ) ``` | Fee Type | Description | | ---------------------------- | --------------------------------- | | `feeLiquidation` | Standard liquidation fee to DAO | | `feeLiquidationExpired` | Higher fee for expired accounts | | `liquidationDiscount` | Discount for healthy liquidations | | `liquidationDiscountExpired` | Discount for expired liquidations | Expired accounts have higher fees to incentivize timely liquidation. *** ## Partial Liquidation ### When Allowed Partial liquidation is useful when: * Market liquidity is insufficient for full conversion * "Deleverage" strategy is preferred * Account can remain healthy with reduced debt ### Constraints * Account must remain open after liquidation * Must pass collateral check post-liquidation (HF >= 1) * Cannot leave "dust" debt below `minDebt` ### Execution ```solidity function partiallyLiquidateCreditAccount( address creditAccount, address token, uint256 repaidAmount, uint256 minSeizedAmount, address to, PriceUpdate[] calldata priceUpdates ) external returns (uint256 seizedAmount) ``` **Steps:** 1. Update price feeds (if provided) 2. Verify account is liquidatable (HF < 1 or expired) 3. Liquidator provides underlying as collateral 4. Calculate payments (repaid, fee, seized) 5. Handle phantom token withdrawal if applicable 6. Decrease account debt 7. Withdraw fee to treasury 8. Transfer seized collateral to liquidator 9. Full collateral check (HF must be >= 1 after) ### Health Factor Thresholds **Protocol Level:** * **Liquidation Trigger**: HF < 1.0 * **Post-Liquidation**: HF >= 1.0 (enforced) **Bot-Specific** (configurable in `PartialLiquidationBotV3`): * `minHealthFactor`: HF threshold for intervention * `maxHealthFactor`: Maximum HF after partial liquidation * Prevents "over-liquidation" ```typescript // TypeScript: Partial liquidation const seizedAmount = await creditFacade.write.partiallyLiquidateCreditAccount([ creditAccountAddress, wbtcAddress, // token to seize parseUnits('1000', 6), // repaid USDC amount parseUnits('0.03', 8), // min BTC to receive liquidatorAddress, [] // price updates ]); ``` *** ## Emergency Liquidations ### Regular vs Emergency | Type | When | Who | | ------------- | ----------------------------- | -------------------------------- | | **Regular** | Protocol functioning normally | Anyone | | **Emergency** | Protocol/Facade paused | `EMERGENCY_LIQUIDATOR` role only | ### whenNotPausedOrEmergency Modifier ```solidity modifier whenNotPausedOrEmergency() { require( !paused() || _hasRole("EMERGENCY_LIQUIDATOR", msg.sender), "Pausable: paused" ); _; } ``` This ensures liquidations can continue even during pause, preventing bad debt accumulation. ### Treasury Backstop The `TreasuryLiquidator` contract allows the DAO treasury to provide emergency liquidity: * Provides underlying funds when external liquidators are absent * Acts as backstop during extreme market conditions * Protects protocol from cascading losses ```typescript // TypeScript: Checking if account can be liquidated const creditFacade = getContract({ address: facadeAddress, abi: creditFacadeV3Abi, client: publicClient, }); const creditManager = getContract({ address: cmAddress, abi: creditManagerV3Abi, client: publicClient, }); // Get health factor const debtData = await creditManager.read.calcDebtAndCollateral([ creditAccount, 2 // DEBT_COLLATERAL ]); const hf = debtData.twvUSD * 10000n / debtData.totalDebtUSD; // Check expiration const expirationDate = await creditFacade.read.expirationDate(); const isExpired = BigInt(Math.floor(Date.now() / 1000)) > expirationDate; const isLiquidatable = hf < 10000n || isExpired; console.log(`Liquidatable: ${isLiquidatable}, HF: ${Number(hf) / 100}%`); ```
Sources * [contracts/credit/CreditFacadeV3.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/credit/CreditFacadeV3.sol) (lines 277-437) * [contracts/credit/CreditManagerV3.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/credit/CreditManagerV3.sol) * [contracts/libraries/CreditLogic.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/libraries/CreditLogic.sol) * [contracts/emergency/TreasuryLiquidator.sol](https://github.com/Gearbox-protocol/periphery-v3/blob/main/contracts/emergency/TreasuryLiquidator.sol) * [contracts/bots/PartialLiquidationBotV3.sol](https://github.com/Gearbox-protocol/bots-v3/blob/main/contracts/bots/PartialLiquidationBotV3.sol)
## Bot System Source: https://docs.gearbox.finance/developers/bot-system File: content/developers/bot-system.mdx Gearbox V3 features a sophisticated bot permission system that allows automated management of Credit Accounts. Bots can execute operations on behalf of account owners with granular, revocable permissions. ## BotList Architecture ### Components | Component | Description | | ------------------ | --------------------------------------------------------------------- | | **BotListV3** | Registry storing `(bot, creditManager, creditAccount)` -> permissions | | **IBot interface** | Bots implement `requiredPermissions()` to declare needed permissions | | **CreditFacadeV3** | Entry point for bot execution via `botMulticall` | ### Permission Storage ```solidity // BotListV3 storage mapping(address bot => mapping(address creditManager => mapping(address creditAccount => uint192 permissions) ) ) internal _permissions; ``` *** ## Permission Model ### Permission Flags Permissions are stored as a `uint192` bitmask: | Permission | Value | Operation | | -------------------------------- | --------- | --------------------- | | `ADD_COLLATERAL_PERMISSION` | `1 << 0` | Add funds to account | | `INCREASE_DEBT_PERMISSION` | `1 << 1` | Borrow more from pool | | `DECREASE_DEBT_PERMISSION` | `1 << 2` | Repay debt | | `WITHDRAW_COLLATERAL_PERMISSION` | `1 << 5` | Withdraw assets | | `UPDATE_QUOTA_PERMISSION` | `1 << 6` | Change token quotas | | `SET_BOT_PERMISSIONS_PERMISSION` | `1 << 8` | Manage other bots | | `EXTERNAL_CALLS_PERMISSION` | `1 << 16` | Execute adapter calls | ### ALL\_PERMISSIONS Constant ```solidity uint192 ALL_PERMISSIONS = ADD_COLLATERAL_PERMISSION | INCREASE_DEBT_PERMISSION | DECREASE_DEBT_PERMISSION | WITHDRAW_COLLATERAL_PERMISSION | UPDATE_QUOTA_PERMISSION | EXTERNAL_CALLS_PERMISSION; ``` Note: `SET_BOT_PERMISSIONS_PERMISSION` is excluded from `ALL_PERMISSIONS` - bots cannot grant permissions to other bots. *** ## Granting Permissions ### Setting Bot Permissions Account owners grant permissions through a multicall: ```solidity function _setBotPermissions(address creditAccount, bytes calldata callData) internal { (address bot, uint192 permissions) = abi.decode(callData, (address, uint192)); // Cannot grant SET_BOT_PERMISSIONS_PERMISSION uint192 allowedPermissions = ALL_PERMISSIONS & ~SET_BOT_PERMISSIONS_PERMISSION; uint192 unexpectedPermissions = permissions & ~allowedPermissions; if (unexpectedPermissions != 0) revert UnexpectedPermissionsException(unexpectedPermissions); uint256 remainingBots = IBotListV3(botList).setBotPermissions({ bot: bot, creditAccount: creditAccount, permissions: permissions }); // Update BOT_PERMISSIONS_SET_FLAG // ... } ``` ### Process 1. Owner calls `setBotPermissions(botAddress, permissions)` in multicall 2. BotListV3 validates permissions match bot's `requiredPermissions()` 3. Max 5 active bots per account (`MAX_SANE_ACTIVE_BOTS`) 4. Revoke by setting `permissions = 0` 5. `eraseAllBotPermissions()` clears all (called automatically on account close) ### BOT\_PERMISSIONS\_SET\_FLAG This optimization flag indicates whether an account has any authorized bots: * Set `true` when first bot is added * Set `false` when last bot is removed * Checked in `botMulticall` before querying BotListV3 ```typescript // TypeScript: Setting bot permissions import { encodeFunctionData } from 'viem'; const ADD_COLLATERAL = 1n << 0n; const DECREASE_DEBT = 1n << 2n; const EXTERNAL_CALLS = 1n << 16n; // Grant bot permission to add collateral, repay debt, and make external calls const permissions = ADD_COLLATERAL | DECREASE_DEBT | EXTERNAL_CALLS; const calls = [ { target: facadeAddress, callData: encodeFunctionData({ abi: creditFacadeMulticallAbi, functionName: 'setBotPermissions', args: [botAddress, permissions] }) } ]; await creditFacade.write.multicall([creditAccount, calls]); ``` *** ## Bot Operations ### botMulticall Execution ```solidity function botMulticall(address creditAccount, MultiCall[] calldata calls) external whenNotPaused whenNotExpired nonReentrant { _getBorrowerOrRevert(creditAccount); // Check bot status (uint256 botPermissions, bool forbidden) = IBotListV3(botList).getBotStatus({bot: msg.sender, creditAccount: creditAccount}); if (forbidden || botPermissions == 0 || _flagsOf(creditAccount) & BOT_PERMISSIONS_SET_FLAG == 0) { revert NotApprovedBotException(msg.sender); } // Execute with permission checks _multicall(creditAccount, calls, _enabledTokensMaskOf(creditAccount), botPermissions); } ``` ### Execution Flow 1. **Status Check**: Query BotListV3 for permissions & forbidden status 2. **Flag Check**: Verify `BOT_PERMISSIONS_SET_FLAG` is set 3. **Granular Authorization**: Each call checked against permission bitmask 4. **Solvency Guard**: Always `fullCollateralCheck` after all calls 5. **Revert**: If HF < 1 after execution ### Permission Enforcement ```solidity function _revertIfNoPermission(uint256 flags, uint256 permission) internal pure { if (flags & permission == 0) { revert NoPermissionException(permission); } } ``` Used throughout multicall processing: ```solidity _revertIfNoPermission(flags, ADD_COLLATERAL_PERMISSION); _revertIfNoPermission(flags, UPDATE_QUOTA_PERMISSION); _revertIfNoPermission(flags, WITHDRAW_COLLATERAL_PERMISSION); _revertIfNoPermission(flags, INCREASE_DEBT_PERMISSION); _revertIfNoPermission(flags, EXTERNAL_CALLS_PERMISSION); ``` *** ## Safety Model ### Security Properties | Property | Mechanism | | ----------------- | --------------------------------------------------- | | **Isolation** | Permissions are account-specific (not global) | | **Immutability** | Bots are typically immutable contracts | | **DAO Override** | Global "forbid" list in BotListV3 | | **Atomic Safety** | Post-execution collateral check prevents fund theft | | **No Bad Debt** | Bots cannot leave protocol with losses | ### Forbidden Bot List The DAO can globally forbid malicious bots: ```solidity // In BotListV3 function setBotForbiddenStatus(address bot, bool forbidden) external; ``` A forbidden bot cannot execute on any account, regardless of individual permissions. ### Collateral Check Protection Even with all permissions, a bot cannot: * Leave account with HF < 1 * Increase forbidden token balances * Bypass debt limits The final collateral check after `botMulticall` ensures account remains healthy. ```typescript // TypeScript: Bot executing operations const botClient = createWalletClient({ account: botAccount, chain: mainnet, transport: http(), }); const creditFacade = getContract({ address: facadeAddress, abi: creditFacadeV3Abi, client: botClient, }); // Bot-initiated operations const calls = [ // Add collateral { target: facadeAddress, callData: encodeFunctionData({ abi: creditFacadeMulticallAbi, functionName: 'addCollateral', args: [usdcAddress, parseUnits('1000', 6)] }) }, // Execute swap via adapter { target: uniswapAdapterAddress, callData: encodeFunctionData({ abi: uniswapAdapterAbi, functionName: 'exactInputSingle', args: [swapParams] }) } ]; // Execute as bot await creditFacade.write.botMulticall([creditAccountAddress, calls]); ``` *** ## Bot Development ### Implementing IBot Interface ```solidity interface IBot { function requiredPermissions() external view returns (uint192); } ``` Bots should declare minimum permissions needed: ```solidity contract MyRebalanceBot is IBot { function requiredPermissions() external pure returns (uint192) { return UPDATE_QUOTA_PERMISSION | EXTERNAL_CALLS_PERMISSION; } function rebalance(address creditAccount, address creditFacade) external { // Build multicall MultiCall[] memory calls = _buildRebalanceCalls(creditAccount); // Execute ICreditFacadeV3(creditFacade).botMulticall(creditAccount, calls); } } ``` ### Common Bot Patterns | Bot Type | Typical Permissions | | --------------------------- | ------------------------------------------------------------- | | **Rebalance Bot** | `UPDATE_QUOTA_PERMISSION`, `EXTERNAL_CALLS_PERMISSION` | | **Collateral Manager** | `ADD_COLLATERAL_PERMISSION`, `WITHDRAW_COLLATERAL_PERMISSION` | | **Debt Manager** | `INCREASE_DEBT_PERMISSION`, `DECREASE_DEBT_PERMISSION` | | **Partial Liquidation Bot** | `DECREASE_DEBT_PERMISSION`, `EXTERNAL_CALLS_PERMISSION` | ```typescript // TypeScript: Checking bot permissions const botList = getContract({ address: botListAddress, abi: botListV3Abi, client: publicClient, }); // Get bot status for specific account const [permissions, forbidden] = await botList.read.getBotStatus([ botAddress, creditAccountAddress ]); console.log(`Permissions: ${permissions.toString(2)}`); // Binary representation console.log(`Forbidden: ${forbidden}`); // Check specific permission const hasExternalCalls = (permissions & (1n << 16n)) !== 0n; console.log(`Can make external calls: ${hasExternalCalls}`); ```
Sources * [contracts/core/BotListV3.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/core/BotListV3.sol) * [contracts/interfaces/IBotListV3.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/interfaces/IBotListV3.sol) * [contracts/interfaces/base/IBot.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/interfaces/base/IBot.sol) * [contracts/credit/CreditFacadeV3.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/credit/CreditFacadeV3.sol)
## Quota Keeper Source: https://docs.gearbox.finance/developers/quota-keeper File: content/developers/quota-keeper.mdx In Gearbox V3, "Quotas" are the primary mechanism for managing risk associated with collateral exposure. While a lending pool provides the capital (underlying), the **PoolQuotaKeeper** regulates how much of that capital can be exposed to specific collateral types and at what cost. ## Pool and PoolQuotaKeeper Interaction The **Pool** (`PoolV3`) and the **PoolQuotaKeeper** (`PoolQuotaKeeperV3`) form a tight loop for financial accounting and revenue distribution. > For the economic rationale behind quotas and how they affect borrowing strategy, see [Quota Controls](https://github.com/de-snake/docs-knowledge/blob/new-docs-dev-1/new-docs-about/economics-and-risk/quota-controls.md). **Architecture and Data Flow** The Pool manages the actual ERC-20 assets, while the QuotaKeeper tracks the borrowing capacity for the collaterals. * **Additive Interest**: Unlike the base debt which compounds, quota interest is additive (linear). The QuotaKeeper tracks a `cumulativeIndex` for each token that grows based on the rate set by the Gauge. *** ## Quota Limits and Risk Management Quota limits represent the protocol's "risk appetite" for specific assets. They are enforced globally per pool. **What are Quota Limits?** A **Quota Limit** is the maximum aggregate amount of debt backed a specific collateral token that all Credit Accounts combined can hold. * **Preventing Tail Risk**: Limits ensure that the protocol is never over-exposed to a single asset that might suffer from a liquidity crunch or oracle failure. * **Capacity Control**: If a token's `totalQuoted` reaches its `limit`, any transaction attempting to increase that quota in a Credit Account will revert with `QuotaIsOutOfBoundsException`. **Mechanism for Setting Limits** Limits are managed directly on the `PoolQuotaKeeperV3` contract: * **Function**: `setTokenLimit(address token, uint96 limit)` * **Access Control**: Only the `CONFIGURATOR` (typically a Risk Curator or the DAO) can call this. * **Validation**: In the **Permissionless** framework, the `PoolFactory` ensures that limits cannot be set for tokens that do not have a valid price feed. *** ## Gauge Model: Gauge vs. Tumbler Every QuotaKeeper relies on an external contract implementing `IRateKeeper` to provide interest rates. **GaugeV3 (Voting Model)** Used in the core protocol where GEAR stakers vote to move interest rates between a `minRate` and `maxRate`. This reflects decentralized market sentiment regarding the risk/reward of specific strategies. **TumblerV3 (Curator Model)** The **Tumbler** is a simplified, non-voting implementation of the Gauge. It is the standard choice for curators in the Gearbox Permissionless ecosystem. * **Direct Control**: Curators set exact rates using `setRate(address token, uint16 rate)`. * **Epoch-Based Updates**: Rates are set in basis points but only take effect when `updateRates()` is called. The Tumbler enforces an `epochLength` to prevent frequent rate manipulation and provide predictability for borrowers. *** ## Data Retrieval and Observability To monitor the state of quotas and limits, several view functions are provided. **Global Quota Data** To see the status of a specific token within a pool, call `PoolQuotaKeeperV3.getTokenQuotaParams(address token)`. This returns: * `rate`: The current annual interest rate in basis points. * `totalQuoted`: Total amount of this token currently held as quota across all accounts. * `limit`: The maximum allowed `totalQuoted`. * `isActive`: Whether the token is currently quoted in this keeper. **User-Specific Data** To see how much quota an individual Credit Account is consuming, call `PoolQuotaKeeperV3.getQuotaAndOutstandingInterest(address creditAccount, address token)`. * `quoted`: The amount of token quota held by the account. * `outstandingInterest`: The interest accrued by this quota that hasn't been added to the account's debt yet. ```typescript // TypeScript: Reading quota data import { getContract } from 'viem'; const quotaKeeper = getContract({ address: quotaKeeperAddress, abi: poolQuotaKeeperV3Abi, client: publicClient, }); // Get global quota parameters for a token const tokenParams = await quotaKeeper.read.getTokenQuotaParams([tokenAddress]); // Returns: { rate, cumulativeIndex, quotaIncreaseFee, totalQuoted, limit, isActive } // Get account-specific quota and accrued interest const [quoted, outstandingInterest] = await quotaKeeper.read.getQuotaAndOutstandingInterest([ creditAccountAddress, tokenAddress, ]); // Check if quota is available (not at limit) const availableQuota = tokenParams.limit - tokenParams.totalQuoted; ```
Sources * [contracts/pool/PoolQuotaKeeperV3.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/pool/PoolQuotaKeeperV3.sol) * [contracts/pool/PoolV3.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/pool/PoolV3.sol) * [contracts/pool/TumblerV3.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/pool/TumblerV3.sol) * [contracts/interfaces/IPoolQuotaKeeperV3.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/interfaces/IPoolQuotaKeeperV3.sol) * [contracts/factories/PoolFactory.sol](https://github.com/Gearbox-protocol/permissionless/blob/master/contracts/factories/PoolFactory.sol) * [contracts/types/MarketData.sol](https://github.com/Gearbox-protocol/periphery-v3/blob/main/contracts/types/MarketData.sol)
## Compressors Source: https://docs.gearbox.finance/developers/compressors File: content/developers/compressors.mdx 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:** | Field | Type | Description | | -------------------- | --------- | --------------------- | | `baseParams.addr` | `address` | Pool contract address | | `availableLiquidity` | `uint256` | Borrowable liquidity | | `dieselRate` | `uint256` | Share price (RAY) | | `supplyRate` | `uint256` | Lender APY (RAY) | | `baseInterestRate` | `uint256` | Borrower APR (RAY) | | `totalAssets` | `uint256` | Total pool value | **Key fields in CreditSuiteData:** | Field | Type | Description | | -------------------- | ------------------- | ------------------------ | | `creditManager` | `address` | Credit Manager address | | `creditFacade` | `address` | Credit Facade address | | `creditConfigurator` | `address` | Configurator address | | `debtLimits` | `DebtLimits` | min/max debt per account | | `collateralTokens` | `CollateralToken[]` | Allowed tokens + LTs | *** ## CreditAccountCompressor Fetches credit account data with filtering and pagination. ### Interface ```solidity interface ICreditAccountCompressor { function getCreditAccounts( address creditManager, CreditAccountFilter memory filter, uint256 offset ) external view returns (CreditAccountData[] memory accounts, uint256 total); function countCreditAccounts( address creditManager, CreditAccountFilter memory filter ) external view returns (uint256); function getCreditAccountData( address creditManager, address creditAccount ) external view returns (CreditAccountData memory); } ``` ### CreditAccountFilter ```solidity struct CreditAccountFilter { address owner; // Filter by owner (address(0) = any) uint256 minHealthFactor; // Minimum HF (0 = no min) uint256 maxHealthFactor; // Maximum HF (type(uint256).max = no max) bool includeZeroDebt; // Include accounts with no debt bool reverting; // Include reverting accounts } ``` ### Solidity Usage ```solidity import {ICreditAccountCompressor} from "@gearbox-protocol/periphery-v3/contracts/interfaces/ICreditAccountCompressor.sol"; ICreditAccountCompressor compressor = ICreditAccountCompressor(compressorAddress); // Get accounts with low health factor (for liquidation) CreditAccountFilter memory filter = CreditAccountFilter({ owner: address(0), minHealthFactor: 0, maxHealthFactor: 10000, // HF < 1.0 includeZeroDebt: false, reverting: false }); (CreditAccountData[] memory accounts, uint256 total) = compressor.getCreditAccounts(creditManager, filter, 0); ``` ### TypeScript Usage ```typescript import { creditAccountCompressorAbi } from '@gearbox-protocol/sdk'; // Get all accounts with debt const [accounts, total] = await client.readContract({ address: compressorAddress, abi: creditAccountCompressorAbi, functionName: 'getCreditAccounts', args: [ creditManagerAddress, { owner: '0x0000000000000000000000000000000000000000', minHealthFactor: 0n, maxHealthFactor: BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'), includeZeroDebt: false, reverting: false, }, 0n, // offset ], }); console.log(`Found ${total} accounts, fetched ${accounts.length}`); ``` ### CreditAccountData Structure ```solidity struct CreditAccountData { address addr; // Credit Account address address owner; // Account owner address creditManager; // Parent Credit Manager uint256 debt; // Total debt (principal + interest) uint256 cumulativeIndexLastUpdate; uint256 cumulativeQuotaInterest; uint128 quotaFees; uint256 enabledTokensMask; // Bitmask of enabled tokens uint256 healthFactor; // Current HF (10000 = 1.0) TokenInfo[] tokens; // Token balances and values bool isLiquidatable; } ``` ### Pagination Large result sets are paginated. Use `offset` to fetch subsequent pages: ```typescript const PAGE_SIZE = 100n; let offset = 0n; let allAccounts: CreditAccountData[] = []; while (true) { const [accounts, total] = await compressor.read.getCreditAccounts([ creditManager, filter, offset, ]); allAccounts.push(...accounts); offset += BigInt(accounts.length); if (offset >= total) break; } ``` *** ## 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 | Scenario | Approach | | ---------------------- | --------------------------------------- | | General market data | SDK `marketRegister` | | Credit account queries | SDK services | | Custom filtering logic | Direct compressor calls | | Liquidation bots | Direct compressor (gas-optimized) | | On-chain integration | Direct compressor (no SDK in contracts) | | Real-time monitoring | Direct compressor with specific filters | The SDK uses compressors internally. Use direct compressor calls when you need: * Custom filter combinations not exposed by SDK * Pagination control * Gas-optimized queries for bots * On-chain access (Solidity 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(), }); async function getMarketOverview() { const marketCompressor = '0x...'; // From AddressProvider const markets = await client.readContract({ address: marketCompressor, 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 accountCompressor = '0x...'; // From AddressProvider const [accounts] = await client.readContract({ address: accountCompressor, abi: creditAccountCompressorAbi, functionName: 'getCreditAccounts', args: [ creditManager, { owner: '0x0000000000000000000000000000000000000000', minHealthFactor: 0n, maxHealthFactor: 10000n, // HF < 1.0 includeZeroDebt: false, reverting: false, }, 0n, ], }); return accounts.filter(a => a.isLiquidatable); } ``` ### 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), minHealthFactor: 0, maxHealthFactor: 10000, includeZeroDebt: false, reverting: false }); (CreditAccountData[] memory accounts,) = ICreditAccountCompressor(ACCOUNT_COMPRESSOR).getCreditAccounts( creditManager, filter, 0 ); return accounts; } ``` ## Automated Insurance Source: https://docs.gearbox.finance/developers/automated-insurance File: content/developers/automated-insurance.mdx The insurance mechanism in Gearbox V3 functions as a **liquidity buffer** held in the `TreasurySplitter` contract. It acts as a first-loss protection layer to maintain pool solvency during bad debt events. ## How the Insurance Mechanism Works The "Insurance" is essentially a **retention policy** on the fees collected by the protocol. Instead of immediately distributing all profits to the Curator and the DAO, the `TreasurySplitter` holds a specific amount of tokens back as a safety buffer. **The Buffer Logic (`TreasurySplitter`)** The `TreasurySplitter` collects fees (from interest and standard liquidations). Before any of these fees can be claimed (distributed) by the admins, the contract checks if the current balance exceeds the `tokenInsuranceAmount`. * **If Balance < Insurance Amount:** The distribution fails/stops. All funds remain in the contract. * **If Balance > Insurance Amount:** Only the surplus (`balance - insuranceAmount`) is distributed. The `insuranceAmount` remains locked in the contract. This ensures that there is always a pile of liquid assets available to the protocol to cover unexpected losses before any profit-taking occurs. *** #### Understanding the Flow (Architecture) The following diagram shows how the assets are held and how the distribution logic protects the insurance amount: *** ## Covering Bad Debt (Liquidation Logic) When a "Bad Debt" liquidation occurs (where the collateral value is less than the debt), the system must cover the deficit to keep the lenders whole. This happens in the `PoolV3` contract, interacting with the protocol's Treasury balance. 1. **Liquidation with Loss:** A liquidator calls `liquidateCreditAccount`. They sell the collateral, but the proceeds are insufficient to repay the full debt. 2. **Reporting the Loss:** The Credit Manager calls `pool.repayCreditAccount(..., profit, loss)`. 3. **Burning the Buffer:** The Pool burns **LP Shares** held by the Treasury address to cover the loss. **Critical Link:** The `TreasurySplitter` accumulates the *pool's LP tokens*. The assets held in the `TreasurySplitter` can be used to **re-deposit** into the Pool effectively using the insurance buffer to pay for the bad debt. *** > For the economic model behind insurance reserves and first-loss capital mechanics, see [Insurance and Solvency Reserves](https://github.com/de-snake/docs-knowledge/blob/new-docs-dev-1/new-docs-about/economics-and-risk/insurance-and-solvency-reserves.md). *** ## Reading Insurance State On-Chain Query the `TreasurySplitter` contract to verify insurance health for a specific pool. ### 1. Check Insurance Target (The Floor) The minimum amount retained before any profit distribution: #### Solidity ```solidity uint256 target = treasurySplitter.tokenInsuranceAmount(token); ``` #### TypeScript ```typescript import { getContract } from 'viem'; import { iTreasurySplitterAbi } from '@gearbox-protocol/sdk'; const treasurySplitter = getContract({ address: treasurySplitterAddress, abi: iTreasurySplitterAbi, client: publicClient }); const insuranceTarget = await treasurySplitter.read.tokenInsuranceAmount([tokenAddress]); ``` ### 2. Check Current Buffer Compare actual balance to target to determine insurance status: #### Solidity ```solidity uint256 target = treasurySplitter.tokenInsuranceAmount(token); uint256 balance = IERC20(token).balanceOf(address(treasurySplitter)); bool fullyInsured = balance >= target; uint256 surplus = balance > target ? balance - target : 0; ``` #### TypeScript ```typescript import { erc20Abi } from 'viem'; // Get target and current balance const target = await treasurySplitter.read.tokenInsuranceAmount([tokenAddress]); const balance = await publicClient.readContract({ address: tokenAddress, abi: erc20Abi, functionName: 'balanceOf', args: [treasurySplitterAddress] }); const fullyInsured = balance >= target; const surplus = balance > target ? balance - target : 0n; ``` ### 3. Monitor Governance Changes Insurance parameter changes require dual signatures (Curator + DAO): #### TypeScript ```typescript // Get pending proposals that may affect insurance const proposals = await treasurySplitter.read.activeProposals(); // Each proposal contains: proposer, target, calldata, executed status for (const proposal of proposals) { console.log('Pending proposal:', proposal); } ``` ### 4. Query Fee Distribution Config Understand where surplus fees are distributed: #### TypeScript ```typescript // Get default split configuration const defaultSplit = await treasurySplitter.read.defaultSplit(); // Or token-specific split const tokenSplit = await treasurySplitter.read.tokenSplits([tokenAddress]); // Returns: { receivers: address[], proportions: uint256[] } ```
Sources * [contracts/market/TreasurySplitter.sol](https://github.com/Gearbox-protocol/permissionless/blob/master/contracts/market/TreasurySplitter.sol) * [contracts/interfaces/ITreasurySplitter.sol](https://github.com/Gearbox-protocol/permissionless/blob/master/contracts/interfaces/ITreasurySplitter.sol) * [contracts/credit/CreditManagerV3.sol](https://github.com/Gearbox-protocol/core-v3/blob/main/contracts/credit/CreditManagerV3.sol)
## Gearbox Permissionless Overview Source: https://docs.gearbox.finance/developers/gp-overview File: content/developers/gp-overview.mdx Gearbox Permissionless is the governance and infrastructure layer that makes the entire protocol trustless, verifiable, and permissionlessly extensible across chains. It is implemented as a collection of smart contracts that define roles, boundaries, and processes — ensuring no single entity can access user funds or override market parameters. The code is open source at [github.com/Gearbox-protocol/permissionless](https://github.com/Gearbox-protocol/permissionless). ## Design Principles - **Non-Interference with Decisions** — the DAO cannot influence or override decisions made by Market Curators or Instance Owners - **No Control Over Market Contracts** — market parameters allow flexible modification by Curators, but the DAO cannot alter them - **Exclusive Control Over System Contract Versions** — only the DAO can authorize new versions of system contracts (core protocol logic). Adding adapters, price feeds, bots, or other components remains permissionless. - **Chain Expansion Oversight** — only the DAO can activate Gearbox on new chains, ensuring the correct Treasury address and Instance Owner multisig are set ## Core Components | Component | Purpose | | --- | --- | | [**Contract Types & Versioning**](https://docs.gearbox.finance/developers/gp-contract-types) | Type system for all protocol contracts. Domain-based organization, semantic versioning, module replacement (not proxies) | | [**Cross-Chain Multisig (CCM)**](https://docs.gearbox.finance/developers/gp-ccm) | Governance synchronization across chains. Hash-linked batches, strict sequential ordering | | [**Bytecode Repository (BCR)**](https://docs.gearbox.finance/developers/gp-bcr) | On-chain registry of audited bytecode. System vs public domains, dual-signature verification | | [**Instances**](https://docs.gearbox.finance/developers/gp-instances) | Per-chain protocol replicas. DAO-activated, managed by Instance Owner | | [**PriceFeed Store**](https://docs.gearbox.finance/developers/gp-pricefeed-store) | Token-to-oracle marketplace. Instance Owner managed, curator-consumed | | [**Treasury & Insurance**](https://docs.gearbox.finance/developers/gp-treasury) | Fee distribution (curator/DAO split) and loss coverage fund | ## Roles The protocol defines a clear hierarchy of roles, each with strictly bounded authority enforced at the smart contract level: | Role | Scope | Can Affect Users | | --- | --- | --- | | DAO (token holders) | All chains | No | | Technical Multisig | All chains | No | | Auditors | All chains | No | | Instance Owners | One chain | No | | Financial Representatives | One chain | No | | Market Curators | Market | Yes (with timelock) | | Emergency Admin | Market | Yes (immediate) | | Pausable/Unpausable Admins | Market | Yes | | Emergency Liquidators | Market | Yes | See [Roles & Permissions](https://docs.gearbox.finance/developers/gp-roles) for detailed authority tables. ## What's in This Section - [**Concepts**](https://docs.gearbox.finance/developers/gp-concepts) — How each component works - [**Building**](https://docs.gearbox.finance/developers/gp-building) — Create adapters, integrate protocols, extend the core ## Concepts Source: https://docs.gearbox.finance/developers/gp-concepts File: content/developers/gp-concepts.mdx The Gearbox Permissionless infrastructure is built from a set of interlocking components. Each enforces specific boundaries at the smart contract level — no role can exceed its authority, even if compromised. - [**Contract Types & Versioning**](https://docs.gearbox.finance/developers/gp-contract-types) — The type system (`contractType`, domains, `::` notation) and semantic versioning that organize all protocol contracts. Upgrades via module replacement, not proxies. - [**Cross-Chain Multisig (CCM)**](https://docs.gearbox.finance/developers/gp-ccm) — The governance synchronization layer. Hash-linked batches originate on Mainnet and propagate to all chains in strict sequential order. - [**Bytecode Repository (BCR)**](https://docs.gearbox.finance/developers/gp-bcr) — On-chain registry of audited contract bytecode. System domains require DAO approval; public domains (adapters, price feeds, IRMs) are permissionless after audit. - [**Instances**](https://docs.gearbox.finance/developers/gp-instances) — Per-chain protocol replicas. DAO-activated, managed by an Instance Owner multisig. One instance per chain. - [**PriceFeed Store**](https://docs.gearbox.finance/developers/gp-pricefeed-store) — A marketplace linking tokens to approved price feeds. Managed by Instance Owners, consumed by Market Curators. - [**Treasury & Insurance**](https://docs.gearbox.finance/developers/gp-treasury) — Fee distribution between curators and the DAO via TreasurySplitter, plus an insurance fund for loss coverage. - [**Roles & Permissions**](https://docs.gearbox.finance/developers/gp-roles) — Complete role hierarchy: DAO, Technical Multisig, Auditors, Instance Owners, Financial Representatives, Market Curators, Emergency Admin, and more. Each with explicit authority boundaries. ## Contract Types & Versioning Source: https://docs.gearbox.finance/developers/gp-contract-types File: content/developers/gp-contract-types.mdx Every contract in Gearbox is identified by a `contractType` (bytes32) and a `version` (uint256), enabling precise classification and safe modular upgrades without proxies. ## Domains and Contract Types Contract types are organized into **domains** based on functionality. Domains and subtypes are separated by `::` notation. | Domain | Example Types | Description | | --- | --- | --- | | `IRM` | `IRM::FIXED`, `IRM::LINEAR_MODEL` | Interest rate models | | `PRICE_FEED` | `PRICE_FEED::CHAINLINK`, `PRICE_FEED::REDSTONE` | Price feed implementations | | `ADAPTER` | `ADAPTER::UNISWAP_V3`, `ADAPTER::CURVE` | Protocol integration adapters | | `PHANTOM_TOKEN` | `PHANTOM_TOKEN::STETH` | Phantom token wrappers | Contract types within the same domain share the same programming interface, but their configurations may differ. For example, `IRM::FIXED` and `IRM::LINEAR_MODEL` both implement the interest rate model interface, but accept different constructor parameters. ## Version Control Versions are encoded as `uint256` integers (e.g., `3_10` represents version 3.10). The versioning scheme uses three levels: | Level | When to Use | Compatibility | | --- | --- | --- | | **Major** | Significant interface changes | Breaking — not backward compatible | | **Minor** | Minor interface changes | May require integration updates | | **Patch** | Same interface, no behavioral changes | Fully backward compatible | ## Module Replacement, Not Proxies Gearbox upgrades contracts through **module replacement** rather than proxy patterns. When a new version is available: - The new contract is deployed as a standalone module - The old module is swapped out for the new one - No proxy delegation or storage layout concerns This approach eliminates the risks associated with proxy-based upgrades (storage collisions, delegatecall vulnerabilities) while keeping the system modular. ## Upgrade Rules Two critical constraints govern upgrades: 1. **Patched versions only** — updates are only permissible via patched versions of an existing contract type, ensuring interface stability 2. **No forced updates** — system upgrades are managed exclusively by market curators. The DAO cannot force a curator to adopt a new contract version Even when a new version passes audit and DAO approval, it remains opt-in. Market curators deliberately choose whether and when to update their deployments. ## Learn More - [Bytecode Repository (BCR)](https://docs.gearbox.finance/developers/gp-bcr) — How contract bytecode is stored, audited, and approved - [Cross-Chain Multisig (CCM)](https://docs.gearbox.finance/developers/gp-ccm) — How governance decisions propagate across chains - [Instances](https://docs.gearbox.finance/developers/gp-instances) — How per-chain deployments operate ## Guardrails & Role Separation Source: https://docs.gearbox.finance/developers/gp-guardrails File: content/developers/gp-guardrails.mdx Most systems fail when one role has too much power. Gearbox achieves permissionless market operation by limiting power rather than adding trust. ## Three Governance Layers ### 1. Protocol DAO (Global) Manages the codebase and high-level protocol parameters across all chains. - Approves new contract versions for the [Bytecode Repository](https://docs.gearbox.finance/developers/gp-bcr) - Authorizes chain deployments - Manages GEAR token incentives - **Cannot** alter curator parameters or access user funds ### 2. Instance Owner (Per-Chain) A technical multisig on each chain that maintains infrastructure. - Manages the Price Feed Store (whitelists oracle feeds) - Executes protocol upgrades on the specific chain - Operates on a **neutral principle**: verifies technical correctness, not financial viability - Composed of diverse ecosystem participants (curators, chain foundation, auditors, core team) ### 3. Market Curators (Per-Market) Independent operators of specific lending markets. - Set risk parameters: liquidation thresholds, adapters, fees, debt limits - Non-custodial — manage *parameters*, not *funds* - Subject to hardcoded safety constraints (see below) ## The Ramping Mechanism Rather than allowing instant parameter changes, Gearbox enforces **linear ramping** for critical updates: - Liquidation threshold changes interpolate linearly over a **minimum 24-hour period** - This minimum is **hardcoded and immutable** — not even curators can bypass it - Prevents sudden liquidation cascades or market manipulation via parameter changes - Users have time to react and adjust positions before new parameters take full effect ## Emergency Toolset Curators have access to immediate intervention capabilities for genuine emergencies: | Emergency Action | Effect | Constraint | | --- | --- | --- | | Prohibit a token | Immediately blocks a risky collateral token | Instant | | Adjust interest rates | Change rate curves to manage liquidity | Instant | | Increase liquidation thresholds | Make accounts safer (never riskier) | Instant | | Switch oracle feeds | Switch to an alternative approved feed | Feed must have been in catalog for 2+ days | The oracle switching constraint is critical: even during emergencies, newly added oracle feeds must have existed in the on-chain catalog for at least 2 days before they can be deployed. This prevents an attacker from adding a malicious oracle and immediately switching to it. ## Key Design Principle Even if governance were compromised, it cannot directly change user positions or interfere with curated markets. Each layer's power is bounded by smart contract logic, not by trust in the operators. ## Learn More - [Bytecode Repository (BCR)](https://docs.gearbox.finance/developers/gp-bcr) — How code verification prevents unaudited deployments - [Cross-Chain Multisig (CCM)](https://docs.gearbox.finance/developers/gp-ccm) — How governance decisions synchronize across chains ## Bytecode Repository (BCR) Source: https://docs.gearbox.finance/developers/gp-bcr File: content/developers/gp-bcr.mdx The Bytecode Repository is an on-chain registry that stores the bytecode of all contracts used in the Gearbox Protocol, with the exception of external tokens, price feeds, and external protocol contracts. Every entry is identified by a `contractType` and `version`. ## System vs Public Domains Contract domains are classified into two categories that determine the approval flow required before a contract can be used in production. | Category | Domains | Approval Required | | --- | --- | --- | | **Public** (permissionless) | `PRICE_FEED::`, `ADAPTER::`, `IRM::`, `PHANTOM_TOKEN::` | Audit signature only | | **System** | All other domains | Audit signature + DAO vote | Public domains allow anyone to contribute new contract types after passing an audit. System domains require an additional DAO governance vote, reflecting their higher impact on protocol integrity. ## Adding Contracts to BCR Any EOA can upload contract bytecode to the BCR via an EIP-712 signature. However, uploading alone does not put a contract into production. The approval flow differs by domain: ### Public Domain Flow 1. Developer uploads contract bytecode to BCR 2. Auditor reviews and signs the bytecode hash 3. Contract becomes available for use by market curators ### System Domain Flow 1. Developer uploads contract bytecode to BCR 2. Auditor reviews and signs the bytecode hash 3. DAO votes to approve the contract 4. Contract becomes available for use by market curators In both cases, the final step is always curator adoption — even with full approval, market curators must deliberately choose to deploy or update to the new contract. ## ContractType Cybersquatting Protection Once a `contractType` has been audited, it is permanently assigned to the original author. This prevents malicious actors from registering a contract under someone else's type identifier. ## Version Mechanics The BCR enforces a strict separation between approval and deployment: - Audit + DAO approval (for system domains) makes a contract **available** - Market curators must **deliberately choose** to update to the new version - No contract is automatically pushed into production This ensures curators retain full control over which contract versions run in their markets. ## Bytecode Requirements All contracts submitted to the BCR must be compiled with the following settings: | Parameter | Required Value | | --- | --- | | Solidity version | `0.8.23` | | EVM target | `shanghai` | | Optimizer runs | `1000` | | Bytecode hash | `none` | These requirements ensure deterministic compilation and consistent bytecode verification across environments. ## Learn More - [Contract Types & Versioning](https://docs.gearbox.finance/developers/gp-contract-types) — How contract types and domains are structured - [Cross-Chain Multisig (CCM)](https://docs.gearbox.finance/developers/gp-ccm) — How governance decisions propagate across chains - [Instances](https://docs.gearbox.finance/developers/gp-instances) — How per-chain deployments operate ## Cross-Chain Multisig (CCM) Source: https://docs.gearbox.finance/developers/gp-ccm File: content/developers/gp-ccm.mdx The Cross-Chain Multisig (CCM) is the core contract that manages DAO governance across all connected networks. It is deployed at the same address on every chain: `0xCCCCcCCc42B7DA9fdEc1761698Fb55fdD41CDF55`. ## Batch Voting System DAO decisions are grouped into **batches**. Token holders vote on each batch, and approved batches are executed across all chains. Batches are connected by hashes in a chain-like structure — each batch references its predecessor. This creates an immutable, ordered history of governance decisions with strict sequential ordering across all EVM chains. ``` Batch N-1 (hash: 0xabc...) └──▶ Batch N (prev: 0xabc..., hash: 0xdef...) └──▶ Batch N+1 (prev: 0xdef..., hash: 0x123...) ``` This sequential ordering guarantees that every chain processes governance decisions in the exact same order, preventing conflicts or state divergence. ## Propagation Mechanisms Once a batch is approved, it must reach every connected chain. CCM supports two transport mechanisms: | Mechanism | Description | | --- | --- | | **Cross-chain multisig signing** | Signers execute the batch directly on each target chain | | **Message bridging** | Batch is relayed through a cross-chain messaging bridge | Both mechanisms deliver the same deterministic batch payload, ensuring identical execution regardless of transport. ## Recovery Mode In edge cases where a batch exceeds the block size limit on a specific chain, CCM provides **rescue batches**. These allow the affected chain to process the oversized batch through an alternative execution path, preventing a single chain's constraints from blocking governance across the entire network. ## Current vs Future Governance | Aspect | Current Implementation | Future Implementation | | --- | --- | --- | | **Decision origin** | Technical multisig signs on Mainnet | Fully on-chain governance contract | | **Batch creation** | Multisig uploads batches to CCM | Governance contract creates batches directly | | **Trust model** | Trusted multisig signers | Trustless on-chain voting | The CCM contract itself does not change between phases — only the entity that submits batches transitions from a multisig to an on-chain governance contract. ## Learn More - [Bytecode Repository (BCR)](https://docs.gearbox.finance/developers/gp-bcr) — How contract bytecode is stored and approved - [Instances](https://docs.gearbox.finance/developers/gp-instances) — How per-chain deployments are activated and managed - [Contract Types & Versioning](https://docs.gearbox.finance/developers/gp-contract-types) — How contracts are classified and versioned ## Instances Source: https://docs.gearbox.finance/developers/gp-instances File: content/developers/gp-instances.mdx An Instance is a complete, functional replica of the Gearbox Protocol on a specific chain. Each chain supports a single Instance, which must be approved by DAO vote before activation. ## Instance Properties | Property | Description | | --- | --- | | **One per chain** | Each blockchain has exactly one Gearbox Instance | | **DAO-approved** | Activation requires a DAO vote that validates the native token address and assigns governance roles | | **Independent operation** | Core functions (lending, borrowing, liquidations) operate without cross-chain dependencies | | **Immutable ownership** | Once set, the Instance Owner cannot be changed — not even by the DAO | ## Permissionless Deployment Anyone can deploy a new Instance via the Gearbox Permissionless Interface. However, deployment alone does not make an Instance operational — it requires **activation** through the DAO. ## Activation Process During activation, the DAO performs the following steps: 1. **Validates the native token address** — confirms the wrapped native token for the target chain 2. **Assigns the Financial Multisig** — designates the multisig responsible for financial operations 3. **Designates the Instance Owner** — assigns the Instance Owner multisig that will manage chain-level infrastructure Once activation is complete, the Instance Owner multisig manages the Instance. This assignment is permanent and cannot be revoked or reassigned by any party, including the DAO. ## Instance Owner Role The Instance Owner is a multisig that manages chain-specific infrastructure for its Instance. Its responsibilities include maintaining price feed allowlists, managing technical chain parameters, and ensuring the Instance operates correctly within its local ecosystem. The Instance Owner does not control market-level parameters — those are managed by individual market curators. ## Learn More - [Cross-Chain Multisig (CCM)](https://docs.gearbox.finance/developers/gp-ccm) — How governance decisions reach each Instance - [Bytecode Repository (BCR)](https://docs.gearbox.finance/developers/gp-bcr) — How contract bytecode is verified before deployment - [Contract Types & Versioning](https://docs.gearbox.finance/developers/gp-contract-types) — How contracts are classified and versioned ## PriceFeed Store Source: https://docs.gearbox.finance/developers/gp-pricefeed-store File: content/developers/gp-pricefeed-store.mdx The PriceFeed Store (PFS) is a marketplace that links tokens with their approved price feeds, serving as the canonical registry that market curators draw from when configuring markets. ## Purpose Price feeds are critical infrastructure — a malicious or misconfigured feed can directly threaten user funds. The PFS exists to provide a vetted catalog of token-to-feed mappings, reducing the risk of both intentional attacks and accidental misconfiguration. | Goal | How PFS Achieves It | | --- | --- | | **Prevent malicious feeds** | Only Instance Owners can add or update feed entries | | **Mitigate misconfiguration** | Curators select from pre-approved options rather than supplying arbitrary addresses | | **Maintain neutrality** | Instance Owners must remain impartial regarding price feed brands | ## How It Works Market curators do not interact with the PFS directly at runtime. Instead, they select assets and feeds from the PFS when composing a market configuration transaction. Once that transaction executes, the market's oracle references are set independently of the PFS. ```mermaid flowchart LR IO[Instance Owner] -->|"approves feeds"| PFS[PriceFeed Store] PFS -->|"curators select from"| TX[Configuration Transaction] TX -->|"sets oracles in"| Market[Market] ``` ### Key Properties - **Snapshot, not live link** — after a market configurator transaction executes, the market no longer relies on the PFS. Removing an asset or feed from the PFS will not affect any existing market. - **Instance Owner controlled** — only the Instance Owner multisig can add, update, or remove entries. The DAO cannot modify PFS contents directly. - **Approval, not endorsement** — Instance Owners approve feeds as valid (not malicious), but are not responsible for the correctness of the underlying price data. ## Management | Action | Who Can Perform It | | --- | --- | | Add a token/feed mapping | Instance Owner | | Update an existing mapping | Instance Owner | | Remove a mapping | Instance Owner | | Use an approved feed in a market | Market Curator | ## Fixed Address The PFS has a deterministic, fixed address on every chain where Gearbox is deployed. The current registry of instances and their addresses is available at: [https://permissionless.gearbox.foundation/instances](https://permissionless.gearbox.foundation/instances) ## Learn More - [Roles & Permissions](https://docs.gearbox.finance/developers/gp-roles) — Full breakdown of Instance Owner authority and other governance roles - [Omni-EVM & Instances](https://docs.gearbox.finance/developers/gp-instances) — How per-chain instances operate independently - [Treasury & Insurance](https://docs.gearbox.finance/developers/gp-treasury) — Fee collection and distribution mechanics ## Building on Permissionless Source: https://docs.gearbox.finance/developers/gp-building File: content/developers/gp-building.mdx Gearbox's permissionless architecture is designed for extensibility. You can build new components that plug into the system without requiring governance approval for the integration itself. ## What You Can Build | Extension Type | Description | Guide | | --- | --- | --- | | **Adapter** | Add support for a new DeFi protocol (DEX, vault, staking) so Credit Accounts can interact with it | [Adapter Development](https://docs.gearbox.finance/developers/gp-adapters) | | **Protocol Integration** | Compose with Credit Accounts from your own smart contracts — build strategies, keepers, or automated managers | [Protocol Integration](https://docs.gearbox.finance/developers/gp-integration) | | **Core Extension** | Extend the protocol itself — custom interest rate models, pool hooks, Credit Manager spokes | [Core Extension](https://docs.gearbox.finance/developers/gp-extension) | ## How It Fits Together ```mermaid flowchart LR subgraph "Your Code" Adapter[New Adapter] Integration[Protocol Integration] Extension[Core Extension] end subgraph "Gearbox Protocol" CM[Credit Manager] Pool[Pool] Facade[Credit Facade] end subgraph "External DeFi" DEX[New DEX] Vault[New Vault] end Adapter -->|"wraps"| DEX Adapter -->|"wraps"| Vault CM -->|"calls via"| Adapter Integration -->|"multicall"| Facade Extension -->|"extends"| Pool Extension -->|"extends"| CM ``` ## Approval Flow While building is permissionless, deploying to production uses the BCR verification process: 1. **Build** your adapter/integration/extension 2. **Test** with Foundry or Hardhat against forked mainnet 3. **Submit** for audit 4. **Register** in the [Bytecode Repository](https://docs.gearbox.finance/developers/gp-bcr) with dual signatures 5. **Curators enable** your component in their Credit Suites Steps 1-2 are fully permissionless. Steps 3-5 ensure production safety. ## Treasury & Insurance Source: https://docs.gearbox.finance/developers/gp-treasury File: content/developers/gp-treasury.mdx The Treasury Splitter contract governs how protocol fees are divided between market curators and the Gearbox DAO, while the insurance fund provides a minimal reserve to cover potential losses. ## Treasury Splitter Every market generates fees from borrower interest. These fees are collected and split between two parties: the market curator who manages risk, and the DAO that maintains the protocol. | Property | Detail | | --- | --- | | **Default split** | 50/50 between market curator and DAO | | **Governance model** | Operates as a 2/2 multisig — changes require approval from both the Financial Representative and the market curator | | **Fee collection timing** | Fees are collected when debt is repaid, not continuously | | **Split change timing** | Changes to the treasury split take effect immediately, including for previously accrued but uncollected fees | ```mermaid flowchart LR Borrower[Borrower Repays] -->|"fees collected"| Splitter[Treasury Splitter] Splitter -->|"50%"| Curator[Market Curator] Splitter -->|"50%"| DAO[DAO Treasury] FR[Financial Representative] -->|"manages split"| Splitter ``` ### Delayed Fee Collection Fees are not streamed or collected in real time. They accumulate within the protocol and are only realized when a borrower repays their debt. This means: - The split ratio at the time of collection determines distribution, not the ratio at the time fees were accrued - Changing the split retroactively affects all uncollected fees - Both parties should be aware of this when negotiating split changes ## Financial Representative Each chain has a Financial Representative appointed by the DAO to manage fee-related operations on that specific chain. | Aspect | Detail | | --- | --- | | **Scope** | One chain | | **Appointment** | Set during instance activation | | **Replacement** | Changed via DAO vote | | **User impact** | Cannot affect end users directly | ### Financial Representative Authority | Action | Function | Description | | --- | --- | --- | | Set default split | `setDefaultSplit()` | Change the default fee division ratio | | Set token-specific split | `setTokenSplit()` | Override the split for a specific token | | Set insurance amount | `setTokenInsuranceAmount()` | Configure the undistributable reserve per token | | Withdraw tokens | `withdrawToken()` | Withdraw collected fees from the splitter | All of these actions require approval from **both** the Financial Representative and the relevant market curator (2/2 multisig). ## Insurance Fund The Treasury Splitter holds a minimal undistributable amount as an insurance reserve. This fund exists to cover potential losses and cannot be withdrawn through normal fee collection. | Property | Detail | | --- | --- | | **Purpose** | Cover protocol losses | | **Configuration** | Set per token via `setTokenInsuranceAmount()` | | **Accessibility** | Cannot be withdrawn through standard fee collection | | **Management** | Requires 2/2 approval (Financial Representative + market curator) to modify | ## Learn More - [Roles & Permissions](https://docs.gearbox.finance/developers/gp-roles) — Full breakdown of Financial Representative and other governance roles - [PriceFeed Store](https://docs.gearbox.finance/developers/gp-pricefeed-store) — How price feeds are approved and managed - [Omni-EVM & Instances](https://docs.gearbox.finance/developers/gp-instances) — How per-chain instances operate independently ## Adapter Development Source: https://docs.gearbox.finance/developers/gp-adapters File: content/developers/gp-adapters.mdx Build adapters to integrate new DeFi protocols with Gearbox Credit Accounts. ## When to Build an Adapter Build an adapter when you want to enable Credit Accounts to interact with a new DeFi protocol. Consider these options: | Approach | When to Use | | ------------------------ | ----------------------------------------------------------------------------------------------------------------- | | **Build an Adapter** | The protocol is mature, has significant TVL, and you want it available across all Gearbox Credit Managers | | **Protocol Integration** | You're building a protocol that wants to accept Credit Accounts as users (e.g., a DEX accepting leveraged trades) | | **Direct Contract** | Your use case doesn't need leverage or margin trading features | Adapters make sense for: * DEX protocols (Uniswap, Curve, Balancer) * Yield vaults (Yearn, ERC-4626 vaults) * Liquid staking protocols (Lido, Rocket Pool) * Lending protocols (Aave, Compound) Do not build adapters for: * Protocols with admin keys that can rug users * Protocols without audits or battle-testing * Highly experimental or unproven contracts ## Architecture Overview Adapters sit between Credit Accounts and external protocols: ``` User -> CreditFacade -> CreditAccount -> Adapter -> Target Protocol | | | +-> Security enforcement | +-> Token state updates | +-> Approval management | +-> Receives output tokens ``` The adapter's job is to: 1. Accept calls from the CreditFacade (not users directly) 2. Translate the call to the target protocol's interface 3. Override recipient addresses to always be the Credit Account 4. Manage token approvals safely 5. Update token states (enable outputs, optionally disable inputs) For architectural background, see [Multicall System](https://docs.gearbox.finance/developers/multicall-system). ## Building Your First Adapter ### Step 1: Inherit AbstractAdapter All adapters extend `AbstractAdapter`: ```solidity import {AbstractAdapter} from "@gearbox-protocol/core-v3/contracts/adapters/AbstractAdapter.sol"; contract MyVaultAdapter is AbstractAdapter { constructor( address _creditManager, address _targetContract ) AbstractAdapter(_creditManager, _targetContract) {} } ``` **Example:** ```solidity // Adapter for an ERC-4626 vault contract ERC4626Adapter is AbstractAdapter { constructor(address _creditManager, address _vault) AbstractAdapter(_creditManager, _vault) {} } ``` ### Step 2: Implement Core Functions Add wrapper functions that call the target protocol: ```solidity function deposit(uint256 assets) external creditFacadeOnly returns (uint256 shares) { address creditAccount = _creditAccount(); // Get token addresses address asset = IERC4626(targetContract).asset(); address vault = targetContract; // Build the call bytes memory callData = abi.encodeCall( IERC4626.deposit, (assets, creditAccount) // Override recipient to creditAccount ); // Execute with safe approval pattern shares = abi.decode( _executeSwapSafeApprove(asset, vault, callData, false), (uint256) ); } ``` **Example:** ```solidity // Withdraw function - burn shares, receive assets function redeem(uint256 shares) external creditFacadeOnly returns (uint256 assets) { address creditAccount = _creditAccount(); address vault = targetContract; address asset = IERC4626(vault).asset(); bytes memory callData = abi.encodeCall( IERC4626.redeem, (shares, creditAccount, creditAccount) ); assets = abi.decode( _executeSwapSafeApprove(vault, asset, callData, false), (uint256) ); } ``` ### Step 3: Implement Diff Functions Diff functions calculate the input amount from the current balance: ```solidity // Standard: requires exact amount function deposit(uint256 assets) external creditFacadeOnly returns (uint256); // Diff: calculates amount as (balance - leftoverAmount) function depositDiff(uint256 leftoverAmount) external creditFacadeOnly returns (uint256); ``` **Example:** ```solidity function depositDiff(uint256 leftoverAmount) external creditFacadeOnly returns (uint256 shares) { address creditAccount = _creditAccount(); address asset = IERC4626(targetContract).asset(); // Calculate actual deposit amount uint256 balance = IERC20(asset).balanceOf(creditAccount); uint256 amount = balance - leftoverAmount; // Call the standard deposit function return deposit(amount); } ``` **Why diff functions exist:** When chaining operations, you often don't know exact amounts: * After a swap, you don't know exact output until execution * After partial withdrawals, remaining balance is variable * Diff functions say "use everything except X" instead of "use exactly Y" ### Step 4: Add Security Modifiers Every external function must use `creditFacadeOnly`: ```solidity // WRONG - allows anyone to call function deposit(uint256 amount) external returns (uint256) { ... } // CORRECT - only CreditFacade can call function deposit(uint256 amount) external creditFacadeOnly returns (uint256) { ... } ``` **Example:** ```solidity // All user-facing functions need the modifier function deposit(uint256 assets) external creditFacadeOnly returns (uint256 shares) { ... } function depositDiff(uint256 leftover) external creditFacadeOnly returns (uint256 shares) { ... } function redeem(uint256 shares) external creditFacadeOnly returns (uint256 assets) { ... } function redeemDiff(uint256 leftover) external creditFacadeOnly returns (uint256 assets) { ... } ``` ## Complete Example: ERC-4626 Vault Adapter Here's a complete adapter for an ERC-4626 vault with all essential patterns: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import {AbstractAdapter} from "@gearbox-protocol/core-v3/contracts/adapters/AbstractAdapter.sol"; import {AdapterType} from "@gearbox-protocol/core-v3/contracts/interfaces/IAdapter.sol"; import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; contract ERC4626Adapter is AbstractAdapter { AdapterType public constant override _gearboxAdapterType = AdapterType.VAULT; constructor(address _creditManager, address _vault) AbstractAdapter(_creditManager, _vault) {} // Deposit assets, receive shares function deposit(uint256 assets) external creditFacadeOnly returns (uint256 shares) { address creditAccount = _creditAccount(); address asset = IERC4626(targetContract).asset(); bytes memory callData = abi.encodeCall( IERC4626.deposit, (assets, creditAccount) ); shares = abi.decode( _executeSwapSafeApprove(asset, targetContract, callData, false), (uint256) ); } // Deposit all assets except leftoverAmount function depositDiff(uint256 leftoverAmount) external creditFacadeOnly returns (uint256 shares) { address creditAccount = _creditAccount(); address asset = IERC4626(targetContract).asset(); uint256 balance = IERC20(asset).balanceOf(creditAccount); return deposit(balance - leftoverAmount); } // Redeem shares, receive assets function redeem(uint256 shares) external creditFacadeOnly returns (uint256 assets) { address creditAccount = _creditAccount(); address asset = IERC4626(targetContract).asset(); bytes memory callData = abi.encodeCall( IERC4626.redeem, (shares, creditAccount, creditAccount) ); assets = abi.decode( _executeSwapSafeApprove(targetContract, asset, callData, false), (uint256) ); } // Redeem all shares except leftoverAmount function redeemDiff(uint256 leftoverAmount) external creditFacadeOnly returns (uint256 assets) { address creditAccount = _creditAccount(); uint256 balance = IERC20(targetContract).balanceOf(creditAccount); return redeem(balance - leftoverAmount); } } ``` ## Security Patterns Deep Dive ### Why creditFacadeOnly Matters Without this modifier, an attacker could call adapter functions directly: **Attack scenario without creditFacadeOnly:** 1. Attacker calls `adapter.deposit(1000)` directly 2. Adapter tries to pull tokens from "current" Credit Account 3. Without CreditFacade context, `_creditAccount()` returns address(0) or wrong account 4. Tokens could be pulled from wrong account or transaction reverts unpredictably **With creditFacadeOnly:** 1. Only CreditFacade can call the adapter 2. CreditFacade sets the active Credit Account before calling 3. Adapter correctly identifies which account to operate on 4. No unauthorized access possible ```solidity // The modifier checks that msg.sender is the CreditFacade modifier creditFacadeOnly() { if (msg.sender != creditFacade) revert CallerNotCreditFacadeException(); _; } ``` ### Recipient Override Pattern Always hardcode the recipient as the Credit Account. Never accept user-specified recipients. **Attack scenario without recipient override:** ```solidity // DANGEROUS - user controls recipient function withdraw(uint256 shares, address recipient) external creditFacadeOnly { IVault(targetContract).redeem(shares, recipient, _creditAccount()); } // Attacker multicall: // 1. Deposit 100 ETH to vault // 2. Call withdraw(shares, attackerAddress) // 3. Funds sent to attacker instead of Credit Account // 4. Credit Account has no collateral, but debt remains ``` **Safe pattern:** ```solidity // CORRECT - recipient is always the Credit Account function withdraw(uint256 shares) external creditFacadeOnly { address creditAccount = _creditAccount(); IVault(targetContract).redeem(shares, creditAccount, creditAccount); } ``` ### Safe Approval Pattern Approvals are reset to 1 (not 0) after each operation. This prevents: * Approval racing attacks * Gas waste from 0 -> N transitions * Front-running of approval transactions ```solidity // _executeSwapSafeApprove does this internally: // 1. Approve tokenIn to target contract // 2. Execute the call // 3. Set approval to 1 (not 0) // 4. Enable tokenOut // 5. Optionally disable tokenIn if balance is 1 wei _executeSwapSafeApprove( tokenIn, // Token being spent tokenOut, // Token being received callData, // The encoded call false // Don't disable tokenIn if non-zero balance remains ); ``` **Why reset to 1 instead of 0:** * ERC-20 standard: 0 -> N costs more gas than 1 -> N * Prevents approval race conditions * Future operations don't need expensive zero-to-nonzero transition ### Token State Management Adapters automatically update which tokens are "enabled" on the Credit Account: ```solidity // After a swap USDC -> WETH: // - WETH mask is enabled (counts toward collateral) // - USDC mask disabled if balance = 1 wei and disableTokenIn = true // If disableTokenIn = false: // - USDC remains enabled even with low balance // - Useful for partial swaps or when you'll receive more USDC later ``` ## Testing with Foundry Test adapters using Foundry fork tests: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import {Test} from "forge-std/Test.sol"; import {ERC4626Adapter} from "../adapters/ERC4626Adapter.sol"; import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; contract ERC4626AdapterTest is Test { ERC4626Adapter adapter; address creditManager = 0x...; // Existing CM on mainnet address vault = 0x...; // Target vault function setUp() public { // Fork mainnet vm.createSelectFork(vm.envString("ETH_RPC_URL")); // Deploy adapter adapter = new ERC4626Adapter(creditManager, vault); } function test_deposit() public { // Setup: get a credit account with assets address creditAccount = _openCreditAccount(); // Execute deposit via CreditFacade uint256 assets = 100e18; uint256 shares = adapter.deposit(assets); // Assertions assertGt(shares, 0, "Should receive shares"); assertEq(IERC20(vault).balanceOf(creditAccount), shares); } function test_depositDiff() public { address creditAccount = _openCreditAccount(); uint256 initialBalance = 100e18; uint256 leftover = 1; uint256 shares = adapter.depositDiff(leftover); assertEq(shares, adapter.previewDeposit(initialBalance - leftover)); } function test_cannotCallDirectly() public { vm.expectRevert(); // CallerNotCreditFacadeException adapter.deposit(100e18); } } ``` **Key test patterns:** 1. **Fork testing** - Test against real protocols on mainnet/testnet 2. **Access control** - Verify creditFacadeOnly works 3. **Balance checks** - Assert correct token transfers 4. **Diff functions** - Verify correct amount calculation 5. **Edge cases** - Test with zero amounts, max values, etc. ## Deployment and Whitelisting After writing and testing your adapter: 1. **Deploy the adapter** - Deploy to mainnet with CreditManager and target addresses 2. **Submit governance proposal** - Request adapter whitelisting via Gearbox governance 3. **Governance vote** - DAO votes on adding adapter to Credit Manager(s) 4. **Adapter registration** - If approved, adapter is added to allowedAdapters mapping **Governance process:** * Submit proposal on Gearbox governance forum * Include audit report (required for new adapters) * Specify which Credit Manager(s) should whitelist it * DAO votes on proposal * If passed, adapter becomes available for Credit Accounts **Note:** Each Credit Manager has its own adapter whitelist. An adapter approved for one Credit Manager isn't automatically available on others. For architectural background, see [Multicall System](https://docs.gearbox.finance/developers/multicall-system). ## Best Practices 1. **Keep it simple** - Adapters should be thin wrappers, not business logic 2. **No state** - Adapters should be stateless (except immutables) 3. **Comprehensive diff** - Implement diff functions for all variable-amount operations 4. **Always override recipients** - Never let users specify where funds go 5. **Test thoroughly** - Test both success and failure paths 6. **Document clearly** - Write NatSpec comments explaining each function 7. **Declare adapter type** - Set `_gearboxAdapterType` for proper categorization ## Key Inherited Functions AbstractAdapter provides these helper functions: | Function | Description | | ------------------------------ | --------------------------------------- | | `_creditAccount()` | Returns current Credit Account address | | `_creditManager()` | Returns Credit Manager address | | `_creditFacade()` | Returns Credit Facade address | | `_getMaskOrRevert(token)` | Gets token mask, reverts if not allowed | | `_execute(callData)` | Executes call on target contract | | `_executeSwapSafeApprove(...)` | Executes call with approval management | | `targetContract` | Immutable address of wrapped protocol | ## Related * [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls) - Using adapters in multicalls * [Multicall System](https://docs.gearbox.finance/developers/multicall-system) - Architectural overview ## Roles & Permissions Source: https://docs.gearbox.finance/developers/gp-roles File: content/developers/gp-roles.mdx Gearbox governance is divided into distinct roles with carefully scoped authority. No single role can unilaterally modify a live market — this separation of concerns is the foundation of the permissionless design. ## Role Summary | Role | Scope | Can Affect End Users? | Primary Responsibility | | --- | --- | --- | --- | | **DAO** | All chains | No | Protocol-level governance, code approval | | **Technical Multisig** | All chains | No | Execute DAO decisions (temporary) | | **Auditors** | All chains | No | Verify and sign contract bytecode | | **Instance Owners** | One chain | No | Chain-specific infrastructure and PFS | | **Financial Representatives** | One chain | No | Fee management per chain | | **Market Curators** | Specific markets | Yes (with timelock) | Create and manage markets | | **Emergency Admin** | Specific markets | Yes (immediate) | Emergency response | | **Pausable/Unpausable Admins** | Specific markets | Yes | Pause/unpause market components | | **Emergency Liquidators** | Specific markets | Yes | Special liquidation during emergencies | ## DAO (Token Holders) The DAO represents GEAR token holders and governs protocol-level decisions across all chains. Critically, none of the DAO's actions can modify existing markets. | Aspect | Detail | | --- | --- | | **Scope** | All chains | | **Voting power** | Proportional to token holdings | | **Current process** | Snapshot voting, then technical multisig executes | | **Future process** | On-chain voting directly on transaction batches | ### DAO Authority | Area | Actions | | --- | --- | | **CCM Management** | Manage the Cross-Chain Multisig configuration | | **BCR Management** | Add auditors, allow system contracts in the Bytecode Repository | | **Instance Management** | Activate instances, set global addresses | ### Key Constraint None of the DAO's actions can modify existing markets. The DAO governs the protocol infrastructure, not individual market parameters. ## Technical Multisig A temporary measure that exists solely to execute DAO decisions. The Technical Multisig has no autonomous decision-making authority. | Aspect | Detail | | --- | --- | | **Scope** | All chains | | **Autonomy** | None — executes DAO decisions only | | **Implementation** | Legacy Safe multisig + Cross-Chain Multisig contract | | **Interaction** | Strictly forced to interact with CCM on Ethereum Mainnet only | This role is designed to be eliminated once on-chain voting is fully implemented. ## Auditors External parties who audit smart contracts and sign verified bytecode. They are the gatekeepers for what code can be deployed. | Aspect | Detail | | --- | --- | | **Scope** | All chains | | **Interaction point** | BCR on Ethereum Mainnet exclusively | | **Management** | Added and removed by DAO | ### Auditor Authority | Action | Function | Description | | --- | --- | --- | | Submit audit report | `submitAuditReport()` | Add an audit report to the BCR | | Assign contract type | via `submitAuditReport()` | Assigns contractType ownership to the verified bytecode | ## Instance Owners Instance Owners manage chain-specific infrastructure through a soft power mechanism. Their authority is limited to preparing the environment — they cannot force changes onto existing markets. | Aspect | Detail | | --- | --- | | **Scope** | One chain | | **Current composition** | 3 core Gearbox members + 9 tech multisig members, threshold 4 | | **Neutrality requirement** | Must remain impartial regarding price feed brands | ### Instance Owner Authority | Area | Actions | | --- | --- | | **PriceFeed Store** | Add, update, and remove token/feed mappings | | **Local addresses** | Manage chain-specific address configuration | | **Bot management** | Forbid specific bots | | **Infrastructure** | Manage router and internal systems | ### Key Constraint None of their actions can modify existing market behavior. PFS changes are not auto-applied to existing markets — they only affect future configuration transactions. ## Financial Representatives Each chain has a Financial Representative who manages fee-related operations. This role requires cooperation with market curators through a 2/2 approval mechanism. | Aspect | Detail | | --- | --- | | **Scope** | One chain | | **Appointment** | Set during instance activation | | **Replacement** | Changed via DAO vote | ### Financial Representative Authority | Action | Function | Requires 2/2 Approval | | --- | --- | --- | | Set default fee split | `setDefaultSplit()` | Yes | | Set token-specific split | `setTokenSplit()` | Yes | | Set insurance amount | `setTokenInsuranceAmount()` | Yes | | Withdraw collected fees | `withdrawToken()` | Yes | ## Market Curators Market curators are the most powerful market-level role. Anyone can become a curator — the DAO cannot deny participation. The DAO has no responsibility for or control over curated markets. | Aspect | Detail | | --- | --- | | **Scope** | Specific markets | | **Entry barrier** | None — anyone can become a curator | | **Primary gateway** | MarketConfigurator contract (supports Ownable2Step) | | **Default timelock** | 24 hours (hardcoded minimum) | ### Governance Flow ```mermaid flowchart LR Gov[Governor] -->|"submits batch"| TL[Timelock - 24h min] TL -->|"executes after delay"| MC[Market Configurator] MC -->|"applies changes"| Market[Market] ``` ### Market Curator Authority — Configurator Level | Action | Description | | --- | --- | | Set emergency admin | Assign or change the emergency admin for the market | | Grant/revoke roles | Manage role assignments within the market | | Create markets | Deploy new markets | | Shutdown markets | Permanently close markets | | Add periphery contracts | Register additional contracts for the market | ### Market Curator Authority — Market Management | Action | Description | | --- | --- | | Add collateral tokens | Extend accepted collateral types | | Create/shutdown credit suites | Manage credit account configurations | | Upgrade oracles | Change price oracle implementations | | Upgrade IRM | Change interest rate model | | Upgrade rate keeper | Change rate keeper implementation | | Upgrade loss policy | Change loss handling policy | | Set fees | Configure fee parameters | | Set limits | Configure borrowing and position limits | | Ramp LTs | Gradually adjust liquidation thresholds | | Forbid/allow tokens | Restrict or permit specific tokens | | Pause/unpause | Halt or resume market operations | ## Emergency Admin The Emergency Admin can act immediately without timelock delays. This role exists for rapid response to security threats or market anomalies. | Aspect | Detail | | --- | --- | | **Scope** | Specific markets | | **Timelock** | None — effects are immediate | | **Appointment** | Set by market owner, can be changed anytime | ### Emergency Admin Authority | Area | Actions | | --- | --- | | **Timelock management** | Cancel pending batches in the timelock | | **Role management** | Revoke roles | | **Oracle management** | Configure PriceOracle | | **Pool emergency** | Set credit manager debt limit to zero, set quota to zero, pause pool | | **Credit suite emergency** | Emergency credit suite management | ## Pausable/Unpausable Admins Specialized roles that can pause or unpause specific market components. These provide granular control over market operations during incidents. | Aspect | Detail | | --- | --- | | **Scope** | Specific markets | | **Authority** | Pause or unpause individual market components | | **User impact** | Can affect end users | ## Emergency Liquidators Accounts with special liquidation rights that are only active during emergency conditions. | Aspect | Detail | | --- | --- | | **Scope** | Specific markets | | **Activation** | Only during emergencies | | **Authority** | Special liquidation permissions beyond normal liquidator access | ## Learn More - [PriceFeed Store](https://docs.gearbox.finance/developers/gp-pricefeed-store) — How price feeds are approved and managed - [Treasury & Insurance](https://docs.gearbox.finance/developers/gp-treasury) — Fee collection and distribution mechanics - [Guardrails & Role Separation](https://docs.gearbox.finance/developers/gp-guardrails) — The three-layer governance model - [Cross-Chain Multisig (CCM)](https://docs.gearbox.finance/developers/gp-ccm) — How governance synchronizes across chains - [Bytecode Repository (BCR)](https://docs.gearbox.finance/developers/gp-bcr) — How code is verified before deployment ## Protocol Integration Source: https://docs.gearbox.finance/developers/gp-integration File: content/developers/gp-integration.mdx Build smart contracts that compose with Gearbox Credit Accounts. ## Overview Protocol integration means building contracts that: * Call Gearbox Credit Accounts from external contracts * Create automated strategies using multicalls * Compose Gearbox with your own protocol logic Unlike adapters (which are called BY Credit Accounts), protocol integrations CALL Credit Accounts from outside. ## Architecture ``` Your Contract -> CreditFacade -> Credit Account -> Adapters -> DeFi Protocols | +-> Multicall execution +-> Collateral checks +-> Access control ``` ## Basic Integration Pattern ### 1. Find the Right Market ```solidity import {IAddressProviderV3} from "@gearbox-protocol/core-v3/contracts/interfaces/IAddressProviderV3.sol"; import {IContractsRegister} from "@gearbox-protocol/core-v3/contracts/interfaces/IContractsRegister.sol"; import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; contract MyStrategy { IAddressProviderV3 public constant ADDRESS_PROVIDER = IAddressProviderV3(0x9ea7b04Da02a5373317D745c1571c84aaD03321D); ICreditFacadeV3 public creditFacade; address public creditManager; function initialize(address _creditManager) external { creditManager = _creditManager; // Get CreditFacade from CreditManager creditFacade = ICreditFacadeV3( ICreditManagerV3(_creditManager).creditFacade() ); } } ``` ### 2. Build and Execute Multicalls ```solidity import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; function depositToStrategy( address creditAccount, address token, uint256 amount ) external { MultiCall[] memory calls = new MultiCall[](1); calls[0] = MultiCall({ target: address(creditFacade), callData: abi.encodeCall( ICreditFacadeV3Multicall.addCollateral, (token, amount) ) }); // Caller must approve creditManager first creditFacade.multicall(creditAccount, calls); } ``` ## Common Integration Patterns ### Automated Strategy Contract A contract that executes predefined strategies: ```solidity // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.17; import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {IUniswapV3Adapter} from "@gearbox-protocol/integrations-v3/contracts/interfaces/uniswap/IUniswapV3Adapter.sol"; import {ISwapRouter} from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; contract LeveragedYieldStrategy { ICreditFacadeV3 public immutable creditFacade; ICreditManagerV3 public immutable creditManager; address public immutable underlying; address public immutable targetAsset; address public immutable uniswapAdapter; address public immutable yieldAdapter; constructor( address _creditManager, address _targetAsset, address _yieldVault ) { creditManager = ICreditManagerV3(_creditManager); creditFacade = ICreditFacadeV3(creditManager.creditFacade()); underlying = creditManager.underlying(); targetAsset = _targetAsset; // Find adapters uniswapAdapter = creditManager.contractToAdapter( 0xE592427A0AEce92De3Edee1F18E0157C05861564 // Uniswap V3 Router ); yieldAdapter = creditManager.contractToAdapter(_yieldVault); require(uniswapAdapter != address(0), "Uniswap adapter not found"); require(yieldAdapter != address(0), "Yield adapter not found"); } /// @notice Open leveraged yield position /// @param collateralAmount Initial collateral /// @param leverage Leverage multiplier (e.g., 4 for 4x) /// @param minYieldTokens Minimum yield tokens to receive function openPosition( uint256 collateralAmount, uint256 leverage, uint256 minYieldTokens ) external returns (address creditAccount) { require(leverage >= 1 && leverage <= 10, "Invalid leverage"); uint256 borrowAmount = collateralAmount * (leverage - 1); MultiCall[] memory calls = new MultiCall[](4); // 1. Add collateral calls[0] = MultiCall({ target: address(creditFacade), callData: abi.encodeCall( ICreditFacadeV3Multicall.addCollateral, (underlying, collateralAmount) ) }); // 2. Borrow calls[1] = MultiCall({ target: address(creditFacade), callData: abi.encodeCall( ICreditFacadeV3Multicall.increaseDebt, (borrowAmount) ) }); // 3. Swap to target asset uint256 totalAmount = collateralAmount + borrowAmount; ISwapRouter.ExactInputSingleParams memory swapParams = ISwapRouter.ExactInputSingleParams({ tokenIn: underlying, tokenOut: targetAsset, fee: 500, recipient: address(0), deadline: block.timestamp + 3600, amountIn: totalAmount, amountOutMinimum: 0, // Using yield token check instead sqrtPriceLimitX96: 0 }); calls[2] = MultiCall({ target: uniswapAdapter, callData: abi.encodeCall( IUniswapV3Adapter.exactInputSingle, (swapParams) ) }); // 4. Deposit to yield vault using diff pattern calls[3] = MultiCall({ target: yieldAdapter, callData: abi.encodeCall( IYearnV2Adapter.depositDiff, (1) // Leave 1 wei ) }); // Approve and open IERC20(underlying).transferFrom(msg.sender, address(this), collateralAmount); IERC20(underlying).approve(address(creditManager), collateralAmount); creditAccount = creditFacade.openCreditAccount(msg.sender, calls, 0); } } ``` ### Strategy with Price Updates When using Pyth or Redstone oracles, your contract must accept and forward price data: ```solidity /// @notice Execute strategy with price updates /// @param creditAccount Target Credit Account /// @param priceUpdates Array of (token, reserve, data) for on-demand oracles /// @param strategyParams Your strategy-specific parameters function executeWithPriceUpdates( address creditAccount, bytes[] calldata priceUpdates, StrategyParams calldata strategyParams ) external { uint256 numUpdates = priceUpdates.length; // Build calls with price updates first MultiCall[] memory calls = new MultiCall[](numUpdates + strategyParams.numCalls); // Add all price updates at the beginning for (uint256 i = 0; i < numUpdates; i++) { (address token, bool reserve, bytes memory data) = abi.decode(priceUpdates[i], (address, bool, bytes)); calls[i] = MultiCall({ target: address(creditFacade), callData: abi.encodeCall( ICreditFacadeV3Multicall.onDemandPriceUpdate, (token, reserve, data) ) }); } // Add strategy calls after price updates _buildStrategyCalls(calls, numUpdates, strategyParams); creditFacade.multicall(creditAccount, calls); } ``` ### Keeper/Bot Integration For automated position management: ```solidity contract PositionKeeper { ICreditFacadeV3 public immutable creditFacade; address public keeper; mapping(address => bool) public managedAccounts; modifier onlyKeeper() { require(msg.sender == keeper, "Not keeper"); _; } /// @notice Rebalance position when health factor is low function rebalance( address creditAccount, address tokenToSell, uint256 sellAmount, uint256 minRepay ) external onlyKeeper { require(managedAccounts[creditAccount], "Not managed"); MultiCall[] memory calls = new MultiCall[](2); // 1. Swap collateral for underlying calls[0] = MultiCall({ target: uniswapAdapter, callData: abi.encodeCall( IUniswapV3Adapter.exactInputSingle, (swapParams) ) }); // 2. Repay debt using diff pattern calls[1] = MultiCall({ target: address(creditFacade), callData: abi.encodeCall( ICreditFacadeV3Multicall.decreaseDebt, (minRepay) ) }); // Execute as bot (requires bot permissions on account) creditFacade.botMulticall(creditAccount, calls); } } ``` ## Access Control Considerations ### Account Ownership Only the account owner (or approved bots) can execute multicalls: ```solidity // This will revert if msg.sender is not account owner creditFacade.multicall(creditAccount, calls); // For keeper/bot access, the owner must grant permissions first // This is done via setBotPermissions in a multicall ``` ### Bot Permissions To allow external contracts to manage accounts: ```solidity // Owner grants bot permissions MultiCall[] memory calls = new MultiCall[](1); calls[0] = MultiCall({ target: address(creditFacade), callData: abi.encodeCall( ICreditFacadeV3Multicall.setBotPermissions, ( botAddress, uint192(1 << 0 | 1 << 1) // Permission flags for allowed operations ) ) }); creditFacade.multicall(creditAccount, calls); ``` Then the bot can use `botMulticall`: ```solidity // Bot executes with limited permissions creditFacade.botMulticall(creditAccount, calls); ``` ## Error Handling ### Reading Account State Before Operations ```solidity function getAccountHealth(address creditAccount) external view returns (uint256) { ( uint256 debt, uint256 cumulativeIndexLastUpdate, uint128 cumulativeQuotaInterest, uint128 quotaFees, uint256 enabledTokensMask, uint16 flags, uint64 lastDebtUpdate, address borrower ) = creditManager.creditAccountInfo(creditAccount); // Calculate health factor using collateral values // ... } ``` ### Handling Reverts ```solidity function safeExecute( address creditAccount, MultiCall[] memory calls ) external returns (bool success) { try creditFacade.multicall(creditAccount, calls) { success = true; } catch Error(string memory reason) { emit ExecutionFailed(creditAccount, reason); success = false; } } ``` ## Gas Optimization ### Use Collateral Hints For accounts with many tokens, provide hints to reduce oracle calls: ```solidity // Get token masks for primary collateral uint256 usdcMask = creditManager.getTokenMaskOrRevert(usdc); uint256 wethMask = creditManager.getTokenMaskOrRevert(weth); uint256[] memory hints = new uint256[](2); hints[0] = usdcMask; hints[1] = wethMask; // Add setFullCheckParams as first non-price-update call calls[0] = MultiCall({ target: address(creditFacade), callData: abi.encodeCall( ICreditFacadeV3Multicall.setFullCheckParams, (hints, 10000) // 1.0 min health factor ) }); ``` ### Batch Operations Combine related operations in single multicalls rather than multiple transactions: ```solidity // GOOD - single multicall MultiCall[] memory calls = new MultiCall[](4); calls[0] = addCollateralCall; calls[1] = borrowCall; calls[2] = swapCall; calls[3] = depositCall; creditFacade.multicall(account, calls); // BAD - multiple transactions (more gas, atomicity issues) creditFacade.multicall(account, [addCollateralCall]); creditFacade.multicall(account, [borrowCall]); creditFacade.multicall(account, [swapCall]); ``` ## Testing ### Foundry Setup ```solidity import {Test} from "forge-std/Test.sol"; contract StrategyTest is Test { LeveragedYieldStrategy strategy; address user = address(0x1); function setUp() public { // Fork mainnet vm.createSelectFork("mainnet"); // Deploy strategy strategy = new LeveragedYieldStrategy( CREDIT_MANAGER, TARGET_ASSET, YIELD_VAULT ); } function test_openPosition() public { // Setup deal(USDC, user, 10_000e6); vm.startPrank(user); IERC20(USDC).approve(address(strategy), 10_000e6); // Execute address account = strategy.openPosition(10_000e6, 4, 0); // Verify assertTrue(account != address(0)); assertGt(IERC20(YIELD_TOKEN).balanceOf(account), 0); vm.stopPrank(); } } ``` ## Security Considerations 1. **Reentrancy** - Multicalls are atomic, but be careful with callbacks 2. **Slippage** - Always use `storeExpectedBalances`/`compareBalances` for swaps 3. **Access control** - Verify account ownership before operations 4. **Oracle manipulation** - Use safe pricing for withdrawals 5. **Flash loan attacks** - Consider same-block restrictions on debt changes ## Related * [Multicalls](https://docs.gearbox.finance/developers/gm-accounts-multicalls) - Core encoding patterns * [Making External Calls](https://docs.gearbox.finance/developers/making-external-calls) - Using adapters * [Controlling Slippage](https://docs.gearbox.finance/developers/controlling-slippage) - Protecting operations * [Adapter Development](https://docs.gearbox.finance/developers/gp-adapters) - Building adapters ## Core Extension Source: https://docs.gearbox.finance/developers/gp-extension File: content/developers/gp-extension.mdx Advanced patterns for extending Gearbox protocol contracts beyond standard adapter integration. > This is advanced material. For standard integrations, see [Adapter Development](https://docs.gearbox.finance/developers/gp-adapters) or [Protocol Integration](https://docs.gearbox.finance/developers/gp-integration). ## When to Extend vs Integrate Different levels of integration require different approaches: | Approach | Complexity | When to Use | | ------------------------ | ---------- | -------------------------------------------------------------------- | | **Adapter** | Low | Wrap existing DeFi protocols for Credit Account access | | **Protocol Integration** | Medium | Build contracts that compose with Credit Accounts externally | | **Core Extension** | High | Modify Credit Manager/Pool behavior, create protocol-specific spokes | Examples by approach: **Adapter:** Wrapping Uniswap, Curve, Yearn for Credit Account users **Protocol Integration:** Strategy vaults that open/manage Credit Accounts **Core Extension:** Custom Credit Manager for protocol-specific accounting, custom interest rate models, pool hooks for fee distribution Build a core extension when you need to: * Modify how debt/collateral calculations work * Change liquidity flow patterns between pools and Credit Managers * Implement protocol-specific Credit Manager variants ("spokes") * Create custom interest rate logic beyond linear models * Add lifecycle hooks to pool operations ## Understanding Money Flows Core extensions require deep understanding of how liquidity moves through the protocol. ### The Fundamental Flow ``` Lenders → Pool → Credit Manager → Credit Account → DeFi Protocols (ERC-4626) | | | +-> Holds collateral +-> Tracks debt ``` **Key invariants:** 1. Pool lends only to whitelisted Credit Managers 2. Credit Managers borrow on behalf of Credit Accounts 3. Credit Accounts hold all collateral and debt 4. All value flows are tracked via indexed interest and quota systems ### Detailed Liquidity Flow **When borrowing:** ```solidity // 1. User opens Credit Account via CreditFacade CreditFacade.openCreditAccount(owner, calls, referralCode) | v // 2. Facade instructs Manager to borrow CreditManager.openCreditAccount(debt, onBehalfOf) | v // 3. Manager requests liquidity from Pool Pool.lendCreditAccount(borrowedAmount, creditAccount) | v // 4. Pool transfers underlying directly to Credit Account IERC20(underlying).transfer(creditAccount, borrowedAmount) ``` **When repaying:** ```solidity // 1. User closes account via CreditFacade CreditFacade.closeCreditAccount(creditAccount, calls) | v // 2. Manager calculates total debt totalDebt = principal + accruedInterest + quotaInterest + fees | v // 3. Underlying transfers from Credit Account to Pool IERC20(underlying).transferFrom(creditAccount, pool, totalDebt) | v // 4. Manager reports repayment to Pool Pool.repayCreditAccount(repaidAmount, profit, loss) ``` **Critical detail:** The Credit Manager never holds funds. It orchestrates transfers between Pool and Credit Account while maintaining accounting state. ## Pool Extension Patterns ### Custom Interest Rate Models The pool queries an external IRM contract for interest rates. You can implement custom logic by deploying a new IRM. **IInterestRateModel interface:** ```solidity interface ILinearInterestRateModelV3 { function calcBorrowRate( uint256 expectedLiquidity, uint256 availableLiquidity, bool checkOptimalBorrowing ) external view returns (uint256 borrowRate); function getModelParameters() external view returns ( uint16 U_1, uint16 U_2, uint16 R_base, uint16 R_slope1, uint16 R_slope2, uint16 R_slope3 ); } ``` **Example: Time-weighted interest model** ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import {ILinearInterestRateModelV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ILinearInterestRateModelV3.sol"; contract TimeWeightedIRM is ILinearInterestRateModelV3 { uint16 public immutable U_1 = 7000; // 70% uint16 public immutable U_2 = 9000; // 90% uint16 public immutable R_base = 100; // 1% uint16 public immutable R_slope1 = 200; // 2% uint16 public immutable R_slope2 = 500; // 5% // Time-based slope adjustment uint16 public immutable peakHourMultiplier = 150; // 1.5x during peak hours function calcBorrowRate( uint256 expectedLiquidity, uint256 availableLiquidity, bool checkOptimalBorrowing ) external view returns (uint256 borrowRate) { uint256 utilizationBps = (expectedLiquidity - availableLiquidity) * 10_000 / expectedLiquidity; // Apply time-based multiplier during peak hours (12-18 UTC) uint256 hour = (block.timestamp / 3600) % 24; uint16 multiplier = (hour >= 12 && hour < 18) ? peakHourMultiplier : 100; // Standard linear calculation with time adjustment uint256 baseRate = R_base; if (utilizationBps <= U_1) { borrowRate = baseRate + (R_slope1 * utilizationBps * multiplier) / 10_000 / 100; } else if (utilizationBps <= U_2) { borrowRate = baseRate + (R_slope2 * utilizationBps * multiplier) / 10_000 / 100; } else { borrowRate = baseRate + (R_slope3 * utilizationBps * multiplier) / 10_000 / 100; } // Convert to RAY (27 decimals) borrowRate = borrowRate * 10**27 / 10_000; } function getModelParameters() external view returns ( uint16, uint16, uint16, uint16, uint16, uint16 ) { // Return adjusted slope based on current time uint256 hour = (block.timestamp / 3600) % 24; uint16 adjustedSlope1 = (hour >= 12 && hour < 18) ? R_slope1 * peakHourMultiplier / 100 : R_slope1; return (U_1, U_2, R_base, adjustedSlope1, R_slope2, R_slope3); } } ``` **Deploying custom IRM:** Custom IRMs can be set via governance: ```solidity // Only CONFIGURATOR can update IRM IPoolV3(pool).setInterestRateModel(newIRMAddress); ``` ### Pool Withdrawal Hooks Pools in V3 support withdrawal fees. These are not "hooks" in the callback sense, but configurable parameters: ```solidity // Read current withdrawal fee uint16 withdrawFee = IPoolV3(pool).withdrawFee(); // basis points // Fee is applied during withdraw/redeem uint256 assets = pool.withdraw(amount, receiver, owner); // Actual received = amount - (amount * withdrawFee / 10000) ``` For custom fee distribution logic, you would typically: 1. Deploy a fee collector contract 2. Configure the pool's treasury address to your collector 3. Implement distribution logic in your collector ## Credit Manager Extension Patterns ### Spoke Development Concept A "spoke" is a specialized Credit Manager variant designed for protocol-specific use cases. Unlike standard Credit Managers, spokes extend core functionality for unique accounting or liquidity patterns. **When to build a spoke:** * Your protocol needs custom collateral valuation logic * You're integrating Credit Accounts as a core protocol primitive * You need specialized debt/liquidation mechanics * You want to modify how positions are opened/closed **Example use case:** A derivatives protocol where Credit Accounts are used as margin accounts with custom position tracking. ### Spoke Architecture Pattern ```solidity import {CreditManagerV3} from "@gearbox-protocol/core-v3/contracts/credit/CreditManagerV3.sol"; contract DerivativesSpoke is CreditManagerV3 { // Custom state for protocol-specific tracking mapping(address => PositionData) public positions; struct PositionData { uint256 longExposure; uint256 shortExposure; int256 unrealizedPnL; } constructor( address _pool, address _addressProvider ) CreditManagerV3(_pool, _addressProvider) {} // Override collateral calculation to include unrealized PnL function calcDebtAndCollateral( address creditAccount, CollateralCalcTask task ) public view override returns ( CollateralDebtData memory cdd ) { // Call parent implementation cdd = super.calcDebtAndCollateral(creditAccount, task); // Adjust TWV based on unrealized PnL PositionData memory pos = positions[creditAccount]; if (pos.unrealizedPnL > 0) { // Add unrealized profit to collateral cdd.twvUSD += uint256(pos.unrealizedPnL); } else { // Subtract unrealized loss from collateral cdd.twvUSD -= uint256(-pos.unrealizedPnL); } } // Protocol-specific function to update position state function updatePosition( address creditAccount, uint256 longExposure, uint256 shortExposure, int256 pnl ) external { // Only allow calls from authorized adapters require( adapterToContract[msg.sender] != address(0), "Not authorized adapter" ); positions[creditAccount] = PositionData({ longExposure: longExposure, shortExposure: shortExposure, unrealizedPnL: pnl }); } } ``` ### Custom Collateral Valuation Extend collateral calculations for protocol-specific assets: ```solidity // Override token price resolution function priceOracle() public view override returns (IPriceOracleV3) { return IPriceOracleV3(customOracleAddress); } // Implement custom oracle with protocol-specific pricing contract CustomOracle is IPriceOracleV3 { function convertToUSD( uint256 amount, address token ) external view override returns (uint256) { if (token == protocolSpecificToken) { // Custom valuation logic return amount * getCustomPrice() / 10**tokenDecimals; } return defaultOracle.convertToUSD(amount, token); } } ``` ### Extending Liquidation Logic Custom liquidation premiums based on collateral type: ```solidity contract CustomLiquidationCM is CreditManagerV3 { mapping(address => uint16) public tokenLiquidationPremiums; function liquidateCreditAccount( address creditAccount, address to, MultiCall[] calldata calls ) external override { // Calculate custom premium based on collateral composition uint256 enabledMask = enabledTokensMaskOf(creditAccount); uint16 premium = _calculatePremium(enabledMask); // Set premium temporarily uint16 oldPremium = liquidationPremium; liquidationPremium = premium; // Execute standard liquidation super.liquidateCreditAccount(creditAccount, to, calls); // Restore liquidationPremium = oldPremium; } function _calculatePremium(uint256 mask) internal view returns (uint16) { uint16 maxPremium = 0; for (uint256 i = 0; i < 256; i++) { if (mask & (1 << i) != 0) { address token = getTokenByMask(1 << i); if (tokenLiquidationPremiums[token] > maxPremium) { maxPremium = tokenLiquidationPremiums[token]; } } } return maxPremium; } } ``` ## Working with Configurators The CreditConfigurator provides governance interface for Credit Manager parameters. When building spokes, you typically extend the configurator as well. ### Standard Configurator Usage ```solidity import {ICreditConfiguratorV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditConfiguratorV3.sol"; ICreditConfiguratorV3 configurator = ICreditConfiguratorV3(configuratorAddress); // Add new collateral token configurator.addCollateralToken( tokenAddress, 8500 // liquidationThreshold (85% = 8500 basis points) ); // Add adapter configurator.allowAdapter(adapterAddress); // Set fees configurator.setFees( 500, // feeInterest (5%) 150, // feeLiquidation (1.5%) 500, // liquidationPremium (5%) 100, // feeLiquidationExpired (1%) 500 // liquidationPremiumExpired (5%) ); ``` ### Custom Configurator for Spokes ```solidity import {CreditConfiguratorV3} from "@gearbox-protocol/core-v3/contracts/credit/CreditConfiguratorV3.sol"; contract DerivativesSpokeConfigurator is CreditConfiguratorV3 { DerivativesSpoke public immutable spoke; constructor( address _creditManager, address _creditFacade ) CreditConfiguratorV3(_creditManager, _creditFacade) { spoke = DerivativesSpoke(_creditManager); } // Protocol-specific configuration function setPositionLimits( uint256 maxLongExposure, uint256 maxShortExposure ) external configuratorOnly { spoke.setPositionLimits(maxLongExposure, maxShortExposure); } function setCustomLiquidationPremium( address token, uint16 premium ) external configuratorOnly { spoke.setTokenLiquidationPremium(token, premium); } } ``` ### Governance Integration For production deployments, configurator changes should go through governance: ```solidity // Propose change via governance forum // After approval, execute via timelock // Example: Adding new collateral token bytes memory data = abi.encodeCall( ICreditConfiguratorV3.addCollateralToken, (newTokenAddress, 8000) ); // Submit to governance contract governance.propose( configuratorAddress, 0, // value data, "Add NEWTOKEN as collateral with 80% LT" ); ``` **Key patterns demonstrated:** 1. **State extension**: Added `Position` tracking on top of base Credit Manager 2. **Collateral override**: Modified TWV calculation to include unrealized PnL 3. **Protocol-specific logic**: Market management and position tracking 4. **Governance integration**: `configuratorOnly` modifier for admin functions For architectural background, see [Credit Suite Architecture](https://docs.gearbox.finance/developers/gm-concept-accounts) and [Pool Architecture](https://docs.gearbox.finance/developers/gm-concept-markets). ## Security Considerations When extending core contracts: 1. **Preserve invariants** - Never break core protocol assumptions (debt tracking, collateral checks) 2. **Test extensively** - Fork mainnet and test against real pools/Credit Managers 3. **Audit thoroughly** - Core extensions require professional audits 4. **Consider upgrade paths** - Plan for parameter changes and emergency controls 5. **Monitor gas costs** - Overrides affect every user operation 6. **Validate inputs** - Custom logic must not allow manipulation of debt/collateral calculations ## Deployment Checklist * [ ] Core contracts audited by reputable firm * [ ] Fork tests against production Gearbox contracts * [ ] Governance proposal prepared with detailed specification * [ ] Documentation for users and integrators * [ ] Emergency pause mechanisms tested * [ ] Oracle manipulation scenarios analyzed * [ ] Gas profiling completed for all overridden functions * [ ] Upgradeability plan documented ## Related * [Adapter Development](https://docs.gearbox.finance/developers/gp-adapters) - Standard integration path * [Protocol Integration](https://docs.gearbox.finance/developers/gp-integration) - Building on top of Credit Accounts * [Credit Suite Architecture](https://docs.gearbox.finance/developers/gm-concept-accounts) - Core architecture reference * [Pool Architecture](https://docs.gearbox.finance/developers/gm-concept-markets) - Pool mechanics reference ## Deployment Addresses Source: https://docs.gearbox.finance/developers/res-addresses File: content/developers/res-addresses.mdx Gearbox Protocol contracts are deployed across multiple networks. This page lists the core contract addresses for each supported chain. ## Programmatic Discovery The recommended way to resolve contract addresses at runtime is through the **AddressProvider** contract. Rather than hardcoding addresses, query the AddressProvider to get the latest verified deployment for any protocol component: ```typescript import { GearboxSDK } from '@gearbox-protocol/sdk'; const sdk = await GearboxSDK.attach({ client, marketConfigurators: [] }); // Resolve any protocol contract by its key const [address, version] = sdk.addressProvider.mustGetLatest( AP_MARKET_COMPRESSOR, VERSION_RANGE_310 ); ``` See the [SDK setup guide](https://docs.gearbox.finance/developers/gm-start-ts) for full initialization details. *** ## Ethereum Mainnet | Contract | Address | | ---------------------- | -------------------------------------------- | | AddressProvider | `0x0000000000000000000000000000000000000001` | | MarketCompressor | `0x0000000000000000000000000000000000000002` | | CreditAccountCompressor| `0x0000000000000000000000000000000000000003` | | PriceFeedCompressor | `0x0000000000000000000000000000000000000004` | | BotList | `0x0000000000000000000000000000000000000005` | > Placeholder addresses shown above. Refer to the AddressProvider or the [Gearbox GitHub](https://github.com/Gearbox-protocol) for canonical deployments. *** ## Arbitrum | Contract | Address | | ---------------------- | -------------------------------------------- | | AddressProvider | `0x0000000000000000000000000000000000000001` | | MarketCompressor | `0x0000000000000000000000000000000000000002` | | CreditAccountCompressor| `0x0000000000000000000000000000000000000003` | | PriceFeedCompressor | `0x0000000000000000000000000000000000000004` | | BotList | `0x0000000000000000000000000000000000000005` | > Placeholder addresses shown above. Refer to the AddressProvider or the [Gearbox GitHub](https://github.com/Gearbox-protocol) for canonical deployments. *** ## Optimism | Contract | Address | | ---------------------- | -------------------------------------------- | | AddressProvider | `0x0000000000000000000000000000000000000001` | | MarketCompressor | `0x0000000000000000000000000000000000000002` | | CreditAccountCompressor| `0x0000000000000000000000000000000000000003` | | PriceFeedCompressor | `0x0000000000000000000000000000000000000004` | | BotList | `0x0000000000000000000000000000000000000005` | > Placeholder addresses shown above. Refer to the AddressProvider or the [Gearbox GitHub](https://github.com/Gearbox-protocol) for canonical deployments. *** ## Notes - Always prefer the **AddressProvider** for programmatic address resolution. Hardcoded addresses may become stale after protocol upgrades. - Market-specific contracts (Pools, Credit Managers, Credit Facades) are discoverable through the MarketCompressor once you have the AddressProvider. - For a complete list of address keys, see the `AP_*` constants exported by the SDK. ## Security & Audits Source: https://docs.gearbox.finance/developers/res-security File: content/developers/res-security.mdx Gearbox Protocol takes security seriously. The protocol has undergone multiple independent audits and maintains an active bug bounty program. ## Audit Reports Gearbox smart contracts have been audited by leading security firms. The following reports cover the core protocol and its extensions: | Auditor | Scope | Report | | --------------- | ------------------ | ------------------------------------------------------- | | ChainSecurity | Core V3 | [View Report](https://github.com/Gearbox-protocol/security/blob/main/audits/PLACEHOLDER) | | Consensys Diligence | Core V3 | [View Report](https://github.com/Gearbox-protocol/security/blob/main/audits/PLACEHOLDER) | | Sigma Prime | V3 Integrations | [View Report](https://github.com/Gearbox-protocol/security/blob/main/audits/PLACEHOLDER) | | ABDK | V3 Math Libraries | [View Report](https://github.com/Gearbox-protocol/security/blob/main/audits/PLACEHOLDER) | > Links above are placeholders. Visit the [Gearbox security repository](https://github.com/Gearbox-protocol/security) for the latest audit reports. *** ## Bug Bounty Program Gearbox maintains an active bug bounty program on **Immunefi**, one of the largest Web3 security platforms. - **Platform:** [Immunefi](https://immunefi.com/) - **Scope:** Smart contracts, protocol logic, and integrations - **Rewards:** Up to $1,000,000 for critical vulnerabilities (severity-dependent) If you discover a potential vulnerability, please report it through the Immunefi platform rather than public disclosure. Responsible disclosure is critical for protecting user funds. *** ## Bytecode Repository (BCR) Verification Gearbox uses a Bytecode Repository (BCR) to ensure that only audited, verified bytecode is deployed on-chain. This provides an additional layer of security beyond source-code audits by verifying the exact compiled output. For details on how BCR verification works and how to check deployed contracts, see [BCR Verification](https://docs.gearbox.finance/developers/gp-bcr). *** ## Security Contact For security-related inquiries that do not fall under the bug bounty program: - **Email:** security@gearbox.fi - **PGP Key:** Available on the [Gearbox security repository](https://github.com/Gearbox-protocol/security) Please do not report vulnerabilities via email. Use the Immunefi bug bounty program for all vulnerability disclosures. *** ## Security Practices The Gearbox Protocol follows several security best practices: - **Multiple independent audits** before each major release - **Formal verification** of critical mathematical components - **Timelocks and multisig governance** for parameter changes - **Immutable core logic** with upgradeable configuration - **On-chain BCR verification** ensuring only audited bytecode is deployed - **Continuous monitoring** of protocol health and anomalous activity ## Glossary Source: https://docs.gearbox.finance/developers/res-glossary File: content/developers/res-glossary.mdx Key terms used throughout the Gearbox Protocol documentation. | Term | Definition | | --- | --- | | Adapter | A thin wrapper contract that translates Credit Account multicalls into calls to an external DeFi protocol (e.g., Uniswap, Aave), enforcing collateral checks before and after execution. | | Bytecode Repository (BCR) | An on-chain registry of audited contract bytecode. Deployments are verified against the BCR to ensure only approved, audited code runs in production. | | Credit Account | An isolated smart-contract account that holds a user's collateral and borrowed funds. All leveraged operations happen inside a Credit Account. | | Credit Configurator | The admin-facing contract that governs a Credit Manager's parameters, such as allowed tokens, adapters, debt limits, and liquidation thresholds. | | Credit Facade | The user-facing entry point for a Credit Manager. It validates multicalls, enforces health-factor checks, and emits events for account operations. | | Credit Manager | The core contract that manages Credit Accounts for a given market. It tracks collateral, debt, and permissions, and delegates user interactions to the Credit Facade. | | Credit Suite | The combination of a Credit Manager, its Credit Facade, and its Credit Configurator, together forming the complete management layer for leveraged accounts in a market. | | Cross-Chain Multisig (CCM) | A governance mechanism that coordinates administrative actions across multiple chains, ensuring consistent parameter changes for Gearbox deployments on different networks. | | Debt Ceiling | The maximum total amount that can be borrowed from a pool by all Credit Managers combined, limiting the pool's overall leverage exposure. | | Diesel Token | The ERC-20 LP share token received when depositing into a Gearbox pool. Its value appreciates over time as interest accrues to the pool. | | Health Factor | The ratio of a Credit Account's total weighted collateral value to its total debt. A health factor below 1.0 means the account is eligible for liquidation. | | Instance | A single deployment of the Gearbox Protocol on a specific chain, consisting of an AddressProvider and all contracts registered through it. | | Instance Owner | The governance address (typically a multisig or DAO) that controls an Instance's AddressProvider and can register or update protocol contracts. | | Liquidation Threshold (LT) | A per-token coefficient (in basis points) that discounts a collateral token's value when computing the weighted collateral for health-factor calculations. A lower LT means the protocol treats the token more conservatively. | | Market Curator | An entity or role responsible for configuring and managing a specific market's parameters, including allowed collaterals, debt limits, and risk settings. | | Multicall | A batched sequence of operations executed atomically on a Credit Account within a single transaction. All health-factor checks are deferred until the end of the batch. | | Omni-EVM | Gearbox's cross-chain execution model that allows Credit Accounts to interact with protocols on multiple EVM-compatible chains from a single position. | | Pool | A lending pool that accepts deposits from liquidity providers and lends to Credit Managers. Each pool is denominated in a single underlying token. | | Protocol DAO | The decentralized governance body that oversees the Gearbox Protocol, controlling upgrades, risk parameters, and treasury operations. | | Quota | A per-token borrowing allocation within a pool that limits how much of a specific collateral type can be used across all Credit Accounts. | | Quota Rate | The additional interest rate (RAY-scaled, per-second) charged on a Credit Account for holding a non-underlying collateral token that requires a quota. | | Total Weighted Value (TWV) | The sum of each collateral token's balance multiplied by its price and its liquidation threshold. TWV divided by total debt gives the health factor. | ## Gearbox Agentic Overview Source: https://docs.gearbox.finance/developers/ga-overview File: content/developers/ga-overview.mdx Gearbox Agentic is AI-powered capital management built on top of Gearbox Credit Accounts. Autonomous agents discover yield opportunities, analyze risk, build transactions, preview exact on-chain outcomes, execute, and monitor positions — all through a structured loop and a single SDK. ## What It Does An AI agent manages DeFi capital across chains using the Gearbox SDK. The SDK handles protocol complexity — the agent handles decisions. The SDK builds transactions and previews outcomes but **never signs or sends** — execution stays with the caller. ## The 6-Step Agent Loop Every agent interaction follows the same structured cycle: | Step | Purpose | Who Decides | | --- | --- | --- | | **Discover** | Scan all current opportunities | SDK returns data | | **Analyze** | Due diligence on shortlisted candidates | Agent reasons over data | | **Propose** | Find optimal rebalance — or decide to do nothing | Agent + Router | | **Preview** | Verify on-chain feasibility right now | SDK simulates | | **Execute** | Sign and submit | User or agent via bot API | | **Monitor** | React to events that require response | SDK returns live state | [Read more about the Agent Loop](https://docs.gearbox.finance/developers/ga-agent-loop) ## Two Execution Modes ### Preview + Verify (Human-in-the-Loop) The agent builds and previews a transaction, then encodes the preview as a URL for [verify.gearbox.finance](https://verify.gearbox.finance). A human reviews decoded calldata, balance changes, and health factor projections before signing. ### Bot Permissions (Autonomous) The agent operates with bounded on-chain autonomy via a permission bitmask on a Credit Account. It cannot exceed its granted authority. [Read more about Execution](https://docs.gearbox.finance/developers/ga-execution) ## Learn More - [Concepts](https://docs.gearbox.finance/developers/ga-concepts) — Agent Loop, Architecture & Tools, MCP Server - [Getting Started](https://docs.gearbox.finance/developers/ga-start) — MCP Setup and First Agent tutorial - [Execution](https://docs.gearbox.finance/developers/ga-execution) — Human-in-the-Loop and Bot Execution ## Concepts Source: https://docs.gearbox.finance/developers/ga-concepts File: content/developers/ga-concepts.mdx The foundational concepts behind Gearbox Agentic. - [**The Agent Loop**](https://docs.gearbox.finance/developers/ga-agent-loop) — The 6-step cycle: Discover → Analyze → Propose → Preview → Execute → Monitor. Event-driven review triggers adapt pace to urgency. - [**Architecture & Tools**](https://docs.gearbox.finance/developers/ga-architecture) — How agents and frontends share the same SDK. The Tool Visualization Map: one SDK method → one MCP tool → one UI component. - [**MCP Server**](https://docs.gearbox.finance/developers/ga-mcp) — 16 tools exposed as MCP tool calls for LLM agents, mapped directly to SDK methods. ## The Agent Loop Source: https://docs.gearbox.finance/developers/ga-agent-loop File: content/developers/ga-agent-loop.mdx The agent loop is a structured 6-step cycle for AI-powered capital management on Gearbox. Each stage has clear inputs, outputs, and decision points. ```mermaid graph LR D[Discover] --> A[Analyze] A --> P[Propose] P --> Pr[Preview] Pr -->|"not feasible"| P Pr --> E[Execute] E --> M[Monitor] M -->|"event"| A ``` | Step | Purpose | Who Decides | | --- | --- | --- | | **Discover** | Scan all current opportunities | SDK returns data | | **Analyze** | Due diligence on shortlisted candidates | Agent reasons over data | | **Propose** | Find optimal rebalance — or decide to do nothing | Agent + Router | | **Preview** | Verify on-chain feasibility right now | SDK simulates | | **Execute** | Sign and submit | User or agent via bot API | | **Monitor** | React to events that require faster response | SDK returns live state | ## Step 1: Discover Scan all available opportunities across chains. This is a broad survey — every pool, every strategy, every chain. The data is lightweight: headline APY, TVL, access requirements. ```typescript const opportunities = await sdk.opportunities.search({ chainIds: ["Mainnet", "Monad"], types: ["pool", "strategy"], assets: [Asset.STABLE], }); ``` The agent applies its own filters (APY floor, TVL minimum, permissionless-only, etc.) and produces a **shortlist** of candidates for deeper analysis. ## Step 2: Analyze Due diligence on the shortlisted candidates. The agent inspects each one in detail using specialized research sub-agents: | Sub-Agent | What It Evaluates | | --- | --- | | **Curator Research** | Governance quality, bad debt history, track record | | **Token Research** | Collateral liquidity, oracle reliability, risk classification | | **Profitability Forecast** | APY sustainability, yield type (organic vs incentivized), trend | | **Risk Scoring** | 5 dimensions: collateral, curator, smart contract, market, exit | | **Final Ranking** | `finalScore = adjustedApy * (1 - overallRisk)` | ```typescript // Deep dive into a candidate const detail = await sdk.pools.getDetail({ chainId, address: poolAddress }); const curator = await sdk.curators.getProfile(detail.curatorId); const apyHistory = await sdk.history.getMetric({ target, metric: "apy", periodDays: 30 }); const events = await sdk.events.getFeed({ chainId, target, sinceDays: 30 }); ``` The output is `AnalyzedOpportunity[]` — ranked by score, each with profitability forecasts, risk breakdowns, and reasoning. ## Step 3: Propose From the analyzed candidates, find the **optimal action** — or decide that no rebalance is needed. The agent considers: - Is the current position already optimal? - Would the rebalance cost (gas, slippage) exceed the expected gain? - What's the best route for the chosen strategy? If a rebalance makes sense: ```typescript // Query router for optimal path const route = await sdk.router.findOpenStrategyPath({ chainId, creditManagerAddress, collateralToken, collateralAmount, debtAmount, targetToken, slippageBps: 50, }); // Build the unsigned transaction const tx = await sdk.accounts.openCreditAccount({ chainId, creditManagerAddress, collateralToken, collateralAmount, debtAmount, pathCalls: route.calls, slippageBps: 50, }); ``` If no action is needed, the agent skips to Monitor. ## Step 4: Preview Verify that the transaction is **feasible on-chain right now**. LLMs are not instant — by the time the agent finishes reasoning, on-chain conditions may have changed (liquidity exhausted, price moved, quota filled). ```typescript const preview = await sdk.previewTransaction(tx); ``` The preview simulates the exact bytes against current chain state and returns: - `success` — would this execute? - `healthFactor` — projected HF after entry - `actions[]` — human-readable step descriptions - `balanceChanges[]` — net token movements - `warnings[]` — concerns (stale oracle, high utilization, etc.) ### If preview fails → back to Propose The agent does **not** re-analyze. The due diligence is still valid — the candidates are sound. Only the execution parameters need adjustment: - Liquidity exhausted → reduce position size or try different route - Price moved → adjust slippage tolerance - Quota filled → switch to the next-ranked candidate from Analyze ```typescript if (!preview.success || (preview.healthFactor ?? 0) < 1.4) { // Adjust parameters and re-propose // Do NOT re-run Analyze — the research is still valid } ``` ## Step 5: Execute Sign and submit the transaction. The SDK **never signs** — execution is the caller's responsibility. Two paths: - **[Human-in-the-Loop](https://docs.gearbox.finance/developers/ga-human-loop)** — agent encodes preview as URL for verify.gearbox.finance, human reviews and signs - **[Bot Execution](https://docs.gearbox.finance/developers/ga-bot-execution)** — agent signs via bot API with bounded on-chain permissions ```typescript const txHash = await walletClient.sendTransaction({ to: tx.to, data: tx.calldata, value: tx.value, }); ``` ## Step 6: Monitor Watch the live position and react to events. The monitor waits for signals — either scheduled (cron) or event-driven (alerts, external data). ```typescript const position = await sdk.accounts.getStatus({ chainId, creditAccount }); const alerts = await sdk.monitor.getAlerts({ chainId, creditAccount }); ``` ### When events trigger a review → back to Analyze The monitor doesn't jump to Propose — it goes back to **Analyze** to re-evaluate the situation with fresh data. This is critical: if a collateral token is dropping, the agent needs to understand the severity before deciding what to do. | Event | Urgency | Response | | --- | --- | --- | | Scheduled check (cron, every 4h) | Normal | Full Analyze → Propose cycle | | Collateral price dropping | Elevated | Quick Analyze → Propose adjustment | | Critical event (hack, depeg, tweet) | Immediate | Emergency exit via Propose → Preview → Execute | | Better opportunity detected | Normal | Analyze alternatives → Propose migration | | HF approaching liquidation | Urgent | Analyze → Propose collateral top-up or debt reduction | The urgency of the trigger determines the pace. A cron check runs the full cycle. A critical event skips straight to action — but still passes through Analyze to confirm the threat is real before executing. ## Learn More - [MCP Server](https://docs.gearbox.finance/developers/ga-mcp) — MCP tools organized by loop stage - [Execution](https://docs.gearbox.finance/developers/ga-execution) — How agents interact with the protocol safely ## Architecture & Tools Source: https://docs.gearbox.finance/developers/ga-architecture File: content/developers/ga-architecture.mdx How agents and frontends share the same SDK, and why every tool has a visual representation. ## Architecture ```mermaid flowchart TD Agent[Agent] --> MCP[MCP Server] Frontend[Frontend] --> SDK MCP --> SDK[Gearbox SDK] SDK --> RPC[On-chain RPC] SDK --> Backend[Backend API] ``` - **Agents** access the SDK through the [MCP Server](https://docs.gearbox.finance/developers/ga-mcp) — 16 tools exposed as MCP tool calls - **Frontends** use the SDK directly — same methods, same types - Both paths reach the same canonical API — identical data, identical types The SDK talks to two backends: - **On-chain RPC** — protocol reads, transaction simulation, live state - **Backend API** — history, cached metrics, curator/token metadata (optional — SDK degrades gracefully without it) ## One Type, One Tool, One Component Every SDK method returns a typed result. That same type is: - Exposed as an **MCP tool** for agents (JSON) - Rendered by a **UI component** for humans (React) This means an agent chat interface can show the same cards, tables, and previews that a regular user sees — not just raw text. ## Tool Visualization Map | SDK Method | MCP Tool | UI Component | Data | | --- | --- | --- | --- | | `sdk.opportunities.search()` | `list_opportunities` | `` | Pools & strategies with APY, TVL, access | | `sdk.pools.list()` | `list_pools` | `` | LP opportunities | | `sdk.strategies.list()` | `list_strategies` | `` | Leveraged strategies | | `sdk.pools.getDetail()` | `get_pool_detail` | `` | Full pool snapshot: tokens, rates, capacity | | `sdk.strategies.getDetail()` | `get_strategy_detail` | `` | Strategy params, leverage, collaterals | | `sdk.curators.getProfile()` | `get_curator` | `` | Track record, bad debt history, TVL | | `sdk.tokens.getMarketData()` | `get_token_liquidity` | `` | Oracle price, liquidity depth | | `sdk.history.getMetric()` | `get_metric_history` | `` | APY, utilization, TVL time series | | `sdk.events.getFeed()` | `get_events` | `` | Parameter changes, pending governance | | `sdk.positions.prepareOpen()` | `prepare_position` | `` | Unsigned transaction (RawTx) | | `sdk.previewTransaction()` | `simulate_position` | `` | Simulated outcome: HF, actions, warnings | | `sdk.accounts.getStatus()` | `get_position_status` | `` | Live health factor, balances, alerts | ## What This Enables - **Frontend developers** build UIs using SDK + `@gearbox-protocol/uikit` components - **Agent developers** get identical data quality through MCP tools - **Agent UIs** (chat with visualization) render MCP tool results using the same UI components — same experience as the native frontend ## Learn More - [MCP Server](https://docs.gearbox.finance/developers/ga-mcp) — all 16 tools in detail - [The Agent Loop](https://docs.gearbox.finance/developers/ga-agent-loop) — how tools are used at each stage - [SDK Namespaces](https://docs.gearbox.finance/developers/gm-start-namespaces) — full SDK namespace reference ## MCP Server Source: https://docs.gearbox.finance/developers/ga-mcp File: content/developers/ga-mcp.mdx The Gearbox MCP (Model Context Protocol) Server exposes SDK methods as tool calls for LLM agents. It is a thin adapter -- no duplicated business logic. MCP tool responses are direct SDK models or thin wrappers around them. ## MCP in the Stack ```mermaid graph TD Agent[AI Agent] --> MCP[MCP Server] MCP --> SDK[Gearbox SDK] SDK --> Chain[On-chain RPC and Contracts] SDK --> Backend[Backend: history, cache, metadata] ``` The MCP Server is **not** the source of truth. The source of truth is: 1. Smart contracts for live protocol state 2. SDK public domain model for integration 3. Backend for enrichment, history, and metadata MCP is the agent transport layer -- a tool-oriented presentation of SDK methods. ## Tools by Stage The 16 MCP tools map directly to the [agent loop](https://docs.gearbox.finance/developers/ga-agent-loop) stages: ### Discovery | MCP Tool | SDK Method | Description | |----------|-----------|-------------| | `list_opportunities` | `sdk.opportunities.search()` | Unified discovery across pools and strategies | | `list_pools` | `sdk.pools.list()` | Pool-specific discovery with APY, TVL, active assets | | `list_strategies` | `sdk.strategies.list()` | Strategy-specific discovery with leverage, debt bounds | **Example -- list_opportunities:** ```typescript // MCP input list_opportunities({ chain_ids: ["Mainnet", "Monad"], types: ["pool", "strategy"], assets: ["stable"], include_paused: false, }) // Maps to SDK const results = await sdk.opportunities.search({ chainIds: ["Mainnet", "Monad"], types: ["pool", "strategy"], assets: [Asset.STABLE], includePaused: false, }); ``` ### Analysis | MCP Tool | SDK Method | Description | |----------|-----------|-------------| | `get_pool_detail` | `sdk.pools.getDetail()` | Full pool parameters, allowed tokens, constraints | | `get_strategy_detail` | `sdk.strategies.getDetail()` | Strategy parameters, CM addresses, exit mechanics | | `get_metric_history` | `sdk.history.getMetric()` | Historical APY, TVL, utilization, borrow rates | | `get_events` | `sdk.events.getFeed()` | Parameter changes, governance events, pending changes | | `get_curator` | `sdk.curators.getProfile()` | Curator track record, bad debt history, managed pools | | `get_token_info` | `sdk.tokens.getProfiles()` | Token profiles and metadata | | `get_token_liquidity` | `sdk.tokens.getMarketData()` | Liquidity depth, market data for sizing checks | **Example -- get_pool_detail:** ```typescript // MCP input get_pool_detail({ chain_id: "Mainnet", pool_address: "0x...", }) // Maps to SDK const detail = await sdk.pools.getDetail({ chainId: "Mainnet", poolAddress: "0x...", }); ``` ### Action Preparation | MCP Tool | SDK Method | Description | |----------|-----------|-------------| | `prepare_deposit` | `sdk.positions.prepareDeposit()` | Build a pool deposit transaction | | `prepare_position` | `sdk.positions.prepareOpen()` | Build a strategy open transaction with route | | `simulate_deposit` | `sdk.positions.previewDeposit()` | Preview a pool deposit outcome | | `simulate_position` | `sdk.positions.previewOpen()` | Preview a strategy position outcome | **Example -- prepare_position:** ```typescript // MCP input prepare_position({ chain_id: "Mainnet", credit_manager: "0x...", collateral_token: "0xA0b8...USDC", collateral_amount: "100000000000", debt_amount: "200000000000", target_token: "0xae78...stETH", slippage_bps: 50, }) // Maps to SDK const route = await sdk.router.findOpenStrategyPath({ ... }); const tx = await sdk.accounts.openCreditAccount({ ... }); const preview = await sdk.previewTransaction(tx); ``` ### Execution | MCP Tool | SDK Method | Description | |----------|-----------|-------------| | `execute_transaction` | `sdk.transactions.execute()` | Submit a prepared and previewed transaction | The SDK does not hold private keys. The `execute_transaction` tool routes the `RawTx` through the configured signer. ### Monitoring | MCP Tool | SDK Method | Description | |----------|-----------|-------------| | `get_pool_status` | `sdk.pools.getStatus()` | Current pool state: rates, utilization, liquidity | | `get_position_status` | `sdk.accounts.getStatus()` | Position health factor, value, debt, alerts | **Example -- get_position_status:** ```typescript // MCP input get_position_status({ chain_id: "Mainnet", credit_account: "0x...", }) // Maps to SDK const status = await sdk.accounts.getStatus({ chainId: "Mainnet", creditAccount: "0x...", }); ``` ## Complete Mapping Reference | MCP Tool | SDK Method | Stage | |----------|-----------|-------| | `list_opportunities` | `sdk.opportunities.search()` | Discover | | `list_pools` | `sdk.pools.list()` | Discover | | `list_strategies` | `sdk.strategies.list()` | Discover | | `get_pool_detail` | `sdk.pools.getDetail()` | Analyze | | `get_strategy_detail` | `sdk.strategies.getDetail()` | Analyze | | `get_metric_history` | `sdk.history.getMetric()` | Analyze | | `get_events` | `sdk.events.getFeed()` | Analyze | | `get_curator` | `sdk.curators.getProfile()` | Analyze | | `get_token_info` | `sdk.tokens.getProfiles()` | Analyze | | `get_token_liquidity` | `sdk.tokens.getMarketData()` | Analyze | | `prepare_deposit` | `sdk.positions.prepareDeposit()` | Propose | | `prepare_position` | `sdk.positions.prepareOpen()` | Propose | | `simulate_deposit` | `sdk.positions.previewDeposit()` | Preview | | `simulate_position` | `sdk.positions.previewOpen()` | Preview | | `execute_transaction` | `sdk.transactions.execute()` | Execute | | `get_pool_status` | `sdk.pools.getStatus()` | Monitor | | `get_position_status` | `sdk.accounts.getStatus()` | Monitor | ## Runtime Modes The MCP Server inherits SDK runtime modes: **Core-Only Mode** -- chain access works, backend unavailable. Discovery, prepare, simulate, execute, and monitoring all work. History, curator profiles, and cached APY are degraded. **Enriched Mode** -- chain + backend available. Full history, metadata, human-readable events, and cached classification surfaces. All tool responses carry `freshness` metadata so the agent knows the data quality: ```typescript { asOf: "2025-04-07T10:30:00Z", sources: ["onchain", "backend-cache"], backendAvailable: true } ``` ## Learn More - [The Agent Loop](https://docs.gearbox.finance/developers/ga-agent-loop) -- how tools map to the 6-step loop - [Transaction Preview](https://docs.gearbox.finance/developers/ga-preview) -- the security gate between Propose and Execute - [Execution Modes](https://docs.gearbox.finance/developers/ga-execution) -- what happens after the agent calls `execute_transaction` ## Transaction Preview Source: https://docs.gearbox.finance/developers/ga-preview File: content/developers/ga-preview.mdx Transaction Preview is the universal security gate in Gearbox Agentic. A single SDK method -- `sdk.previewTransaction(tx)` -- simulates any Gearbox transaction and returns a full breakdown of what will happen before any funds are committed. ## Key Principle **Same bytes previewed = same bytes executed.** The input to `previewTransaction` is the actual `RawTx` -- the exact calldata that would be sent to the network. This is not a parameter-based estimate; it is a simulation of the real transaction. ## Transaction Lifecycle ```mermaid graph LR P[Propose] --> Pr[Preview] Pr --> V[Validate] V -->|pass| E[Execute] V -->|fail| P E --> M[Monitor] ``` ## Input The method accepts a `RawTx` -- the unsigned transaction built in the Propose stage: ```typescript interface RawTx { to: Address; calldata: Hex; value?: bigint; } ``` One method handles all Gearbox transactions: open credit account, close, adjust, add collateral, swap -- everything. The agent does not need to know which preview method to call. ## Output ```typescript const preview = await sdk.previewTransaction(tx); ``` The preview returns: ```typescript interface TransactionPreview { // Would this transaction execute? success: boolean; // Any concerns warnings: string[]; // Projected health factor after entry healthFactor?: number; // Estimated gas cost gasEstimate?: string; // Human-readable breakdown of multicall actions actions: Array<{ title: string; // e.g. "Deposit 100,000 USDC" description: string; // e.g. "Collateral added to credit account" protocol?: string; // e.g. "Curve", "1inch" }>; // Net token movements for the wallet balanceChanges: Array<{ token: TokenRef; delta: string; direction: "in" | "out"; }>; // Swap route details routes?: Array<{ tokenIn: TokenRef; tokenOut: TokenRef; amountIn: string; expectedOut: string; priceImpactBps?: number; dex?: string; }>; // Exit characteristics for this position exitInfo?: { hasDelayedWithdrawal: boolean; zeroSlippageAvailable: boolean; }; } ``` ## What the Agent Validates Before proceeding to execution, the agent checks every aspect of the preview: ```typescript // 1. Did simulation succeed? if (!preview.success) { throw new Error("Transaction would revert"); } // 2. Is health factor safe? if ((preview.healthFactor ?? 0) < 1.4) { // Go back to PROPOSE, reduce leverage } // 3. Any warnings? if (preview.warnings.length > 0) { // Evaluate each warning, decide to proceed or abort } // 4. Review balance changes for (const change of preview.balanceChanges) { // Verify no unexpected tokens leave the wallet // Verify amounts match expectations } // 5. Review actions for (const action of preview.actions) { // "Deposit 100,000 USDC" -- correct // "Borrow 200,000 USDC" -- correct // "Swap 200,000 USDC to stETH via 1inch" -- correct } // 6. Check swap routes for (const route of preview.routes ?? []) { if ((route.priceImpactBps ?? 0) > 100) { // > 1% price impact -- consider reducing size } } // 7. Understand exit conditions if (preview.exitInfo?.hasDelayedWithdrawal) { // Closing will involve phantom tokens -- factor into decision } ``` ## Verify URL The preview can be encoded as a URL for human review at [verify.gearbox.finance](https://verify.gearbox.finance). The verifier displays: - **Decoded calldata** -- the inner `MultiCall[]` structure decoded against Gearbox ABIs - **Actions** -- human-readable list of what the transaction does - **Balance changes** -- net token movements - **Health factor projection** -- projected HF after execution - **Warnings** -- any concerns flagged by the simulation This is the bridge between autonomous agents and human approval. The agent builds and previews; the human verifies and signs. ## Looping Back If the preview fails or shows unacceptable results, the agent adjusts and retries: ``` PREVIEW -> constraints fail -> PROPOSE (adjust parameters) -> PREVIEW ``` The agent can adjust leverage, debt amount, slippage tolerance, or select a different strategy entirely, then rebuild the transaction and preview again. ## Why One Method Traditional DeFi integrations require different preview methods for different transaction types. Gearbox uses a single `previewTransaction` that works for any `RawTx`. This means: - Agents do not need to know the transaction type to preview it - The same security gate applies to every operation - Independent verifiers can simulate any Gearbox transaction using the same method - The preview surface cannot be bypassed by using a different code path ## Learn More - [The Agent Loop](https://docs.gearbox.finance/developers/ga-agent-loop) -- how Preview fits into the 6-step loop - [Execution Modes](https://docs.gearbox.finance/developers/ga-execution) -- what happens after preview validation - [MCP Server](https://docs.gearbox.finance/developers/ga-mcp) -- `simulate_deposit` and `simulate_position` tools ## Execution Source: https://docs.gearbox.finance/developers/ga-execution File: content/developers/ga-execution.mdx How agents interact with the Gearbox protocol on-chain — and why it's safe. ## The Security Model A core principle of Gearbox Agentic: **the SDK builds transactions, but never signs them**. Transaction construction (what to do) is separated from transaction execution (actually doing it). This creates a clear security boundary. Every transaction goes through **preview** before execution: 1. **Build** — `sdk.positions.prepareOpen()` → produces a `RawTx { to, calldata, value }` 2. **Preview** — `sdk.previewTransaction(rawTx)` → simulates the exact bytes, returns success, health factor, actions, balance changes, warnings 3. **Validate** — agent (or human) checks: success = true, HF > threshold, no critical warnings 4. **Execute** — sign and send via wallet The same bytes that were previewed are the bytes that go on-chain. No deviation. ## Two Execution Modes | Mode | Trust Level | Best For | | --- | --- | --- | | [**Human-in-the-Loop**](https://docs.gearbox.finance/developers/ga-human-loop) | Agent proposes, human approves | High-value positions, institutional compliance, initial trust building | | [**Bot Execution**](https://docs.gearbox.finance/developers/ga-bot-execution) | Agent executes autonomously within bounds | Rebalancing, liquidation monitoring, automated management | Both modes use the same preview mechanism. The difference is who signs. ## Learn More - [Human-in-the-Loop](https://docs.gearbox.finance/developers/ga-human-loop) — verify.gearbox.finance approval flow - [Bot Execution](https://docs.gearbox.finance/developers/ga-bot-execution) — bounded on-chain permissions - [The Agent Loop](https://docs.gearbox.finance/developers/ga-agent-loop) — how Preview and Execute fit in the 6-step cycle ## Getting Started Source: https://docs.gearbox.finance/developers/ga-start File: content/developers/ga-start.mdx Gearbox Agentic lets AI agents and programmatic integrators discover yield opportunities, analyze risk, and prepare transactions across the Gearbox protocol. There are two ways to get started, depending on how you want to interact. ## Option 1: MCP Setup (Recommended for LLM Agents) If you are using an LLM agent like Claude, ChatGPT, or any MCP-compatible client, the fastest path is to install the **Gearbox MCP server**. This gives your agent direct access to 16+ tools for discovering pools, analyzing curators, simulating deposits, and more — all through natural language conversation. Best for: Claude Desktop, Cursor, Windsurf, custom MCP clients. [Set up MCP Server](https://docs.gearbox.finance/developers/ga-setup-mcp) ## Option 2: Build a Custom Agent with the SDK If you are building a standalone agent, bot, or backend service, you can integrate the **Gearbox SDK** directly into your TypeScript application. The SDK is the canonical public API that the MCP server itself wraps. This gives you full control over the agent loop: discover, analyze, propose, preview, execute, and monitor. Best for: automated vaults, rebalancing bots, custom dashboards, programmatic integrators. [Build your first agent](https://docs.gearbox.finance/developers/ga-first-agent) ## The Agent Loop Both paths follow the same six-stage lifecycle: ```mermaid graph LR D[Discover] --> A[Analyze] A --> P[Propose] P --> Pr[Preview] Pr -->|constraints fail| P Pr --> E[Execute] E --> M[Monitor] M -->|rebalance| D M -->|adjust| P ``` | Stage | What happens | | -------- | ----------------------------------------------------- | | Discover | Find yield opportunities across chains | | Analyze | Inspect details, history, risk, curator quality | | Propose | Build intended transaction | | Preview | Simulate exact on-chain outcome before committing | | Execute | Sign and submit the transaction | | Monitor | Watch the live position and react to changes | ## Next Steps - [MCP Setup](https://docs.gearbox.finance/developers/ga-setup-mcp) — install and configure the MCP server - [First Agent](https://docs.gearbox.finance/developers/ga-first-agent) — walk through a complete discover-to-preview flow ## MCP Setup Source: https://docs.gearbox.finance/developers/ga-setup-mcp File: content/developers/ga-setup-mcp.mdx Connect the Gearbox MCP server to your AI coding tool and start interacting with the protocol. ## Installation Add the Gearbox MCP server to your client. The configuration is the same across all clients — just the config file location differs. ```json { "mcpServers": { "gearbox": { "command": "npx", "args": ["@gearbox-protocol/mcp-server"] } } } ``` ### Where to put this config | Client | Config File | | --- | --- | | **Claude Desktop** | `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows) | | **Claude Code** | `.claude/settings.json` (project) or `~/.claude/settings.json` (global) | | **VS Code (Copilot)** | `.vscode/settings.json` — use `"mcp": { "servers": { ... } }` format | | **Cursor** | `.cursor/mcp.json` in project root | | **Windsurf** | `~/.codeium/windsurf/mcp_config.json` | After adding the config, restart your client. ## Verify the Connection Once configured, restart your MCP client and verify the connection by asking the agent to list available opportunities: > List all available Gearbox yield opportunities on Mainnet The agent should call `list_opportunities` and return a list of pools and strategies with APY, TVL, and access information. If you see results, the setup is working. ## What You Can Do The MCP server exposes 16 tools organized by the agent loop stages: ### Discover | Tool | Description | | -------------------- | ---------------------------------------------------- | | `list_opportunities` | Find opportunities across chains, filtered by asset type, chain, and kind | | `list_pools` | List pool (passive lending) opportunities | | `list_strategies` | List strategy (leveraged) opportunities | ### Analyze | Tool | Description | | -------------------- | ---------------------------------------------------- | | `get_pool_detail` | Full pool detail: allowed tokens, rates, capacity | | `get_strategy_detail`| Strategy detail: leverage, collaterals, exit modes | | `get_metric_history` | Historical APY, TVL, utilization over a time period | | `get_events` | Recent parameter changes and governance events | | `get_curator` | Curator profile: track record, bad debt history, managed TVL | | `get_token_info` | Token profiles and metadata | | `get_token_liquidity`| On-chain liquidity depth and market data | ### Propose | Tool | Description | | -------------------- | ---------------------------------------------------- | | `prepare_deposit` | Build a deposit transaction for a pool | | `prepare_position` | Build a leveraged position transaction for a strategy| ### Preview | Tool | Description | | -------------------- | ---------------------------------------------------- | | `simulate_deposit` | Simulate a deposit and see expected outcomes | | `simulate_position` | Simulate a leveraged position opening | ### Execute & Monitor | Tool | Description | | -------------------- | ---------------------------------------------------- | | `execute_transaction`| Submit a prepared transaction to the blockchain | | `get_pool_status` | Current pool state: rates, utilization, TVL | | `get_position_status`| Current position health factor, value, and alerts | ## Multi-Chain Support All tools are chain-aware. You can query across multiple chains or target a specific one: > Show me stablecoin opportunities on both Mainnet and Monad > Get pool details for 0x... on chain 1 Every entity reference includes a `chainId`, so there is no ambiguity when the same token or contract exists on multiple chains. ## Next Steps - [First Agent](https://docs.gearbox.finance/developers/ga-first-agent) — walk through a complete discover-to-preview flow using MCP tools - [Getting Started](https://docs.gearbox.finance/developers/ga-start) — overview of both integration paths ## First Agent Source: https://docs.gearbox.finance/developers/ga-first-agent File: content/developers/ga-first-agent.mdx This walkthrough takes you through a complete **discover, analyze, preview** flow using MCP tools. By the end, you will have found a yield opportunity, researched its risk profile, and simulated a deposit — all through natural conversation with an LLM agent. Before starting, make sure you have [set up the MCP server](https://docs.gearbox.finance/developers/ga-setup-mcp). ## Step 1: Discover Opportunities Start by asking your agent to find yield opportunities. The `list_opportunities` tool searches across chains and returns pools and strategies with headline APY, TVL, and access requirements. > Find all permissionless pool opportunities on Mainnet with APY above 5% The agent calls: ``` Tool: list_opportunities Input: { "types": ["pool"], "chain_ids": [1], "include_paused": false } ``` You get back a list of opportunities, each with: - **title** — human-readable name (e.g. "USDC Lending Pool") - **headlineApy** — current total APY - **tvlUsd** — total value locked - **depositToken** — what you deposit (USDC, WETH, etc.) - **access** — whether it is permissionless or requires KYC - **risk.warnings** — any red flags Pick a candidate that matches your criteria. Note its `chainId` and `poolAddress` for the next step. ## Step 2: Analyze the Candidate Now dig deeper into the pool you selected. This stage uses multiple tools to build a full picture of risk and return. ### 2a. Get Pool Details > Show me the full details for pool 0xABC... on Mainnet ``` Tool: get_pool_detail Input: { "chain_id": 1, "address": "0xABC..." } ``` This returns the pool's allowed tokens, current utilization, borrow rates, capacity limits, and the curator who manages its risk parameters. Pay attention to: - **allowedTokens** — which collateral the pool accepts and their liquidation thresholds - **availableLiquidity** — how much room remains for deposits - **isPaused** — whether the pool is currently active ### 2b. Research the Curator Every pool is managed by a curator who sets risk parameters. Check their track record: > Who is the curator for this pool? What is their track record? ``` Tool: get_curator Input: { "curator_id": "steakhouse" } ``` The curator profile reveals: - **badDebtEvents** and **badDebtUsd** — historical losses (lower is better) - **parameterChanges30d** — how actively they manage the pool (too few changes may signal neglect, too many may signal instability) - **totalTvlUsd** — total value they manage across all pools - **isActive** — whether they are still actively managing ### 2c. Check Historical Performance > Show me the APY history for this pool over the last 30 days ``` Tool: get_metric_history Input: { "chain_id": 1, "target": "0xABC...", "metric": "apy", "period_days": 30 } ``` Compare the current APY against the 30-day trend. A pool showing 12% APY today but averaging 4% over the month may be experiencing a temporary spike. Look for: - **Stability** — low standard deviation means more predictable returns - **Trend** — is APY trending up or down? - **Yield type** — organic yield is more sustainable than incentivized yield ## Step 3: Prepare a Deposit Once you are satisfied with the analysis, prepare the deposit transaction. This builds the transaction without sending it. > Prepare a deposit of 10,000 USDC into pool 0xABC... on Mainnet ``` Tool: prepare_deposit Input: { "chain_id": 1, "pool_address": "0xABC...", "amount": "10000000000", "token": "USDC" } ``` The tool returns a `RawTx` object containing the transaction `to` address and `calldata`. This is the exact transaction that would be sent to the blockchain, but it has not been signed or submitted yet. ## Step 4: Preview the Transaction Before committing any funds, simulate the transaction to see exactly what will happen on-chain. > Simulate this deposit and show me the expected outcome ``` Tool: simulate_deposit Input: { "raw_tx": { "to": "0x...", "calldata": "0x..." } } ``` The simulation returns a full breakdown: ``` { "success": true, "healthFactor": 2.1, "warnings": [], "actions": [ { "title": "Deposit 10,000 USDC", "description": "Added to lending pool" } ], "balanceChanges": [ { "token": "USDC", "delta": "-10000", "direction": "out" }, { "token": "dUSDC", "delta": "9987.5", "direction": "in" } ], "gasEstimate": "142000" } ``` ### What to Check Before approving the transaction, verify these conditions: 1. **`success` is `true`** — the transaction would not revert 2. **`healthFactor` > 1.4** — sufficient safety margin (for leveraged positions) 3. **No critical warnings** — review any items in the `warnings` array 4. **Balance changes look correct** — you are sending the expected token and receiving the right pool token 5. **Actions match your intent** — the human-readable action list should describe exactly what you asked for 6. **Gas estimate is reasonable** — no unexpectedly high gas costs ## Step 5: Review Before Execution At this point, you have a fully simulated transaction with confirmed outcomes. Before executing: ### Option A: Execute Through the Agent If your agent has signing capabilities and you trust the setup: > Execute this transaction The agent calls `execute_transaction` with the raw transaction data. The SDK submits it to the blockchain and returns a transaction hash. ### Option B: Manual Review and Approval For higher security, review the transaction independently before signing. The transaction calldata can be inspected at: **[verify.gearbox.finance](https://verify.gearbox.finance)** — paste the raw transaction to decode the multicall, view each step, and simulate on a fork before signing in your wallet. This is the recommended approach for large deposits or when the agent is not trusted with automatic execution. ### Understanding the Preview Output | Field | What it tells you | | ---------------- | ------------------------------------------------------- | | `success` | Whether the transaction would execute without reverting | | `healthFactor` | Projected solvency ratio (only for leveraged positions) | | `warnings` | Risk flags — review each one before proceeding | | `actions` | Step-by-step breakdown of what the multicall does | | `balanceChanges` | Net token movements for your wallet | | `routes` | Swap paths used, including price impact per hop | | `exitInfo` | Whether closing will involve delayed withdrawal | | `gasEstimate` | Estimated gas cost in wei | ## Full Flow Summary ```mermaid graph TD A["1. list_opportunities\nFind pools with APY > 5%"] --> B["2a. get_pool_detail\nInspect allowed tokens, rates"] B --> C["2b. get_curator\nCheck curator track record"] C --> D["2c. get_metric_history\nReview 30-day APY trend"] D --> E["3. prepare_deposit\nBuild the transaction"] E --> F["4. simulate_deposit\nVerify success, health, warnings"] F --> G{"All checks pass?"} G -->|Yes| H["5. Execute or review manually"] G -->|No| I["Adjust parameters\nor pick another pool"] I --> E ``` ## Next Steps - [MCP Setup](https://docs.gearbox.finance/developers/ga-setup-mcp) — configure additional chains or environment variables - [Getting Started](https://docs.gearbox.finance/developers/ga-start) — overview of both MCP and SDK integration paths ## Human-in-the-Loop Source: https://docs.gearbox.finance/developers/ga-human-loop File: content/developers/ga-human-loop.mdx The Human-in-the-Loop execution mode means the agent builds and previews transactions, but a human reviews and approves every action before it goes on-chain. ## The Flow ```mermaid flowchart LR Agent[Agent builds tx] --> Preview[Preview tx] Preview --> Encode[Encode preview URL] Encode --> Verify[verify.gearbox.finance] Verify --> Human[Human reviews] Human -->|approve| Sign[Sign in wallet] Sign --> Chain[On-chain] Human -->|reject| Agent ``` 1. **Agent builds** — `sdk.positions.prepareOpen(params)` → `RawTx` 2. **Agent previews** — `sdk.previewTransaction(rawTx)` → `TransactionPreview` 3. **Agent encodes** — preview data encoded as URL: `verify.gearbox.finance/?tx=` 4. **Human reviews** at verify.gearbox.finance: - Decoded calldata (human-readable actions) - Token balance changes (what goes in, what comes out) - Swap routes and price impact - Projected Health Factor - Warnings and concerns 5. **Human approves** → signs in wallet (MetaMask, Safe, etc.) 6. **Transaction executes** — exact bytes from preview ## Why This Works - **Same bytes** — what was previewed is what gets signed. No deviation. - **No key management** — the agent never holds private keys - **Auditable** — the preview URL creates a shareable record of what was proposed - **LLM-friendly** — the preview actions are human-readable, so both the agent and the human can understand them ## When to Use | Scenario | Recommendation | | --- | --- | | First deployment / building trust | Always human-in-the-loop | | High-value positions (>\$100K) | Human-in-the-loop | | Institutional / compliance requirements | Human-in-the-loop | | Routine rebalancing | Consider [Bot Execution](https://docs.gearbox.finance/developers/ga-bot-execution) | ## Example ```typescript // Agent builds the transaction const rawTx = await sdk.positions.prepareOpen({ chainId: "Mainnet", strategy: strategyId, depositToken: "USDC", depositAmount: 10_000n * 10n ** 6n, leverage: 3, }); // Agent previews const preview = await sdk.previewTransaction(rawTx); if (preview.success && preview.healthFactor > 1.4) { // Encode for human review const verifyUrl = `https://verify.gearbox.finance/?tx=${encodePreview(preview)}`; console.log(`Review and approve: ${verifyUrl}`); // Human opens URL, reviews, signs in wallet } ``` ## Learn More - [Bot Execution](https://docs.gearbox.finance/developers/ga-bot-execution) — autonomous execution with bounded permissions - [The Agent Loop](https://docs.gearbox.finance/developers/ga-agent-loop) — where Preview and Execute fit in the cycle ## Bot Execution Source: https://docs.gearbox.finance/developers/ga-bot-execution File: content/developers/ga-bot-execution.mdx Bot Execution mode allows an agent to operate autonomously on-chain, but within strictly bounded permissions. The agent has its own address with explicit, revocable permissions granted per Credit Account. ## How It Works The Gearbox [Bot System](https://docs.gearbox.finance/developers/gm-bots) provides granular permission control: 1. **Account owner grants permissions** — specific operations allowed for a specific bot on a specific account 2. **Agent executes via `botMulticall`** — operations go through CreditFacade with permission checks 3. **Protocol enforces boundaries** — any unpermitted operation reverts the transaction 4. **Solvency check still applies** — bot multicalls undergo the same HF >= 1 check as user multicalls ## Permission Bitmask Each permission is a bit flag. The account owner composes a bitmask of allowed operations: | Permission | What the Bot Can Do | | --- | --- | | `ADD_COLLATERAL` | Deposit tokens into the account | | `INCREASE_DEBT` | Borrow more from the pool | | `DECREASE_DEBT` | Repay debt | | `WITHDRAW_COLLATERAL` | Remove tokens from the account | | `UPDATE_QUOTA` | Adjust token quotas | | `EXTERNAL_CALLS` | Call DeFi protocols via adapters | An agent managing a yield strategy might need `ADD_COLLATERAL | EXTERNAL_CALLS | UPDATE_QUOTA` but explicitly **not** `WITHDRAW_COLLATERAL` — preventing it from removing funds. ## Safety Model - **Scoped** — permissions are per `(bot, creditManager, creditAccount)` tuple. One bot's permissions on one account don't affect any other. - **Revocable** — the account owner can revoke at any time by setting permissions to 0 - **Immutable boundary** — bots cannot modify their own permissions - **DAO forbid list** — the DAO can globally forbid a malicious bot address - **Same solvency rules** — bot operations undergo identical collateral checks ## Monitoring Bot Activity The agent (or a separate monitor) should track bot state: ```typescript const position = await sdk.accounts.getStatus({ chainId: "Mainnet", creditAccount: accountAddress, }); // Check active bots for (const bot of position.bots) { console.log(`Bot: ${bot.address}, permissions: ${bot.permissions}`); } ``` ## When to Use | Scenario | Recommendation | | --- | --- | | Automated rebalancing | Bot with EXTERNAL_CALLS + UPDATE_QUOTA | | Liquidation protection | Bot with ADD_COLLATERAL + DECREASE_DEBT | | Full autonomy | Bot with all permissions (high trust required) | | Withdrawal needed | Prefer [Human-in-the-Loop](https://docs.gearbox.finance/developers/ga-human-loop) | ## Combining Both Modes A common pattern: use **Bot Execution** for routine operations (rebalancing, quota adjustments) and **Human-in-the-Loop** for high-impact actions (opening new positions, withdrawals, strategy changes). The agent runs autonomously within its bounded permissions, but when it needs to do something outside those bounds, it generates a preview URL for human approval. ## Learn More - [Human-in-the-Loop](https://docs.gearbox.finance/developers/ga-human-loop) — preview + verify flow for human approval - [Bot System](https://docs.gearbox.finance/developers/gm-bots) — detailed bot permission mechanics - [The Agent Loop](https://docs.gearbox.finance/developers/ga-agent-loop) — how execution fits in the 6-step cycle # Curator documentation Market-curator operations, configuration, governance execution, price feeds, adapter setup, and market activation. ## The Market Source: https://docs.gearbox.finance/curators/the-market File: content/curators/the-market.mdx ## Market Structure ### Market Structure Gearbox uses a hierarchical, tree-structured constraint model: Pools define global rules, Credit Managers inherit and specialize them, and Credit Accounts inherit both. Every node operates strictly within the envelopes defined by its ancestors, ensuring consistent risk and parameter discipline across all strategies. 1. **Pool (Global Constraint Layer):** Defines system-wide parameters: eligible collateral types, price sources, utilization curve, and global limits. All downstream components inherit these constraints. 2. **Credit Managers (Strategy Constraint Layer):** Each Credit Manager refines the global constraints into strategy-specific ones: position-level rules, leverage parameters, liquidation settings and more. Credit Manager configuration + Pool-level boundaries are applied to all the credit accounts. 3. **Credit Accounts (Execution Layer):** Individual accounts execute under both the global Pool constraints and the strategy-level constraints of their Credit Manager. ![Figure](https://docs.gearbox.finance/assets/docs/curators/the-market/01-market-structure.png) ### How Market Rules Shape Outcomes Understanding the rules at each level guides decision-making process for every participant: * **For lending users (LPs and borrowers)** * Constraints set the credit risk and expected yield for LPs. Tighter settings reduce risk and also reduce return. * Borrowers must operate within market parameters, so they should review the rules before taking leverage. * **For curators** * Constraints determine the target investors by fixing the risk and return profile on both supply and borrow sides. * **For asset issuers and applications** * Market configuration includes parameters that shape UX: external integrations, capital capacity, and liquidation discounts influence how end users experience the product. ### Market-specific rules #### Pool-level rules If a user disagrees with these terms, they need to select another pool. * **Total debt limit:** maximum that can be borrowed across the entire pool * **Collateral limit:** maximum that can be borrowed against each token * **Main Price Feed:** price source for calculating account value and triggering liquidations * **Reserve Price Feed:** runs safety checks on operations and can block Credit Account actions to protect LPs * **Increase Rate:** one-time fee whenever exposure to a collateral increases * **Collateral-specific rate:** extra interest for borrowing against a given collateral * **IRM:** utilization-based interest rate model * **Loss Policy:** additional liquidation logic for cases that create bad debt **Credit Manager-level rules** If a user disagrees with these terms, they can choose another Credit Manager within the same pool. * **Total debt limit:** maximum aggregate debt of all Credit Accounts created from this Credit Manager * **MinDebt:** minimum required debt for a Credit Account * **MaxDebt:** maximum permitted debt for a Credit Account * **Liquidation Premium:** portion of collateral value paid to the liquidator during liquidation * **Liquidation Fee:** portion of collateral value paid to the curator and Gearbox DAO during liquidation * **Max Enabled Tokens:** number of different collateral tokens that can count toward account value * **Interest Fee:** extra rate on top of the IRM and collateral-specific rate, split between the curator and DAO * **List of allowed collaterals and their LT** (loan to value) * **List of allowed adapters:** restricts which external contracts a Credit Account can use * **Expiration Policy:** curator may set an expiration; after the cutoff date, all Credit Accounts become liquidatable regardless of Health Factor with penalties set by the expired liquidation fee and premium parameters. ## Fee sharing Source: https://docs.gearbox.finance/curators/fee-sharing File: content/curators/fee-sharing.mdx ## Fee sharing ### What fees does Gearbox take? * Interest Fee\ Fee taken from the total interest paid by borrower. Paid when user repays debt * Liquidation Fee\ Fee taken from liquidated collateral *** ### Who set the fees value? Both Interest Fee and Liquidation fee is controlled only by a Curator. *** ### Accrued fees as insurance buffer Both Curator and DAO fees are accumulated on Treasury Splitter contract which is unique for every curator. Curator and DAO have to claim accrued fees from the contract. If a liquidation happens with bad debt, fees from Treasury Splitter contract are burnt to cover loss, so unclaimed fees act as an insurance buffer. *** ### How is the fee split between Curator and Gearbox DAO? All the fees taken by the protocol are split 50/50 between DAO and Curator by default. To change this proportion both Gearbox DAO and Curator should sign transactions on TreasurySplitter contract (requires DAO proposal). *** ### Practical considerations Both Interest and Liquidation fees are set on Credit Manager level. Some examples when it can be useful: * Charge 0% fee on first 5,000,000 USDC borrowed: * Create Credit Manager with limit of 5,000,000 and set its fee to 0% * Once the limit is reached set it to 0. It will allow existing CM users to stay at 0% while disallowing new positions to be opened * Create a new Credit Manager with nonzero Interest Fee keeping other parameters untouched. That will result in new users opening positions with nonzero fee. * Charge higher fee for borrowing at exclusive terms: * Create Credit Manager specifically for collaterals with boosts negotiated by curator * Projects issuing the collateral may have private lp deals or offer higher rewards for position opened for specified period of time. Curator may charge additional fee for bringing the opportunity to borrowers ![Figure](https://docs.gearbox.finance/assets/docs/curators/fee-sharing/01-fees.png) ## Deployment addresses Source: https://docs.gearbox.finance/curators/deployment-addresses File: content/curators/deployment-addresses.mdx ## Deployment addresses ### System contracts System contracts are deployed using [deterministic deployer](https://ethglobal.com/showcase/deterministic-deployer-p3eyi), thus have the same address on all EVM chains. | Contract | Address | |---|---| | Address Provider | 0xF7f0a609BfAb9a0A98786951ef10e5FE26cC1E38 | | Bytecode Repository | 0x1cE2B1BE96a082b1b1539F80d5D8f82Ec06a0f9A | | Cross-Chain Multisig | 0xcCCCCcCc42B7DA9fdEc1761698Fb55fdD41CDF55 | | Instance Manager | 0xBcD875f0D62B9AA22481c81975F9AE1753Fc559A | | Bot List | 0x0Bc03983Da93021a374C964A22b73865220Ce962 | | Price Feed Store | 0x74A868AC479EE145029bB80827BB77F7B7c441cB | | Market Configurator Factory | 0x7D60CfaF7c2cec210638A5e46E4000894830C034 | | GEAR Staking | 0x2fcbD02d5B1D52FC78d4c02890D7f4f47a459c33 | | Pool Factory | 0x2238eDf33a72860cDbaec5F83ec246Df9e85c8E2 | | Credit Factory | 0x81Cda0aB38d8Bd0732123Eb0e36C0C566d35DADD | | Price Oracle Factory | 0xF7533CDCE5A2F7BF78B6fbf4B05f04F45D10140B | | IRM Factory | 0xA7dE2e941c8818E51D1Fd84111d8F71dcafa6C3B | | Rate Keeper Factory | 0xbede127c14407b9c345f5d7fae5782ab8eaa33f3 | | Loss Policy Factory | 0x0E535b7D073a93646512cEa18fa7e650CC2b17C4 | | Batches Chain | 0x59b2fd348e4Ade84ffEfDaf5fcdDa7276c8C5041 | ### Helper (periphery) contracts | Contract | Address | |---|---| | Account Compressor | 0x4115708Fc8fe6bB392De2e0C21c2C81dA2222394 | | Credit Suite Compressor | 0x93Cba8445b13a05287bFf90D882cbcB514D617b7 | | Gauge Compressor | 0x12c8faEdD62cF0C5d4D742E57B98737a9a3F5E0f | | Market Compressor | 0x70F1753a765C4df582FFA3B8d96AB492714E8992 | | Periphery Compressor | 0xa7ED6dB5761613CaE7CaCfAAE9Dca07a77809F9d | | Price Feeds Compressor | 0x847a05C22c7508C674342A95356Adf9b3a0e0D57 | | Rewards Compressor | 0x19Ca61E672d1c6105f609418bfDC784F92F4Ecf0 | | Token Compressor | 0xAe3Dd11e5a7f99eD4cba2768D4095a55fbF7841B | | Router | 0x00aDE38841AB8c6e236E232041e43B41d74B8B45 | | DefiLlama Compressor | 0x81cb9eA2d59414Ab13ec0567EFB09767Ddbe897a | | Withdrawal Compressor | 0x36F3d0Bb73CBC2E94fE24dF0f26a689409cF9023 | ## Create a Market Source: https://docs.gearbox.finance/curators/create-a-market File: content/curators/create-a-market.mdx ### Prerequisites: The Price Feed Check Before creating a market, the underlying asset (the token you want lenders to deposit) must be whitelisted in the **Price Feed Store** of the current chain. **Check Availability:** 1. Go to the **Price Feed Store** section in the interface (click on the needed chain on [Instances page](https://permissionless.gearbox.foundation/instances)) 2. Search for your target token (e.g., USDC, WETH). 3. **If it exists:** Proceed to the steps below. 4. **If it is missing:** You must add it first. Guide: [add-required-price-feeds](https://docs.gearbox.finance/curators/add-required-price-feeds) ### Configuration Walkthrough []() ## Market Parameters 1 #### Asset & Identity * **Pool Version:** Select the latest verified version (currently **v3.1**). * **Underlying Asset:** Select the token lenders will deposit (e.g., USDC). * **Price Feed:** Select the Oracle feed used to value this asset. * **Market Name:** A descriptive name for your dashboard (e.g., "USDC Core Market"). 2 ## Global Capacity (Total Debt Limit) Max amount of underlying token that can be borrowed from entire pool. * **Tip:** Setting this higher than your immediate target TVL will help to avoid frequent updates. * *Note:* You will set more granular limits for specific strategies later. 3 #### Interest Rate Model (The Cost Engine) The IRM determines the base borrowing rate based on pool utilization. Gearbox uses a **Two-Kink Model** to create a stable "Optimal Zone" for utilization. **Key Parameters:** * **U1 (Optimal Low):** The start of your target utilization range. * **U2 (Optimal High):** The end of your target utilization range. * **R\_base:** The interest rate at 0% utilization (The minimum cost of capital). * **R\_slope1 / R\_slope2:** The rate increase as utilization rises to U1 and U2. * **R\_slope3 (Penalty):** The sharp rate spike after U2. This forces borrowers to repay if liquidity becomes scarce. **Strategy Tip:** A common approach is to target **80-85% utilization**. Set the borrow rate at this level to be roughly **60-70% of the expected yield** of the collateral strategies. This leaves a healthy spread for borrowers while attracting lenders.\ **Important: The Curator Fee is additive.**\ The Interest Fee (curator's & DAO's revenue) is charged **on top** of the rate paid to lenders. *Example:* If the IRM rate is **5%** and your Interest Fee is **20%**, the borrower pays **6%** total (5% to LPs + 1% Fee). Ensure your IRM leaves room for this markup while remaining competitive. * ***Reference:*** * [Desmos IRM visualizer](https://www.desmos.com/calculator/d281eeb4a9) * [Mainnet ETH pool](https://app.gearbox.fi/pools/0xda0002859b2d05f66a753d8241fcde8623f26f4f/utilization) * [Mainnet USDC pool](https://app.gearbox.fi/pools/0xda00000035fef4082f78def6a8903bee419fbf8e) 4 ## Rate Governance (The "Tumbler") This determines how you manage **Collateral-Specific Rates** (add-on fees for specific collaterals of increased demand). * **Type:** Select **Tumbler**. This allows the Risk Curator to manually update rates as needed. * **Epoch Length:** The mandatory waiting period between rate updates. * *Example:* If set to **2 days**, you can only adjust rates once every 48 hours. This gives borrowers predictability. 5 #### Safety (Loss Policy) This defines the logic for handling "Bad Debt" (when a position is insolvent even after liquidation). * **Policy Type:** Select **Aliased**. * **Function:** This protects Liquidity Providers during market de-pegs. If the market price of a collateral crashes (e.g., a flash crash), the system can switch to a "Fundamental Price" (e.g., Exchange Rate) to prevent selling collateral at a massive loss, effectively pausing liquidations until the market stabilizes. ### Next Steps The Liquidity Pool is now deployed. However, users cannot borrow yet because there are no **Strategies** (Credit Managers) attached to it. ## Execute transactions onchain Source: https://docs.gearbox.finance/curators/execute-transactions-onchain File: content/curators/execute-transactions-onchain.mdx This is the final step. With the market configured, parameters verified, and user experience tested, the changes are ready to be pushed to the live blockchain. ### The Timelock Lifecycle Gearbox governance enforces a **24-hour Timelock** on all critical changes. This security feature provides users time to exit if they disagree with a parameter change. Deployment consists of two distinct actions: 1. **Queue (Propose):** Submit the transaction to the Timelock contract. The 24-hour countdown begins. 2. **Execute (Apply):** After the countdown ends, submit a second transaction to apply the changes. 1 ### Finalize the Proposal Navigate to the GIP page in the interface. 1. **Finalize:** Click **"Finalize GIP"**. This locks the configuration and prepares the transaction data. 2. **Set Earliest Execution Date:** * The default timelock is 24 hours. * **Calculation:** `Current Time + Signing Buffer + 24 Hours`. * *Recommendation:* Add a buffer (e.g., 2 hours) to allow sufficient time for collecting signatures from multisig signers before the target execution time. **Troubleshooting:** If last-minute edits are required, click **"Reopen for Changes"**. Re-finalization is required after editing. ![Figure](https://docs.gearbox.finance/assets/docs/curators/execute-transactions-onchain/01-finalize-the-proposal.png) 2 ## Queue the Transaction The interface generates a link to the **Permissionless Safe App**. 1. Click the link to open the Safe App. 2. **Sign & Submit:** Execute the transaction in the Safe. This initiates the onchain timer. ![Figure](https://docs.gearbox.finance/assets/docs/curators/execute-transactions-onchain/02-queue-the-transaction.png) ### Video walkthrough []() 3 ## Execute (After 24 Hours) Once the timelock expires: 1. Return to the **Permissionless Safe App**. 2. **Sign & Submit:** Execute the final transaction. ### Video walkthrough []()
Learn more: Transaction lifecycle details ![Figure](https://docs.gearbox.finance/assets/docs/curators/execute-transactions-onchain/03-timeline.png)
### Deployment Complete The market is now live on the blockchain. * **New Pools:** Lenders can deposit assets. * **New Strategies:** Borrowers can open Credit Accounts. **Requirement:** Ensure the frontend PRs have been merged so users can view the new market and strategies in the app. * Review [frontend listing guide](https://docs.gearbox.finance/curators/listing-a-new-asset-in-the-main-app). ## Claim accrued fees Source: https://docs.gearbox.finance/curators/claim-accrued-fees File: content/curators/claim-accrued-fees.mdx Unclaimed fees sit in the protocol and act as a first line of defense against bad debt. If a liquidation results in a loss, the protocol can burn these accrued fees to cover the deficit before touching the Liquidity Pool. 1 ## Initiate a Proposal Navigate to the **Permissionless Interface**. 1. Click **"New GIP"** (or select an existing draft). 2. Select the **Market** you want to claim fees from. Then select a market you want to claim fees for. 2 ## Add Distribution Action 1. Go to the **Details** tab of the Market. 2. Locate the **Accrued Fees** section. 3. Click the **"Distribute"** button. * *Note:* This adds a transaction to your GIP batch. It does not execute immediately. ![Figure](https://docs.gearbox.finance/assets/docs/curators/claim-accrued-fees/01-add-distribution-action.png) 3 ## Execute via Timelock Like all governance actions, claiming fees is subject to the standard proposal lifecycle. 1. **Finalize** the GIP. 2. **Queue** the transaction in your Safe (starts the 24h timelock). 3. **Execute** the transaction after the timelock expires. Once executed, the funds will appear in your Fee Collector wallet. ## Create Credit Manager Source: https://docs.gearbox.finance/curators/create-credit-manager File: content/curators/create-credit-manager.mdx 1 ### Name Name can reflect the properties of collaterals and position size: * Volatile/ Correlated * Blue-chip/ Experimental * Small/ Medium/ Big (depending on account debt limit) Simple notation is calling naming it with tiers: Tier 1; Tier 2; Tier 3\ Higher tier means larger positions and safer collaterals. 2 ### **Interest Fee** % of borrowing interest taken by DAO and Curator\ Default fee split is 50/50 between DAO and Curator Interest fee of a Credit Manager ***can’t be changed*** after it’s deployed. Curator's fee is added ***on top of interest paid*** by borrower.\ If the IRM + [collateral-specific rate](https://docs.gearbox.finance/core/interest-rate-model#total-cost-of-capital) is 5% and the fee is 20% of the interest, then borrowers pay 6%. Interest fee & Credit Manager's debt limit can be used to ***bootstrap Market utilization.*** e.g. Create Credit Manager with limit of 5,000,000 USD and Interest Fee of 0% can be created to incentivize first borrowers as they will get more favorable borrow rates. 3 ### Liquidation Premium & Fee * **Premium -** % of liquidated collateral taken by liquidator Liquidation premium & fee of a credit manager can’t be modified after it’s deployed. * **Fee -** % of liquidated collateral taken by DAO and Curator It’s not recommended to set liquidation fee to be lower than 0.01%. If the fee is set to 0, then account that fully consists of leveraged underlying token will create bad debt upon liquidation. There is no impact of liquidation fee on the safety of liquidations (it doesn't increase or decrease probability of succesfull liquidations with profit). Borrower loses Liquidation Premium + Liquidation Fee from liquidation collateral. Expired liquidation premium and fee are useful only if Credit Manager is expirable, which is a rare case, so you can freely omit that parameters.\ If set, "Expired" versions of liquidation premium and fee are applied after Credit Manager expiration. 4 ### Minimum debt, Maximum debt, Max. enabled tokens * **Minimum & Maximum debt** - Credit account created in this Credit Manager can't have debt less than minimum and more than maximum. * **Max. enabled tokens** - maximal amount of different tokens that can be counted towards account value (used as cross-collateral margin). **maxDebt/minDebt <= 100/max enabled tokens**\ \ \&#xNAN;*Example: If max enabled tokens = 4 and minimum debt = 10k USDC, maximum debt can't be larger than 250k USDC.* 5 ### Whitelist policy, Expiration **Whitelist** - Allow borrowing only to owners of particular NFT. **Expiration** - Credit Manager can be shut down following specified schedule. May be useful for time-sensitive types of collaterals. 6 ### Total Debt Limit Maximal sum debt on all credit accounts created in this Credit Manager. Interest fee & Credit Manager's debt limit can be used to ***bootstrap Market utilization.*** e.g. Create Credit Manager with limit of 5,000,000 USD and Interest Fee of 0% can be created to incentivize first borrowers as they will get more favorable borrow rates. ## Configure Credit Manager Source: https://docs.gearbox.finance/curators/configure-credit-manager File: content/curators/configure-credit-manager.mdx ### ***Setup examples*** [setup example (BNB chain: USD1 pool, USDX collateral)](https://www.notion.so/Adapter-setup-example-BNB-chain-USD1-pool-USDX-collateral-208145c16224807fa1a0d318c01bc1ae?pvs=21) [setup example (Ethereum chain: tBTC pool, uptBTC collateral)](https://www.notion.so/Adapter-setup-example-Ethereum-chain-tBTC-pool-uptBTC-collateral-20e145c1622480c886d8d43dc5e9f5bb?pvs=21) [setup example (Ethereum chain: USDC pool, frxUSD/USDf collateral)](https://gearboxprotocol.notion.site/Adapter-setup-example-Ethereum-chain-USDC-pool-frxUSD-USDf-collateral-24c145c16224809d80d2d171e1128317?source=copy_link) ### ***Collaterals*** ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-credit-manager/01-collaterals.png) 1 #### ***Add new collateral*** Select token from those already added to Market. If not present, [add token to Market.](https://docs.gearbox.finance/curators/configure-market#add-new-asset-and-set-main-feed) Set LT of a collateral - Liquidation Threshold (same as Liquidation LTV on other lending protocols) LT can't be higher than 100% - liquidation Fee - liquidation Premium 2 #### Modify LT of existing collateral To protect borrowers from immediate liquidations, LT can't be changed immediately.\ LT ramping makes LT linearly change current LT to target LT over a specified period. The minimal Ramp duration is 2 days (172800 seconds). Ramp starts when transactions are executed onchain (duration of ramp can be set in UI). ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-credit-manager/02-modify-lt-of-existing-collateral.png) ### ***Adapters*** [***Detailed section on adapters configuration.***](https://docs.gearbox.finance/curators/configure-adapters) ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-credit-manager/03-adapters.png) ## Key concepts & system overview Source: https://docs.gearbox.finance/curators/key-concepts-system-overview File: content/curators/key-concepts-system-overview.mdx With permissionless architecture Gearbox has became even more composable, evolving into a techical stack that allows growing lending businesses, developing DeFi ecosystems and deploy lending markets on any chain by enyone having interest and capacity to do so. is the entrypoint for no-code deployment, curation and collaboration with Gearbox. #### What is permissionless? Anyone can deploy Market Configurator to create and manage Gearbox Markets without needing governance approval. #### What is Gearbox Market? Gearbox Market is a set of modular contracts allowing to facilitate lending, borrowing and productive usage of collaterals at rules set by Curator.\ Properties of a single market include but are not limited to Underlying Token, its Price Feed, Interest Rate Model, collateral-specific Limits and Additional Rates. #### What is Gearbox Instance? **Instance** = **Chain ID** activated by DAO for deployment + Chain-specific address of **DAO Treasury** + **Instance Owne**r multisig that helps configure chain-specific parameters but can't affect Markets configuration. #### What can curator change? The Curator can adjust all Market parameters, with a mandatory 24-hour timelock enforced at the smart-contract level for any changes. #### What is possible with permissionless curation? Each market consists of tens of contracts, including Pool, Oracle, IRM, Loss policy, Credit Managers and Adapters. Such modular architecture allows creating products with market-best flexibility and granular parametrization making Gearbox Protocol the premier platform for crafting sophisticated financial products that address specific market demands and drive long-term value creation. Below is a diagram of the contracts and parameters that a curator can configure, so you can get an idea of how detailed market configuration can be. ![Figure](https://docs.gearbox.finance/assets/docs/curators/key-concepts-system-overview/01-system.png) ## Curator's operations Source: https://docs.gearbox.finance/curators/curator-s-operations File: content/curators/curator-s-operations.mdx Morpho has pioneered the concept of curated lending markets in DeFi, but its approach differs significantly from Gearbox's model. Below is a clear comparison of how curators function in each protocol: #### Morpho: Active Capital Allocation In Morpho, curators are active capital allocators. They: * Distribute depositors' funds across various yield-generating markets. * Operate within markets defined by immutable parameters, such as Loan-to-Value (LTV) ratios and oracles. #### Gearbox: Risk Parameter Management In Gearbox, curators have a more limited role, focusing solely on risk management. They: * Set risk parameters for markets, such as LTV ratios or liquidation thresholds. * Have no authority to move or allocate depositors' funds, which remain under user or protocol control. | Action | Gearbox | Morpho | | ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Add exposure to new collateral |
  1. Set collateral limit, LTV and oracle for a new token in Market
  2. Borrowers can now use pool's liquidity
|
  1. Add nonzero supply cap for existing market (LTV and oracle are pre-configured)
  2. Deposit vault's funds to the new market
  3. Borrowers can now use vault's liquidity
| | Modify collateral LTV or Price Feed |
  1. Set new price feed
  2. Start ramp of LTV to target value
  3. Feed & LTV for old and new borrowers are changed
|
  1. Deploy a market with needed LTV and oracle and set nonzero supply cap for it
  2. Feed & LTV are changed only for new borrowers
  3. Start withdrawing liquidity from old market & push borrowers out by raising rate
| | Increase/decrease collateral-specific borrow rate |
  1. Set a new collateral-specific rate in addition to IRM utilization rate
|
  1. Move vault's allocation in/out of the Market to move dynamic IRM
| | Enable 1-click leverage for a collateral |
  1. Allow the list of needed adapters in the Market
|
  1. Contact contango or another strategy provider to integrate your collateral
| ## Curation plans Source: https://docs.gearbox.finance/curators/curation-plans File: content/curators/curation-plans.mdx This page does not impose any access restrictions. Instead, it serves as a guide for Curators, helping them navigate the process of building a lending business on Gearbox and making effective use of the technical stack built around permissionless contracts. The Gearbox Permissionless Governance contracts are designed to enable non-custodial use by anyone interested. The "tariffs" below serve only as an analogy to guide Curators in choosing the level of autonomy and customization that fits their goals, whether it's testing business ideas, expanding into new markets quickly, or fine-tuning every critical detail. ### Codebase usage | Feature | Basic | Professional | Enterprise | |---------|:-----:|:------------:|:----------:| | Build transactions to Create and Configure Markets using [Permissionless Interface](https://permissionless.gearbox.foundation/curators/) (PI), using all the Gearbox contracts that were signed by auditors in Bytecode Repository | ✅ | ✅ | ✅ | | Use Gearbox testing suite to simulate the state, test transactions and Front-End before launching Markets in production | ✅ | ✅ | ✅ | | Request additional integrations (adapters, price feeds) from Gearbox core developers | | ✅ | ✅ | | Develop and audit new pieces of code for specific needs | | | ✅ | ### Front-end | Feature | Basic | Professional | Enterprise | |---------|:-----:|:------------:|:----------:| | Get your personal Curator's domain (your_curator.gearbox.fi) | ✅ | ✅ | ✅ | | Get your Market and Strategies featured on app.gearbox.fi | | ✅ | ✅ | | Host your own version of Gearbox Front-end | | | ✅ | ### Fee sharing and Liquidity Mining incentives | Feature | Basic | Professional | Enterprise | |---------|:-----:|:------------:|:----------:| | Receive 50% of fees generated by curated markets | ✅ | ✅ | ✅ | | Receive $GEAR LM incentives for the Markets' deposits | | ✅ | ✅ | | Negotiate specific fee/token sharing with DAO | | | ✅ | ### Monitoring tools and Emergency permissions | Feature | Basic | Professional | Enterprise | |---------|:-----:|:------------:|:----------:| | Use Gearbox monitoring services to keep an eye on critical metrics (Optimistic Liquidator, Insolvency Monitor) or connect external products (Hypernative, etc.) | ✅ | ✅ | ✅ | | Use Emergency and Loss liquidators maintained by Gearbox core developers | ✅ | ✅ | ✅ | | Run own monitoring tools and liquidators | | ✅ | ✅ | ## Tooling for curators Source: https://docs.gearbox.finance/curators/tooling-for-curators File: content/curators/tooling-for-curators.mdx ## Essential tooling for curators Gearbox goes beyond providing just a protocol by offering a complete ecosystem of tools tailored for curators. These tools enable: * **Market Configuration**: Safely set up and manage lending markets with intuitive interfaces. * **Transaction Integrity**: Ensure the accuracy and security of transactions before they are executed onchain. * **Pre-Deployment Testing**: Test changes in a controlled environment to validate configurations and prevent errors. * **Multi-Chain Support**: Operate seamlessly on almost any EVM-compatible blockchain. #### Curation Supply Chain The curation supply chain in Gearbox is supported by a set of specialized tools designed to streamline market deployment and transaction management while prioritizing security and transparency. **Permissionless Interface** * **URL**: * **Purpose**: Enables curators to create transaction batches for market deployment and configuration using human-readable tables. The interface generates transaction data, which is uploaded to IPFS, with the Content Identifier (CID) signed by the GIP creator to prevent phishing. * **Note**: This interface can't modify onchain state directly; it consists both of a frontend and backend maintained by Gearbox contributors. Therefore it shouldn't be perceived as a final source of truth for onchain state or actions. ![Figure](https://docs.gearbox.finance/assets/docs/curators/tooling-for-curators/01-curation-supply-chain.png) **Permissionless Safe** * **URL:** [**https://safe.gearbox.finance/**](https://safe.gearbox.finance/) * **Repository**: * **Purpose**: An open-source, IPFS-hosted version of the Safe Multisig UI designed to review and sign transactions securely in a human-readable format. It eliminates backend dependencies to mitigate risks like Bybit-type attacks and performs checks of IPFS CID signature to prevent phishing. * **Note**: The open-source nature and IPFS hosting ensure users can verify the code's integrity. ![Figure](https://docs.gearbox.finance/assets/docs/curators/tooling-for-curators/02-curation-supply-chain.png) **Anvil Fork-Based Simulations** * **Purpose**: A unique Gearbox service that allows curators to test market configurations and transaction changes on a fork of the blockchain before onchain execution. This ensures the correctness of state changes and supports testing of various Gearbox components, including liquidators, routers, and frontends. ![Figure](https://docs.gearbox.finance/assets/docs/curators/tooling-for-curators/03-curation-supply-chain.png) ## Create a new Curator (Market Configurator) Source: https://docs.gearbox.finance/curators/create-a-new-curator-market-configurator File: content/curators/create-a-new-curator-market-configurator.mdx The **Market Configurator** serves as the central administration contract for a lending business. It acts as the root permission node. From this single point of control, Curators deploy new markets, adjust risk parameters, and manage fee distribution. This contract must be deployed once per blockchain network. ## Prerequisites **Separation of Drafting vs. Signing** The Gearbox Curation Interface is a **drafting tool**, not a signing terminal. * **Drafting:** You may connect **any** standard wallet (e.g., a hot wallet) to the Gearbox UI to configure parameters and generate transaction files. * **Signing:** The actual execution happens securely within the Gearbox Safe interface () * **Benefit:** Operations teams can draft complex updates without requiring the Admin/Signers to connect their high-security wallets to the web interface. **Recommendation for MPC Users (Fordefi, Fireblocks, etc.)** Institutional MPC wallets often lack direct support for batch transaction builders. * **Recommendation:** Deploy a **1/1 Safe Multisig** with your MPC address as the sole signer. * **Why:** This acts as a compatibility layer, allowing you to utilize the Gearbox Safe interface and transaction batching flow while retaining the custody security of your MPC provider. ## Deployment walkthrough **Access the Interface:** [https://permissionless.gearbox.foundation/curators](https://www.google.com/url?sa=E\&q=https%3A%2F%2Fpermissionless.gearbox.foundation%2Fcurators) []() 1 ## Define Governance Roles * **Admin Address:** * *Function:* Primary governance. Can modify all parameters subject to a **24-hour timelock**. * *Recommendation:* Main Safe Multisig (or 1/1 Safe for MPC users). * **Emergency Admin:** * *Function:* Crisis response. Can disable specific tokens and perform limited list of emergency actions instantly (bypassing timelock). * *Recommendation:* A separate Security Multisig or secure Hardware Wallet. * **Fee Collector:** * *Function:* Revenue destination. Receives all accrued interest and liquidation fees. * **Transaction Format:** * Select **SAFE** to generate a compatible JSON file.
UI walkthrough ![Figure](https://docs.gearbox.finance/assets/docs/curators/create-a-new-curator-market-configurator/01-define-governance-roles.png) ![Figure](https://docs.gearbox.finance/assets/docs/curators/create-a-new-curator-market-configurator/02-define-governance-roles.png)
2 #### Execute transactions in Safe UI The interface generates a JSON file containing the deployment bytecode. 1. Navigate to the **Safe App** (using the Admin wallet defined in Step 1). 2. Open the **Transaction Builder** application. 3. Upload the generated JSON file. 4. Review the transaction details and execute.
UI walkthrough ![Figure](https://docs.gearbox.finance/assets/docs/curators/create-a-new-curator-market-configurator/03-execute-transactions-in-safe-ui.png) ![Figure](https://docs.gearbox.finance/assets/docs/curators/create-a-new-curator-market-configurator/04-execute-transactions-in-safe-ui.png)
3 #### Sync Permissionless Interface Once the transaction is confirmed onchain, the Gearbox interface must index the new Configurator. 1. Navigate to the **Instances Page** on the Gearbox UI. 2. Select the relevant chain and click **Sync**. 3. Wait for the sync to complete. The new Market Configurator will appear in the dashboard.
UI walkthrough On Instances Page click on a chain where you've deployed Market Configurator ![Figure](https://docs.gearbox.finance/assets/docs/curators/create-a-new-curator-market-configurator/05-sync-permissionless-interface.png) Click on a Sync button and wait for Sync to end ![Figure](https://docs.gearbox.finance/assets/docs/curators/create-a-new-curator-market-configurator/06-sync-permissionless-interface.png)
### Next Steps With the Market Configurator deployed, the infrastructure is ready for the first lending Market. ## Allow leverage strategies Source: https://docs.gearbox.finance/curators/allow-leverage-strategies File: content/curators/allow-leverage-strategies.mdx ## What is a strategy? A **Strategy** (technically a "Credit Manager") is a specific credit product offered to borrowers. While the Pool holds the liquidity, the Strategy defines **how that liquidity can be used**. * *Example 1:* "Stablecoin Farming" (Low Risk, High LTV, Whitelisted Stablecoins only). * *Example 2:* "Memecoin Trading" (High Risk, Low LTV, Wide asset list). You can attach multiple Strategies to a single Pool, allowing to segment risk and offer different terms for different user behaviors. ## Prerequisites: The Strategy Library To make setup easy, Gearbox uses **Strategy Bundles**. These are pre-configured "recipes" organized by the **Collateral Token** you want to support. **How to check availability:** 1. Open the **New Strategy** tab in the interface. 2. **Search for the Target Token** you want users to leverage (e.g., search for `wstETH` or `sUSDe`). 3. **If the token appears:** A Strategy Bundle exists. Selecting it will automatically configure the necessary smart contract connections (Adapters) to enable leverage for that asset. 4. **If the token is missing:** A bundle for this specific asset hasn't been created yet. * *Action:* Contact Gearbox Contributors to request a new Strategy Bundle. ### How to add and configure a strategy 1 ## Click on a "New Strategy" tab ![Figure](https://docs.gearbox.finance/assets/docs/curators/allow-leverage-strategies/01-click-on-a-new-strategy-tab.png) 2 ## Select Strategy Search for your Target Token to allow leverage on. * *Note:* The bundle automatically handles the complex technical setup (Adapter configuration), so you only need to focus on the financial parameters. ![Figure](https://docs.gearbox.finance/assets/docs/curators/allow-leverage-strategies/02-select-strategy.png) **Liquidation Threshold (LT)**\ This determines the maximum leverage. * *Formula:* `Max Leverage = 1 / (1 - LT)` * *Example:* LT 90% = 10x Leverage. LT 80% = 5x Leverage. **Interest Fee (Revenue)**\ The percentage of the borrowing interest that is captured as revenue. * *Split:* By default, this fee is split 50/50 between Curator and the Gearbox DAO. * *Impact:* This is charged **on top** of the base rate. If the base rate is 5% and your fee is 20%, the borrower pays 6%. **Important:** In the current version, the Interest Fee percentage is fixed upon deployment. To change it later, you must deploy a new Credit Manager. **Growth Hack:** Set a **0% Interest Fee** initially to attract early users with cheaper rates, then launch a new "Premium" strategy later once you have traction. 3 ## Liquidation Economics These parameters ensure the system remains solvent by incentivizing third-party liquidators. **Liquidation Premium (The Bounty)**\ The percentage of collateral given to the liquidator as a reward. **Liquidation Fee (The Penalty)**\ The percentage of collateral taken by the Protocol (You + DAO) during a liquidation. **Risk Management Intuition:**\ The Liquidation Premium is not just a "fee", it is the **incentive** for liquidators to keep the protocol solvent by forcefully exchanging Collateral token for the Debt token.\ For the liquidations to happen organically, it must take multiple factors into account: 1. **Slippage:** The cost of selling the collateral on a DEX. 2. **Gas Costs:** The transaction fee to execute the liquidation. 3. **Time value of money + collateral risk:** If the asset is illiquid and/or has timelocked redemptions, liquidator will have to hold the collateral through redemption cycle. 4. **Oracle reliability:** Lending market values collateral by the oracle price, however "true" value at every given moment can differ with magnitude defined by oracle methodology and market conditions. 4 ## Position Limits **Min & Max Debt**\ Defines the size of accounts allowed in this strategy. * *Min Debt:* Must be high enough to cover gas costs for liquidators. (e.g., $10,000+ on Ethereum Mainnet). * *Max Debt:* Limits exposure to a single whale. **Max Enabled Tokens**\ The maximum number of different tokens a user can hold as collateral simultaneously. * *Rule of Thumb:* Keep this number low (1) for efficiency. In practice, users rarely use more than 1 unique collateral token. **Technical Constraint:**\ The protocol enforces a ratio between your debt limits and the token count to ensure liquidations are always mathematically possible. **Formula:** `maxDebt / minDebt <= 100 / maxEnabledTokens` *Example:* If you allow **4 tokens**, the ratio `100/4 = 25`. Therefore, your Max Debt cannot be more than **25x** your Min Debt.\ \&#xNAN;*(If Min Debt = 10k, Max Debt must be <= 250k).* 5 ## Lifecycle (Optional) If you are running a fixed-term lending product (e.g., a "Season 1" pool or a bond-like structure), you can configure expiration settings. **Expiration Date**\ The timestamp after which the strategy winds down. * *Behavior:* After this date, **all** accounts can be liquidated, regardless of their Health Factor. Borrowing is disabled. **Expired Premium & Fee**\ You can set different liquidation penalties that apply *only* after the expiration date. * *Use Case:* Usually set lower than standard penalties to minimize users' losses if market conditions allow it. 6 #### Review & Deploy Review the configuration summary. ![Figure](https://docs.gearbox.finance/assets/docs/curators/allow-leverage-strategies/03-review-and-deploy.png) ### Next Steps Now you need to ensure that the resulting market state matches with the expectations. The best way to do it is to simulate execution of the real transactions on chain fork. The Testing section will show how to do it. ## Verify & Simulate Source: https://docs.gearbox.finance/curators/verify-simulate File: content/curators/verify-simulate.mdx Before executing any transaction on the mainnet (which costs gas, time and operations), it's better to verify that configuration works as intended. Gearbox provides a **Simulation Service** (Fork Testing). The system spins up a temporary "Sandbox" copy of the blockchain, applies your changes, and runs a list of tests. ## Automated Safety Checks The simulation runs a suite of automated checks to ensure your parameters are safe and functional. You should review the output of these tests (typically provided in the GIP report or Interface). ## The "Staging" App (User Experience Test) Automated tests check the math, but they don't check the experience. The simulation service generates a temporary **Staging Frontend** connected to the Sandbox fork. **Action:** Open the Staging App link and act as a user. 1. **Connect Wallet:** Use a test wallet (the fork will impersonate your tokens). 2. **Open a Position:** Try to borrow funds using your new strategy. 3. **Execute a Trade:** Try to swap assets or deposit into a vault via the adapter. 4. **Close/Repay:** Ensure you can exit the position. **After the fork has been created and the tests have passed, you can open the App connected to the test blockchain state.** ![Figure](https://docs.gearbox.finance/assets/docs/curators/verify-simulate/01-the-staging-app-user-experience-test.png) #### Application test walkthrough []() ## Prepare the Main Interface Once the contracts are deployed, they exist on the blockchain, but the official Gearbox Interface (app.gearbox.finance) may not know the imporant data: token icon, collateral APY, the list of points earned by borrowers or suppliers. For the tokens and strategies to be supported by the app, ensure that frontend configuration has all the required data: [listing-a-new-asset-in-the-main-app](https://docs.gearbox.finance/curators/listing-a-new-asset-in-the-main-app) ## Next Steps If the simulations pass and the UI looks correct, you are ready to execute the transactions onchain. ## Price feeds' configuration Source: https://docs.gearbox.finance/curators/price-feeds-configuration File: content/curators/price-feeds-configuration.mdx The feeds configurations are reviewed at . It requires CID of txs file uploaded to IPFS. ![Figure](https://docs.gearbox.finance/assets/docs/curators/price-feeds-configuration/01-price-feeds-configuration.png) #### TL;DR (Actionable checklist) 1. Txs simulation must pass. Click on Simulate button next to each batch to check. 2. Check the displayed price in the multisig UI to adequatly match current market values 1. Review allowPriceFeed transactions. 2. Grab the token address and verify its price on a DEX aggregator () 3. If not tradable on aggregators, ask the proposer for the correct reference (e.g. Pendle UI for PTs, Curve UI for LP tokens, or the issuer’s app for derivatives/vaults) 4. Zero price feed (always returns $0) can be safely added to any token for compatibility. 3. Check staleness period of the feed 1. Pull feeds → 4 min staleness 2. Push feeds → Heartbeat + 15 min (Ethereum) / Heartbeat + 2 min (L2s & faster chains). 4. Check that the feed contract is verified 1. Confirm verification on the chain’s block explorer. 5. Check that feeds are adequately capped from above: 1. Stablecoin feeds are capped by $1.04 from above 2. PT feeds for dollar-pegged vaults are capped by $1 from above 6. If the feed is deployed from external factory, it should use no Pull feeds as underlying feeds of factory deployment. ⚠️ If any of these criteria aren’t met: don’t sign, ask in chat for clarification. ✅ For a setLimiter transactions it's enough to check that simulation passes. This action updates exchange rate bounds of LP price feeds, and its correctness is checked on a contract level. *** #### 1) Purpose & Scope These Terms & Conditions define the minimum due‑diligence and neutral‑gatekeeping standards for IO signers when **adding, configuring, or allowing** price feeds in the **Price Feed Store (PFS)** on any supported EVM chain. The sole goal is to ensure that, **at the moment of signing**, every configured feed **returns an adequate market price for the intended token, normalized to 8 decimals**, and satisfies staleness / quality constraints. > Scope explicitly excludes any market‑risk, business, or curation decisions. IO signers act only as neutral technical gatekeepers. *** #### 2) Authority, Membership & Neutrality (summary) * **Authority (PFS):** IO may add/remove feeds; set staleness period; attach/detach feeds to tokens; and run feed configuration calls required by integrated providers. * **Neutrality:** IO remains **business-neutral**. Decisions must be based **only on objective technical criteria** below. All valid, safe requests should be processed in a reasonable timeframe. * **Non‑interference with markets:** PFS changes **do not alter behavior of existing Markets by themselves** and **are not auto‑applied** to them. *** #### 3) Definitions & Expectations * **Price Feed Store (PFS):** Chain‑specific registry of tokens and feeds. A token can be used as collateral only after its token entry and at least one allowed feed are present. * **8‑decimal normalization:** All effective Gearbox price feeds **must return USD‑denominated prices with 8 decimals** (`1e8` scale). Signers should verify output scale when checking a feed. * **Staleness Period:** Maximum allowed time since last update before a feed is considered stale and reverts/invalidates. * **Adequate market price:** A price reasonably close to reputable sources at the time of signing. *** #### 4) Pre‑Signing Due‑Diligence (hard requirements) **Signers must complete all checks below before approving the transaction.** If any check fails, **do not sign.** **4.1 Contract & Deployment** 1. **Feed contract is verified** on a reputable explorer (Etherscan/chain explorer). 2. If the feed is not external, it must be deployed from Bytecode Repository. **4.2 Price Output & Decimals** 1. **Price sanity:** Read the feed (via explorer read panel, provider dashboard, or PFS UI). The value must be **within a reasonable range** of one or more of: 1. **CoinGecko** (or equivalent public index), 2. **Trusted DEX/aggregators** (Uniswap/Curve/Balancer; 1inch/Cow/Odos), 3. **Designated platforms** when public indexes are unavailable (e.g., **Pendle markets** for PTs; **Pyth Insights**; **Redstone App**; protocol UIs for ERC4626 vault exchange rate). 2. **Decimals:** Confirm that the effective price value is **normalized to 8 decimals**. **4.3 Staleness** 1. **Staleness period** must be reasonable for the source and chain: 1. **Pull‑type feeds (e.g., Pyth/Redstone pull):** *recommended* `240s` (4 min) unless documented otherwise. 2. **External Aggregator feeds (push/heartbeat):** heartbeat **+ 15 min** (slower chains, e.g. Ethereum) or **+ 2 min** (faster chains, e.g. L2s). **4.4 Asset‑Specific Parameters (when applicable)** 1. **Stablecoin‑to‑USD feeds:** The observed price should be **bounded from above at 1.04**. 2. **Pegged assets feeds (LST-to-ETH, LRT-to-BTC, cbBTC-to-BTC etc.):** The observed ratio should be **bounded from above at 1.04**. *** #### 5) Refusal Policy If **any** requirement in fails or is inconclusive, **do not sign any transactions**. Examples: * Contract not verified; * Output not 8‑decimals normalized; * Price materially diverges from reputable venues; * Staleness period unreasonable for the source/chain; * Asset‑specific parameters missing/incorrect. *** ### Asset classes Asset class is a pair of (token-specific features, price feed methodology) which defines the behavior of collateral in different market scenarios. The same token can have different risks for LPs/Borrowers if priced differently. All of the tokens can be borrow-only or used as collaterals. \ Consider cases of * Correlated debt/collateral pairs * Volatile debt/collateral pairs Describe the policy of setting reserve feeds and aliased loss policy. Take into account that pull feeds providers (pyth and especially redstone) can be less reliable than push Some of the used feeds can be provided by token issuer itself (for example Resolv PoR, midas feeds etc.) and have no strict update frequency (we've seen Resolv update PoR feeds 2 hours later than was initially stated) 1. Stablecoins/ synthetic dollars\ USDT, USDe, USDai, DAI, USDf etc. 2. ETH or BTC equivalents 1. stETH, tBTC etc 3. Yield-bearing vaults\ Stream.finance xUSD, Midas vaults, tETH, LRTs etc. 1. Priced using ERC4626 feeds 2. Priced using composite feeds (prices can be market-based, exchange rate or PoR) 4. Pendle PT tokens 1. TWAP-based pricing or deterministic feeds 5. Curve, Balancer LP tokens 1. For the tokens having rate oracle or erc4626 vault attached in Curve or Balancer pools, oracle price appreciation is automatically displayed in virtual\_price 6. Pendle LP tokens 1. TWAP-based pricing or deterministic feeds 7. Delayed withdrawal phantom tokens 1. Since delayed withdrawal tokens are not liquidatable, the most favorable setting is when the position's HF is high enough not to fall below 1 due to accrued debt while redemption is being processed.\ \ One of the ways to achieve it is to set reserve feed of withdrawal token to be lower than its Main feed by some percentage. This percentage will effectively enforce the minimal health factor for user to have to initiate delayed withdrawal.\ \ Reserve to main price discount of 2% will mean that user has to maintain HF above \~1.02 to initiate full withdrawal of his collateral. ## Instance activation guidlines Source: https://docs.gearbox.finance/curators/instance-activation-guidlines File: content/curators/instance-activation-guidlines.mdx #### TL;DR (Actionable checklist) 1. Chain's block Gas Limit ≥ 30M (it's possible to execute transaction that uses 30M gas) 2. Canonical safe proxy factory v1.4.1 (0x4e1DCf7AD4e460CfD30791CCC4F9c8a4f820ec67) is verified 3. $GEAR address is either null or can be verified on block explorer to be $GEAR token correctly bridged from Ethereum 4. Wrapped Gas Token address is listed on Chain's docs as canonical 5. Instance Owner Safe Proxy is deployed on target chain and can be verified on block explorer 6. Financial Multisig Safe Proxy is deployed on target chain and can be verified on block explorer ⚠️ If any of these criteria aren’t met: don’t sign, ask in chat for clarification. > Chain sync process involves uploading all the bytecode of used contracts to Bytecode Repository (like onchain github for secure deployment of all the modules)\ \ Here is an example of sync txs on Optimism: \ \ The process is gas- and txs- extensive, and requires \~400M of gas and RPC with 10k blocks per getLogs request. ## Listing a new asset in the main App Source: https://docs.gearbox.finance/curators/listing-a-new-asset-in-the-main-app File: content/curators/listing-a-new-asset-in-the-main-app.mdx Once the market contracts are deployed onchain, the Gearbox Interface (`app.gearbox.fi`) must be updated to display them. The official interface is maintained by Gearbox Contributors. To accelerate the listing process, Curators can submit a **Pull Request (PR)** to the configuration repositories. This provides the development team with the necessary data (icons, addresses, APY sources) in a ready-to-merge format. ## Prerequisites 1. **GitHub Account:** Required to submit changes. 2. **Asset Icons:** High-quality `.svg` files for the underlying token and any reward tokens. 3. **Contract Addresses:** The addresses of the deployed Credit Managers. 4. **APY Data Sources:** Links to DefiLlama or Merkl pools (if applicable). 1 ## Upload Asset Icons **Repository Location:** **Instructions:** * Format: `.svg` (Strict requirement). * Naming: **Lowercase symbol** (e.g., `susde.svg`, `wsteth.svg`).
Asset display example ![Figure](https://docs.gearbox.finance/assets/docs/curators/listing-a-new-asset-in-the-main-app/01-upload-asset-icons.png)
**Merkl Campaigns:** If the strategy earns rewards via Merkl, the reward token icon must also be uploaded, or the APR tooltip will break.
Merkl display example ![Figure](https://docs.gearbox.finance/assets/docs/curators/listing-a-new-asset-in-the-main-app/02-upload-asset-icons.png)
2 ### Configure Lending Pools (Earn Page) If a new Liquidity Pool was deployed, it must be added to the "Earn" page configuration. **Repository Location:** **Fill in the following fields:** * `name`: The displayed name (e.g., "Edge UltraYield USDC"). * `address`: The contract address of the Liquidity Pool. * `chainId`: The integer ID of the network (e.g., `1` for Mainnet, `42161` for Arbitrum). * `network`: The string name of the network (e.g., "Mainnet", "Arbitrum"). * `curator`: The entity managing the pool. * *Constraint:* This must match a valid `Curator` type defined in the [Gearbox SDK](https://github.com/Gearbox-protocol/sdk/blob/master/src/sdk/chain/chains.ts). * `poolType`: The category tag (e.g., `["stable"]`, `["eth"]`). * *Constraint:* This must match a valid pool type defined in the [Pools type list](https://github.com/Gearbox-protocol/static/blob/main/src/core/pools.ts). 3 ### Configure Strategies (Farm Page) If new Credit Managers (Strategies) were deployed, they must be added to the "Farm" page configuration. **Repository Location:** **Fill in the following fields:** * `name`: The display name (e.g., "Lido staked ETH"). * `id`: The token symbol (e.g., "susde"). This serves as the unique key. * `tokenOutAddress`: The address of the collateral token. * `creditManagers`: An array containing the addresses of all Credit Managers that support this strategy. * *Example:* `["0xCM_Address_1", "0xCM_Address_2"]` * `strategyType`: The category tag (e.g., `["stable"]`, `["eth"]`). * *Constraint:* This must match a valid strategy type defined in the [Strategy types list.](https://github.com/Gearbox-protocol/static/blob/main/src/core/strategy.ts) * `issuesOnClose`: Set to `true` if the asset has delayed redemptions or requires extra capital to close (prevents users from getting stuck). 4 ## Connect Yield Data (APY) #### Option A: DefiLlama Integration If the underlying protocol is tracked on DefiLlama. **Repository Location:** * **Action:** Add the DefiLlama Pool ID to the configuration map. #### Option B: Merkl Integration If the strategy earns incentives via Merkl. **Repository Location:** * **Action:** Add the Merkl Campaign parameters to the relevant Network object (e.g., `Plasma`, `Monad`). * **Key:** The token address (e.g., `"0x2d84..."`). * **Value Object:** * `id`: The token address(repeated). * `symbol`: Token symbol (e.g., `"USDT0USDe"`). * `type`: Usually `"common"`. #### Option C: Points Campaigns If the strategy or pool earns points (e.g., Ethena Sats, EigenLayer Points), the configuration is split into three parts. **1. Register the Point Type**\ If this is a new point system, define it in the base configuration. * [**Path**](https://github.com/Gearbox-protocol/apy-server/blob/92bf265744b95ecf7ce85da67278b27a71229691/src/tokens/points/constants.ts#L58) * **Action:** Add a new entry to `REWARDS_BASE_INFO`. ```typescript somnia: (multiplier: PointsReward["multiplier"]): PointsReward => ({ name: "Somnia", units: "points multiplier", multiplier, type: "somnia", }), ``` **2. Apply to Strategies (Farm Page)**\ If the points are earned by holding collateral (e.g., weETH). * [**Path**](https://github.com/Gearbox-protocol/apy-server/blob/92bf265744b95ecf7ce85da67278b27a71229691/src/tokens/points/constants.ts#L276C14-L285C7) * **Action:** Add the collateral address to `POINTS_INFO_BY_NETWORK`. ```typescript { address: "0xCollateralAddress...", symbol: "weETH", rewards: [REWARDS_BASE_INFO.etherfi(200n)], // 200n = 2x Multiplier }, ``` **3. Apply to Pools (Earn Page)**\ If the points are earned by depositing into a lending pool. * **File:** * **Action:** 1. Add the Pool Address to `const POOLS`. 2. Add the Token Address to `const TOKENS`. 3. Add the Reward Logic to the Network array. ```typescript { pool: POOLS.USDC_E_V3_SOMNIA, token: TOKENS.USDC_E_SOMNIA, symbol: "USDC.e", amount: 12n * 1000n, // 12n * 1000n = 1.2x Multiplier duration: "day", name: `${REWARDS_BASE_INFO.somnia(1n).name} ${REWARDS_BASE_INFO.somnia(1n).units}`, type: REWARDS_BASE_INFO.somnia(1n).type, estimation: "absolute", condition: "holding", }, ``` ## Emergency admin Source: https://docs.gearbox.finance/curators/emergency-admin File: content/curators/emergency-admin.mdx UI for executing Emergency Admin function is located at [https://permissionless-safe.gearbox.foundation/emergency/](https://permissionless-safe.gearbox.foundation/emergency/) ### Why is it needed? The Emergency Admin role has a very limited set of actions that can be executed immediately, without a timelock. These actions are designed to let curators respond quickly to incidents and protect the solvency of the market. *** ### How to add an emergency admin? Only one address can have Emergency Admin role. It is set at the moment of creating a Market Configurator. It can be configured in Curators' UI for the existing Market Configurator: []() *** ### What are the available functions, its scope and impact? | Action | New positions | Borrow | Withdraw | Adapter call | Liquidate | |---|---|---|---|---|---| | Token Limit = 0 Impact: Asset (Pool) | ❌ | ⚠️ | ✅ | ✅ | ✅ | | Forbid Adapter Impact: Adapter (CM) | ⚠️ | ✅ | ✅ | ❌ | ⚠️ | | CM debt limit = 0 Impact: CM | ❌ | ⚠️ | ✅ | ✅ | ✅ | | Forbid borrowing Impact: CM | ❌ | ❌ | ✅ | ✅ | ✅ | | Set Main Feed Impact: Asset (Pool) | ✅ | ✅ | ⚠️ | ⚠️ | ⚠️ | | Forbid Token Impact: Collateral (CM) | ❌ | ❌ | ❌ | ❌ | ✅ | | Pause CM Impact: CM | ❌ | ❌ | ❌ | ❌ | ❌ | | Pause Pool Impact: Pool | ❌ | ❌ | ❌ | ❌ | ❌ | *** ### Emergency scenarios
Collateral token incident * **Low severity** *(incident status is unclear)* * **Set token limit = 0** in Pool * Collateral exposure can't be increased * Existing positions operations are not limited * **Medium severity** *(collateral behavior is unhealthy, but no immediate bad debt risk)* * **Forbid token** in Credit Manager * Collateral exposure can't be increased * Existing positions operations are limited * Operations which decrease HF are blocked (increase debt, withdraw collateral, swap into different collateral with lower LT) * Operations which increase balance of forbidden token are blocked * **High severity** *(collateral poses risk to market solvency)* * **Pause** all Credit Managers which have exposure * No user-side operations are allowed * Only emergency liquidators can liquidate accounts
Price feed incident #### **Overpricing token** * **Feed price is higher than market price enough to block liquidations**\ In cases when price feeds deviates from market price by more than liquidation premium, liquidations become unprofitable. * **Low severity** *(existing positions create no insolvency risks)* * Set **Token Limit = 0** in Pool to limit increasing exposure to Asset. * Consider creating a new Credit Manager with higher liquidation premium. * **High severity** *(existing positions create risk to market solvency)* * **Set Main Feed** of token to one that is closer to market value. * This action will reduce Health Factor of existing positions which may result in immediate liquidations. * If the new Main feed is equal to current Reserve feed, reserve feed will be automatically detached from token, which will block operations relying on Safe Price (Collateral withdrawals, Usage of adapters, Partial Liquidations). * **Feed price is higher than market price enough to drain Pool**\ In cases when price feeds higher than market price by more than 1/LT of a token, one can buy token on secondary market and borrow more than was the cost, repeating it until "buy" liquidity or the pool is exhausted.\ \ \&#xNAN;*This risk is mitigated if at least one of Main and Reserve feeds returns adequate value, as the token at risk will be priced at minimal price during collateral withdrawals.* * **High severity** * **Forbid token** in Credit Manager * Collateral exposure can't be increased * Existing positions operations are limited (users can only fully close accounts)
External protocol incident **An external contract that is used through Adapter may appear to be misconfigured, hacked or is a proxy contract having its implementation replaced for an unsafe one.** Call **Forbid Adapter** for every Credit Manager which has the adapter allowed.
#### Emergency Methods Definitions **Token‑Specific** **`setTokenLimit(token, 0)`** * **Impact Scope:** Pool * Sets the quota limit for a token to zero. * Users cannot increase quota in that token, meaning new exposure to collateral can't be created. * Withdrawals, debt increases, and adapter calls for existing positions remain enabled. **`forbidToken(token)`** * **Impact Scope:** Credit Manager * Highly ***Restricts allowed operations*** for accounts. * Operations which decrease HF are blocked (increase debt, withdraw collateral, swap into different collateral with lower LT) * Operations which increase balance of forbidden token are blocked * **Liquidations** are not impacted. **Feed‑Specific** **`setMainPriceFeed(token, feed)`** * Switches the main price feed of a token to another feed pre‑approved in the Price Feed Store. * Target feed must have been added at least 1 day earlier. * **Side effects:** * If the new main feed equals the current reserve feed, the reserve feed is removed (token ends up with only one feed). * New main price may be low enough to trigger immediate liquidations of Credit Accounts. **Adapter‑Specific** **`forbidAdapter(adapter)`** * Disables calls through a specific adapter. * Prevents swaps on DEXes, vault deposits/withdrawals, etc. * **Side effects:** * If the forbidden adapter highly contributes to some tokens' liquidity, forbidding it may break liquidations, since most of Gearbox's internal liquidators rely on allowed adapters for searching tokens' swap paths. External liquidators may or may not be affected. **Pool‑Global** **`pausePool(pool)`** * Pauses pool‑level operations (deposit into pool, withdraw LP tokens) * Designed to be combined with Credit Manager pause to prevent bank runs in the most extremal scenarios. **`setCreditManagerDebtLimit(cm, 0)`** * Sets the Credit Manager debt limit to zero. * Prevents new borrowing capacity from the pool into that CM. Existing positions are not affected. **Credit Manager‑Global** **`pauseCreditManager(cm)`** * Pauses all Credit Manager operations. * Borrowing, withdrawing collateral, opening & closing credit accounts, performing adapter calls are blocked. * Only whitelisted **Emergency Liquidators** can liquidate accounts. **`forbidBorrowing(cm)`** * Forbids opening new accounts in the CM. * Prevents increasing debt in existing accounts. **Loss Policy** **`setAccessMode(mode)`** * Adjusts who can execute liquidations which result in bad debt accrual. * Modes must be documented (TBD). **`setChecksEnabled(flag)`** * Enables/disables specific safety checks within loss policy. ## Pausable/Unpausable admin Source: https://docs.gearbox.finance/curators/pausable-unpausable-admin File: content/curators/pausable-unpausable-admin.mdx > ### UI for executing Pausable admin functions is located at Pausable admin can pause active **Pools** and **Credit Managers.** Unpausable admin can unpause paused **Pools** and **Credit Managers.** > Pausable admin is a sensitive role, but its permissions are softer that unpausable admin.\ \ You can set **pausable admin** to be **EOA** to be able to react quickly, but **unpausable admin should be a multisig**. *** ## Multipause Multipause is a helper contract that allows pausing multiple Market contracts in one transaction. > For multipause contract to function, you need to add a Multipause contract and at least one Pausable admin to the list. ## How to add admins and multipause []() *** *** ## Functions definition **`Pause Pool(pool)`** * Pauses pool‑level operations (deposit into pool, withdraw LP tokens) * Designed to be combined with Credit Manager pause to prevent bank runs in the most extremal scenarios. **`Pause Credit Manager(cm)`** * Pauses all Credit Manager operations. * Borrowing, withdrawing collateral, opening & closing credit accounts, performing adapter calls are blocked. * Only whitelisted **Emergency Liquidators** can liquidate accounts. **`Pause Market (cm)`** * Pause Pool and all Credit Managers of a Market. **`Pause All Contracts (mc)`** * Pause all Pool and all Credit Managers of a Market Configurator. *** ## How to pause contracts Source: https://docs.gearbox.finance/curators/how-to-pause-contracts File: content/curators/how-to-pause-contracts.mdx 1 ### Navigate to emergency dashboard & Select Curator 2 ### Pause needed contracts ![Figure](https://docs.gearbox.finance/assets/docs/curators/how-to-pause-contracts/01-pause-needed-contracts.png) * `Pause CM` * Forbid all operations with credit accounts within a CM * Liquidations are allowed to whitelisted emergency liquidators * `Pause pool` * *Forbid deposits and withdrawals* * `Pause market` * *Pause pool and all CMs* * `Pause all contracts` * *For each market:* * *Pause pool and all CMs* ## How to unpause contracts Source: https://docs.gearbox.finance/curators/how-to-unpause-contracts File: content/curators/how-to-unpause-contracts.mdx ## Unpause Credit Manager 1 ### Navigate to the curator's page ### 2 ### Create a new GIP, select a Market and go to the paused Credit Manager's page Add unpause transaction and execute GIP ![Figure](https://docs.gearbox.finance/assets/docs/curators/how-to-unpause-contracts/01-create-new-gip-select-market-go-paused-credit-manager.png) ## Unpause Pool 1 ### Navigate to the curator's page ### 2 ### Create a new GIP, select a Market and go to Details section Add unpause transaction and execute GIP ![Figure](https://docs.gearbox.finance/assets/docs/curators/how-to-unpause-contracts/02-create-new-gip-select-market-go-details-section.png) ## Add required Price Feeds Source: https://docs.gearbox.finance/curators/add-required-price-feeds File: content/curators/add-required-price-feeds.mdx ### Price Feed Store (PFS) The Price Feed Store is a chain-specific registry that lists which tokens and price feeds can be used within Gearbox on that chain. For a token to be used as collateral, it must first be added to the Price Feed Store, along with a list of available price feeds. Only the **Instance Owner**—a chain-specific multisig—can add or update entries in the Price Feed Store. This role acts as a neutral technical gatekeeper, ensuring safe and verified configurations while staying out of risk or business decisions. The Instance Owner multisig is open to participation from active curators and chain contributors, making the process transparent and inclusive without compromising protocol safety. ### How to work with PFS? Interface for accessing each chain's PFS is located at [https://permissionless.gearbox.foundation/instances](https://permissionless.gearbox.foundation/instances/1). **Demo of PFS setup workflow:** []() ### What price feed sources are already integrated? *(Click on feed to see details)* | Price source | Feed type | Supported collaterals & features | |---|---|---| | [Chainlink, Redstone push, EO AggregatorV3Interface - compatible external price providers](https://docs.gearbox.finance/curators/add-required-price-feeds#external-feeds) | External | Blue-chip tokens | | [ERC4626 exchange rate](https://docs.gearbox.finance/curators/add-required-price-feeds#erc4626-exchange-rate) | ERC4626 | Most of the yield-bearing vaults | | [Pyth](https://docs.gearbox.finance/curators/add-required-price-feeds#pyth) | Pyth | Blue chip & emerging tokens | | [Redstone pull](https://docs.gearbox.finance/curators/add-required-price-feeds#redstone-pull) | Redstone | Deployed on any EVM on day 0 | | Upper bound | Bounded | Bound borrowed tokens to protect borrowers from liquidationsBound collateral tokens to protect LPs from price manipulation | | Multiply 2 feeds price | Composite | Optimal way to price correlated token pairs | | Constant price | Constant | Hardcode pegged assetsApply premium or discount combining with composite feed | | [Curve LP](https://docs.gearbox.finance/curators/add-required-price-feeds#curve-stable) | Curve_crypto Curve_stable | Collateralize Curve LP tokens | | Token price from Curve Pool | Curve TWAP | Collateralize experimental tokens with pricing based on DEX trades | | [Pendle PT](https://docs.gearbox.finance/curators/add-required-price-feeds#pendle-pt) | Pendle PT TWAP | Get TWAP market price of PTs | | [Kodiak Island](https://docs.gearbox.finance/curators/add-required-price-feeds#kodiak-island) | Kodiak_island | Get island share price | ### Updatable LP bounds Some tokens in Gearbox are tokenized vault shares — they represent ownership of assets inside a vault or liquidity pool. Examples include: * Vault tokens like ERC-4626 share tokens * LP tokens from DEXs or yield strategies **How pricing works:** * Each share has an exchange rate to its underlying asset (e.g., 1 share = X ETH). * The LP price feed combines: * the share price from the vault, and * the USD price of the underlying asset. **Why bounds are needed:** * Vault share prices can be manipulated or distorted through smart-contract exploits. * Normally, share prices move slowly and predictably with yield — not like volatile traded tokens. **To protect against abnormal price swings, Gearbox sets updatable bounds:** * A minimum and maximum price for each LP share. * These bounds cap sudden drops or spikes in reported prices. * They are updated periodically to track the vault’s real exchange rate as it appreciates over time. This mechanism keeps LP pricing stable, reliable, and manipulation-resistant while still following genuine on-chain growth. *** ### Setup details
Pyth **Click New Feed and select Pyth type** ![Figure](https://docs.gearbox.finance/assets/docs/curators/add-required-price-feeds/01-setup-details.png) ***Pyth dashboard with feeds info:*** [***https://insights.pyth.network/price-feeds***](https://insights.pyth.network/price-feeds) * Name: * Specify token Symbol and Price methodology * Examples: * Name: RLP (Redemption rate)\ Feed: * Name: RLP (Market)\ Feed: * Token: * Token address\ Needed for Gearbox contracts to understand what pull feed needs to be updated * descriptionTicker * The same as name\ This parameter is to be removed later * priceFeedId ![Figure](https://docs.gearbox.finance/assets/docs/curators/add-required-price-feeds/02-setup-details.png) * Pyth * Address of Pyth singleton contract on the target chain\ see here: * Ethereum - 0x4305FB66699C3B2702D4d05CF36551390A4c69C6 * Berachain - 0x2880aB155794e7179c9eE2e38200202908C17B43 * Etherlink - 0x2880aB155794e7179c9eE2e38200202908C17B43 * maxConfToPriceRatio (takes value in bps: 300 = 3%) * Except for the current price, Pyth returns confidence interval * If the width of confidence interval in % is larger than this parameter, feed ourput is considered invalid causing tx revert * Example (consider maxConfToPriceRatio = 3%) * Valid price: * Price: 3000 * Confidence interval: 15 * confToPriceRatio = 15/3000 = 0.5% * Invalid price: * Price: 3000 * Confidence interval: 120 * confToPriceRatio = 120/3000 = 4% * Staleness Period * Gearbox contracts track the timestamp of last Feed's update\ If the update happened more than Staleness Period seconds ago, feed value should be updated or the contracts will revert * Recommended value for Pull feeds: 240s = 4min Right after a new Pyth feed is deployed it's required to send 0.000001 ETH to its address. Without it won't function and can't be added to Price Feed Store.
External feeds **Click New Feed and select External type** ![Figure](https://docs.gearbox.finance/assets/docs/curators/add-required-price-feeds/03-setup-details.png) ***Dashboards of external providers:*** * *Redstone:* [***https://app.redstone.finance/app/feeds/***](https://app.redstone.finance/app/feeds/) * *Chainlink:* [***https://docs.chain.link/data-feeds/price-feeds/addresses?page=1\&testnetPage=1***](https://docs.chain.link/data-feeds/price-feeds/addresses?page=1\&testnetPage=1) * *EO:* [***https://docs.eo.app/docs/eprice/feeds-addresses/price-feed-addresses***](https://docs.eo.app/docs/eprice/feeds-addresses/price-feed-addresses) * *Some* *protocols may provide custom feeds compatible with AggregatorV3Interface* * [*Resolv*](https://docs.resolv.xyz/litepaper/for-developers/smart-contracts/price-oracles) * [*Midas*](https://docs.midas.app/defi-integration/price-oracle) #### *Config parameters:* * Name: * Specify token Symbol and Provider name * Examples: * USDC (Chainlink) * hemiBTC (EO) * ETH (Redstone Push) * mTBILL (Midas NAV) * priceFeedAddress * Address of deployed feed * Staleness Period (in seconds) * Gearbox contracts track the timestamp of last Feed's update\ If the update happened more than Staleness Period seconds ago contracts will revert\ \ \&#xNAN;***Motivation**: If the feed with heartbeat of 24 hours wasn't updated in the last 30 hours, smth bad happened with the oracle providers and protocol operations are blocked waiting for Curator to interfere* * Recommended value: * Heartbeat + 15 minutes for slower chains (Ethereum) * 87 300s = 24h + 15min * Heartbeat + 2 minutes for faster chains * 86 520s = 24h + 2min
ERC4626 exchange rate *This contract fetches mint/redeem rate from specified erc4626 vault and multiplies it by the underlying feed output to return the vault shares' USD price.* **Click New Feed and select ERC4626 type** ![Figure](https://docs.gearbox.finance/assets/docs/curators/add-required-price-feeds/04-config-parameters.png) #### *Config parameters:* * Name: * Specify token Symbol and underlying feed price Provider name * Example: * Name: sDAI (Chainlink)\ Will mean that this feed takes ERC4626 sDAI/DAI exchange rate directly from sDAI contract + DAI/USD price from Chainlink * Vault: * Address of ERC4626 vault to fetch mint/redeem rate from. * underlyingPriceFeed: * Select existing price feed * Example: * If the specified vault it sUSDe, then underlying price feed should return USDe/USD price. To understand what asset's feed should be passed as underlying, go to the ERC4626 vault contract and call its ***asset()*** method — you will get the address of the token which is vault's underlying.
Redstone pull **Click New Feed and select Redstone type** ![Figure](https://docs.gearbox.finance/assets/docs/curators/add-required-price-feeds/05-config-parameters.png) #### *Config parameters:* * Name: * Specify token Symbol and Price methodology Examples: * Name: ezETH (Market)\ Feed: * Name: ezETH (Fundamental)\ Feed: * Token: * Token address\ Needed for Gearbox contracts to understand what pull feed needs to be updated * descriptionTicker * The same as name\ This parameter is to be removed later * dataServiceId * Most likely should be kept untouched\ Internal variable for non-standard sources of redstone data * dataFeedId * The same as Symbol in Redstone UI ![Figure](https://docs.gearbox.finance/assets/docs/curators/add-required-price-feeds/06-config-parameters.png) * signersThreshold * Minimum amount of signatures from Redstone nodes to have for the feed's result to be deemed valid. * Redstone currently have maximum of 5 nodes. * The safest option is to set this value to 5 (this was historically used in Gearbox), but sometimes couple of Redstone nodes may stop working for a short periods of time. * Signer 1/2/3/4/5 * Most likely should be kept untouched\ Redstone have fixed list of signers' addresses that rarely (if ever) changes
Kodiak island **Click New Feed and select Kodiak\_island type** ![Figure](https://docs.gearbox.finance/assets/docs/curators/add-required-price-feeds/07-config-parameters.png) #### *Config parameters:* * Name: * Specify token Symbol and sources of Underlying Prices\ Example: * Name: iBERA-iBGT (Pyth; Redstone push) * [Island](https://app.kodiak.finance/#/liquidity/pools/0x24afceb372b755f4953e738d6b38e9e4646d9f57?farm=0x199f156bba61496401dc2a009b5f69eb9a7e6f21\&chain=berachain_mainnet) * Feed0: [Pyth iBERA](https://insights.pyth.network/price-feeds/Crypto.IBERA%2FUSD) * Feed1: [Redstone push iBGT](https://app.redstone.finance/app/feeds/berachain/ibgt/) * kodiakIsland: * Island Address * PriceFeed0 * Select the feed from already added to price token with 0'th index in terms of USD * PriceFeed1 * Select the feed from already added to price token with 1'st index in terms of USD * descriptionTicker * The same as name\ This parameter is to be removed later
Pendle PT **Before any deployment, ensure that pendle market has correct cardinality. It should be no less than twapWindow / blockTime + 1 for a given chain.** To check cardinality, go to LP contract and get \_storage()\[4].\ To update cardinality, call increaseObservationsCardinalityNext of an LP contract. ### Pendle chainlink-compatible factory * Factory Addresses: * Plasma: 0xAcD67f36183c8bA6b80Cfa60375510Ce17D0dd26 * Mainnet: 0x9E5129dcC15d39625617DcD7F0F44FB0BB957FFd 1. Deploy PT to SY oracle using createOracle Factory method **Market**: Pendle Market address\ **twapDuration**: twap duration in seconds (1800 recommended)\ **baseOracleType**: 0 (PT to SY price) ![Figure](https://docs.gearbox.finance/assets/docs/curators/add-required-price-feeds/08-pendle-chainlink-compatible-factory.png) 2. Add deployed pendle feed as external (staleness period = 1) 3. Deploy Composite Gearbox Oracle\ Set Feed 1 to previously deployed PT-to-SY feed\ Set Feed 2 to feed which prices SY to USD SY to USD feed shouldn't be of updatable type (Redstone Pull or Pyth pull) ![Figure](https://docs.gearbox.finance/assets/docs/curators/add-required-price-feeds/09-pendle-chainlink-compatible-factory.png) 3. Deploy Bounded Gearbox Oracle\ Set underlying feed to previously deployed Composite feed\ Set bound to 1 ![Figure](https://docs.gearbox.finance/assets/docs/curators/add-required-price-feeds/10-pendle-chainlink-compatible-factory.png) ### Gearbox PT feed **Click New Feed and select Pendle PT TWAP type** ![Figure](https://docs.gearbox.finance/assets/docs/curators/add-required-price-feeds/11-gearbox-pt-feed.png) #### *Config parameters:* * Name: * Specify token Symbol and source of Underlying Price\ Example: * Name: PT-sUSDE-25SEP2025 (Chainlink) * Underlying feed: sUSDe/USD (Chainlink) * market * Pendle Market address ![Figure](https://docs.gearbox.finance/assets/docs/curators/add-required-price-feeds/12-config-parameters.png) * UnderlyingPriceFeed * The feed contract is able to fetch price of PT token in terms of SY token from the Pendle Market and then multiplies it by SY price in terms of USD ⇒ underlying feed is an intended method to price SY in terms of USD. * priceToSy * ***Most likely you need to check this box*** (if on the previous step you set underlying price feed to be equal to SY price) * If you don't check this box, you will need to use asset price as underlying price feed. (read more about the difference between Asset and SY [here](https://docs.pendle.finance/Developers/Contracts/StandardizedYield#asset-of-sy--assetinfo-function)) * twapWindow * The window length in seconds for averaging market price * Value of 1800s was usually used for previous deployments ### Deploy Bounded Gearbox Oracle Set underlying feed to previously deployed PT TWAP feed\ Set bound to 1
Curve Stable **Click New Feed and select Curve\_stable type** ![Figure](https://docs.gearbox.finance/assets/docs/curators/add-required-price-feeds/13-deploy-bounded-gearbox-oracle.png) #### *Config parameters:* * **Name** * Specify pool Symbol and sources of Underlying Prices\ Example: * Name: crvUSD-USDC (Chainlink) * [Pool](https://www.curve.finance/dex/ethereum/pools/factory-crvusd-0/deposit/) * Feed0: Chainlink crvUSD * Feed1: Chainlink USDC * **Token** * LP token address ![Figure](https://docs.gearbox.finance/assets/docs/shared/curve-stable-token-input.png) * **Pool** * The address of the pool ![Figure](https://docs.gearbox.finance/assets/docs/shared/curve-stable-pool-input.png) * underlyingPriceFeed 0/1/2/3 * Select a feed from allowed list to price pool's tokens at given indexes * If pool has only 2 tokens in it, specify only underlyingPriceFeed0 & 1
Pendle LP **Before any deployment, ensure that pendle market has correct cardinality. It should be no less than twapWindow / blockTime + 1 for a given chain.** To check cardinality, go to LP contract and get \_storage()\[4].\ To update cardinality, call increaseObservationsCardinalityNext of an LP contract. ### Pendle chainlink-compatible factory * Factory Addresses: * Plasma: 0xAcD67f36183c8bA6b80Cfa60375510Ce17D0dd26 * Mainnet: 0x9E5129dcC15d39625617DcD7F0F44FB0BB957FFd 1. Deploy PT to SY oracle using createOracle Factory method **Market**: Pendle Market address\ **twapDuration**: twap duration in seconds (1800 recommended)\ **baseOracleType**: 2 (LP to SY price) ![Figure](https://docs.gearbox.finance/assets/docs/curators/add-required-price-feeds/08-pendle-chainlink-compatible-factory.png) 2. Add deployed pendle feed as external (staleness period = 1) 3. Deploy Composite Gearbox Oracle\ Set Feed 1 to previously deployed LP-to-SY feed\ Set Feed 2 to feed which prices SY to USD SY to USD feed shouldn't be of updatable type (Redstone Pull or Pyth pull) ![Figure](https://docs.gearbox.finance/assets/docs/curators/add-required-price-feeds/09-pendle-chainlink-compatible-factory.png) 3. Deploy Bounded Gearbox Oracle\ Set underlying feed to previously deployed Composite feed\ Set bound to 1 ![Figure](https://docs.gearbox.finance/assets/docs/curators/add-required-price-feeds/10-pendle-chainlink-compatible-factory.png) ### Gearbox PT feed **Click New Feed and select Pendle PT TWAP type** ![Figure](https://docs.gearbox.finance/assets/docs/curators/add-required-price-feeds/11-gearbox-pt-feed.png) #### *Config parameters:* * Name: * Specify token Symbol and source of Underlying Price\ Example: * Name: PT-sUSDE-25SEP2025 (Chainlink) * Underlying feed: sUSDe/USD (Chainlink) * market * Pendle Market address ![Figure](https://docs.gearbox.finance/assets/docs/curators/add-required-price-feeds/12-config-parameters.png) * UnderlyingPriceFeed * The feed contract is able to fetch price of PT token in terms of SY token from the Pendle Market and then multiplies it by SY price in terms of USD ⇒ underlying feed is an intended method to price SY in terms of USD. * priceToSy * ***Most likely you need to check this box*** (if on the previous step you set underlying price feed to be equal to SY price) * If you don't check this box, you will need to use asset price as underlying price feed. (read more about the difference between Asset and SY [here](https://docs.pendle.finance/Developers/Contracts/StandardizedYield#asset-of-sy--assetinfo-function)) * twapWindow * The window length in seconds for averaging market price * Value of 1800s was usually used for previous deployments ### Deploy Bounded Gearbox Oracle Set underlying feed to previously deployed PT TWAP feed\ Set bound to 1
Balancer V3 LP ### Balancer chainlink-compatible factory Feeds of underlying tokens used for deployment shouldn't be of updatable type (Redstone Pull or Pyth pull) Factory address: * Plasma: 0x86e67E115f96DF37239E0479441303De0de7bc2b * Mainnet: 0x83bf399fa3dc49af8fb5c34031a50c7c93f56129
## Configure Market Source: https://docs.gearbox.finance/curators/configure-market File: content/curators/configure-market.mdx ### Assets ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-market/01-assets.png) 1 #### Add new asset and set Main Feed **Asset:** Collateral token address. Select from PriceFeed Store or [add new if needed.](https://docs.gearbox.finance/curators/add-required-price-feeds) **Price Feed:** Collateral token Main price feed. Select from PriceFeed Store or [add new if needed](https://docs.gearbox.finance/curators/add-required-price-feeds). Main feed is used to for collateral pricing during liquidation checks. 2 #### Set Reserve Feed Select from PriceFeed Store or [add new if needed](https://docs.gearbox.finance/curators/add-required-price-feeds). Used to protect the protocol against manipulations of Main Feeds’ price. See [Dual-oracle pricing](https://docs.gearbox.finance/core/dual-oracle-system) for detailed explanation. Set Reserve Feed equal to Main Feed if you have no other options.\ \&#xNAN;***If reserve price feed is not set, part of the protocol functions (withdrawals, partial liquidations) won't be available.*** 3 #### Quota limit Max amount of debt that can be backed by particular asset in the pool. Measured in amount of underlying asset. Used for calculation of Account Value and quota interest rate.\ see [Docs](https://docs.gearbox.finance/core/liquidation-dynamics#what-is-a-health-factor) for detailed explanation. 4 #### Quota Increase Fee **Rarely used, feel free to omit**\ When user increases Quota (CA-specific max amount of debt that can be backed by particular collateral), charge a fixed % fee on the quota difference: works like a one-time fee charged on swaps by exchanges. Added to account's Debt. Distributed as a DAO & Curator fee on repayment according to the fee split rules. ### Rates ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-market/02-rates.png) 1 #### Collateral-specific Rates Additional rate which is applied on top of IRM-based utilization rate for borrowing against particular collaterals. To modify collateral-specific rates, set the intended rates in front of each collateral and click "Update Rates". See [Collateral-specific rates](https://docs.gearbox.finance/curators/fee-sharing) for detailed explanation. Setting IRM in a way that **borrow rate at target utilization (\~80-85%)** equals **60-70% of expected collateral yield** will allow you to bootstrap utilization by allowing favorable rates.\ Equlibrium rate can then be found by increasing collateral-specific rates. ### IRM ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-market/03-irm.png) 1 #### IRM parameters Rate curve parameters can be changed after the creation of Market by executing transactions generated from "Change Model" action. ### Loss policy Additional logic applied during CA liquidation if it results in creation of Bad Debt.\ Properly set loss policy is especially helpful in cases when secondary market oracle is used as a Main feed. **Risks of using secondary market price as Main price feed** \ \&#xNAN;***Example**:* * Main ezETH feed - Market price ## Configure Adapters Source: https://docs.gearbox.finance/curators/configure-adapters File: content/curators/configure-adapters.mdx ## ### What are adapters? The Credit Account design enables active interaction with the DeFi ecosystem while borrowing — such as swapping tokens, depositing into vaults, claiming rewards, and more. However, allowing arbitrary operations poses security risks. > Adapters — modular contracts that enable secure, controlled interactions with external protocols. ### Why do curators need to configure adapters? Having adapters properly configured in the market is essential for allowing collateral swaps, 1-click leverage and other UX features of Gearbox protocol. > Existing offchain infra (Front End, Liquidator) rely on router for finding paths from/to available collaterals. Router is not part of Gearbox protocol, therefore it’s not present in Bytecode repository. Router is used by Gearbox SDK to provide swap paths and it doesn’t interact with core contracts directly. ### What protocols are already integrated? | Protocol | Supported actions | | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | | Uniswap, Sushiswap, Oku Trade [V2](https://docs.gearbox.finance/curators/configure-adapters#uniswap-sushiswap-v2), [V3](https://docs.gearbox.finance/curators/configure-adapters#uniswap-sushiswap-pancakeswap-iguanadex-oku-trade-v3) | Swaps | | Pancakeswap, IguanaDEX [V3](https://docs.gearbox.finance/curators/configure-adapters#uniswap-sushiswap-pancakeswap-iguanadex-oku-trade-v3), [StableSwap](https://docs.gearbox.finance/curators/configure-adapters#pancakeswap-iguanadex-stableswap) | Swaps, Stableswap LP deposits | | Balancer [V2](https://docs.gearbox.finance/curators/configure-adapters#balancer-v2), [V3](https://docs.gearbox.finance/curators/configure-adapters#balancer-v3) | Swaps, LP deposits | | Curve [Stableswap, CryptoSwap, Stable NG](https://docs.gearbox.finance/curators/configure-adapters#curve-stableswap-cryptoswap-and-stableng) | Swaps, LP deposits | | [***Pendle***](https://docs.gearbox.finance/curators/configure-adapters#curve-stableswap-cryptoswap-and-stableng) | PT swaps | | [Mellow](https://docs.gearbox.finance/curators/configure-adapters#mellow-erc4626) ERC4626 vaults, DVstETH | Instant deposits, Delayed withdrawals | | Velodrome, Aerodrome V3, Stableswap | Swaps | | Camelot, Thena (Algebra AMM dexes) V3 | Swaps | | ***Napier*** | PT Swaps, LP deposits | | ***Convex*** | Staking LP, claiming rewards | | [***Fluid DEX***](https://docs.gearbox.finance/curators/configure-adapters#fluid-dex) | Swaps | | Camelot, Thena, Quickswap (Algebra AMM) V3 | Swaps | | ***Trader Joe*** | Swaps | | ***Infrared*** | Staking LP, claiming rewards | | ***Sky*** | DAI - USDS conversion, Staking USDS for SKY | | ***Lido*** | stETH - wstETH conversion | | [***ERC4626***](https://docs.gearbox.finance/curators/configure-adapters#erc4626) | Instant deposits and withdrawals (whenever possible) | | [***Kodiak Island***](https://docs.gearbox.finance/curators/configure-adapters#erc4626) | Deposit into Island, Swaps in pool | | Uniswap V4 | Swaps | | InfiniFi | Instant deposits, Delayed withdrawals | All the source code and audit reports of the contracts can be found in [Bytecode Repository](https://permissionless.gearbox.foundation/bytecode). Use search, click on the target contract and then **View Source** or **View Report**. All the Adapters can be found by searching for the ADAPTER domain in Bytecode Repository. [setup example (BNB chain: USD1 pool, USDX collateral)](https://www.notion.so/Adapter-setup-example-BNB-chain-USD1-pool-USDX-collateral-208145c16224807fa1a0d318c01bc1ae?pvs=21) [setup example (Ethereum chain: tBTC pool, uptBTC collateral)](https://www.notion.so/Adapter-setup-example-Ethereum-chain-tBTC-pool-uptBTC-collateral-20e145c1622480c886d8d43dc5e9f5bb?pvs=21) [setup example (Ethereum chain: USDC pool, frxUSD/USDf collateral)](https://gearboxprotocol.notion.site/Adapter-setup-example-Ethereum-chain-USDC-pool-frxUSD-USDf-collateral-24c145c16224809d80d2d171e1128317?source=copy_link)
Uniswap, Sushiswap V2 ### Router configuration For the router on the chain to support swaps, Uniswap V2 worker should be configured. It requires passing the following addresses: * SwapRouter * **Add UniswapV2 adapter (requires providing router address):** ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/01-router-configuration.png) * Uni V2 deployment addresses: * Sushi V2 deployment addresses: > Before allowing pools in adapter, please ensure that tokens from a pair are added as ***Assets to Market*** and as ***Collaterals to Credit Manager***.\ \ \&#xNAN;*e.g. to add WETH/USDC pool both WETH and USDC must be added before.* * **Configure adapter to whitelist pools:** ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/02-router-configuration.png) ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/03-router-configuration.png) * Uni V2 * Configuration requires specifying tokens from a pair ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/04-router-configuration.png) * Sushi V2 * Configuration requires specifying tokens from a pair ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/05-router-configuration.png)
Uniswap, Sushiswap, Pancakeswap, IguanaDEX, Oku trade V3 ### Router configuration For the router on the chain to support swaps, Uniswap V3 worker should be configured. It requires passing the following addresses: * SwapRouter * QuoterV2 * **Add UniswapV3 adapter (requires providing SwapRouter address):** ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/06-router-configuration.png) * Uni V3 deployment addresses: * Sushi V3 deployment addresses: * Oku Trade deployment addresses: * PancakeSwap deployment addresses: * IguanaDEX deployment addresses: > Router deployment must have bytecode of Uniswap's [SwapRouter.sol](https://github.com/Uniswap/v3-periphery/blob/v1.0.0/contracts/SwapRouter.sol) contract. Sometimes it has only [SwapRouter02](https://github.com/Uniswap/swap-router-contracts/blob/main/contracts/SwapRouter02.sol) deployment specified.\ \ On some chains that was already solved by deploying required implementation of router (see below).\ If it's not, reach out to Gearbox contributors. * Custom SwapRouter deployments: * Uni V3 * [BNB chain](https://bscscan.com/address/0xe7aC922b9751C7aca3A46D5505F36d5BbB1456b6#code) * Oku Trade * [Etherlink](https://explorer.etherlink.com/address/0x2afB54fcaECd41BE4Ecd05d7bd2e193F2F05B99d?tab=contract) * [Plasma](https://plasmascan.to/address/0x9Ed7DFCDE80838f9FfaF4e7fFCe5CcE4737c3e3b) * [Optimism](https://explorer.optimism.io/address/0xDb7D5A2146533BAE5C08A869Cb7e085d8Bee6e0F?tab=contract) > Before allowing pools in adapter, please ensure that tokens from a pair are added as ***Assets to Market*** and as ***Collaterals to Credit Manager***.\ \ \&#xNAN;*e.g. to add WETH/USDC pool both WETH and USDC must be added before.* * **Configure adapter to whitelist pools:**\ \&#xNAN;*Configuration requires specifying tokens and fee from a pair* ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/07-router-configuration.png) ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/08-router-configuration.png) * Uni V3 ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/09-router-configuration.png) * Sushi V3 ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/10-router-configuration.png) * [PancakeSwap](https://pancakeswap.finance/info/v3/pairs), [IguanaDEX](https://www.iguanadex.com/info/v3?chain=etherlink) ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/11-router-configuration.png)
Velodrome, Aerodrome Concentrated Liquidity (Slipstream) For the router on the chain to support swaps, Uniswap V3 worker should be configured. It requires passing the following addresses: * SwapRouter * Quoter * **Add UniswapV3 adapter (requires providing SwapRouter address):** ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/06-router-configuration.png) * Velodrome V3 (Slipstream) multichain deployment addresses: * Aerodrome V3 (Slipstream) * **Configure adapter to whitelist pools:**\ \&#xNAN;*Configuration requires specifying tokens and fee from a pair* ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/07-router-configuration.png) ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/08-router-configuration.png) * Fee is a number specified in UI divided by 10000\ e.g. Concentrated Volatile 100 ⇒ fee = 0.01%\ Concentrated Stable 1 ⇒ fee = 0.0001% ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/15-router-configuration.png)
Curve StableSwap, CryptoSwap and StableNG * **How to understand what's the type of the pool of interest:** 1. Go to the block explorer page of Curve Address provider on a chain of interest:\ 2. Call Address Provider's get\_address method with id = 7 to get address of MetaRegistry\ On Mainnet MetaRegistry is located [here](https://etherscan.io/address/0xF98B45FA17DE75FB1aD0e7aFD971b0ca00e379fC). 3. Call get\_registry\_handlers\_by\_pool of MetaRegistry, passing target pool address as argument. 4. Check non-zero address from step 3. output. It usually has clues in first lines of its code. > Before adding adapter, please ensure that tokens from a pool and pool LP token itself are added as ***Assets to Market*** and as ***Collaterals to Credit Manager***.\ \ \&#xNAN;*e.g. to add 3Pool (USDC/USDT/DAI) adapter both USDC, USDT, DAI and 3Pool token itself must be added before.*\ \ \&#xNAN;*learn how to find pool's token address below.* * ***If the pool is not Stable NG:***\ \&#xNAN;*Select Curve V1 2/3/4 Assets adapter depending on the number of different tokens in target pool:* ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/16-router-configuration.png) * ***If the pool is Stable NG:***\ \&#xNAN;*Select Curve StableNG adapter:* ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/17-router-configuration.png) > If the pool operates with non-erc20 ETH balance, deploy a ETH Gateway first and then pass it as target address.\ See the list of deployed gateways below and reach out to Gearbox team if the needed is not present. * ***Adapter arguments:*** * **Target Address** * The address of the pool ![Figure](https://docs.gearbox.finance/assets/docs/shared/curve-stable-pool-input.png) * **LP token** * The address of the pool's LP token (may be different from pool itself) ![Figure](https://docs.gearbox.finance/assets/docs/shared/curve-stable-token-input.png) * **Base Pool Address** * Applicable only if pool is a metapool.\ Example: [this](https://www.curve.finance/dex/ethereum/pools/factory-v2-251/deposit/) pool has [FRAX/USDC](https://www.curve.finance/dex/ethereum/pools/fraxusdc/deposit/) as its base pool. * **Crypto Swap or PancakeSwap pool** * If Type of Pool is Crypto Swap (a.k.a Twocrypto/ Tricrypto) checkout this box. * ETH Gateway deployments: * Mainnet: * [ETH/stETH pool](https://etherscan.io/address/0xdc24316b9ae028f1497c275eb9192a3ea0f67022) Gateway: 0x0675cb2066bacae2edfd09633d5b62be3c619a35
PancakeSwap/ IguanaDEX StableSwap > Before adding adapter, please ensure that tokens from a pool and pool LP token itself are added as ***Assets to Market*** and as ***Collaterals to Credit Manager***.\ \ \&#xNAN;*e.g. to add USDX/USDT adapter both USDX, USDT and pool's LP token itself must be added before.*\ \ \&#xNAN;*learn how to find pool's token address below.* * **Select Curve V1 2 Assets adapter:** ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/16-router-configuration.png) * **Target Address** * The address of the pool ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/21-router-configuration.png) * **LP token** * The address of the pool's LP token (can be retreived by calling token() method of pool contract) ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/22-router-configuration.png) * **Base Pool Address** * Not applicable to PancakeSwap. Leave untouched. * **Crypto Swap or PancakeSwap pool** * Checkout this checkbox.
Pendle ### Router configuration For the router on the chain to support swaps, Pendle worker should be configured. It requires passing the following addresses: * routerStatic ### Adapter configuration * **Add Pendle adapter (requires providing router address):** ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/23-adapter-configuration.png) * Pendle deployment addresses: > Before adding pool to adapter, please ensure that pool's input token and PT token are added as ***Assets to Market*** and as ***Collaterals to Credit Manager***.\ \ \&#xNAN;*e.g. to add Pendle pool for PT-sUSDe, both sUSDe and PT-sUSDe must be added before.* * **Configure adapter to whitelist pools:**\ \&#xNAN;*Configuration requires specifying market address and input/output tokens* ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/24-adapter-configuration.png) ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/25-adapter-configuration.png) * ***Market:*** ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/26-adapter-configuration.png) ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/27-adapter-configuration.png) ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/28-adapter-configuration.png) ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/29-adapter-configuration.png) * ***Input token:***\ Select a token that is in the "1 SY Equals To" row on the screenshot above ^ * ***Pendle token:***\ Target PT token
Fluid DEX ### Router configuration For the router on the chain to support swaps, Fluid worker should be configured. It requires passing the following addresses: * fluidDexResolver > Before adding pool to adapter, please ensure that pool's tokens are added as ***Assets to Market*** and as ***Collaterals to Credit Manager***.\ \ \&#xNAN;*e.g. to add Fluid DEX for wstUSR/USDT, both wstUSR and USDT must be added.* * **Add Fluid DEX adapter (requires providing DEX address)** ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/30-router-configuration.png) > If the pool includes ETH token, ETH Gateway must be deployed first and then be passed as target address to Fluid DEX adapter. * Fluid deployment addresses: > DEX addresses have names in the similar format: **Dex\_wstUSR\_USDT.**\ Search the name based on required tokens above. * ETH Gateway deployments: * Mainnet: * **Dex\_wstETH\_ETH: 0x9f294BF3201533B652aFb6B10c0385972C28a16f** * **ezETH\_ETH: 0xa59fc0102b7c2aee66e237ee15cb56ad58a97b2e** * **rsETH\_ETH: 0xb219cE3Fa907edCb375B7375F3C50d920e244bba** * **weETH\_ETH:** 0x0A226E0efa6FCF26837441d623210A9464349200
ERC4626 ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/31-router-configuration.png) Takes ERC4626 **Vault Address** as parameter. Target vault must be added as Asset to Market and as Collateral to Credit Manager. > Before adding adapter, please ensure that token being underlying asset of a ERC4626 vault is added as ***Assets to Market*** and as ***Collaterals to Credit Manager***.\ \ \&#xNAN;*e.g. to add sDAI ERC4626 adapter DAI itself must be added before.* Operates using deposit, withdraw, mint and redeem functions of ERC4626 standard. Allows performing swaps from the vault’s **asset** token into ERC4626 vault **share** token. > Sometimes tokens look very much like ERC4626 but with overwritten methods, like those implementing timelocked deposits and withdrawals.\ Note that this adapter works with vanilla standard methods only.\ \ e.g. sUSDe can be minted from USDe using ERC4626 deposit interface, but has timelocked withdrawals.
Kodiak Island ### Router configuration For the router on the chain to support swaps, Kodiak Island worker should be configured. It requires passing: * \_kodiakIslandRouter - 0x679a7C63FC83b6A4D9C1F931891d705483d4791F * \_kodiakSwapRouter - 0xEd158C4b336A6FCb5B193A5570e3a571f6cbe690 * \_kodiakQuoter - 0x644C8D6E501f7C994B74F5ceA96abe65d0BA662B Takes Gateway Address as parameter. On Berachain it's 0x8d41361d340515d1cdd8c369ca7b5c79f6b2e9c9. ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/32-router-configuration.png) After adding adapter, click configure to whitelist particular Islands. > Before adding Island to adapter, please ensure that Island's tokens and Island itself are added as ***Assets to Market*** and as ***Collaterals to Credit Manager***.\ \ \&#xNAN;*e.g. to add WBERA/iBERA Island, WBERA, iBERA and Island must be added.* ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/33-router-configuration.png)
Convex-staked Curve LP > Before adding and configuring Convex pool adapters, ensure that **Curve LP token**, **Convex Deposit Token**, **Staked Phantom Token**, **CRV** and **CVX** are added as collaterals to Market and Credit Manager (everything except **Staked Phantom Token** can have zero limit, LT and feed).\ \ \ **Convex Deposit Token** can be found by its symbol. If the Curve LP token has symbol frxUSDUSDf, then Convex deposit token will have symbol cvxfrxUSDUSDf. **Staked Phantom Token** can be found by its symbol. If the Curve LP token has symbol frxUSDUSDf, then Convex deposit token will have symbol stkcvxfrxUSDUSDf. **Add Convex Base Reward Pool adapter.** ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/34-router-configuration.png) * ***Base Reward Pool Address:*** * Rewards contract address from Convex pool Info. ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/35-router-configuration.png) * ***Staked phantom token:*** * **Staked Phantom Token** can be found by its symbol. If the Curve LP token has symbol frxUSDUSDf, then Convex deposit token will have symbol stkcvxfrxUSDUSDf. **Add Convex Booster adapter** > If the Credit Manager already includes the Convex Booster adapter, skip it and proceed to the next step (Update Convex booster Pool IDs). > Booster address is single across all chains and is suggested as default option. ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/36-router-configuration.png) **Update Convex booster Pool IDs** > After each new Convex pool is added, Booster pool ids should be updated. ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/37-router-configuration.png) ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/38-router-configuration.png)
Balancer V2 ### Router configuration For the router on the chain to support swaps, Balancer V2 worker should be configured. Configuration requires passing: * BalancerQueries Balancer deployment addresses can be found [here](https://docs-v2.balancer.fi/reference/contracts/deployment-addresses/mainnet.html). ### Adapter configuration * **Add BalancerV2 adapter (requires providing Vault address):** ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/39-adapter-configuration.png) * Deployment addresses:\ > Before adding adapter, please ensure that tokens from a pool and pool LP token itself are added as ***Assets to Market*** and as ***Collaterals to Credit Manager***.\ \ \&#xNAN;*e.g. to add WETH/osETH pool to adapter both WETH, osETH and WETH/osETH token itself must be added before.*\ \ \&#xNAN;*learn how to find pool's token address below.* * **Finding Pool LP Token Address:** ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/40-adapter-configuration.png) * **Configure adapter to whitelist pools:** ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/41-adapter-configuration.png) ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/42-adapter-configuration.png) * Configuration requires specifying PoolID which can be found on Balancer UI ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/43-adapter-configuration.png)
Balancer V3 ### Router configuration For the router on the chain to support swaps, Balancer V3 worker should be configured. Configuration requires passing: * [BalancerV3MultiActionQueries](https://github.com/Van0k/balancer-queries/blob/master/src/BalancerV3MultiActionQueries.sol) (needs to be deployed manually, reach out to contributors for support) Balancer deployment addresses can be found [here](https://docs.balancer.fi/developer-reference/contracts/deployment-addresses/plasma.html#core-contracts). BalancerV3MultiActionQueries deployments: * Plasma * 0x1a9B1bfD35fA3932493b5f4F20Cb16b2B88Cc0C8 * Mainnet * 0x0BA8417d19D87b7b5C9dA8762ba505d61D1bF1E7 * Optimism * 0x1b8a4BA520C7789D7bE7476960B8Cdd42e57d928 * Monad * 0x79840073664F6c7bD384C3452B2C034cDEEFEAe5 ### Adapter configuration * **Add BalancerV3 adapter (requires providing Gateway address):** ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/44-adapter-configuration.png) * Gateway deployment addresses: * Ethereum: * v3.10 (outdated) 0x21f55223de449224e8bdf4f59452e072bdf7af57 * **v3.11** — 0x8A57c21234ddc225499843F6A073dd374c952560 * Plasma: * v3.10 (outdated) 0xd5c89297ad23e12d7f0ff24112418dbe9ebeae56 * **v3.11** — 0x55109bA88c396008cfBe9F27Ad97A7e1e4394f6F * Optimism: * **v3.11** — 0x77b2dfc344072fa242f2d03893ccbdbb0ef47b7c * Monad * **v3.11** — 0x9dA18982a33FD0c7051B19F0d7C76F2d5E7e017c > Before adding adapter, please ensure that tokens from a pool are added as ***Assets to Market*** and as ***Collaterals to Credit Manager***.\ \ \&#xNAN;*e.g. to add* waEthLidowstETH*/rstETH pool to adapter both* waEthLidowstETH*, rstETH and* waEthLidowstETH*/rstETH token itself must be added before.*\ \ \&#xNAN;*learn how to find pool's token address below.* > What are *wa*-tokens?\ It's erc4626 vaults representing positions staked in Aave pools.\ To support swaps from wstETH through waEthLidowstETH*/rstETH* boosted Balancer pool, you need to include wa-token as collateral and add erc4626 adapter with wa-token address as vault which will process swaps from wstETH to waEthLidowstETH. * **Finding Pool LP Token Address:** ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/45-adapter-configuration.png) * **Configure adapter to whitelist pools:** ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/41-adapter-configuration.png) ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/47-adapter-configuration.png) * Configuration requires specifying Pool Address which can be found on Balancer UI ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/45-adapter-configuration.png)
Mellow ERC4626 ### Router configuration For the router on the chain to support swaps, Mellow worker should be configured. Reach out to contributors for support. > Before adding adapter, please ensure that mellow vault (LRT itself) and its Withdrawal Phantom Token are added ***Assets to Market*** and as ***Collaterals to Credit Manager***.\ \ If the phantom token is not present in PFS, ask Gearbox contributors to help you deploy a new one. #### **Add Mellow ERC4626 adapter:** ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/49-add-mellow-erc4626-adapter.png) * Vault address * Select a corresponding Mellow vault (LRT itself) that was previously added as collateral. * Phantom Token * A token that tracks user's position in withdrawal queue and allows unstaking LRT right from the Credit Account. #### **Add Mellow claimer adapter:** This adapter allows claiming unstaked tokens after the redemption request was processed. ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/50-add-mellow-claimer-adapter.png) Mellow Claimer is a contract deployed by Mellow. Deployment addresses can be found here: **Configure Mellow Claimer Adapter** ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/51-add-mellow-claimer-adapter.png) ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/52-add-mellow-claimer-adapter.png) * Multi vault * Mellow LRT itself * Phantom token * A token that tracks user's position in withdrawal queue and allows unstaking LRT right from the Credit Account.
Midas (direct deposits & redemptions) Midas risks: \- If Midas rejects a withdrawal request, a credit account that has the request rejected will have its phantom token balance locked and non-claimable. This means that de-facto the account has bad debt (that cannot be liquidated) until the situation is resolved manually \- A gateway has a function to manually process a cancelled request by paying an amount of at least pendingTokenOutAmount for the respective credit account (the function can be called by anyone). This will allow the credit account to claim a withdrawal as if it was normally processed \- It's best to forbid the withdrawal phantom token if there is a rejected request to Gearbox CA, since Midas might accidentally refund the withdrawal to the CA itself, leading to double counting. Forbidding the token will prevent the user to borrow and withdraw more against their collateral in this case. > For safety, each curator on each chain must have its own gateway and phantom token for each vault. Gateway addresses: * Plasma * Hyperithm Curator: 0xB375DF6a1D7a1c172e65D4FBDA2d3caa144Bf8e7 Phantom token addresses: * Plasma * Hyperithm Curator: 0x0835e60e9A56734cEE76e3953c3BE0635Fcb71d5
Velodrome, Aerodrome V1 & V2 (Basic volatile and Basic stable) For the router on the chain to support swaps, Velodrome worker should be configured. It requires passing the following addresses: * Router * **Add Velodrome V2 adapter (requires providing Router address):** ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/53-add-mellow-claimer-adapter.png) * Velodrome v2 optimism deployment addresses: * **Configure adapter to whitelist pools:**\ \&#xNAN;*Configuration requires specifying tokens and fee from a pair*\ \&#xNAN;*Look for Pool Factory in deployment addresses* ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/54-add-mellow-claimer-adapter.png) * Is Stable?\ Basic stable ⇒ Stable\ Basic volatile ⇒ not Stable
Uniswap V4 ### Router configuration For the router on the chain to support swaps, Uniswap V3 worker should be configured. It requires passing the following addresses: * [Universal Router](https://github.com/Uniswap/universal-router/blob/dev/contracts/UniversalRouter.sol) * [Quoter](https://github.com/Uniswap/v4-periphery/blob/main/src/lens/V4Quoter.sol) * **Add UniswapV4 adapter (requires providing Gateway address):** ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/55-router-configuration.png) * Uni V4 deployment addresses: * Gateway deployment addresses: * Monad: 0xCC7944C237DC540585935F19Bc9aeA0003BC4224 * Ethereum: 0x3b74c70283b291e875da84d58176a63dac5d1824 > Before allowing pools in adapter, please ensure that tokens from a pair are added as ***Assets to Market*** and as ***Collaterals to Credit Manager***.\ \ \&#xNAN;*e.g. to add WETH/USDC pool both WETH and USDC must be added before.* > To fetch fee, tick spacing and hook list, go to **Position Manager** contract and call ***poolKeys*** method passing first 52 symbols of pool identifier from Uniswap UI as PoolID.\ \ E.g. if uniswap link has 0x9b25899648292dce5f8805823aebd0d025bf2625be3162a2f1199e13d8d300c8, then 0x9b25899648292dce5f8805823aebd0d025bf2625be3162a2f1 should be passed as poolID to Position Manager. \ \ Position Manager addresses on different chains can be found [here](https://docs.uniswap.org/contracts/v4/deployments). ![Figure](https://docs.gearbox.finance/assets/docs/curators/configure-adapters/56-router-configuration.png) * **Configure adapter to whitelist** \ \&#xNAN;*Configuration requires specifying tokens and fee from a pair*
## Configure fee split Source: https://docs.gearbox.finance/curators/configure-fee-split File: content/curators/configure-fee-split.mdx []()