Freeze tutorials: fixes and cleanup

- Move JS code samples to JS folder (future-proofing for other
  languages)
- Make "Freeze a Trust Line" tutorial interactive
- Add necessary functionality to interactive_tutorial helper JS
- Rework freeze a trust line tutorial/code sample to make an incoming
  line from another address and make looking up trust lines a
  full-fledged step
This commit is contained in:
mDuo13
2021-10-25 22:56:31 -07:00
parent afe6b6263d
commit 7c6257c2d8
15 changed files with 448 additions and 117 deletions

View File

@@ -255,6 +255,7 @@ function get_wallet(event) {
const block = $(event.target).closest(".interactive-block")
if (!block.length) {return}
show_error(block, tl("Can't use the example secret here. Check that the previous steps were completed successfully."))
return
}
return xrpl.Wallet.fromSeed(secret)
}
@@ -285,6 +286,16 @@ async function call_faucet(faucet_url, destination) {
return data
}
/**
* Tutorials' scripts should push functions to this array to have them run
* automatically after connecting to the network. The scopes don't work out
* right to use api.on("connect", callback) directly from the tutorials' unique
* scripts because the api instance (specific to the network) is instantiated
* by the setup_connect_step() in this file, below.
*/
window.after_connect = window.after_connect || [];
/**
* To be used with _snippets/interactive-tutorials/connect-step.md
* Adds an event to the "Connect" button to connect to the appropriate
@@ -322,10 +333,14 @@ function setup_connect_step() {
disable_followup_steps()
})
$("#connect-button").click(() => {
$("#connect-button").click(async (event) => {
$("#connection-status").text( tl("Connecting...") )
$("#loader-connect").show()
api.connect()
await api.connect()
for (const fn of after_connect) {
fn()
}
})
}

View File

@@ -14,10 +14,13 @@ $(document).ready(() => {
"TransactionType": "AccountSet",
"Account": address
}
let step_name
if ($(event.target).data("action") === "start_freeze") {
astx["SetFlag"] = xrpl.AccountSetAsfFlags.asfGlobalFreeze
step_name = "Send AccountSet"
} else if ($(event.target).data("action") === "end_freeze") {
astx["ClearFlag"] = xrpl.AccountSetAsfFlags.asfGlobalFreeze
step_name = "End Freeze"
} else {
show_error(block, "There was an error with this tutorial: the button clicked must have data-action defined.")
}
@@ -25,7 +28,7 @@ $(document).ready(() => {
try {
block.find(".loader").show()
await generic_full_send(event, astx)
complete_step("Send AccountSet")
complete_step(step_name)
} catch(err) {
block.find(".loader").hide()
show_error(block, err)

View File

@@ -0,0 +1,176 @@
// 1. Generate
// 2. Connect
// The code for these steps is handled by interactive-tutorial.js
const CURRENCY_TO_FREEZE = "FOO"
// Helper to get a Wallet instance for the peer wallet
function get_peer_wallet(event) {
let peer_seed
try {
peer_seed = $("#peer-seed").val()
} catch(e) {
show_error(block, err)
return
}
if (!peer_seed) {
const block = $(event.target).closest(".interactive-block")
if (!block.length) {return}
show_error(block, "Couldn't get information on the peer account. Check that the previous steps were completed successfully.")
return
}
return xrpl.Wallet.fromSeed(peer_seed)
}
let trust_line_setup_done = false
window.after_connect = window.after_connect || [];
window.after_connect.push(async () => {
// 2.5. One-time setup on connect to create an incoming trust line after
// the "api" instance has been created by the connect handler.
if (trust_line_setup_done) {return} // Don't repeat if we disconnect/reconnect
console.log("Setting up an incoming trust line so our test address has something to freeze...")
$("#trust-line-setup-loader").show()
const address = get_address()
const peer = (await api.fundWallet()).wallet
const tx_json = {
"TransactionType": "TrustSet",
"Account": peer.address,
"LimitAmount": {
"currency": CURRENCY_TO_FREEZE,
"issuer": address,
"value": "123456.789" // arbitrary limit
}
}
try {
const submitted = await api.submitAndWait(tx_json, {wallet: peer})
console.log("Set up incoming trust line result:", submitted)
} catch(e) {
const block = $("#trust-line-setup-loader").closest(".interactive-block")
show_err(block, e)
$("#trust-line-setup-loader").hide()
return
}
$("#trust-line-setup-loader").hide()
$("#look-up-trust-lines").prop("disabled", false).prop("title", "")
$("#peer-seed").val(peer.seed)
trust_line_setup_done = true
})
$(document).ready(() => {
// 3. Choose Trust Line ------------------------------------------------------
$("#look-up-trust-lines").click( async (event) => {
const block = $(event.target).closest(".interactive-block")
block.find(".output-area").html("")
const address = get_address(event)
if (!address) {return}
const peer = get_peer_wallet(event)
if (!peer) {return}
block.find(".loader-looking").show()
let account_lines
try {
account_lines = await api.request({
"command": "account_lines",
"account": address,
"peer": peer.address,
"ledger_index": "validated"
})
} catch(e) {
show_error(block, err)
}
block.find(".loader-looking").hide()
block.find(".output-area").append(
`<p>Found trust line(s) between ${address} and ${peer.address}:</p>
<pre><code>${pretty_print(account_lines.result.lines)}</code></pre>
<p>Choosing ${CURRENCY_TO_FREEZE} trust line.</p>`)
complete_step("Choose Trust Line")
})
// 4. Send TrustSet to freeze ------------------------------------------------
// also 7. Send TrustSet to end the freeze
$(".send-trustset").click( async (event) => {
const block = $(event.target).closest(".interactive-block")
const address = get_address(event)
if (!address) {return}
const peer = get_peer_wallet(event)
if (!peer) {return}
let tstx = {
"TransactionType": "TrustSet",
"Account": address,
"LimitAmount": {
"currency": CURRENCY_TO_FREEZE,
"issuer": peer.address,
"value": "0"
}
}
let step_name
if ($(event.target).data("action") === "start_freeze") {
tstx["Flags"] = xrpl.TrustSetFlags.tfSetFreeze
step_name = "Send TrustSet to Freeze"
} else if ($(event.target).data("action") === "end_freeze") {
tstx["Flags"] = xrpl.TrustSetFlags.tfClearFreeze
step_name = "Send TrustSet to End Freeze"
} else {
show_error(block, "There was an error with this tutorial: the button clicked must have data-action defined.")
}
try {
await generic_full_send(event, tstx)
complete_step(step_name)
} catch(err) {
block.find(".loader").hide()
show_error(block, err)
}
})
// 5. Wait for Validation is handled by the snippet
// 6. Check Trust Line Freeze Status
$("#confirm-settings").click( async (event) => {
const block = $(event.target).closest(".interactive-block")
const address = get_address(event)
if (!address) {return}
const peer = get_peer_wallet(event)
if (!peer) {return}
block.find(".output-area").html("")
block.find(".loader").show()
const account_lines = await api.request({
"command": "account_lines",
"account": address,
"peer": peer.address,
"ledger_index": "validated"
})
console.log(account_lines)
block.find(".loader").hide()
const trustlines = account_lines.result.lines
for (let i = 0; i < trustlines.length; i++) {
if(trustlines[i].currency === CURRENCY_TO_FREEZE) {
const line = trustlines[i]
block.find(".output-area").append(
`<p>Status of ${CURRENCY_TO_FREEZE} line between ${address} and ${peer.address}:</p>
<pre><code>${pretty_print(line)}</code></pre>`)
if (line.freeze === true) {
block.find(".output-area").append(`<p><i class="fa fa-check-circle"></i>
Line is frozen.`)
} else {
block.find(".output-area").append(`<p><i class="fa fa-times-circle"></i>
Line is NOT FROZEN.</p>`)
}
complete_step("Check Freeze Status")
return
}
}
show_error(block, `Couldn't find a ${CURRENCY_TO_FREEZE} line between ${address} and ${peer.address}`)
})
// 7. Send TrustSet to End the Freeze is covered by the shared handler above
})

View File

@@ -0,0 +1,133 @@
// Dependencies for Node.js.
// In browsers, use <script> tags as in the example demo.html.
if (typeof module !== "undefined") {
// gotta use var here because const/let are block-scoped to the if statement.
var xrpl = require('xrpl')
}
async function main() {
// Connect -------------------------------------------------------------------
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
await client.connect()
// Get credentials from the Testnet Faucet -----------------------------------
console.log("Requesting an address from the Testnet faucet...")
const { wallet, balance } = await client.fundWallet()
// Set up an incoming trust line so we have something to freeze --------------
// We use a hard-coded example wallet here so the sample code can have a hard-
// coded example address below. Don't use this seed for anything real.
const peer = xrpl.Wallet.fromSeed("sho56WRm8fKLrfixaWa9cxhYJg8hc")
await client.fundWallet(peer)
const submitted = await client.submitAndWait({
"TransactionType": "TrustSet",
"Account": peer.address,
"LimitAmount": {
"currency": 'FOO',
"issuer": wallet.address,
"value": "123456.789" // arbitrary limit
}
}, {wallet: peer})
console.log("Set up incoming trust line result:", submitted)
// Look up current trust lines -----------------------------------------------
const issuing_address = wallet.address
const address_to_freeze = 'rhPuJPcd9kcSRCGHWudV3tjUuTvvysi6sv'
const currency_to_freeze = 'FOO'
console.log('Looking up', currency_to_freeze, 'trust line from',
issuing_address, 'to', address_to_freeze)
const account_lines = await client.request({
"command": "account_lines",
"account": issuing_address,
"peer": address_to_freeze,
"ledger_index": "validated"
})
const trustlines = account_lines.result.lines
console.log("Found lines:", trustlines)
// Find the trust line for our currency_to_freeze ----------------------------
let trustline = null
for (let i = 0; i < trustlines.length; i++) {
if(trustlines[i].currency === currency_to_freeze) {
trustline = trustlines[i]
break
}
}
if (trustline === null) {
console.error(`Couldn't find a ${currency_to_freeze} trustline between
${issuing_address} and ${address_to_freeze}`)
return
}
// Send a TrustSet transaction to set an individual freeze -------------------
// Construct a TrustSet, preserving our existing limit value
const trust_set = {
"TransactionType": 'TrustSet',
"Account": issuing_address,
"LimitAmount": {
"value": trustline.limit,
"currency": trustline.currency,
"issuer": trustline.account
},
"Flags": xrpl.TrustSetFlags.tfSetFreeze
}
// Best practice for JavaScript users: use validate(tx_json) to confirm
// that a transaction is well-formed or throw ValidationError if it isn't.
xrpl.validate(trust_set)
console.log('Submitting TrustSet tx:', trust_set)
const result = await client.submitAndWait(trust_set, { wallet: wallet })
console.log("Transaction result:", result)
// Confirm trust line status -------------------------------------------------
const account_lines_2 = await client.request({
"command": "account_lines",
"account": issuing_address,
"peer": address_to_freeze,
"ledger_index": "validated"
})
const trustlines_2 = account_lines_2.result.lines
let line = null
for (let i = 0; i < trustlines_2.length; i++) {
if(trustlines_2[i].currency === currency_to_freeze) {
line = trustlines_2[i]
console.log(`Status of ${currency_to_freeze} line between
${issuing_address} and ${address_to_freeze}:
${JSON.stringify(line, null, 2)}`)
if (line.freeze === true) {
console.log(`✅ Line is frozen.`)
} else {
console.error(`❌ Line is NOT FROZEN.`)
}
}
}
if (line === null) {
console.error(`Couldn't find a ${CURRENCY_TO_FREEZE} line between
${issuing_address} and ${address_to_freeze}.`)
}
// Investigate ---------------------------------------------------------------
console.log(`You would investigate whatever prompted you to freeze the
trust line now... (This script waits 5000ms to end the freeze.)`)
await new Promise(resolve => setTimeout(resolve, 5000))
// Clear the individual freeze -----------------------------------------------
// We're reusing our TrustSet transaction from earlier with a different flag.
trust_set.Flags = xrpl.TrustSetFlags.tfClearFreeze
// Submit a TrustSet transaction to clear an individual freeze ---------------
console.log('Submitting TrustSet tx:', trust_set)
const result2 = await client.submitAndWait(trust_set, { wallet: wallet })
console.log("Transaction result:", result2)
console.log("Finished submitting. Now disconnecting.")
await client.disconnect()
// End main()
}
main().catch(console.error)

View File

@@ -1,104 +0,0 @@
// Dependencies for Node.js.
// In browsers, use <script> tags as in the example demo.html.
if (typeof module !== "undefined") {
// gotta use var here because const/let are block-scoped to the if statement.
var xrpl = require('xrpl')
}
async function main() {
// Connect -------------------------------------------------------------------
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
await client.connect()
// Get credentials from the Testnet Faucet ------------------------------------
console.log("Requesting an address from the Testnet faucet...")
const { wallet, balance } = await client.fundWallet()
// Look up current state of a trust line --------------------------------------
const issuing_address = wallet.address
const address_to_freeze = 'rUpy3eEg8rqjqfUoLeBnZkscbKbFsKXC3v'
const currency_to_freeze = 'USD'
const account_lines = {
command: 'account_lines',
account: issuing_address,
peer: address_to_freeze,
}
console.log('Looking up', currency_to_freeze, 'trust line from',
issuing_address, 'to', address_to_freeze)
const data = await client.request(account_lines)
const trustlines = data.result.lines
// Find the trust line for our currency_to_freeze ------------------------------
let trustline = null
for (let i = 0; i < trustlines.length; i++) {
if(trustlines[i].currency === currency_to_freeze) {
trustline = trustlines[i]
break
}
}
// Prepare a TrustSet transaction to create or modify the target trust line ----
let trust_set = null
if(trustline === null) {
console.log('Trustline not found, making a default one')
trust_set = {
TransactionType: 'TrustSet',
Account: issuing_address,
LimitAmount: {
value: '0',
currency: currency_to_freeze,
issuer: address_to_freeze,
},
}
} else {
console.log('Found existing trustline: ', trustline)
trust_set = {
TransactionType: 'TrustSet',
Account: issuing_address,
LimitAmount: {
value: trustline.limit,
currency: trustline.currency,
issuer: trustline.account
},
}
}
// Set a flag to freeze the trust line --------------------------------------------
trust_set.Flags = xrpl.TrustSetFlags.tfSetFreeze
// Best practice for JS users - validate checks if a transaction is well-formed
xrpl.validate(trust_set)
// Submit a TrustSet transaction to set an individual freeze ----------------------
console.log('Submitting TrustSet tx:', trust_set)
const result = await client.submitAndWait(trust_set, { wallet: wallet })
console.log("Submitted TrustSet!")
// Investigate --------------------------------------------------------------------
console.log(
`You would investigate whatever prompted you to freeze the trust line now...`)
await new Promise(resolve => setTimeout(resolve, 5000))
// Clear the individual freeze ----------------------------------------------------
// We're reusing our TrustSet transaction from earlier with a different flag
trust_set.Flags = xrpl.TrustSetFlags.tfClearFreeze
// Submit a TrustSet transaction to clear an individual freeze --------------------
console.log('Submitting TrustSet tx:', trust_set)
const result2 = await client.submitAndWait(trust_set, { wallet: wallet })
console.log("Submitted TrustSet!")
console.log("Finished submitting. Now disconnecting.")
await client.disconnect()
// End main()
}
main().catch(console.error)

View File

@@ -73,7 +73,7 @@ For example:
_JavaScript_
{{ include_code("_code-samples/freeze/set-no-freeze.js", start_with="// Submit an AccountSet transaction", end_before="// Done", language="js") }}
{{ include_code("_code-samples/freeze/js/set-no-freeze.js", start_with="// Submit an AccountSet transaction", end_before="// Done", language="js") }}
_WebSocket_
@@ -122,7 +122,7 @@ After the transaction is validated, you can check your account's settings to con
_JavaScript_
{{ include_code("_code-samples/freeze/check-no-freeze.js", start_with="// Request account info", end_before="await client.disconnect()", language="js") }}
{{ include_code("_code-samples/freeze/js/check-no-freeze.js", start_with="// Request account info", end_before="await client.disconnect()", language="js") }}
_WebSocket_

View File

@@ -78,7 +78,7 @@ For example:
_JavaScript_
{{ include_code("_code-samples/freeze/set-global-freeze.js", language="js", start_with="// Prepare an AccountSet", end_before="// Investigate") }}
{{ include_code("_code-samples/freeze/js/set-global-freeze.js", language="js", start_with="// Prepare an AccountSet", end_before="// Investigate") }}
_WebSocket_
@@ -125,7 +125,7 @@ After the transaction is validated, you can check your issuing account's setting
_JavaScript_
{{ include_code("_code-samples/freeze/check-global-freeze.js", language="js", start_with="// Request account info", end_before="await client.disconnect()") }}
{{ include_code("_code-samples/freeze/js/check-global-freeze.js", language="js", start_with="// Request account info", end_before="await client.disconnect()") }}
_WebSocket_
@@ -202,7 +202,7 @@ For example:
_JavaScript_
{{ include_code("_code-samples/freeze/set-global-freeze.js", language="js", start_with="// Now we disable", end_before="// Global freeze disabled") }}
{{ include_code("_code-samples/freeze/js/set-global-freeze.js", language="js", start_with="// Now we disable", end_before="// Global freeze disabled") }}
_WebSocket_

View File

@@ -2,7 +2,9 @@
html: freeze-a-trust-line.html
parent: use-tokens.html
blurb: Freeze an individual holder of a token.
embed_ripple_lib: true
filters:
- interactive_steps
- include_code
labels:
- Tokens
@@ -23,6 +25,9 @@ This tutorial shows the steps to [freeze an individual trust line](freezes.html#
- This tutorial assumes **you have already [issued a token](issue-a-fungible-token.html)** in the XRP Ledger.
- You **cannot** have enabled the [No Freeze setting](freezes.html#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="assets/js/tutorials/freeze-individual-line.js"></script>
## Example Code
@@ -37,6 +42,8 @@ Complete sample code for all of the steps of this tutorial is available under th
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](issuing-and-operational-addresses.html), you need the keys to the _cold address_, which is the **issuer** of the token.
{% include '_snippets/interactive-tutorials/generate-step.md' %}
### {{n.next()}}. 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](client-libraries.html):
@@ -55,6 +62,78 @@ _WebSocket_
<!-- MULTICODE_BLOCK_END -->
For purposes of this tutorial, use the following interface to connect and perform setup:
{% include '_snippets/interactive-tutorials/connect-step.md' %}
### {{n.next()}}. Choose Trust Line
You can only freeze one trust line per transaction, so you need to know which one you want. A trust line 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](trust-lines-and-issuing.html) 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:
<!-- MULTICODE_BLOCK_START -->
_JavaScript_
{{ include_code("_code-samples/freeze/js/set-individual-freeze.js", language="js", start_with="// Look up current trust lines", end_before="// Send a TrustSet") }}
_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"
}
```
<!-- MULTICODE_BLOCK_END -->
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:
{{ start_step("Choose Trust Line")}}
<div class="loader collapse" id="trust-line-setup-loader"><img class="throbber" src="assets/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="assets/img/xrp-loader-96.png">Looking...</div>
<div class="output-area"></div>
{{ end_step() }}
### {{n.next()}}. Send TrustSet Transaction to Freeze the Trust Line
@@ -76,7 +155,7 @@ As always, to send a transaction, you _prepare_ it by filling in all the necessa
_JavaScript_
{{ include_code("_code-samples/freeze/set-individual-freeze.js", language="js", start_with="// Prepare a TrustSet", end_before="// Investigate") }}
{{ include_code("_code-samples/freeze/js/set-individual-freeze.js", language="js", start_with="// Send a TrustSet", end_before="// Investigate") }}
_WebSocket_
@@ -103,11 +182,22 @@ _WebSocket_
<!-- MULTICODE_BLOCK_END -->
{{ start_step("Send TrustSet to Freeze") }}
<button class="btn btn-primary previous-steps-required send-trustset" data-wait-step-name="Wait" data-action="start_freeze">Send TrustSet (Freeze)</button>
<div class="loader collapse"><img class="throbber" src="assets/img/xrp-loader-96.png">Sending...</div>
<div class="output-area"></div>
{{ end_step() }}
**Note:** If you want to freeze multiple trust lines in different currencies with the same counterparty, repeat this step for each one, choosing a different currency code each time. It is possible to send several transactions in a single ledger if you use different [sequence numbers](basic-data-types.html#account-sequence) for each. <!--{# TODO: link rapid/batch submission guidelines when https://github.com/XRPLF/xrpl-dev-portal/issues/1025 is done #}-->
### {{n.next()}}. 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](reliable-transaction-submission.html).)
{{ start_step("Wait") }}
{% include '_snippets/interactive-tutorials/wait-step.md' %}
{{ end_step() }}
### {{n.next()}}. Check Trust Line Freeze Status
@@ -120,13 +210,13 @@ At this point, the trust line from the counterparty should be frozen. You can ch
**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.
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:
<!-- MULTICODE_BLOCK_START -->
_JavaScript_
{{ include_code("_code-samples/freeze/check-individual-freeze.js", language="js", start_with="// Look up current state", end_before="await client.disconnect()") }}
{{ include_code("_code-samples/freeze/js/set-individual-freeze.js", language="js", start_with="// Confirm trust line status", end_before="// Investigate") }}
_WebSocket_
@@ -167,6 +257,13 @@ Example Response:
<!-- MULTICODE_BLOCK_END -->
{{ start_step("Check Freeze Status") }}
<button id="confirm-settings" class="btn btn-primary previous-steps-required">Check Trust Line</button>
<div class="loader collapse"><img class="throbber" src="assets/img/xrp-loader-96.png">Checking...</div>
<div class="output-area"></div>
{{ end_step() }}
### {{n.next()}}. (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](trustset.html#trustset-flags). The other fields of the transaction should be the same as when you froze the trust line:
@@ -187,7 +284,7 @@ As always, to send a transaction, you _prepare_ it by filling in all the necessa
_JavaScript_
{{ include_code("_code-samples/freeze/set-individual-freeze.js", language="js", start_with="// Clear the individual", end_before="// End main") }}
{{ include_code("_code-samples/freeze/js/set-individual-freeze.js", language="js", start_with="// Clear the individual", end_before="// End main") }}
_WebSocket_
@@ -214,10 +311,21 @@ _WebSocket_
<!-- MULTICODE_BLOCK_END -->
{{ start_step("Send TrustSet to End Freeze") }}
<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>
<div class="loader collapse"><img class="throbber" src="assets/img/xrp-loader-96.png">Sending...</div>
<div class="output-area"></div>
{{ end_step() }}
### {{n.next()}}. Wait for Validation
As before, wait for the previous transaction to be validated by consensus before continuing.
As before, wait for the transaction to be validated by consensus.
{{ start_step("Wait (again)") }}
{% include '_snippets/interactive-tutorials/wait-step.md' %}
{{ end_step() }}
## See Also