<html>

<head>
  <title>XRPL Token Test Harness</title>
  <link href='https://fonts.googleapis.com/css?family=Work Sans' rel='stylesheet'>
  <script src='https://unpkg.com/xrpl@2.6.0'></script>
  <script>
    if (typeof module !== "undefined") {
      const xrpl = require('xrpl')
    }
  </script>

</head>

 <div id="selectLedger">
  <div class="appField">
    <strong>Choose your ledger instance:</strong><br />
    <input type="radio" id="tn" name="server" value="wss://s.altnet.rippletest.net:51233" checked>
    <label for="testnet">Testnet</label>
    &nbsp;&nbsp;
    <input type="radio" id="dn" name="server" value="wss://s.devnet.rippletest.net:51233">
    <label for="devnet">Devnet</label>
  </div>
  <div class="appField">
    <button type="button" onClick="getAccountsFromSeeds()">Get Accounts From Seeds</button><br />
    <textarea id="seeds" cols="40" rows="2"></textarea>
  </div>
</div>
<div id="flexContainer">
<div class="flexColumn">  
<div id="standbyApp">
  <button type="button" onClick="getAccount('standby')">Create Standby Account</button><br />

  <h2>Standby Account Info</h2>
  <div class="appField">Standby Account<br />
    <div id="standbyAccountField" class="appValue"></div>
  </div>
  <div class="appField">Public Key<br />
    <div id="standbyPubKeyField" class="appValue"></div>
  </div>
  <div class="appField">Private Key<br />
    <div id="standbyPrivKeyField" class="appValue"></div>
  </div>
  <div class="appField"> Seed<br />
    <div id="standbySeedField" class="appValue"></div>
  </div>
  <div class="appField"> XRP Balance<br />
    <div id="standbyBalanceField" class="appValue"></div>
  </div>

  <div id="standbyTransact">
    <p><strong>Send XRP</strong></p>
    <div class="appField">
      Amount<br />
      <input id="standbyAmountField" class="appValue"></input>
    </div>
    <div class="appField">
      Destination Account <br />
      <input id="standbyDestinationField" class="appValue"></input>
    </div>
    <p align="right">
      <button type="button" onClick="sendXRP()">Send XRP &#8594;</button>
    </p>
    <p><strong>Transaction Log</strong></p>
    <div id="standbyResultField"></div>
  </div>
  </div>

</div>
  <div class="flexColumn">
<div id="operationalApp">
  <button type="button" onClick="getAccount('operational')">Create Operational Account</button><br />

  <h2>Operational Account Info</h2>
  <div class="appField">Operational Account<br />
    <div id="operationalAccountField" class="appValue"></div>
  </div>
  <div class="appField">Public Key<br />
    <div id="operationalPubKeyField" class="appValue"></div>
  </div>
  <div class="appField">Private Key<br />
    <div id="operationalPrivKeyField" class="appValue"></div>
  </div>
  <div class="appField"> Seed<br />
    <div id="operationalSeedField" class="appValue"></div>
  </div>
  <div class="appField"> XRP Balance<br />
    <div id="operationalBalanceField" class="appValue"></div>
  </div>

  <div id="operationalTransact">
    <p><strong>Send XRP</strong></p>
    <div class="appField">
      Amount<br />
      <input id="operationalAmountField" class="appValue"></input>
    </div>
    <div class="appField">
      Destination Account <br />
      <input id="operationalDestinationField" class="appValue"></input>
    </div>
    <p align="right">
      <button type="button" onClick="oPsendXRP()"> &#8592; Send XRP</button>
    </p>
    <p><strong>Transaction Log</strong></p>
    <div id="operationalResultField"></div>
  </div>

</div>
</div>
</div>
</body>

</html>
body {
  font-family: "Work Sans", sans-serif;
  padding: 20px;
  background: #fafafa;
  font-size: 0.8em;
}
h1 {
  font-weight: bold;
}
button {
  padding: 12px;
  margin-bottom: 8px;
  font-size: 1em;
  background: #fff;
  border-radius: 0.5em;
  border: solid 2px #444;
}
button {
  font-weight: bold;
  font-family: "Work Sans", sans-serif;
}
button:hover {
  background: #eee;
  cursor: pointer;
}
td {
  vertical-align: top;
  padding-right: 10px;
}
#selectLedger {
  background: #ff78bb;
  padding: 1em 1em 0 1em;
  border-radius: 1em;
  width: 80%;
  margin: 0 0 1em 0;
  font-size: 1.25em;
  line-height: 2em;
}

.appField {
  vertical-align: top;
  display: inline-block;
  margin: 0 1em 0 0;
}
.appValue {
  display: inline-block;
  overflow-wrap: break-word;
  padding: 0.25em;
  height: 2.5em;
  font-size: 10px;
  background: #efefef;
  min-width: 100px;
  max-width:300px;
  border-radius: 0.5em;
  margin: 0.25em 0 0.5em 0;
}
#flexContainer{
  display:flex;
  align-content:flex-start;
  margin:0 -.5em;
}
.flexColumn{
    width:100%;
  flex:1 0 50%;
  max-width:50%;
  margin:0 .5em;
}

