Skip to main content
This guide shows how to turn on Borrow in an existing @stakekit/widget integration. If you already embed the widget for Earn, your Earn setup stays as it is. You update the widget to 0.0.290, add two config props and, if your app manages the wallet, add two methods to your wallet adapter. Once Borrow is on, users supply collateral, borrow, manage positions, repay and withdraw collateral from the widget. To build your own Borrow interface instead, see the Borrow API guide.

At a glance

Prerequisites

  • Borrow enabled for your project. Email hello@yield.xyz with the API key you test with. Start with your dev environment.
  • A funded test wallet on Ethereum or Base, holding collateral (for example WETH or cbBTC) and native gas. Testing on Base costs less than on Ethereum.

Update the widget

If you use SKApp, your app needs React 19. The widget now uses its own wallet dialogs instead of RainbowKit, so remove color.connectKit and borderRadius.connectKit from your theme if you set them.
Skip this section for a new integration on 0.0.290. These are the changes since 0.0.282 that can break or change an existing integration.React 19. The react and react-dom peers are >=19. Upgrade your host app first if it is on React 18.Removed props and exports:Wallet dialogs (0.0.290). RainbowKit is gone. The widget ships its own connect, account and chain dialogs and its own WalletConnect. Existing Tron, Cosmos and Polkadot WalletConnect sessions reconnect once after the update.Adapter results (0.0.290). sendTransaction can resolve { type: "cancelled" } when the user declines, and signMessage can resolve a result object (success, cancelled or error) as well as a plain signature string. Borrow methods accept result objects only. signTypedData moved off SKWallet and is now a required Borrow method.Browser renderer. renderSKWidget returns { rerender, unmount }. Call unmount() when your page removes the widget.External provider state sync. The widget syncs your provider snapshot (address, chain, supported chains and callbacks) on every update. Keep externalProviders present while the wallet is disconnected, with currentAddress: "". Adding or removing externalProviders needs a remount.

Turn on Borrow

Borrow needs two props:
  • dashboardVariant: true. Borrow appears in the dashboard tab bar, next to Manage and Activity.
  • borrowEnabled: true.
The widget must also group yields by category. With dashboardVariant on, grouping defaults to "category", so remove yieldGrouping: "flat" if you set it.

If the widget connects the wallet

Add the two props:
Keep your theme and other Earn props as they are. Once Borrow is enabled for your project, the Borrow tab appears next to Earn.

If your app manages the wallet

If you pass your own wallet through externalProviders, your adapter needs two more methods. Your Earn methods (signMessage, switchChain and sendTransaction) stay as they are. The widget checks for both methods when it mounts. If either is missing, it rejects the configuration with borrow-provider-capability-missing.

The adapter: SKBorrowWallet

SKBorrowWallet is your Earn SKWallet plus the two Borrow methods. These types are exported from both @stakekit/widget and @stakekit/widget/bundle: SKWallet, SKBorrowWallet, SKBorrowTx, SKBorrowTxMeta, SKBorrowTxResult, SKBorrowSignatureResult, SKBorrowExternalProviders and SKEip712TypedData.
The yourWallet calls are placeholders for your wallet SDK or custody provider. getTransactionReceipt remains optional, as it is for Earn.

Results

Both Borrow methods return a result object. A plain hash or signature string is rejected as Invalid external provider result.
A rejected promise counts as error without a txHash.
Do not cast an Earn-only adapter to SKBorrowWallet to satisfy the compiler. The widget calls sendBorrowTransaction and signTypedData on it.

What is in SKBorrowTx

SKBorrowTx is { type: "evm"; tx }, where tx has: Fee fields are undefined unless the Borrow API quotes them; your signer estimates them in that case. Borrow transactions carry no nonce, so your wallet assigns it.

What is in SKBorrowTxMeta

actionType is what the user asked for. txType is what this one transaction does. Use these fields to label the request your users or approvers see.

