update to match existing modular tutorials

This commit is contained in:
Oliver Eggert
2024-08-26 21:45:03 -07:00
parent 5358b7170c
commit c9bb4102e0
22 changed files with 1076 additions and 348 deletions

View File

@@ -1,91 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>AMM Test Harness</title>
<link href='https://fonts.googleapis.com/css?family=Work Sans' rel='stylesheet'>
<meta charset="UTF-8">
<style>
body{font-family: "Work Sans", sans-serif;padding: 20px;background: #fafafa;}
h1{font-weight: bold;}
input, button {padding: 6px;margin-bottom: 8px;}
button{font-weight: bold;font-family: "Work Sans", sans-serif;}
td{vertical-align: middle;}
</style>
<script src='https://unpkg.com/xrpl@4.0.0/build/xrpl-latest-min.js'></script>
<script src='1.create-an-amm.js'></script>
<script>
if (typeof module !== "undefined") {
const xrpl = require('xrpl')
}
</script>
</head>
<!-- ************************************************************** -->
<!-- ********************** The Form ****************************** -->
<!-- ************************************************************** -->
<body>
<h1>AMM Test Harness</h1>
<form id="theForm">
<table>
<tr valign="top">
<td>
<table>
<tr valign="top">
<td>
<button type="button" onClick="getAccount()">Get New Devnet Account</button>
<table>
<tr valign="top">
<td>
<label for="accountField">Account:</label>
<br>
<textarea readonly id="accountField" cols="40"></textarea>
<br>
</td>
</tr>
<tr>
<td>
<label for="seedField">Seed:</label>
<br>
<textarea readonly id="seedField" cols="40"></textarea>
<br>
</td>
</tr>
<tr>
<td>
<label for="balanceField">XRP Balance:</label>
<br>
<textarea readonly id="balanceField" cols="40"></textarea>
<br>
</td>
</tr>
</table>
<button type="button" onClick="issueFOO()">Issue FOO Tokens</button>
<table>
<tr valign="top">
<td>
<label for="fooField">FOO Balance:</label>
<br>
<textarea readonly id="fooField" cols="40"></textarea>
<br>
</td>
</tr>
</table>
<br>
<button type="button" onClick="checkAMM()">Check for AMM</button>
<button type="button" onClick="createAMM()">Create AMM</button>
<br>
<br>
<label for="resultField">Log</label>
<p align="right">
<textarea readonly id="resultField" cols="80" rows="20" ></textarea>
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</form>
</body>
</html>

View File

@@ -1,185 +0,0 @@
// Define client, network, and explorer.
const WS_URL = 'wss://s.devnet.rippletest.net:51233'
const EXPLORER = 'https://devnet.xrpl.org'
const client = new xrpl.Client(WS_URL);
let wallet = null
let issuer = null
// Connect to devnet
async function getAccount() {
results = 'Connecting to Devnet ...'
resultField.value = results
await client.connect()
results += '\nConnected, funding wallet.'
resultField.value = results
// Fund a new devnet wallet
wallet = (await client.fundWallet()).wallet
results += '\nPopulated wallet info.'
resultField.value = results
// Get wallet info.
accountField.value = wallet.address
seedField.value = wallet.seed
balanceField.value = (await client.getXrpBalance(wallet.address))
client.disconnect()
}
// Issue FOO tokens to Devnet wallet.
async function issueFOO() {
// Create a new issuer on Devnet
results += '\n\nIssuing FOO tokens ...'
resultField.value = results
await client.connect()
issuer = (await client.fundWallet()).wallet
results += `\n\nCreated issuer account: ${issuer.address}`
resultField.value = results
// Enable issuer DefaultRipple
const issuer_setup_result = await client.submitAndWait({
"TransactionType": "AccountSet",
"Account": issuer.address,
"SetFlag": xrpl.AccountSetAsfFlags.asfDefaultRipple
}, {autofill: true, wallet: issuer} )
results += `\n\nIssuer DefaultRipple enabled: ${EXPLORER}/transactions/${issuer_setup_result.result.hash}`
resultField.value = results
// Create trust line from wallet to issuer
const trust_result = await client.submitAndWait({
"TransactionType": "TrustSet",
"Account": wallet.address,
"LimitAmount": {
"currency": "FOO",
"issuer": issuer.address,
"value": "10000000000" // Large limit, arbitrarily chosen
}
}, {autofill: true, wallet: wallet})
results += `\n\nTrust line created: ${EXPLORER}/transactions/${trust_result.result.hash}`
resultField.value = results
// Issue tokens
results += '\n\nSending 1000 FOO tokens ...'
resultField.value = results
const issue_result = await client.submitAndWait({
"TransactionType": "Payment",
"Account": issuer.address,
"Amount": {
"currency": "FOO",
"value": "1000",
"issuer": issuer.address
},
"Destination": wallet.address
}, {autofill: true, wallet: issuer})
results += `\nTokens issued: ${EXPLORER}/transactions/${issue_result.result.hash}`
resultField.value = results
walletBalances = (await client.getBalances(wallet.address))
const fooCurrency = walletBalances.find(item => item.currency === 'FOO');
const fooValue = fooCurrency ? fooCurrency.value : 'Currency not found';
fooField.value = fooValue
client.disconnect()
}
// Check if AMM exists.
async function checkAMM() {
await client.connect()
results += '\n\nChecking AMM ...'
resultField.value = results
const amm_info_request = {
"command": "amm_info",
"asset": {
"currency": "XRP"
},
"asset2": {
"currency": "FOO",
"issuer": issuer.address
},
"ledger_index": "validated"
}
try {
const amm_info_result = await client.request(amm_info_request)
results += `\n\n ${JSON.stringify(amm_info_result.result.amm, null, 2)}`
} catch(err) {
if (err.data.error === 'actNotFound') {
results += (`\nNo AMM exists for the pair FOO / XRP.`)
} else {
throw(err)
}
}
resultField.value = results
client.disconnect()
}
// Create new AMM.
async function createAMM() {
// This example assumes that 10 XRP ≈ 100 FOO in value.
await client.connect()
results += '\n\nCreating AMM ...'
resultField.value = results
// AMMCreate requires burning one owner reserve. We can look up that amount
// (in drops) on the current network using server_state:
const ss = await client.request({"command": "server_state"})
const amm_fee_drops = ss.result.state.validated_ledger.reserve_inc.toString()
const ammcreate_result = await client.submitAndWait({
"TransactionType": "AMMCreate",
"Account": wallet.address,
"Amount": {
"currency": "FOO",
"issuer": issuer.address,
"value": "500"
},
"Amount2": "50000000", // 50 XRP in drops
"TradingFee": 500, // 0.5%
"Fee": amm_fee_drops,
}, {autofill: true, wallet: wallet, fail_hard: true})
// Use fail_hard so you don't waste the tx cost if you mess up
results += `\n\nAMM created: ${EXPLORER}/transactions/${ammcreate_result.result.hash}`
resultField.value = results
// Update balances
balanceField.value = (await client.getXrpBalance(wallet.address))
walletBalances = (await client.getBalances(wallet.address))
const fooCurrency = walletBalances.find(item => item.currency === 'FOO');
const fooValue = fooCurrency ? fooCurrency.value : 'Currency not found';
fooField.value = fooValue
client.disconnect()
}

View File

@@ -0,0 +1,243 @@
<html>
<head>
<title>Create AMM Test Harness</title>
<link href='https://fonts.googleapis.com/css?family=Work Sans' rel='stylesheet'>
<style>
body{font-family: "Work Sans", sans-serif;padding: 20px;background: #fafafa;}
h1{font-weight: bold;}
input, button {padding: 6px;margin-bottom: 8px;}
button{font-weight: bold;font-family: "Work Sans", sans-serif;}
td{vertical-align: middle;}
</style>
<script src='https://unpkg.com/xrpl@4.0.0/build/xrpl-latest-min.js'></script>
<script src='ripplex1-send-xrp.js'></script>
<script src='ripplex2-send-currency.js'></script>
<script src='ripplex11-create-amm.js'></script>
<script>
if (typeof module !== "undefined") {
const xrpl = require('xrpl')
}
</script>
</head>
<!-- ************************************************************** -->
<!-- ********************** The Form ****************************** -->
<!-- ************************************************************** -->
<body>
<h1>Create AMM Test Harness</h1>
<form id="theForm">
Choose your ledger instance:
&nbsp;&nbsp;
<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>
<br/><br/>
<button type="button" onClick="getAccountsFromSeeds()">Get Accounts From Seeds</button>
<br/>
<textarea id="seeds" cols="40" rows= "2"></textarea>
<br/><br/>
<table>
<tr valign="top">
<td>
<table>
<tr valign="top">
<td>
<td>
<button type="button" onClick="getAccount('standby')">Get New Standby Account</button>
<table>
<tr valign="top">
<td align="right">
Standby Account
</td>
<td>
<input type="text" id="standbyAccountField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Seed
</td>
<td>
<input type="text" id="standbySeedField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
XRP Balance
</td>
<td>
<input type="text" id="standbyBalanceField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Amount
</td>
<td>
<input type="text" id="standbyAmountField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Destination
</td>
<td>
<input type="text" id="standbyDestinationField" size="40"></input>
<br>
</td>
</tr>
<tr valign="top">
<td><button type="button" onClick="configureAccount('standby',document.querySelector('#standbyDefault').checked)">Configure Account</button></td>
<td>
<input type="checkbox" id="standbyDefault" checked="true"/>
<label for="standbyDefault">Allow Rippling</label>
</td>
</tr>
<tr>
<td align="right">
Currency
</td>
<td>
<input type="text" id="standbyCurrencyField" size="40" value="USD"></input>
</td>
</tr>
</table>
<p align="left">
<textarea id="standbyResultField" cols="80" rows="20" ></textarea>
</p>
</td>
</td>
<td>
<table>
<tr valign="top">
<td align="center" valign="top">
<br><br><br><br>
<button type="button" onClick="sendXRP()">Send XRP&#62;</button>
<br/><br/>
<button type="button" onClick="createTrustline()">Create TrustLine</button>
<br/>
<button type="button" onClick="sendCurrency()">Send Currency</button>
<br/>
<button type="button" onClick="getBalances()">Get Balances</button>
<br/>
<button type="button" onClick="checkAMM()">Check AMM</button>
<br/>
<button type="button" onClick="createAMM()">Create AMM</button>
</td>
</tr>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
<td>
<table>
<tr>
<td>
<td>
<table>
<tr>
<td align="center" valign="top">
<button type="button" onClick="oPsendXRP()">&#60; Send XRP</button>
<br/><br/>
<button type="button" onClick="oPcreateTrustline()">Create TrustLine</button>
<br/>
<button type="button" onClick="oPsendCurrency()">Send Currency</button>
<br/>
<button type="button" onClick="getBalances()">Get Balances</button>
</td>
<td valign="top" align="right">
<button type="button" onClick="getAccount('operational')">Get New Operational Account</button>
<table>
<tr valign="top">
<td align="right">
Operational Account
</td>
<td>
<input type="text" id="operationalAccountField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Seed
</td>
<td>
<input type="text" id="operationalSeedField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
XRP Balance
</td>
<td>
<input type="text" id="operationalBalanceField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Amount
</td>
<td>
<input type="text" id="operationalAmountField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Destination
</td>
<td>
<input type="text" id="operationalDestinationField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td>
</td>
<td align="right">
<input type="checkbox" id="operationalDefault" checked="true"/>
<label for="operationalDefault">Allow Rippling</label>
<button type="button" onClick="configureAccount('operational',document.querySelector('#operationalDefault').checked)">Configure Account</button>
</td>
</tr>
<tr>
<td align="right">
Currency
</td>
<td>
<input type="text" id="operationalCurrencyField" size="40" value="USD"></input>
</td>
</tr>
</table>
<p align="right">
<textarea id="operationalResultField" cols="80" rows="20" ></textarea>
</p>
</td>
</td>
</tr>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</form>
</body>
</html>

View File

@@ -0,0 +1,272 @@
<html>
<head>
<title>Add Assets to AMM Test Harness</title>
<link href='https://fonts.googleapis.com/css?family=Work Sans' rel='stylesheet'>
<style>
body{font-family: "Work Sans", sans-serif;padding: 20px;background: #fafafa;}
h1{font-weight: bold;}
input, button {padding: 6px;margin-bottom: 8px;}
button{font-weight: bold;font-family: "Work Sans", sans-serif;}
td{vertical-align: middle;}
</style>
<script src='https://unpkg.com/xrpl@4.0.0/build/xrpl-latest-min.js'></script>
<script src='ripplex1-send-xrp.js'></script>
<script src='ripplex2-send-currency.js'></script>
<script src='ripplex11-create-amm.js'></script>
<script src='ripplex12-add-to-amm.js'></script>
<script>
if (typeof module !== "undefined") {
const xrpl = require('xrpl')
}
</script>
</head>
<!-- ************************************************************** -->
<!-- ********************** The Form ****************************** -->
<!-- ************************************************************** -->
<body>
<h1>Add Assets to AMM Test Harness</h1>
<form id="theForm">
Choose your ledger instance:
&nbsp;&nbsp;
<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>
<br/><br/>
<button type="button" onClick="getAccountsFromSeeds()">Get Accounts From Seeds</button>
<br/>
<textarea id="seeds" cols="40" rows= "2"></textarea>
<br/><br/>
<table>
<tr valign="top">
<td>
<table>
<tr valign="top">
<td>
<td>
<button type="button" onClick="getAccount('standby')">Get New Standby Account</button>
<table>
<tr valign="top">
<td align="right">
Standby Account
</td>
<td>
<input type="text" id="standbyAccountField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Seed
</td>
<td>
<input type="text" id="standbySeedField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
XRP Balance
</td>
<td>
<input type="text" id="standbyBalanceField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Amount
</td>
<td>
<input type="text" id="standbyAmountField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Destination
</td>
<td>
<input type="text" id="standbyDestinationField" size="40"></input>
<br>
</td>
</tr>
<tr valign="top">
<td><button type="button" onClick="configureAccount('standby',document.querySelector('#standbyDefault').checked)">Configure Account</button></td>
<td>
<input type="checkbox" id="standbyDefault" checked="true"/>
<label for="standbyDefault">Allow Rippling</label>
</td>
</tr>
<tr>
<td align="right">
Currency
</td>
<td>
<input type="text" id="standbyCurrencyField" size="40" value="USD"></input>
</td>
</tr>
<tr>
<td align="right">
LP Tokens
</td>
<td>
<input type="text" id="standbyLPField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Trading Fee
</td>
<td>
<input type="text" id="standbyFeeField" size="40"></input>
<br>
</td>
</tr>
</table>
<p align="left">
<textarea id="standbyResultField" cols="80" rows="20" ></textarea>
</p>
</td>
</td>
<td>
<table>
<tr valign="top">
<td align="center" valign="top" style="padding-top: 270px;">
<br>
<button type="button" onClick="sendXRP()">Send XRP&#62;</button>
<br/><br/>
<button type="button" onClick="createTrustline()">Create TrustLine</button>
<br/>
<button type="button" onClick="sendCurrency()">Send Currency</button>
<br/>
<button type="button" onClick="getBalances()">Get Balances</button>
<br/><br/>
<button type="button" onClick="checkAMM()">Check AMM</button>
<br/>
<button type="button" onClick="createAMM()">Create AMM</button>
<br/>
<button type="button" onClick="addAssets()">Add to AMM</button>
<br/>
<button type="button" onClick="voteFees()">Vote on Fee</button>
<br/>
<button type="button" onClick="calculateLP()">Get LP Value</button>
<br/>
<button type="button" onClick="redeemLP()">Redeem LP</button>
</td>
</tr>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
<td>
<table>
<tr>
<td>
<td>
<table>
<tr>
<td align="center" valign="top" style="padding-top: 15px;">
<br/>
<button type="button" onClick="oPsendXRP()">&#60; Send XRP</button>
<br/><br/>
<button type="button" onClick="oPcreateTrustline()">Create TrustLine</button>
<br/>
<button type="button" onClick="oPsendCurrency()">Send Currency</button>
<br/>
<button type="button" onClick="getBalances()">Get Balances</button>
<br>
</td>
<td valign="top" align="right">
<button type="button" onClick="getAccount('operational')">Get New Operational Account</button>
<table>
<tr valign="top">
<td align="right">
Operational Account
</td>
<td>
<input type="text" id="operationalAccountField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Seed
</td>
<td>
<input type="text" id="operationalSeedField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
XRP Balance
</td>
<td>
<input type="text" id="operationalBalanceField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Amount
</td>
<td>
<input type="text" id="operationalAmountField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Destination
</td>
<td>
<input type="text" id="operationalDestinationField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td>
</td>
<td align="right">
<input type="checkbox" id="operationalDefault" checked="true"/>
<label for="operationalDefault">Allow Rippling</label>
<button type="button" onClick="configureAccount('operational',document.querySelector('#operationalDefault').checked)">Configure Account</button>
</td>
</tr>
<tr>
<td align="right" style="padding-bottom: 60px;">
Currency
</td>
<td>
<input type="text" id="operationalCurrencyField" size="40" value="USD"></input>
</td>
</tr>
</table><br><br>
<p align="right">
<textarea id="operationalResultField" cols="80" rows="20" ></textarea>
</p>
</td>
</td>
</tr>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</form>
</body>
</html>

View File

@@ -0,0 +1,96 @@
// Create AMM function
async function createAMM() {
let net = getNet()
const client = new xrpl.Client(net)
results = `\n\nConnecting to ${getNet()} ...`
standbyResultField.value = results
await client.connect()
results += '\n\nConnected.'
standbyResultField.value = results
const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value)
const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value)
const xrp_value = standbyBalanceField.value
const currency_code = standbyCurrencyField.value
const currency_value = standbyAmountField.value
results += '\n\nCreating AMM ...'
standbyResultField.value = results
// AMMCreate requires burning one owner reserve. We can look up that amount
// (in drops) on the current network using server_state:
const ss = await client.request({"command": "server_state"})
const amm_fee_drops = ss.result.state.validated_ledger.reserve_inc.toString()
const ammcreate_result = await client.submitAndWait({
"TransactionType": "AMMCreate",
"Account": standby_wallet.address,
"Amount": {
"currency": currency_code,
"issuer": operational_wallet.address,
"value": currency_value
},
"Amount2": JSON.stringify(xrp_value * 1000000), // convert XRP to drops
"TradingFee": 500, // 500 = 0.5%
"Fee": amm_fee_drops,
}, {autofill: true, wallet: standby_wallet, fail_hard: true}) // Use fail_hard so you don't waste the tx cost if you mess up
checkAMM()
client.disconnect()
}
// Check AMM function
async function checkAMM() {
let net = getNet()
const client = new xrpl.Client(net)
results = `\n\nConnecting to ${getNet()} ...`
standbyResultField.value = results
await client.connect()
results += '\n\nConnected.'
standbyResultField.value = results
// Gets the issuer and currency code
const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value)
const currency_code = standbyCurrencyField.value
results += '\n\nChecking AMM ...'
standbyResultField.value = results
// Get AMM info transaction
const amm_info_request = {
"command": "amm_info",
"asset": {
"currency": "XRP"
},
"asset2": {
"currency": currency_code,
"issuer": operational_wallet.address
},
"ledger_index": "validated"
}
try {
const amm_info_result = await client.request(amm_info_request)
results += `\n\nAMM Info:\n${JSON.stringify(amm_info_result.result.amm, null, 2)}`
} catch(err) {
if (err.data.error === 'actNotFound') {
results += `\n\nNo AMM exists for the pair ${currency_code} / XRP.`
} else {
results += `\n\n${err}`
}
}
standbyResultField.value = results
client.disconnect()
}

