<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>

<body>
  <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 or Currency</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>
      <div class="appField">
        Currency<br />
        <input type="text" class="appValue" id="standbyCurrencyField" size="30" value="USD"></input>
      </div>
      <br /><br />
      <button type="button" onClick="configureAccount('standby',document.querySelector('#standbyDefault').checked)">Configure Account</button><br />
      <input type="checkbox" id="standbyDefault" checked="true" />
      <label for="standbyDefault">Allow Rippling</label>
  
  <p align="right">
        <button type="button" onClick="createTrustline()">Create TrustLine</button>
        <button type="button" onClick="sendCurrency()">Send Currency</button>
        <button type="button" onClick="getBalances()">Get Balances</button>
        <button type="button" onClick="sendXRP()">Send XRP &#8594;</button>
      </p>
  
  <p><strong>NFTs</strong></p>
 <div class="appField">
  NFToken URL<br />
  <input type="text" id="standbyTokenUrlField" class="appValue" value="ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf4dfuylqabf3oclgtqy55fbzdi" />
 </div>
  <div class="appField">
    Flags<br />
    <input class="appValue" type="text" id="standbyFlagsField" value="1" size="10" />
  </div>
  <div class="appField">
     NFToken ID<br />
    <input class="appValue" type="text" id="standbyTokenIdField" value="" />
  </div>
  <div class="appField">
     Transfer Fee<br />
     <input class="appValue" type="text" id="standbyTransferFeeField" value="" />
  </div>
  <p align="right">
    <button type="button" onClick="mintToken()">Mint NFToken</button>
    <button type="button" onClick="getTokens()">Get NFTokens</button>
    <button type="button" onClick="burnToken()">Burn NFToken</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">Standby 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>
      <div class="appField">
        Currency<br />
        <input type="text" class="appValue" id="operationalCurrencyField" size="30" value="USD"></input>
      </div>
      <br /><br />
      <button type="button" onClick="configureAccount('standby',document.querySelector('#standbyDefault').checked)">Configure Account</button><br />
      <input type="checkbox" id="operationalDefault" checked="true" />
      <label for="operationalDefault">Allow Rippling</label>
      <p align="right">
        <button type="button" onClick="oPcreateTrustline()">Create TrustLine</button>
        <button type="button" onClick="oPsendCurrency()">Send Currency</button>
        <button type="button" onClick="oPgetBalances()">Get Balances</button>
        <button type="button" onClick="oPsendXRP()"> &#8592; Send XRP</button>
      </p>
<p><strong>NFTs</strong></p>
 <div class="appField">
  NFToken URL<br />
  <input type="text" id="operationalTokenUrlField" class="appValue" value="ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf4dfuylqabf3oclgtqy55fbzdi" />
 </div>
  <div class="appField">
    Flags<br />
    <input class="appValue" type="text" id="operationalFlagsField" value="1" />
  </div>
  <div class="appField">
     NFToken ID<br />
    <input class="appValue" type="text" id="operationalTokenIdField" value="" />
  </div>
  <div class="appField">
     Transfer Fee<br />
     <input class="appValue" type="text" id="operationalTransferFeeField" value="" />
  </div>
  <p align="right">
    <button type="button" onClick="oPmintToken()">Mint NFToken</button>
    <button type="button" onClick="oPgetTokens()">Get NFTokens</button>
    <button type="button" onClick="oPburnToken()">Burn NFToken</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: 40px;
  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 -0.5em;
}
.flexColumn {
  width: 100%;
  flex: 1 0 50%;
  max-width: 50%;
  margin: 0 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;
  overflow-wrap: break-word;
}

#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;
}
// ********************** Mint Token *********************

async function mintToken() {
  results = "Connecting to " + getNet() + "....";
  standbyResultField.innerHTML = results;
  let net = getNet();
  const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.innerHTML);
  const client = new xrpl.Client(net);
  await client.connect();
  results += "<br/>Connected. Minting NFToken.";
  standbyResultField.innerHTML = results;

  // Note that you must convert the token URL to a hexadecimal
  // value for this transaction.
  // ------------------------------------------------------------------------
  const transactionBlob = {
    TransactionType: "NFTokenMint",
    Account: standby_wallet.classicAddress,
    URI: xrpl.convertStringToHex(standbyTokenUrlField.value),
    Flags: parseInt(standbyFlagsField.value),
    TransferFee: parseInt(standbyTransferFeeField.value),
    NFTokenTaxon: 0 //Required, but if you have no use for it, set to zero.
  };

  // ----------------------------------------------------- Submit signed blob
  const tx = await client.submitAndWait(transactionBlob, {
    wallet: standby_wallet
  });
  const nfts = await client.request({
    method: "account_nfts",
    account: standby_wallet.classicAddress
  });

  // ------------------------------------------------------- Report results
  results += "<br/><br/>Transaction result: " + tx.result.meta.TransactionResult;
  results += "<br/><br/>nfts: " + JSON.stringify(nfts, null, 2);
  standbyBalanceField.innerHTML = await client.getXrpBalance(
    standby_wallet.address
  );
  standbyResultField.innerHTML = results;
  client.disconnect();
} //End of mintToken()

// *******************************************************
// ******************* Get Tokens ************************
// *******************************************************

async function getTokens() {
  const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.innerHTML);
  let net = getNet();
  const client = new xrpl.Client(net);
  results = "Connecting to " + net + "...";
  standbyResultField.innerHTML = results;
  await client.connect();
  results += "<br/>Connected. Getting NFTokens...";
  standbyResultField.innerHTML = results;
  const nfts = await client.request({
    method: "account_nfts",
    account: standby_wallet.classicAddress
  });
  results += "<br/>NFTs:<br/> " + JSON.stringify(nfts, null, 2);
  standbyResultField.innerHTML = results;
  client.disconnect();
} //End of getTokens()

