> ## Documentation Index
> Fetch the complete documentation index at: https://xoxno.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Repay

> Repay any account from a payer wallet or contract and reconcile overpayment refunds.

Repay transfers tokens from a payer to the pool and reduces an account's debt.
Any caller can repay any account; the account owner's authorization is not
required. The pool refunds overpayment to the payer.

## Choose the payment

Each payment is `(HubAssetKey, amount)` in token base units. The list must be
nonempty and every amount strictly positive. Duplicate market entries are
summed. Repayment has no zero-amount sentinel.

Read `get_borrow_amount(account_id, hub_asset)` for the displayed debt. That
view rounds half-up; full repayment uses ceiling-rounded debt. Full repayment
can require one more base unit before later interest. Allow a buffer for
rounding and accrual, then simulate the payment. The pool refunds excess.

Credit uses the amount actually delivered to the pool. A transfer that delivers
less reduces debt by less. Use `parseStellarTokenAmount(input, decimals)` for a
positive decimal payment; there is no need to write an amount parser.

Repayment needs no oracle prices or account solvency check. It remains
available during global protocol pause and when the listing is frozen. A paused
listing blocks repayment of that asset. A missing listing permits repayment
of an existing debt position. Partial repayment burns debt shares with floor
rounding; a payment too small to burn one share reverts.

## Build and authorize the call

```rust theme={"system"}
repay(
    caller: Address,
    account_id: u64,
    payments: Vec<(HubAssetKey, i128)>,
)
```

The account must exist and have a debt position for every market in `payments`.
The caller must hold the requested tokens and authorize the controller call and
each nested token transfer to the pool.

<CodeGroup>
  ```bash Stellar CLI theme={"system"}
  # Set CONTROLLER, IDENTITY, and CALLER_ADDRESS as in the quickstart.
  # Replace the token address. Repay 200 XLM; excess is refunded.
  stellar contract invoke \
    --id "$CONTROLLER" \
    --source-account "$IDENTITY" \
    --network testnet \
    -- repay \
    --caller "$CALLER_ADDRESS" \
    --account_id 42 \
    --payments '[[{"hub_id":1,"asset":"<XLM_SAC>"}, "2000000000"]]'
  ```

  ```typescript TypeScript theme={"system"}
  import { rpc } from '@stellar/stellar-sdk'
  import {
    assertStellarPreparedTxAuth,
    buildStellarRepayTx,
    getStellarDeployment,
    prepareStellarBuiltTx,
    type StellarHubAssetAmount,
    type StellarNetwork,
  } from '@xoxno/sdk-js/stellar-lending'

  export async function prepareRepayment(
    server: rpc.Server,
    network: StellarNetwork,
    caller: string,
    accountId: string,
    payment: StellarHubAssetAmount,
  ): Promise<string> {
    const deployment = getStellarDeployment(network)
    const source = await server.getAccount(caller)
    const built = buildStellarRepayTx({
      network,
      caller,
      sourceSequence: source.sequenceNumber(),
      controllerAddress: deployment.lendingController,
    }, { ...payment, accountNonce: accountId })
    const preparedXdr = await prepareStellarBuiltTx(server, built, { network })
    assertStellarPreparedTxAuth(preparedXdr, {
      network, caller, builtXdr: built.xdr,
    })
    return preparedXdr
  }
  ```
</CodeGroup>

The SDK builder returns unsigned, unprepared XDR without an RPC call. The
function above fetches the Stellar source sequence, prepares the XDR, and checks
its authorization tree. Pass the payer's `G...` address as `caller` and token
base units as `payment.amount`. The RPC must use the selected network.

Sign only the returned prepared XDR. Follow the
[wallet transaction lifecycle](/docs/stellar-lending/dev/wallet-integration#4-sign-submit-and-confirm)
for signing, durable submission records, confirmation, and uncertain outcomes.
For several debt markets, use `buildStellarRepayBatchTx`.

## Verify repayment and refunds

Read `get_borrow_amount(account_id, hub_asset)` to confirm remaining debt and
check the payer's token balances for excess-payment refunds. The controller
emits `UpdatePositionBatchEvent` at `["position", "batch_update"]`; the pool
emits `PoolMarketStateBatchEvent` at `["market", "batch_state_update"]`.

When valid prices are available, `get_total_borrow_usd(account_id)` and
`get_health_factor(account_id)` provide an account valuation. A debt-free
account reports `i128::MAX` health factor. That value alone does not prove no
debt: a saturated ratio or missing account can return it too. Oracle-free balance reads
remain available during price outages.

## Close the account

Repaying the final debt does not remove the account or its remaining collateral.
To exit fully, repay all debt, then [withdraw](/docs/stellar-lending/dev/withdraw)
all supplied assets with the full-position sentinel. Removing the final
position burns the account's position NFT.

## Common errors

| Error | Cause | Fix |
| - | - | - |
| `#120 DebtPositionNotFound` | No debt position for the asset in this account | Repay an asset the account actually owes. |
| `#16 InvalidPayments` | Empty payments vector | Pass at least one `(asset, amount)` entry. |
| `#14 AmountMustBePositive` | A payment amount is zero or negative | Use a positive amount per asset; repayment has no zero sentinel. |
| `#52 RepayRoundsToZeroShares` | The net repayment is too small to burn one scaled debt share | Repay more. |

To fund a repayment from collateral in one transaction, use
[repay debt with collateral](/docs/stellar-lending/dev/strategies#repay-debt-with-collateral).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.