View File

@@ -0,0 +1,331 @@
// Deposit assets to existing AMM.
async function addAssets() {
let net = getNet()
const client = new xrpl.Client(net)
results = `\n\nConnecting to ${getNet()} ...`
standbyResultField.value = results
await client.connect()
results += '\n\nConnected.'
standbyResultField.value = results
const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value)
const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value)
const addXRP = standbyBalanceField.value
const currency_code = standbyCurrencyField.value
const addCurrency = standbyAmountField.value
let ammdeposit = null
if (addXRP && addCurrency) {
ammdeposit = {
"TransactionType": "AMMDeposit",
"Asset": {
currency: "XRP"
},
"Asset2": {
currency: currency_code,
issuer: operational_wallet.address
},
"Account": standby_wallet.address,
"Amount": xrpl.xrpToDrops(addXRP),
"Amount2": {
currency: currency_code,
issuer: operational_wallet.address,
value: addCurrency
},
"Flags": 0x00100000
}
} else if ( addXRP ) {
ammdeposit = {
"TransactionType": "AMMDeposit",
"Asset": {
currency: "XRP"
},
"Asset2": {
currency: currency_code,
issuer: operational_wallet.address
},
"Account": standby_wallet.address,
"Amount": xrpl.xrpToDrops(addXRP),
"Flags": 0x00080000
}
} else if ( addCurrency ) {
ammdeposit = {
"TransactionType": "AMMDeposit",
"Asset": {
currency: "XRP"
},
"Asset2": {
currency: currency_code,
issuer: operational_wallet.address
},
"Account": standby_wallet.address,
"Amount": {
currency: currency_code,
issuer: operational_wallet.address,
value: addCurrency
},
"Flags": 0x00080000
}
} else {
results += `\n\nNo assets selected to add ...`
standbyResultField.value = results
standbyResultField.scrollTop = standbyResultField.scrollHeight
}
const prepared_deposit = await client.autofill(ammdeposit)
results += `\n\nPrepared transaction:\n${JSON.stringify(prepared_deposit, null, 2)}`
standbyResultField.value = results
standbyResultField.scrollTop = standbyResultField.scrollHeight
const signed_deposit = standby_wallet.sign(prepared_deposit)
results += `\n\nSending AMMDeposit transaction ...`
standbyResultField.value = results
standbyResultField.scrollTop = standbyResultField.scrollHeight
const lp_deposit = await client.submitAndWait(signed_deposit.tx_blob)
if (lp_deposit.result.meta.TransactionResult == "tesSUCCESS") {
results += `\n\nTransaction succeeded.`
} else {
results += `\n\nError sending transaction: ${lp_deposit}`
}
standbyResultField.value = results
standbyResultField.scrollTop = standbyResultField.scrollHeight
// Update LP token balance.
standbyWalletBalances = (await client.getBalances(standby_wallet.address))
const amm_info_request = {
"command": "amm_info",
"asset": {
"currency": "XRP"
},
"asset2": {
"currency": currency_code,
"issuer": operational_wallet.address
},
"ledger_index": "validated"
}
const amm_info_result = await client.request(amm_info_request)
// Get the AMM account address that issues LP tokens to depositors
ammAccount = amm_info_result.result.amm.account
const lpCurrency = standbyWalletBalances.find(item => item.issuer === ammAccount);
const lpValue = lpCurrency ? lpCurrency.value : 'Currency not found';
standbyLPField.value = lpValue
client.disconnect()
}
// Vote on AMM trading fees
async function voteFees() {
let net = getNet()
const client = new xrpl.Client(net)
results = `\n\nConnecting to ${getNet()} ...`
standbyResultField.value = results
await client.connect()
results += '\n\nConnected.'
standbyResultField.value = results
const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value)
const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value)
const currency_code = standbyCurrencyField.value
const voteFee = standbyFeeField.value
const ammvote = {
"TransactionType": "AMMVote",
"Asset": {
"currency": "XRP"
},
"Asset2": {
"currency": currency_code,
"issuer": operational_wallet.address
},
"Account": standby_wallet.address,
"TradingFee": Number(voteFee)
}
const prepared_vote = await client.autofill(ammvote)
results += `\n\nPrepared transaction:\n${JSON.stringify(prepared_vote, null, 2)}`
standbyResultField.value = results
standbyResultField.scrollTop = standbyResultField.scrollHeight
const signed_vote = standby_wallet.sign(prepared_vote)
results += `\n\nSending AMMVote transaction ...`
standbyResultField.value = results
standbyResultField.scrollTop = standbyResultField.scrollHeight
const response_vote = await client.submitAndWait(signed_vote.tx_blob)
if (response_vote.result.meta.TransactionResult == "tesSUCCESS") {
results += `\n\nTransaction succeeded.`
} else {
results += `\n\nError sending transaction: ${response_vote}`
}
standbyResultField.value = results
standbyResultField.scrollTop = standbyResultField.scrollHeight
client.disconnect()
}
// Calculate the value of your LP tokens.
async function calculateLP() {
let net = getNet()
const client = new xrpl.Client(net)
results = `\n\nConnecting to ${getNet()} ...`
standbyResultField.value = results
await client.connect()
results += '\n\nConnected.'
standbyResultField.value = results
const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value)
const currency_code = standbyCurrencyField.value
const LPTokens = standbyLPField.value
const amm_info = (await client.request({
"command": "amm_info",
"asset": {
"currency": "XRP"
},
"asset2": {
"currency": currency_code,
"issuer": operational_wallet.address
}
}))
const my_share = LPTokens / amm_info.result.amm.lp_token.value
const my_asset1 = (amm_info.result.amm.amount * my_share) / 1000000
const my_asset2 = amm_info.result.amm.amount2.value * my_share
results += `\n\nMy ${LPTokens} LP tokens are worth:\n
XRP: ${my_asset1}
${amm_info.result.amm.amount2.currency}: ${my_asset2}`
standbyResultField.value = results
standbyResultField.scrollTop = standbyResultField.scrollHeight
client.disconnect()
}
// Withdraw by redeeming LP tokens.
async function redeemLP() {
let net = getNet()
const client = new xrpl.Client(net)
results = `\n\nConnecting to ${getNet()} ...`
standbyResultField.value = results
await client.connect()
results += '\n\nConnected.'
standbyResultField.value = results
const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value)
const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value)
const currency_code = standbyCurrencyField.value
const LPTokens = standbyLPField.value
// Get LP token info.
const amm_info_request = {
"command": "amm_info",
"asset": {
"currency": "XRP"
},
"asset2": {
"currency": currency_code,
"issuer": operational_wallet.address
},
"ledger_index": "validated"
}
const amm_info_result = await client.request(amm_info_request)
const ammIssuer = amm_info_result.result.amm.lp_token.issuer
const ammCurrency = amm_info_result.result.amm.lp_token.currency
const ammwithdraw = {
"TransactionType": "AMMWithdraw",
"Asset": {
"currency": "XRP"
},
"Asset2": {
"currency": currency_code,
"issuer": operational_wallet.address
},
"Account": standby_wallet.address,
"LPTokenIn": {
currency: ammCurrency,
issuer: ammIssuer,
value: LPTokens
},
"Flags": 0x00010000
}
const prepared_withdraw = await client.autofill(ammwithdraw)
results += `\n\nPrepared transaction:\n${JSON.stringify(prepared_withdraw, null, 2)}`
standbyResultField.value = results
standbyResultField.scrollTop = standbyResultField.scrollHeight
const signed_withdraw = standby_wallet.sign(prepared_withdraw)
results += `\n\nSending AMMWithdraw transaction ...`
standbyResultField.value = results
standbyResultField.scrollTop = standbyResultField.scrollHeight
const response_withdraw = await client.submitAndWait(signed_withdraw.tx_blob)
if (response_withdraw.result.meta.TransactionResult == "tesSUCCESS") {
results += `\n\nTransaction succeeded. Updating balances ...`
} else {
results += `\n\nError sending transaction: ${response_withdraw}`
}
standbyResultField.value = results
standbyResultField.scrollTop = standbyResultField.scrollHeight
// Update standby wallet XRP, token, and LP balances.
standbyBalanceField.value = (await client.getXrpBalance(standby_wallet.address))
walletBalances = (await client.getBalances(standby_wallet.address))
const currencyAmount = walletBalances.find(item => item.currency === currency_code);
const currencyValue = currencyAmount ? currencyAmount.value : 'Currency not found';
standbyAmountField.value = currencyValue
ammAccount = amm_info_result.result.amm.account
const lpCurrency = walletBalances.find(item => item.issuer === ammAccount);
const lpValue = lpCurrency ? lpCurrency.value : 'Currency not found';
standbyLPField.value = lpValue
client.disconnect()
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