// *******************************************************
// ********************* Burn Token **********************
// *******************************************************

async function burnToken() {
  const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.innerHTML);
  let net = getNet();
  const client = new xrpl.Client(net);
  results = "Connecting to " + net + "...";
  standbyResultField.innerHTML = results;
  await client.connect();
  results += "<br/>Connected. Burning NFToken...";
  standbyResultField.innerHTML = results;

  // ------------------------------------------------------- Prepare transaction
  const transactionBlob = {
    TransactionType: "NFTokenBurn",
    Account: standby_wallet.classicAddress,
    NFTokenID: standbyTokenIdField.value
  };

  //---------------------------------- Submit transaction and wait for the results
  const tx = await client.submitAndWait(transactionBlob, {
    wallet: standby_wallet
  });
  const nfts = await client.request({
    method: "account_nfts",
    account: standby_wallet.classicAddress
  });
  results += "<br/>Transaction result: " + tx.result.meta.TransactionResult;
  results +=
    "<br/>Balance changes: " +
    JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2);
  standbyResultField.innerHTML = results;
  standbyBalanceField.innerHTML = await client.getXrpBalance(
    standby_wallet.address
  );
  results += "<br/>NFTs: <br/>" + JSON.stringify(nfts, null, 2);
  standbyResultField.innerHTML = results;
  client.disconnect();
} // End of burnToken()

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

// *******************************************************
// ************** Operational Mint Token *****************
// *******************************************************

async function oPmintToken() {
  results = "Connecting to " + getNet() + "....";
  operationalResultField.innerHTML = results;
  let net = getNet();
  const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.innerHTML);
  const client = new xrpl.Client(net);
  await client.connect();
  results += "<br/>Connected. Minting NFToken.";
  operationalResultField.innerHTML = results;

  // Note that you must convert the token URL to a hexadecimal
  // value for this transaction.
  // ------------------------------------------------------------------------
  const transactionBlob = {
    TransactionType: "NFTokenMint",
    Account: operational_wallet.classicAddress,
    URI: xrpl.convertStringToHex(operationalTokenUrlField.value),
    Flags: parseInt(operationalFlagsField.value),
    TransferFee: parseInt(operationalTransferFeeField.value),
    NFTokenTaxon: 0 //Required, but if you have no use for it, set to zero.
  };

  // ----------------------------------------------------- Submit signed blob
  const tx = await client.submitAndWait(transactionBlob, {
    wallet: operational_wallet
  });
  const nfts = await client.request({
    method: "account_nfts",
    account: operational_wallet.classicAddress
  });

  // ------------------------------------------------------- Report results
  results += "<br/><br/>Transaction result: " + tx.result.meta.TransactionResult;
  results += "<br/><br/>nfts: " + JSON.stringify(nfts, null, 2);
  operationalBalanceField.innerHTML = await client.getXrpBalance(
    operational_wallet.address
  );
  operationalResultField.innerHTML = results;

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

// *******************************************************
// ************** Operational Get Tokens *****************
// *******************************************************

async function oPgetTokens() {
  const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.innerHTML);
  let net = getNet();
  const client = new xrpl.Client(net);
  results = "Connecting to " + getNet() + "...";
  operationalResultField.innerHTML = results;
  await client.connect();
  results += "<br/>Connected. Getting NFTokens...";
  operationalResultField.innerHTML = results;
  const nfts = await client.request({
    method: "account_nfts",
    account: operational_wallet.classicAddress
  });
  results += "<br/>NFTs:<br/> " + JSON.stringify(nfts, null, 2);
  operationalResultField.innerHTML = results;
  client.disconnect();
} //End of oPgetTokens

// *******************************************************
// ************* Operational Burn Token ******************
// *******************************************************

async function oPburnToken() {
  const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.innerHTML);
  let net = getNet();
  const client = new xrpl.Client(net);
  results = "Connecting to " + getNet() + "...";
  operationalResultField.innerHTML = results;
  await client.connect();
  results += "<br/>Connected. Burning NFToken...";
  operationalResultField.innerHTML = results;

  // ------------------------------------------------------- Prepare transaction
  const transactionBlob = {
    TransactionType: "NFTokenBurn",
    Account: operational_wallet.classicAddress,
    NFTokenID: operationalTokenIdField.value
  };

  //-------------------------------------------------------- Submit signed blob
  const tx = await client.submitAndWait(transactionBlob, {
    wallet: operational_wallet
  });
  const nfts = await client.request({
    method: "account_nfts",
    account: operational_wallet.classicAddress
  });
  results += "<br/>Transaction result: " + tx.result.meta.TransactionResult;
  results +=
    "<br/>Balance changes: " +
    JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2);
  operationalResultField.innerHTML = results;
  operationalBalanceField.innerHTML = await client.getXrpBalance(
    operational_wallet.address
  );
  operationalBalanceField.innerHTML = await client.getXrpBalance(
    operational_wallet.address
  );
  results += "<br/>NFTs: <br/>" + JSON.stringify(nfts, null, 2);
  operationalResultField.innerHTML = results;
  client.disconnect();
}
// End of oPburnToken()

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://assets.codepen.io/t-4946/get-accounts-send-xrp.js
  2. https://assets.codepen.io/t-4946/create-trustline-send-currency.js