diff --git a/assets/js/interactive-tutorial.js b/assets/js/interactive-tutorial.js index 01d6a4e473..48dcf46d50 100644 --- a/assets/js/interactive-tutorial.js +++ b/assets/js/interactive-tutorial.js @@ -186,29 +186,36 @@ function setup_generate_step() { const faucet_url = $("#generate-creds-button").data("fauceturl") try { - // destination not defined - API will create account. - const data = await call_faucet(faucet_url, undefined, event) + const wallet = xrpl.Wallet.generate("ed25519") + const data = await call_faucet(faucet_url, wallet.address, event) block.find(".loader").hide() block.find(".output-area").html(`
${tl("Populated this page's examples with these credentials.")}
`) + if (creds_updated) { + block.find(".output-area").append(`${tl("Populated this page's examples with these credentials.")}
`) + } complete_step("Generate") @@ -278,7 +285,7 @@ async function call_faucet(faucet_url, destination, event) { step: block.data("stepnumber"), totalsteps: block.data("totalsteps"), }; - //pass in plain text instead of HEX- the API will encode. + //pass in plain text instead of HEX- the API will encode. const memo = { data: JSON.stringify(tutorial_info, null, 0), format: "application/json", // application/json @@ -288,9 +295,7 @@ async function call_faucet(faucet_url, destination, event) { }; const body = {}; - if (typeof destination != "undefined") { - body["destination"] = destination; - } + body["destination"] = destination; body["memos"] = [memo]; const response = await fetch(faucet_url, { diff --git a/assets/js/tutorials/create-amm.js b/assets/js/tutorials/create-amm.js new file mode 100644 index 0000000000..df13add292 --- /dev/null +++ b/assets/js/tutorials/create-amm.js @@ -0,0 +1,269 @@ +// 1. Generate +// 2. Connect +// The code for these steps is handled by interactive-tutorial.js +$(document).ready(() => { + + const EXPLORER = $("#connect-button").data("explorer") + + $("#get-foo").click( async (event) => { + const block = $(event.target).closest(".interactive-block") + const wallet = get_wallet(event) + if (!wallet) {return} + + const currency_code = "FOO" + const issue_quantity = "1000" + + block.find(".loader").show() + show_log(block, "Funding an issuer address with the faucet...
") + const issuer = (await api.fundWallet()).wallet + show_log(block, `Got issuer ${issuer.address}.
`) + $(".foo-issuer").text(issuer.address) // Update display in the "Create AMM" step + + // Enable issuer DefaultRipple ---------------------------------------------- + const issuer_setup_tx = { + "TransactionType": "AccountSet", + "Account": issuer.address, + "SetFlag": xrpl.AccountSetAsfFlags.asfDefaultRipple + } + add_memo(event, issuer_setup_tx) + const issuer_setup_result = await api.submitAndWait(issuer_setup_tx, {autofill: true, wallet: issuer} ) + if (issuer_setup_result.result.meta.TransactionResult == "tesSUCCESS") { + show_log(block, `✅ Issuer DefaultRipple enabled
`) + } else { + show_error(block, `Error sending transaction:${pretty_print(issuer_setup_result)}`)
+ }
+
+ // Create trust line to issuer ----------------------------------------------
+ const trust_tx = {
+ "TransactionType": "TrustSet",
+ "Account": wallet.address,
+ "LimitAmount": {
+ "currency": currency_code,
+ "issuer": issuer.address,
+ "value": "10000000000" // Large limit, arbitrarily chosen
+ }
+ }
+ add_memo(event, trust_tx)
+ const trust_result = await api.submitAndWait(trust_tx, {autofill: true, wallet: wallet})
+ if (trust_result.result.meta.TransactionResult == "tesSUCCESS") {
+ show_log(block, ``)
+ } else {
+ show_error(block, `Error sending transaction: ${pretty_print(trust_result)}`)
+ }
+
+ // Issue tokens -------------------------------------------------------------
+ const issue_tx = {
+ "TransactionType": "Payment",
+ "Account": issuer.address,
+ "Amount": {
+ "currency": currency_code,
+ "value": issue_quantity,
+ "issuer": issuer.address
+ },
+ "Destination": wallet.address
+ }
+ add_memo(event, issue_tx)
+ const issue_result = await api.submitAndWait(issue_tx, {autofill: true, wallet: issuer})
+ if (issue_result.result.meta.TransactionResult == "tesSUCCESS") {
+ show_log(block, ``)
+ $("#get-foo").data("foo-acquired", true).prop("disabled", true).addClass("disabled").addClass("done")
+ } else {
+ show_error(block, `Error sending transaction: ${pretty_print(issue_result)}`)
+ }
+ block.find(".loader").hide()
+
+ if ($("#get-foo").data("foo-acquired") && $("#buy-tst").data("tst-acquired")) {
+ complete_step("Acquire tokens")
+ }
+ })
+
+ $("#buy-tst").click( async (event) => {
+ const block = $(event.target).closest(".interactive-block")
+ const wallet = get_wallet(event)
+ if (!wallet) {return}
+ block.find(".loader").show()
+
+ const tx_json = {
+ "TransactionType": "OfferCreate",
+ "Account": wallet.address,
+ "TakerPays": {
+ currency: "TST",
+ issuer: "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd",
+ value: "25"
+ },
+ "TakerGets": xrpl.xrpToDrops(25*10*1.16)
+ }
+ add_memo(event, tx_json)
+
+ const offer_result = await api.submitAndWait(tx_json, {autofill: true, wallet: wallet})
+
+ if (offer_result.result.meta.TransactionResult == "tesSUCCESS") {
+ show_log(block, ``)
+ const balance_changes = xrpl.getBalanceChanges(offer_result.result.meta)
+ for (const bc of balance_changes) {
+ if (bc.account != wallet.address) {continue}
+ for (const bal of bc.balances) {
+ if (bal.currency == "TST") {
+ show_log(block, `Got ${bal.value} ${bal.currency}.${bal.issuer}.
`) + break + } + } + break + } + $("#buy-tst").data("tst-acquired", true).prop("disabled", true).addClass("disabled").addClass("done") + } else { + show_error(block, `Transaction failed:
${pretty_print(offer_result)}`)
+ }
+ block.find(".loader").hide()
+
+ if ($("#get-foo").data("foo-acquired") && $("#buy-tst").data("tst-acquired")) {
+ complete_step("Acquire tokens")
+ }
+ })
+
+ $("#check-for-amm").click( async (event) => {
+ const block = $(event.target).closest(".interactive-block")
+ const foo_issuer_address = $("#issuer-address").text()
+
+ block.find(".output-area").html("")
+ block.find(".loader").show()
+ try {
+ const amm_info = await api.request({
+ "command": "amm_info",
+ "asset": {
+ "currency": "TST",
+ "issuer": "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd"
+ },
+ "asset2": {
+ "currency": "FOO",
+ "issuer": foo_issuer_address
+ },
+ "ledger_index": "validated"
+ })
+ show_log(block, `${pretty_print}amm_info`)
+ } catch(err) {
+ if (err.data.error === 'actNotFound') {
+ show_log(block, `✅ No AMM exists yet for the pair + FOO.${foo_issuer_address} / + TST.rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd.`) + complete_step("Check for AMM") + } else { + show_error(block, err) + } + } + block.find(".loader").hide() + }) + + $("#look-up-ammcreate-cost").click( async (event) => { + const block = $(event.target).closest(".interactive-block") + block.find(".loader").show() + let amm_fee_drops = "5000000" + try { + const ss = await api.request({"command": "server_state"}) + amm_fee_drops = ss.result.state.validated_ledger.reserve_inc.toString() + show_log(block, `
Current AMMCreate transaction cost: ${xrpl.dropsToXrp(amm_fee_drops)} XRP (${amm_fee_drops} drops)
`) + complete_step("Look up AMMCreate cost") + } catch(err) { + show_error(block, `Error looking up AMMCreate tx cost: ${err}`) + } + block.find(".loader").hide() + }) + + $("#create-amm").click( async (event) => { + const block = $(event.target).closest(".interactive-block") + const wallet = get_wallet(event) + if (!wallet) {return} + + amm_fee_drops = $("#ammcreate-cost-drops").text() + if (!amm_fee_drops) {return} + + const asset_amount = $("#asset-amount").val() + const asset2_amount = $("#asset2-amount").val() + const asset2_issuer_address = $("#issuer-address").text() + const trading_fee = Math.floor($("#trading-fee").val()*1000) // Convert from % + + const ammcreate_tx = { + "TransactionType": "AMMCreate", + "Account": wallet.address, + "Amount": { + currency: "TST", + issuer: "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd", + value: asset_amount + }, + "Amount2": { + "currency": "FOO", + "issuer": asset2_issuer_address, + "value": asset2_amount + }, + "TradingFee": 500, // 0.5% + "Fee": amm_fee_drops + } + add_memo(event, ammcreate_tx) + const ammcreate_result = await api.submitAndWait(ammcreate_tx, {autofill: true, wallet: wallet, fail_hard: true}) + if (ammcreate_result.result.meta.TransactionResult == "tesSUCCESS") { + show_log(block, ` +${pretty_print(ammcreate_result)}`)
+ complete_step("Create AMM")
+ } else {
+ throw `Error sending transaction: ${ammcreate_result}`
+ }
+ block.find(".loader").hide()
+ })
+
+ $("#check-amm-info").click( async (event) => {
+ const block = $(event.target).closest(".interactive-block")
+ const foo_issuer_address = $("#issuer-address").text()
+
+ block.find(".output-area").html("")
+ block.find(".loader").show()
+ try {
+ const amm_info = await api.request({
+ "command": "amm_info",
+ "asset": {
+ "currency": "TST",
+ "issuer": "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd"
+ },
+ "asset2": {
+ "currency": "FOO",
+ "issuer": foo_issuer_address
+ },
+ "ledger_index": "validated"
+ })
+ show_log(block, `AMM Info:
${pretty_print(amm_info)}`)
+ const lp_token = amm_info.result.amm.lp_token
+ show_log(block, `The AMM account ${lp_token.issuer} has ${lp_token.value} total
+ LP tokens outstanding, and uses the currency code ${lp_token.currency}.
In its pool, the AMM holds ${amount.value} ${amount.currency}.${amount.issuer} + and ${amount2.value} ${amount2.currency}.${amount2.issuer}
`) + complete_step("Check AMM info") + } catch(err) { + show_error(block, err) + } + block.find(".loader").hide() + }) + + $("#check-trust-lines").click( async (event) => { + const block = $(event.target).closest(".interactive-block") + const address = get_address() + if (!address) {return} + + block.find(".output-area").html("") + block.find(".loader").show() + try { + const account_lines = await api.request({ + "command": "account_lines", + "account": address, + "ledger_index": "validated" + }) + show_log(block, `Trust lines:
${pretty_print(account_lines)}`)
+ complete_step("Check trust lines")
+ } catch(err) {
+ show_error(block, err)
+ }
+ block.find(".loader").hide()
+ })
+
+})
+
diff --git a/content/_code-samples/create-amm/js/connect.js b/content/_code-samples/create-amm/js/connect.js
index 5ee463ea25..483ebb0cbf 100644
--- a/content/_code-samples/create-amm/js/connect.js
+++ b/content/_code-samples/create-amm/js/connect.js
@@ -1,8 +1,8 @@
// In browsers, use a