#standbyApp {
  background: #86e3b0;
  padding: 1.5em;
  border-radius: 1em;
}
#standbyTransact {
  display: inline-block;
  background: #42df89;
  border-radius: 0.5em;
  display: inline-block;
  margin: 0.5em 0;
  padding: 0 1.5em;
  min-width: 90%;
}

#standbyResultField {
  display: inline-block;
  padding: 0.25em;
  border: solid 1px white;
  height: 2em;
  font-size: 1em;
  background: #efefef;
  width: 100%;
  border-radius: 3px;
  margin: 0.25em 0 0.5em 0;
  height: 100px;
  overflow-y: scroll;
}

#operationalApp {
  background: #58bbfd;
  padding: 1.5em;
  border-radius: 1em;
}
#operationalTransact {
  display: inline-block;
  background: #19a3ff;
  border-radius: 0.5em;
  display: inline-block;
  margin: 0.5em 0;
  padding: 0 1.5em;
  min-width: 90%;
}
#operationalResultField {
  display: inline-block;
  padding: 0.25em;
  border: solid 1px white;
  height: 2em;
  font-size: 1em;
  background: #efefef;
  width: 100%;
  border-radius: 3px;
  margin: 0.25em 0 0.5em 0;
  height: 100px;
  overflow-y: scroll;
}
input {
  border: none;
}
// ************* Define HTML Form Fields as constants **************
const tn = document.getElementById("tn");
const dn = document.getElementById("dn");
const standbyResultField = document.getElementById("standbyResultField");
const operationalResultsField = document.getElementById("operationalResultField");
const standbyAccountField = document.getElementById("standbyAccountField");
const standbyPubKeyField = document.getElementById("standbyPubKeyField");
const standbyPrivKeyField = document.getElementById("standbyPrivKeyField");
const standbyBalanceField = document.getElementById("standbyBalanceField");
const standbySeedField = document.getElementById("standbySeedField");
const operationalAccountField = document.getElementById("operationalAccountField");
const operationalPubKeyField = document.getElementById("operationalPubKeyField");
const operationalPrivKeyField = document.getElementById("operationalPrivKeyField");
const operationalSeedField = document.getElementById("operationalSeedField");
const operationalBalanceField = document.getElementById("operationalBalanceField");
const seeds = document.getElementById("seeds");

// ************* Get the Preferred Network **************
function getNet() {
  let net;
  if (tn.checked) net = "wss://s.altnet.rippletest.net:51233";
  if (dn.checked) net = "wss://s.devnet.rippletest.net:51233";
  return net;
} // End of getNet()

// ************* Get Account *****************************
async function getAccount(type) {
  let net = getNet();

  const client = new xrpl.Client(net);
  results = "Connecting to " + net + "....<br/>";

  // This uses the default faucet for Testnet/Devnet
  let faucetHost = null;
  let amount = '930';
  if (type == "standby") {
    standbyResultField.innerHTML = results;
  } else {
    operationalResultField.innerHTML = results;
  }
  await client.connect();

  results += "\nConnected, funding wallet.<br/>";
  if (type == "standby") {
    standbyResultField.innerHTML = results;
  } else {
    operationalResultField.innerHTML = results;
  }

  // -----------------------------------Create and fund a test account wallet
  const my_wallet = (await client.fundWallet(null, {amount, faucetHost })).wallet;

  results += "\nGot a wallet.<br/>";
  if (type == "standby") {
    standbyResultField.innerHTML = results;
  } else {
    operationalResultField.innerHTML = results;
  }

  // -----------------------------------Get the current balance.
  const my_balance = await client.getXrpBalance(my_wallet.address);

  if (type == "standby") {
    standbyAccountField.innerHTML = my_wallet.address;
    standbyPubKeyField.innerHTML = my_wallet.publicKey;
    standbyPrivKeyField.innerHTML = my_wallet.privateKey;
    standbyBalanceField.innerHTML = await client.getXrpBalance(
      my_wallet.address
    );
    standbySeedField.innerHTML = my_wallet.seed;
    results += "\nStandby account created.<br/>";
    standbyResultField.innerHTML = results;
  } else {
    operationalAccountField.innerHTML = my_wallet.address;
    operationalPubKeyField.innerHTML = my_wallet.publicKey;
    operationalPrivKeyField.innerHTML = my_wallet.privateKey;
    operationalSeedField.innerHTML = my_wallet.seed;
    operationalBalanceField.innerHTML = await client.getXrpBalance(
      my_wallet.address
    );
    results += "\nOperational account created.<br/>";
    operationalResultField.innerHTML = results;
  }
  // --------------- Capture the seeds for both accounts for ease of reload.
  seeds.value =
    standbySeedField.innerHTML + "\n" + operationalSeedField.innerHTML;
  client.disconnect();
} // End of getAccount()

// *******************************************************
// ********** Get Accounts from Seeds ********************
// *******************************************************

