Let Your Users Borrow USDC Against Their Crypto Assets With Borrow Kit

Summary
Borrow Kit helps you offer crypto-backed USDC borrowing directly within your product, so users can borrow against their assets without leaving your platform. You can add this experience without building and maintaining the underlying lending integration yourself, and without writing any smart contract code.
Part of the App Kits suite, Borrow Kit is a TypeScript SDK that enables developers to let users borrow USDC from onchain lending markets on Arc using supported crypto assets as collateral. At launch, Borrow Kit supports Circle Wrapped Bitcoin (cirBTC) as collateral in Morpho markets, with more assets and lending protocols designed to follow. The USDC users borrow comes from third-party lenders supplying those markets, not from Circle.
This post covers the whole loan flow, end to end:
- What it takes to build crypto-backed USDC borrowing yourself
- The developer work Borrow Kit handles
- The six steps of a loan, from choosing a market to closing the position
- How Borrow Kit sizes collateral based on the amount a user wants to borrow
- How one user-facing transaction bundles the operations required to open a loan
- How health factors, risk bands, and liquidation work
- What Arc removes from the developer and user experience
What it takes to build crypto-backed USDC borrowing yourself
Adding borrowing to your app involves more than building the interface. Without Borrow Kit, you need to solve six categories of developer work.
Protocol integration
You need to select a lending protocol and market, integrate with its contracts, and maintain that integration as interfaces and market parameters evolve.
Chain and gas experience
You need to choose a network and make sure users can pay transaction fees. If the network uses a separate gas token, your product also needs a way to source, price, and manage that asset.
Collateral onboarding
You need to determine how users acquire or move a supported crypto asset onto the selected network. For bitcoin-backed borrowing on an EVM network, that includes deciding which wrapped bitcoin asset to support and how users obtain it.
Wallet infrastructure
Every borrower needs a wallet capable of signing and submitting the required transactions. That may be an externally owned account, a smart account, or a developer-controlled wallet.
Asset and issuer diligence
You need to evaluate the collateral asset, the asset being borrowed, and the organizations responsible for issuing or managing them.
Ongoing loan operations
You need to orchestrate transactions, manage gas, monitor positions and oracles, track changing health factors, and alert users before they become eligible for liquidation.
Each category introduces its own integration, operational responsibility, and failure mode. Building the product yourself means making all six work together and continuing to operate them after launch.
What Borrow Kit handles for developers
Borrow Kit handles protocol interactions, transaction orchestration, loan lifecycle operations, and position monitoring through the wallet adapter you provide.
There is no smart contract code to write or direct lending protocol integration to maintain. Health tracking arrives as data and webhooks instead of through indexers you operate.
Your product still chooses the market, provides the interface, and determines how to respond when a position enters a warning band. Your wallet remains the signing authority for each loan action through the adapter.
What cirBTC is and why it is the first supported collateral
Lending markets on Arc are EVM markets, and an EVM market cannot accept native bitcoin as collateral.
Circle Wrapped Bitcoin, or cirBTC, closes that gap. It is wrapped BTC backed 1:1 by native bitcoin, with reserves independently verifiable onchain and custodied at Circle National Trust Bank, a federally chartered trust bank and qualified custodian. Onchain, cirBTC is an ERC-20 token, so lending protocols can treat it like other supported collateral assets.
Using cirBTC can help simplify asset and issuer diligence. Both sides of the loan, the cirBTC used as collateral and the USDC drawn by the borrower, are issued by Circle entities.
For your integration, the collateral is an ordinary token balance. The user’s cirBTC remains in the wallet connected through your adapter until the loan opens. The loan transaction then deposits it into the selected market as collateral. When the loan closes, the collateral returns to the same wallet.
On Arc Testnet, developers can obtain cirBTC from the Circle faucet. In production, Circle will work with integrators to make bridging BTC into cirBTC seamless and invisible to end users, so they can use BTC as collateral without managing the wrapping step themselves.
Set up the project
The next six steps walk through one loan from origination to payoff. For project setup and the complete set of wallet adapters, see the Borrow Kit quickstart.
To follow along, you need a wallet on Arc Testnet with two assets:
- cirBTC to deposit as collateral
- USDC to pay gas
Both are available from the Circle faucet on Arc Testnet.
Everything below builds on one connected Borrow Kit instance:
import { BorrowKit } from "@circle-fin/borrow-kit";
import { createViemAdapterFromPrivateKey } from "@circle-fin/adapter-viem-v2/next";
import { privateKeyToAccount } from "viem/accounts";
const kit = new BorrowKit();
const adapter = createViemAdapterFromPrivateKey({
privateKey: process.env.PRIVATE_KEY as `0x${string}`,
});
const walletAddress = privateKeyToAccount(
process.env.PRIVATE_KEY as `0x${string}`
).address;
Borrow Kit is permissionless by default. You do not need an API key or approval to get started.
1. Choose a cirBTC and USDC lending market
A market pairs a collateral asset with a loan asset and defines the risk parameters that govern the position.
exploreMarkets returns the available markets, so your integration does not need to hardcode a market address.
const { markets } = await kit.exploreMarkets({
chain: "Arc_Testnet",
sortBy: "borrowApy",
});
const { marketId } = markets[0];
The response below is trimmed to the fields that matter for this walkthrough:
{
"marketId": "0xf8a71f6df9dc7725d1c2fd848e4635d1e9ddca11da4e2dc2f9801005bd2b5d58",
"protocol": "morpho",
"collateralAsset": { "symbol": "cirBTC", "decimals": 8 },
"loanAsset": { "symbol": "USDC", "decimals": 6 },
"lltv": 0.86,
"borrowApy": 0.000281,
"liquidity": { "token": "USDC", "amount": "9383.670224" },
"utilization": 0.036897
}
Two fields define the market terms.
lltv is the liquidation loan-to-value ratio. It describes how much debt a position can carry relative to its collateral value before it becomes liquidatable. An LLTV of 0.86 means the liquidation threshold is 86 percent of the collateral value.
borrowApy is the annualized rate charged on the outstanding debt. It is a cost paid by the borrower, not a return they receive.
The 0.000281 value in this testnet response is approximately 0.03 percent. It reflects an almost empty testnet market and should not be treated as representative of a production rate. Borrow rates are variable and move with market supply and demand.
2. Size the loan before anything is signed
Your user thinks, “I need 5 USDC,” not, “I would like to deposit 0.00043605 cirBTC as collateral.”
Borrow Kit starts with the amount the user wants to borrow and calculates how much collateral would be required for a target health factor.
const sizing = await kit.getRequiredCollateral({
chain: "Arc_Testnet",
marketId,
borrowAmount: "5",
targetHealthFactor: 1.5,
});
// requiredCollateral: 0.00011628 cirBTC
The responsibilities break down into four parts:
- Developer input:
borrowAmountand, for this sizing preview,targetHealthFactor - Borrow Kit calculation: the amount of collateral required
- Market constraint: the market’s LLTV
- User-facing result: the collateral amount, resulting health factor, LTV, risk band, and liquidation price
targetHealthFactor is an input to getRequiredCollateral. It asks how much collateral would put the previewed position at a health factor of 1.5.
It is not a setting stored on the loan. When the loan is quoted, the borrow service applies its own sizing target and returns the resulting health factor.
getMaxBorrow answers the same sizing question from the other direction. Given the collateral a user already holds, it calculates how much USDC they can borrow.
Neither sizing call requires a wallet or produces a signature. You can call them as the user changes an amount or moves a slider. Every write that moves funds also has a corresponding quote that can be shown before the user signs.
getBorrowQuote produces the information for the approval screen:
const quote = await kit.getBorrowQuote({
chain: "Arc_Testnet",
marketId,
walletAddress,
borrowAmount: "5",
});{
"collateralAmount": { "token": "cirBTC", "amount": "0.00009583" },
"loanAssetAmount": { "token": "USDC", "amount": "5" },
"borrowApy": 0.000281,
"resultingHealthFactor": 1.2362067527586496,
"resultingLtv": 0.6956765104873213,
"resultingBand": "SAFE",
"liquidationPrice": { "token": "USDC", "amount": "60669.463124" }
}
The quote tells the user that the loan would open with a health factor of 1.236, enter the SAFE band, and become liquidatable if cirBTC fell to 16,180.89 USDC.
The liquidation price comes from the market’s oracle. On Arc Testnet, the oracle uses a fixed value instead of a live market price, so developers should treat this result as a demonstration of the calculation rather than a current market view.
The 1.236 health factor is not specific to a 5 USDC loan. A 1 USDC loan and a 5 USDC loan can produce the same health factor because Borrow Kit adjusts the collateral amount with the requested loan size.
For this market, the resulting health factor comes from reading the resulting LTV against the market’s LLTV:
0.86 ÷ 0.6958 = 1.236A market with a different LLTV may produce a different result.
3. Open the loan in one user-facing transaction
Once the user accepts the quote, call borrow:
const result = await kit.borrow({
from: { adapter, chain: "Arc_Testnet" },
marketId,
borrowAmount: "5",
});The user signs one transaction. Inside that transaction, Borrow Kit bundles several operations:
- An exact collateral approval
- A Morpho authorization naming Circle’s adapter contract
- The Circle-signed execution
- A matching revocation
These operations succeed or fail together. There is no half-open loan or orphaned approval. The authorization and revocation are included in the same atomic transaction, so the adapter does not retain standing authority over the user’s position.
You can monitor the phases as they complete:
kit.on("*", ({ method, values }) => console.log(method, values.state));
// fetchParams success
// approve success
// setAuthorization success
// execute success
A borrow can return one of three statuses. Branch on status instead of checking only for a transaction hash:
if (result.status === "confirmed") {
console.log(
result.loanId,
result.amountBorrowed.amount,
result.txHash
);
} else if (result.status === "confirmed-details-unavailable") {
// The transaction landed, but the receipt could not be decoded.
// Do not retry.
console.log(result.loanId, result.txHash);
} else {
// The wallet accepted the batch, but the outcome is not yet known.
console.log(result.batchId);
}
Your integration should plan for a submitted result. Resolve it through the wallet’s EIP-5792 wallet_getCallsStatus method before retrying.
You can also pass an optional idempotencyKey to the write. Reusing the same value points to the original request instead of issuing a second one.
Every later call uses the loanId returned by the confirmed result.
Why this runs on Arc
Three properties of Arc shape the borrowing experience.
Gas is paid in USDC
Because USDC pays for gas on Arc, developers do not need to manage a separate native gas token for the borrow flow.
The wallet still needs enough USDC to cover transaction fees. If a user arrives holding only collateral, a paymaster can cover that cost. Arc supports ERC-4337 and EIP-7702 natively.
Settlement is deterministic
Arc finalizes blocks in under a second. A transaction is either unconfirmed or final, with no intermediate confirmation state.
This can remove confirmation-count logic and chain rollback handling from the integration. When borrow returns confirmed, the loan exists and downstream work can begin immediately. Your product can update its database, send a notification, or trigger another workflow without waiting for additional blocks.
You should still reconcile submitted and confirmed-details-unavailable results. In those cases, the uncertainty is in the wallet or the receipt rather than the finality of the chain.
The collateral and loan asset stay on Arc
Borrow Kit is designed to support crypto assets broadly, with cirBTC as the first supported collateral asset. On Arc, cirBTC is used as collateral and USDC is the borrowed asset within the same lending market. This avoids an additional bridge or crosschain settlement dependency in the core borrow flow, reducing the external trust assumptions integrators need to evaluate.
4. Monitor loan health and liquidation risk
Interest accrues and prices move, so a position’s health factor can deteriorate after origination.
Borrow Kit exposes the position data and risk bands your product can use to monitor the loan and alert the user as the position approaches liquidation.
const loan = await kit.getPosition({
loanId
});{
"dataStatus": "READY",
"status": "active",
"collateral": { "token": "cirBTC", "amount": "0.00009583" },
"healthFactor": 1.236,
"healthFactorBand": "SAFE",
"liquidationPrice": { "token": "USDC", "amount": "60669.463124" }
}
Immediately after a borrow, the position may return dataStatus: "PENDING" with null economic values because the onchain transaction has not been indexed yet. Poll until the status becomes READY.
For the outstanding payoff amount, use getCloseLoanQuote. It prices the debt at quote time and provides the amount to show a user who wants to know what they currently owe.
Health factor is calculated as:
Below 1.00, a liquidator can repay part or all of the debt and take collateral at a discount. This is a permissionless Morpho action that bypasses the SDK, so Borrow Kit cannot stop it.
Use the SAFE → WARN → URGENT → IMMINENT → LIQUIDATABLE progression to trigger notifications and give users time to add collateral or repay.
Borrow Kit can push these updates to your application through a webhook:
await kit.registerWebhook({
from: {
adapter,
chain: "Arc_Testnet"
},
loanId,
webhookUrl: "https://example.com/borrow-webhook",
});
Webhook registration is signed but does not go onchain. The wallet that owns the loan signs an EIP-712 intent, which the service verifies offchain.
See Monitor a Loan for webhook delivery and signature verification details.
5. Add collateral or repay the loan
Users have two primary ways to improve the health of an active position.
Adding collateral lowers the LTV and raises the health factor. Repaying debt improves the position from the other side.
addCollateral deposits more cirBTC into the position:
await kit.addCollateral({
from: {
adapter,
chain: "Arc_Testnet"
},
loanId,
collateralAmount: "0.0001",
});
For the example loan above, adding 0.0001 cirBTC would move the health factor from 1.236 to approximately 1.58.
withdrawCollateral releases collateral from the position:
await kit.withdrawCollateral({
from: {
adapter,
chain: "Arc_Testnet"
},
loanId,
collateralAmount: "0.0001",
});
Withdrawing collateral may require the user to repay part of the debt first. Borrow Kit calculates the repayment needed to keep the position healthy and bundles both operations into one signed transaction.
Users can also borrow more against the same position by passing loanId instead of marketId. See Grow a Loan for both operations.
Repaying part of the balance is one call:
const repaid = await kit.repay({
from: {
adapter,
chain: "Arc_Testnet"
},
loanId,
repayAmount: "1",
});Both adding collateral and repaying debt increase the health factor. Your interface can use the updated position and risk band to show how the action affects the user’s liquidation buffer.
The exact change depends on the market’s LLTV, the collateral value, and the size of the outstanding loan. Read the result back from the position and use getCloseLoanQuote when you need the current payoff amount.
6. Repay the balance and close the loan
A full payoff cannot be specified as a fixed number in advance because interest continues to accrue until the transaction settles.
Borrow Kit handles this through a quote and a close operation:
const quote = await kit.getCloseLoanQuote({
chain: "Arc_Testnet",
loanId,
slippageBps: 300,
});
// maximumRepayment: 4.243526 USDCconst closed = await kit.closeLoan({
from: {
adapter,
chain: "Arc_Testnet"
},
loanId,
slippageBps: 300,
});
// amountRepaid: 4.000001 USDC
// collateralWithdrawn: 0.00009583 cirBTC
// closed: truemaximumRepayment is the most the close transaction can pull from the wallet, including the selected slippage allowance.
The wallet should hold at least that amount before submitting the transaction. Borrow Kit will refuse to submit a close that could take more than the quoted ceiling.
In this example, the transaction repaid 4.000001 USDC. The amount was decoded from the onchain receipt. Any unused headroom was returned in the same transaction, and all collateral was sent back to the wallet that originally provided it.
See Pay Down a Loan for the complete set of repayment and wind-down paths.
How to handle Borrow Kit errors and retries
Reads and writes can fail for ordinary reasons, including network interruptions, insufficient collateral, and unsupported chains.
Borrow Kit surfaces these failures through a typed KitError. Each error includes a code, a type, and a recoverability flag. This lets your application branch on structured data instead of parsing error messages.
import {
BorrowKit,
isKitError,
isRetryableError
} from "@circle-fin/borrow-kit";
try {
await kit.borrow({
from: {
adapter,
chain: "Arc_Testnet"
},
marketId,
borrowAmount: "5"
});
} catch (err) {
if (isKitError(err) && isRetryableError(err)) {
const result = await kit.retry(err);
} else {
throw err;
}
}
Each write is submitted as one atomic transaction. If the transaction fails onchain, none of its bundled operations take effect.
retry resubmits the still-valid signed execution instead of asking the user for a new one. It also refuses to apply a write that has already been confirmed, which prevents the same action from being executed twice.
A thrown error does not always prove that the transaction failed to land. The client can throw after a wallet or network has already accepted the transaction.
Before retrying an origination, reconcile the result. Read the wallet’s loans and check whether a position already exists in that market. isRetryableError tells you whether the failure can be retried. It does not tell you whether the original transaction landed.
See Borrow Error Handling for the complete list of error codes.
Add crypto-backed USDC borrowing to your app
With Borrow Kit, you can let users open, monitor, adjust, and close crypto-backed USDC loans without integrating directly with a lending protocol or building the surrounding transaction and monitoring infrastructure yourself.
At launch, that means letting users borrow USDC against cirBTC directly within your product. As Borrow Kit adds support for more collateral assets and lending protocols, the same integration can support more borrowing experiences.
The connected wallet signs each loan action through the adapter. Each write is atomic, and the user signs one transaction for each action even when Borrow Kit bundles several operations inside it.
Arc further simplifies the flow by keeping cirBTC and USDC within the same market, avoiding an additional bridge or crosschain settlement dependency. Gas is paid in USDC, and deterministic settlement means integrations do not need to manage a separate native gas token or wait for additional confirmations.
Start with the Borrow Kit docs, go directly to Originate a Loan, clone the sample app, or explore the complete App Kits suite.
Borrow Kit is intended to provide software infrastructure and technical tooling that may enable third parties to build or offer access to certain borrowing-related functionality for their own users. Each integrator is solely responsible for ensuring that its use of the Borrow Kit, including how it structures, offers, markets, monetizes, or supports related products and services, complies with all applicable laws and regulations. By providing the Borrow Kit, Circle is providing software infrastructure and technical tools only and does not provide legal, tax, or regulatory advice. Integrators should consult their own advisors before launching or offering any related product or service.
USDC is issued by regulated affiliates of Circle. See Circle’s list of regulatory authorizations.
App Kits is offered by Circle Technology Services, LLC ("CTS"), a software provider. CTS does not provide regulated financial, legal, or advisory services and is not responsible for the content, accuracy, legality, or functionality of third-party applications or services integrated with App Kits. Integrators are solely responsible for their own compliance, including obtaining any necessary licenses. App Kits has not been reviewed or approved by any regulatory authority. Features may change at any time. Nothing herein constitutes a commitment, warranty, or guarantee; legal, regulatory, tax, or investment advice; an offer to sell any security or financial instrument; or an endorsement of any protocol, strategy, or transaction.
cirBTC is issued by Circle International Bermuda Limited, a Class F Digital Asset Business licensed and regulated by the Bermuda Monetary Authority. Circle Mint and related distribution services are provided by Circle Internet Financial, LLC, NMLS # 1201441.
Circle Ventures, an affiliate of Circle Internet Financial, LLC, has invested in Morpho.
Arc mainnet is an open L1 blockchain launched and offered by Arc Network Services LLC (“Arc LLC”) and operated by a permissioned validator set. Arc testnet is offered by Circle Technology Services, LLC (“CTS”). Arc LLC and CTS are software providers only and do not provide regulated financial or advisory services. Neither the Arc mainnet nor testnet has been reviewed or approved by the New York State Department of Financial Services or any other regulatory authority.
The Arc network is provided “as is” and “as available.” Use of Arc involves inherent risks associated with blockchain technology, including smart contract vulnerabilities, network disruptions, and the absence of recourse for transaction errors or losses. The ability to transact on Arc depends on the ability to obtain and use USDC to pay gas fees. Neither Arc LLC nor any permissioned validator is responsible for the content, accuracy, legality, or functionality of third-party applications, protocols, or services built on or integrated with Arc.
You are solely responsible for any features or services you provide to users, including obtaining any necessary licenses or approvals and otherwise complying with applicable laws. All Arc features may be modified, delayed, or cancelled at any time without notice and, where applicable, at the sole discretion of Arc LLC or CTS. Nothing herein constitutes a commitment, warranty, guarantee, or legal, regulatory, tax, or investment advice.
USDC is issued by Circle Internet Financial, LLC (NMLS #1201441) and is a separate product from any custody services provided by Circle National Trust or Circle New York Trust. Circle National Trust is the trade name of First National Digital Currency Bank, N.A., a national trust bank chartered and regulated by the Office of the Comptroller of the Currency (OCC), providing custody of digital assets. Digital assets are not deposits, are not insured by the Federal Deposit Insurance Corporation (FDIC), and may be subject to investment and other risks. Circle National Trust does not accept deposits or make loans.

