mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2025-11-04 20:05:50 +00:00
add amm demo video
This commit is contained in:
3
_code-samples/amm-clob/README.md
Normal file
3
_code-samples/amm-clob/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# AMM CLOB Demo
|
||||
|
||||
Simulate how offers interact with each other and AMMs on the XRPL DEX.
|
||||
303
_code-samples/amm-clob/js/amm-clob.js
Normal file
303
_code-samples/amm-clob/js/amm-clob.js
Normal file
@@ -0,0 +1,303 @@
|
||||
if (typeof module !== "undefined") {
|
||||
// Use var here because const/let are block-scoped to the if statement.
|
||||
var xrpl = require('xrpl')
|
||||
}
|
||||
|
||||
const client = new xrpl.Client("wss://s.devnet.rippletest.net:51233");
|
||||
client.connect()
|
||||
|
||||
let aliceWallet = null
|
||||
let bobWallet = null
|
||||
let issuerWallet = null
|
||||
|
||||
let aliceWalletBalance = null
|
||||
let bobWalletBalance = null
|
||||
|
||||
// Add an event listener to the startButton
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
startButton.addEventListener("click", start)
|
||||
aCreateOfferButton.addEventListener("click", aliceCreateOffer)
|
||||
bCreateOfferButton.addEventListener("click", bobCreateOffer)
|
||||
});
|
||||
|
||||
// Function to get Alice and Bob balances
|
||||
|
||||
async function getBalances() {
|
||||
aliceWalletBalance = await client.getBalances(aliceWallet.address)
|
||||
bobWalletBalance = await client.getBalances(bobWallet.address)
|
||||
|
||||
aliceWalletField.value = `${aliceWalletBalance[0].value} XRP / ${aliceWalletBalance[1].value} USD`
|
||||
bobWalletField.value = `${bobWalletBalance[0].value} XRP / ${bobWalletBalance[1].value} USD`
|
||||
}
|
||||
|
||||
// Function to update AMM
|
||||
|
||||
async function ammInfoUpdate() {
|
||||
const ammInfo = await client.request({
|
||||
"command": "amm_info",
|
||||
"asset": {
|
||||
"currency": "XRP"
|
||||
},
|
||||
"asset2": {
|
||||
"currency": "USD",
|
||||
"issuer": issuerWallet.address
|
||||
},
|
||||
"ledger_index": "validated"
|
||||
})
|
||||
|
||||
ammInfoField.value = JSON.stringify(ammInfo.result.amm, null, 2)
|
||||
}
|
||||
|
||||
// Function to update Alice and Bobs offers
|
||||
|
||||
async function updateOffers() {
|
||||
const aliceOffers = await client.request({
|
||||
"command": "account_offers",
|
||||
"account": aliceWallet.address
|
||||
})
|
||||
|
||||
if ( aliceOffers.result.offers == "" ) {
|
||||
aliceOffersField.value = `No offers.`
|
||||
} else {
|
||||
aliceOffersField.value = `${JSON.stringify(aliceOffers.result.offers, null, 2)}`
|
||||
}
|
||||
|
||||
const bobOffers = await client.request({
|
||||
"command": "account_offers",
|
||||
"account": bobWallet.address
|
||||
})
|
||||
|
||||
if ( bobOffers.result.offers == "" ) {
|
||||
bobOffersField.value = `No offers.`
|
||||
} else {
|
||||
bobOffersField.value = `${JSON.stringify(bobOffers.result.offers, null, 2)}`
|
||||
}
|
||||
}
|
||||
|
||||
// Function to set up test harness
|
||||
async function start() {
|
||||
|
||||
// Fund wallets and wait for each to complete
|
||||
startButton.textContent = "Loading wallets...";
|
||||
|
||||
const issuerStart = client.fundWallet()
|
||||
const ammStart = client.fundWallet()
|
||||
const aliceStart = client.fundWallet()
|
||||
const bobStart = client.fundWallet()
|
||||
|
||||
const [issuerResult, ammResult, aliceResult, bobResult] = await Promise.all([issuerStart, ammStart, aliceStart, bobStart])
|
||||
|
||||
issuerWallet = issuerResult.wallet
|
||||
const ammWallet = ammResult.wallet
|
||||
aliceWallet = aliceResult.wallet
|
||||
bobWallet = bobResult.wallet
|
||||
|
||||
// Set up account settings
|
||||
startButton.textContent = "Setting up account settings...";
|
||||
|
||||
const issuerSetRipple = client.submitAndWait({
|
||||
"TransactionType": "AccountSet",
|
||||
"Account": issuerWallet.address,
|
||||
"SetFlag": xrpl.AccountSetAsfFlags.asfDefaultRipple
|
||||
}, {autofill: true, wallet: issuerWallet})
|
||||
|
||||
const ammSetTrust = client.submitAndWait({
|
||||
"TransactionType": "TrustSet",
|
||||
"Account": ammWallet.address,
|
||||
"LimitAmount": {
|
||||
"currency": "USD",
|
||||
"issuer": issuerWallet.address,
|
||||
"value": "10000"
|
||||
}
|
||||
}, {autofill: true, wallet: ammWallet})
|
||||
|
||||
const aliceSetTrust = client.submitAndWait({
|
||||
"TransactionType": "TrustSet",
|
||||
"Account": aliceWallet.address,
|
||||
"LimitAmount": {
|
||||
"currency": "USD",
|
||||
"issuer": issuerWallet.address,
|
||||
"value": "10000"
|
||||
}
|
||||
}, {autofill: true, wallet: aliceWallet})
|
||||
|
||||
const bobSetTrust = client.submitAndWait({
|
||||
"TransactionType": "TrustSet",
|
||||
"Account": bobWallet.address,
|
||||
"LimitAmount": {
|
||||
"currency": "USD",
|
||||
"issuer": issuerWallet.address,
|
||||
"value": "10000"
|
||||
}
|
||||
}, {autofill: true, wallet: bobWallet})
|
||||
|
||||
await Promise.all([issuerSetRipple, ammSetTrust, aliceSetTrust, bobSetTrust])
|
||||
|
||||
// Send USD token
|
||||
startButton.textContent = "Sending USD...";
|
||||
|
||||
const issuerAccountInfo = await client.request({
|
||||
"command": "account_info",
|
||||
"account": issuerWallet.address
|
||||
})
|
||||
|
||||
let sequence = issuerAccountInfo.result.account_data.Sequence
|
||||
|
||||
const ammUSD = client.submitAndWait({
|
||||
"TransactionType": "Payment",
|
||||
"Account": issuerWallet.address,
|
||||
"Amount": {
|
||||
"currency": "USD",
|
||||
"value": "1000",
|
||||
"issuer": issuerWallet.address
|
||||
},
|
||||
"Destination": ammWallet.address,
|
||||
"Sequence": sequence ++
|
||||
}, {autofill: true, wallet: issuerWallet})
|
||||
|
||||
const aliceUSD = client.submitAndWait({
|
||||
"TransactionType": "Payment",
|
||||
"Account": issuerWallet.address,
|
||||
"Amount": {
|
||||
"currency": "USD",
|
||||
"value": "1000",
|
||||
"issuer": issuerWallet.address
|
||||
},
|
||||
"Destination": aliceWallet.address,
|
||||
"Sequence": sequence ++
|
||||
}, {autofill: true, wallet: issuerWallet})
|
||||
|
||||
const bobUSD = client.submitAndWait({
|
||||
"TransactionType": "Payment",
|
||||
"Account": issuerWallet.address,
|
||||
"Amount": {
|
||||
"currency": "USD",
|
||||
"value": "1000",
|
||||
"issuer": issuerWallet.address
|
||||
},
|
||||
"Destination": bobWallet.address,
|
||||
"Sequence": sequence ++
|
||||
}, {autofill: true, wallet: issuerWallet})
|
||||
|
||||
await Promise.all([ammUSD, aliceUSD, bobUSD])
|
||||
|
||||
// Update Alice and Bob's XRP and USD balances
|
||||
|
||||
getBalances()
|
||||
|
||||
// Set up AMM
|
||||
startButton.textContent = "Creating AMM...";
|
||||
|
||||
await client.submitAndWait({
|
||||
"TransactionType": "AMMCreate",
|
||||
"Account": ammWallet.address,
|
||||
"Amount": "50000000", // XRP as drops
|
||||
"Amount2": {
|
||||
"currency": "USD",
|
||||
"issuer": issuerWallet.address,
|
||||
"value": "500"
|
||||
},
|
||||
"TradingFee": 500 // 0.5%
|
||||
}, {autofill: true, wallet: ammWallet})
|
||||
|
||||
// Update AMM
|
||||
ammInfoUpdate()
|
||||
|
||||
startButton.textContent = "Ready (Click to Restart)";
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Submit Alice Offers
|
||||
async function aliceCreateOffer() {
|
||||
|
||||
aCreateOfferButton.textContent = "Creating Offer..."
|
||||
|
||||
try {
|
||||
let aliceTakerGets = null
|
||||
let aliceTakerPays = null
|
||||
|
||||
if ( aliceTakerGetsCurrency.value == 'XRP' ) {
|
||||
aliceTakerGets = xrpl.xrpToDrops(aliceTakerGetsAmount.value)
|
||||
} else {
|
||||
aliceTakerGets = {
|
||||
"currency": "USD",
|
||||
"issuer": issuerWallet.address,
|
||||
"value": aliceTakerGetsAmount.value
|
||||
}
|
||||
}
|
||||
|
||||
if ( aliceTakerPaysCurrency.value == 'XRP' ) {
|
||||
aliceTakerPays = xrpl.xrpToDrops(aliceTakerPaysAmount.value)
|
||||
} else {
|
||||
aliceTakerPays = {
|
||||
"currency": "USD",
|
||||
"issuer": issuerWallet.address,
|
||||
"value": aliceTakerPaysAmount.value
|
||||
}
|
||||
}
|
||||
|
||||
await client.submitAndWait({
|
||||
"TransactionType": "OfferCreate",
|
||||
"Account": aliceWallet.address,
|
||||
"TakerGets": aliceTakerGets,
|
||||
"TakerPays": aliceTakerPays
|
||||
}, {autofill: true, wallet: aliceWallet})
|
||||
|
||||
updateOffers()
|
||||
getBalances()
|
||||
ammInfoUpdate()
|
||||
|
||||
} catch (error) {
|
||||
aliceOffersField.value = `${error.message}`
|
||||
}
|
||||
|
||||
aCreateOfferButton.textContent = "Create Another Offer"
|
||||
}
|
||||
|
||||
// Submit Bob Offers
|
||||
async function bobCreateOffer() {
|
||||
|
||||
bCreateOfferButton.textContent = "Creating Offer..."
|
||||
|
||||
try {
|
||||
let bobTakerGets = null
|
||||
let bobTakerPays = null
|
||||
|
||||
if ( bobTakerGetsCurrency.value == 'XRP' ) {
|
||||
bobTakerGets = xrpl.xrpToDrops(bobTakerGetsAmount.value)
|
||||
} else {
|
||||
bobTakerGets = {
|
||||
"currency": "USD",
|
||||
"issuer": issuerWallet.address,
|
||||
"value": bobTakerGetsAmount.value
|
||||
}
|
||||
}
|
||||
|
||||
if ( bobTakerPaysCurrency.value == 'XRP' ) {
|
||||
bobTakerPays = xrpl.xrpToDrops(bobTakerPaysAmount.value)
|
||||
} else {
|
||||
bobTakerPays = {
|
||||
"currency": "USD",
|
||||
"issuer": issuerWallet.address,
|
||||
"value": bobTakerPaysAmount.value
|
||||
}
|
||||
}
|
||||
|
||||
await client.submitAndWait({
|
||||
"TransactionType": "OfferCreate",
|
||||
"Account": bobWallet.address,
|
||||
"TakerGets": bobTakerGets,
|
||||
"TakerPays": bobTakerPays
|
||||
}, {autofill: true, wallet: bobWallet})
|
||||
|
||||
updateOffers()
|
||||
getBalances()
|
||||
ammInfoUpdate()
|
||||
|
||||
} catch (error) {
|
||||
bobOffersField.value = `${error.message}`
|
||||
}
|
||||
|
||||
bCreateOfferButton.textContent = "Create Another Offer"
|
||||
}
|
||||
72
_code-samples/amm-clob/js/demo.html
Normal file
72
_code-samples/amm-clob/js/demo.html
Normal file
@@ -0,0 +1,72 @@
|
||||
<script src="https://unpkg.com/xrpl@4.0.0/build/xrpl-latest.js"></script>
|
||||
<script type="application/javascript" src="amm-clob.js"></script>
|
||||
|
||||
<div style="padding: 5px">
|
||||
<div id="header">
|
||||
<button id="startButton" type="button" class="btn btn-primary" style="margin-bottom: 5px">Start Demo</button>
|
||||
</div>
|
||||
<div id="amm-box" style="border: 1px solid black; height: 250px; margin-bottom: 5px; padding: 5px; background-color: #f0f0f0">
|
||||
<p style="font-weight: bold">XRP/USD AMM</p>
|
||||
<textarea id="ammInfoField" style="height: 80%; width: 100%; resize: none" disabled></textarea>
|
||||
</div>
|
||||
<div id="offers-box" style="display:flex; gap: 5px">
|
||||
<div id="alice-box" style="border: 1px solid black; width: 50%; background-color: #f0f0f0; padding: 5px">
|
||||
<p style="font-weight: bold">Alice's Wallet</p>
|
||||
<textarea readonly id="aliceWalletField" style="height: 30px; width: 225px; resize: none" disabled></textarea>
|
||||
<div style="display: flex; gap: 10px">
|
||||
<label style="display: flex; align-items: center; gap: 10px">Taker Gets:
|
||||
<textarea id="aliceTakerGetsAmount" style="height: 30px; width: 100px; resize: none"></textarea>
|
||||
</label>
|
||||
<label style="display: flex; align-items: center; gap: 10px">Currency:
|
||||
<select id="aliceTakerGetsCurrency" style="height: 30px">
|
||||
<option>XRP</option>
|
||||
<option>USD</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div style="display:flex; gap: 10px">
|
||||
<label style="display: flex; align-items: center; gap: 10px">Taker Pays:
|
||||
<textarea id="aliceTakerPaysAmount" style="height: 30px; width: 100px; resize: none"></textarea>
|
||||
</label>
|
||||
<label style="display: flex; align-items: center; gap: 10px">Currency:
|
||||
<select id="aliceTakerPaysCurrency" style="height: 30px">
|
||||
<option>USD</option>
|
||||
<option>XRP</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<button id= "aCreateOfferButton" type="button" class="btn btn-primary" style="margin-bottom: 5px">Create Offer</button>
|
||||
<p style="font-weight: bold">Alice's Offers</p>
|
||||
<textarea id="aliceOffersField" style="height: 210px; width: 100%; resize: none" disabled></textarea>
|
||||
</div>
|
||||
<div id="bob-box" style="border: 1px solid black; width: 50%; background-color: #f0f0f0; padding: 5px">
|
||||
<p style="font-weight: bold">Bob's Wallet</p>
|
||||
<textarea readonly id="bobWalletField" style="height: 30px; width: 225px; resize: none" disabled></textarea>
|
||||
<div style="display: flex; gap: 10px">
|
||||
<label style="display: flex; align-items: center; gap: 10px">Taker Gets:
|
||||
<textarea id="bobTakerGetsAmount" style="height: 30px; width: 100px; resize: none"></textarea>
|
||||
</label>
|
||||
<label style="display: flex; align-items: center; gap: 10px">Currency:
|
||||
<select id="bobTakerGetsCurrency" style="height: 30px">
|
||||
<option>XRP</option>
|
||||
<option>USD</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div style="display:flex; gap: 10px">
|
||||
<label style="display: flex; align-items: center; gap: 10px">Taker Pays:
|
||||
<textarea id="bobTakerPaysAmount" style="height: 30px; width: 100px; resize: none"></textarea>
|
||||
</label>
|
||||
<label style="display: flex; align-items: center; gap: 10px">Currency:
|
||||
<select id="bobTakerPaysCurrency" style="height: 30px">
|
||||
<option>USD</option>
|
||||
<option>XRP</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<button id="bCreateOfferButton" type="button" class="btn btn-primary" style="margin-bottom: 5px">Create Offer</button>
|
||||
<p style="font-weight: bold">Bob's Offers</p>
|
||||
<textarea id="bobOffersField" style="height: 210px; width: 100%; resize: none" disabled></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -65,6 +65,11 @@ The diagram below illustrates how an offer interacts with other offers and AMM l
|
||||
|
||||

|
||||
|
||||
<div align="center">
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/tJ1mQxYpt-A" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
|
||||
### Restrictions on Assets
|
||||
|
||||
To prevent misuse, some restrictions apply to the assets used in an AMM. If you try to create an AMM with an asset that does not meet these restrictions, the transaction fails. The rules are as follows:
|
||||
|
||||
Reference in New Issue
Block a user