diff --git a/assets/js/interactive-tutorial.js b/assets/js/interactive-tutorial.js index b3e676b677..f280101c95 100644 --- a/assets/js/interactive-tutorial.js +++ b/assets/js/interactive-tutorial.js @@ -114,6 +114,7 @@ function complete_step_by_id(step_id) { ".interactive-block").eq(0).find(".previous-steps-required") next_ui.prop("title", "") next_ui.prop("disabled", false) + next_ui.removeClass("disabled") } /** @@ -360,7 +361,6 @@ function setup_wait_steps() { min_ledger, max_ledger }) - console.log(tx_result) if (tx_result.validated) { status_box.html( diff --git a/assets/js/tutorials/issue-a-token.js b/assets/js/tutorials/issue-a-token.js index 1b1914d3ee..8729572913 100644 --- a/assets/js/tutorials/issue-a-token.js +++ b/assets/js/tutorials/issue-a-token.js @@ -174,7 +174,7 @@ $(document).ready(() => { "Flags": flags } - generic_full_send(event, cold_settings_tx, cold_secret) + await generic_full_send(event, cold_settings_tx, cold_secret) complete_step("Configure Issuer") } catch(err) { @@ -212,7 +212,7 @@ $(document).ready(() => { "Flags": flags } - generic_full_send(event, hot_settings_tx, hot_secret) + await generic_full_send(event, hot_settings_tx, hot_secret) complete_step("Configure Hot Address") } catch(err) { @@ -256,7 +256,7 @@ $(document).ready(() => { "value": limit } } - generic_full_send(event, trust_set_tx, hot_secret) + await generic_full_send(event, trust_set_tx, hot_secret) complete_step("Make Trust Line") } catch(err) { @@ -301,7 +301,7 @@ $(document).ready(() => { if (use_dest_tag) { send_token_tx["DestinationTag"] = dest_tag } - generic_full_send(event, send_token_tx, cold_secret) + await generic_full_send(event, send_token_tx, cold_secret) complete_step("Send Token") } catch(err) { diff --git a/assets/js/tutorials/require-destination-tags.js b/assets/js/tutorials/require-destination-tags.js index 15199b8ba1..40ac243793 100644 --- a/assets/js/tutorials/require-destination-tags.js +++ b/assets/js/tutorials/require-destination-tags.js @@ -4,16 +4,21 @@ $(document).ready(() => { // 3. Send AccountSet -------------------------------------------------------- - $("#send-accountset").click( (event) => { + $("#send-accountset").click( async (event) => { const address = get_address(event) if (!address) {return} - generic_full_send(event, { - "TransactionType": "AccountSet", - "Account": address, - "SetFlag": 1 // RequireDest - }) - complete_step("Send AccountSet") + try { + await generic_full_send(event, { + "TransactionType": "AccountSet", + "Account": address, + "SetFlag": 1 // RequireDest + }) + complete_step("Send AccountSet") + } catch(err) { + block.find(".loader").hide() + show_error(block, err) + } }) // 4. Wait for Validation: handled by interactive-tutorial.js and by the diff --git a/content/_code-samples/issue-a-token/demo.html b/content/_code-samples/issue-a-token/js/demo.html similarity index 100% rename from content/_code-samples/issue-a-token/demo.html rename to content/_code-samples/issue-a-token/js/demo.html diff --git a/content/_code-samples/issue-a-token/issue-a-token.js b/content/_code-samples/issue-a-token/js/issue-a-token.js similarity index 100% rename from content/_code-samples/issue-a-token/issue-a-token.js rename to content/_code-samples/issue-a-token/js/issue-a-token.js diff --git a/content/_code-samples/issue-a-token/package.json b/content/_code-samples/issue-a-token/js/package.json similarity index 100% rename from content/_code-samples/issue-a-token/package.json rename to content/_code-samples/issue-a-token/js/package.json diff --git a/content/_code-samples/issue-a-token/yarn.lock b/content/_code-samples/issue-a-token/js/yarn.lock similarity index 100% rename from content/_code-samples/issue-a-token/yarn.lock rename to content/_code-samples/issue-a-token/js/yarn.lock diff --git a/content/_code-samples/issue-a-token/py/issue-a-token.py b/content/_code-samples/issue-a-token/py/issue-a-token.py new file mode 100644 index 0000000000..2bfe9767ba --- /dev/null +++ b/content/_code-samples/issue-a-token/py/issue-a-token.py @@ -0,0 +1,108 @@ +# Stand-alone code sample for the "issue a token" tutorial: +# https://xrpl.org/issue-a-fungible-token.html +# License: https://github.com/XRPLF/xrpl-dev-portal/blob/master/LICENSE + +# Connect ---------------------------------------------------------------------- +import xrpl +testnet_url = "https://s.altnet.rippletest.net:51234" +client = xrpl.clients.JsonRpcClient(testnet_url) + + +# Get credentials from the Testnet Faucet -------------------------------------- +# For production, instead create a Wallet instance +faucet_url = "https://faucet.altnet.rippletest.net/accounts" +print("Getting 2 new accounts from the Testnet faucet...") +from xrpl.wallet import generate_faucet_wallet +cold_wallet = generate_faucet_wallet(client, debug=True) +hot_wallet = generate_faucet_wallet(client, debug=True) + + +# Configure issuer (cold address) settings ------------------------------------- +cold_settings_tx = xrpl.models.transactions.AccountSet( + account=cold_wallet.classic_address, + transfer_rate=0, + tick_size=5, + domain=bytes.hex("example.com".encode("ASCII")), + set_flag=xrpl.models.transactions.AccountSetFlag.ASF_DEFAULT_RIPPLE, +) +cst_prepared = xrpl.transaction.safe_sign_and_autofill_transaction( + transaction=cold_settings_tx, + wallet=cold_wallet, + client=client, +) +print("Sending cold address AccountSet transaction...") +response = xrpl.transaction.send_reliable_submission(cst_prepared, client) +print(response) + + +# Configure hot address settings ----------------------------------------------- +hot_settings_tx = xrpl.models.transactions.AccountSet( + account=hot_wallet.classic_address, + set_flag=xrpl.models.transactions.AccountSetFlag.ASF_REQUIRE_AUTH, +) +hst_prepared = xrpl.transaction.safe_sign_and_autofill_transaction( + transaction=hot_settings_tx, + wallet=hot_wallet, + client=client, +) +print("Sending hot address AccountSet transaction...") +response = xrpl.transaction.send_reliable_submission(hst_prepared, client) +print(response) + + +# Create trust line from hot to cold address ----------------------------------- +currency_code = "FOO" +trust_set_tx = xrpl.models.transactions.TrustSet( + account=hot_wallet.classic_address, + limit_amount=xrpl.models.amounts.issued_currency_amount.IssuedCurrencyAmount( + currency=currency_code, + issuer=cold_wallet.classic_address, + value="10000000000", # Large limit, arbitrarily chosen + ) +) +ts_prepared = xrpl.transaction.safe_sign_and_autofill_transaction( + transaction=trust_set_tx, + wallet=hot_wallet, + client=client, +) +print("Creating trust line from hot address to issuer...") +response = xrpl.transaction.send_reliable_submission(ts_prepared, client) +print(response) + + +# Send token ------------------------------------------------------------------- +issue_quantity = "3840" +send_token_tx = xrpl.models.transactions.Payment( + account=cold_wallet.classic_address, + destination=hot_wallet.classic_address, + amount=xrpl.models.amounts.issued_currency_amount.IssuedCurrencyAmount( + currency=currency_code, + issuer=cold_wallet.classic_address, + value=issue_quantity + ) +) +pay_prepared = xrpl.transaction.safe_sign_and_autofill_transaction( + transaction=send_token_tx, + wallet=cold_wallet, + client=client, +) +print(f"Sending {issue_quantity} {currency_code} to {hot_wallet.classic_address}...") +response = xrpl.transaction.send_reliable_submission(pay_prepared, client) +print(response) + + +# Check balances --------------------------------------------------------------- +print("Getting hot address balances...") +response = client.request(xrpl.models.requests.AccountLines( + account=hot_wallet.classic_address, + ledger_index="validated", +)) +print(response) + +print("Getting cold address balances...") +response = client.request(xrpl.models.requests.GatewayBalances( + account=cold_wallet.classic_address, + ledger_index="validated", + hotwallet=[hot_wallet.classic_address] +)) +print(response) diff --git a/content/tutorials/use-tokens/issue-a-fungible-token.md b/content/tutorials/use-tokens/issue-a-fungible-token.md index 1dc3cbe52f..a96656e034 100644 --- a/content/tutorials/use-tokens/issue-a-fungible-token.md +++ b/content/tutorials/use-tokens/issue-a-fungible-token.md @@ -17,9 +17,9 @@ Anyone can issue various types of tokens in the XRP Ledger, ranging from informa - 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](reserves.html) including the additional reserve for a trust line. -- You need a connection to the XRP Ledger network. +- You need a connection to the XRP Ledger network. As shown in this tutorial, you can use public servers for testing. -This page provides examples that use [ripple-lib for JavaScript](get-started-with-rippleapi-for-javascript.html). Since JavaScript works in the web browser, you can read along and use the interactive steps without any setup. +This page provides examples that use [ripple-lib for JavaScript](get-started-with-rippleapi-for-javascript.html) or [xrpl-py for Python](get-started-using-python.html). You can also read along and use the interactive steps in your browser without any setup. @@ -59,7 +59,11 @@ When you're [building actual production-ready software](production-readiness.htm You must be connected to the network to submit transactions to it. -The following code uses a [ripple-lib for JavaScript](rippleapi-reference.html) instance to connect to a public XRP Ledger Testnet server: +The following code shows how to connect to a public XRP Ledger Testnet server a supported [client library](client-libraries.html): + + + +_JavaScript_ ```js ripple = require('ripple-lib') // Node.js only. Use a