Skip to main content
Use the API to read the data your interface needs. Use the SDK to build an unsigned transaction when the user selects an action. Soroban RPC prepares that transaction, and your wallet signs it. Each lending account has a position NFT. Display its supplied assets and debt as a position, rather than a receipt token in the wallet balance list. Transferring the NFT transfers control of the whole account, including its debt.
The v1 routes are available on mainnet and testnet. These examples read mainnet. For testnet transactions, select testnet and use its API, RPC, contracts, and token addresses together.

1. Read positions and supported assets

Call the API from any language. These responses are arrays.
The first call lists collateral assets; the second lists borrow assets. The third returns one item per indexed position NFT owned by the address. Each position includes balances, prices, names, logos, and risk estimates. You do not need a separate token catalog or client-side balance calculations. For direct HTTP reads, follow Link: <...>; rel="next" until the header is absent. Resolve relative links against the URL of the page you just read. Keep requests on the same endpoint, reject cycles, and check HTTP errors. An empty page can still have a next link. The optional SDK read client handles pagination. It has no Stellar SDK runtime dependency. Public response types are available from the same entry.
For React Native, the optional reader needs standards-compatible URL and URLSearchParams, plus fetch and cancellation support. Your wallet runtime may already provide them. If compatible URL support is missing, install react-native-url-polyfill@2.0.0. Load import 'react-native-url-polyfill/auto' first in the app entry point, before SDK and app imports. Direct HTTP reads do not require the SDK reader.
Use read.assets({ usage: 'borrow' }) for a borrowing screen. Pass an AbortSignal when a screen closes or the selected wallet changes. See the integrator API reference for fields, pagination, and freshness rules.

2. Select a market

Let the user choose an asset and one of its spokes. Preserve hubId, spokeId, and sac together. The same token can appear in several hubs or spokes. A symbol such as USDC is a label, not a transaction identifier. For new supply, check canOpenAccount, canSupply, and supplyCapacity.amountRaw. For a top-up, select an existing account and use its spoke. These fields help your interface explain whether supply appears available. Simulation and ledger execution enforce the current contract rules. Keep API data, RPC, contract addresses, market selection, and signing passphrase on the same network. Use addresses to verify contract wiring. Reading the API does not require an API key.

3. Prepare a supply transaction for the wallet

The caller needs a funded Stellar account, XLM for fees, and the selected tokens. XLM supply uses its Stellar Asset Contract address, not the string XLM. Keep enough spendable XLM for fees and account reserves. Builders are synchronous and make no RPC requests. Their xdr is unsigned and unprepared. Fetch the current source sequence, build the transaction, then call prepareStellarTxXdr before signing. Preparation adds the Soroban footprint, authorization entries, and resource fees. The following functions continue from the initialization above. Supply amounts are decimal integer strings in token base units. For a 7-decimal token, "1.25" becomes "12500000". Use parseStellarTokenAmount for decimal input. It checks precision, positive amounts, and the i128 range through the SDK.
Install one copy of the Stellar SDK so the builder and RPC helper use the same transaction classes. This example continues from the network selected above. For React Native transaction imports, initialize TextEncoder and TextDecoder first. Use your wallet integration’s Stellar SDK and Metro runtime setup. Verify preparation, signing, submission, and recovery on the target device.
Pass asset: selectedAsset.sac, hubId, spokeId, and a positive raw amount string as amount. Use the SDK helper to convert decimal input:
The helper accepts decimal strings, never JavaScript numbers. It rejects excess precision instead of rounding and stops when token decimals are missing. Show its validation error before signing. Pass accountNonce: '0' to create an account. For a top-up, use the selected position’s accountId and its spoke. In an owner wallet flow, recheck owner_of(accountId) on deployment.positionNftContract before preparation. Indexed ownership can lag an NFT transfer. Other supply permissions are covered in Supply. The authorization check compares the prepared invocation with the builder output and limits caller token transfers to the requested supply. If the check fails, do not send the XDR to the wallet. The result of prepareSupply is unsigned XDR ready for the wallet to sign. Show the network, token, amount, account, spoke, hub, and estimated fee first. Keep the prepared authorization entries; they cover the controller invocation and nested token transfer. See position NFT for its ownership view. sourceSequence is the Stellar source account sequence. accountNonce is the lending account id. They are unrelated. A wallet can own several accounts on one spoke. Never infer its account id from a spoke, token, or first position.

