# Deposit and Withdraw First-Loss Capital

This tutorial shows you how to deposit and withdraw first-loss capital from a [LoanBroker](/docs/references/protocol/ledger-data/ledger-entry-types/loanbroker) on the XRP Ledger. First-loss capital helps protect vault depositor's assets, acting as a buffer in the event of loan defaults.

The tutorial demonstrates how a loan broker can manage risk by depositing XRP as first-loss capital, and how they can withdraw it when needed.

LendingProtocol
## Goals

By the end of this tutorial, you will be able to:

- Deposit an MPT as first-loss capital into a `LoanBroker` entry.
- Check the available cover balance in the loan broker's pseudo-account.
- Withdraw first-loss capital from a `LoanBroker` entry.


## Prerequisites

To complete this tutorial, you should:

- Have a basic understanding of the XRP Ledger.
- Have an XRP Ledger client library set up in your development environment. This page provides examples for the following:
  - **JavaScript** with the [xrpl.js library](https://github.com/XRPLF/xrpl.js). See [Get Started Using JavaScript](/docs/tutorials/get-started/get-started-javascript) for setup steps.
  - **Python** with the [xrpl-py library](https://github.com/XRPLF/xrpl-py). See [Get Started Using Python](/docs/tutorials/get-started/get-started-python) for setup steps.
  - **Go** with the [xrpl-go library](https://github.com/XRPLF/xrpl-go). See [Get Started Using Go](/docs/tutorials/get-started/get-started-go) for setup steps.


## Source Code

You can find the complete source code for this tutorial's examples in the code samples section of this website's repository.

## Steps

### 1. Install dependencies

JavaScript
From the code sample folder, use `npm` to install dependencies.


```bash
npm install xrpl
```

Python
From the code sample folder, set up a virtual environment and use `pip` to install dependencies.


```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```

Go
From the code sample folder, use `go` to install dependencies.


```bash
go mod tidy
```

### 2. Set up client and accounts

To get started, import the necessary libraries and instantiate a client to connect to the XRPL. This example imports:

JavaScript
- `xrpl`: Used for XRPL client connection, transaction submission, and wallet handling.
- `fs` and `child_process`: Used to run tutorial set up scripts.



```js
// IMPORTANT: This example deposits and withdraws first-loss capital from a
// preconfigured LoanBroker entry.

import fs from 'fs'
import { execSync } from 'child_process'
import xrpl from 'xrpl'

// Connect to the network ----------------------
const client = new xrpl.Client('wss://s.devnet.rippletest.net:51233')
await client.connect()
```

Python
- `xrpl`: Used for XRPL client connection, transaction submission, and wallet handling.
- `json`: Used for loading and formatting JSON data.
- `os`, `subprocess`, and `sys`: Used to run tutorial set up scripts.



```py
# IMPORTANT: This example deposits and withdraws first-loss capital from a
# preconfigured LoanBroker entry.

import json
import os
import subprocess
import sys

from xrpl.clients import JsonRpcClient
from xrpl.models import LoanBrokerCoverDeposit, LoanBrokerCoverWithdraw, MPTAmount
from xrpl.transaction import submit_and_wait
from xrpl.wallet import Wallet

# Set up client ----------------------
client = JsonRpcClient("https://s.devnet.rippletest.net:51234")
```

Go
- `xrpl-go`: Used for XRPL client connection, transaction submission, and wallet handling.
- `encoding/json` and `fmt`: Used for formatting and printing results to the console.
- `os` and `os/exec`: Used to run tutorial set up scripts.



```go
// IMPORTANT: This example deposits and withdraws first-loss capital from a
// preconfigured LoanBroker entry.

package main

import (
	"encoding/json"
	"fmt"
	"os"
	"os/exec"

	"github.com/Peersyst/xrpl-go/xrpl/transaction"
	"github.com/Peersyst/xrpl-go/xrpl/transaction/types"
	"github.com/Peersyst/xrpl-go/xrpl/wallet"
	"github.com/Peersyst/xrpl-go/xrpl/websocket"
	wstypes "github.com/Peersyst/xrpl-go/xrpl/websocket/types"
)

func main() {
	// Connect to the network ----------------------
	client := websocket.NewClient(
		websocket.NewClientConfig().
			WithHost("wss://s.devnet.rippletest.net:51233"),
	)
	defer client.Disconnect()

	if err := client.Connect(); err != nil {
		panic(err)
	}
```

Next, load the loan broker account, loan broker ID, and MPT issuance ID.

JavaScript

```js
// This step checks for the necessary setup data to run the lending protocol tutorials.
// If missing, lendingSetup.js will generate the data.
if (!fs.existsSync('lendingSetup.json')) {
  console.log(`\n=== Lending tutorial data doesn't exist. Running setup script... ===\n`)
  execSync('node lendingSetup.js', { stdio: 'inherit' })
}

// Load preconfigured accounts and LoanBrokerID.
const setupData = JSON.parse(fs.readFileSync('lendingSetup.json', 'utf8'))

// You can replace these values with your own
const loanBroker = xrpl.Wallet.fromSeed(setupData.loanBroker.seed)
const loanBrokerID = setupData.loanBrokerID
const mptID = setupData.mptID

console.log(`\nLoan broker address: ${loanBroker.address}`)
console.log(`LoanBrokerID: ${loanBrokerID}`)
console.log(`MPT ID: ${mptID}`)
```

This example uses preconfigured accounts and loan broker data from the `lendingSetup.js` script, but you can replace `loanBroker`, `loanBrokerID`, and `mptID` with your own values.

Python

```py
# This step checks for the necessary setup data to run the lending protocol tutorials.
# If missing, lending_setup.py will generate the data.
if not os.path.exists("lending_setup.json"):
    print("\n=== Lending tutorial data doesn't exist. Running setup script... ===\n")
    subprocess.run([sys.executable, "lending_setup.py"], check=True)

# Load preconfigured accounts and loan_broker_id.
with open("lending_setup.json") as f:
    setup_data = json.load(f)

# You can replace these values with your own.
loan_broker = Wallet.from_seed(setup_data["loan_broker"]["seed"])
loan_broker_id = setup_data["loan_broker_id"]
mpt_id = setup_data["mpt_id"]

print(f"\nLoan broker address: {loan_broker.address}")
print(f"LoanBrokerID: {loan_broker_id}")
print(f"MPT ID: {mpt_id}")
```

This example uses preconfigured accounts and loan broker data from the `lending_setup.py` script, but you can replace `loan_broker`, `loan_broker_id`, and `mpt_id` with your own values.

Go

```go
	// Check for setup data; run lending-setup if missing
	if _, err := os.Stat("lending-setup.json"); os.IsNotExist(err) {
		fmt.Printf("\n=== Lending tutorial data doesn't exist. Running setup script... ===\n\n")
		cmd := exec.Command("go", "run", "./lending-setup")
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		if err := cmd.Run(); err != nil {
			panic(err)
		}
	}

	// Load preconfigured accounts and LoanBrokerID
	data, err := os.ReadFile("lending-setup.json")
	if err != nil {
		panic(err)
	}
	var setup map[string]any
	if err := json.Unmarshal(data, &setup); err != nil {
		panic(err)
	}

	// You can replace these values with your own
	loanBrokerWallet, err := wallet.FromSecret(setup["loanBroker"].(map[string]any)["seed"].(string))
	if err != nil {
		panic(err)
	}
	loanBrokerID := setup["loanBrokerID"].(string)
	mptID := setup["mptID"].(string)

	fmt.Printf("\nLoan broker address: %s\n", loanBrokerWallet.ClassicAddress)
	fmt.Printf("LoanBrokerID: %s\n", loanBrokerID)
	fmt.Printf("MPT ID: %s\n", mptID)
```

This example uses preconfigured accounts and loan broker data from the `lending-setup` script, but you can replace `loanBrokerWallet`, `loanBrokerID`, and `mptID` with your own values.

### 3. Prepare LoanBrokerCoverDeposit transaction

Create the [LoanBrokerCoverDeposit transaction](/docs/references/protocol/transactions/types/loanbrokercoverdeposit) object.

JavaScript

```js
// Prepare LoanBrokerCoverDeposit transaction ----------------------
console.log(`\n=== Preparing LoanBrokerCoverDeposit transaction ===\n`)
const coverDepositTx = {
  TransactionType: 'LoanBrokerCoverDeposit',
  Account: loanBroker.address,
  LoanBrokerID: loanBrokerID,
  Amount: {
    mpt_issuance_id: mptID,
    value: '2000'
  }
}

// Validate the transaction structure before submitting
xrpl.validate(coverDepositTx)
console.log(JSON.stringify(coverDepositTx, null, 2))
```

The `Amount` field specifies the MPT and amount to deposit as first-loss capital.

Python

```py
# Prepare LoanBrokerCoverDeposit transaction ----------------------
print("\n=== Preparing LoanBrokerCoverDeposit transaction ===\n")
cover_deposit_tx = LoanBrokerCoverDeposit(
    account=loan_broker.address,
    loan_broker_id=loan_broker_id,
    amount=MPTAmount(mpt_issuance_id=mpt_id, value="2000"),
)

print(json.dumps(cover_deposit_tx.to_xrpl(), indent=2))
```

The `amount` field specifies the MPT and amount to deposit as first-loss capital.

Go

```go
	// Prepare LoanBrokerCoverDeposit transaction ----------------------
	fmt.Printf("\n=== Preparing LoanBrokerCoverDeposit transaction ===\n\n")
	coverDepositTx := transaction.LoanBrokerCoverDeposit{
		BaseTx: transaction.BaseTx{
			Account: loanBrokerWallet.ClassicAddress,
		},
		LoanBrokerID: loanBrokerID,
		Amount: types.MPTCurrencyAmount{
			MPTIssuanceID: mptID,
			Value:         "2000",
		},
	}

	// Flatten() converts the struct to a map and adds the TransactionType field
	flatCoverDepositTx := coverDepositTx.Flatten()
	coverDepositTxJSON, _ := json.MarshalIndent(flatCoverDepositTx, "", "  ")
	fmt.Printf("%s\n", string(coverDepositTxJSON))
```

The `Amount` field specifies the MPT and amount to deposit as first-loss capital.

If the transaction succeeds, the amount is deposited and held in the pseudo-account associated with the `LoanBroker` entry.

### 4. Submit LoanBrokerCoverDeposit transaction

Sign and submit the `LoanBrokerCoverDeposit` transaction to the XRP Ledger.

JavaScript

```js
// Sign, submit, and wait for deposit validation ----------------------
console.log(`\n=== Submitting LoanBrokerCoverDeposit transaction ===\n`)
const depositResponse = await client.submitAndWait(coverDepositTx, {
  wallet: loanBroker,
  autofill: true
})
if (depositResponse.result.meta.TransactionResult !== 'tesSUCCESS') {
  const resultCode = depositResponse.result.meta.TransactionResult
  console.error('Error: Unable to deposit cover:', resultCode)
  await client.disconnect()
  process.exit(1)
}
console.log('Cover deposit successful!')
```

Python

```py
# Sign, submit, and wait for deposit validation ----------------------
print("\n=== Submitting LoanBrokerCoverDeposit transaction ===\n")
deposit_response = submit_and_wait(cover_deposit_tx, client, loan_broker)

if deposit_response.result["meta"]["TransactionResult"] != "tesSUCCESS":
    result_code = deposit_response.result["meta"]["TransactionResult"]
    print(f"Error: Unable to deposit cover: {result_code}")
    sys.exit(1)

print("Cover deposit successful!")
```

Go

```go
	// Sign, submit, and wait for deposit validation ----------------------
	fmt.Printf("\n=== Submitting LoanBrokerCoverDeposit transaction ===\n\n")
	depositResponse, err := client.SubmitTxAndWait(flatCoverDepositTx, &wstypes.SubmitOptions{
		Autofill: true,
		Wallet:   &loanBrokerWallet,
	})
	if err != nil {
		panic(err)
	}

	if depositResponse.Meta.TransactionResult != "tesSUCCESS" {
		fmt.Printf("Error: Unable to deposit cover: %s\n", depositResponse.Meta.TransactionResult)
		os.Exit(1)
	}
	fmt.Printf("Cover deposit successful!\n")
```

Verify that the transaction succeeded by checking for a `tesSUCCESS` result code.

### 5. Check cover balance after deposit

Retrieve the cover balance from the transaction result by checking the `LoanBroker` entry in the transaction metadata.

JavaScript

```js
// Extract cover balance from the transaction result
console.log(`\n=== Cover Balance ===\n`)
let loanBrokerNode = depositResponse.result.meta.AffectedNodes.find(node =>
  node.ModifiedNode?.LedgerEntryType === 'LoanBroker'
)
// First-loss capital is stored in the LoanBroker's pseudo-account.
console.log(`LoanBroker Pseudo-Account: ${loanBrokerNode.ModifiedNode.FinalFields.Account}`)
console.log(`Cover balance after deposit: ${loanBrokerNode.ModifiedNode.FinalFields.CoverAvailable} TSTUSD`)
```

Python

```py
# Extract cover balance from the transaction result
print("\n=== Cover Balance ===\n")
loan_broker_node = next(
    node for node in deposit_response.result["meta"]["AffectedNodes"]
    if node.get("ModifiedNode", {}).get("LedgerEntryType") == "LoanBroker"
)
# First-loss capital is stored in the LoanBroker's pseudo-account.
print(f"LoanBroker Pseudo-Account: {loan_broker_node['ModifiedNode']['FinalFields']['Account']}")
print(f"Cover balance after deposit: {loan_broker_node['ModifiedNode']['FinalFields']['CoverAvailable']} TSTUSD")
```

Go

```go
	// Extract cover balance from the transaction result
	fmt.Printf("\n=== Cover Balance ===\n\n")
	for _, node := range depositResponse.Meta.AffectedNodes {
		if node.ModifiedNode != nil && node.ModifiedNode.LedgerEntryType == "LoanBroker" {
			// First-loss capital is stored in the LoanBroker's pseudo-account.
			fmt.Printf("LoanBroker Pseudo-Account: %s\n", node.ModifiedNode.FinalFields["Account"])
			fmt.Printf("Cover balance after deposit: %s TSTUSD\n", node.ModifiedNode.FinalFields["CoverAvailable"])
			break
		}
	}
```

The `LoanBroker` pseudo-account address is the `Account` field, and `CoverAvailable` shows the cover balance.

### 6. Prepare LoanBrokerCoverWithdraw transaction

Create the [LoanBrokerCoverWithdraw transaction](/docs/references/protocol/transactions/types/loanbrokercoverwithdraw) object.

JavaScript

```js
// Prepare LoanBrokerCoverWithdraw transaction ----------------------
console.log(`\n=== Preparing LoanBrokerCoverWithdraw transaction ===\n`)
const coverWithdrawTx = {
  TransactionType: 'LoanBrokerCoverWithdraw',
  Account: loanBroker.address,
  LoanBrokerID: loanBrokerID,
  Amount: {
    mpt_issuance_id: mptID,
    value: '1000'
  }
}

// Validate the transaction structure before submitting
xrpl.validate(coverWithdrawTx)
console.log(JSON.stringify(coverWithdrawTx, null, 2))
```

Python

```py
# Prepare LoanBrokerCoverWithdraw transaction ----------------------
print("\n=== Preparing LoanBrokerCoverWithdraw transaction ===\n")
cover_withdraw_tx = LoanBrokerCoverWithdraw(
    account=loan_broker.address,
    loan_broker_id=loan_broker_id,
    amount=MPTAmount(mpt_issuance_id=mpt_id, value="1000"),
)

print(json.dumps(cover_withdraw_tx.to_xrpl(), indent=2))
```

Go

```go
	// Prepare LoanBrokerCoverWithdraw transaction ----------------------
	fmt.Printf("\n=== Preparing LoanBrokerCoverWithdraw transaction ===\n\n")
	coverWithdrawTx := transaction.LoanBrokerCoverWithdraw{
		BaseTx: transaction.BaseTx{
			Account: loanBrokerWallet.ClassicAddress,
		},
		LoanBrokerID: loanBrokerID,
		Amount: types.MPTCurrencyAmount{
			MPTIssuanceID: mptID,
			Value:         "1000",
		},
	}

	flatCoverWithdrawTx := coverWithdrawTx.Flatten()
	coverWithdrawTxJSON, _ := json.MarshalIndent(flatCoverWithdrawTx, "", "  ")
	fmt.Printf("%s\n", string(coverWithdrawTxJSON))
```

### 7. Submit LoanBrokerCoverWithdraw transaction

Sign and submit the `LoanBrokerCoverWithdraw` transaction to the XRP Ledger.

JavaScript

```js
// Sign, submit, and wait for withdraw validation ----------------------
console.log(`\n=== Submitting LoanBrokerCoverWithdraw transaction ===\n`)
const withdrawResponse = await client.submitAndWait(coverWithdrawTx, {
  wallet: loanBroker,
  autofill: true
})
if (withdrawResponse.result.meta.TransactionResult !== 'tesSUCCESS') {
  const resultCode = withdrawResponse.result.meta.TransactionResult
  console.error('Error: Unable to withdraw cover:', resultCode)
  await client.disconnect()
  process.exit(1)
}
console.log('Cover withdraw successful!')
```

Python

```py
# Sign, submit, and wait for withdraw validation ----------------------
print("\n=== Submitting LoanBrokerCoverWithdraw transaction ===\n")
withdraw_response = submit_and_wait(cover_withdraw_tx, client, loan_broker)

if withdraw_response.result["meta"]["TransactionResult"] != "tesSUCCESS":
    result_code = withdraw_response.result["meta"]["TransactionResult"]
    print(f"Error: Unable to withdraw cover: {result_code}")
    sys.exit(1)

print("Cover withdraw successful!")
```

Go

```go
	// Sign, submit, and wait for withdraw validation ----------------------
	fmt.Printf("\n=== Submitting LoanBrokerCoverWithdraw transaction ===\n\n")
	withdrawResponse, err := client.SubmitTxAndWait(flatCoverWithdrawTx, &wstypes.SubmitOptions{
		Autofill: true,
		Wallet:   &loanBrokerWallet,
	})
	if err != nil {
		panic(err)
	}

	if withdrawResponse.Meta.TransactionResult != "tesSUCCESS" {
		fmt.Printf("Error: Unable to withdraw cover: %s\n", withdrawResponse.Meta.TransactionResult)
		os.Exit(1)
	}
	fmt.Printf("Cover withdraw successful!\n")
```

Verify that the transaction succeeded by checking for a `tesSUCCESS` result code.

### 8. Check cover balance after withdrawal

Retrieve the updated cover balance from the transaction result.

JavaScript

```js
// Extract updated cover balance from the transaction result
console.log(`\n=== Updated Cover Balance ===\n`)
loanBrokerNode = withdrawResponse.result.meta.AffectedNodes.find(node =>
  node.ModifiedNode?.LedgerEntryType === 'LoanBroker'
)
console.log(`LoanBroker Pseudo-Account: ${loanBrokerNode.ModifiedNode.FinalFields.Account}`)
console.log(`Cover balance after withdraw: ${loanBrokerNode.ModifiedNode.FinalFields.CoverAvailable} TSTUSD`)

await client.disconnect()
```

Python

```py
# Extract updated cover balance from the transaction result
print("\n=== Updated Cover Balance ===\n")
loan_broker_node = next(
    node for node in withdraw_response.result["meta"]["AffectedNodes"]
    if node.get("ModifiedNode", {}).get("LedgerEntryType") == "LoanBroker"
)
print(f"LoanBroker Pseudo-Account: {loan_broker_node['ModifiedNode']['FinalFields']['Account']}")
print(f"Cover balance after withdraw: {loan_broker_node['ModifiedNode']['FinalFields']['CoverAvailable']} TSTUSD")
```

Go

```go
	// Extract updated cover balance from the transaction result
	fmt.Printf("\n=== Updated Cover Balance ===\n\n")
	for _, node := range withdrawResponse.Meta.AffectedNodes {
		if node.ModifiedNode != nil && node.ModifiedNode.LedgerEntryType == "LoanBroker" {
			fmt.Printf("LoanBroker Pseudo-Account: %s\n", node.ModifiedNode.FinalFields["Account"])
			fmt.Printf("Cover balance after withdraw: %s TSTUSD\n", node.ModifiedNode.FinalFields["CoverAvailable"])
			break
		}
	}
}
```

The `CoverAvailable` field now shows the reduced balance after the withdrawal.

## See Also

**Concepts**:

- [Lending Protocol](/docs/concepts/tokens/lending-protocol)


**Tutorials**:

- [Create a Loan Broker](/docs/tutorials/defi/lending/use-the-lending-protocol/create-a-loan-broker)


**References**:

- [LoanBrokerCoverDeposit transaction](/docs/references/protocol/transactions/types/loanbrokercoverdeposit)
- [LoanBrokerCoverWithdraw transaction](/docs/references/protocol/transactions/types/loanbrokercoverwithdraw)