<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">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>
<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>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">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>
<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>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;
}
#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;
}
// **************** Configure Account ********************
async function configureAccount(type, rippleDefault) {
let net = getNet();
const client = new xrpl.Client(net);
results = "Connecting to " + getNet() + "....";
standbyResultField.innerHTML = results;
await client.connect();
results += "<br/>Connected, finding wallet.";
standbyResultField.innerHTML = results;
if (type == "standby") {
my_wallet = xrpl.Wallet.fromSeed(standbySeedField.innerHTML);
} else {
my_wallet = xrpl.Wallet.fromSeed(operationalSeedField.innerHTML);
}
results += "Ripple Default Setting: " + rippleDefault;
standbyResultField.innerHTML = results;
let settings_tx = {};
if (rippleDefault) {
settings_tx = {
TransactionType: "AccountSet",
Account: my_wallet.address,
SetFlag: xrpl.AccountSetAsfFlags.asfDefaultRipple
};
results += "<br/> Set Default Ripple flag.";
} else {
settings_tx = {
TransactionType: "AccountSet",
Account: my_wallet.address,
ClearFlag: xrpl.AccountSetAsfFlags.asfDefaultRipple
};
results += "<br/> Clear Default Ripple flag.";
}
results += "<br/>Sending account setting.";
standbyResultField.innerHTML = results;
const cst_prepared = await client.autofill(settings_tx);
const cst_signed = my_wallet.sign(cst_prepared);
const cst_result = await client.submitAndWait(cst_signed.tx_blob);
if (cst_result.result.meta.TransactionResult == "tesSUCCESS") {
results += "<br/>Account setting succeeded.";
standbyResultField.innerHTML = results;
} else {
throw "Error sending transaction: ${cst_result}";
results += "<br/>Account setting failed.";
standbyResultField.innerHTML = results;
}
client.disconnect();
} // End of configureAccount()
// *******************************************************
// ***************** Create TrustLine ********************
// *******************************************************
async function createTrustline() {
let net = getNet();
const client = new xrpl.Client(net);
results = "Connecting to " + getNet() + "....";
standbyResultField.innerHTML = results;
await client.connect();
results += "<br/>Connected.";
standbyResultField.innerHTML = results;
const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.innerHTML);
const operational_wallet = xrpl.Wallet.fromSeed(
operationalSeedField.innerHTML
);
const currency_code = standbyCurrencyField.value;
const trustSet_tx = {
TransactionType: "TrustSet",
Account: standbyDestinationField.value,
LimitAmount: {
currency: standbyCurrencyField.value,
issuer: standby_wallet.address,
value: standbyAmountField.value
}
};
const ts_prepared = await client.autofill(trustSet_tx);
const ts_signed = operational_wallet.sign(ts_prepared);
results +=
"<br/>Creating trust line from operational account to standby account...";
standbyResultField.innerHTML = results;
const ts_result = await client.submitAndWait(ts_signed.tx_blob);
if (ts_result.result.meta.TransactionResult == "tesSUCCESS") {
results +=
"<br/>Trustline established between account <br/>" +
standbyDestinationField.value +
" <br/> and account<br/>" +
standby_wallet.address +
".";
standbyResultField.innerHTML = results;
} else {
results += "<br/>TrustLine failed. See JavaScript console for details.";
standbyResultField.innerHTML = results;
throw "Error sending transaction: ${ts_result.result.meta.TransactionResult}";
}
} //End of createTrustline()
// *******************************************************
// *************** Send Issued Currency ******************
// *******************************************************
async function sendCurrency() {
let net = getNet();
const client = new xrpl.Client(net);
results = "Connecting to " + getNet() + "....";
standbyResultField.innerHTML = results;
await client.connect();
results += "<br/>Connected.";
standbyResultField.value = results;
const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.innerHTML);
const operational_wallet = xrpl.Wallet.fromSeed(
operationalSeedField.innerHTML
);
const currency_code = standbyCurrencyField.value;
const issue_quantity = standbyAmountField.value;
const send_token_tx = {
TransactionType: "Payment",
Account: standby_wallet.address,
Amount: {
currency: standbyCurrencyField.value,
value: standbyAmountField.value,
issuer: standby_wallet.address
},
Destination: standbyDestinationField.value
};
const pay_prepared = await client.autofill(send_token_tx);
const pay_signed = standby_wallet.sign(pay_prepared);
results +=
"Sending " +
standbyAmountField.value +
standbyCurrencyField.value +
"to " +
standbyDestinationField.value +
"...";
standbyResultField.innerHTML = results;
const pay_result = await client.submitAndWait(pay_signed.tx_blob);
if (pay_result.result.meta.TransactionResult == "tesSUCCESS") {
results +=
"Transaction succeeded: https://testnet.xrpl.org/transactions/${pay_signed.hash}";
standbyResultField.innerHTML = results;
} else {
results += "Transaction failed: See JavaScript console for details.";
standbyResultField.innerHTML = results;
throw "Error sending transaction: ${pay_result.result.meta.TransactionResult}";
}
standbyBalanceField.innerHTML = await client.getXrpBalance(
standby_wallet.address
);
operationalBalanceField.innerHTML = await client.getXrpBalance(
operational_wallet.address
);
getBalances();
client.disconnect();
} // end of sendIOU()
// *******************************************************
// ****************** Get Balances ***********************
// *******************************************************
async function getBalances() {
let net = getNet();
const client = new xrpl.Client(net);
results = "Connecting to " + getNet() + "....";
standbyResultField.innerHTML = results;
await client.connect();
results += "<br/>Connected.";
standbyResultField.innerHTML = results;
const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.innerHTML);
const operational_wallet = xrpl.Wallet.fromSeed(
operationalSeedField.innerHTML
);
results = "<br/>Getting standby account balances...<br/>";
const standby_balances = await client.request({
command: "gateway_balances",
account: standby_wallet.address,
ledger_index: "validated",
hotwallet: [operational_wallet.address]
});
results += JSON.stringify(standby_balances.result, null, 2);
standbyResultField.innerHTML = results;
results = "<br/>Getting operational account balances...<br/>";
const operational_balances = await client.request({
command: "account_lines",
account: operational_wallet.address,
ledger_index: "validated"
});
results += JSON.stringify(operational_balances.result, null, 2);
operationalResultField.innerHTML = results;
operationalBalanceField.innerHTML = await client.getXrpBalance(
operational_wallet.address
);
standbyBalanceField.innerHTML = await client.getXrpBalance(
standby_wallet.address
);
client.disconnect();
} // End of getBalances()
// **********************************************************************
// ****** Reciprocal Transactions ***************************************
// **********************************************************************
// *******************************************************
// ************ Create Operational TrustLine *************
// *******************************************************
async function oPcreateTrustline() {
let net = getNet();
const client = new xrpl.Client(net);
results = "Connecting to " + getNet() + "....";
operationalResultField.innerHTML = results;
await client.connect();
results += "<br/>Connected.";
operationalResultField.innerHTML = results;
const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.innerHTML);
const operational_wallet = xrpl.Wallet.fromSeed(
operationalSeedField.innerHTML
);
const trustSet_tx = {
TransactionType: "TrustSet",
Account: operationalDestinationField.value,
LimitAmount: {
currency: operationalCurrencyField.value,
issuer: operational_wallet.address,
value: operationalAmountField.value
}
};
const ts_prepared = await client.autofill(trustSet_tx);
const ts_signed = standby_wallet.sign(ts_prepared);
results +=
"<br/>Creating trust line from operational account to " +
operationalDestinationField.value +
" account...";
operationalResultField.innerHTML = results;
const ts_result = await client.submitAndWait(ts_signed.tx_blob);
if (ts_result.result.meta.TransactionResult == "tesSUCCESS") {
results +=
"<br/>Trustline established between account <br/>" +
standby_wallet.address +
" <br/> and account<br/>" +
operationalDestinationField.value +
".";
operationalResultField.innerHTML = results;
} else {
results += "<br/>TrustLine failed. See JavaScript console for details.";
operationalResultField.innerHTML = results;
throw "Error sending transaction: ${ts_result.result.meta.TransactionResult}";
}
} //End of oPcreateTrustline
// *******************************************************
// ************* Operational Send Issued Currency ********
// *******************************************************
async function oPsendCurrency() {
let net = getNet();
const client = new xrpl.Client(net);
results = "Connecting to " + getNet() + "....";
operationalResultField.value = results;
await client.connect();
results += "<br/>Connected.";
operationalResultField.innerHTML = results;
const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value);
const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value);
const currency_code = operationalCurrencyField.value;
const issue_quantity = operationalAmountField.value;
const send_token_tx = {
TransactionType: "Payment",
Account: operational_wallet.address,
Amount: {
currency: currency_code,
value: issue_quantity,
issuer: operational_wallet.address
},
Destination: operationalDestinationField.value
};
const pay_prepared = await client.autofill(send_token_tx);
const pay_signed = operational_wallet.sign(pay_prepared);
results +=
"Sending" +
operationalAmountField.value +
operationalCurrencyField.value +
" to " +
operationalDestinationField.value +
"...";
operationalResultField.innerHTML = results;
const pay_result = await client.submitAndWait(pay_signed.tx_blob);
if (pay_result.result.meta.TransactionResult == "tesSUCCESS") {
results +=
"Transaction succeeded: https://testnet.xrpl.org/transactions/${pay_signed.hash}";
operationalResultField.innerHTML = results;
} else {
results += "Transaction failed: See JavaScript console for details.";
operationalResultField.innerHTML = results;
throw "Error sending transaction: ${pay_result.result.meta.TransactionResult}";
}
standbyBalanceField.innerHTML = await client.getXrpBalance(
standby_wallet.address
);
operationalBalanceField.innerHTML = await client.getXrpBalance(
operational_wallet.address
);
getBalances();
client.disconnect();
} // end of oPsendCurrency()
This Pen doesn't use any external CSS resources.