<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>
<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 →</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()"> ← 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()
This Pen doesn't use any external CSS resources.