4. Sign, submit and confirm

Connect the prepared XDR to your wallet provider. Sign with deployment.passphrase and the selected caller. Keep private keys in the wallet. The XOXNO builder and preparation helper do not sign or broadcast. This example receives your wallet callback and durable pending-transaction storage. Store the network with the hash and signed XDR before submission. XDR does not contain a network passphrase. Recovery must use the recorded network and its RPC, even if the user has since switched networks. Run browser signing in the client. A native wallet uses the same prepared XDR and signing network in its own signing flow.
Your signing callback returns a signed XDR string. Keep the prepared transaction’s sequence, operations, fees, authorizations, and timebounds unchanged. If preparation fails, show the error and stop before signing. Never pass unprepared builder output to the signer. For UNKNOWN, query server.getTransaction(hash) again. If you retry submission, send the same signed XDR and retain its hash. A later rejection does not prove that the original failed. Do not sign a replacement while the original envelope remains valid. After its timebound expires, resolve the original hash before deciding whether a replacement is needed. Expiry alone does not prove failure. If lookup remains NOT_FOUND, check the original network’s retained transaction history and reconcile ledger and account state. If the available history cannot prove the outcome, keep the operation unresolved and do not automatically repeat it. Serialize actions from the same Stellar source account to avoid sequence races. After SUCCESS, store a new lending account id from result.returnValue, decoded with scValToNative. Reconcile it with the indexed positions and NFT ownership. Mark the pending record terminal on SUCCESS, FAILED, or a definitive first-send rejection. An indexer delay means the interface is refreshing, not that supply should be repeated.

5. Display the wallet’s positions

Use accountId as the position id within its network and nftContract. Show spokeName, then display supplied and borrow as separate lists. Use each leg’s hubId and sac together as its key. Keep amountRaw and accountId as strings. Do not convert them to JavaScript numbers. The API applies interest indexes; do not apply legacy RAY conversion again. USD values and risk remain indexed estimates. This small formatter works in a browser or React Native application:
Render nftImage with an HTML image in a browser. In React Native, use your SVG renderer; native Image does not provide portable SVG support. For example, SvgUri from react-native-svg accepts a URL. Use native Image for supported raster token logos and an SVG renderer for SVG logos. Use the public HTTPS API from a mobile device. For local development, configure a reachable server URL: a physical device’s localhost refers to the device, not your computer. Show loading, empty, error, and incomplete-data states separately. A failed request is not an empty portfolio. Discard an old wallet result when selection changes. Check each field even when another field makes the item incomplete. Read spendable wallet balances through Horizon or the token contract’s balance view. Before receiving a classic issued asset, check its code/issuer trustline. This includes borrow, withdraw, and possible refunds. XLM and pure Soroban tokens need no classic trustline. A SAC address alone cannot identify the code/issuer.

Other lending actions

Use the same build → prepare → sign → submit → confirm lifecycle for every action. Repay has no repay-all sentinel. To close debt, use the ceiled debt with an accrual buffer; excess is refunded. Withdrawal and borrowing must satisfy the account’s current risk checks and pool liquidity. See withdraw, borrow, and repay.

Agent instructions and integration checks

Agents should follow the same explicit user intent and wallet signing boundary as a human integration. Use the skills already maintained in XOXNO/rs-lending-xlm: The SDK skill includes reads.md, positions.md, transactions.md, and frontend.md; the data skill includes api.md. Check the installed SDK exports and deployed routes before copying an example. Before shipping, verify:
  • The selected network matches API, metadata, contracts, RPC, and the signing passphrase.
  • The user selected an explicit reserve tuple and, for an existing position, an explicit account id with current NFT ownership.
  • Amounts use integer base units; v1 positions need no RAY conversion; missing values remain unavailable.
  • Only prepared XDR reaches the signer; the signed envelope and hash survive app reloads.
  • Success requires ledger SUCCESS; uncertain submission cannot trigger a second supply.
  • Position rows, prices, balances, and ownership reconcile after confirmation, including when the indexer lags.
  • Testnet covers new supply, existing-account top-up, withdrawal, wallet rejection, metadata/price unavailability, and recovery after a submission timeout.