# Gearbox Protocol developer documentation full export > Full text export for agents and retrieval systems. Use https://docs.gearbox.finance/developers/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. # Developer documentation SDK, contracts, Credit Accounts, multicalls, market data, integrations, deployment addresses, and automation guides. ## Connect SDK Source: https://docs.gearbox.finance/developers/sdk-setup File: content/developers/sdk-setup.mdx Connect `GearboxSDK` to the networks your application uses. Reuse the connected instance to find strategies, prepare transactions, and read positions. ## Install ```bash npm install @gearbox-protocol/sdk viem ``` ## Configure and connect Create `gearbox.ts`. Set the chain ID and its RPC URL, then connect: ```typescript import { GearboxSDK } from "@gearbox-protocol/sdk"; import { getNetworkType } from "@gearbox-protocol/sdk/onchain"; const chainId = 1; // Ethereum mainnet const rpcUrl = "https://your-rpc.example"; // Replace with your RPC URL for the selected network const mode = "both"; const apiBaseUrl = "https://api.gearbox.fi"; const network = getNetworkType(chainId); export const sdk = new GearboxSDK({ mode, networks: [network], onchain: { chains: { [network]: { rpcURLs: [rpcUrl] } } }, offchain: { baseUrl: apiBaseUrl }, }); await sdk.attach(); ``` This configuration connects to your RPC endpoint and the Gearbox API, providing protocol data, analytics, and transaction preparation through one SDK instance. `await sdk.attach()` loads the markets, contracts, and protocol state needed by subsequent calls. Wait for it once during startup, then reuse `sdk`. High-level reads, preparation, and preview calls automatically attempt to refresh onchain state when it is older than 30 seconds by default. Refresh happens when a call needs it, not on a background timer; manual refresh is normally unnecessary. If synchronization fails, the SDK can continue using the previous snapshot, so check the returned block and timestamp. Direct access to low-level cached prices or market configuration does not trigger this freshness check. This connects the SDK to blockchain data. Supply the owner's address directly when reading leveraged positions or preparing transactions; no wallet connection or signer is required for these steps. Signing and execution are handled by your chosen execution system. ### Network names `getNetworkType(chainId)` resolves the SDK's network name automatically and throws for unsupported chain IDs. The SDK uses these mappings: | Chain ID | Network name | | --- | --- | | 1 | `Mainnet` | | 42161 | `Arbitrum` | | 10 | `Optimism` | | 8453 | `Base` | | 146 | `Sonic` | | 4326 | `MegaETH` | | 143 | `Monad` | | 80094 | `Berachain` | | 43114 | `Avalanche` | | 56 | `BNB` | | 480 | `WorldChain` | | 42793 | `Etherlink` | | 43111 | `Hemi` | | 1135 | `Lisk` | | 9745 | `Plasma` | | 5031 | `Somnia` | Continue with [Open](https://docs.gearbox.finance/developers/open-leveraged-position), [Monitor](https://docs.gearbox.finance/developers/monitor-position), or [Manage](https://docs.gearbox.finance/developers/manage-position). ## Open Source: https://docs.gearbox.finance/developers/open-leveraged-position File: content/developers/open-leveraged-position.mdx A user deposits tokens and borrows more. The combined funds are then swapped into the strategy’s target collateral token, which is held in their Credit Account. ## Connect SDK Follow [Connect SDK](https://docs.gearbox.finance/developers/sdk-setup) first. All code below uses the already-connected instance as `sdk`. ## Find available strategies Start by listing the strategies on the chains configured in the SDK: ```typescript const strategies = await sdk.opportunities.list({ kind: "strategy" }); ``` The response contains the strategy list in `data` and per-chain read status, source, block, and timestamp in `meta.chains`. Check that metadata before presenting a chain's list as current. A failed read does not mean the chain has no strategies. Each strategy is identified by `{ chainId, creditManager }`. Use that key for the user's selection. An app URL ending in `/earn/strategy//` supplies the same key. Being listed does not guarantee that a particular wallet or deposit can open the strategy. Check the selected strategy's status, eligibility requirements, and available capacity next. ## Understand the selected strategy Let the user choose an entry from `strategies.data`, then use that entry's chain ID and Credit Manager to read its details. Here, `selectedIndex` is the index chosen in your application's strategy list: ```typescript import type { StrategyOpportunity } from "@gearbox-protocol/sdk/model"; const selectedIndex = 0; // Replace with the user's selection const strategy = strategies.data[selectedIndex] as StrategyOpportunity; const selectedStrategy = await sdk.opportunities.getStrategy({ chainId: strategy.chainId, creditManager: strategy.creditManager, }); ``` `selectedStrategy.data` contains a `StrategyOpportunityDetail`. The fields relevant to opening a position are: | Field | Type | Meaning | | --- | --- | --- | | `chainId` | `number` | Chain where the strategy exists | | `creditManager` | `Address` | Credit Manager address identifying the strategy on that chain | | `name` | `string` | Strategy display name | | `underlyingToken` | `UnderlyingToken` | Asset used to denominate borrowing and the amounts below; for RWA markets, the unwrapped asset | | `targetCollateral` | `Token` | Token bought with the combined deposit and borrowed funds | | `allowedDepositTokens` | `Token[]` | Tokens the user can deposit from their wallet | | `minDebt` | `Amount` | Minimum debt a position may hold | | `maxBorrowAmount` | `Amount` | Current maximum borrowing for a new position, accounting for liquidity and debt limits | | `availableLiquidity` | `Amount` | Free liquidity in the lending pool | | `totalDebtLimit` | `Amount` | Borrowing cap shared by all accounts in this Credit Manager | | `maxLeverage` | `number` | Maximum leverage as a multiple: `4` means 4×, unlike the opening input `400n` | | `collateralApy` | `ApyBreakdown \| undefined` | Collateral yield before leverage, supplied by the backend; may be unavailable and is absent in onchain-only mode | | `collateralApy.organicApy` | `number` | Yield excluding incentives, in basis points: `610` means 6.10%; available when `collateralApy` is present | | `collateralApy.totalApy` | `number \| undefined` | Yield including incentives, in basis points | | `collateralApy.rewards` | `Rewards[] \| undefined` | Incentive breakdown, including points programs that may have no APY | | `borrowApy` | `number` | Annual borrowing cost in basis points, including the protocol interest fee; `520` means 5.2% | | `quotaRate` | `number` | Annual quota cost for the target collateral in basis points, including the protocol interest fee | | `liquidationThreshold` | `number` | Target collateral's value counted toward solvency before the quota cap, in basis points: `9000` means 90% | | `liquidationPremium` | `number` | Share of liquidated account value paid to the liquidator, in basis points | | `liquidationFee` | `number` | Share of liquidated account value taken by the protocol, in basis points | | `paused` | `boolean` | Whether the Credit Facade or lending pool is paused | | `sunset` | `boolean` | Whether the strategy is being wound down and should no longer be entered | | `expirationDate` | `number \| null` | Credit Facade expiry as a Unix timestamp in seconds, or `null` if it does not expire | | `kyc` | `KycRequirement \| null \| undefined` | Strategy registration requirements; `null` means no KYC gate, `undefined` means unavailable. This is not a wallet eligibility result | `Token` includes `address`, `symbol`, and `decimals`. `Amount.value` is a `bigint` in `underlyingToken` base units; `Amount.valueUsd` is a dollar value or `null` when unavailable. Check `selectedStrategy.meta.chains` for the source, block, timestamp, and read status. The deposit token and target collateral token serve different purposes. The user supplies the deposit token from their wallet; the combined deposited and borrowed funds buy the strategy's configured target collateral token. ## Choose opening parameters Pass the selected strategy and an `OpenStrategyParams` object to `sdk.opportunities.prepare.openNewStrategy()`. | Field | Type | Meaning | | --- | --- | --- | | `collateral[].token` | `Address` | Deposit token address, selected from `allowedDepositTokens` | | `collateral[].balance` | `bigint` | Deposit amount in that token's base units | | `leverage` | `bigint` | Requested leverage in hundredths of a multiple: `250n` = 2.5×, `400n` = 4× | | `slippage` | `number` | Swap slippage tolerance in basis points: `5` = 0.05%, `50` = 0.5% | | `targetToken` | `Address \| undefined` | Optional target token; defaults to the selected strategy's target collateral | These are SDK fields. The snippet below uses the user's selected deposit token, amount, leverage, and slippage from your application's form. Convert the amount to base units with the deposit token's decimals. ## Prepare the transaction ```typescript import type { OpenStrategyParams } from "@gearbox-protocol/sdk"; import { parseUnits } from "viem"; const params: OpenStrategyParams = { collateral: [{ token: depositToken.address, balance: parseUnits(depositAmount, depositToken.decimals), }], leverage, slippage, quotaReserve: 100, // Optional: 1% extra quota }; const sim = await sdk.opportunities.prepare.openNewStrategy(strategy, params); if (!sim.ok) throw sim.error; ``` Validate form inputs before converting them: the amount must be positive and fit the token's decimals; leverage and slippage must use the units above. The SDK calculates borrowing, routing, and the resulting position. If preparation fails, display its error instead of building a transaction. `sim.data.state` contains the projected position, including `totalDebt`, `totalValue`, `netValue`, leverage, health factor, and borrowing cost. The amounts include their token metadata and use that token's base units. `sim.data.blockNumber` and `sim.data.timestamp` identify the state used for preparation. The projected leverage can differ from the requested multiple after fees and price impact. ## Resolve the approval spender For a new Credit Account, `owner` is the address that will fund and own the leveraged position. Supply it directly; no wallet connection is needed. Resolve its approval spender: ```typescript const spender = await sdk.onchain .chain(strategy.chainId) .accounts.getApprovalAddress({ creditManager: strategy.creditManager, borrower: owner, }); ``` For each ERC-20 in `params.collateral`, check its allowance from `owner` to `spender`. If it is below `balance`, the required approval is `approve(spender, balance)` on that token, sent by `owner`. `balance` is the deposit amount in the token's base units. Approve only your deposit, not the borrowed amount or total leveraged position. Approval execution belongs to your chosen execution flow. ## Build, preview, and check Continue with `strategy`, `selectedStrategy`, `params`, the successful `sim`, and `owner` in [Build, preview, and check](https://docs.gearbox.finance/developers/build-preview-check#open-a-leveraged-position). That page covers transaction construction, preview fields, validation issues, and the payload to pass to your chosen execution system. ## Next steps Continue with [Monitor](https://docs.gearbox.finance/developers/monitor-position) to read the Credit Account and [Manage](https://docs.gearbox.finance/developers/manage-position) to change it. Use [Close](https://docs.gearbox.finance/developers/close-leveraged-position) to repay the loan and withdraw all remaining equity. ## Source - [SDK package](https://www.npmjs.com/package/@gearbox-protocol/sdk) - [Opening preparation](https://github.com/Gearbox-protocol/sdk/blob/076de9c284c536c76eb3f93bc8284759acea539b/src/sdk/prepare/PrepareApi.ts) - [Position reads](https://github.com/Gearbox-protocol/sdk/blob/076de9c284c536c76eb3f93bc8284759acea539b/src/sdk/positions/types.ts) ## Lender (Pools) Source: https://docs.gearbox.finance/developers/lending File: content/developers/lending.mdx This section explains how to integrate programmatically with Gearbox pools. ## Overview Lenders provide the pool's underlying asset and receive ERC-4626 pool shares. Interest paid by borrowers increases the amount of underlying represented by those shares over time. ## What's in This Section | Page | Covers | | --- | --- | | [Pool Integration](https://docs.gearbox.finance/developers/pool-integration) | Deposit any pool underlying, withdraw it, check limits, and price pool shares | | [Obtaining RWA Underlying](https://docs.gearbox.finance/developers/obtain-rwa-underlying) | Mint or redeem `DefaultRWAUnderlying` when it is the asset accepted by a pool | ## Monitor Source: https://docs.gearbox.finance/developers/monitor-position File: content/developers/monitor-position.mdx Check a Credit Account's health factor, then inspect the balances, oracle prices, liquidation thresholds, and quotas that determine it. ## Connect SDK Follow [Connect SDK](https://docs.gearbox.finance/developers/sdk-setup) first. The snippets below use the already-connected instance as `sdk`. ## Find your leveraged position Read the leveraged positions owned by your wallet address, `owner`. Use the onchain source here so the position and the market data below come from RPC: ```typescript const positions = await sdk.positions.onchain.list({ wallet: owner, filter: { kind: "strategy" }, }); ``` `positions.data` contains the leveraged positions. Check `positions.meta.chains` for read status, block, and timestamp. A failed read does not mean there are no leveraged positions. With the strategy filter, each entry in `positions.data` is a `StrategyPosition`: | Field | Type | Meaning | | --- | --- | --- | | `kind` | `"strategy"` | Identifies a leveraged position | | `name` | `string` | Strategy name | | `chainId` | `number` | Chain where the position exists | | `creditAccount` | `Address` | Your position's Credit Account address | | `creditManager` | `Address` | Credit Manager governing the position | | `underlyingToken` | `UnderlyingToken` | Asset used to denominate debt and total value; the unwrapped asset for RWA markets | | `targetCollateral` | `Token \| null` | Strategy's target collateral token, or `null` when no target is identified | | `collaterals` | `PositionCollateral[]` | Held token balances, allocated quotas, and pending withdrawals | | `totalValue` | `TokenAmount` | Total value of the account's holdings in the market underlying | | `totalDebt` | `TokenAmount` | Debt principal plus accrued interest and fees | | `leverage` | `number` | Total value divided by equity: `4` means 4× | | `healthFactor` | `number` | Health factor in basis points: `12500` means 1.25 | | `borrowApy` | `number` | Annual base borrowing cost including the protocol interest fee, in basis points: `520` means 5.2% | | `borrowRate` | `BorrowRateBreakdown \| undefined` | Borrowing cost broken down into base and quota costs | | `timeToLiquidation` | `bigint \| null \| undefined` | Estimated milliseconds to HF 1 at a fixed borrowing rate and collateral value—no collateral yield or appreciation. Not a guaranteed safe period. `null` if the rate is zero or HF is already ≤ 1 | | `liquidationPrice` | `bigint \| null \| undefined` | Immediate price-change threshold for HF 1, using current balances, debt, and LTs. Underlying per collateral token, scaled by `10 ** 8`. Excludes future accrual and quota caps. `null` unless exactly one non-dust, non-underlying asset is held | | `error` | `string \| undefined` | Incomplete or failed valuation; balances may be available while valued fields are unreliable | `TokenAmount` contains `token`, `value`, and `valueUsd`. `value` is a `bigint` in that token's base units; `valueUsd` is a dollar value or `null` when unavailable. Equity is `totalValue.value - totalDebt.value`; the position does not have a `netValue` field. Backend-only fields such as historical APYs and PnL are not included in this onchain read. Select the account to inspect: ```typescript import type { StrategyPosition } from "@gearbox-protocol/sdk/model"; const selectedIndex = 0; // Index of your position in the returned list const position = positions.data[selectedIndex] as StrategyPosition; ``` ## Check health factor Health factor is the collateral value counted for solvency divided by total debt value: $$ \mathrm{HF} = \frac{\sum_i C_i}{D}, \qquad C_i = \begin{cases} \min(B_i P_i L_i,\; Q_i P_u), & \text{quota-bearing collateral} \\ B_i P_i L_i, & \text{collateral without a quota cap} \end{cases} $$ - $B_i$ is the token balance in whole-token units. - $P_i$ is its oracle price; $P_u$ is the underlying token's oracle price. - $L_i$ is its liquidation threshold as a fraction, such as $0.9$ for 90%. - $Q_i$ is its allocated quota in whole underlying-token units. - $D$ is total debt, including accrued interest and fees, valued using $P_u$. Prices must use the same currency. A quota caps the **LT-weighted value**, not the raw collateral value. An inactive quota contributes zero. The formula describes eligible collateral; the SDK also applies integer rounding and token eligibility and dust rules. Safe-price checks can use lower prices than the main oracle prices. The SDK reports `healthFactor` as $\lfloor 10000 \times \mathrm{HF} \rfloor$: `12500` means 1.25, and below `10000` the account is liquidatable. With zero debt, the SDK returns the sentinel `65535` instead of dividing by zero. A falling HF can come from a lower token balance or oracle price, a lower liquidation threshold, a binding quota, or growing debt. Inspect these components to distinguish the cause. Collateral yield can increase balances or the token's oracle price and improve HF, but only while the resulting contribution is not capped by quota. Borrowing interest and quota costs increase debt and reduce HF over time. A change in quota affects HF only when it changes the collateral value counted for solvency. A pending or claimable redemption does not eliminate debt or liquidation risk. Continue monitoring HF while [tracking settlement](https://docs.gearbox.finance/developers/delayed-withdrawals#monitor-settlement). ## Inspect collateral Each entry in `position.collaterals` describes one held token: | Field | Type | Meaning | | --- | --- | --- | | `collateral.token` | `Token` | Held token, including address, symbol, and decimals | | `collateral.value` | `bigint` | Balance in that token's base units | | `collateral.valueUsd` | `number \| null` | Dollar value, or `null` when unavailable | | `quota.value` | `bigint` | Allocated quota in market underlying base units, not collateral token units | | `withdrawals` | `DelayedReceivedAsset[]` | Pending delayed withdrawals associated with this collateral | The account can hold several tokens. Inspect every collateral entry, not just `targetCollateral`. A redemption phantom is reported as the held token; its pending underlying proceeds are described by `withdrawals`. This represents a claim, not liquid funds available in the wallet. See [claims, redeemers, and phantom tokens](https://docs.gearbox.finance/developers/delayed-withdrawals#claims-redeemers-and-phantom-tokens) for how the claim is held and counted as collateral. Prices and liquidation thresholds are available from the selected account's market. They are not fields of `PositionCollateral`. Select one held token: ```typescript const chain = sdk.onchain.chain(position.chainId); const suite = chain.marketRegister.findCreditManager(position.creditManager); const collateralIndex = 0; // Index of the collateral to inspect const token = position.collaterals[collateralIndex].collateral.token.address; const price = suite.market.priceOracle.mainPrice(token); // USD per token, 8 decimals const lt = suite.creditManager.liquidationThresholds.get(token); // Basis points: 9000 = 90% ``` `mainPrice()` throws if the price is unavailable; `lt` is `undefined` if the threshold is missing. Neither case is a successful valuation. Use `collateral.valueUsd` above for the held balance's dollar value. Read the position and its market data together. After refreshing chain state, read the position again rather than combining old balances with new prices or thresholds. ## Actions and their effect on HF | Action | Effect on HF | Requirements and dependencies | Side effects | | --- | --- | --- | --- | | [Repay](https://docs.gearbox.finance/developers/manage-position#repay) | Increases HF by reducing debt while retaining collateral | Underlying tokens held in your wallet, or the supported unwrapped asset for an RWA market; partial repayment must respect minimum debt | Spends wallet funds and reduces future debt interest; partial repayment does not automatically reduce quotas | | [Adjust leverage](https://docs.gearbox.finance/developers/manage-position#adjust-leverage) | Increasing leverage generally lowers HF; decreasing leverage generally raises it | Available swap or redemption paths; increasing leverage also requires borrowing and quota capacity | Slippage, price impact, and fees; deleveraging can require delayed settlement | | [Deposit](https://docs.gearbox.finance/developers/manage-position#deposit) | Approximately preserves HF when keeping current leverage | Wallet funds; increases position size by adding collateral and borrowing more, requiring routes and available capacity | Slippage and fees can change HF; increases exposure, debt, and potentially quota costs | | [Withdraw](https://docs.gearbox.finance/developers/manage-position#withdraw) | Approximately preserves HF for a proportional partial withdrawal | Decreases position net value by selling assets and repaying debt; requires an available withdrawal route | Slippage and fees; may trigger delayed operations, during which debt continues accruing costs | | [Add collateral](https://docs.gearbox.finance/developers/manage-position#add-collateral) | Can increase HF at fixed debt; no increase if the added value is excluded or already capped by quota | The position's collateral token held in your wallet; sufficient quota for its value to count where required | Commits more wallet funds without increasing debt; a direct token transfer has no swap slippage, but any associated quota increase can add costs | | [Withdraw collateral](https://docs.gearbox.finance/developers/manage-position#withdraw-collateral) | Lowers HF if it removes value counted for solvency; may leave HF unchanged while the remaining value still exceeds the quota cap | A directly withdrawable token and sufficient remaining collateral coverage | Returns tokens without reducing debt; reduces equity and generally increases leverage; a direct transfer has no swap slippage | | [Increase quota](https://docs.gearbox.finance/developers/manage-position#update-quota) | Raises HF only while quota caps the token's LT-weighted value | Active quota market and available quota capacity | More quota increases quota interest expense and may incur a quota-increase fee; the applicable quota rate can also change over time | | [Decrease quota](https://docs.gearbox.finance/developers/manage-position#update-quota) | Leaves HF unchanged until quota falls below the token's LT-weighted value; further reduction lowers HF | Remaining quota must provide sufficient collateral coverage | Reduces quota interest expense without changing balances or repaying debt | HF effects assume unchanged prices and liquidation thresholds. Deposit and withdraw preserve leverage by default, but quota caps and execution costs can prevent exact HF preservation. Preview the proposed action to check its actual effect before executing it. ## Source - [SDK position fields](https://github.com/Gearbox-protocol/sdk/blob/076de9c284c536c76eb3f93bc8284759acea539b/src/model/positions.ts) - [Collateral valuation](https://github.com/Gearbox-protocol/sdk/blob/076de9c284c536c76eb3f93bc8284759acea539b/src/onchain/accounts/intents/collateral-valuation.ts) ## Manage Source: https://docs.gearbox.finance/developers/manage-position File: content/developers/manage-position.mdx Manage a leveraged position in an existing Credit Account with the SDK. Find your wallet's leveraged positions, then select the account you want to change. These operations update that account; they do not open a second leveraged position. | Action | Effect on HF | Requirements and dependencies | Side effects | | --- | --- | --- | --- | | [Repay](https://docs.gearbox.finance/developers/manage-position#repay) | Increases HF by reducing debt while retaining collateral | Underlying tokens held in your wallet, or the supported unwrapped asset for an RWA market; partial repayment must respect minimum debt | Spends wallet funds and reduces future debt interest; partial repayment does not automatically reduce quotas | | [Adjust leverage](https://docs.gearbox.finance/developers/manage-position#adjust-leverage) | Increasing leverage generally lowers HF; decreasing leverage generally raises it | Available swap or redemption paths; increasing leverage also requires borrowing and quota capacity | Slippage, price impact, and fees; deleveraging can require delayed settlement | | [Deposit](https://docs.gearbox.finance/developers/manage-position#deposit) | Approximately preserves HF when keeping current leverage | Wallet funds; increases position size by adding collateral and borrowing more, requiring routes and available capacity | Slippage and fees can change HF; increases exposure, debt, and potentially quota costs | | [Withdraw](https://docs.gearbox.finance/developers/manage-position#withdraw) | Approximately preserves HF for a proportional partial withdrawal | Decreases position net value by selling assets and repaying debt; requires an available withdrawal route | Slippage and fees; may trigger delayed operations, during which debt continues accruing costs | | [Add collateral](https://docs.gearbox.finance/developers/manage-position#add-collateral) | Can increase HF at fixed debt; no increase if the added value is excluded or already capped by quota | The position's collateral token held in your wallet; sufficient quota for its value to count where required | Commits more wallet funds without increasing debt; a direct token transfer has no swap slippage, but any associated quota increase can add costs | | [Withdraw collateral](https://docs.gearbox.finance/developers/manage-position#withdraw-collateral) | Lowers HF if it removes value counted for solvency; may leave HF unchanged while the remaining value still exceeds the quota cap | A directly withdrawable token and sufficient remaining collateral coverage | Returns tokens without reducing debt; reduces equity and generally increases leverage; a direct transfer has no swap slippage | | [Increase quota](https://docs.gearbox.finance/developers/manage-position#update-quota) | Raises HF only while quota caps the token's LT-weighted value | Active quota market and available quota capacity | More quota increases quota interest expense and may incur a quota-increase fee; the applicable quota rate can also change over time | | [Decrease quota](https://docs.gearbox.finance/developers/manage-position#update-quota) | Leaves HF unchanged until quota falls below the token's LT-weighted value; further reduction lowers HF | Remaining quota must provide sufficient collateral coverage | Reduces quota interest expense without changing balances or repaying debt | HF effects assume unchanged prices and liquidation thresholds. Deposit and withdraw preserve leverage by default, but quota caps and execution costs can prevent exact HF preservation. Preview the proposed action to check its actual effect before executing it. ## Find your leveraged positions Follow [Connect SDK](https://docs.gearbox.finance/developers/sdk-setup) first. Using the connected `sdk`, list the leveraged positions owned by `owner`. Supply this address directly; no wallet connection is needed: ```typescript const positions = await sdk.positions.list(owner, { kind: "strategy" }); ``` `positions.data` contains your leveraged positions on the networks configured in the SDK. `positions.meta.chains` reports each chain's read status, block, and timestamp; a failed read does not mean that you have no leveraged positions on that chain. Select an entry from `positions.data`. Its `chainId` and `creditAccount` identify the leveraged position to pass to the operations below. The `creditManager` identifies its strategy, not the individual account. See [Monitor](https://docs.gearbox.finance/developers/monitor-position) for the position's balances, debt, leverage, and health factor. Amounts are `bigint` token base units: convert a user's decimal string using that token's decimals, as in the opening example. Leverage uses hundredths (`300n` = 3×), and slippage uses basis points (`5` = 0.05%). The SDK checks the chosen account and market limits. Select the leveraged position once: ```typescript import type { StrategyPosition } from "@gearbox-protocol/sdk/model"; const selectedIndex = 0; // Index of the account to manage const position = positions.data[selectedIndex] as StrategyPosition; ``` The operation snippets below are alternatives. Run the one you need, then use its successful `sim`, `position`, and `owner` in [Build, preview, and check](https://docs.gearbox.finance/developers/build-preview-check#update-a-leveraged-position). Quota updates build `tx` directly and continue at [Preview and check](https://docs.gearbox.finance/developers/build-preview-check#preview-and-check). The variables in each call are the inputs you supply, described by its table. All preparation methods accept these shared settings. Fields tagged **Optional** can be omitted. | Field | Type | Meaning | | --- | --- | --- | | `slippage` **Optional** | `number` | Swap slippage in basis points: `5` = 0.05%; defaults to 0 | | `quotaReserve` **Optional** | `number` | Extra quota buffer in basis points: `100` = 1%; defaults to 0 | ## Deposit Use `depositStrategy` to grow a leveraged position using funds from the wallet. The SDK borrows additional funds and routes the combined amount into the position token. | Field | Type | Meaning | | --- | --- | --- | | `token` | `Address` | Funding token: market underlying or supported unwrapped RWA asset | | `amount` | `bigint` | Deposit in funding token base units | | `targetLeverage` **Optional** | `bigint` | Target leverage in hundredths; defaults to current leverage | | `positionToken` **Optional** | `Address` | Token to buy; defaults to the largest non-phantom, non-underlying holding | | `value` **Optional** | `bigint` | Native value in wei when funding a wrapped-native market with the native coin | ```typescript const sim = await sdk.opportunities.prepare.depositStrategy(position, { token, amount, slippage, }); if (!sim.ok) throw sim.error; ``` Check the new borrowing requirement against current capacity. This differs from `addCollateral`, which adds the position token at fixed debt and lowers leverage. **Quota.** The SDK includes quota updates for changed balances, using their value, liquidation thresholds, and `quotaReserve`. Increases require available quota capacity and can increase quota costs. Inspect `sim.data.state.quotas`; no separate quota transaction is normally needed. **Approval.** For an ERC-20 deposit, resolve the spender: ```typescript const spender = await sdk.onchain.chain(position.chainId).accounts.getApprovalAddress({ creditManager: position.creditManager, creditAccount: position.creditAccount, }); ``` Check `token`'s allowance from `owner` to `spender` against `amount`, in token base units. If insufficient, call `approve(spender, amount)` on that token and wait for confirmation. Approve your deposit only, not the borrowed funds or total exposure. Reprepare and preview after approval. ## Withdraw Use `withdrawStrategy` to withdraw part of the position's equity. The SDK sells position assets and repays debt proportionally. Withdrawing all equity closes the position; follow [Close](https://docs.gearbox.finance/developers/close-leveraged-position) for the full exit flow, including instant and delayed routes. | Field | Type | Meaning | | --- | --- | --- | | `amount` | `bigint` | Amount to receive in `tokenOut` base units | | `to` | `Address` | Recipient of the withdrawn tokens | | `tokenOut` **Optional** | `Address` | Output token; defaults to underlying or the unwrapped RWA asset | | `sourceToken` **Optional** | `Address` | Token to sell; defaults to the largest non-phantom holding | ```typescript const prepared = await sdk.opportunities.prepare.withdrawStrategy(position, { amount, to, slippage, }); if (!prepared.ok) throw prepared.error; ``` **Route.** A successful preparation means at least one route is available; it does not guarantee instant withdrawal. Choose the route explicitly: ```typescript const route = "instant"; // Choose "delayed" for redemption with later settlement const selected = prepared.data[route]; if (!selected) throw prepared.data.errors[route] ?? new Error("Route unavailable"); const sim = { ok: true as const, data: selected }; ``` For a delayed route, the transaction only requests redemption. `selected.state` projects the result after completion; `selected.delayed.afterRequest` describes the account immediately after the request. Debt remains outstanding while it settles. The request records an [intent](https://docs.gearbox.finance/developers/delayed-withdrawals#intent) for the withdrawal steps that require the proceeds. Save the delayed route result with the confirmed transaction, then follow [Delayed operations](https://docs.gearbox.finance/developers/delayed-withdrawals#monitor-settlement) to track settlement and complete the operation. **Quota.** The SDK recalculates quotas for balances changed by the withdrawal, using their value, liquidation thresholds, and `quotaReserve`. Inspect the selected route's `state.quotas`; no separate quota transaction is normally needed. No wallet ERC-20 approval is required. Use `prepare.maxWithdraw(position)` to obtain withdrawal ceilings in underlying units. Do not compare those raw values to an amount in a different `tokenOut`. A partial withdrawal can be refused if the remaining loan falls below minimum debt, even when a full exit is possible. Passing `MAX_UINT256`, or an amount at or above net value, selects the [full exit flow](https://docs.gearbox.finance/developers/close-leveraged-position) instead of a partial withdrawal. `tokenOut` is then ignored. Review this change of intent before submitting; use `MAX_UINT256` when the intention is to exit completely. ## Repay Use `repayStrategy` to pay down debt with funds from the wallet while retaining the position assets. This reduces leverage rather than withdrawing equity. | Field | Type | Meaning | | --- | --- | --- | | `token` | `Address` | Funding token: underlying or supported unwrapped RWA asset | | `amount` | `bigint` | Payment in funding token base units; `MAX_UINT256` requests full repayment | | `value` **Optional** | `bigint` | Native value in wei when funding a wrapped-native market with the native coin | ```typescript const sim = await sdk.opportunities.prepare.repayStrategy(position, { token, amount, }); if (!sim.ok) throw sim.error; ``` `prepare.maxRepay(position)` reads the currently outstanding debt. Interest can accrue before the transaction lands. To settle in full, `amount: MAX_UINT256` asks the SDK to size funding with a 10-basis-point interest buffer; unused funds remain as collateral in the Credit Account. Show the actual funding requirement from the preview before approval. Partial repayments must respect minimum debt. **Quota.** Partial repayment leaves quotas unchanged. Full repayment clears the account's quotas automatically. **Approval.** For ERC-20 repayment, resolve the spender: ```typescript const spender = await sdk.onchain.chain(position.chainId).accounts.getApprovalAddress({ creditManager: position.creditManager, creditAccount: position.creditAccount, }); ``` Check the funding token's allowance from `owner` to `spender`. For a fixed repayment, approve `amount` in funding token base units. For `MAX_UINT256`, approve the actual required payment including the interest buffer; use `required.value` from an `insufficientAllowance` issue when approval is needed. Do not use the sentinel as the approval amount. If allowance is insufficient, call `approve(spender, approvalAmount)` on the funding token, wait for confirmation, then reprepare and preview. ## Add collateral Use `addCollateral` to transfer the position's collateral token from your wallet into the Credit Account. It does not borrow more or swap tokens. Unlike a leveraged deposit, it increases equity at fixed debt and lowers leverage. The HF improvement depends on how much of the added value counts after liquidation thresholds and quota limits. | Field | Type | Meaning | | --- | --- | --- | | `token` | `Address` | Position collateral token to add; this method does not accept arbitrary deposit tokens | | `amount` | `bigint` | Amount in that token's base units | | `value` **Optional** | `bigint` | Native value in wei when depositing the native coin into a wrapped-native position | ```typescript const sim = await sdk.opportunities.prepare.addCollateral(position, { token, amount, }); if (!sim.ok) throw sim.error; ``` **Quota.** The SDK can increase quota for the added token based on its resulting value, liquidation threshold, and `quotaReserve`. Existing quota may already cover it. An increase requires available quota capacity and can add quota costs even though no swap is performed. Inspect `sim.data.state.quotas`; no separate quota transaction is normally needed. Transferring tokens alone does not adjust quota. **Approval.** The wallet must hold the tokens. For ERC-20 collateral, resolve the spender: ```typescript const spender = await sdk.onchain.chain(position.chainId).accounts.getApprovalAddress({ creditManager: position.creditManager, creditAccount: position.creditAccount, }); ``` Check `token`'s allowance from `owner` to `spender` against `amount`, in that token's base units. If insufficient, call `approve(spender, amount)` on the token and wait for confirmation. Reprepare and preview after approval. ## Withdraw collateral Use `withdrawCollateral` to transfer a token already held in the Credit Account to a recipient **without repaying debt**. Remaining collateral must support the debt; this action increases leverage. | Field | Type | Meaning | | --- | --- | --- | | `token` | `Address` | Held token to withdraw | | `amount` | `bigint` | Amount in that token's base units | | `to` | `Address` | Recipient of the tokens | ```typescript const sim = await sdk.opportunities.prepare.withdrawCollateral(position, { token, amount, to, }); if (!sim.ok) throw sim.error; ``` Use `sdk.opportunities.prepare.withdrawableCollaterals(position)` to list withdrawable tokens from the selected position. This excludes assets that cannot be transferred directly, such as pending-redemption phantom tokens. Use `prepare.maxWithdrawCollateral(position, token)` for a current ceiling, then prepare the requested amount again before submitting. **Quota.** The SDK can reduce the withdrawn token's quota based on its remaining value, liquidation threshold, and `quotaReserve`. Inspect `sim.data.state.quotas`; no separate quota transaction is normally needed. No wallet ERC-20 approval is required. ## Adjust leverage Use `adjustLeverage` to change exposure without depositing or withdrawing wallet funds. Increasing leverage borrows and buys; decreasing leverage sells or redeems assets and repays debt. | Field | Type | Meaning | | --- | --- | --- | | `targetLeverage` | `bigint` | Target leverage in hundredths: `300n` = 3×; `100n` requests no debt | | `token` **Optional** | `Address` | Token to buy or sell; defaults to the largest non-phantom, non-underlying holding | ```typescript const prepared = await sdk.opportunities.prepare.adjustLeverage(position, { targetLeverage, slippage, }); if (!prepared.ok) throw prepared.error; ``` **Route.** Increasing leverage has only an instant route. Decreasing leverage can also use delayed redemption. Successful preparation means at least one route is available; choose it explicitly: ```typescript const route = "instant"; // Choose "delayed" for redemption with later settlement const selected = prepared.data[route]; if (!selected) throw prepared.data.errors[route] ?? new Error("Route unavailable"); const sim = { ok: true as const, data: selected }; ``` For a delayed decrease, the transaction only requests redemption; it does not repay debt yet. `selected.state` projects the completed operation, while `selected.delayed.afterRequest` describes the account after the request alone. Inspect both states and save the delayed route result with the confirmed request transaction. The [intent](https://docs.gearbox.finance/developers/delayed-withdrawals#intent) preserves the leverage adjustment that must wait for the proceeds. Continue with [Delayed operations](https://docs.gearbox.finance/developers/delayed-withdrawals#monitor-settlement) to track settlement and complete the leverage decrease. **Quota.** The SDK updates quotas for changed balances. Increasing exposure can require more quota capacity and increase quota costs; reducing exposure can reduce quota. Inspect the selected route's `state.quotas`. No wallet ERC-20 approval is required. ## Update quota Use the connected SDK to build a quota update for the selected `position`. There is no high-level `prepare.adjustQuota()` method; the Credit Facade provides `prepareUpdateQuotas()`. | Variable | Type | Meaning | | --- | --- | --- | | `quotaToken` | `Address` | Collateral token whose quota you want to change | | `quotaChange` | `bigint` | Signed quota change: positive to increase, negative to decrease, in pool underlying base units | | `minQuota` | `bigint` | Minimum acceptable resulting quota, in pool underlying base units | These amounts use the pool underlying's decimals, not the collateral token's decimals. Quota changes are rounded down by the Credit Facade to a multiple of `10000` base units; account for that when setting `minQuota`. ```typescript const chainId = position.chainId; const chain = sdk.onchain.chain(chainId); const account = await chain.accounts.getCreditAccountData(position.creditAccount); if (!account || !account.success) throw new Error("Credit Account data unavailable"); const suite = chain.marketRegister.findCreditManager(account.creditManager); const calls = suite.creditFacade.prepareUpdateQuotas({ averageQuota: [{ token: quotaToken, balance: quotaChange }], minQuota: [{ token: quotaToken, balance: minQuota }], }); const tx = await chain.accounts.executeCaUpdate(account, calls); ``` Continue with this `tx`, `chainId`, and `owner` at [Preview and check](https://docs.gearbox.finance/developers/build-preview-check#preview-and-check). Increasing quota uses available quota capacity and can increase quota costs. Decreasing quota can reduce the position's health factor. This changes the account's quota; `quotaReserve` is a buffer used when preparing other operations. ## Source - [SDK preparation contracts](https://github.com/Gearbox-protocol/sdk/blob/93df7583a73ea533dacdc73aa2a9073460d97185/src/sdk/prepare/types.ts) ## Close Source: https://docs.gearbox.finance/developers/close-leveraged-position File: content/developers/close-leveraged-position.mdx Close a leveraged position by withdrawing all its equity: sell or redeem the position assets, repay the loan including accrued interest and fees, and send the remaining funds to the recipient. This uses the same `withdrawStrategy` method as [Manage → Withdraw](https://docs.gearbox.finance/developers/manage-position#withdraw), with `MAX_UINT256` selecting a full exit. The Credit Account remains open and empty. Closing the position here means ending its exposure and debt, not permanently closing the Credit Account. ## Select the position Use the connected `sdk`, `owner`, and `position` from [Find your leveraged positions](https://docs.gearbox.finance/developers/manage-position#find-your-leveraged-positions). Refresh the selected position before preparing the exit. ## Prepare the exit ```typescript import { MAX_UINT256 } from "@gearbox-protocol/sdk/onchain"; const prepared = await sdk.opportunities.prepare.withdrawStrategy(position, { amount: MAX_UINT256, to: owner, slippage, }); if (!prepared.ok) throw prepared.error; ``` | Field | Type | Meaning | | --- | --- | --- | | `amount` | `bigint` | `MAX_UINT256` requests full repayment and withdrawal of the remaining balances | | `to` | `Address` | Recipient of the exit proceeds | | `sourceToken` **Optional** | `Address` | Position token to redeem; defaults to the most valuable non-phantom holding | | `slippage` **Optional** | `number` | Swap slippage in basis points; defaults to 0 | | `quotaReserve` **Optional** | `number` | Extra quota buffer in basis points; defaults to 0 | For a full exit, `tokenOut` is ignored: proceeds use the market underlying, unwrapped on RWA markets. The mF-ONE/frxUSD position returns frxUSD. No wallet ERC-20 approval is needed. If the account holds several assets, specify the intended redemption token as `sourceToken`. ## Choose instant or delayed A successful preparation means at least one route is available. Select the route explicitly: ```typescript const route = "delayed"; // Choose "instant" to exit in one transaction const selected = prepared.data[route]; if (!selected) throw prepared.data.errors[route] ?? new Error("Route unavailable"); const sim = { ok: true as const, data: selected }; ``` | Route | First transaction | When funds reach the recipient | | --- | --- | --- | | `instant` | Sells assets, repays debt, and withdraws the remainder | In that transaction | | `delayed` | Requests redemption and records the full-exit intent | After settlement, when you submit the finalization transaction | A delayed exit is complete only after claiming, repayment, and withdrawal. See [how delayed operations work](https://docs.gearbox.finance/developers/delayed-withdrawals#how-delayed-operations-work) for the lifecycle and the role of the recorded intent. For `delayed`, `selected.state` projects the completed exit; `selected.delayed.afterRequest` describes the account after the request itself. Debt remains outstanding and the account can still be liquidated while waiting. Save `selected.delayed.record` with the confirmed request for intent recovery on older withdrawal compressors. ## Build and execute Continue with `position`, `sim`, and `owner` in [Build, preview, and check](https://docs.gearbox.finance/developers/build-preview-check#update-a-leveraged-position). That produces the transaction's destination, calldata, and value. Signing and execution belong to your chosen execution system. For ordinary markets, this SDK flow calls the Credit Facade's `multicall(creditAccount, calls)`; RWA markets can route through the applicable RWA factory. Use the transaction destination returned by the builder. For a delayed exit, the first multicall submits the redemption; a later multicall claims the proceeds, repays debt, and withdraws the remainder. You do not call `closeCreditAccount` for this flow. For the delayed route, [monitor settlement](https://docs.gearbox.finance/developers/delayed-withdrawals#monitor-settlement) after the request confirms, then [claim and complete the operation](https://docs.gearbox.finance/developers/delayed-withdrawals#claim-and-complete-the-operation). ## Confirm completion After an instant exit or delayed finalization confirms, refresh the position and withdrawals. Verify that debt is zero, the intended request has no pending or claimable balance, no material position assets or other redemption claims remain, and the expected funds reached `to`. Check the receipt and fresh per-chain read metadata; empty withdrawal arrays alone do not prove an exit. The Credit Account may remain in the position list with zero debt and only dust balances. Monitor debt, balances, and transfers rather than waiting for the account to disappear. ## Source - [SDK withdrawal and finalization](https://github.com/Gearbox-protocol/sdk/blob/d9699ecce9e74d39651d9b3b455f93e9c67b3b85/src/sdk/prepare/PrepareApi.ts) - [Transaction builder](https://github.com/Gearbox-protocol/sdk/blob/d9699ecce9e74d39651d9b3b455f93e9c67b3b85/src/sdk/execute/ExecuteApi.ts) ## Delayed operations Source: https://docs.gearbox.finance/developers/delayed-withdrawals File: content/developers/delayed-withdrawals.mdx Some assets cannot be redeemed for liquid funds immediately. To understand how Gearbox handles this, first consider the steps that make up a position-management operation. ## How position-management operations work A single operation combines several actions inside the Credit Account: | Operation | Steps | | --- | --- | | [Deposit](https://docs.gearbox.finance/developers/manage-position#deposit) | Add the user's funds to the Credit Account → borrow additional underlying → **convert the combined funds into the target asset** | | [Withdraw](https://docs.gearbox.finance/developers/manage-position#withdraw) | **Convert some target assets into underlying** → repay the corresponding debt → transfer the remaining proceeds to the recipient | | [Close](https://docs.gearbox.finance/developers/close-leveraged-position) | **Convert the position's assets into underlying** → repay all outstanding debt → transfer the remaining equity to the recipient | The **target asset** is the asset held for exposure; the **underlying** is the asset borrowed from the lending pool. Here, **convert** can mean a market swap or a deposit or redemption through the asset's protocol. > **Conversion can block the following steps.** If redemption takes time, > the underlying is not available yet. Repayment and withdrawal funded by > that conversion must wait until the proceeds can be claimed. When conversion is immediate, those steps can execute together in one transaction. ### Intent An **intent** is a piece of data recorded onchain for application use. It describes the planned steps after a delayed conversion. For Withdraw, this includes the repayment and transfer parameters, such as the requested withdrawal amount and recipient. It helps the application prepare the follow-up transaction; it does not obligate the user to follow that plan. After claiming, the user can choose different valid Credit Account operations. ## How delayed operations work If conversion requires a redemption period, the first transaction requests redemption but cannot yet execute the steps that depend on its proceeds. For a withdrawal, the sequence becomes: **Request redemption → Wait for settlement → Claim proceeds → Repay debt → Withdraw remaining proceeds** Repayment and withdrawal funded by those proceeds must wait. The user can still perform other permitted actions, such as adding collateral or repaying debt with wallet funds. ![The Credit Account's collateral changes from the original token to a pending redemption claim, then to redemption proceeds after collection.](https://docs.gearbox.finance/assets/docs/core/usecase-direct-redemptions/redemption-lifecycle.png) Borrowing costs continue until repayment; keep monitoring [health factor](https://docs.gearbox.finance/developers/monitor-position#check-health-factor) while waiting. ## Claims, redeemers, and phantom tokens The request replaces the redeemed portion of the position asset with a claim on future proceeds. These contracts and accounting concepts serve different roles: | Concept | Role | | --- | --- | | **Redeemer** | an escrow contract that holds the request and claim rights on behalf of the Credit Account and receives settlement proceeds. | | **Phantom token** | Gearbox's accounting representation of pending and claimable proceeds until claimed. Its value can count as Credit Account collateral under the market's oracle, liquidation threshold, and quota rules; it is not liquid cash sent to the user's wallet | For gateway-based redemptions, the gateway records which account owns each redeemer and controls transfers of its funds. Claiming through the gateway returns the settlement proceeds to the owning account. Liquidation is one use of this ownership model: it can transfer the redeemer to a liquidator. See [redeemers during liquidation](https://docs.gearbox.finance/developers/delayed-redemptions#redeemers-during-liquidation). ## Monitor settlement Use the connected `sdk` and the leveraged `position` selected in [Manage](https://docs.gearbox.finance/developers/manage-position#find-your-leveraged-positions). ```typescript const withdrawals = await sdk.positions.getCurrentWithdrawals({ chainId: position.chainId, creditAccount: position.creditAccount, creditManager: position.creditManager, }); ``` | Field | Type | Meaning | | --- | --- | --- | | `data.pending` | `PositionPendingWithdrawal[]` | Requests still waiting for settlement | | `data.pending[].claimableAt` | `Timestamp` | Expected claimable time, in Unix seconds; reread status before claiming | | `data.pending[].expectedOutputs` | `WithdrawalOutputAmount[]` | Estimated settlement outputs | | `data.claimable` | `PositionClaimableWithdrawal[]` | Matured withdrawals available to claim now | | `data.claimable[].outputs` | `WithdrawalOutputAmount[]` | Outputs of the claim; `isDelayed: true` means that output still needs a later claim | | `data.claimable[].withdrawalPhantomToken` | `TokenAmount` | Withdrawal representation and amount burned by the claim | | `data.claimable[].claimCall` | `TxCall` | Encoded adapter call to include in a Credit Facade multicall | | `meta.chains` | Per-chain metadata | Source, block, timestamp, and read status | - Match your request using `sourceToken` and `redeemer` where available; one Credit Account may have several requests. - Proceed when your request appears in a fresh `data.claimable` response, not merely when `claimableAt` has passed. ## Claim and complete the operation The claim executes inside a Credit Facade multicall. Choose either path: - **Follow the intent:** use `finalize` to prepare the claim and remaining steps. - **Choose different actions:** include the claim in a custom multicall. ### Follow the intent `finalize` prepares the claim together with the remaining steps, such as repaying debt and transferring the requested withdrawal to the wallet. Here, `claimableIndex` is your application's selection from the fresh response, matched to the request being completed; do not default to the first entry. ```typescript const claimable = withdrawals.data.claimable[claimableIndex]; if (!claimable) throw new Error("Selected withdrawal is not claimable"); const sim = await sdk.opportunities.prepare.finalize(position, { claimable, slippage, }); if (!sim.ok) throw sim.error; ``` | Field | Type | Meaning | | --- | --- | --- | | `claimable` | `PositionClaimableWithdrawal` | Fresh matured withdrawal selected above | | `slippage` **Optional** | `number` | Swap slippage in basis points; defaults to 0 | | `quotaReserve` **Optional** | `number` | Extra quota buffer in basis points; defaults to 0 | | `intent` **Optional** | `ResumableIntent` | Operation to resume; defaults to the intent recorded in the withdrawal | If the reader does not return an intent, pass the saved request's `delayed.record` as `intent` to `finalize`. Continue with `position`, `sim`, and `owner` in [Build, preview, and check](https://docs.gearbox.finance/developers/build-preview-check#update-a-leveraged-position). Refresh the leveraged position and its withdrawals after confirmation. If an output has `isDelayed: true`, some value still awaits settlement; refresh the request and repeat finalization when the next proceeds are claimable. For a full exit, verify zero debt and receipt of the remaining funds by the recorded recipient, as described in [Close](https://docs.gearbox.finance/developers/close-leveraged-position#confirm-completion). ### Build a custom multicall Include `claimable.claimCall` followed by your chosen actions instead of executing the intent. The claimed token may not count as collateral, so a claim by itself is not always a valid transaction. See [Build a custom multicall](https://docs.gearbox.finance/developers/build-custom-multicall#include-a-delayed-claim) for call construction, ordering, and transaction building. ## Source - [SDK withdrawal structures](https://github.com/Gearbox-protocol/sdk/blob/076de9c284c536c76eb3f93bc8284759acea539b/src/model/withdrawals.ts) - [Preparation and finalization contracts](https://github.com/Gearbox-protocol/sdk/blob/076de9c284c536c76eb3f93bc8284759acea539b/src/sdk/prepare/types.ts) - [Midas redeemer request and settlement balances](https://github.com/Gearbox-protocol/integrations-v3/blob/096d9b18f943de1ee73b28daa530f27f31f57577/contracts/integrations/midas/MidasRedeemer.sol) ## Build, preview, and check Source: https://docs.gearbox.finance/developers/build-preview-check File: content/developers/build-preview-check.mdx Turn a prepared operation into transaction calldata, assess its projected effect, and check its prerequisites. Continue here from [Open](https://docs.gearbox.finance/developers/open-leveraged-position), [Manage](https://docs.gearbox.finance/developers/manage-position), [Close](https://docs.gearbox.finance/developers/close-leveraged-position), or [Delayed operations](https://docs.gearbox.finance/developers/delayed-withdrawals). For individually selected calls, start with [Build a custom multicall](https://docs.gearbox.finance/developers/build-custom-multicall), then continue at [Preview and check](#preview-and-check) with its `tx`. Use the already-connected `sdk` and supply the sender's address as `owner`. No wallet connection or signer is required. The result is a transaction payload; signing and execution are up to you. ## Build the transaction Choose the builder for your operation. Each snippet defines `chainId` and `tx` for the shared preview below. If an operation already produced `tx`, such as a [quota update](https://docs.gearbox.finance/developers/manage-position#update-quota), skip to [Preview and check](#preview-and-check) with its `chainId` and `owner`. ### Open a leveraged position Use `strategy`, `selectedStrategy`, `params`, and the successful `sim` from [Open](https://docs.gearbox.finance/developers/open-leveraged-position#prepare-the-transaction). `owner` is the address funding and owning the new Credit Account. ```typescript const chainId = strategy.chainId; const targetToken = params.targetToken ?? selectedStrategy.data.targetCollateral.address; const tx = await sdk.opportunities.execute.buildTx({ kind: "open", chainId, creditManager: strategy.creditManager, wallet: owner, collateral: params.collateral, ethAmount: 0n, targetToken, sim, }); ``` ### Update a leveraged position Use the selected `position` and successful `sim` from an operation in [Manage](https://docs.gearbox.finance/developers/manage-position) or from [finalizing a delayed withdrawal](https://docs.gearbox.finance/developers/delayed-withdrawals#claim-and-complete-the-operation). For a routed operation, pass the chosen route's result, not the two-route container. Quota updates already produced `tx` and do not use this builder. ```typescript const chainId = position.chainId; const tx = await sdk.opportunities.execute.buildTx({ kind: "account", chainId, creditAccount: position.creditAccount, wallet: owner, sim, }); ``` ## Preview and check `previewOperation()` estimates the transaction's effect. `checkOperation()` checks the operation's prerequisites, including token approvals, balances, market limits, and the chosen HF thresholds. For an opening or reopening, it also checks applicable KYC/registration requirements. Neither call signs or broadcasts a transaction. ```typescript const preview = await sdk.preview.previewOperation({ chainId, to: tx.to, calldata: tx.callData, value: BigInt(tx.value), sender: owner, }); if (!preview.ok) throw preview.error; const issues = await sdk.preview.checkOperation( { chainId, preview: preview.data, sender: owner }, { minHealthFactor: 10_500, // Require HF >= 1.05 at main prices (basis points) minSafeHealthFactor: 10_500, // Require HF >= 1.05 at safe prices }, ); ``` These thresholds leave a buffer above the liquidation boundary, HF 1.0. Choose the buffer for your risk policy; omitting a threshold disables that check. They are SDK validation settings, not constraints added to the calldata. ## Read the preview result `preview.ok` means the SDK could produce a preview; it does not mean the operation passed validation. Read `preview.data.operation` to identify the result's structure. It describes the decoded transaction, so do not infer it solely from the preparation method you called. | `operation` | Meaning | | --- | --- | | `"OpenCreditAccount"` | Opening a leveraged position; also used when borrowing again on an existing account with zero debt and no quotas | | `"AdjustCreditAccount"` | Account adjustment, including quota changes and partial repayments | | `"RepayCreditAccount"` | Full repayment | | `"CloseCreditAccount"` | Exit | | `"DelayedCreditAccountOperation"` | `instantPreview` describes the account after the request; `delayedPreview` is the best-effort result after claiming and resuming the recorded operation. `estClaimableAt` **Optional** is the estimated claimable time in Unix seconds | For delayed operations, inspect both nested previews. `checkOperation()` checks only `instantPreview`; it does not validate the future claim. If no intent was recorded, `delayedPreview` describes the claim alone. These previews describe different stages of the [delayed operation lifecycle](https://docs.gearbox.finance/developers/delayed-withdrawals#how-delayed-operations-work). Follow [Delayed operations](https://docs.gearbox.finance/developers/delayed-withdrawals#monitor-settlement) to track settlement and complete the remaining steps. The fields below are on `preview.data` for immediate operations, or on each nested preview for a delayed operation. Compare them with the current leveraged position, if any, and the outcome you requested. For immediate operations and `instantPreview`, fields prefixed with `est` use the minimum swap outputs encoded in calldata; preparation reports expected outputs instead. `delayedPreview` uses oracle-based estimates for future conversions, so its amounts are not guaranteed swap minimums. | Field | Type | Meaning | | --- | --- | --- | | `creditAccount` **Optional on opening** | `Address \| undefined` | Account affected; when updating a position, check that it matches the selected account | | `creditManager` | `Address` | Credit Manager identifying the strategy affected | | `name` | `string` | Strategy name | | `underlyingToken` | `UnderlyingToken` | Asset used to denominate value and debt; the unwrapped asset for RWA markets | | `targetCollateral` **Optional on opening** | `TokenAmount \| undefined` | Opening only: target collateral and its balance at minimum swap output; absent when nothing is quoted | | `targetCollateral` | `Token \| null` | Adjustment, repayment, exit, or delayed request: target token metadata, without a balance | | `totalDebt` | `TokenAmount` | Debt after the operation, including interest and fees | | `estTotalValue` | `TokenAmount` | Projected value remaining in the account | | `estNetValue` | `TokenAmount` | Remaining equity: account value minus debt | | `estAssets` | `TokenAmount[]` | Projected token balances remaining in the account | | `quotas` | `TokenAmount[]` | Resulting quotas; each `token` identifies collateral, but `value` is in market underlying base units | | `estLeverage` | `number` | Resulting leverage as a multiple: `4` means 4× | | `estHealthFactor` | `number` | HF in basis points: `12500` means 1.25; below `10000` is liquidatable | | `estSafeHealthFactor` | `number` | HF using safe collateral prices, in the same units | | `estBorrowRate.base` | `number` | Annual base borrowing cost including the protocol interest fee, in basis points | | `estBorrowRate.totalOnDebt` | `number` | Annual borrowing cost including quotas, relative to debt, in basis points | | `estBorrowRate.total` | `number` | Annual borrowing cost including quotas, relative to account value, in basis points | | `estBorrowRate.quotas` | `TokenQuotaRate[]` | Per-collateral quota cost; each `rate` is in basis points relative to account value | | `estTimeToLiquidation` | `bigint \| null` | Estimated milliseconds to HF 1 with fixed collateral value and borrowing rate; excludes collateral yield. `null` if debt has no rate or the account is already liquidatable | | `estLiquidationPrice` | `bigint \| null` | Immediate HF 1 price threshold, in underlying per collateral token scaled by `10 ** 8`; excludes future accrual and quota caps. `null` unless a single non-underlying collateral applies | | `collateralAdded`, `collateralWithdrawn` | `TokenAmount[]` | Tokens supplied and returned by an opening, adjustment, or repayment; exits report `receivedAmount` instead | | `totalDebtChange` | `TokenAmount` | Adjustment only: debt after minus debt before; negative means debt was repaid | | `assetsChange` | `TokenAmount[]` | Adjustment only: token balances after minus balances before | | `quotasChange` | `TokenAmount[]` | Adjustment only: quotas after minus quotas before, in market underlying base units, with each `token` identifying the collateral | | `debtRepaid` | `TokenAmount` | Repayment only: positive amount of debt settled | | `receivedAmount` | `TokenAmount` | Exit only: output returned to the recipient; minimum for an immediate exit, estimated for delayed completion | | `permanent` | `boolean` | Repayment or exit only: whether the Credit Account is permanently closed; `false` means it remains open | | `warning` **Optional** | `UnpriceableTokenError` | A token could not be priced and was excluded from valuation; investigate before relying on the value and HF figures | `TokenAmount` contains `token`, `value` (`bigint` base units), and `valueUsd` (`number` or `null` when unavailable). Format amounts using their token's decimals, except `quotas` and `quotasChange`: those use market underlying decimals even though their token metadata identifies collateral. Rates use basis points: `520` means 5.2%. ## Resolve validation issues `issues` is an `OperationValidationError[]`. An empty array means no issues were found by the applicable checks, not that a transaction was executed or successfully simulated. Each issue has a machine-readable `code` and an explanatory `message`; use `code` to access its details. For example, `insufficientAllowance` includes `owner`, `spender`, `required`, and `allowed`; `insufficientCollateral` includes `healthFactor`, `healthFactorThreshold`, and `safePrices`. Review the projected outcome even when `issues` is empty. Resolve prerequisites, including the approvals described in the action guide. `insufficientAllowance` is a pre-transaction validation issue, not a failed transaction. Approval execution belongs to your chosen execution flow. After an approval confirms or the inputs change, repeat the action's preparation and build steps, selecting its route if applicable. For a direct quota transaction, repeat the quota update steps. Preview and check the new `tx`, then resolve any remaining issues. ## Transaction payload The output is `tx`, to hand to your chosen execution system: | Field | Meaning | | --- | --- | | `tx.to` | Destination contract | | `tx.callData` | Encoded calldata; use as `data` in an Ethereum transaction request | | `tx.value` | Native-token amount in wei; convert with `BigInt(tx.value)` if required by the executor | Keep `chainId` and `owner` with this payload: they identify the chain and sender used for the checks. Signing and execution are up to you. If execution is delayed, prepare, build, and check again. After execution, use [Monitor](https://docs.gearbox.finance/developers/monitor-position) to read the leveraged position. ## Source - [Transaction builder](https://github.com/Gearbox-protocol/sdk/blob/93df7583a73ea533dacdc73aa2a9073460d97185/src/sdk/execute/ExecuteApi.ts) - [Preview result structures](https://github.com/Gearbox-protocol/sdk/blob/93df7583a73ea533dacdc73aa2a9073460d97185/src/model/previews.ts) - [Operation checks](https://github.com/Gearbox-protocol/sdk/blob/93df7583a73ea533dacdc73aa2a9073460d97185/src/onchain/validation/checkOperation.ts) ## Build a custom multicall Source: https://docs.gearbox.finance/developers/build-custom-multicall File: content/developers/build-custom-multicall.mdx A multicall executes an ordered list of Credit Account actions in one transaction. Use it when you want to choose the individual steps instead of using a prepared operation from [Manage](https://docs.gearbox.finance/developers/manage-position) or following a [delayed operation's intent](https://docs.gearbox.finance/developers/delayed-withdrawals#intent). ## Calls and their targets Each `MultiCall` entry contains: | Field | Meaning | | --- | --- | | `target` | Credit Facade for account actions, or an adapter allowed by this Credit Manager for protocol interactions | | `callData` | Encoded function and arguments for that target | Use SDK helpers to encode account actions and the [router](#generate-adapter-calls-with-the-router) to generate supported conversion paths. Encode adapter calls directly only for operations the router does not cover; do not substitute a protocol contract or token address as the target. The batch executes in order and reverts if a call or required account check fails. ## Available actions ### Credit Facade actions These are the supported Credit Facade multicall entries for V3.1. Their `target` is the account's Credit Facade. Token amounts use integer base units, not human-readable decimals: `1_000_000n` represents 1 token with 6 decimals. In TypeScript, use `bigint` for amounts, quotas, and bitmasks. `MAX_UINT256` below means `2^256 - 1`. Debt changes must respect market limits and cannot be repeated in the same block for an account. Full repayment requires all quotas to be disabled. Opening, closing, liquidation, and bot-driven batches have additional permissions; this guide uses an owner-driven update of an existing account. These are entries inside the batch. Functions such as `multicall`, `openCreditAccount`, and `closeCreditAccount` are transaction entry points, not calls to nest inside it. | Action | Arguments and behavior | | :--- | :--- | | `addCollateral` | Transfer approved tokens from the caller into the Credit Account. The caller must approve the Credit Manager. | | `addCollateralWithPermit` | Add collateral using an EIP-2612 permit. The caller signs the permit with the Credit Manager as spender and the funding amount as value. | | `increaseDebt` | Borrow underlying into the Credit Account. | | `decreaseDebt` | Repay using underlying already held by the Credit Account.An amount covering the total debt requests full repayment. Use MAX_UINT256 for full repayment; the Credit Account still needs sufficient underlying to fund it. | | `withdrawCollateral` | Transfer collateral from the Credit Account to a recipient.For a supported phantom token, withdrawal redeems it and sends its deposited token to the recipient. | | `updateQuota` | Increase, reduce, or disable a collateral token's quota.A positive change increases quota; a negative change reduces it. Use -2^95 to disable the quota and 0 as the minimum. The call reverts if the resulting quota is below minQuota. | | `setBotPermissions` | Set or revoke a bot's access to the Credit Account.Combine permission bits with bitwise OR:A nonzero grant must exactly match the bot's requiredPermissions(). Other bits are rejected, including the set-bot-permissions bit (1n << 8n). | | `onDemandPriceUpdates` | Submit price updates. This call must be first in the batch. executeCaUpdate supplies the required updates.Each update contains: | | `storeExpectedBalances` | Record minimum balances to check after subsequent operations.Each delta contains:The stored floor is the balance at this call plus the delta. A positive delta requires a gain, a negative delta permits a bounded spend, and zero requires the starting balance to be preserved. For example, 100 starting units with a delta of −30 sets a floor of 70. The floor cannot be negative.Call compareBalances before storing another set of expectations. The ABI field is named amount, not minBalanceDelta. | | `compareBalances` | No arguments. Check that current balances are at least the stored floors, then clear the expectations. Reverts if no expectations were stored.Outstanding expectations are checked automatically at the end of the batch. | | `setFullCheckParams` | Configure the final collateral check. Unavailable during closure or liquidation.Each hint is an individual, single-bit collateral token mask from the Credit Manager. Token addresses, combined masks, and the underlying mask are not valid.For the health factor, 10000 means 1.0 and 12000 means 1.2. Values below 10000 revert. | ### Adapter actions Adapter actions depend on the integrations enabled for the selected Credit Manager. Common categories include: | Action | Examples | | --- | --- | | Swap | Exchange tokens through an allowed DEX adapter | | Deposit or mint | Convert tokens into vault shares or a position token | | Withdraw or redeem | Convert shares or position tokens back into assets | | Add or remove liquidity | Enter or exit a liquidity pool | | Stake or unstake | Enter or exit a supported staking position | | Claim rewards | Collect rewards from a supported position | | Request redemption | Start a [delayed operation](https://docs.gearbox.finance/developers/delayed-withdrawals) | | Claim redemption | Collect proceeds through the integration's claim adapter | | Integration-specific operations | For example, receive a Midas greenlisting or transfer a redeemer where permitted | There is no single fixed list of adapter methods across all markets. For supported conversions, the router assembles the adapter chain for you. Use the selected suite's `creditManager.adapters` and each adapter's ABI to identify its supported calls. A method's presence does not remove its permissions or integration-specific requirements. ## Select the account Start with the connected `sdk`, `owner`, and `position` from [Manage](https://docs.gearbox.finance/developers/manage-position#find-your-leveraged-positions). ```typescript import type { MultiCall } from "@gearbox-protocol/sdk/onchain"; const chainId = position.chainId; const chain = sdk.onchain.chain(chainId); const account = await chain.accounts.getCreditAccountData(position.creditAccount); if (!account) throw new Error("Credit Account not found"); const suite = chain.marketRegister.findCreditManager(account.creditManager); const facade = suite.creditFacade; ``` ## Assemble the calls For example, repay part of a loan with wallet funds: **add underlying → repay**. Here, `repayAmount` is a positive `bigint` in the pool underlying's base units. This example uses an ordinary ERC-20 underlying; RWA markets may require additional wrapping or factory-specific steps. ```typescript if (repayAmount <= 0n) throw new Error("Repayment must be positive"); const calls: MultiCall[] = [ ...facade.prepareAddCollateral([ { token: account.underlying, balance: repayAmount }, ], {}), facade.prepareChangeDebt(repayAmount, true), // true means decrease debt ]; ``` Approve the funding amount to the SDK-resolved spender before execution, as described in [Repay](https://docs.gearbox.finance/developers/manage-position#repay). Partial repayment must leave debt above the market minimum. These helpers encode calls; they do not calculate an affordable amount or validate the operation. For other batches, order the steps by their dependencies: - **Claim → convert → repay → withdraw:** claim before spending its proceeds. - **Quotas:** include required quota updates when changing collateral; the transaction builder does not derive them for you. - **Swap limits:** preserve the route's minimum outputs and balance checks. - **Final state:** leave sufficient eligible collateral for the remaining debt. A claimed token may need conversion before its value counts toward HF. ## Generate adapter calls with the router The router is an onchain contract that builds a conversion path using the adapters available in the relevant Credit Manager. It returns the ordered adapter calls needed to execute that path. Use `chain.routerFor(account)` to find a conversion path through the market's supported integrations. This is a read-only quote: it returns ordered `route.calls` to insert into your batch, not a router transaction to send. As an alternative to the wallet-funded example above, **convert collateral → repay**. Here, `tokenIn` differs from the underlying, `inputBalance` is its available balance when the route executes, and `swapAmount` is the portion to convert. Amounts are `bigint` base units; `slippage` is in basis points (`100` means 1%). ```typescript if (swapAmount <= 0n || swapAmount > inputBalance) { throw new Error("Invalid conversion amount"); } const route = await chain.routerFor(account).findManyToOnePath({ creditAccount: account, creditManager: suite.creditManager, expectedBalances: [{ token: tokenIn, balance: inputBalance }], leftoverBalances: [{ token: tokenIn, balance: inputBalance - swapAmount }], target: account.underlying, slippage, }); if (repayAmount <= 0n || repayAmount > route.minAmount) { throw new Error("Repayment exceeds the route's minimum output"); } const calls: MultiCall[] = [ ...route.calls, facade.prepareChangeDebt(repayAmount, true), ]; ``` Preserve the returned sequence and its slippage and balance checks. `route.amount` is the quoted output; `route.minAmount` is the slippage-adjusted minimum. The example caps repayment at that minimum and must still satisfy debt, quota, and health checks. Build and preview the complete batch below. | Routing need | SDK method | | --- | --- | | Convert a single token's full balance | `findOneTokenPath` | | Convert selected balances while retaining explicit amounts | `findManyToOnePath` with `expectedBalances` and `leftoverBalances` | | Convert collateral and borrowed funds when opening | `findOpenStrategyPath` | | Convert assets to underlying for closing | `findBestClosePath`; use the [Close guide](https://docs.gearbox.finance/developers/close-leveraged-position) for the complete operation | For a **claim → convert** batch, quote with the balances expected after the claim, including any pre-existing input-token balance, and place the claim before `route.calls`. Do not reuse a quote made before settlement. A route only supplies the conversion leg; add the required claim, debt, quota, and withdrawal actions yourself. If no route is available, the batch is not ready to execute. ## Build the transaction ```typescript const tx = await chain.accounts.executeCaUpdate(account, calls); ``` Despite its name, `executeCaUpdate` only builds a transaction. It prepends required price updates and chooses the Credit Facade or applicable RWA factory as the transaction destination. It does not sign, send, or invent missing calls. Continue with `chainId`, `tx`, and `owner` at [Preview and check](https://docs.gearbox.finance/developers/build-preview-check#preview-and-check). Use that page's transaction payload instructions for signing and execution. ## Include a delayed claim For a fresh `claimable` entry from [Monitor settlement](https://docs.gearbox.finance/developers/delayed-withdrawals#monitor-settlement), the claim entry is: ```typescript const claimCall: MultiCall = { target: claimable.claimCall.to, callData: claimable.claimCall.callData, }; ``` Place this entry before the calls that use its proceeds, replacing the repayment example's funding step as appropriate. The claim does not execute the recorded intent. Add your chosen conversion, repayment, quota, or withdrawal calls so the complete batch passes the final health check. For expected-balance checks around a claim, use `chain.accounts.assembleClaimDelayedCalls(...)` with the lower-level withdrawal data; the raw entry above does not add those checks. ## Source - [Account transaction builder](https://github.com/Gearbox-protocol/sdk/blob/d9699ecce9e74d39651d9b3b455f93e9c67b3b85/src/onchain/accounts/CreditAccountsServiceV310.ts) - [Credit Facade call helpers](https://github.com/Gearbox-protocol/sdk/blob/d9699ecce9e74d39651d9b3b455f93e9c67b3b85/src/onchain/market/credit/CreditFacadeV310Contract.ts) - [Router path construction](https://github.com/Gearbox-protocol/sdk/blob/11ff4136681561df17e42f56015c636071f89957/src/onchain/router/RouterV310Contract.ts) - [Complete Credit Facade multicall interface](https://github.com/Gearbox-protocol/core-v3/blob/510fc6541c3767ce825929b4c311826fe81d6fa5/contracts/interfaces/ICreditFacadeV3Multicall.sol) - [Credit Facade argument validation](https://github.com/Gearbox-protocol/core-v3/blob/510fc6541c3767ce825929b4c311826fe81d6fa5/contracts/credit/CreditFacadeV3.sol) - [Balance delta structure and checks](https://github.com/Gearbox-protocol/core-v3/blob/510fc6541c3767ce825929b4c311826fe81d6fa5/contracts/libraries/BalancesLogic.sol) - [Price update structure](https://github.com/Gearbox-protocol/core-v3/blob/510fc6541c3767ce825929b4c311826fe81d6fa5/contracts/interfaces/base/IPriceFeedStore.sol) ## mF-ONE fork walkthrough Source: https://docs.gearbox.finance/developers/mfone-fork-walkthrough File: content/developers/mfone-fork-walkthrough.mdx Get test tokens, open an **mF-ONE leveraged position with 75,000 frxUSD at 4×**, monitor it, and exit instantly on the supplied Gearbox Mainnet fork. For a full exit through either route, see [Close](https://docs.gearbox.finance/developers/close-leveraged-position). For delayed redemption, see [Delayed operations](https://docs.gearbox.finance/developers/delayed-withdrawals). The steps below show the key calls. Use the [complete script](#complete-script) to run the flow, including approvals, preview checks, and transaction confirmation. It uses a fresh test wallet; fork resets erase its balances and transactions. ## 1. Connect Use Node.js 22.18 or later and install the dependencies: ```bash npm install @gearbox-protocol/sdk viem ``` Set the supplied RPC and opening parameters in the complete script: ```typescript const rpcUrl = "https://your-fork-rpc.example"; // Replace with the Gearbox fork RPC supplied to you const chainId = 1; const creditManager: Address = "0xBAdfE155662646A1A668c00276220B02FB7f1b23"; const depositAmount = "75000"; const leverage = 400n; const slippage = 5; const account = privateKeyToAccount(generatePrivateKey()); const owner = account.address; ``` `400n` means 4× leverage; `5` means 0.05% slippage. The script verifies the fork, loads its deployment configuration, and attaches `sdk` in `onchain` mode. All clients use the same fork execution. See [Connect SDK](https://docs.gearbox.finance/developers/sdk-setup) for the regular connection flow. ## 2. Get tokens Request test ETH and frxUSD from the fork's faucet: ```typescript const ethResponse = await fetch( `${baseUrl}/api/v1/forks/${fork.executionId}/eth-faucet?to=${owner}`, ); assert.ok(ethResponse.ok, `ETH faucet failed: ${ethResponse.status}`); const faucetResponse = await fetch( `${baseUrl}/api/v1/forks/${fork.executionId}/faucet?to=${owner}&midas=true`, ); assert.ok(faucetResponse.ok, `Token faucet failed: ${faucetResponse.status}`); ``` The script waits for the faucet transaction and checks the wallet's actual balances before opening. ## 3. Open Select mF-ONE from the SDK's strategy list and prepare the opening parameters: ```typescript const params: OpenStrategyParams = { collateral: [{ token: depositToken.address, balance: parseUnits(depositAmount, depositToken.decimals), }], leverage, slippage, quotaReserve: 100, // Optional: 1% extra quota }; ``` Then prepare the transaction: ```typescript let sim = await sdk.opportunities.prepare.openNewStrategy(strategy, params); if (!sim.ok) throw sim.error; ``` The complete script resolves the approval spender, approves exactly the 75,000 frxUSD deposit, then builds, previews, checks, and executes the opening. See [Open](https://docs.gearbox.finance/developers/open-leveraged-position) for strategy and parameter details, and [Build, preview, and check](https://docs.gearbox.finance/developers/build-preview-check) for transaction validation. ## 4. Monitor Read the wallet's leveraged positions and select the account just opened: ```typescript const positions = await sdk.positions.onchain.list({ wallet: owner, filter: { kind: "strategy" }, }); ``` Inspect its debt, collateral value, leverage, and health factor: ```typescript console.table({ creditAccount: position.creditAccount, debtFrxUSD: formatUnits(position.totalDebt.value, position.totalDebt.token.decimals), valueFrxUSD: formatUnits(position.totalValue.value, position.totalValue.token.decimals), leverage: position.leverage, healthFactor: position.healthFactor / 10_000, }); ``` The script refreshes SDK state after execution. See [Monitor](https://docs.gearbox.finance/developers/monitor-position) for collateral balances, prices, liquidation thresholds, quotas, and the HF formula. ## 5. Exit instantly Request a full withdrawal and choose the instant route: ```typescript const prepared = await sdk.opportunities.prepare.withdrawStrategy(position, { amount: MAX_UINT256, to: owner, slippage, }); if (!prepared.ok) throw prepared.error; ``` ```typescript const route = "instant"; const selected = prepared.data[route]; if (!selected) throw prepared.data.errors[route] ?? new Error("Route unavailable"); const exitSim = { ok: true as const, data: selected }; ``` The script builds, checks, and executes this route, then verifies zero debt, no collateral above SDK dust, and frxUSD returned to the wallet. The returned amount reflects fees, slippage, and interest. The Credit Account remains open after the economic exit. See [Manage → Withdraw](https://docs.gearbox.finance/developers/manage-position#withdraw). ## Complete script Copy this into `mfone.mts`, replace the `rpcUrl` placeholder, and run: ```bash node mfone.mts ```
Show complete runnable script ```typescript import assert from "node:assert/strict"; import { GearboxSDK, type OpenStrategyParams } from "@gearbox-protocol/sdk"; import { verifyTestnet } from "@gearbox-protocol/sdk/dev"; import { getNetworkType, MAX_UINT256 } from "@gearbox-protocol/sdk/onchain"; import { createPublicClient, createWalletClient, erc20Abi, formatUnits, http, parseUnits, type Address, type Hex, } from "viem"; import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; import { mainnet } from "viem/chains"; const baseUrl = "https://anvil.gearbox.foundation"; const rpcUrl = "https://your-fork-rpc.example"; // Replace with the Gearbox fork RPC supplied to you const chainId = 1; const creditManager: Address = "0xBAdfE155662646A1A668c00276220B02FB7f1b23"; const depositAmount = "75000"; const leverage = 400n; const slippage = 5; const account = privateKeyToAccount(generatePrivateKey()); const owner = account.address; console.log("Test wallet:", owner); const rpc = new URL(rpcUrl); assert.equal(rpc.origin, baseUrl, "Use the supplied Gearbox fork RPC"); const forkRef = rpc.pathname.match(/^\/rpc\/([^/]+)\/?$/)?.[1]; assert.ok(forkRef, "Expected a Gearbox /rpc/ URL"); const statusResponse = await fetch(`${baseUrl}/api/v1/forks/${forkRef}`); assert.ok(statusResponse.ok, `Fork status failed: ${statusResponse.status}`); const fork: { executionId: string; isActive: boolean; paused: boolean; addressProvider: Address; marketConfigurators: Address[]; } = await statusResponse.json(); assert.ok(fork.isActive && !fork.paused, "Fork is not active"); const forkRpcUrl = `${baseUrl}/rpc/${encodeURIComponent(fork.executionId)}`; const transport = http(forkRpcUrl, { timeout: 60_000 }); const publicClient = createPublicClient({ chain: mainnet, transport }); const wallet = createWalletClient({ account, chain: mainnet, transport }); assert.ok( await verifyTestnet(publicClient, { executionId: fork.executionId }), "RPC does not match the expected Gearbox fork", ); const network = getNetworkType(chainId); const sdk = new GearboxSDK({ mode: "onchain", networks: [network], maxStateAgeSeconds: Infinity, // Refresh explicitly after test transactions onchain: { chains: { [network]: { rpcURLs: [forkRpcUrl], timeout: 60_000 } } }, attach: { perChain: { [network]: { addressProvider: fork.addressProvider, marketConfigurators: fork.marketConfigurators, ignoreUpdateablePrices: true, } } }, }); await sdk.attach(); const chain = sdk.onchain.chain(chainId); const strategies = await sdk.opportunities.list({ kind: "strategy" }); assert.ok(strategies.meta.chains.some(entry => entry.chainId === chainId && entry.status === "success", ), "Strategy read failed"); const strategy = strategies.data.find(entry => entry.kind === "strategy" && entry.chainId === chainId && entry.creditManager.toLowerCase() === creditManager.toLowerCase(), ); assert.ok(strategy?.kind === "strategy", "mF-ONE strategy is not available"); const selectedStrategy = await sdk.opportunities.getStrategy({ chainId: strategy.chainId, creditManager: strategy.creditManager, }); const depositToken = selectedStrategy.data.allowedDepositTokens.find(token => token.address.toLowerCase() === "0xcacd6fd266af91b8aed52accc382b4e165586e29", ); assert.ok(depositToken, "frxUSD is not an allowed deposit token"); const params: OpenStrategyParams = { collateral: [{ token: depositToken.address, balance: parseUnits(depositAmount, depositToken.decimals), }], leverage, slippage, quotaReserve: 100, // Optional: 1% extra quota }; const amount = params.collateral[0].balance; assert.ok(amount > 0n); const ethResponse = await fetch( `${baseUrl}/api/v1/forks/${fork.executionId}/eth-faucet?to=${owner}`, ); assert.ok(ethResponse.ok, `ETH faucet failed: ${ethResponse.status}`); const faucetResponse = await fetch( `${baseUrl}/api/v1/forks/${fork.executionId}/faucet?to=${owner}&midas=true`, ); assert.ok(faucetResponse.ok, `Token faucet failed: ${faucetResponse.status}`); const faucetResult: { claimed: boolean; tx: Hex } = await faucetResponse.json(); if (faucetResult.claimed) { const faucetReceipt = await publicClient.waitForTransactionReceipt({ hash: faucetResult.tx, }); assert.equal(faucetReceipt.status, "success", "Faucet transaction reverted"); } const fundedBalance = await publicClient.readContract({ address: depositToken.address, abi: erc20Abi, functionName: "balanceOf", args: [owner], }); console.log("Wallet frxUSD:", formatUnits(fundedBalance, depositToken.decimals)); assert.ok(await publicClient.getBalance({ address: owner }) > 0n, "No test ETH received"); assert.ok(fundedBalance >= amount, "Faucet did not supply enough frxUSD"); let sim = await sdk.opportunities.prepare.openNewStrategy(strategy, params); if (!sim.ok) throw sim.error; const spender = await sdk.onchain .chain(strategy.chainId) .accounts.getApprovalAddress({ creditManager: strategy.creditManager, borrower: owner, }); const approvalHash = await wallet.writeContract({ address: depositToken.address, abi: erc20Abi, functionName: "approve", args: [spender, amount], }); const approvalReceipt = await publicClient.waitForTransactionReceipt({ hash: approvalHash }); assert.equal(approvalReceipt.status, "success", "Approval reverted"); const approvalBlock = await publicClient.getBlock({ blockNumber: approvalReceipt.blockNumber }); await chain.syncState({ blockNumber: approvalBlock.number, timestamp: approvalBlock.timestamp, ignoreUpdateablePrices: true, }); assert.ok(chain.currentBlock >= approvalReceipt.blockNumber, "SDK refresh failed"); sim = await sdk.opportunities.prepare.openNewStrategy(strategy, params); if (!sim.ok) throw sim.error; const targetToken = params.targetToken ?? selectedStrategy.data.targetCollateral.address; const openTx = await sdk.opportunities.execute.buildTx({ kind: "open", chainId: strategy.chainId, creditManager: strategy.creditManager, wallet: owner, collateral: params.collateral, ethAmount: 0n, targetToken, sim, }); const openPreview = await sdk.preview.previewOperation({ chainId: strategy.chainId, to: openTx.to, calldata: openTx.callData, value: BigInt(openTx.value), sender: owner, }); if (!openPreview.ok) throw openPreview.error; console.dir(openPreview.data, { depth: null }); const openIssues = await sdk.preview.checkOperation( { chainId: strategy.chainId, preview: openPreview.data, sender: owner }, { minHealthFactor: 10_500, minSafeHealthFactor: 10_500 }, // HF >= 1.05 ); if (openIssues.length) throw new Error(openIssues.map(issue => issue.message).join("\n")); const openRequest = { to: openTx.to, data: openTx.callData, value: BigInt(openTx.value) }; await publicClient.call({ ...openRequest, account: owner }); const openHash = await wallet.sendTransaction(openRequest); const openReceipt = await publicClient.waitForTransactionReceipt({ hash: openHash, confirmations: 2, }); assert.equal(openReceipt.status, "success", "Opening reverted"); console.log("Opened:", openHash); const openBlock = await publicClient.getBlock({ blockNumber: openReceipt.blockNumber }); await chain.syncState({ blockNumber: openBlock.number, timestamp: openBlock.timestamp, ignoreUpdateablePrices: true, }); assert.ok(chain.currentBlock >= openReceipt.blockNumber, "SDK refresh failed"); const positions = await sdk.positions.onchain.list({ wallet: owner, filter: { kind: "strategy" }, }); assert.ok(positions.meta.chains.some(entry => entry.chainId === strategy.chainId && entry.status === "success", ), "Position read failed"); const position = positions.data.find(entry => entry.kind === "strategy" && entry.creditManager.toLowerCase() === strategy.creditManager.toLowerCase(), ); assert.ok(position?.kind === "strategy", "Opened position not found"); assert.ok(!position.error, position.error); assert.ok(position.totalDebt.value > 0n, "No outstanding debt after opening"); console.table({ creditAccount: position.creditAccount, debtFrxUSD: formatUnits(position.totalDebt.value, position.totalDebt.token.decimals), valueFrxUSD: formatUnits(position.totalValue.value, position.totalValue.token.decimals), leverage: position.leverage, healthFactor: position.healthFactor / 10_000, }); console.log("Read metadata:", positions.meta.chains); console.dir(position.collaterals, { depth: null }); const suite = chain.marketRegister.findCreditManager(position.creditManager); const collateralIndex = 0; const token = position.collaterals[collateralIndex].collateral.token.address; const price = suite.market.priceOracle.mainPrice(token); // USD per token, 8 decimals const lt = suite.creditManager.liquidationThresholds.get(token); // Basis points console.log({ price, lt }); const prepared = await sdk.opportunities.prepare.withdrawStrategy(position, { amount: MAX_UINT256, to: owner, slippage, }); if (!prepared.ok) throw prepared.error; const route = "instant"; const selected = prepared.data[route]; if (!selected) throw prepared.data.errors[route] ?? new Error("Route unavailable"); const exitSim = { ok: true as const, data: selected }; const exitTx = await sdk.opportunities.execute.buildTx({ kind: "account", chainId: position.chainId, creditAccount: position.creditAccount, wallet: owner, sim: exitSim, }); const exitPreview = await sdk.preview.previewOperation({ chainId: position.chainId, to: exitTx.to, calldata: exitTx.callData, value: BigInt(exitTx.value), sender: owner, }); if (!exitPreview.ok) throw exitPreview.error; assert.equal(exitPreview.data.operation, "CloseCreditAccount"); console.dir(exitPreview.data, { depth: null }); const exitIssues = await sdk.preview.checkOperation( { chainId: position.chainId, preview: exitPreview.data, sender: owner }, { minHealthFactor: 10_500, minSafeHealthFactor: 10_500 }, ); if (exitIssues.length) throw new Error(exitIssues.map(issue => issue.message).join("\n")); const balanceBeforeExit = await publicClient.readContract({ address: depositToken.address, abi: erc20Abi, functionName: "balanceOf", args: [owner], }); const exitRequest = { to: exitTx.to, data: exitTx.callData, value: BigInt(exitTx.value) }; await publicClient.call({ ...exitRequest, account: owner }); const exitHash = await wallet.sendTransaction(exitRequest); const exitReceipt = await publicClient.waitForTransactionReceipt({ hash: exitHash }); assert.equal(exitReceipt.status, "success", "Instant exit reverted"); console.log("Exited:", exitHash); const exitBlock = await publicClient.getBlock({ blockNumber: exitReceipt.blockNumber }); await chain.syncState({ blockNumber: exitBlock.number, timestamp: exitBlock.timestamp, ignoreUpdateablePrices: true, }); assert.ok(chain.currentBlock >= exitReceipt.blockNumber, "SDK refresh failed"); const after = await sdk.positions.onchain.list({ wallet: owner, filter: { kind: "strategy" }, }); assert.ok(after.meta.chains.some(entry => entry.chainId === strategy.chainId && entry.status === "success", ), "Final position read failed"); const exited = after.data.find(entry => entry.kind === "strategy" && entry.creditAccount === position.creditAccount, ); assert.ok(exited?.kind === "strategy" && !exited.error, "Cannot verify the Credit Account"); assert.equal(exited.totalDebt.value, 0n, "Debt remains"); assert.ok(exited.collaterals.every(entry => entry.collateral.value === 0n), "Collateral above the SDK dust threshold remains"); const balanceAfterExit = await publicClient.readContract({ address: depositToken.address, abi: erc20Abi, functionName: "balanceOf", args: [owner], }); const received = balanceAfterExit - balanceBeforeExit; assert.ok(received > 0n, "No frxUSD returned"); console.log("Returned frxUSD:", formatUnits(received, depositToken.decimals)); console.log("PASS: opened, monitored, and exited through the instant route"); ```
Sources: [fork faucet](https://github.com/Gearbox-protocol/client-v3/blob/206dc48cb930919e3c8886fcdaad16837ef88611/src/core/dev-mode/faucet.ts), [SDK preparation](https://github.com/Gearbox-protocol/sdk/blob/93df7583a73ea533dacdc73aa2a9073460d97185/src/sdk/prepare/types.ts), [fork verification](https://github.com/Gearbox-protocol/sdk/blob/93df7583a73ea533dacdc73aa2a9073460d97185/src/dev/verifyTestnet.ts). ## Liquidations Source: https://docs.gearbox.finance/developers/liquidations File: content/developers/liquidations.mdx Liquidations repay debt from an unhealthy or expired Credit Account. This page explains when liquidation is possible and routes liquidators through the execution flow. ## When an account is liquidatable An account can be liquidated when: - its health factor is below `1.0`; or - its configured Credit Facade expiration has passed and the account still has debt. ### Full liquidation A full liquidation lets the liquidator buy the account's complete collateral portfolio at a discount. All debt is settled and the Credit Account closes. See [Full Liquidation](https://docs.gearbox.finance/developers/full-liquidation) for execution details. The standard entrypoints are permissionless while the Credit Facade is active. If it is paused, only an approved emergency liquidator can execute them. Loss-policy and asset-specific eligibility checks can also apply. If a full liquidation transfers pending redemption positions, continue with [Delayed Redemptions Liquidation](https://docs.gearbox.finance/developers/delayed-redemptions) for redeemer monitoring and claims. ## Recommended flow 1. **Discover accounts** that are unhealthy or expired. 2. **Inspect the exact outcome**, including the underlying amount to pay and the collateral to receive. 3. **Obtain the execution requirements**: the optional approval and unsigned liquidation transaction. 4. **Pass them to the operator's transaction pipeline** for simulation, signing, and submission. Continue with [Full Liquidation](https://docs.gearbox.finance/developers/full-liquidation). ## Full Liquidation Source: https://docs.gearbox.finance/developers/full-liquidation File: content/developers/full-liquidation.mdx A full liquidation is a purchase of a Credit Account's complete collateral portfolio at the liquidation discount. ```text required underlying = total collateral value × liquidation discount ``` The transaction sends that underlying from the liquidator to the Credit Account, transfers the account's enabled collateral balances to the liquidator, settles the debt, and closes the account. This guide covers the Gearbox-specific steps for one liquidation attempt: find candidates, inspect one candidate, and obtain the execution payload. Before continuing, [install and attach the Gearbox SDK](https://docs.gearbox.finance/developers/sdk-setup). The examples below use the chain instance returned by `connectedSdk.onchain.chain(chainId)`, named `sdk` here. The caller supplies these inputs: | Variable | Type | Meaning | |---|---|---| | `sdk` | `OnchainSDK` | Attached Gearbox SDK instance | | `liquidator` | `Address` | Address that will pay for the liquidation and receive its outputs | | `supportedMainCollateral` | `Address[]` | Main collateral assets used to shortlist accounts | | `supportedRepaymentTokens` | `Address[]` | Tokens the liquidator is willing to pay | ## 1. Find liquidatable accounts `getLiquidatableAccounts()` returns unhealthy accounts and expired accounts with debt. Each result includes its `creditAccount` address, so no separate address discovery is required. ```typescript import { isAddressEqual } from "viem"; const collateralCandidates = await sdk.liquidations.getLiquidatableAccounts({ assets: supportedMainCollateral, }); const candidates = collateralCandidates.filter(candidate => supportedRepaymentTokens.some(token => isAddressEqual(token, candidate.repaymentAmount.token), ), ); ``` `candidates` is a `LiquidatableAccount[]`. Each `candidate` contains: | Field | Type | Meaning | |---|---|---| | `creditAccount` | `Address` | Credit Account to inspect or liquidate | | `creditManager` | `Address` | Credit Manager in which the account is opened | | `network` | `NetworkType` | Network on which the account exists | | `asset` | `Address` | Main collateral asset used for discovery filtering | | `totalValue.token` | `Address` | Token in which the account value is expressed | | `totalValue.balance` | `bigint` | Estimated account value in that token's native decimals | | `totalValueUSD` | `bigint` | Estimated account value in USD with 8 decimals | | `repaymentAmount.token` | `Address` | Estimated payment token | | `repaymentAmount.balance` | `bigint` | Estimated payment amount in that token's native decimals | | `estimatedProfit.token` | `Address` | Token in which gross profit is estimated | | `estimatedProfit.balance` | `bigint` | Gross profit estimate before gas and funding costs | | `isDelayed` | `boolean` | Whether the account contains delayed-redemption collateral | | `paused` | `boolean` | Whether its Credit Facade is paused | `assets` matches only `candidate.asset`, the account's main collateral. Use `details.receivedAssets` to validate the complete collateral portfolio. Candidate amounts are discovery estimates; use `getLiquidationDetails()` for the exact selected liquidation path before execution. ## 2. Inspect one candidate Choose one `candidate` from the filtered `candidates` list. `creditAccount` is the address of that candidate's Credit Account, and `details` is its fresh liquidation preview for the supplied `liquidator`: ```typescript const candidate = candidates[0]; if (!candidate) throw new Error("No supported liquidation candidates"); const creditAccount = candidate.creditAccount; const details = await sdk.liquidations.getLiquidationDetails({ creditAccount, liquidator, }); if (details.paused) throw new Error("Credit Facade is paused"); if (details.isCreditAccountFrozen) throw new Error("Credit Account is frozen"); if (!details.isLiquidatorEligible) { throw new Error(`Liquidator is not eligible for ${details.kycProtocol}`); } if ( !supportedRepaymentTokens.some(token => isAddressEqual(token, details.repaymentAmount.token), ) ) { throw new Error("Unsupported payment token"); } ``` `buildLiquidationTx()` can be called without this step, but `details` is the pre-execution preview. Use it to verify the approval, exact payment, complete received-asset list, and eligibility before execution. `details` is a preview, not a transaction: | Field | Type | Meaning | |---|---|---| | `repaymentAmount.token` | `Address` | ERC-20 the liquidator pays | | `repaymentAmount.balance` | `bigint` | Exact payment amount in that token's native decimals | | `receivedAssets` | `ReceivedAsset[]` | Complete list of immediate and delayed outputs | | `receivedAssets[].isDelayed` | `boolean` | Whether this output settles after the liquidation transaction | | `receivedAssets[].token` | `Address` | ERC-20 the liquidator receives now or after settlement | | `receivedAssets[].amount` | `bigint` | Immediate amount, or exact/estimated delayed amount, in native decimals | | `receivedAssets[].redeemerAddress` | `Address \| undefined` | Redeemer assigned to the liquidator for a delayed output | | `receivedAssets[].claimableAt` | `bigint \| undefined` | Estimated settlement time; `undefined` means the output is immediate or claimable now | | `approve.token` | `Address` | ERC-20 that must be approved, when approval is required | | `approve.spender` | `Address` | Exact contract address that receives the allowance | | `approve.amount` | `bigint` | Required allowance with the SDK's execution buffer | | `estimatedProfit.token` | `Address` | Token in which gross profit is estimated | | `estimatedProfit.balance` | `bigint` | Gross profit estimate before gas and funding costs, in the token's native decimals | | `isLiquidatorEligible` | `boolean` | Whether this wallet may receive restricted assets | | `isCreditAccountFrozen` | `boolean` | Whether frozen collateral prevents liquidation | | `isDelayed` | `boolean` | Whether some proceeds settle after the liquidation transaction | The payment token is specific to the selected liquidation path. If `details.approve.token` is `DefaultRWAUnderlying`, the SDK builds the liquidation call but does not obtain that token for the liquidator. First [obtain the RWA underlying](https://docs.gearbox.finance/developers/obtain-rwa-underlying) by depositing its configured ERC-20 asset. Some dedicated RWA liquidation paths accept the configured ERC-20 asset and wrap it during execution. In that case, `details.approve.token` already reports that asset. Always use the token, spender, and amount returned in `details.approve` for the selected path. Use `receivedAssets` to confirm that the liquidator supports the complete outcome, rather than relying only on the main-asset discovery filter. When an item has `isDelayed: true`, `redeemerAddress` identifies the contract holding that redemption request. Executing the liquidation assigns the redeemer—and the future claim it represents—to the liquidator. See [Preview before liquidation](https://docs.gearbox.finance/developers/delayed-redemptions#preview-before-liquidation) for the delayed-output workflow. ## 3. Obtain the execution payload Build immediately before execution so that the SDK uses current prices and selects the correct liquidation contract. This call recomputes the liquidation data independently; it does not consume the `details` object: ```typescript const transaction = await sdk.liquidations.buildLiquidationTx({ creditAccount, liquidator, }); ``` When `details.approve` is present, approve its `token` for its `spender` and `amount`. Use `details.approve.spender` as the approval target. `transaction` contains the unsigned liquidation call. Pass the approval requirement and transaction to the operator's existing transaction pipeline, which handles allowance state, simulation, gas policy, signing, submission, and monitoring. ## Integration boundary This page provides Gearbox discovery, outcome inspection, approval requirements, and unsigned liquidation calldata. The operator's existing infrastructure owns execution and service operation. ## Sources - [Gearbox SDK](https://github.com/Gearbox-protocol/sdk) - [Standard liquidation construction](https://github.com/Gearbox-protocol/periphery-v3/blob/af447ac4619ad7943d5aa7d6914dbce34a7b243e/contracts/compressors/LiquidationCompressor.sol#L100-L180) - [Delayed-redemption liquidation construction](https://github.com/Gearbox-protocol/periphery-v3/blob/af447ac4619ad7943d5aa7d6914dbce34a7b243e/contracts/compressors/subcompressors/liquidation/SecuritizeLiquidationSubcompressor.sol) - [`CreditFacadeV3.liquidateCreditAccount`](https://github.com/Gearbox-protocol/core-v3/blob/510fc6541c3767ce825929b4c311826fe81d6fa5/contracts/credit/CreditFacadeV3.sol#L280-L370) ## Delayed Redemptions Liquidation Source: https://docs.gearbox.finance/developers/delayed-redemptions File: content/developers/delayed-redemptions.mdx A delayed redemption is collateral that has been submitted to an issuer but has not yet settled into the output token. Full liquidation can transfer this pending position to the liquidator together with the account's immediate assets. ## Redeemers during liquidation See [Redeemers and phantom tokens](https://docs.gearbox.finance/developers/delayed-withdrawals#claims-redeemers-and-phantom-tokens) for the redeemer's role and gateway ownership model. During liquidation, ownership of an unclaimed redeemer moves from the Credit Account to the liquidator. The liquidator therefore receives a future claim, not immediately spendable tokens. Once settlement arrives, the liquidator claims the output through the gateway. ## Preview before liquidation The `details` object returned by [`getLiquidationDetails()`](https://docs.gearbox.finance/developers/full-liquidation#2-inspect-one-candidate) contains every output expected from the liquidation. Select the delayed ones: ```typescript const delayedOutputs = details.receivedAssets.filter( asset => asset.isDelayed, ); ``` | Value | Type | Meaning | |---|---|---| | `details.receivedAssets` | `ReceivedAsset[]` | Complete list of immediate and delayed liquidation outputs | | `delayedOutputs` | `DelayedReceivedAsset[]` | Items from `receivedAssets` whose `isDelayed` field is `true` | | `delayedOutputs[].token` | `Address` | ERC-20 expected when the redemption settles | | `delayedOutputs[].amount` | `bigint` | Exact amount when claimable; estimate while pending | | `delayedOutputs[].redeemerAddress` | `Address \| undefined` | Redeemer currently owned by the Credit Account and assigned to the liquidator if execution succeeds | | `delayedOutputs[].claimableAt` | `bigint \| undefined` | Estimated Unix timestamp; `undefined` means claimable now | This preview answers what the liquidator is buying before execution. The redeemer address is informational at this stage: the SDK builds the correct liquidation transaction, including the ownership assignment. After execution, use the liquidator address to query the redeemers it now owns. ## List current withdrawals Using the [attached SDK instance](https://docs.gearbox.finance/developers/sdk-setup), query the delayed withdrawals currently owned by the liquidator after liquidation: Here, `sdk` is the chain instance returned by `connectedSdk.onchain.chain(chainId)` from the connected `GearboxSDK`. ```typescript const withdrawals = await sdk.liquidations.getLiquidatorWithdrawals({ liquidator, }); ``` | Value | Type | Meaning | |---|---|---| | `liquidator` | `Address` | Wallet that received the redeemers during liquidation | | `withdrawals` | `LiquidatorWithdrawal[]` | Current pending and claimable withdrawals owned by `liquidator` | | `withdrawals[].sourceToken` | `Address` | Asset submitted for redemption | | `withdrawals[].token` | `Address` | ERC-20 receivable from settlement | | `withdrawals[].amount` | `bigint` | Exact amount when claimable; estimate while pending | | `withdrawals[].claimableAt` | `bigint \| undefined` | Estimated Unix timestamp; `undefined` means claimable now | | `withdrawals[].redeemer` | `Address \| undefined` | Redeemer owned by the liquidator | The SDK queries every supported redemption gateway and returns its pending and claimable redeemers for the liquidator address. Redeemers do not need to be saved before executing the liquidation. Fully claimed withdrawals are not returned. ## Check status with the SDK Extract the redeemer addresses returned above and query their current status: ```typescript const compressor = sdk.withdrawalCompressor; if (!compressor) throw new Error("Delayed withdrawals are not supported"); const redeemers = withdrawals.flatMap(withdrawal => withdrawal.redeemer ? [withdrawal.redeemer] : [], ); const statuses = await compressor.getWithdrawalStatus(...redeemers); ``` | Variable | Type | Meaning | |---|---|---| | `compressor` | `IWithdrawalCompressorContract` | SDK reader for delayed-withdrawal state | | `redeemers` | `Address[]` | Redeemer addresses returned in `withdrawals` | | `statuses` | `WithdrawalStatus[]` | Status corresponding to each address in `redeemers` | `statuses[i]` describes `redeemers[i]`: | Status | Meaning | |---|---| | `NULL` | The address is not a supported redeemer | | `PENDING` | The issuer has not completed settlement | | `CLAIMABLE` | Output tokens are available at the redeemer | | `CLAIMED` | No pending or claimable output remains | `claimableAt` is only an estimate. Use the current status before claiming. ## Build claim calls The high-level method above is intended for monitoring. To obtain encoded claim calls, query the same data through the withdrawal compressor: ```typescript await compressor.loadWithdrawableAssets(); const withdrawalTokens = [ ...new Set( compressor .getWithdrawableAssets() .map(asset => asset.withdrawalPhantomToken), ), ]; const current = await compressor.getExternalAccountCurrentWithdrawals( liquidator, ...withdrawalTokens, ); const claimCalls = current.claimable.flatMap( withdrawal => withdrawal.claimCalls, ); ``` | Variable | Type | Meaning | |---|---|---| | `withdrawalTokens` | `Address[]` | Supported delayed-withdrawal configurations known to the SDK | | `current` | `CurrentWithdrawals` | Pending and claimable withdrawals returned by the compressor | | `current.pending` | `PendingWithdrawal[]` | Withdrawals that have not settled | | `current.claimable` | `ClaimableWithdrawal[]` | Settled withdrawals and their encoded claim calls | | `claimCalls` | `MultiCall[]` | Calls for all outputs currently available to claim | Each item in `claimCalls` contains the protocol gateway in `target` and the encoded method in `callData`. Pass those values to the operator's existing transaction pipeline. ## Protocol-specific redeemers ### Securitize Each redemption request creates a `SecuritizeRedeemer`. The redeemer sends its DS tokens to Securitize's redemption account and stores the starting NAV and timestamp. The resulting stablecoin is later delivered to the redeemer. The SDK reports: - `PENDING` while no stablecoin is available and `pendingDsTokenAmount` is non-zero; - `CLAIMABLE` as soon as the redeemer holds stablecoin; and - `CLAIMED` after the gateway has claimed the balance and cleared the pending amount. While pending, the displayed output is a NAV-based estimate. Once claimable, the output is the redeemer's actual stablecoin balance. Its generated claim call targets the `SecuritizeRedemptionGateway` and encodes `claim([redeemer])`; the gateway transfers the complete stablecoin balance to the liquidator. Securitize requires the new redeemer owner to be a registered wallet. Check `details.isLiquidatorEligible` before liquidation; the transfer reverts if the liquidator is not eligible. Source: [SecuritizeRedeemer.sol](https://github.com/Gearbox-protocol/integrations-v3/blob/midas-rwa/contracts/integrations/securitize/SecuritizeRedeemer.sol) and [SecuritizeRedemptionGateway.sol](https://github.com/Gearbox-protocol/integrations-v3/blob/midas-rwa/contracts/integrations/securitize/SecuritizeRedemptionGateway.sol). ### Midas Each redemption request creates a `MidasRedeemer`. It submits the mToken redemption to the Midas vault, stores the returned `requestId`, and records the start time. The requested quote token is later delivered to the redeemer. The SDK reports: - `PENDING` while the Midas request status is pending; - `CLAIMABLE` when the request is no longer pending and the redeemer holds quote tokens; and - `CLAIMED` when neither a pending estimate nor claimable quote-token balance remains. While pending, the displayed output is estimated from the current mToken rate and the request's quote-token rate. Once claimable, the output is the redeemer's exact quote-token balance. Its generated claim call targets the `MidasGateway` and encodes `withdrawFromRedeemer(redeemer, claimableAmount)`. Claims are per redeemer. In permissioned Midas mode, the liquidator must have the gateway's greenlisted role. Check `details.isLiquidatorEligible` before submitting the liquidation. Source: [MidasRedeemer.sol](https://github.com/Gearbox-protocol/integrations-v3/blob/midas-rwa/contracts/integrations/midas/MidasRedeemer.sol) and [MidasGateway.sol](https://github.com/Gearbox-protocol/integrations-v3/blob/midas-rwa/contracts/integrations/midas/MidasGateway.sol). ## Related pages - [Delayed operations for leveraged positions](https://docs.gearbox.finance/developers/delayed-withdrawals) - [SDK Setup](https://docs.gearbox.finance/developers/sdk-setup) - [Full Liquidation](https://docs.gearbox.finance/developers/full-liquidation) ## Pool Integration Source: https://docs.gearbox.finance/developers/pool-integration File: content/developers/pool-integration.mdx Use the Gearbox SDK to resolve a pool, build unsigned deposit and withdrawal transactions, and preview the token amounts. The same flow works for every pool underlying. Before continuing, [install and attach the Gearbox SDK](https://docs.gearbox.finance/developers/sdk-setup). The examples below use the chain instance returned by `connectedSdk.onchain.chain(chainId)`, named `sdk` here. The examples use these inputs: | Variable | Type | Meaning | |---|---|---| | `sdk` | `OnchainSDK` | Attached Gearbox SDK instance | | `poolAddress` | `Address` | Gearbox pool to integrate | | `lender` | `Address` | Wallet supplying the underlying and owning the pool shares | | `depositAmount` | `bigint` | Underlying amount to deposit, in native token units | | `sharesToRedeem` | `bigint` | Pool-share amount to redeem, in native token units | ## Resolve the pool Resolve the market once from the configured pool address: ```typescript import { RWA_UNDERLYING_DEFAULT } from "@gearbox-protocol/sdk"; const market = sdk.marketRegister.findByPool(poolAddress); const pool = market.pool.pool; const underlying = market.underlying; const underlyingMeta = sdk.tokensMeta.mustGet(underlying); const requiresRwaUnderlying = sdk.tokensMeta.isRWAUnderlying(underlyingMeta) && underlyingMeta.contractType === RWA_UNDERLYING_DEFAULT; if (pool.isPaused) throw new Error("Pool is paused"); ``` `underlying` is the ERC-20 supplied to and returned by this pool. `pool.address` is also the pool-share token address. > **If `requiresRwaUnderlying` is `true`:** the pool accepts > `DefaultRWAUnderlying`, not the ERC-20 asset wrapped by it. Follow > [Obtaining RWA Underlying](https://docs.gearbox.finance/developers/obtain-rwa-underlying) to obtain > the token, then return to the deposit flow below. ## Deposit This step assumes the lender already holds the exact `underlying` resolved above. ### Preview deposit ```typescript const expectedShares = await pool.contract.read.previewDeposit([ depositAmount, ]); ``` `expectedShares` is the expected pool-share output for `depositAmount`. ### Generate deposit transaction ```typescript const depositTransaction = pool.depositWithReferral( depositAmount, lender, 0n, ); ``` Approve `underlying` for `pool.address` with an allowance of at least `depositAmount`. `depositTransaction` is the unsigned deposit call. ## Check how much can be withdrawn Read the ERC-4626 limits through the SDK client: ```typescript const [withdrawableUnderlying, redeemableShares] = await Promise.all([ pool.contract.read.maxWithdraw([lender]), pool.contract.read.maxRedeem([lender]), ]); ``` `withdrawableUnderlying` is the current asset-denominated limit. `redeemableShares` is the current share-denominated limit. Both account for the lender's position, available pool liquidity, withdrawal fees, and pause state. ## Withdraw The SDK withdrawal builder redeems pool shares. ### Preview withdrawal ```typescript const expectedUnderlying = await pool.contract.read.previewRedeem([ sharesToRedeem, ]); ``` `expectedUnderlying` is the expected underlying output after the withdrawal fee. ### Generate withdrawal transaction ```typescript const withdrawalTransaction = pool.redeem( sharesToRedeem, lender, lender, ); ``` No pool-share approval is required when `lender` submits this transaction. If another address submits it, `lender` must approve that address to spend the shares. `withdrawalTransaction` is the unsigned redemption call. ## Pricing Use the ERC-4626 conversion methods for the current accounting rate: ```typescript const oneTokenUnit = 10n ** BigInt(pool.decimals); const [underlyingPerShare, sharesPerUnderlying] = await Promise.all([ pool.contract.read.convertToAssets([oneTokenUnit]), pool.contract.read.convertToShares([oneTokenUnit]), ]); ``` Conversions exclude operation-specific fees. Use `previewDeposit` and `previewRedeem` when preparing an actual transaction. ## Integration boundary This page provides Gearbox address resolution, current limits, previews, exact approval targets, and unsigned calldata. The lender's existing infrastructure owns allowance state, simulation, signing, submission, and monitoring. ## Sources - [Gearbox SDK pool transaction builders](https://github.com/Gearbox-protocol/sdk/blob/next/src/sdk/market/pool/PoolV310Contract.ts#L150-L181) - [Gearbox pool ERC-4626 implementation](https://github.com/Gearbox-protocol/core-v3/blob/next/contracts/pool/PoolV3.sol) ## Securitize Admin Source: https://docs.gearbox.finance/developers/securitize-admin File: content/developers/securitize-admin.mdx The Securitize Admin is the address configured as the owner of a [`SecuritizeRWAFactory`](https://github.com/Gearbox-protocol/periphery-v3/blob/2a63cf27b458c9c3b7824086da32f9dd6ee73613/contracts/rwa/SecuritizeRWAFactory.sol). It can freeze Credit Accounts managed by that `SecuritizeRWAFactory` and reassign investor control over them. Securitize determines when to use these tools. There is no separate freezer or Credit Account transfer role. The active `SecuritizeRWAFactory.owner()` has both authorities. ## Credit Account control model Each managed position links an investor, a `SecuritizeWallet`, and a Credit Account. See [Securitize DS Token Registration](https://docs.gearbox.finance/developers/securitize-ds-token-registration) for their ownership and control relationship and how both contract addresses are registered under the investor. Admin operations update state in the `SecuritizeRWAFactory`; they do not replace the `SecuritizeWallet` or change the Credit Account's onchain owner. ## Freeze behavior The admin can freeze or unfreeze: - one Credit Account; - all Credit Accounts assigned to an investor; or - an investor's Credit Accounts under one Credit Manager. While a Credit Account is frozen: - the `SecuritizeRWAFactory` rejects the investor's Credit Account operations; and - the configured RWA underlying rejects token movements to or from that Credit Account. With the current default and on-demand RWA underlying implementations, freezing also blocks liquidation of the Credit Account. Operators must account for this effect before freezing a Credit Account. Unfreezing restores these `SecuritizeRWAFactory` and RWA-underlying execution paths. Other protocol, market, token, or registry restrictions may still prevent an operation. ## Reassigning investor control The admin can reassign: - one Credit Account; - all Credit Accounts assigned to an investor; or - an investor's Credit Accounts under one Credit Manager. After reassignment, the previous investor can no longer execute Credit Account actions through the `SecuritizeRWAFactory`. The new investor becomes the authorized caller. The Credit Account's collateral, debt, `SecuritizeWallet` address, Credit Manager, and frozen status do not change. Before reassignment, the new investor address is expected to be recognized in all required Securitize registries under the same identity as the previous investor. The `SecuritizeRWAFactory` does not verify this condition. It only rejects the zero address; passing the currently assigned investor makes no change. ## Function reference All functions below can only be called by the active `SecuritizeRWAFactory.owner()`. | Function | Scope | Effect | |---|---|---| | `setCreditAccountFrozenStatus(creditAccount, frozen)` | One known Credit Account | Sets its frozen status. | | `setAllCreditAccountsFrozenStatus(investor, frozen)` | All Credit Accounts assigned to an investor | Sets the same frozen status on each Credit Account. | | `setAllCreditAccountsFrozenStatus(creditManager, investor, frozen)` | The investor's Credit Accounts under one Credit Manager | Sets the same frozen status on matching Credit Accounts. | | `transferCreditAccount(creditAccount, newInvestor)` | One known Credit Account | Reassigns investor control to `newInvestor`. | | `transferAllCreditAccounts(investor, newInvestor)` | All Credit Accounts assigned to an investor | Reassigns all of them to `newInvestor`. | | `transferAllCreditAccounts(creditManager, investor, newInvestor)` | The investor's Credit Accounts under one Credit Manager | Reassigns matching Credit Accounts to `newInvestor`. | Bulk functions iterate over the investor's recorded Credit Accounts in one transaction. Operators should simulate bulk calls with the intended Credit Account set before submitting them. Successful changes emit `SetCreditAccountFrozenStatus` for each changed freeze state or `TransferCreditAccount` for each reassigned Credit Account. Calling a freeze function with the current status, or transferring to the currently assigned investor, makes no state change and emits no event. ## Securitize Admin address The `SecuritizeRWAFactory` constructor sets the supplied `securitizeAdmin` address as its initial owner. The current authority can be read from `owner()`. `SecuritizeRWAFactory` ownership can be moved to another Securitize address using the inherited two-step ownership-transfer process: the current owner proposes the new owner, and the new address accepts the role. ## Read methods Operators can inspect the current state before building an admin transaction: | Function | Returns | |---|---| | `isCreditAccount(creditAccount)` | Whether the Credit Account is managed by this `SecuritizeRWAFactory`. | | `isFrozen(creditAccount)` | Whether a known Credit Account is frozen. | | `getInvestor(creditAccount)` | The investor currently authorized to control a known Credit Account. | | `getCreditAccounts(investor)` | All Credit Accounts currently assigned to an investor. | | `getWallet(creditAccount)` | The `SecuritizeWallet` that owns a known Credit Account. | ## Sources - [`SecuritizeRWAFactory.sol`](https://github.com/Gearbox-protocol/periphery-v3/blob/2a63cf27b458c9c3b7824086da32f9dd6ee73613/contracts/rwa/SecuritizeRWAFactory.sol) - [`SecuritizeWallet.sol`](https://github.com/Gearbox-protocol/periphery-v3/blob/2a63cf27b458c9c3b7824086da32f9dd6ee73613/contracts/rwa/SecuritizeWallet.sol) - [`IRWAFactory.sol`](https://github.com/Gearbox-protocol/periphery-v3/blob/2a63cf27b458c9c3b7824086da32f9dd6ee73613/contracts/interfaces/base/IRWAFactory.sol) - [Default RWA Underlying](https://docs.gearbox.finance/developers/rwa-underlying) ## Default RWA Underlying Source: https://docs.gearbox.finance/developers/rwa-underlying File: content/developers/rwa-underlying.mdx [`DefaultRWAUnderlying`](https://github.com/Gearbox-protocol/periphery-v3/blob/main/contracts/rwa/DefaultRWAUnderlying.sol) is a 1:1 ERC-4626 wrapper used as the underlying token of a Gearbox RWA pool. It connects the pool to borrower-level compliance controls without applying those controls to ordinary liquidity providers. ## Purpose RWA markets may need to freeze a borrower's Credit Account while preserving normal pool operations for LPs. `DefaultRWAUnderlying` provides the token-level enforcement point for that boundary. The wrapper exists primarily to block token movements involving a frozen Credit Account, including movements used during liquidation. Other operations on a frozen Credit Account are blocked by the configured RWA factory. It does not represent the borrower's RWA collateral. LPs interact with the wrapper's configured ERC-20 asset, `DefaultRWAUnderlying`, and Gearbox pool shares. ## ERC-4626 behavior The wrapper uses the standard ERC-4626 interface: - `deposit` and `mint` wrap the configured ERC-20 asset; - `withdraw` and `redeem` return that asset; and - conversions between the asset and wrapper shares are fixed at 1:1. ```solidity uint256 wrapperShares = rwaUnderlying.previewDeposit(assetAmount); uint256 assetOut = rwaUnderlying.previewRedeem(wrapperShares); ``` The Gearbox pool has a separate exchange rate between `DefaultRWAUnderlying` and pool shares. See [Obtaining RWA Underlying](https://docs.gearbox.finance/developers/obtain-rwa-underlying) to mint or redeem the wrapper token, then use the standard [Pool Integration](https://docs.gearbox.finance/developers/pool-integration) flow. ## Freeze scope Before a wrapper-token transfer, `DefaultRWAUnderlying` checks both the sender and recipient against its configured RWA factory. The transfer reverts only if an address is both: 1. a Credit Account registered by that factory; and 2. marked as frozen by the factory. This check is applied to the transfer's `from` and `to` addresses. See [`_beforeTokenTransfer` and `_revertIfFrozenCreditAccount`](https://github.com/Gearbox-protocol/periphery-v3/blob/2a63cf27b458c9c3b7824086da32f9dd6ee73613/contracts/rwa/DefaultRWAUnderlying.sol#L62-L70) in the implementation. ## Freeze authority and storage `DefaultRWAUnderlying` does not define a freezer role and does not store frozen addresses. It stores only an immutable reference to its configured RWA factory. In the Securitize implementation, [`SecuritizeRWAFactory`](https://github.com/Gearbox-protocol/periphery-v3/blob/main/contracts/rwa/SecuritizeRWAFactory.sol) inherits `Ownable2Step`. Its constructor receives a `securitizeAdmin` address and sets that address as the initial factory owner. The active factory owner is the only address authorized to call: - `setCreditAccountFrozenStatus` for one Credit Account; - `setAllCreditAccountsFrozenStatus(investor, frozen)` for all accounts belonging to an investor; or - `setAllCreditAccountsFrozenStatus(creditManager, investor, frozen)` for an investor's accounts in one Credit Manager. Ownership can subsequently be transferred through the factory's two-step ownership process. There is no separately assigned freezer role. The state is stored in the factory's Credit Account mapping: ```solidity mapping(address creditAccount => CreditAccountInfo) internal _creditAccountInfo; struct CreditAccountInfo { address wallet; address investor; bool frozen; } ``` The relevant storage and authority boundary is: | Item | Contract | Location | |---|---|---| | Active freeze authority | `SecuritizeRWAFactory` | inherited `owner()` state | | Frozen status | `SecuritizeRWAFactory` | `_creditAccountInfo[creditAccount].frozen` | | Factory used for checks | `DefaultRWAUnderlying` | immutable `_FACTORY` reference | When wrapper tokens move, `DefaultRWAUnderlying` calls `isCreditAccount(account)` and `isFrozen(account)` on that factory. It does not copy the frozen status into its own storage. ## LPs do not require KYC An ordinary LP address and the Gearbox pool are not registered borrower Credit Accounts. Consequently, the additional logic in `DefaultRWAUnderlying`: - does not create an LP allowlist; - does not require LP identity registration or KYC; and - does not provide a mechanism for marking an arbitrary LP address as frozen. LPs use the standard ERC-4626 deposit and redemption methods. Borrower compliance is handled separately at the Credit Account level. This boundary applies to the additional freeze logic in `DefaultRWAUnderlying`. It does not remove controls or risks that exist outside the wrapper, such as issuer-level controls in the configured ERC-20 asset, a paused Gearbox pool, or insufficient pool liquidity for an immediate withdrawal. ## Contract relationships An integration can verify the wrapper and pool relationship onchain: ```solidity require(rwaUnderlying.asset() == expectedAssetAddress, "Unexpected wrapper asset"); require(rwaUnderlying.getFactory() == rwaFactoryAddress, "Unexpected RWA factory"); require(pool.asset() == address(rwaUnderlying), "Unexpected pool underlying"); ``` The factory controls borrower Credit Account registration and frozen status. The wrapper only reads that state when enforcing transfers; it does not maintain a separate freeze list. ## See also - [Obtaining RWA Underlying](https://docs.gearbox.finance/developers/obtain-rwa-underlying) - [Pool Integration](https://docs.gearbox.finance/developers/pool-integration) - [`DefaultRWAUnderlying.sol`](https://github.com/Gearbox-protocol/periphery-v3/blob/main/contracts/rwa/DefaultRWAUnderlying.sol) - [`IRWAUnderlying.sol`](https://github.com/Gearbox-protocol/periphery-v3/blob/main/contracts/interfaces/base/IRWAUnderlying.sol) - [`IRWAFactory.sol`](https://github.com/Gearbox-protocol/periphery-v3/blob/main/contracts/interfaces/base/IRWAFactory.sol) ## Securitize DS Token Registration Source: https://docs.gearbox.finance/developers/securitize-ds-token-registration File: content/developers/securitize-ds-token-registration.mdx The [`SecuritizeRWAFactory`](https://github.com/Gearbox-protocol/periphery-v3/blob/2a63cf27b458c9c3b7824086da32f9dd6ee73613/contracts/rwa/SecuritizeRWAFactory.sol) is the authorization registry for Securitize-enabled Credit Accounts. It records who may operate each Credit Account and the [`SecuritizeWallet`](https://github.com/Gearbox-protocol/periphery-v3/blob/2a63cf27b458c9c3b7824086da32f9dd6ee73613/contracts/rwa/SecuritizeWallet.sol) through which calls are executed. The integration uses three different addresses for one investor position: | Address | What it is | |---|---| | Investor | The external address recognized by Securitize. It signs registration authorizations and submits actions to the `SecuritizeRWAFactory`. | | `SecuritizeWallet` | A contract deployed for one position. Gearbox records it as the Credit Account's owner, or borrower. | | [`CreditAccount`](https://github.com/Gearbox-protocol/core-v3/blob/510fc6541c3767ce825929b4c311826fe81d6fa5/contracts/credit/CreditAccountV3.sol) | A separate Gearbox contract that holds the position's collateral and debt. | ## SecuritizeRWAFactory — authorization registry For each Credit Account, the `SecuritizeRWAFactory` records its `SecuritizeWallet`, authorized investor, and frozen status. Before forwarding a multicall, it checks that the caller is that investor and the Credit Account is not frozen. This is operational authorization, not Gearbox ownership. The Credit Manager records the `SecuritizeWallet` as the Credit Account's borrower. Freezing Credit Accounts and reassigning investor control are covered separately in [Securitize Admin](https://docs.gearbox.finance/developers/securitize-admin). ### When DS token eligibility is checked DS token eligibility is checked when the contracts are registered for a specific DS token. The [`SecuritizeDegenNFT`](https://github.com/Gearbox-protocol/periphery-v3/blob/2a63cf27b458c9c3b7824086da32f9dd6ee73613/contracts/rwa/SecuritizeDegenNFT.sol) first checks through that token's [`VaultRegistrar`](https://github.com/Gearbox-protocol/periphery-v3/blob/2a63cf27b458c9c3b7824086da32f9dd6ee73613/contracts/interfaces/external/securitize/IVaultRegistrar.sol) that the investor is registered. Because the `SecuritizeDegenNFT` has the registrar's operator role, it can then register the `CreditAccount` and `SecuritizeWallet` contract addresses as vaults belonging to that investor. ## Changes to investor eligibility Gearbox does not automatically remove DS token registrations, freeze `CreditAccount` contracts, or reassign them when an investor's Securitize eligibility changes. The `SecuritizeRWAFactory` continues to recognize the recorded investor until a Securitize operator freezes or reassigns the `CreditAccount`. The DS token continues to apply its current registry rules to transfers. ## Sources - [`SecuritizeRWAFactory.sol`](https://github.com/Gearbox-protocol/periphery-v3/blob/2a63cf27b458c9c3b7824086da32f9dd6ee73613/contracts/rwa/SecuritizeRWAFactory.sol) - [`SecuritizeDegenNFT.sol`](https://github.com/Gearbox-protocol/periphery-v3/blob/2a63cf27b458c9c3b7824086da32f9dd6ee73613/contracts/rwa/SecuritizeDegenNFT.sol) - [`SecuritizeWallet.sol`](https://github.com/Gearbox-protocol/periphery-v3/blob/2a63cf27b458c9c3b7824086da32f9dd6ee73613/contracts/rwa/SecuritizeWallet.sol) - [`IVaultRegistrar.sol`](https://github.com/Gearbox-protocol/periphery-v3/blob/2a63cf27b458c9c3b7824086da32f9dd6ee73613/contracts/interfaces/external/securitize/IVaultRegistrar.sol) ## Obtaining RWA Underlying Source: https://docs.gearbox.finance/developers/obtain-rwa-underlying File: content/developers/obtain-rwa-underlying.mdx Some Gearbox RWA pools use [`DefaultRWAUnderlying`](https://docs.gearbox.finance/developers/rwa-underlying) as their underlying. Obtain it by depositing the wrapper's configured ERC-20 asset. This does not require KYC or an allowlist step. After obtaining the token, use the standard [Pool Integration](https://docs.gearbox.finance/developers/pool-integration) flow without changing the pool logic. Before continuing, [install and attach the Gearbox SDK](https://docs.gearbox.finance/developers/sdk-setup). The examples below use the chain instance returned by `connectedSdk.onchain.chain(chainId)`, named `sdk` here. The examples use these inputs: | Variable | Type | Meaning | |---|---|---| | `sdk` | `OnchainSDK` | Attached Gearbox SDK instance | | `poolAddress` | `Address` | RWA pool whose underlying must be obtained | | `lender` | `Address` | Wallet supplying the configured asset and receiving the RWA underlying | | `assetAmount` | `bigint` | ERC-20 asset amount to deposit, in native token units | | `rwaUnderlyingAmount` | `bigint` | RWA underlying amount to redeem, in native token units | ## Resolve the wrapper Resolve the RWA underlying and its ERC-20 asset from the pool: ```typescript import { BaseContract, RWA_UNDERLYING_DEFAULT, } from "@gearbox-protocol/sdk"; import { iRWAUnderlyingAbi } from "@gearbox-protocol/sdk/abi/rwa/iRWAUnderlying"; const market = sdk.marketRegister.findByPool(poolAddress); const meta = sdk.tokensMeta.mustGet(market.underlying); if ( !sdk.tokensMeta.isRWAUnderlying(meta) || meta.contractType !== RWA_UNDERLYING_DEFAULT ) { throw new Error("Pool does not use DefaultRWAUnderlying"); } const underlyingAsset = meta.asset; const rwaUnderlying = new BaseContract(sdk, { addr: market.underlying, abi: iRWAUnderlyingAbi, name: "DefaultRWAUnderlying", }); ``` `underlyingAsset` is the token supplied to and returned by the wrapper. `rwaUnderlying.address` is the token used by the Gearbox pool. ## Obtain RWA underlying ### Preview deposit ```typescript const expectedRwaUnderlying = await rwaUnderlying.contract.read.previewDeposit([assetAmount]); ``` The wrapper converts its configured asset 1:1, but use the preview rather than hardcoding that result. ### Generate deposit transaction ```typescript const depositTransaction = rwaUnderlying.createRawTx({ functionName: "deposit", args: [assetAmount, lender], }); ``` Approve `underlyingAsset` for `rwaUnderlying.address` with an allowance of at least `assetAmount`. `depositTransaction` is the unsigned wrapper deposit call. After execution, approve the received RWA underlying to the Gearbox pool and continue with [Pool Integration](https://docs.gearbox.finance/developers/pool-integration#deposit). ## Check how much can be redeemed ```typescript const [withdrawableAsset, redeemableRwaUnderlying] = await Promise.all([ rwaUnderlying.contract.read.maxWithdraw([lender]), rwaUnderlying.contract.read.maxRedeem([lender]), ]); ``` `withdrawableAsset` is the asset-denominated limit. `redeemableRwaUnderlying` is the share-denominated limit. ## Redeem to the underlying asset ### Preview redemption ```typescript const expectedAsset = await rwaUnderlying.contract.read.previewRedeem([ rwaUnderlyingAmount, ]); ``` ### Generate redemption transaction ```typescript const redeemTransaction = rwaUnderlying.createRawTx({ functionName: "redeem", args: [rwaUnderlyingAmount, lender, lender], }); ``` No approval is required when `lender` submits the redemption. If another address submits it, `lender` must approve that address to spend the RWA underlying. `redeemTransaction` is the unsigned wrapper redemption call. ## Pricing ```typescript const [rwaUnderlyingOut, assetOut] = await Promise.all([ rwaUnderlying.contract.read.convertToShares([assetAmount]), rwaUnderlying.contract.read.convertToAssets([rwaUnderlyingAmount]), ]); ``` `DefaultRWAUnderlying` currently defines a 1:1 conversion in both directions. Use `previewDeposit` and `previewRedeem` when preparing an actual transaction. ## Integration boundary This page provides Gearbox address resolution, limits, previews, approval targets, and unsigned calldata. The lender's existing infrastructure owns allowance state, simulation, signing, submission, and monitoring. For why this token exists, how freeze authority works, and why it does not add direct freeze risk to LP wallets, see [Default RWA Underlying](https://docs.gearbox.finance/developers/rwa-underlying). ## Sources - [`DefaultRWAUnderlying`](https://github.com/Gearbox-protocol/periphery-v3/blob/main/contracts/rwa/DefaultRWAUnderlying.sol) - [Gearbox SDK RWA underlying ABI](https://github.com/Gearbox-protocol/sdk/blob/next/src/abi/rwa/iRWAUnderlying.ts) ## Deployment Addresses Source: https://docs.gearbox.finance/developers/deployments File: content/developers/deployments.mdx Gearbox v3.1 contracts are deployed through a [deterministic deployer](https://ethglobal.com/showcase/deterministic-deployer-p3eyi), so every system contract has the same address on all supported chains. This page is the canonical address list for the protocol. ## 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. *** ## System Contracts | Contract | Address | | ------------------------ | -------------------------------------------- | | Address Provider | `0xF7f0a609BfAb9a0A98786951ef10e5FE26cC1E38` | | Bytecode Repository | `0x1cE2B1BE96a082b1b1539F80d5D8f82Ec06a0f9A` | | Cross-Chain Governance | `0xcCCCCcCc42B7DA9fdEc1761698Fb55fdD41CDF55` | | Instance Manager | `0x77777777144339Bdc3aCceE992D8d4D31734CB2e` | | Instance Manager Proxy | `0xBcD875f0D62B9AA22481c81975F9AE1753Fc559A` | | Bot List | `0x0Bc03983Da93021a374C964A22b73865220Ce962` | | Price Feed Store | `0x74A868AC479EE145029bB80827BB77F7B7c441cB` | | GEAR Staking | `0x2fcbD02d5B1D52FC78d4c02890D7f4f47a459c33` | *** ## Factories Used by market configurators to deploy and upgrade market components. | Contract | Address | | --------------------------- | -------------------------------------------- | | Market Configurator Factory | `0x7D60CfaF7c2cec210638A5e46E4000894830C034` | | Pool Factory | `0x2238eDf33a72860cDbaec5F83ec246Df9e85c8E2` | | Credit Factory | `0x81Cda0aB38d8Bd0732123Eb0e36C0C566d35DADD` | | Price Oracle Factory | `0xF7533CDCE5A2F7BF78B6fbf4B05f04F45D10140B` | | Interest Rate Model Factory | `0xA7dE2e941c8818E51D1Fd84111d8F71dcafa6C3B` | | Rate Keeper Factory | `0xBEde127c14407B9c345F5D7fAE5782ab8eAa33f3` | | Loss Policy Factory | `0x0E535b7D073a93646512cEa18fa7e650CC2b17C4` | *** ## Periphery Contracts Read-only compressors and the router, registered in the AddressProvider under `GLOBAL::*` keys. | Contract | Address | | ----------------------- | -------------------------------------------- | | Market Compressor | `0x70F1753a765C4df582FFA3B8d96AB492714E8992` | | Account Compressor | `0x4115708Fc8fe6bB392De2e0C21c2C81dA2222394` | | Credit Suite Compressor | `0x93Cba8445b13a05287bFf90D882cbcB514D617b7` | | Price Feeds Compressor | `0x847a05C22c7508C674342A95356Adf9b3a0e0D57` | | Gauge Compressor | `0x12c8faEdD62cF0C5d4D742E57B98737a9a3F5E0f` | | Periphery Compressor | `0xa7ED6dB5761613CaE7CaCfAAE9Dca07a77809F9d` | | Rewards Compressor | `0x19Ca61E672d1c6105f609418bfDC784F92F4Ecf0` | | Token Compressor | `0xAe3Dd11e5a7f99eD4cba2768D4095a55fbF7841B` | | Router | `0x00aDE38841AB8c6e236E232041e43B41d74B8B45` | *** ## Activated Chains Chains activated through cross-chain governance, with the per-chain treasury, wrapped native token, and GEAR token addresses. This table is generated from the `InstanceManager.activate` calls executed by the Cross-Chain Governance multisig on Ethereum (`npm run generate:addresses`). | Chain | Chain ID | Treasury | WETH | GEAR | | ----- | -------- | -------- | ---- | ---- | | Ethereum | 1 | `0x3e965117a51186e41c2bb58b729a1e518a715e5f` | `0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2` | `0xba3335588d9403515223f109edc4eb7269a9ab5d` | | Optimism | 10 | `0x1acc5bc353f23b901801f3ba48e1e51a14263808` | `0x4200000000000000000000000000000000000006` | `0x39e6c2e1757ae4354087266e2c3ea9ac4257c1eb` | | BNB Chain | 56 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c` | not deployed | | Unichain | 130 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x4200000000000000000000000000000000000006` | not deployed | | Polygon | 137 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270` | not deployed | | Monad | 143 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x3bd359c1119da7da1d913d1c4d2b7c461115433a` | not deployed | | Sonic | 146 | `0x74028cf1cba6a4513c9a27137e7d0f3847833795` | `0x039e2fb66102314ce7b64ce5ce3e5183bc94ad38` | `0x0fdbce271bea0d9819034cd09021e0bbe94be3fd` | | X Layer | 196 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0xe538905cf8410324e03a5a23c1c177a474d59b2b` | not deployed | | B2 Network | 223 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x4200000000000000000000000000000000000006` | not deployed | | Fraxtal | 252 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0xfc00000000000000000000000000000000000002` | not deployed | | World Chain | 480 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x4200000000000000000000000000000000000006` | not deployed | | Chain 777 | 777 | `0x96992b7e28147767701d4408fc45eaba86c30f15` | `0x76818770d192a506f90e79d5cb844e708be0d7a0` | not deployed | | HyperEVM | 999 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x5555555555555555555555555555555555555555` | not deployed | | Polygon zkEVM | 1101 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x4f9a0e7fd2bf6067db6994cf12e4495df938e6e9` | not deployed | | Lisk | 1135 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x4200000000000000000000000000000000000006` | not deployed | | Soneium | 1868 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x4200000000000000000000000000000000000006` | not deployed | | Swellchain | 1923 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x4200000000000000000000000000000000000006` | not deployed | | Morph | 2818 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x5300000000000000000000000000000000000011` | not deployed | | Botanix | 3637 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x0d2437f93fed6ea64ef01ccde385fb1263910c56` | not deployed | | MegaETH | 4326 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x4200000000000000000000000000000000000006` | not deployed | | Beam | 4337 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0xd51bfa777609213a653a2cd067c9a0132a2d316a` | not deployed | | Mantle | 5000 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x78c1b0c915c4faa5fffa6cabf0219da63d7f4cb8` | not deployed | | Somnia | 5031 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x046ede9564a72571df6f5e44d0405360c0f4dcab` | not deployed | | Superseed | 5330 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x4200000000000000000000000000000000000006` | not deployed | | Chain 5920 | 5920 | `0x18b1778f45944d1ce779a5bf2a386215d8f04d5f` | `0x32e10f12e5de1f8f591c83bbcb920e39a8f172f4` | not deployed | | MegaETH Testnet | 6342 | `0x18b1778f45944d1ce779a5bf2a386215d8f04d5f` | `0x776401b9bc8aae31a685731b7147d4445fd9fb19` | not deployed | | Nibiru | 6900 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x0cacf669f8446beca826913a3c6b96acd4b02a97` | not deployed | | Kaia | 8217 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x19aac5f612f524b754ca7e7c41cbfa2e981a4432` | not deployed | | Base | 8453 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x4200000000000000000000000000000000000006` | not deployed | | Plasma | 9745 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x6100e367285b01f48d07953803a2d8dca5d19873` | not deployed | | Monad Testnet | 10143 | `0x18b1778f45944d1ce779a5bf2a386215d8f04d5f` | `0x760afe86e5de5fa0ee542fc7b7b713e1c5425701` | not deployed | | Mode | 34443 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x4200000000000000000000000000000000000006` | not deployed | | Arbitrum | 42161 | `0x2c31effe426765e68a43163a96dd13df70b53c14` | `0x82af49447d8a07e3bd95bd0d56f35241523fbab1` | `0x2f26337576127efabeec1f62be79db1bca9148a4` | | Celo | 42220 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x471ece3750da237f93b8e339c536989b8978a438` | not deployed | | Etherlink | 42793 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0xc9b53ab2679f573e480d01e0f49e2b5cfb7a3eab` | not deployed | | Hemi | 43111 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x4200000000000000000000000000000000000006` | not deployed | | Avalanche | 43114 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7` | not deployed | | Sophon | 50104 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x2b1a859de6a55c553520d7780bc5805712b128f9` | not deployed | | Ink | 57073 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x4200000000000000000000000000000000000006` | not deployed | | Linea | 59144 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f` | not deployed | | BOB | 60808 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x4200000000000000000000000000000000000006` | not deployed | | Berachain | 80094 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0x6969696969696969696969696969696969696969` | not deployed | | Plume | 98866 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0xea237441c92cae6fc17caaf9a7acb3f953be4bd1` | not deployed | | Taiko | 167000 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0xa51894664a773981c6c112c43ce576f315d5b1b6` | not deployed | | Bitlayer | 200901 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0xff204e2681a6fa0e2c3fade68a1b28fb90e4fc5f` | not deployed | | Katana | 747474 | `0xef78f5ffd8c6c5aa45bcab7f4ba638b0a4fbc7a1` | `0xee7d8bcfb72bc1880d0cf19822eb0a2e6577ab62` | not deployed | | Chain 5042002 | 5042002 | `0x6763fe48cc800f24c128ce651257c9f991081d1a` | `0x3600000000000000000000000000000000000000` | not deployed | | RISE Testnet | 11155931 | `0x18b1778f45944d1ce779a5bf2a386215d8f04d5f` | `0x4200000000000000000000000000000000000006` | not deployed | *** ## 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 Market Compressor 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/security File: content/developers/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/glossary File: content/developers/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. |