mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2025-11-24 05:35:51 +00:00
Reorg tutorials to match nav, and update links
This commit is contained in:
@@ -0,0 +1,288 @@
|
||||
---
|
||||
parent: use-tokens.html
|
||||
seo:
|
||||
description: Set up an Automated Market Maker (AMM)
|
||||
embed_xrpl_js: true
|
||||
status: not_enabled
|
||||
filters:
|
||||
- interactive_steps
|
||||
labels:
|
||||
- Decentralized Exchange
|
||||
- Tokens
|
||||
- AMM
|
||||
steps: ['Connect', 'Generate', 'Acquire tokens', 'Check for AMM', 'Look up AMMCreate cost', 'Create AMM', 'Check AMM info', 'Check trust lines']
|
||||
---
|
||||
# Create an Automated Market Maker
|
||||
|
||||
_(Requires the [AMM amendment][] {% not-enabled /%})_
|
||||
|
||||
An [Automated Market Maker (AMM)](../../../concepts/tokens/decentralized-exchange/automated-market-makers.md) can be an efficient way to facilitate exchanges between two assets while earning its liquidity providers passive income. This tutorial shows how to create an AMM for a given asset pair.
|
||||
|
||||
<!-- Source for this specific tutorial's interactive bits: -->
|
||||
<script type="application/javascript" src="/js/interactive-tutorial.js"></script>
|
||||
<script type="application/javascript" src="/js/tutorials/create-amm.js"></script>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- You must have an XRP Ledger address and some XRP. For development and testing purposes, you can get these from a [Faucet](/resources/dev-tools/xrp-faucets).
|
||||
- You should be familiar with the Getting Started instructions for your preferred client library. This page provides examples for the following:
|
||||
- **JavaScript** with the [xrpl.js library](https://github.com/XRPLF/xrpl.js/) **version 2.11.0 or later**. See [Get Started Using JavaScript](../../javascript/get-started.md) for setup steps.
|
||||
- You can also read along and use the interactive steps in your browser without any setup.
|
||||
- You should have a basic understanding of how [tokens](../../../concepts/tokens/index.md) work in the XRP Ledger.
|
||||
- You may want to read about [Automated Market Makers in the XRP Ledger](../../../concepts/tokens/decentralized-exchange/automated-market-makers.md) first.
|
||||
|
||||
|
||||
## Example Code
|
||||
|
||||
Complete sample code for all of the steps of these tutorials is available under the [MIT license](https://github.com/XRPLF/xrpl-dev-portal/blob/master/LICENSE).
|
||||
|
||||
- See [Code Samples: Create an AMM](https://github.com/XRPLF/xrpl-dev-portal/tree/master/_code-samples/create-amm/) in the source repository for this website.
|
||||
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Connect to the network
|
||||
|
||||
You must be connected to the network to query it and submit transactions. The following code shows how to connect to a public {{use_network}} server using a supported [client library](../../../references/client-libraries.md):
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/create-amm/js/connect.js" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
For this tutorial, click the following button to connect:
|
||||
|
||||
{% partial file="/docs/_snippets/interactive-tutorials/connect-step.md" /%}
|
||||
|
||||
### 2. Get credentials
|
||||
|
||||
To transact on the XRP Ledger, you need an address, a secret key, and some XRP. For development and testing purposes, you can get these on the [{{use_network}}](../../../concepts/networks-and-servers/parallel-networks.md) using the following interface:
|
||||
|
||||
{% partial file="/docs/_snippets/interactive-tutorials/generate-step.md" /%}
|
||||
|
||||
When you're building production-ready software, you should use an existing account, and manage your keys using a [secure signing configuration](../../../concepts/transactions/secure-signing.md). The following code shows how to get a `Wallet` instance using either the faucet or a seed provided by environment variable:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/create-amm/js/create-amm.js" from="// Get credentials" before="// Acquire tokens" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
|
||||
### 3. Select and acquire assets
|
||||
|
||||
As the creator of an AMM, you are also the first liquidity provider and you have to supply it with a starting pool of assets. Other users of the XRP Ledger can also become liquidity providers by supplying assets after the AMM exists. It's crucial to choose assets carefully because, as a liquidity provider for an AMM, you are supplying some amounts of both for users to swap between. If one of the AMM's assets becomes worthless, other users can use the AMM to trade for the other asset, leaving the AMM (and thus, its liquidity providers including you) holding only the worthless one. Technically, the AMM always holds some positive amount of both assets, but the amounts can be very small.
|
||||
|
||||
You can choose any pair of fungible assets in the XRP Ledger, including XRP or tokens, as long as they meet the [restrictions on AMM assets](../../../concepts/tokens/decentralized-exchange/automated-market-makers.md#restrictions-on-assets).
|
||||
|
||||
For each of the two assets, you need to know its currency code and issuer; as an exception, XRP has no issuer. For each of the assets, you must hold a balance of the asset (or _be_ the issuer). The following sample code acquires two assets, "TST" (which it buys using XRP) and "FOO" (which it receives from the issuer).
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/create-amm/js/create-amm.js" from="// Acquire tokens" before="// Check if AMM already exists" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
This tutorial includes some example code to issue FOO tokens from a second test address. This is not realistic for a production scenario, because tokens do not inherently have value, but it makes it possible to demonstrate creating a new AMM for a unique currency pair. In production, you would acquire a second token in some other way, such as making an off-ledger deposit with the [stablecoin issuer](../../../use-cases/tokenization/stablecoin-issuer.md), or buying it in the [decentralized exchange](../../../concepts/tokens/decentralized-exchange/index.md).
|
||||
|
||||
The helper function for issuing follows an abbreviated version of the steps in the [Issue a Fungible Token](issue-a-fungible-token.md) tutorial:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/create-amm/js/create-amm.js" from="/* Issue tokens" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
{% interactive-block label="Acquire tokens" steps=$frontmatter.steps %}
|
||||
|
||||
<button id="buy-tst" class="btn btn-primary previous-steps-required">Buy TST</button>
|
||||
<button id="get-foo" class="btn btn-primary previous-steps-required">Get FOO</button>
|
||||
|
||||
{% loading-icon message="Working..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
### 4. Check if the AMM exists
|
||||
|
||||
Since there can only be one AMM for a specific pair of assets, it's best to check first before trying to create one. Use the [amm_info method][] to check whether the AMM already exists. For the request, you specify the two assets. The response should be an `actNotFound` error if the AMM does not exist.
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/create-amm/js/create-amm.js" from="// Check if AMM already exists" before="// Look up AMM transaction cost" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
If the AMM does already exist, you should double-check that you specified the right pair of assets. If someone else has already created this AMM, you can deposit to it instead. <!-- TODO: link to a tutorial about depositing to and withdrawing from an AMM when one exists -->
|
||||
|
||||
{% interactive-block label="Check for AMM" steps=$frontmatter.steps %}
|
||||
|
||||
<button id="check-for-amm" class="btn btn-primary previous-steps-required">Check AMM</button>
|
||||
|
||||
{% loading-icon message="Sending..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
### 5. Look up the AMMCreate transaction cost
|
||||
|
||||
Creating an AMM has a special [transaction cost][] to prevent spam: since it creates objects in the ledger that no one owns, you must burn at least one [owner reserve increment](../../../concepts/accounts/reserves.md) of XRP to send the AMMCreate transaction. The exact value can change due to [fee voting](https://xrpl.org/fee-voting.html), so you should look up the current incremental reserve value using the [server_state method][].
|
||||
|
||||
It is also a good practice to display this value and give a human operator a chance to stop before you send the transaction. Burning an owner reserve is typically a much higher cost than sending a normal transaction, so you don't want it to be a surprise. (Currently, on both Mainnet and Devnet, the cost of sending a typical transaction is 0.000010 XRP but the cost of AMMCreate is 2 XRP.)
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/create-amm/js/create-amm.js" from="// Look up AMM transaction cost" before="// Create AMM" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
{% interactive-block label="Look up AMMCreate cost" steps=$frontmatter.steps %}
|
||||
|
||||
<button id="look-up-ammcreate-cost" class="btn btn-primary previous-steps-required">Check cost</button>
|
||||
|
||||
{% loading-icon message="Sending..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
|
||||
### 6. Send AMMCreate transaction
|
||||
|
||||
Send an [AMMCreate transaction][] to create the AMM. Important aspects of this transaction include:
|
||||
|
||||
| Field | Value | Description |
|
||||
|-------|--------|-------------|
|
||||
| `Asset` | [Currency Amount][] | Starting amount of one asset to deposit in the AMM. |
|
||||
| `Asset2` | [Currency Amount][] | Starting amount of the other asset to deposit in the AMM. |
|
||||
| `TradingFee` | Number | The fee to charge when trading against this AMM instance. The maximum value is `1000`, meaning a 1% fee; the minimum value is `0`. If you set this too high, it may be too expensive for users to trade against the AMM; but the lower you set it, the more you expose yourself to currency risk from the AMM's assets changing in value relative to one another. |
|
||||
| `Fee` | String - XRP Amount | The transaction cost you looked up in a previous step. Client libraries may require that you add a special exception or reconfigure a setting to specify a `Fee` value this high. |
|
||||
|
||||
For the two starting assets, it does not matter which is `Asset` and which is `Asset2`, but you should specify amounts that are about equal in total value, because otherwise other users can profit at your expense by trading against the AMM.
|
||||
|
||||
**Tip:** Use `fail_hard` when submitting this transaction, so you don't have to pay the high transaction cost if the transaction initially fails. (It's still _possible_ that the transaction could tentatively succeed, and then fail and still burn the transaction cost, but this protects you from burning XRP on many of types of failures.)
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/create-amm/js/create-amm.js" from="// Create AMM" before="// Confirm that AMM exists" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
{% interactive-block label="Create AMM" steps=$frontmatter.steps %}
|
||||
|
||||
<form>
|
||||
<div class="form-group row">
|
||||
<label for="trading-fee" class="col-form-label col-sm-3">Trading Fee</label>
|
||||
<div class="input-group col">
|
||||
<input type="number" class="form-control" id="trading-fee" value="0.5" step="0.001" min="0" max="1" />
|
||||
<div class="input-group-append">
|
||||
<div class="input-group-text">%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="asset-amount" class="col-form-label col-sm-3">Amount</label>
|
||||
<div class="input-group col">
|
||||
<input type="number" class="form-control" id="asset-amount" value="15" step="any" min="0" />
|
||||
<div class="input-group-append">
|
||||
<div class="input-group-text">TST.rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="asset2-amount" class="col-form-label col-sm-3">Amount2</label>
|
||||
<div class="input-group col">
|
||||
<input type="number" class="form-control" id="asset2-amount" value="100" step="any" min="0" />
|
||||
<div class="input-group-append">
|
||||
<div class="input-group-text">FOO.<span class="foo-issuer">(issuer)</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<button id="create-amm" class="btn btn-primary previous-steps-required">Create AMM</button>
|
||||
|
||||
{% loading-icon message="Sending..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
### 7. Check AMM info
|
||||
|
||||
If the AMMCreate transaction succeeded, it creates the AMM and related objects in the ledger. You _could_ check the metadata of the AMMCreate transaction, but it is often easier to call the [amm_info method][] again to get the status of the newly-created AMM.
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/create-amm/js/create-amm.js" from="// Confirm that AMM exists" before="// Check token balances" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
In the result, the `amm` object's `lp_token` field is particularly useful because it includes the issuer and currency code of the AMM's LP Tokens, which you need to know for many other AMM-related transactions. LP Tokens always have a hex currency code starting with `03`, and the rest of the code is derived from the issuers and currency codes of the tokens in the AMM's pool. The issuer of the LP Tokens is the AMM address, which is randomly chosen when you create an AMM.
|
||||
|
||||
Initially, the AMM's total outstanding LP Tokens, reported in the `lp_token` field of the `amm_info` response, match the tokens you hold as its first liquidity provider. However, after other accounts deposit liquidity to the same AMM, the amount shown in `amm_info` updates to reflect the total issued to all liquidity providers. Since others can deposit at any time, even potentially in the same ledger version where the AMM was created, you shouldn't assume that this amount represents your personal LP Tokens balance.
|
||||
|
||||
{% interactive-block label="Check AMM info" steps=$frontmatter.steps %}
|
||||
|
||||
<button id="check-amm-info" class="btn btn-primary previous-steps-required">Check AMM</button>
|
||||
|
||||
{% loading-icon message="Sending..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
### 8. Check trust lines
|
||||
|
||||
You can also use the [account_lines method][] to get an updated view of your token balances. Your balances should be decreased by the amounts you deposited, but you now have a balance of LP Tokens that you received from the AMM.
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/create-amm/js/create-amm.js" from="// Check token balances" before="// Disconnect" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
The `account_lines` response shows only the tokens held by the account you looked up (probably yours). If you have a lot of tokens, you may want to specify the AMM address as the `peer` in the request so you don't have to [paginate](../../../references/http-websocket-apis/api-conventions/markers-and-pagination.md) over multiple requests to find the AMM's LP Tokens. In this tutorial, your account probably only holds the three different tokens, so you can see all three in the same response.
|
||||
|
||||
**Tip:** If one of the assets in the AMM's pool is XRP, you need to call the [account_info method][] on your account to see the difference in your balance (the `Balance` field of the account object).
|
||||
|
||||
{% interactive-block label="Check trust lines" steps=$frontmatter.steps %}
|
||||
|
||||
<button id="check-trust-lines" class="btn btn-primary previous-steps-required">Check trust lines</button>
|
||||
|
||||
{% loading-icon message="Sending..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
|
||||
## Next Steps
|
||||
|
||||
At this point the AMM is up and running, and [trades in the DEX](trade-in-the-decentralized-exchange.md) automatically use this AMM in combination with Offers to achieve the best exchange rate possible between the two assets in the AMM's pool. If the flow of funds between the two assets is relatively balanced and there are no major shifts in the value of one asset compared to the other, this can become a source of passive income for you and anyone else who deposits liquidity into the AMM's pool.
|
||||
|
||||
When you want to withdraw liquidity from the AMM, you can use [AMMDeposit][] to cash in your LP Tokens to receive a share of the AMM's assets. You can also use LP Tokens like any other tokens in the XRP Ledger, which means you can trade them, use them in payments, or even deposit them in another AMM.
|
||||
|
||||
However, you should keep an eye on market conditions, and use tools like [AMMBid][] and [AMMVote][] to insulate yourself from losses due to changes in the relative value of the two assets in the pool.
|
||||
|
||||
{% raw-partial file="/docs/_snippets/common-links.md" /%}
|
||||
202
docs/tutorials/tasks/use-tokens/enable-no-freeze.md
Normal file
202
docs/tutorials/tasks/use-tokens/enable-no-freeze.md
Normal file
@@ -0,0 +1,202 @@
|
||||
---
|
||||
html: enable-no-freeze.html
|
||||
parent: use-tokens.html
|
||||
seo:
|
||||
description: Permanently give up your account's ability to freeze tokens it issues.
|
||||
embed_xrpl_js: true
|
||||
filters:
|
||||
- interactive_steps
|
||||
labels:
|
||||
- Tokens
|
||||
steps: ['Generate', 'Connect', 'Send AccountSet', 'Wait', 'Confirm Settings']
|
||||
---
|
||||
# Enable No Freeze
|
||||
|
||||
If you [issue tokens](../../../concepts/tokens/index.md) in the XRP Ledger, can enable the [No Freeze setting](../../../concepts/tokens/fungible-tokens/freezes.md#no-freeze) to permanently limit your own ability to use the token freezing features of the XRP Ledger. (As a reminder, this only applies to issued tokens, not XRP.) This tutorial shows how to enable the No Freeze setting on your issuing account.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- You need a connection to the XRP Ledger network. As shown in this tutorial, you can use public servers for testing.
|
||||
- You should be familiar with the Getting Started instructions for your preferred client library. This page provides examples for the following:
|
||||
- **JavaScript** with the [xrpl.js library](https://github.com/XRPLF/xrpl.js/). See [Get Started Using JavaScript](../../javascript/get-started.md) for setup steps.
|
||||
- You don't need to have [issued a token](issue-a-fungible-token.md) in the XRP Ledger to enable No Freeze, but the main reason you would do so is if you intend to or have already issued such a token.
|
||||
|
||||
<!-- Source for this specific tutorial's interactive bits: -->
|
||||
<script type="application/javascript" src="/js/interactive-tutorial.js"></script>
|
||||
<script type="application/javascript" src="/js/tutorials/enable-no-freeze.js"></script>
|
||||
|
||||
|
||||
## Example Code
|
||||
|
||||
Complete sample code for all of the steps of this tutorial is available under the [MIT license](https://github.com/XRPLF/xrpl-dev-portal/blob/master/LICENSE).
|
||||
|
||||
- See [Code Samples: Freeze](https://github.com/XRPLF/xrpl-dev-portal/tree/master/_code-samples/freeze/) in the source repository for this website.
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Get Credentials
|
||||
|
||||
To transact on the XRP Ledger, you need an address and secret key, and some XRP. If you use the best practice of having separate ["cold" and "hot" addresses](../../../concepts/accounts/account-types.md), you need the **master keys** to the _cold address_, which is the **issuer** of the token. Only the issuer's No Freeze setting has any effect on a token.
|
||||
|
||||
**Caution:** You cannot use a [regular key pair](../../../concepts/accounts/cryptographic-keys.md) or [multi-signing](../../../concepts/accounts/multi-signing.md) to enable the No Freeze setting.
|
||||
|
||||
For this tutorial, you can get credentials from the following interface:
|
||||
|
||||
{% partial file="/docs/_snippets/interactive-tutorials/generate-step.md" /%}
|
||||
|
||||
When you're building production-ready software, you should use an existing account, and manage your keys using a [secure signing configuration](../../../concepts/transactions/secure-signing.md).
|
||||
|
||||
|
||||
### 2. Connect to the Network
|
||||
|
||||
You must be connected to the network to submit transactions to it. The following code shows how to connect to a public XRP Ledger Testnet server a supported [client library](../../../references/client-libraries.md):
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/get-started/js/base.js" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
For this tutorial, click the following button to connect:
|
||||
|
||||
{% partial file="/docs/_snippets/interactive-tutorials/connect-step.md" /%}
|
||||
|
||||
|
||||
### 3. Send AccountSet Transaction
|
||||
|
||||
To enable the No Freeze setting, send an [AccountSet transaction][] with a `SetFlag` field containing the [`asfNoFreeze` value (`6`)](../../../references/protocol/transactions/types/accountset.md#accountset-flags). To send the transaction, you first _prepare_ it to fill out all the necessary fields, then _sign_ it with your account's secret key, and finally _submit_ it to the network.
|
||||
|
||||
For example:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/freeze/js/set-no-freeze.js" from="// Submit an AccountSet transaction" before="// Done" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="WebSocket" %}
|
||||
```json
|
||||
{
|
||||
"id": 12,
|
||||
"command": "submit",
|
||||
"tx_json": {
|
||||
"TransactionType": "AccountSet",
|
||||
"Account": "raKEEVSGnKSD9Zyvxu4z6Pqpm4ABH8FS6n",
|
||||
"Fee": "12",
|
||||
"Flags": 0,
|
||||
"SetFlag": 6,
|
||||
"LastLedgerSequence": 18124917,
|
||||
"Sequence": 4
|
||||
},
|
||||
"secret": "s████████████████████████████"
|
||||
}
|
||||
```
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
|
||||
{% interactive-block label="Send AccountSet" steps=$frontmatter.steps %}
|
||||
|
||||
<button id="send-accountset" class="btn btn-primary previous-steps-required" data-wait-step-name="Wait">Send AccountSet</button>
|
||||
|
||||
{% loading-icon message="Sending" /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
|
||||
|
||||
### 4. Wait for Validation
|
||||
|
||||
Most transactions are accepted into the next ledger version after they're submitted, which means it may take 4-7 seconds for a transaction's outcome to be final. If the XRP Ledger is busy or poor network connectivity delays a transaction from being relayed throughout the network, a transaction may take longer to be confirmed. (For information on how to set an expiration for transactions, see [Reliable Transaction Submission](../../../concepts/transactions/reliable-transaction-submission.md).)
|
||||
|
||||
{% partial file="/docs/_snippets/interactive-tutorials/wait-step.md" /%}
|
||||
|
||||
|
||||
### 5. Confirm Account Settings
|
||||
|
||||
After the transaction is validated, you can check your account's settings to confirm that the No Freeze flag is enabled. You can do this by calling the [account_info method][] and checking the value of the account's `Flags` field to see if the [`lsfNoFreeze` bit (`0x00200000`)](../../../references/protocol/ledger-data/ledger-entry-types/accountroot.md#accountroot-flags) is enabled.
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/freeze/js/check-no-freeze.js" from="// Request account info" before="await client.disconnect()" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="WebSocket" %}
|
||||
```json
|
||||
Request:
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"command": "account_info",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated"
|
||||
}
|
||||
|
||||
Response:
|
||||
|
||||
{
|
||||
"id": 4,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"account_data": {
|
||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"AccountTxnID": "41320138CA9837B34E82B3B3D6FB1E581D5DE2F0A67B3D62B5B8A8C9C8D970D0",
|
||||
"Balance": "100258663",
|
||||
"Domain": "6D64756F31332E636F6D",
|
||||
"EmailHash": "98B4375E1D753E5B91627516F6D70977",
|
||||
"Flags": 12582912,
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"MessageKey": "0000000000000000000000070000000300",
|
||||
"OwnerCount": 4,
|
||||
"PreviousTxnID": "41320138CA9837B34E82B3B3D6FB1E581D5DE2F0A67B3D62B5B8A8C9C8D970D0",
|
||||
"PreviousTxnLgrSeq": 18123095,
|
||||
"Sequence": 352,
|
||||
"TransferRate": 1004999999,
|
||||
"index": "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8",
|
||||
"urlgravatar": "http://www.gravatar.com/avatar/98b4375e1d753e5b91627516f6d70977"
|
||||
},
|
||||
"ledger_hash": "A777B05A293A73E511669B8A4A45A298FF89AD9C9394430023008DB4A6E7FDD5",
|
||||
"ledger_index": 18123249,
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
```
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
{% interactive-block label="Confirm Settings" steps=$frontmatter.steps %}
|
||||
|
||||
<button id="confirm-settings" class="btn btn-primary previous-steps-required" data-wait-step-name="Wait">Confirm Settings</button>
|
||||
|
||||
{% loading-icon message="Sending" /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
|
||||
## See Also
|
||||
|
||||
- **Concepts:**
|
||||
- [Freezing Issued Currencies](../../../concepts/tokens/fungible-tokens/freezes.md)
|
||||
- [Trust Lines](../../../concepts/tokens/fungible-tokens/index.md)
|
||||
- **Tutorials:**
|
||||
- [Enact Global Freeze](enact-global-freeze.md)
|
||||
- [Freeze a Trust Line](freeze-a-trust-line.md)
|
||||
- **References:**
|
||||
- [account_lines method][]
|
||||
- [account_info method][]
|
||||
- [AccountSet transaction][]
|
||||
- [TrustSet transaction][]
|
||||
- [AccountRoot Flags](../../../references/protocol/ledger-data/ledger-entry-types/accountroot.md#accountroot-flags)
|
||||
- [RippleState (trust line) Flags](../../../references/protocol/ledger-data/ledger-entry-types/ripplestate.md#ripplestate-flags)
|
||||
|
||||
{% raw-partial file="/docs/_snippets/common-links.md" /%}
|
||||
288
docs/tutorials/tasks/use-tokens/enact-global-freeze.md
Normal file
288
docs/tutorials/tasks/use-tokens/enact-global-freeze.md
Normal file
@@ -0,0 +1,288 @@
|
||||
---
|
||||
html: enact-global-freeze.html
|
||||
parent: use-tokens.html
|
||||
seo:
|
||||
description: Freeze all tokens issued by your address.
|
||||
embed_xrpl_js: true
|
||||
filters:
|
||||
- interactive_steps
|
||||
labels:
|
||||
- Tokens
|
||||
- Security
|
||||
steps: ['Generate', 'Connect', 'Send AccountSet (Start Freeze)', 'Wait', 'Confirm Settings', 'Send AccountSet (End Freeze)', 'Wait (again)', 'Confirm Settings (After Freeze)']
|
||||
---
|
||||
# Enact Global Freeze
|
||||
|
||||
If you [issue tokens](../../../concepts/tokens/index.md) in the XRP Ledger, can enact a [Global Freeze](../../../concepts/tokens/fungible-tokens/freezes.md#global-freeze) to prevent users from sending your tokens to each other and trading your token in the [decentralized exchange](../../../concepts/tokens/decentralized-exchange/index.md). This tutorial shows how to enact and end a Global Freeze. You might want to do this, for example, if you see signs of suspicious activity related to your issuing address in the ledger, or to off-ledger systems you use to manage your token. (For example, if your token is a stablecoin and you process withdrawals and deposits from the ledger, you may want to freeze your token while you investigate if you suspect your systems have been hacked.) You can later disable the Global Freeze setting unless you have also enabled the [No Freeze setting](../../../concepts/tokens/fungible-tokens/freezes.md#no-freeze).
|
||||
|
||||
**Tip:** As a reminder, freezes only apply to issued tokens, not XRP, and do not prevent users from sending the tokens _directly_ back to the issuer.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- You need a connection to the XRP Ledger network. As shown in this tutorial, you can use public servers for testing.
|
||||
- You should be familiar with the Getting Started instructions for your preferred client library. This page provides examples for the following:
|
||||
- **JavaScript** with the [xrpl.js library](https://github.com/XRPLF/xrpl.js/). See [Get Started Using JavaScript](../../javascript/get-started.md) for setup steps.
|
||||
- You don't need to have [issued a token](issue-a-fungible-token.md) in the XRP Ledger to enact a Global Freeze, but the main reason you would do so is if you have already issued such a token.
|
||||
|
||||
<!-- Source for this specific tutorial's interactive bits: -->
|
||||
<script type="application/javascript" src="/js/interactive-tutorial.js"></script>
|
||||
<script type="application/javascript" src="/js/tutorials/enact-global-freeze.js"></script>
|
||||
|
||||
## Example Code
|
||||
|
||||
Complete sample code for all of the steps of this tutorial is available under the [MIT license](https://github.com/XRPLF/xrpl-dev-portal/blob/master/LICENSE).
|
||||
|
||||
- See [Code Samples: Freeze](https://github.com/XRPLF/xrpl-dev-portal/tree/master/_code-samples/freeze/) in the source repository for this website.
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Get Credentials
|
||||
|
||||
To transact on the XRP Ledger, you need an address and secret key, and some XRP. If you use the best practice of having separate ["cold" and "hot" addresses](../../../concepts/accounts/account-types.md), you need the keys to the _cold address_, which is the **issuer** of the token. Only the issuer's Global Freeze setting has any effect on a token.
|
||||
|
||||
**Tip:** Unlike the No Freeze setting, you _can_ enable and disable a Global Freeze using a [regular key pair](../../../concepts/accounts/cryptographic-keys.md) or [multi-signing](../../../concepts/accounts/multi-signing.md).
|
||||
|
||||
For this tutorial, you can get credentials from the following interface:
|
||||
|
||||
{% partial file="/docs/_snippets/interactive-tutorials/generate-step.md" /%}
|
||||
|
||||
When you're building production-ready software, you should use an existing account, and manage your keys using a [secure signing configuration](../../../concepts/transactions/secure-signing.md).
|
||||
|
||||
|
||||
### 2. Connect to the Network
|
||||
|
||||
You must be connected to the network to submit transactions to it. The following code shows how to connect to a public XRP Ledger Testnet server a supported [client library](../../../references/client-libraries.md):
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/get-started/js/base.js" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
For this tutorial, click the following button to connect:
|
||||
|
||||
{% partial file="/docs/_snippets/interactive-tutorials/connect-step.md" /%}
|
||||
|
||||
|
||||
### 3. Send AccountSet Transaction to Start the Freeze
|
||||
|
||||
To enable the Global Freeze setting, send an [AccountSet transaction][] with a `SetFlag` field containing the [`asfGlobalFreeze` value (`7`)](../../../references/protocol/transactions/types/accountset.md#accountset-flags). To send the transaction, you first _prepare_ it to fill out all the necessary fields, then _sign_ it with your account's secret key, and finally _submit_ it to the network.
|
||||
|
||||
**Caution:** Enacting a global freeze affects _all tokens issued by the address._ Furthermore, if you use the No Freeze setting, you cannot undo this action.
|
||||
|
||||
For example:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/freeze/js/set-global-freeze.js" from="// Prepare an AccountSet" before="// Investigate" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="WebSocket" %}
|
||||
```json
|
||||
{
|
||||
"id": "example_enable_global_freeze",
|
||||
"command": "submit",
|
||||
"tx_json": {
|
||||
"TransactionType": "AccountSet",
|
||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"Fee": "12",
|
||||
"Flags": 0,
|
||||
"SetFlag": 7,
|
||||
"LastLedgerSequence": 18122753,
|
||||
"Sequence": 349
|
||||
},
|
||||
"secret": "s████████████████████████████"
|
||||
}
|
||||
```
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
{% interactive-block label="Send AccountSet (Start Freeze)" steps=$frontmatter.steps %}
|
||||
|
||||
<button class="btn btn-primary previous-steps-required send-accountset" data-wait-step-name="Wait" data-action="start_freeze">Send AccountSet</button>
|
||||
|
||||
{% loading-icon message="Sending..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
|
||||
### 4. Wait for Validation
|
||||
|
||||
Most transactions are accepted into the next ledger version after they're submitted, which means it may take 4-7 seconds for a transaction's outcome to be final. If the XRP Ledger is busy or poor network connectivity delays a transaction from being relayed throughout the network, a transaction may take longer to be confirmed. (For information on how to set an expiration for transactions, see [Reliable Transaction Submission](../../../concepts/transactions/reliable-transaction-submission.md).)
|
||||
|
||||
{% interactive-block label="Wait" steps=$frontmatter.steps %}
|
||||
|
||||
{% partial file="/docs/_snippets/interactive-tutorials/wait-step.md" /%}
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
|
||||
### 5. Confirm Account Settings
|
||||
|
||||
After the transaction is validated, you can check your issuing account's settings to confirm that the Global Freeze flag is enabled. You can do this by calling the [account_info method][] and checking the value of the account's `Flags` field to see if the [`lsfGlobalFreeze` bit (`0x00400000`)](../../../references/protocol/ledger-data/ledger-entry-types/accountroot.md#accountroot-flags) is on.
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/freeze/js/check-global-freeze.js" from="// Request account info" before="await client.disconnect()" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="WebSocket" %}
|
||||
```json
|
||||
Request:
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"command": "account_info",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated"
|
||||
}
|
||||
|
||||
Response:
|
||||
|
||||
{
|
||||
"id": 4,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"account_data": {
|
||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"AccountTxnID": "41320138CA9837B34E82B3B3D6FB1E581D5DE2F0A67B3D62B5B8A8C9C8D970D0",
|
||||
"Balance": "100258663",
|
||||
"Domain": "6D64756F31332E636F6D",
|
||||
"EmailHash": "98B4375E1D753E5B91627516F6D70977",
|
||||
"Flags": 12582912,
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"MessageKey": "0000000000000000000000070000000300",
|
||||
"OwnerCount": 4,
|
||||
"PreviousTxnID": "41320138CA9837B34E82B3B3D6FB1E581D5DE2F0A67B3D62B5B8A8C9C8D970D0",
|
||||
"PreviousTxnLgrSeq": 18123095,
|
||||
"Sequence": 352,
|
||||
"TransferRate": 1004999999,
|
||||
"index": "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8",
|
||||
"urlgravatar": "http://www.gravatar.com/avatar/98b4375e1d753e5b91627516f6d70977"
|
||||
},
|
||||
"ledger_hash": "A777B05A293A73E511669B8A4A45A298FF89AD9C9394430023008DB4A6E7FDD5",
|
||||
"ledger_index": 18123249,
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
```
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
{% interactive-block label="Confirm Settings" steps=$frontmatter.steps %}
|
||||
|
||||
<button id="confirm-settings" class="btn btn-primary previous-steps-required">Confirm Settings</button>
|
||||
|
||||
{% loading-icon message="Sending..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
|
||||
### Intermission: While Frozen
|
||||
|
||||
At this point all token issued by your address are frozen. During this time, you may want to investigate the potential security breach or take a snapshot of the balances of your token, depending on your reasons for enacting the global freeze.
|
||||
|
||||
Keep in mind that while a token is frozen, it is still possible for the frozen token to be sent _directly to_ or _directly from_ the issuer, so you may still want to disable any systems you have that are configured to send such transactions, and you may want to track incoming transactions without processing them so that you can eventually process the legitimate ones.
|
||||
|
||||
If you use a [hot wallet or operational address](../../../concepts/accounts/account-types.md), it has no special status compared to other users, so it also cannot send and receive the frozen tokens except when dealing directly with the issuer. <!-- STYLE_OVERRIDE: wallet, hot wallet -->
|
||||
|
||||
If you use the [No Freeze setting](../../../concepts/tokens/fungible-tokens/freezes.md#no-freeze) then the Global Freeze continues forever. If you want to resume issuing tokens, you must create a new account and start over from there.
|
||||
|
||||
Otherwise, you can continue to the next step whenever you're ready.
|
||||
|
||||
|
||||
### 6. Send AccountSet Transaction to End the Freeze
|
||||
|
||||
To end the Global Freeze, send an [AccountSet transaction][] with a `ClearFlag` field containing the [`asfGlobalFreeze` value (`7`)](../../../references/protocol/transactions/types/accountset.md#accountset-flags). As always, you first _prepare_ the transaction, _sign_ it, and finally _submit_ it to the network.
|
||||
|
||||
For example:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/freeze/js/set-global-freeze.js" from="// Now we disable" before="// Global freeze disabled" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="WebSocket" %}
|
||||
```json
|
||||
{
|
||||
"id": "example_disable_global_freeze",
|
||||
"command": "submit",
|
||||
"tx_json": {
|
||||
"TransactionType": "AccountSet",
|
||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"Fee": "12",
|
||||
"Flags": 0,
|
||||
"ClearFlag": 7,
|
||||
"LastLedgerSequence": 18122788,
|
||||
"Sequence": 350
|
||||
},
|
||||
"secret": "s████████████████████████████"
|
||||
}
|
||||
```
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
{% interactive-block label="Send AccountSet (End Freeze)" steps=$frontmatter.steps %}
|
||||
|
||||
<button class="btn btn-primary previous-steps-required send-accountset" data-wait-step-name="Wait (again)" data-action="end_freeze">Send AccountSet (end the freeze)</button>
|
||||
|
||||
{% loading-icon message="Sending..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
|
||||
### 7. Wait for Validation
|
||||
|
||||
As before, wait for the previous transaction to be validated by consensus before continuing.
|
||||
|
||||
{% partial file="/docs/_snippets/interactive-tutorials/wait-step.md" variables={label: "Wait (again)"} /%}
|
||||
|
||||
|
||||
### 8. Confirm Account Settings
|
||||
|
||||
After the transaction is validated, you can confirm the status of the Global Freeze flag in the same way as before: by calling the [account_info method][] and checking the value of the account's `Flags` field to see if the [`lsfGlobalFreeze` bit (`0x00400000`)](../../../references/protocol/ledger-data/ledger-entry-types/accountroot.md#accountroot-flags) is **off**.
|
||||
|
||||
{% interactive-block label="Confirm Settings (After Freeze)" steps=$frontmatter.steps %}
|
||||
|
||||
<button id="confirm-settings-end" class="btn btn-primary previous-steps-required">Confirm Settings (After Freeze)</button>
|
||||
|
||||
{% loading-icon message="Sending..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
|
||||
## See Also
|
||||
|
||||
- **Concepts:**
|
||||
- [Freezing Issued Currencies](../../../concepts/tokens/fungible-tokens/freezes.md)
|
||||
- [Trust Lines](../../../concepts/tokens/fungible-tokens/index.md)
|
||||
- **Tutorials:**
|
||||
- [Enable No Freeze](enable-no-freeze.md)
|
||||
- [Freeze a Trust Line](freeze-a-trust-line.md)
|
||||
- [Change or Remove a Regular Key Pair](../manage-account-settings/change-or-remove-a-regular-key-pair.md)
|
||||
- **References:**
|
||||
- [account_lines method][]
|
||||
- [account_info method][]
|
||||
- [AccountSet transaction][]
|
||||
- [TrustSet transaction][]
|
||||
- [AccountRoot Flags](../../../references/protocol/ledger-data/ledger-entry-types/accountroot.md#accountroot-flags)
|
||||
- [RippleState (trust line) Flags](../../../references/protocol/ledger-data/ledger-entry-types/ripplestate.md#ripplestate-flags)
|
||||
|
||||
{% raw-partial file="/docs/_snippets/common-links.md" /%}
|
||||
359
docs/tutorials/tasks/use-tokens/freeze-a-trust-line.md
Normal file
359
docs/tutorials/tasks/use-tokens/freeze-a-trust-line.md
Normal file
@@ -0,0 +1,359 @@
|
||||
---
|
||||
html: freeze-a-trust-line.html
|
||||
parent: use-tokens.html
|
||||
seo:
|
||||
description: Freeze an individual holder of a token.
|
||||
embed_xrpl_js: true
|
||||
filters:
|
||||
- interactive_steps
|
||||
labels:
|
||||
- Tokens
|
||||
- Security
|
||||
steps: ['Generate', 'Connect', 'Choose Trust Line', 'Send TrustSet to Freeze', 'Wait', 'Check Freeze Status', 'Send TrustSet to End Freeze', 'Wait (again)']
|
||||
---
|
||||
# Freeze a Trust Line
|
||||
|
||||
This tutorial shows the steps to [freeze an individual trust line](../../../concepts/tokens/fungible-tokens/freezes.md#individual-freeze). The issuer of a token in the XRP Ledger may freeze the trust line to a particular counterparty if that account is engaged in suspicious activity.
|
||||
|
||||
**Tip:** As a reminder, freezes only apply to issued tokens, not XRP.
|
||||
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- You need a connection to the XRP Ledger network. As shown in this tutorial, you can use public servers for testing.
|
||||
- You should be familiar with the Getting Started instructions for your preferred client library. This page provides examples for the following:
|
||||
- **JavaScript** with the [xrpl.js library](https://github.com/XRPLF/xrpl.js/). See [Get Started Using JavaScript](../../javascript/get-started.md) for setup steps.
|
||||
- This tutorial assumes **you have already [issued a token](issue-a-fungible-token.md)** in the XRP Ledger.
|
||||
- You **cannot** have enabled the [No Freeze setting](../../../concepts/tokens/fungible-tokens/freezes.md#no-freeze), which gives up your ability to freeze individual trust lines.
|
||||
|
||||
<!-- Source for this specific tutorial's interactive bits: -->
|
||||
<script type="application/javascript" src="/js/interactive-tutorial.js"></script>
|
||||
<script type="application/javascript" src="/js/tutorials/freeze-individual-line.js"></script>
|
||||
|
||||
|
||||
## Example Code
|
||||
|
||||
Complete sample code for all of the steps of this tutorial is available under the [MIT license](https://github.com/XRPLF/xrpl-dev-portal/blob/master/LICENSE).
|
||||
|
||||
- See [Code Samples: Freeze](https://github.com/XRPLF/xrpl-dev-portal/tree/master/_code-samples/freeze/) in the source repository for this website.
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Get Credentials
|
||||
|
||||
To transact on the XRP Ledger, you need an address and secret key, and some XRP. If you use the best practice of having separate ["cold" and "hot" addresses](../../../concepts/accounts/account-types.md), you need the keys to the _cold address_, which is the **issuer** of the token.
|
||||
|
||||
{% partial file="/docs/_snippets/interactive-tutorials/generate-step.md" /%}
|
||||
|
||||
### 2. Connect to the Network
|
||||
|
||||
You must be connected to the network to submit transactions to it. The following code shows how to connect to a public XRP Ledger Testnet server a supported [client library](/docs/references/client-libraries.md):
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/get-started/js/base.js" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="WebSocket" %}
|
||||
```
|
||||
(Connect to wss:// URL of an XRP Ledger server using your preferred client.)
|
||||
```
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
For purposes of this tutorial, use the following interface to connect and perform setup:
|
||||
|
||||
{% partial file="/docs/_snippets/interactive-tutorials/connect-step.md" /%}
|
||||
|
||||
|
||||
### 3. Choose Trust Line
|
||||
|
||||
You can only freeze one trust line per transaction, so you need to know which trust line you want. Each of your trust lines is uniquely identified by these 3 things:
|
||||
|
||||
- Your own address.
|
||||
- The address of the account linked to yours via the trust line.
|
||||
- The currency code of the trust line.
|
||||
|
||||
There can be multiple [trust lines](../../../concepts/tokens/fungible-tokens/index.md) between two accounts, each for a different currency. If you suspect a particular account is behaving maliciously, you may want to freeze all the trust lines between your accounts, one at a time. Use the [account_lines method][] with a pair of accounts to find all trust lines between those accounts, then choose a trust line to freeze from among the results. For example:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/freeze/js/set-individual-freeze.js" from="// Look up current trust lines" before="// Send a TrustSet" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="WebSocket" %}
|
||||
```json
|
||||
Example Request:
|
||||
|
||||
{
|
||||
"id": "example_look_up_trust_lines",
|
||||
"command": "account_lines",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"peer": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
|
||||
"ledger_index": "validated"
|
||||
}
|
||||
|
||||
// Example Response:
|
||||
|
||||
{
|
||||
"id": "example_look_up_trust_lines",
|
||||
"result": {
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_hash": "AF5C6E6FBC44183D8662C7F5BF88D52F99738A0E66FF07FC7B5A516AC8EA1B37",
|
||||
"ledger_index": 67268474,
|
||||
"lines": [
|
||||
{
|
||||
"account": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
|
||||
"balance": "0",
|
||||
"currency": "USD",
|
||||
"limit": "0",
|
||||
"limit_peer": "110",
|
||||
"quality_in": 0,
|
||||
"quality_out": 0
|
||||
}
|
||||
],
|
||||
"validated": true
|
||||
},
|
||||
"status": "success",
|
||||
"type": "response"
|
||||
}
|
||||
```
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
For purposes of this tutorial, a second test address has created a trust line to the test address for the currency "FOO", which you can see in the following example:
|
||||
|
||||
{% interactive-block label="Choose Trust Line" steps=$frontmatter.steps %}
|
||||
|
||||
<div class="loader collapse" id="trust-line-setup-loader"><img class="throbber" src="/img/xrp-loader-96.png">Waiting for setup to complete...</div>
|
||||
<input type="hidden" id="peer-seed" value="" />
|
||||
<button id="look-up-trust-lines" class="btn btn-primary" disabled="disabled" title="Wait for setup to complete...">Choose Trust Line</button>
|
||||
<div class="loader loader-looking collapse"><img class="throbber" src="/img/xrp-loader-96.png">Looking...</div>
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
|
||||
### 4. Send TrustSet Transaction to Freeze the Trust Line
|
||||
|
||||
To enable or disable an Individual Freeze on a specific trust line, send a [TrustSet transaction][] with the [`tfSetFreeze` flag enabled](../../../references/protocol/transactions/types/trustset.md#trustset-flags). The fields of the transaction should be as follows:
|
||||
|
||||
| Field | Value | Description |
|
||||
|--------------------------|--------|-------------|
|
||||
| `Account` | String | Your issuing account's address. |
|
||||
| `TransactionType` | String | `TrustSet` |
|
||||
| `LimitAmount` | Object | Object defining the trust line to freeze. |
|
||||
| `LimitAmount`.`currency` | String | Currency of the trust line (cannot be XRP) |
|
||||
| `LimitAmount`.`issuer` | String | The XRP Ledger address of the counterparty to freeze |
|
||||
| `LimitAmount`.`value` | String | The amount of currency you trust this counterparty to issue to you, as a quoted number. As an issuer, this is typically `"0"`. |
|
||||
| `Flags` | Number | To enable a freeze, turn on the `tfSetFreeze` bit (`0x00100000`). |
|
||||
|
||||
As always, to send a transaction, you _prepare_ it by filling in all the necessary fields, _sign_ it with your cryptographic keys, and _submit_ it to the network. For example:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/freeze/js/set-individual-freeze.js" from="// Send a TrustSet" before="// Investigate" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="WebSocket" %}
|
||||
```json
|
||||
{
|
||||
"id": "example_freeze_individual_line",
|
||||
"command": "submit",
|
||||
"tx_json": {
|
||||
"TransactionType": "TrustSet",
|
||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"Fee": "12",
|
||||
"Flags": 1048576,
|
||||
"LastLedgerSequence": 18103014,
|
||||
"LimitAmount": {
|
||||
"currency": "USD",
|
||||
"issuer": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
|
||||
"value": "0"
|
||||
},
|
||||
"Sequence": 340
|
||||
},
|
||||
"secret": "s████████████████████████████"
|
||||
}
|
||||
```
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
{% interactive-block label="Send TrustSet to Freeze" steps=$frontmatter.steps %}
|
||||
|
||||
<button class="btn btn-primary previous-steps-required send-trustset" data-wait-step-name="Wait" data-action="start_freeze">Send TrustSet (Freeze)</button>
|
||||
|
||||
{% loading-icon message="Sending..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
**Note:** If you want to freeze multiple trust lines in different currencies with the same counterparty, repeat this step for each trust line. It is possible to send several transactions in a single ledger if you use a different [sequence number](../../../references/protocol/data-types/basic-data-types.md#account-sequence) for each transaction. <!--{# TODO: link rapid/batch submission guidelines when https://github.com/XRPLF/xrpl-dev-portal/issues/1025 is done #}-->
|
||||
|
||||
|
||||
### 5. Wait for Validation
|
||||
|
||||
Most transactions are accepted into the next ledger version after they're submitted, which means it may take 4-7 seconds for a transaction's outcome to be final. If the XRP Ledger is busy or poor network connectivity delays a transaction from being relayed throughout the network, a transaction may take longer to be confirmed. (For information on how to set an expiration for transactions, see [Reliable Transaction Submission](../../../concepts/transactions/reliable-transaction-submission.md).)
|
||||
|
||||
{% partial file="/docs/_snippets/interactive-tutorials/wait-step.md" /%}
|
||||
|
||||
### 6. Check Trust Line Freeze Status
|
||||
|
||||
At this point, the trust line from the counterparty should be frozen. You can check the freeze status of any trust line using the [account_lines method][] with the following fields:
|
||||
|
||||
| Field | Value | Description |
|
||||
|:----------|:-------|:---------------------------------------------------|
|
||||
| `account` | String | Your address. (In this case, the issuing address.) |
|
||||
| `peer` | String | The address of the counterparty. |
|
||||
|
||||
**Caution:** The response includes _all_ trust lines between the two accounts. (Each different currency code uses a different trust line.) Be sure to check the one for the right token.
|
||||
|
||||
In the response, the field `"freeze": true` indicates that the account from the request has enabled an Individual Freeze on that trust line. The field `"freeze_peer": true` indicates that the counterparty (`peer`) from the request has frozen the trust line. For example:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/freeze/js/set-individual-freeze.js" from="// Confirm trust line status" before="// Investigate" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="WebSocket" %}
|
||||
```json
|
||||
Example Request:
|
||||
|
||||
{
|
||||
"id": "example_check_individual_freeze",
|
||||
"command": "account_lines",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"peer": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW"
|
||||
}
|
||||
|
||||
Example Response:
|
||||
|
||||
{
|
||||
"id": "example_check_individual_freeze",
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"lines": [
|
||||
{
|
||||
"account": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
|
||||
"balance": "10",
|
||||
"currency": "USD",
|
||||
"freeze": true,
|
||||
"limit": "0",
|
||||
"limit_peer": "110",
|
||||
"quality_in": 0,
|
||||
"quality_out": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
{% interactive-block label="Check Freeze Status" steps=$frontmatter.steps %}
|
||||
|
||||
<button id="confirm-settings" class="btn btn-primary previous-steps-required">Check Trust Line</button>
|
||||
|
||||
{% loading-icon message="Checking..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
|
||||
### 7. (Optional) Send TrustSet Transaction to End the Freeze
|
||||
|
||||
If you decide that the trust line no longer needs to be frozen (for example, you investigated and decided that the suspicious activity was benign), you can end the individual freeze in almost the same way that you froze the trust line in the first place. To end an individual freeze, send a [TrustSet transaction][] with the [`tfClearFreeze` flag enabled](../../../references/protocol/transactions/types/trustset.md#trustset-flags). The other fields of the transaction should be the same as when you froze the trust line:
|
||||
|
||||
| Field | Value | Description |
|
||||
|--------------------------|--------|-------------|
|
||||
| `Account` | String | Your issuing account's address. |
|
||||
| `TransactionType` | String | `TrustSet` |
|
||||
| `LimitAmount` | Object | Object defining the trust line to unfreeze. |
|
||||
| `LimitAmount`.`currency` | String | Currency of the trust line (cannot be XRP) |
|
||||
| `LimitAmount`.`issuer` | String | The XRP Ledger address of the counterparty to unfreeze |
|
||||
| `LimitAmount`.`value` | String | The amount of currency you trust this counterparty to issue to you, as a quoted number. As an issuer, this is typically `"0"`. |
|
||||
| `Flags` | Number | To end an individual freeze, turn on the `tfClearFreeze` bit (`0x00200000`) |
|
||||
|
||||
As always, to send a transaction, you _prepare_ it by filling in all the necessary fields, _sign_ it with your cryptographic keys, and _submit_ it to the network. For example:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/freeze/js/set-individual-freeze.js" from="// Clear the individual" before="// End main" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="WebSocket" %}
|
||||
```json
|
||||
{
|
||||
"id": "example_end_individual_freeze",
|
||||
"command": "submit",
|
||||
"tx_json": {
|
||||
"TransactionType": "TrustSet",
|
||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"Fee": "12",
|
||||
"Flags": 2097152,
|
||||
"LastLedgerSequence": 18105115,
|
||||
"LimitAmount": {
|
||||
"currency": "USD",
|
||||
"issuer": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
|
||||
"value": "0"
|
||||
},
|
||||
"Sequence": 341
|
||||
},
|
||||
"secret": "s████████████████████████████"
|
||||
}
|
||||
```
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
{% interactive-block label="Send TrustSet to End Freeze" steps=$frontmatter.steps %}
|
||||
|
||||
<button class="btn btn-primary previous-steps-required send-trustset" data-wait-step-name="Wait (again)" data-action="end_freeze">Send TrustSet (End Freeze)</button>
|
||||
|
||||
{% loading-icon message="Sending..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
|
||||
### 8. Wait for Validation
|
||||
|
||||
As before, wait for the transaction to be validated by consensus.
|
||||
|
||||
{% partial file="/docs/_snippets/interactive-tutorials/wait-step.md" variables={label: "Wait (again)"} /%}
|
||||
|
||||
|
||||
|
||||
## See Also
|
||||
|
||||
- **Concepts:**
|
||||
- [Freezing Issued Currencies](../../../concepts/tokens/fungible-tokens/freezes.md)
|
||||
- [Trust Lines](../../../concepts/tokens/fungible-tokens/index.md)
|
||||
- **Tutorials:**
|
||||
- [Enable No Freeze](enable-no-freeze.md)
|
||||
- [Enact Global Freeze](enact-global-freeze.md)
|
||||
- [Change or Remove a Regular Key Pair](../manage-account-settings/change-or-remove-a-regular-key-pair.md)
|
||||
- **References:**
|
||||
- [account_lines method][]
|
||||
- [account_info method][]
|
||||
- [AccountSet transaction][]
|
||||
- [TrustSet transaction][]
|
||||
- [AccountRoot Flags](../../../references/protocol/ledger-data/ledger-entry-types/accountroot.md#accountroot-flags)
|
||||
- [RippleState (trust line) Flags](../../../references/protocol/ledger-data/ledger-entry-types/ripplestate.md#ripplestate-flags)
|
||||
|
||||
{% raw-partial file="/docs/_snippets/common-links.md" /%}
|
||||
520
docs/tutorials/tasks/use-tokens/issue-a-fungible-token.md
Normal file
520
docs/tutorials/tasks/use-tokens/issue-a-fungible-token.md
Normal file
@@ -0,0 +1,520 @@
|
||||
---
|
||||
html: issue-a-fungible-token.html
|
||||
parent: use-tokens.html
|
||||
seo:
|
||||
description: Create your own token and issue it on the XRP Ledger Testnet.
|
||||
embed_xrpl_js: true
|
||||
filters:
|
||||
- interactive_steps
|
||||
labels:
|
||||
- Tokens
|
||||
steps: ['Generate', 'Connect', 'Configure Issuer', 'Wait (Issuer Setup)', 'Configure Hot Address', 'Wait (Hot Address Setup)', 'Make Trust Line', 'Wait (TrustSet)', 'Send Token', 'Wait (Payment)', 'Confirm Balances']
|
||||
---
|
||||
# Issue a Fungible Token
|
||||
|
||||
Anyone can issue various types of tokens in the XRP Ledger, ranging from informal "IOUs" to fiat-backed stablecoins, purely digital fungible and semi-fungible tokens, and more. This tutorial shows the technical steps of creating a token in the ledger. For more information on how XRP Ledger tokens work, see [Issued Currencies](../../../concepts/tokens/index.md); for more on the business decisions involved in issuing a stablecoin, see [Stablecoin Issuer](../../../use-cases/tokenization/stablecoin-issuer.md). <!-- STYLE_OVERRIDE: ious -->
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- You need two funded XRP Ledger accounts, each with an address, secret key, and some XRP. For this tutorial, you can generate new test credentials as needed.
|
||||
- Each address needs enough XRP to satisfy the [reserve requirement](../../../concepts/accounts/reserves.md) including the additional reserve for a trust line.
|
||||
- You need a connection to the XRP Ledger network. As shown in this tutorial, you can use public servers for testing.
|
||||
- You should be familiar with the Getting Started instructions for your preferred client library. This page provides examples for the following:
|
||||
- **JavaScript** with the [xrpl.js library](https://github.com/XRPLF/xrpl.js/). See [Get Started Using JavaScript](../../javascript/get-started.md) for setup steps.
|
||||
- **Python** with the [`xrpl-py` library](https://xrpl-py.readthedocs.io/). See [Get Started using Python](../../python/get-started.md) for setup steps.
|
||||
- **Java** with the [xrpl4j library](https://github.com/XRPLF/xrpl4j). See [Get Started Using Java](../../java/get-started.md) for setup steps.
|
||||
- You can also read along and use the interactive steps in your browser without any setup.
|
||||
|
||||
<!-- Source for this specific tutorial's interactive bits: -->
|
||||
<script type="application/javascript" src="/js/interactive-tutorial.js"></script>
|
||||
<script type="application/javascript" src="/js/tutorials/issue-a-token.js"></script>
|
||||
|
||||
## Example Code
|
||||
|
||||
Complete sample code for all of the steps of these tutorials is available under the [MIT license](https://github.com/XRPLF/xrpl-dev-portal/blob/master/LICENSE).
|
||||
|
||||
- See [Code Samples: Issue a Fungible Token](https://github.com/XRPLF/xrpl-dev-portal/tree/master/_code-samples/issue-a-token/) in the source repository for this website.
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Get Credentials
|
||||
|
||||
To transact on the XRP Ledger, you need an address and secret key, and some XRP. You also need one or more recipients who are willing to hold the tokens you issue: unlike in some other blockchains, in the XRP Ledger you cannot force someone to hold a token they do not want.
|
||||
|
||||
The best practice is to use ["cold" and "hot" addresses](../../../concepts/accounts/account-types.md). The cold address is the **issuer** of the token. The hot address is like a regular user's address that you control. It receives tokens from the cold address, which you can then transfer to other users. A hot address is not strictly necessary, since you could send tokens directly to users from the cold address, but it is good practice for security reasons. In production, you should take extra care of the cold address's cryptographic keys (for example, keeping them offline) because it is much harder to replace a cold address than a hot address.
|
||||
|
||||
In this tutorial, the hot address receives the tokens you issue from the cold address. You can get the keys for two addresses using the following interface.
|
||||
|
||||
<!-- Special version of generate-step.md for getting sender AND receiver credentials -->
|
||||
|
||||
{% interactive-block label="Generate" steps=$frontmatter.steps %}
|
||||
|
||||
<button id="generate-2x-creds-button" class="btn btn-primary" data-fauceturl="https://faucet.altnet.rippletest.net/accounts">Get Testnet credentials</button>
|
||||
|
||||
{% loading-icon message="Generating Keys..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
**Caution:** Ripple provides the [Testnet and Devnet](../../../concepts/networks-and-servers/parallel-networks.md) for testing purposes only, and sometimes resets the state of these test networks along with all balances. As a precaution, **do not** use the same addresses on Testnet/Devnet and Mainnet.
|
||||
|
||||
When you're building production-ready software, you should use an existing account, and manage your keys using a [secure signing configuration](../../../concepts/transactions/secure-signing.md).
|
||||
|
||||
|
||||
### 2. Connect to the Network
|
||||
|
||||
You must be connected to the network to submit transactions to it. The following code shows how to connect to a public XRP Ledger Testnet server with a supported [client library](../../../references/client-libraries.md):
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/get-started/js/base.js" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/issue-a-token/py/issue-a-token.py" from="# Connect" before="# Get credentials" language="py" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Java" %}
|
||||
{% code-snippet file="/_code-samples/issue-a-token/java/IssueToken.java" from="// Construct a network client" before="// Create cold" language="java" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
|
||||
**Note:** The JavaScript code samples in this tutorial use the [`async`/`await` pattern](https://javascript.info/async-await). Since `await` needs to be used from within an `async` function, the remaining code samples are written to continue inside the `main()` function started here. You can also use Promise methods `.then()` and `.catch()` instead of `async`/`await` if you prefer.
|
||||
|
||||
For this tutorial, click the following button to connect:
|
||||
|
||||
{% partial file="/docs/_snippets/interactive-tutorials/connect-step.md" /%}
|
||||
|
||||
|
||||
### 3. Configure Issuer Settings
|
||||
|
||||
First, configure the settings for your cold address (which will become the issuer of your token). Most settings can be reconfigured later, with the following exceptions: <!-- STYLE_OVERRIDE: will -->
|
||||
|
||||
- [Default Ripple][]: **This setting is required** so that users can send your token to each other. It's best to enable it _before_ setting up any trust lines or issuing any tokens.
|
||||
- [Authorized Trust Lines][]: (Optional) This setting (also called "Require Auth") limits your tokens to being held _only_ by accounts you've explicitly approved. You cannot enable this setting if you already have any trust lines or offers for _any_ token.
|
||||
**Note:** To use authorized trust lines, you must perform additional steps that are not shown in this tutorial.
|
||||
|
||||
[Default Ripple]: ../../../concepts/tokens/fungible-tokens/rippling.md
|
||||
[Authorized Trust Lines]: ../../../concepts/tokens/fungible-tokens/authorized-trust-lines.md
|
||||
|
||||
Other settings you may want to, optionally, configure for your cold address (issuer):
|
||||
|
||||
| Setting | Recommended Value | Summary |
|
||||
|:-----------------------------|:--------------------|:------------------------|
|
||||
| [Require Destination Tags][] | Enabled or Disabled | Enable if you process withdrawals of your token to outside systems. (For example, your token is a stablecoin.) |
|
||||
| Disallow XRP | Enabled or Disabled | Enable if this address isn't meant to process XRP payments. |
|
||||
| [Transfer Fee][] | 0–1% | Charge a percentage fee when users send your token to each other. |
|
||||
| [Tick Size][] | 5 | Limit the number of decimal places in exchange rates for your token in the [decentralized exchange](../../../concepts/tokens/decentralized-exchange/index.md). A tick size of 5-6 reduces churn of almost-equivalent offers and speeds up price discovery compared to the default of 15. |
|
||||
| [Domain][] | (Your domain name) | Set to a domain you own so can [verify ownership of the accounts](../../../references/xrp-ledger-toml.md#account-verification). This can help reduce confusion or impersonation attempts. |
|
||||
|
||||
[Require Destination Tags]: ../manage-account-settings/require-destination-tags.md
|
||||
[Transfer Fee]: ../../../concepts/tokens/transfer-fees.md
|
||||
[Tick Size]: ../../../concepts/tokens/decentralized-exchange/ticksize.md
|
||||
[Domain]: ../../../references/protocol/transactions/types/accountset.md#domain
|
||||
|
||||
You can change these settings later as well.
|
||||
|
||||
**Note:** Many issuing settings apply equally to all tokens issued by an address, regardless of the currency code. If you want to issue multiple types of tokens in the XRP Ledger with different settings, you should use a different address to issue each different token.
|
||||
|
||||
The following code sample shows how to send an [AccountSet transaction][] to enable the recommended cold address settings:
|
||||
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/issue-a-token/js/issue-a-token.js" from="// Configure issuer" before="// Configure hot" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/issue-a-token/py/issue-a-token.py" from="# Configure issuer" before="# Configure hot" language="py" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Java" %}
|
||||
{% code-snippet file="/_code-samples/issue-a-token/java/IssueToken.java" from="// Configure issuer" before="// Configure hot" language="java" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
{% interactive-block label="Configure Issuer" steps=$frontmatter.steps %}
|
||||
|
||||
<form>
|
||||
<div class="form-inline">
|
||||
<div class="input-group form-check">
|
||||
<input type="checkbox" class="form-check-input mr-3" value="" id="cold-default-ripple" disabled="disabled" checked title="The issuer MUST enable Default Ripple first." />
|
||||
<label for="cold-default-ripple" class="col-form-label" title="The issuer MUST enable Default Ripple first.">Default Ripple</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-inline">
|
||||
<div class="input-group form-check">
|
||||
<input type="checkbox" class="form-check-input mr-3" value="" id="cold-require-dest" />
|
||||
<label for="cold-require-dest" class="col-form-label">Require Destination Tags</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-inline">
|
||||
<div class="input-group form-check">
|
||||
<input type="checkbox" class="form-check-input mr-3" value="" id="cold-disallow-xrp" checked />
|
||||
<label for="cold-disallow-xrp" class="col-form-label">Disallow XRP</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="cold-transfer-fee" class="col-form-label col-sm-3">Transfer Fee</label>
|
||||
<div class="input-group col">
|
||||
<input type="number" class="form-control" id="cold-transfer-fee" value="0" step="0.0000001" min="0" max="100" />
|
||||
<div class="input-group-append">
|
||||
<div class="input-group-text">%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="cold-tick-size" class="col-form-label col-sm-3">Tick Size</label>
|
||||
<div class="input-group col">
|
||||
<input type="number" class="form-control" id="cold-tick-size" value="5" step="1" min="0" max="15" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="cold-domain-text" class="col-form-label col-sm-3">Domain</label>
|
||||
<div class="input-group col">
|
||||
<div>
|
||||
<input type="text" class="form-control" value="example.com" pattern="([a-z0-9][a-z0-9\-]{0,62}[.])+[a-z]{2,6}" id="cold-domain-text" title="lower-case domain name of the account owner" />
|
||||
<small class="form-text">(text)</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group col">
|
||||
<div class="col">
|
||||
<label class="form-control-plaintext" id="cold-domain-hex" for="cold-domain-text">6578616D706C652E636F6D</label>
|
||||
<small class="form-text">(hexadecimal)</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<button id="config-issuer-button" class="btn btn-primary previous-steps-required" data-wait-step-name="Wait (Issuer Setup)">Configure issuer</button>
|
||||
|
||||
{% loading-icon message="Sending transaction..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
### 4. Wait for Validation
|
||||
|
||||
Most transactions are accepted into the next ledger version after they're submitted, which means it may take 4-7 seconds for a transaction's outcome to be final. You should wait for your earlier transactions to be fully validated before proceeding to the later steps, to avoid unexpected failures from things executing out of order. For more information, see [Reliable Transaction Submission](../../../concepts/transactions/reliable-transaction-submission.md).
|
||||
|
||||
The code samples in this tutorial use helper functions to wait for validation when submitting a transaction:
|
||||
|
||||
- **JavaScript:** The `submit_and_verify()` function, as defined in the [submit-and-verify code sample](https://github.com/XRPLF/xrpl-dev-portal/tree/master/_code-samples/submit-and-verify).
|
||||
- **Python:** The `submit_and_wait()` [method of the xrpl-py library](https://xrpl-py.readthedocs.io/en/stable/source/xrpl.transaction.html#xrpl.transaction.submit_and_wait).
|
||||
- **Java:** The `submitAndWaitForValidation()` method in the [sample Java class](https://github.com/XRPLF/xrpl-dev-portal/blob/master/_code-samples/issue-a-token/java/IssueToken.java).
|
||||
|
||||
**Tip:** Technically, you can configure the hot address in parallel with configuring the issuer address. For simplicity, this tutorial waits for each transaction one at a time.
|
||||
|
||||
{% partial file="/docs/_snippets/interactive-tutorials/wait-step.md" variables={label: "Wait (Issuer Setup)"} /%}
|
||||
|
||||
|
||||
### 5. Configure Hot Address Settings
|
||||
|
||||
The hot address does not strictly require any settings changes from the default, but the following are recommended as best practices:
|
||||
|
||||
| Setting | Recommended Value | Summary |
|
||||
|:-----------------------------|:--------------------|:------------------------|
|
||||
| [Default Ripple][] | Disabled | Leave this setting **disabled.** (This is the default.) |
|
||||
| [Authorized Trust Lines][] | Enabled | Enable this setting on the hot address—and never approve any trust lines to the hot address—to prevent accidentally issuing tokens from the wrong address. (Optional, but recommended.) |
|
||||
| [Require Destination Tags][] | Enabled or Disabled | Enable if you process withdrawals of your token to outside systems. (For example, your token is a stablecoin.) |
|
||||
| Disallow XRP | Enabled or Disabled | Enable if this address isn't meant to process XRP payments. |
|
||||
| [Domain][] | (Your domain name) | Set to a domain you own so can [verify ownership of the accounts](../../../references/xrp-ledger-toml.md#account-verification). This can help reduce confusion or impersonation attempts. |
|
||||
|
||||
The following code sample shows how to send an [AccountSet transaction][] to enable the recommended hot address settings:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/issue-a-token/js/issue-a-token.js" from="// Configure hot address" before="// Create trust line" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/issue-a-token/py/issue-a-token.py" from="# Configure hot address" before="# Create trust line" language="py" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Java" %}
|
||||
{% code-snippet file="/_code-samples/issue-a-token/java/IssueToken.java" from="// Configure hot address" before="// Create trust line" language="java" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
{% interactive-block label="Configure Hot Address" steps=$frontmatter.steps %}
|
||||
|
||||
<form>
|
||||
<div class="form-inline">
|
||||
<div class="input-group form-check">
|
||||
<input type="checkbox" class="form-check-input mr-3" value="" id="hot-default-ripple" disabled="disabled" title="Default Ripple must remain disabled on the hot address." />
|
||||
<label for="hot-default-ripple" class="form-check-label" title="Default Ripple must remain disabled on the hot address.">Default Ripple</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-inline">
|
||||
<div class="input-group form-check">
|
||||
<input type="checkbox" class="form-check-input mr-3" value="" id="hot-require-auth" disabled="disabled" checked="checked" title="The hot address should enable Authorized Trust Lines as a precaution." />
|
||||
<label for="hot-default-ripple" class="form-check-label" title="The hot address should enable Authorized Trust Lines as a precaution.">Authorized Trust Lines</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-inline">
|
||||
<div class="input-group form-check">
|
||||
<input type="checkbox" class="form-check-input mr-3" value="" id="hot-require-dest" />
|
||||
<label for="hot-require-dest" class="form-check-label">Require Destination Tags</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-inline">
|
||||
<div class="input-group form-check">
|
||||
<input type="checkbox" class="form-check-input mr-3" value="" id="hot-disallow-xrp" checked="checked" />
|
||||
<label for="hot-disallow-xrp" class="form-check-label">Disallow XRP</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="hot-domain-text" class="col-form-label col-sm-3">Domain</label>
|
||||
<div class="input-group col">
|
||||
<div>
|
||||
<input type="text" class="form-control" value="example.com" pattern="([a-z0-9][a-z0-9\-]{0,62}[.])+[a-z]{2,6}" id="hot-domain-text" title="lower-case domain name of the account owner" />
|
||||
<small class="form-text">(text)</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group col">
|
||||
<div class="col">
|
||||
<label class="form-control-plaintext" id="hot-domain-hex" for="hot-domain-text">6578616D706C652E636F6D</label>
|
||||
<small class="form-text">(hexadecimal)</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<button id="config-hot-address-button" class="btn btn-primary previous-steps-required" data-wait-step-name="Wait (Hot Address Setup)">Configure hot address</button>
|
||||
|
||||
{% loading-icon message="Sending transaction..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
### 6. Wait for Validation
|
||||
|
||||
As before, wait for the previous transaction to be validated by consensus before continuing.
|
||||
|
||||
{% partial file="/docs/_snippets/interactive-tutorials/wait-step.md" variables={label: "Wait (Hot Address Setup)"} /%}
|
||||
|
||||
|
||||
### 7. Create Trust Line from Hot to Cold Address
|
||||
|
||||
Before you can receive tokens, you need to create a [trust line](../../../concepts/tokens/fungible-tokens/index.md) to the token issuer. This trust line is specific to the [currency code](../../../references/protocol/data-types/currency-formats.md#currency-codes) of the token you want to issue, such as USD or FOO. You can choose any currency code you want; each issuer's tokens are treated as separate in the XRP Ledger protocol. However, users' balances of tokens with the same currency code can [ripple](../../../concepts/tokens/fungible-tokens/rippling.md) between different issuers if the users enable rippling settings.
|
||||
|
||||
The hot address needs a trust line like this before it can receive tokens from the issuer. Similarly, each user who wants to hold your token must also create a trust line[¹](#footnotes). Each trust line increases the [reserve requirement](../../../concepts/accounts/reserves.md) of the hot address, so you must hold enough spare XRP to pay for the increased requirement. Your reserve requirement goes back down if you remove the trust line.
|
||||
|
||||
**Tip:** A trust line has a "limit" on how much the recipient is willing to hold; others cannot send you more tokens than your specified limit. For community credit systems, you may want to configure limits per individual based on how much you trust that person. For other types and uses of tokens, it is normally OK to set the limit to a very large number.
|
||||
|
||||
To create a trust line, send a [TrustSet transaction][] from the **hot address** with the following fields:
|
||||
|
||||
| Field | Value |
|
||||
|:-----------------------|:----------------------------------------------------|
|
||||
| `TransactionType` | `"TrustSet"` |
|
||||
| `Account` | The hot address. (More generally, this is the account that wants to receive the token.) |
|
||||
| `LimitAmount` | An object specifying how much, of which token, from which issuer, you are willing to hold. |
|
||||
| `LimitAmount.currency` | The currency code of the token. |
|
||||
| `LimitAmount.issuer` | The cold address. |
|
||||
| `LimitAmount.value` | The maximum amount of the token you are willing to hold. |
|
||||
|
||||
The following code sample shows how to send a [TrustSet transaction][] from the hot address, trusting the issuing address for a limit of 1 billion FOO:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/issue-a-token/js/issue-a-token.js" from="// Create trust line" before="// Send token" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/issue-a-token/py/issue-a-token.py" from="# Create trust line" before="# Send token" language="py" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Java" %}
|
||||
{% code-snippet file="/_code-samples/issue-a-token/java/IssueToken.java" from="// Create trust line" before="// Send token" language="java" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
{% interactive-block label="Make Trust Line" steps=$frontmatter.steps %}
|
||||
|
||||
<form>
|
||||
<p>Currency code:</p>
|
||||
<div class="container">
|
||||
<div class="input-group row">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text form-check bg-transparent">
|
||||
<input type="radio" id="use-std-code" name="currency-code-type" checked="checked" />
|
||||
</div>
|
||||
</div>
|
||||
<label for="use-std-code" class="input-group-text col-lg-3">Standard:</label>
|
||||
<input type="text" id="currency-code-std" pattern="[A-Za-z0-9?!@#$%*\(\)\{\}\|\x26\x3c\x3e]{3}" value="FOO" class="form-control col-lg-8" title="3 character code (letters, numbers, and some symbols)" />
|
||||
</div>
|
||||
<div class="input-group row mt-2">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text form-check bg-transparent">
|
||||
<input type="radio" id="use-hex-code" name="currency-code-type" />
|
||||
</div>
|
||||
</div>
|
||||
<label for="use-hex-code" class="input-group-text col-lg-3">Non-standard:</label>
|
||||
<input type="text" id="currency-code-hex" pattern="[0-9A-F]{40}" value="015841551A748AD2C1F76FF6ECB0CCCD00000000" title="40 hexadecimal characters" class="form-control col-lg-8" />
|
||||
</div>
|
||||
<div class="input-group row mt-4">
|
||||
<label for="trust-limit" class="input-group-text col-lg-3">Limit:</label>
|
||||
<input type="number" id="trust-limit" min="0" value="1000000000" title="Maximum amount the hot address can hold" class="form-control col-lg-9" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<button id="create-trust-line-button" class="btn btn-primary previous-steps-required" data-wait-step-name="Wait (TrustSet)">Create Trust Line</button>
|
||||
|
||||
{% loading-icon message="Sending transaction..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
**Note:** If you use [Authorized Trust Lines][], there is an extra step after this one: the cold address must approve the trust line from the hot address. For details of how to do this, see [Authorizing Trust Lines](../../../concepts/tokens/fungible-tokens/authorized-trust-lines.md#authorizing-trust-lines).
|
||||
|
||||
|
||||
### 8. Wait for Validation
|
||||
|
||||
As before, wait for the previous transaction to be validated by consensus before continuing.
|
||||
|
||||
{% partial file="/docs/_snippets/interactive-tutorials/wait-step.md" variables={label: "Wait (TrustSet)"} /%}
|
||||
|
||||
|
||||
### 9. Send Token
|
||||
|
||||
Now you can create tokens by sending a [Payment transaction][] from the cold address to the hot address. This transaction should have the following attributes (dot notation indicates nested fields):
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| `TransactionType` | `"Payment"` |
|
||||
| `Account` | The cold address issuing the token. |
|
||||
| `Amount` | An [token amount](../../../references/protocol/data-types/basic-data-types.md#specifying-currency-amounts) specifying how much of which token to create. |
|
||||
| `Amount.currency` | The currency code of the token. |
|
||||
| `Amount.value` | Decimal amount of the token to issue, as a string. |
|
||||
| `Amount.issuer` | The cold address issuing the token. |
|
||||
| `Destination` | The hot address (or other account receiving the token) |
|
||||
| `Paths` | Omit this field when issuing tokens. |
|
||||
| `SendMax` | Omit this field when issuing tokens. |
|
||||
| `DestinationTag` | Any whole number from 0 to 2<sup>32</sup>-1. You must specify _something_ here if you enabled [Require Destination Tags][] on the hot address. |
|
||||
|
||||
You can use [auto-filled values](../../../references/protocol/transactions/common-fields.md#auto-fillable-fields) for all other required fields.
|
||||
|
||||
The following code sample shows how to send a [Payment transaction][] to issue 88 FOO from the cold address to the hot address:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/issue-a-token/js/issue-a-token.js" from="// Send token" before="// Check balances" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/issue-a-token/py/issue-a-token.py" from="# Send token" before="# Check balances" language="py" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Java" %}
|
||||
{% code-snippet file="/_code-samples/issue-a-token/java/IssueToken.java" from="// Send token" before="// Check balances" language="java" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
{% interactive-block label="Send Token" steps=$frontmatter.steps %}
|
||||
|
||||
<form>
|
||||
<div class="form-inline mt-2">
|
||||
<div class="input-group">
|
||||
<label for="send-amount" class="input-group-text">Send amount:</label>
|
||||
<input type="number" id="send-amount" min="0" value="123.45" step="0.01" title="How much to send to the hot address" class="form-control" />
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text" id="send-currency-code">FOO</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-inline mt-2">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text bg-transparent">
|
||||
<input type="checkbox" id="use-dest-tag" class="mr-2" checked="checked" />
|
||||
</div>
|
||||
</div>
|
||||
<label for="dest-tag" class="input-group-text">DestinationTag:</label>
|
||||
<input type="number" id="dest-tag" value="0" min="0" max="4294967295" class="form-control" title="Any 32-bit integer" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<button id="send-token-button" class="btn btn-primary previous-steps-required" data-wait-step-name="Wait (Payment)">Send Token</button>
|
||||
|
||||
{% loading-icon message="Sending transaction..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
|
||||
### 10. Wait for Validation
|
||||
|
||||
As before, wait for the previous transaction to be validated by consensus before continuing.
|
||||
|
||||
{% partial file="/docs/_snippets/interactive-tutorials/wait-step.md" variables={label: "Wait (Payment)"} /%}
|
||||
|
||||
|
||||
### 11. Confirm Token Balances
|
||||
|
||||
You can check the balances of your token from the perspective of either the token issuer or the hot address. Tokens issued in the XRP Ledger always have balances that sum to 0: negative from the perspective of the issuer and positive from the perspective of the holder.
|
||||
|
||||
Use the [account_lines method][] to look up the balances from the perspective of the holder. This lists each trust line along with its limit, balance, and settings.
|
||||
|
||||
Use the [gateway_balances method][] to look up balances from the perspective of a token issuer. This provides a sum of all tokens issued by a given address.
|
||||
|
||||
**Tip:** Since the XRP Ledger is fully public, you can check the balances of any account at any time without needing any cryptographic keys.
|
||||
|
||||
The following code sample shows how to use both methods:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/issue-a-token/js/issue-a-token.js" from="// Check balances" before="// End of" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/issue-a-token/py/issue-a-token.py" from="# Check balances" language="py" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Java" %}
|
||||
{% code-snippet file="/_code-samples/issue-a-token/java/IssueToken.java" from="// Check balances" before="// Helper" language="java" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
{% interactive-block label="Confirm Balances" steps=$frontmatter.steps %}
|
||||
|
||||
<button id="confirm-balances-button" class="btn btn-primary previous-steps-required">Confirm Balances</button>
|
||||
|
||||
{% loading-icon message="Checking..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
|
||||
### Next Steps
|
||||
|
||||
Now that you've created the token, you can explore how it fits into features of the XRP Ledger:
|
||||
|
||||
- Send tokens from the hot address to other users.
|
||||
- Trade it in the decentralized exchange.
|
||||
- Monitor for incoming payments of your token.
|
||||
- Create an [xrp-ledger.toml file](../../../references/xrp-ledger-toml.md) and set up domain verification for your token's issuer.
|
||||
- Learn about other [features of XRP Ledger tokens](../../../concepts/tokens/index.md).
|
||||
|
||||
|
||||
## Footnotes
|
||||
|
||||
¹ Users can hold your token without explicitly creating a trust line if they buy your token in the [decentralized exchange](../../../concepts/tokens/decentralized-exchange/index.md). Buying a token in the exchange [automatically creates the necessary trust lines](../../../concepts/tokens/decentralized-exchange/offers.md#offers-and-trust). This is only possible if someone is selling your token in the decentralized exchange.
|
||||
|
||||
{% raw-partial file="/docs/_snippets/common-links.md" /%}
|
||||
@@ -0,0 +1,266 @@
|
||||
---
|
||||
parent: use-tokens.html
|
||||
seo:
|
||||
description: Buy or sell fungible tokens for each other or for XRP in the decentralized exchange.
|
||||
embed_xrpl_js: true
|
||||
filters:
|
||||
- interactive_steps
|
||||
labels:
|
||||
- Decentralized Exchange
|
||||
- Tokens
|
||||
steps: ['Connect', 'Generate', 'Look Up Offers',' Send OfferCreate', 'Wait', 'Check Metadata', 'Check Balances and Offers']
|
||||
---
|
||||
# Trade in the Decentralized Exchange
|
||||
|
||||
This tutorial demonstrates how you can buy and sell tokens in the [decentralized exchange](../../../concepts/tokens/decentralized-exchange/index.md) (DEX).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- You need a connection to the XRP Ledger network. As shown in this tutorial, you can use public servers for testing.
|
||||
- You should be familiar with the Getting Started instructions for your preferred client library. This page provides examples for the following:
|
||||
- **JavaScript** with the [xrpl.js library](https://github.com/XRPLF/xrpl.js/). See [Get Started Using JavaScript](../../javascript/get-started.md) for setup steps.
|
||||
- **Python** with the [`xrpl-py` library](https://xrpl-py.readthedocs.io/). See [Get Started using Python](../../python/get-started.md) for setup steps.
|
||||
- You can also read along and use the interactive steps in your browser without any setup.
|
||||
|
||||
<!-- Source for this specific tutorial's interactive bits: -->
|
||||
<script type="application/javascript" src="/js/interactive-tutorial.js"></script>
|
||||
<script src='https://cdn.jsdelivr.net/npm/bignumber.js@9.0.2/bignumber.min.js'></script>
|
||||
<script type="application/javascript" src="/js/tutorials/trade-in-the-dex.js"></script>
|
||||
|
||||
## Example Code
|
||||
|
||||
Complete sample code for all of the steps of this tutorial is available under the [MIT license](https://github.com/XRPLF/xrpl-dev-portal/blob/master/LICENSE).
|
||||
|
||||
- See [Code Samples: Trade in the Decentralized Exchange](https://github.com/XRPLF/xrpl-dev-portal/tree/master/_code-samples/trade-in-the-decentralized-exchange/) in the source repository for this website.
|
||||
|
||||
|
||||
## Steps
|
||||
|
||||
This tutorial demonstrates how to buy a fungible token in the decentralized exchange by selling XRP. (Other types of trades are possible, but selling a token, for example, requires you to have it first.) The example token used in this tutorial is as follows:
|
||||
|
||||
| Currency Code | Issuer | Notes |
|
||||
|---|---|---|
|
||||
| TST | `rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd` | A test token pegged to XRP at a rate of approximately 10 XRP per 1 TST. The issuer has existing Offers on the XRP Ledger Testnet to buy and sell these tokens. |
|
||||
|
||||
|
||||
### 1. Connect to Network
|
||||
|
||||
You must be connected to the network to submit transactions to it. Additionally, some languages (including JavaScript) require a high-precision number library for performing calculations on currency amounts you may find in the ledger. The following code shows how to connect to a public XRP Ledger Testnet server a supported [client library](../../../references/client-libraries.md) with the appropriate dependencies.
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/trade-in-the-decentralized-exchange/js/base-with-bignumber.js" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/get-started/py/base-async.py" language="py" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
**Note:** The JavaScript code samples in this tutorial use the [`async`/`await` pattern](https://javascript.info/async-await). Since `await` needs to be used from within an `async` function, the remaining code samples are written to continue inside the `main()` function started here. You can also use Promise methods `.then()` and `.catch()` instead of `async`/`await` if you prefer.
|
||||
|
||||
For this tutorial, click the following button to connect:
|
||||
|
||||
{% partial file="/docs/_snippets/interactive-tutorials/connect-step.md" /%}
|
||||
|
||||
### 2. Get Credentials
|
||||
|
||||
To transact on the XRP Ledger, you need an address, a secret key, and some XRP. For development purposes, you can get these on the [{{use_network}}](../../../concepts/networks-and-servers/parallel-networks.md) using the following interface:
|
||||
|
||||
{% partial file="/docs/_snippets/interactive-tutorials/generate-step.md" /%}
|
||||
|
||||
When you're building production-ready software, you should use an existing account, and manage your keys using a [secure signing configuration](../../../concepts/transactions/secure-signing.md). The following code shows how to create a `Wallet` instance to use your keys:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/trade-in-the-decentralized-exchange/js/trade-in-the-dex.js" from="// Get credentials" before="// Define the proposed trade" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/trade-in-the-decentralized-exchange/py/trade-in-the-dex.py" from="# Get credentials" before="# Define the proposed trade" language="py" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
### 7. Look Up Offers
|
||||
|
||||
Before you buy or sell a token, you usually want to look up what others are buying and selling for, to get a sense of how others value it. In the XRP Ledger, you can look up existing offers for any currency pair using the [book_offers method][].
|
||||
|
||||
**Tip:** Technically, this step is not a requirement for placing an Offer, but it is a good practice to confirm the current situation before trading anything with real value.
|
||||
|
||||
The following code shows how to look up existing Offers and compare them to a proposed Offer to estimate how it would execute:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/trade-in-the-decentralized-exchange/js/trade-in-the-dex.js" from="// Define the proposed trade" before="// Send OfferCreate" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/trade-in-the-decentralized-exchange/py/trade-in-the-dex.py" from="# Define the proposed trade" before="# Send OfferCreate" language="py" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
**Note:** Other users of the XRP Ledger can also make trades at any time, so this is only an estimate of what would happen if nothing else changes. The outcome of a transaction is not guaranteed until it is [final](../../../concepts/transactions/finality-of-results/index.md).
|
||||
|
||||
The following block demonstrates these calculations in action:
|
||||
|
||||
{% interactive-block label="Look Up Offers" steps=$frontmatter.steps %}
|
||||
|
||||
<form>
|
||||
<h5>TakerPays</h5>
|
||||
<div class="form-group row">
|
||||
<label for="taker-pays-currency-1" class="col-form-label col-sm-3">currency</label>
|
||||
<div class="input-group col">
|
||||
<input type="text" class="form-control" id="taker-pays-currency-1" value="TST" disabled="disabled" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="taker-pays-issuer-1" class="col-form-label col-sm-3">issuer</label>
|
||||
<div class="input-group col">
|
||||
<input type="text" class="form-control" id="taker-pays-issuer-1" value="rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd" disabled="disabled" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="taker-pays-amount-1" class="col-form-label col-sm-3">value</label>
|
||||
<div class="input-group col">
|
||||
<input type="number" class="form-control" id="taker-pays-amount-1" value="10" step="0.000001" min="0" max="1000" />
|
||||
</div>
|
||||
</div>
|
||||
<h5>TakerGets</h5>
|
||||
<div class="form-group row">
|
||||
<label for="taker-gets-amount-1" class="col-form-label col-sm-3">XRP:</label>
|
||||
<div class="input-group col">
|
||||
<input type="number" class="form-control" value="115" id="taker-gets-amount-1"
|
||||
aria-label="Amount of XRP, as a decimal" aria-describedby="xrp-amount-label"
|
||||
min=".000001" max="100000000000" step="any" />
|
||||
</div>
|
||||
</div>
|
||||
<h5>Exchange Rate</h5>
|
||||
<div class="form-group row">
|
||||
<label for="exchange-rate-1" class="col-form-label col-sm-3">XRP cost per 1 TST:</label>
|
||||
<div class="input-group col">
|
||||
<input type="number" class="form-control" value="11.5" id="exchange-rate-1" step="any" disabled="disabled" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<button id="look-up-offers" class="btn btn-primary previous-steps-required">Look Up Offers</button>
|
||||
|
||||
{% loading-icon message="Querying..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
### 3. Send OfferCreate Transaction
|
||||
|
||||
To actually make a trade, send an [OfferCreate transaction][]. In this case, you want to buy TST using XRP, so you should set the parameters as follows:
|
||||
|
||||
| Field | Type | Description |
|
||||
|---|---|---|
|
||||
| `TakerPays` | [Token Amount object][Currency Amount] | How much of what currency you want to buy, in total. For this tutorial, buy some amount of **TST** issued by `rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd`. |
|
||||
| `TakerGets` | [XRP, in drops][] | How much of what currency you are offering to pay in total. For this tutorial, you should specify about 11.5 XRP per TST or slightly more. |
|
||||
|
||||
The following code shows how to prepare, sign, and submit the transaction:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/trade-in-the-decentralized-exchange/js/trade-in-the-dex.js" from="// Send OfferCreate" before="// Check metadata" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/trade-in-the-decentralized-exchange/py/trade-in-the-dex.py" from="# Send OfferCreate" before="# Check metadata" language="py" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
You can use this interface to send the transaction specified by the amounts in the previous step:
|
||||
|
||||
{% interactive-block label="Send OfferCreate" steps=$frontmatter.steps %}
|
||||
|
||||
<button id="send-offercreate" class="btn btn-primary previous-steps-required" data-wait-step-name="Wait">Send OfferCreate</button>
|
||||
|
||||
{% loading-icon message="Sending..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
### 4. Wait for Validation
|
||||
|
||||
Most transactions are accepted into the next ledger version after they're submitted, which means it may take 4-7 seconds for a transaction's outcome to be final. If the XRP Ledger is busy or poor network connectivity delays a transaction from being relayed throughout the network, a transaction may take longer to be confirmed. (For information on how to set an expiration for transactions, see [Reliable Transaction Submission](../../../concepts/transactions/reliable-transaction-submission.md).)
|
||||
|
||||
{% partial file="/docs/_snippets/interactive-tutorials/wait-step.md" /%}
|
||||
|
||||
|
||||
### 5. Check Metadata
|
||||
|
||||
You can use the validated transaction's [metadata](../../../references/protocol/transactions/metadata.md) to determine exactly what it did. (Don't use metadata from tentative transaction results, because it may be different from the [final result](../../../concepts/transactions/finality-of-results/index.md), especially when using the decentralized exchange.) In case of an OfferCreate transaction, likely results include:
|
||||
|
||||
- Some or all of the Offer may have been filled by matching with existing Offers in the ledger.
|
||||
- The unmatched remainder, if any, has been placed into the ledger to await new matching Offers. <!-- STYLE_OVERRIDE: remainder -->
|
||||
- Other bookkeeping may have occurred, such as removing expired or unfunded Offers that would have matched.
|
||||
|
||||
The following code demonstrates how to check the metadata of the transaction:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/trade-in-the-decentralized-exchange/js/trade-in-the-dex.js" from="// Check metadata" before="// Check balances" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/trade-in-the-decentralized-exchange/py/trade-in-the-dex.py" from="# Check metadata" before="# Check balances" language="py" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
You can use this interface to test it out:
|
||||
|
||||
{% interactive-block label="Check Metadata" steps=$frontmatter.steps %}
|
||||
|
||||
<button id="check-metadata" class="btn btn-primary previous-steps-required">Check Metadata</button>
|
||||
|
||||
{% loading-icon message="Checking..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
|
||||
### 6. Check Balances and Offers
|
||||
|
||||
This is also a good time to look up the balances and outstanding Offers owned by your account as of the latest validated ledger. This shows any changes caused by your transaction as well as any others that executed in the same ledger version.
|
||||
|
||||
The following code demonstrates how to look up balances using the [account_lines method][] and look up Offers using the [account_offers method][].
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/trade-in-the-decentralized-exchange/js/trade-in-the-dex.js" from="// Check balances" before="client.disconnect()" language="js" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/trade-in-the-decentralized-exchange/py/trade-in-the-dex.py" from="# Check balances" before="# End main()" language="py" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
You can use this interface to test it out:
|
||||
|
||||
{% interactive-block label="Check Balances and Offers" steps=$frontmatter.steps %}
|
||||
|
||||
<button id="check-balances-and-offers" class="btn btn-primary previous-steps-required">Check Balances and Offers</button>
|
||||
|
||||
{% loading-icon message="Checking..." /%}
|
||||
|
||||
<div class="output-area"></div>
|
||||
|
||||
{% /interactive-block %}
|
||||
|
||||
{% raw-partial file="/docs/_snippets/common-links.md" /%}
|
||||
Reference in New Issue
Block a user