async function getAccountsFromSeeds() {
  let net = getNet();
  const client = new xrpl.Client(net);
  results = "Connecting to " + getNet() + "....<br/>";
  standbyResultField.innerHTML = results;
  await client.connect();
  results += "\nConnected, finding wallets.<br/>";
  standbyResultField.innerHTML = results;

  // -----------------------------------Find the test account wallets
  var lines = seeds.value.split("\n");
  const standby_wallet = xrpl.Wallet.fromSeed(lines[0]);
  const operational_wallet = xrpl.Wallet.fromSeed(lines[1]);

  // -----------------------------------Get the current balance.
  const standby_balance = await client.getXrpBalance(standby_wallet.address);
  const operational_balance = await client.getXrpBalance(
    operational_wallet.address
  );

  // ------------------Populate the fields for Standby and Operational accounts
  standbyAccountField.innerHTML = standby_wallet.address;
  standbyPubKeyField.innerHTML = standby_wallet.publicKey;
  standbyPrivKeyField.innerHTML = standby_wallet.privateKey;
  standbySeedField.innerHTML = standby_wallet.seed;
  standbyBalanceField.innerHTML = await client.getXrpBalance(
    standby_wallet.address
  );

  operationalAccountField.innerHTML = operational_wallet.address;
  operationalPubKeyField.innerHTML = operational_wallet.publicKey;
  operationalPrivKeyField.innerHTML = operational_wallet.privateKey;
  operationalSeedField.innerHTML = operational_wallet.seed;
  operationalBalanceField.innerHTML = await client.getXrpBalance(
    operational_wallet.address
  );

  client.disconnect();
} // End of getAccountsFromSeeds()

// *******************************************************
// ******************** Send XRP *************************
// *******************************************************

async function sendXRP() {
  results = "Connecting to the selected ledger.<br/>";
  standbyResultField.innerHTML = results;
  let net = getNet();
  results = "Connecting to " + getNet() + "....<br/>";
  const client = new xrpl.Client(net);
  await client.connect();

  results += "\nConnected. Sending XRP.<br/>";
  standbyResultField.innerHTML = results;

  const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.innerHTML);
  const operational_wallet = xrpl.Wallet.fromSeed(
    operationalSeedField.innerHTML
  );
  const sendAmount = standbyAmountField.value;

  results += "\nstandby_wallet.address: = " + standby_wallet.address + "<br/>";
  standbyResultField.innerHTML = results;

  // ------------------------------------------------------- Prepare transaction
  // Note that the destination is hard coded.
  const prepared = await client.autofill({
    TransactionType: "Payment",
    Account: standby_wallet.address,
    Amount: xrpl.xrpToDrops(sendAmount),
    Destination: standbyDestinationField.value
  });

  // ------------------------------------------------ Sign prepared instructions
  const signed = standby_wallet.sign(prepared);

  // -------------------------------------------------------- Submit signed blob
  const tx = await client.submitAndWait(signed.tx_blob);

  results +=
    "<br/>Balance changes: " +
    JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2);
  standbyResultField.innerHTML = results;

  standbyBalanceField.innerHTML = await client.getXrpBalance(
    standby_wallet.address
  );
  operationalBalanceField.innerHTML = await client.getXrpBalance(
    operational_wallet.address
  );
  client.disconnect();
} // End of sendXRP()

// **********************************************************************
// ****** Reciprocal Transactions ***************************************
// **********************************************************************

// *******************************************************
// ********* Send XRP from Operational account ***********
// *******************************************************

async function oPsendXRP() {
  results = "Connecting to the selected ledger.<br/>";
  operationalResultField.innerHTML = results;
  let net = getNet();
  results = "Connecting to " + getNet() + "....<br/>";
  const client = new xrpl.Client(net);
  await client.connect();

  results += "<br/>Connected. Sending XRP.<br/>";
  operationalResultField.innerHTML = results;

  const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value);
  const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.innerHTML);
  const sendAmount = operationalAmountField.value;

  results +=
    "\noperational_wallet.address: = " + operational_wallet.address + "<br/>";
  operationalResultField.innerHTML = results;

  // ------------------------------------------------------- Prepare transaction
  // Note that the destination is hard coded.
  const prepared = await client.autofill({
    TransactionType: "Payment",
    Account: operational_wallet.address,
    Amount: xrpl.xrpToDrops(operationalAmountField.value),
    Destination: operationalDestinationField.value
  });

  // ------------------------------------------------ Sign prepared instructions
  const signed = operational_wallet.sign(prepared);

  // -------------------------------------------------------- Submit signed blob
  const tx = await client.submitAndWait(signed.tx_blob);

  results +=
    "<br/>Balance changes: " +
    JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2);
  operationalResultField.innerHTML = results;

  standbyBalanceField.innerHTML = await client.getXrpBalance(
    standby_wallet.address
  );
  operationalBalanceField.innerHTML = await client.getXrpBalance(
    operational_wallet.address
  );

  client.disconnect();
} // End of oPsendXRP()

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.