How a Borrow action runs

One action can need several steps, for example an APPROVAL, then a SUPPLY, then a BORROW. For each step:
  1. The widget asks your adapter for a transaction (sendBorrowTransaction) or a signature (signTypedData).
  2. Your adapter signs, and for a transaction, broadcasts.
  3. Your adapter returns the hash or the signature.
  4. For a transaction, the widget reports the hash to the Borrow API and polls for confirmation: 20 checks, 2 seconds apart, about 40 seconds in total. For a signature, the widget submits it to the Borrow API itself.
  5. Once the step is confirmed, the widget moves to the next one.
The widget waits for your adapter with no timeout, so custody and multi-approval flows that take several minutes still complete. Return the hash only after the transaction is broadcast. If you return it earlier, polling can end before the transaction reaches the chain.

Pass your wallet to the widget

Keep passing your adapter through externalProviders, as you do for Earn.
Use the exported chain id constants for currentChain and supportedChainIds, or validate the ids from your SDK, rather than casting a plain number.
  • Disconnected wallet. Keep externalProviders and set currentAddress: "". Do not pass null or undefined, and do not remove the object. To add or remove externalProviders itself, remount the widget.
  • Rerender. rerender replaces all props. It does not merge them, so pass the full set each time.
  • Read at mount. apiKey, baseUrl, borrowApiUrl, yieldsApiUrl and borrowEnabled are read when the widget mounts. Remount to change them. Other props, including borrowMarketsScope, update live.
  • During a flow. Each step uses the provider you passed most recently. Keep both Borrow methods on every rerender, or the next step fails.
The widget sends your API key as the X-API-KEY header to borrowApiUrl, which defaults to https://borrow.yield.xyz. You do not need to set borrowApiUrl.

Which markets appear

borrowMarketsScope sets which markets the Borrow tab lists for new borrows:
To use "enabled", send the Yield.xyz team the markets you want for your project. Until a list is set, "enabled" shows no markets, so keep "all" until then. Existing positions stay visible and manageable under either scope. Markets load for the wallet’s current network only, on Ethereum, Base, Arbitrum and Optimism. A market is listed for new borrows only when:
  • borrowing is enabled on it,
  • it has at least $10,000 of available liquidity (a loan token with no USD price counts as no liquidity),
  • its borrow rate is 100% or lower, and
  • it has at least one collateral with a max LTV of 1% or more that is not the loan token itself.
Lists are sorted by available liquidity. Aave V3 and SparkLend are pooled markets, labeled by loan token, where all collateral sits in one account. Morpho Blue and Lista are isolated markets, labeled by their collateral and loan token pair. The widget handles both, so no per-protocol code is needed.

What the user sees

1

Borrow tab

The dashboard tab bar shows the Earn category tabs, then Borrow, then Manage and Activity.
2

Pick a market and collateral

The user picks a market for the wallet’s network, then a collateral. Collateral the wallet holds is listed first. The user enters amounts, with a Max shortcut.
3

Review

The review shows the action, the loan-to-value and health factor before and after, and any warnings. If the Borrow API rejects the action, its reason shows here.
4

Steps

The widget runs each transaction or signature in order. Each one has its own collapsible step, with an explorer link once it is submitted.
5

Manage and Activity

Borrow positions appear under Manage next to Earn positions, where the user repays or withdraws collateral. Borrow actions appear in Activity, with a Borrow filter and a receipt showing the market, fees, loan-to-value and health factor.
Risk checks. The health factor limit applies to every change that adds risk. The max LTV limit blocks only changes that add debt. A withdrawal past max LTV with a health factor of 1 or more shows a warning instead. Loan-to-value turns amber from 90% of max LTV and red past it; the health factor turns amber at 1.1 or below and red below 1. A full repayment can go ahead when the wallet balance appears insufficient, because the Borrow API checks the live balance when it builds the transaction. If you pass tracking, Borrow adds these page names: "Borrow", "Borrow review", "Borrow steps" and "Borrow complete", and these events: "Borrow market selected", "Borrow collateral selected", "Borrow page max clicked" and "Borrow review clicked".

