# Manage XRPL tokens

You can perform the following fungible token management operations on the XRP ledger:

- Manage trust lines, including trust line creation, settings, and freezing
- Preauthorize deposits on an account
- Claw back tokens from an account
- Trade tokens in the decentralized exchange (DEX)


Each of these operations involves the creation of a transaction order.

You can also issue XRPL fungible tokens with a transfer order or transaction order. Transfer orders are the recommended method for sending all assets, including XRPL tokens.

For more information about:

- Issuing tokens with a transfer order, see [Send assets](/products/custody/v1.34/api/accounting/send-assets)
- Trading tokens on the DEX, see Trade in the Decentralized Exchange in the XRPL documentation


System change process
All new requests to change the system state follow the same process. To familiarize yourself with this process first, follow the [Request a change with an intent](/products/custody/v1.34/resources/tutorials/intent) tutorial.

This page covers XRPL fungible tokens using trust lines. For Multi-Purpose Tokens (MPTs), see [Multi-Purpose Tokens](/products/custody/v1.34/api/accounting/multi-purpose-tokens).

## XRPL token decimals and amounts

XRPL uses decimal values for fungible tokens, but Ripple Custody only supports integers. Based on the smallest possible token value in XRPL (`1000000000000000e-96`) Ripple Custody represents this as 1 and registers the token asset with 81 decimals.

This means that to send 1 unit of a token, you must be represent it as `1000000000000000000000000000000000000000000000000000000000000000000000000000000000`.

For an example of an XRPL token payload, see [Add tokens](/products/custody/v1.34/api/accounting-entities/token-management/add).

## Manage trust lines

A trust line is an accounting relationship between two accounts: a token **issuer** account, which controls the tokens, and a token **holder** account, which receives the tokens. A trust line:

- Creates a trust relationship between accounts for trading fungible tokens
- Is identified by the account pair and currency symbol
- Provides a structure to hold the tokens


In a given trust line, the token issuer has a negative balance equal to the positive balance of the token holder. For example, if the token holder holds 10 tokens issued by the issuer:

- The issuer account has a balance of -10 tokens
- The holder account has a balance of 10 tokens


For more information about trust lines, see Trust Lines in the XRPL documentation.

In Ripple Custody, you can create a trust line in two ways:

- With an issuer account and currency
- With a validated fungible token asset


### Prerequisites

To create trust lines, you need the following:

| Prerequisite | Additional information |
|  --- | --- |
| The account ID of the holder account. | [View account details](/products/custody/v1.34/api/accounting-entities/account/view) |
| The address of the token issuer account, or `tickerId` of an allowlisted fungible token. | If you want to use:An account address, see [View account details](/products/custody/v1.34/api/accounting-entities/account/view)A token, see [View tokens](/products/custody/v1.34/api/accounting-entities/token-management/view) |
| Enough funds in the accounts to cover the transaction and all reserves, including the network reserve of 10 XRP and the reserve of 2 XRP for each object held in the account, including the account itself. | [Check account balances](/products/custody/v1.34/api/accounting-entities/account/balances#check-account-balances) |
| The following new IDs, in a standard UUID format:A transaction order IDAn intent ID |  |


### Create a trust line

You can use the `TrustSet` operation to create new trust lines.

For more information about the `TrustSet` operation, see TrustSet in the XRPL documentation.

Creation of a trust line adds a reserved amount of 2 XRP. For more information about reserved amounts, see [Check account balances](/products/custody/v1.34/api/accounting-entities/account/balances#check-account-balances).

To create a trust line, follow the steps in [Request a change with an intent](/products/custody/v1.34/resources/tutorials/intent), with a transaction order payload similar to one of the following examples.

#### Payload examples

The following example creates a trust line between a holder account and an issuer account specified with a code and issuer address:


```json
{
    "payload": {   
        "id": "8fd2d859-77de-4bcc-976c-3f4ccdfdcc3d",
        "accountId": "c8b9519a-be18-4db7-9aca-cce93834841b",
        "parameters": {
            "operation": {
                "type": "TrustSet",
                "flags": [],
                "enableRippling": false,
                "limitAmount": {
                    "currency": {
                        "code": "USD",
                        "issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
                        "type": "Currency"
                    },
                    "value": "100",
                },
            }
            "sourceTag": 123456,
            "memos": [],
            "feeStrategy": {
                "drops": "5",
                "type": "SpecifiedAdditionalFee"
            },
            "maximumFee": "50",
            "type": "XRPL",
        },
        "description": "string",
        "customProperties": {},
        "type": "v0_CreateTransactionOrder"
    }
}
```

The following example creates a trust line between a holder account and an issuer account specified with a ticker ID:


```json
{
    "payload": {   
        "id": "8fd2d859-77de-4bcc-976c-3f4ccdfdcc3d",
        "accountId": "c8b9519a-be18-4db7-9aca-cce93834841b",
        "parameters": {
            "operation": {
                "type": "TrustSet",
                "flags": [],
                "enableRippling": false,
                "limitAmount": {
                    "currency": {
                       "tickerId": "3334a1d5-1176-401f-b534-ec13a6b5ee8e",
                       "type": "TickerId"
                    },
                    "value": "100",
                },
            }
            "sourceTag": 123456,
            "memos": [],
            "feeStrategy": {
                "drops": "5",
                "type": "SpecifiedAdditionalFee"
            },
            "maximumFee": "50",
            "type": "XRPL",
        },
        "description": "string",
        "customProperties": {},
        "type": "v0_CreateTransactionOrder"
    }
}
```

Fields of the `payload` block to note are as follows:

| Field | Description |
|  --- | --- |
| `id` | ID of the transaction order |
| `accountId` | ID of the holder account |
| `parameters.operation` | Details of the operation:`type`: `TrustSet``flags`: A list of flags to set for the trust line. The options are `tfSetFreeze`, `tfClearFreeze`, and `tfSetAuth`. `enableRippling`: Enables settlement through rippling for these accounts. This field is optional and set to `false` by default.For more information, see Rippling in the XRPL documentation. `limitAmount.currency`: Details of the trust line, either:`type`: `Currency`: Currency code and issuer account address. The currency code must be a three-character string or a 160-bit hexadecimal string.For more information, see Currency Codes in the XRPL documentation.`type`: `TickerId`: ID of an asset that is a validated XRPL fungible token.`limitAmount.value`: Maximum balance of tokens that the holder account is willing to hold. |
| `parameters.feeStrategy` | The fee strategy to use for the transaction.For more information, see [Fee strategy and maximum fee](/products/custody/v1.34/concepts/transactions-reference#fee-strategy-and-maximum-fee). |
| `parameters.maximumFee` | The maximum fee, in drops.For more information, see [Fee strategy and maximum fee](/products/custody/v1.34/concepts/transactions-reference#fee-strategy-and-maximum-fee). |
| `parameters.type` | Ledger type, in this case `XRPL`. |
| `type` | `v0_CreateTransactionOrder` |


### Create an authorized trust line

You can use the `TrustSet` operation with flag `tfSetAuth` to authorize the counterparty to hold assets.

This setting is only relevant if `asfRequireAuth` is enabled for the holder account. For more information, see [Update XRPL account settings](/products/custody/v1.34/api/accounting/account-settings/xrpl).

To create an authorized trust line, follow the steps in [Request a change with an intent](/products/custody/v1.34/resources/tutorials/intent), with a transaction order payload similar to the examples in [Create a trust line](#create-a-trust-line). The key fields to note are:

- `accountID`: The holder account ID.
- `flags`: Set to `tfSetAuth`.


### Freeze or unfreeze a trust line

You can use the `TrustSet` operation with flags `tfSetFreeze` or `tfClearFreeze` to freeze and unfreeze trust lines.

You cannot freeze the trust line if `asfNoFreeze` is enabled for the issuer account. For more information, see [Update XRPL account settings](/products/custody/v1.34/api/accounting/account-settings/xrpl).

To freeze or unfreeze a trust line, follow the steps in [Request a change with an intent](/products/custody/v1.34/resources/tutorials/intent), with a transaction order payload similar to the examples in [Create a trust line](#create-a-trust-line). The key fields to note are:

- `accountID`: The issuer account ID.
- `flags`: Set to `tfSetFreeze` or `tfClearFreeze`.


### Authorize an account to hold tokens in a trust line

You can use the `TrustSet` operation with flag `tfSetAuth` to authorize a holder account to hold tokens in a trust line.

This setting is only relevant if `asfRequireAuth` is enabled for the holder account. For more information, see [Update XRPL account settings](/products/custody/v1.34/api/accounting/account-settings/xrpl).

To authorize an account, follow the steps in [Request a change with an intent](/products/custody/v1.34/resources/tutorials/intent), with a transaction order payload similar to the examples in [Create a trust line](#create-a-trust-line). The key fields to note are:

- `accountID`: The holder account ID.
- `flags`: Set to `tfSetAuth`.


## Preauthorize deposits on an account

You can use the `DepositPreAuth` operation to authorize an account to send tokens and XRP to the holder account. You can also remove authorization from an authorized account.

For more information about the `DepositPreAuth` operation, see DepositPreAuth in the XRPL documentation.

This operation is only valid for accounts with the `asfDepositAuth` setting enabled.

For more information, see [Update XRPL account settings](/products/custody/v1.34/api/accounting/account-settings/xrpl).

To authorize or unauthorize an account, follow the steps in [Request a change with an intent](/products/custody/v1.34/resources/tutorials/intent) with a transaction order payload similar to one of the following examples.

### Payload examples

The following example shows an account authorization:


```json
{
    "payload": {   
        "id": "8fd2d859-77de-4bcc-976c-3f4ccdfdcc3d",
        "accountId": "c8b9519a-be18-4db7-9aca-cce93834841b",
        "parameters": {
            "operation": {
                "type": "DepositPreauth",
                "authorize": {
                   "address": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
                   "type": "Address"
                },
            },    
        }
        "sourceTag": 123456,
        "memos": [],
        "feeStrategy": {
            "drops": "5",
            "type": "SpecifiedAdditionalFee"
        },
        "maximumFee": "50",
        "type": "XRPL",
    },
    "description": "string",
    "customProperties": {},
    "type": "v0_CreateTransactionOrder"
}
```

The following example shows the removal of an account authorization:


```json
{
    "payload": {   
        "id": "8fd2d859-77de-4bcc-976c-3f4ccdfdcc3d",
        "accountId": "c8b9519a-be18-4db7-9aca-cce93834841b",
        "parameters": {
            "operation": {
                "type": "DepositPreauth",
                "unauthorize": {
                   "address": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
                   "type": "Address"
                },   
            },
        }
        "sourceTag": 123456,
        "memos": [],
        "feeStrategy": {
            "drops": "5",
            "type": "SpecifiedAdditionalFee"
        },
        "maximumFee": "50",
        "type": "XRPL",
    },
    "description": "string",
    "customProperties": {},
    "type": "v0_CreateTransactionOrder"
}
```

Fields of the `payload` block to note are as follows:

| Field | Description |
|  --- | --- |
| `id` | ID of the transaction order |
| `accountId` | ID of the holder account |
| `parameters.operation` | Details of the operation:`type`: `DepositPreauth``authorize` or `unauthorize`: Authorize or unauthorize the following account details:`type`: Possible types:`Address`: An account address`Account`: An account ID`Endpoint`: An endpoint IDYou cannot authorize and unauthorize in the same operation. |
| `parameters.feeStrategy` | The fee strategy to use for the transaction.For more information, see [Fee strategy and maximum fee](/products/custody/v1.34/concepts/transactions-reference#fee-strategy-and-maximum-fee). |
| `parameters.maximumFee` | The maximum fee, in drops.For more information, see [Fee strategy and maximum fee](/products/custody/v1.34/concepts/transactions-reference#fee-strategy-and-maximum-fee). |
| `parameters.type` | Ledger type, in this case `XRPL`. |
| `type` | `v0_CreateTransactionOrder` |


## Claw back tokens from an account

You can use the `Clawback` operation to claw back tokens issued from the issuer account. You can use this, for example, when the trust line for an account is frozen.

For more information about the `Clawback` operation, see Clawback in the XRPL documentation.

This operation is only valid for accounts with the `asfAllowTrustLineClawback` setting enabled.

For more information, see [Update XRPL account settings](/products/custody/v1.34/api/accounting/account-settings/xrpl).

### Prerequisites

| Prerequisite | Additional information |
|  --- | --- |
| The account ID of the issuer account. | [View account details](/products/custody/v1.34/api/accounting-entities/account/view) |
| The address and currency of the account or `tickerId` of an allowlisted fungible token. | If you want to use:An account address, see [View account details](/products/custody/v1.34/api/accounting-entities/account/view)A token, see [View tokens](/products/custody/v1.34/api/accounting-entities/token-management/view) |
| The details of the account from which to claw back tokens. | If the account is:Another Ripple Custody account, an account ID or address.For more information, see [View account details](/products/custody/v1.34/api/accounting-entities/account/view).An external account, an account address.For more information, see [View account details](/products/custody/v1.34/api/accounting-entities/account/view).Associated with an endpoint, an endpoint ID.For more information, see [View endpoint details](/products/custody/v1.34/api/accounting-entities/endpoint/view). |
| Enough funds in the accounts to cover the transaction and all reserves, including the network reserve of 10 XRP and the reserve of 2 XRP for each object held in the account, including the account itself. | [Check account balances](/products/custody/v1.34/api/accounting-entities/account/balances#check-account-balances) |
| The following new IDs, in a standard UUID format:A transaction order IDAn intent ID |  |


To claw back tokens from an account, follow the steps in [Request a change with an intent](/products/custody/v1.34/resources/tutorials/intent) with a transaction order payload similar to one of the following example.

### Payload example

The following example shows clawback of a specific asset ID from an account address:


```json
{
    "payload": {   
        "id": "8fd2d859-77de-4bcc-976c-3f4ccdfdcc3d",
        "accountId": "c8b9519a-be18-4db7-9aca-cce93834841b",
        "parameters": {
            "operation": {
                "type": "Clawback",
                "currency": {
                    "tickerId": "3334a1d5-1176-401f-b534-ec13a6b5ee8e",
                    "type": "TickerId"
                },
                "holder": {
                    "address": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
                    "type": "Address"
                },
                "value": "3141592650000000000000000000000000000000000000000000000000000000000000000000000000"
            }
            "sourceTag": 123456,
            "memos": [],
            "feeStrategy": {
                "drops": "5",
                "type": "SpecifiedAdditionalFee"
            },
            "maximumFee": "50",
            "type": "XRPL",
        },
        "description": "string",
        "customProperties": {},
        "type": "v0_CreateTransactionOrder"
    }
}
```

Fields of the `payload` block to note are as follows:

| Field | Description |
|  --- | --- |
| `id` | ID of the transaction order |
| `accountId` | ID of the issuer account |
| `parameters.operation` | Details of the operation:`type`: `Clawback``currency`: Details of the token, one of the following: `type`:  `Currency`: Currency code and issuer account address. The currency code must be a three-character string or a 160-bit hexadecimal string.For more information, see the XRPL documentation.`type`: `TickerId`: The ID of an asset that is an XRPL fungible token that is validated.`holder`: Details of the token holder account to claw back from: `type`: Possible types:`Address`: An account address.`Account`: An account ID`Endpoint`: An endpoint ID.`value`: The amount to be clawed back, as a valid token amount.For more information, see [XRPL token decimals and amounts](#xrpl-token-decimals-and-amounts). |
| `parameters.feeStrategy` | The fee strategy to use for the transaction.For more information, see [Fee strategy and maximum fee](/products/custody/v1.34/concepts/transactions-reference#fee-strategy-and-maximum-fee). |
| `parameters.maximumFee` | The maximum fee, in drops.For more information, see [Fee strategy and maximum fee](/products/custody/v1.34/concepts/transactions-reference#fee-strategy-and-maximum-fee). |
| `parameters.type` | Ledger type, in this case `XRPL`. |
| `type` | `v0_CreateTransactionOrder` |


## Trade tokens in the decentralized exchange (DEX)

You can use the `OfferCreate` operation to create an offer on the DEX to trade XRP for tokens, or tokens for other tokens.
Only offers that have a corresponding offer on the DEX are executed.

For example:

- A seller account offers tokens for XRP.
- A taker account offers XRP for tokens.


As long as the offer amounts match, the trade is automatically executed on the ledger.

For more information about:

- The `OfferCreate` operation, see OfferCreate in the XRPL documentation.
- Trading tokens on the DEX, see Trade in the Decentralized Exchange in the XRPL documentation.


### Supported settings

Since Ripple Custody only supports the creation of offers with a corresponding offer on the DEX, it is mandatory to set one of the following settings:

- `tfImmediateOrCancel`: The offer is either executed immediately or cancelled. It can be partially fulfilled.
- `tfFillOrKill`: The offer is either fully filled immediately or cancelled. It can't be partially fulfilled.


You can also set the following optional setting:

- `tfSell`: Used to agree to receive more than the amount specified in **Taker Pays** if an offer is available for more than the amount asked for.


### Create an offer to trade on the DEX

To create an offer to trade on the DEX, follow the steps in [Request a change with an intent](/products/custody/v1.34/resources/tutorials/intent), with a transaction order payload similar to the following example.

#### Payload example

The following example shows an immediate-or-cancel offer for a token:


```json
{
    "payload": {   
        "id": "8fd2d859-77de-4bcc-976c-3f4ccdfdcc3d",
        "accountId": "c8b9519a-be18-4db7-9aca-cce93834841b",
        "parameters": {
            "operation": {
                "type": "OfferCreate",
                "flags": ["tfImmediateOrCancel"],
                "takerGets": {
                    "currency": {
                        "tickerId": "3334a1d5-1176-401f-b534-ec13a6b5ee8e",
                        "type": "TickerId" 
                    },
                    "amount": "3141592650000000000000000000000000000000000000000000000000000000000000000000000000"
                },
                "takerPays": {
                    "currency": {
                        "code": "USD",
                        "issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
                        "type": "Currency"
                    },
                    "amount": "3141592650000000000000000000000000000000000000000000000000000000000000000000000000"
                },
            }
            "sourceTag": 123456,
            "memos": [],
            "feeStrategy": {
                "drops": "5",
                "type": "SpecifiedAdditionalFee"
            },
            "maximumFee": "50",
            "type": "XRPL",
        },
        "description": "string",
        "customProperties": {},
        "type": "v0_CreateTransactionOrder"
    }
}
```

Fields of the `payload` block to note are as follows:

| Field | Description |
|  --- | --- |
| `id` | ID of the transaction order |
| `accountId` | ID of the account creating the offer |
| `parameters.operation` | Details of the operation:`type`: `OfferCreate``flags`: Settings for the offer.For more information, see [Supported settings](/products/custody/v1.34/api/accounting/account-settings/xrpl#supported-settings).`takerGets`: Details of what you want to offer:`currency`: Null if this is XRP, otherwise one of the following:`type`: `Currency`: Currency code and issuer account address. The currency code must be a three-character string or a 160-bit hexadecimal string.For more information, see Currency Codes in the XRPL documentation.`type`: `TickerId`: The ID of an asset that is a validated XRPL fungible token.`amount`: Amount of tokens you want to offer, or the amount in drops if you want to offer XRP.For more information about token amounts, see [XRPL token decimals and amounts](#xrpl-token-decimals-and-amounts).`takerPays`: Details of what you are willing to accept:`currency`: Null if this is XRP, otherwise one of the following:`type`: `Currency`: Currency code and issuer account address. The currency code must be a three-character string or a 160-bit hexadecimal string.For more information, see Currency Codes in the XRPL documentation.`type`: `TickerId`: The ID of an asset that is an XRPL fungible token that is validated.`amount`: Amount of the token that you are willing to accept, or the amount in drops if you are willing to accept XRP.For more information about token amounts, see [XRPL token decimals and amounts](#xrpl-token-decimals-and-amounts). |
| `parameters.feeStrategy` | The fee strategy to use for the transaction.For more information, see [Fee strategy and maximum fee](/products/custody/v1.34/concepts/transactions-reference#fee-strategy-and-maximum-fee). |
| `parameters.maximumFee` | The maximum fee, in drops.For more information, see [Fee strategy and maximum fee](/products/custody/v1.34/concepts/transactions-reference#fee-strategy-and-maximum-fee). |
| `parameters.type` | Ledger type, in this case `XRPL`. |
| `type` | `v0_CreateTransactionOrder` |