View File

@@ -10,86 +10,103 @@ labels:
This example shows how to: This example shows how to:
1. Purchase `FOO` tokens from an AMM. 1. Deposit `XRP` and issued tokens to an AMM and receive LP tokens.
2. Deposit `XRP` and `FOO` to the AMM and receive LP tokens. 2. Vote on AMM trading fees.
3. Vote on AMM trading fees. 3. Check the value of your LP tokens.
4. Redeem LP Tokens for assets. 4. Redeem LP Tokens for assets.
[![Add assets to AMM test harness](/docs/img/quickstart-add-to-amm1.png)](/docs/img/quickstart-add-to-amm1.png)
You can download the [Quickstart Samples](https://github.com/XRPLF/xrpl-dev-portal/tree/master/_code-samples/quickstart/js/)<!-- {.github-code-download} --> archive to try each of the samples in your own browser.
{% admonition type="note" name="Note" %}
Without the Quickstart Samples, you will not be able to try the examples that follow.
{% /admonition %}
## Usage ## Usage
![Test harness to create AMM](/docs/img/add-assets-to-amm.png) ### Get Accounts
Download the [AMM Samples](https://github.com/XRPLF/xrpl-dev-portal/tree/master/_code-samples/amm/js/) to use the AMM test harness in your browser and follow along in this tutorial. 1. Open `12.add-to-amm.html` in a browser.
2. Select **Testnet** or **Devnet**
3. Get test accounts.
- If you have existing account seeds:
1. Paste account seeds in the **Seeds** field.
2. Click **Get Accounts from Seeds**.
- If you don't have account seeds:
1. Click **Get New Standby Account**.
2. Click **Get New Operational Account**.
### Set up an AMM [![Get account results](/docs/img/quickstart-add-to-amm2.png)](/docs/img/quickstart-add-to-amm2.png)
1. Click **Get New Devnet Account**.
2. Click **Issue FOO Tokens**.
3. Click **Create AMM**. You can view the AMM pool info in the `AMM Info` box.
### Buy FOO tokens ### Add Assets to an Existing AMM
Buy `FOO` tokens from the established AMM in order to interact with the pool. Choose the amount of assets to add to the AMM. You can deposit either one or both assets, but deposting only one asset reduces the amount of LP tokens you receive. In the standby account fields:
1. Click **Get Second Devnet Account**. 1. Enter how much XRP to add in the **XRP Balance** field.
2. Click **Buy FOO Tokens**. To simplify this tutorial, this purchases 250 `FOO`. The AMM starts with a ratio of 10:1 `FOO`:`XRP`. This doesn't translate to a direct 25 `XRP` spend, since the AMM will adjust the cost of `FOO` to be more expensive as you buy more from it. 2. Enter how many issued tokens to add in the **Amount** field.
3. Enter the token issuer address in the **Destination** field.
4. Click **Add to AMM**.
[![Add assets to AMM results](/docs/img/quickstart-add-to-amm3.png)](/docs/img/quickstart-add-to-amm3.png)
### Add Assets to the AMM
Add a value in the `XRP` and `FOO` fields, then click **Add Assets**. You can deposit either one or both assets, but depositing only one asset will reduce the amount of LP tokens you receive.
### Vote on trading fees ### Vote on trading fees
Add a value in the `Fee` field, then click **Add Vote**. You can view the updated AMM info after doing so and see your submission under trading fees. 1. Enter a value in the **Trading Fee** field. The proposed fee is in units of 1/100,000; a value of 1 is equivalent to 0.001%. The maximum value is 1000, indicating a 1% fee.
2. Click **Vote on Fee**.
The proposed fee is in units of 1/100,000; a value of 1 is equivalent to 0.001%. The maximum value is 1000, indicating a 1% fee. [![Vote on trading fees results](/docs/img/quickstart-add-to-amm4.png)](/docs/img/quickstart-add-to-amm4.png)
### Redeem your LP tokens ### Check LP Token Value
1. Click **Calculate LP Value**. 1. Enter a value in the **LP Tokens** field.
2. Click **Withdraw LP**. This tutorial redeems all your LP tokens to withdraw both assets, but AMM withdrawals can be either both or one, depending on the fields specified in the transaction. 2. Click **Get LP Value**.
[![Get LP token value results](/docs/img/quickstart-add-to-amm5.png)](/docs/img/quickstart-add-to-amm5.png)
### Redeem Your LP Tokens
1. Enter a value in the **LP Tokens** field.
2. Click **Redeem LP**.
[![Get LP token value results](/docs/img/quickstart-add-to-amm6.png)](/docs/img/quickstart-add-to-amm6.png)
## Code Walkthrough ## Code Walkthrough
You can open `ripplex12-add-to-amm.js` from the [Quickstart Samples](https://github.com/XRPLF/xrpl-dev-portal/tree/master/_code-samples/quickstart/js/) to view the source code.
### Buy FOO tokens
Purchases 250 `FOO` tokens by creating an offer on the XRPL DEX. Since the AMM created in the test harness is the only available source of `FOO`, it takes the offer.
{% code-snippet file="/_code-samples/amm/js/2.add-assets-to-amm.js" language="js" from="// Buy FOO tokens from the XRP/FOO AMM." before="// Deposit assets to AMM." /%}
### Deposit assets ### Add Assets to an Existing AMM
This code checks if you're trying to add one or both assets, and then modifies the `AMMDeposit` transaction to be either a single or double-asset deposit. This code checks if you're trying to add one or both assets, and then modifies the `AMMDeposit` transaction to be either a single or double-asset deposit.
The function to update LP balance checks the AMM to get the unique AMM account, which acts as its own issuer of LP tokens. It then checks your wallet balance and gets the LP token value by matching it with the AMM issuer. The function to update LP balance checks the AMM to get the unique AMM account, which acts as its own issuer of LP tokens. It then checks your wallet balance and gets the LP token value by matching it with the AMM issuer.
{% code-snippet file="/_code-samples/amm/js/2.add-assets-to-amm.js" language="js" from="// Deposit assets to AMM." before="// Vote on fees." /%} {% code-snippet file="/_code-samples/quickstart/js/ripplex12-add-to-amm.js" from="// Deposit assets to existing AMM." before="// Vote on AMM trading fees" language="js" /%}
### Vote on trading fees ### Vote on Trading Fees
Trading fees are applied to any transaction that interacts with the AMM. The act of voting is straightforward and only requires you to hold the AMM LP tokens before submitting a vote. Trading fees are applied to any transaction that interacts with the AMM. The act of voting is straightforward and only requires you to hold the AMM LP tokens before submitting a vote.
{% code-snippet file="/_code-samples/amm/js/2.add-assets-to-amm.js" language="js" from="// Vote on fees." before="// Calculate the value of LP tokens." /%} {% code-snippet file="/_code-samples/quickstart/js/ripplex12-add-to-amm.js" from="// Vote on AMM trading fees" before="// Calculate the value of your LP tokens." language="js" /%}
### Calculate value of LP tokens ### Calculate Value of LP Tokens
There isn't a dedicated method to calculate how much you can redeem your LP tokens for, but the math isn't too complicated. The percentage of the total LP tokens you own qualifies you for the same percentage of the total assets in the AMM. There isn't a dedicated method to calculate how much you can redeem your LP tokens for, but the math isn't too complicated. The percentage of the total LP tokens in circulation that you own qualifies you for the same percentage of the total assets in the AMM.
{% code-snippet file="/_code-samples/amm/js/2.add-assets-to-amm.js" language="js" from="// Calculate the value of LP tokens." before="// Withdraw by redeeming LP tokens." /%} {% code-snippet file="/_code-samples/quickstart/js/ripplex12-add-to-amm.js" from="// Calculate the value of your LP tokens." before="// Withdraw by redeeming LP tokens." language="js" /%}
### Redeem your LP tokens ### Redeem Your LP Tokens
Redeeming your LP tokens requires you to get the LP token issuer and currency code, both of which you can check using the `amm_info` method. This code redeems assets using all your LP tokens, but you can also specify withdrawals by the amount of an asset you want to take out. Redeeming your LP tokens requires you to get the LP token issuer and currency code, both of which you can check using the `amm_info` method.
{% code-snippet file="/_code-samples/amm/js/2.add-assets-to-amm.js" language="js" from="// Withdraw by redeeming LP tokens." /%} {% code-snippet file="/_code-samples/quickstart/js/ripplex12-add-to-amm.js" from="// Withdraw by redeeming LP tokens." language="js" /%}

View File

@@ -2,55 +2,100 @@
This example shows how to: This example shows how to:
1. Issue `FOO` tokens on Devnet. 1. Check if an AMM pair exists.
2. Check if an AMM exists for `XRP/FOO`. 2. Issue tokens.
3. Create an AMM for `XRP/FOO`. 3. Create an AMM pair with the issued tokens and XRP.
[![Create AMM test harness](/docs/img/quickstart-create-amm1.png)](/docs/img/quickstart-create-amm1.png)
You can download the [Quickstart Samples](https://github.com/XRPLF/xrpl-dev-portal/tree/master/_code-samples/quickstart/js/)<!-- {.github-code-download} --> archive to try each of the samples in your own browser.
{% admonition type="note" name="Note" %}
Without the Quickstart Samples, you will not be able to try the examples that follow.
{% /admonition %}
## Usage ## Usage
![Test harness to create AMM](/docs/img/create-an-amm.png) ### Get Accounts
Download the [AMM Samples](https://github.com/XRPLF/xrpl-dev-portal/tree/master/_code-samples/amm/js/) to use the AMM test harness in your browser and follow along in this tutorial. 1. Open `11.create-amm.html` in a browser.
2. Select **Testnet** or **Devnet**
3. Get test accounts.
- If you have existing account seeds:
1. Paste account seeds in the **Seeds** field.
2. Click **Get Accounts from Seeds**.
- If you don't have account seeds:
1. Click **Get New Standby Account**.
2. Click **Get New Operational Account**.
1. Open `create-an-amm.html` in a browser. [![Get account results](/docs/img/quickstart-create-amm2.png)](/docs/img/quickstart-create-amm2.png)
2. Click **Get New Devnet Account**.
3. Click **Issue FOO Tokens**.
4. Click **Check for AMM**. ### Check AMM
5. Click **Create AMM**.
6. Click **Check for AMM**. In the standby account fields:
1. Enter a [currency code](/docs/references/protocol/data-types/currency-formats.md#currency-codes) in the **Currency** field.
2. Enter a token issuer in the **Destination** field.
3. Click **Check AMM**.
[![Check AMM results](/docs/img/quickstart-create-amm3.png)](/docs/img/quickstart-create-amm3.png)
### Create Trustline
Create a trustline from the operational account to the standby account. In the standby account fields:
1. Enter a currency code in the **Currency** field.
2. Enter the maximum transfer limit in the **Amount** field.
3. Enter the operational account address in the **Destination** field.
4. Click **Create Trustline**.
[![Create trustline results](/docs/img/quickstart-create-amm4.png)](/docs/img/quickstart-create-amm4.png)
### Issue Tokens
Send issued tokens from the operational account to the standby account. In the operational account fields:
1. Select **Allow Rippling** and click **Configure Account**.
2. Enter a value in the **Amount** field.
3. Enter the standby account address in the **Destination** field.
4. Enter the currency code from the trustline in the **Currency** field.
5. Click **Send Currency**.
[![Issue token results](/docs/img/quickstart-create-amm5.png)](/docs/img/quickstart-create-amm5.png)
### Create an AMM
In the standby account fields:
1. Click **Get Balances** to verify how many tokens you have.
2. Enter how much XRP to add in the **XRP Balance** field.
3. Enter the operational account address in the **Destination** field.
4. Enter the currency code in the **Currency** field.
5. Enter how many issued tokens to add in the **Amount** field.
6. Click **Create AMM**.
[![Create AMM results](/docs/img/quickstart-create-amm6.png)](/docs/img/quickstart-create-amm6.png)
## Code Walkthrough ## Code Walkthrough
### Connect to Devnet and generate credentials You can open `ripplex11-create-amm.js` from the [Quickstart Samples](https://github.com/XRPLF/xrpl-dev-portal/tree/master/_code-samples/quickstart/js/) to view the source code.
You must be connected to the network to query it and submit transactions. This code connects to Devnet and generates a fresh wallet, funded with 100 XRP.
{% code-snippet file="/_code-samples/amm/js/1.create-an-amm.js" from="// Define client, network, and explorer." before="// Issue FOO tokens to Devnet wallet." language="js" /%}
### Issue FOO tokens ### Check AMM
Normally, you'd acquire a second token through a stablecoin issuer, or buying it off an exchange. For this tutorial, we'll go through the process of issuing a brand new FOO token, enabling us to create a unique AMM pair later. Creating a new issuer and issuing a token involves: This checks if an AMM already exists. While multiple tokens can share the same currency code, each issuer makes them unique. When specifying an AMM, you must include the currency code and token issuer. If the AMM pair exists, this responds with the AMM information, such as token pair, trading fees, etc.
1. Creating a new issuer wallet. {% code-snippet file="/_code-samples/quickstart/js/ripplex11-create-amm.js" from="// Check AMM" language="js" /%}
2. Enabling the `DefaultRipple` flag.
3. Creating a trustline from your wallet to the issuer wallet.
4. Sending the `FOO` tokens from the issuer to your wallet.
{% code-snippet file="/_code-samples/amm/js/1.create-an-amm.js" from="// Issue FOO tokens to Devnet wallet." before="// Check if AMM exists." language="js" /%}
### Check if an AMM already exists.
Each AMM pair is unique. This checks to make sure the `XRP/FOO` pair doesn't already exist. In the previous step, we created a new issuer and `FOO` token; even if another `FOO` token already exists, it's considered unique if issued by another account. If the AMM pair exists, this responds with the AMM information, such as token pair, trading fees, etc.
{% code-snippet file="/_code-samples/amm/js/1.create-an-amm.js" from="// Check if AMM exists." before="// Create new AMM." language="js" /%}
### Create AMM ### Create AMM
This send the `AMMCreate` transaction with an initial pairing of 50 `XRP` to 500 `FOO`. This sends the `AMMCreate` transaction and creates a new AMM, using the initial assets provided.
{% code-snippet file="/_code-samples/amm/js/1.create-an-amm.js" from="// Create new AMM." language="js" /%} {% code-snippet file="/_code-samples/quickstart/js/ripplex11-create-amm.js" from="// Create AMM function" before="// Check AMM function" language="js" /%}