Testing

  1. Update to 0.0.290 and turn on Borrow in your dev environment.
  2. If you pass your own wallet, implement both Borrow methods.
  3. Connect the test wallet on Base or Ethereum.
  4. Open Borrow, pick a USDC market (for example on Aave V3 or Morpho Blue), supply collateral and borrow a small amount, such as 10 USDC.
  5. Approve each step in your wallet. If you pass your own wallet, check that each request shows the expected txType.
  6. Open Manage and check that the position shows the collateral and the debt. Check that the action shows in Activity.
  7. Repay in full, then withdraw all collateral. Check that the position is gone from Manage.
If you pass your own wallet, also check that declining a request returns { type: "cancelled" }, that signTypedData works when a step asks for it, that an empty currentAddress keeps the widget running, and that switching networks updates the market list. Compare the behavior with the demo.

Troubleshooting

The widget logs errors to the browser console. Configuration problems include an issue code and the prop path. Each entry is titled with the console message, or with the symptom when there is no message.

Configuration

After you add borrowEnabled, the Borrow tab does not appear or the widget does not start. The widget logs this message on first mount with one of these issues:
A rerender is ignored and the widget keeps the previous configuration. The usual causes are a partial props object (rerender replaces everything) or a currentAddress of null or undefined, which shows as host-configuration-decode-failed. Set currentAddress: "" while the wallet is disconnected.
Check that the wallet is on Ethereum, Base, Arbitrum or Optimism, and that the chain is in supportedChainIds. With borrowMarketsScope: "enabled", check that markets are enabled for your project, or switch to "all".

Signing

A step needs an EIP-712 signature and the provider has no signTypedData. Implement it, and keep it on every rerender.
A step started and the provider had no sendBorrowTransaction. Keep both Borrow methods on every provider you pass.
The adapter returned something other than a result object, such as a plain hash string. Return { type: "success", txHash } or { type: "success", signature }.
The adapter reported success without a hash. Return the hash after broadcast, or return { type: "error", error }.

Confirmation

The hash came back, but the Borrow API did not see a confirmed transaction within about 40 seconds. Return the hash only after broadcast, and check that it is on the chain in tx.tx.chainId.
Also appears as Borrow transaction ended with NOT_FOUND status. The transaction reverted, or the hash is wrong or on another chain. Compare the hash in your wallet with the one you returned.

Wallet sync

externalProviders was added or removed after mount (external-provider-presence-changed). Keep the object present with currentAddress: "" while the wallet is disconnected, or remount the widget. Account and chain changes do not need a remount.
The widget tried to connect the currentAddress you passed and the connection failed. Check that the address and currentChain match the account and chain active in your wallet.

Build

Look for the removed props and exports in Upgrading from an earlier version, and check that React is on version 19.

FAQ

No. Borrow uses the same project key as Earn. Yield.xyz enables Borrow for that project.
No. Earn stays as it is. Borrow adds a tab and adds Borrow positions and actions to Manage and Activity. If your app manages the wallet, you add the two Borrow methods.
Yes. Send the Yield.xyz team the markets you want for your project and set borrowMarketsScope: "enabled".
The widget’s Borrow tab supports Ethereum, Base, Arbitrum and Optimism. The Borrow API supports more networks if you build your own UI. See Coverage.
Yes. The widget waits for your adapter with no timeout. Return the hash once the transaction is broadcast, and the widget tracks confirmation from there.
Not unless they are configured for your project. Fees apply to Morpho Blue markets. Contact hello@yield.xyz and see Borrow monetization.

Next steps

Borrow API

The full lifecycle behind the widget, for teams that build their own UI.

Core concepts

Markets, positions, health factor and the action lifecycle.