mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2025-11-22 20:55:50 +00:00
DEX tutorial: simplify metadata section, use BigNumber
This commit is contained in:
@@ -9,6 +9,20 @@ if (typeof module !== "undefined") {
|
|||||||
var BigNumber = require('bignumber.js')
|
var BigNumber = require('bignumber.js')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an XRPL amount, which could be a string (XRP in drops) or an object
|
||||||
|
* (token amount) to a string for display in one of the following formats:
|
||||||
|
* "123.456 XRP"
|
||||||
|
* "123.456 TST.rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd"
|
||||||
|
*/
|
||||||
|
def amt_str(amt) {
|
||||||
|
if (typeof amt == "string") {
|
||||||
|
return `${xrpl.dropsToXrp(amt)} XRP`
|
||||||
|
} else {
|
||||||
|
return `${amt.value} ${amt.currency}.${amt.issuer}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Connect ---------------------------------------------------------------------
|
// Connect ---------------------------------------------------------------------
|
||||||
async function main() {
|
async function main() {
|
||||||
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
|
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
|
||||||
@@ -28,10 +42,10 @@ async function main() {
|
|||||||
value: "25"}
|
value: "25"}
|
||||||
|
|
||||||
// 250 TST * 10 XRP per TST * 1.15 fx cost
|
// 250 TST * 10 XRP per TST * 1.15 fx cost
|
||||||
const we_spend = {currency: "XRP", value: xrpl.xrpToDrops(25*10*1.15)}
|
const we_spend = {currency: "XRP", value: xrpl.xrpToDrops(25*10*1.05)}
|
||||||
// "Quality" is defined as TakerPays ÷ TakerGets. The lower the "quality"
|
// "Quality" is defined as TakerPays ÷ TakerGets. The lower the "quality"
|
||||||
// number, the better the proposed exchange rate is for the taker.
|
// number, the better the proposed exchange rate is for the taker.
|
||||||
const proposed_quality = Number(we_spend.value / we_want.value)
|
const proposed_quality = BigNumber(we_spend.value) / BigNumber(we_want.value)
|
||||||
|
|
||||||
// Look up Offers. -----------------------------------------------------------
|
// Look up Offers. -----------------------------------------------------------
|
||||||
// To buy TST, look up Offers where "TakerGets" is TST:
|
// To buy TST, look up Offers where "TakerGets" is TST:
|
||||||
@@ -54,7 +68,7 @@ async function main() {
|
|||||||
// compensate.
|
// compensate.
|
||||||
|
|
||||||
const offers = orderbook_resp.result.offers
|
const offers = orderbook_resp.result.offers
|
||||||
const want_amt = Number(we_want.value)
|
const want_amt = BigNumber(we_want.value)
|
||||||
let running_total = 0
|
let running_total = 0
|
||||||
if (!offers) {
|
if (!offers) {
|
||||||
console.log(`No Offers in the matching book.
|
console.log(`No Offers in the matching book.
|
||||||
@@ -63,7 +77,7 @@ async function main() {
|
|||||||
for (const o of offers) {
|
for (const o of offers) {
|
||||||
if (o.quality <= proposed_quality) {
|
if (o.quality <= proposed_quality) {
|
||||||
console.log(`Matching Offer found, funded with ${o.owner_funds}`)
|
console.log(`Matching Offer found, funded with ${o.owner_funds}`)
|
||||||
running_total += Number(o.owner_funds)
|
running_total += BigNumber(o.owner_funds)
|
||||||
if (running_total >= want_amt) {
|
if (running_total >= want_amt) {
|
||||||
console.log("Full Offer will probably fill")
|
console.log("Full Offer will probably fill")
|
||||||
break
|
break
|
||||||
@@ -103,7 +117,7 @@ async function main() {
|
|||||||
|
|
||||||
// Since TakerGets/TakerPays are reversed, the quality is the inverse.
|
// Since TakerGets/TakerPays are reversed, the quality is the inverse.
|
||||||
// You could also calculate this as 1/proposed_quality.
|
// You could also calculate this as 1/proposed_quality.
|
||||||
const offered_quality = Number(we_want.value / we_spend.value)
|
const offered_quality = BigNumber(we_want.value) / BigNumber(we_spend.value)
|
||||||
|
|
||||||
const offers2 = orderbook2_resp.result.offers
|
const offers2 = orderbook2_resp.result.offers
|
||||||
let running_total2 = 0
|
let running_total2 = 0
|
||||||
@@ -113,7 +127,7 @@ async function main() {
|
|||||||
for (const o of offers2) {
|
for (const o of offers2) {
|
||||||
if (o.quality <= offered_quality) {
|
if (o.quality <= offered_quality) {
|
||||||
console.log(`Existing offer found, funded with ${o.owner_funds}`)
|
console.log(`Existing offer found, funded with ${o.owner_funds}`)
|
||||||
running_total2 += Number(o.owner_funds)
|
running_total2 += BigNumber(o.owner_funds)
|
||||||
} else {
|
} else {
|
||||||
console.log(`Remaining orders are below where ours would be placed.`)
|
console.log(`Remaining orders are below where ours would be placed.`)
|
||||||
break
|
break
|
||||||
@@ -155,86 +169,51 @@ async function main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Interpret metadata --------------------------------------------------------
|
// Interpret metadata --------------------------------------------------------
|
||||||
|
// In JavaScript, you can use getBalanceChanges() to help summarize all the
|
||||||
|
// balance changes caused by a transaction.
|
||||||
|
const balance_changes = xrpl.getBalanceChanges(result.result.meta)
|
||||||
|
console.log("Total balance changes:", JSON.stringify(balance_changes, null, 2))
|
||||||
|
|
||||||
|
let offers_affected = 0
|
||||||
for (const affnode of result.result.meta.AffectedNodes) {
|
for (const affnode of result.result.meta.AffectedNodes) {
|
||||||
if (affnode.hasOwnProperty("ModifiedNode")) {
|
if (affnode.hasOwnProperty("ModifiedNode")) {
|
||||||
const mn = affnode.ModifiedNode
|
if (affnode.ModifiedNode.LedgerEntryType == "Offer") {
|
||||||
if (mn.LedgerEntryType == "AccountRoot") {
|
offers_affected += 1
|
||||||
if (mn.FinalFields.Account == wallet.address) {
|
}
|
||||||
// Found our account in the metadata
|
} else if (affnode.hasOwnProperty("DeletedNode")) {
|
||||||
const final_xrp_bal = mn.FinalFields.Balance
|
if (affnode.DeletedNode.LedgerEntryType == "Offer") {
|
||||||
const prev_xrp_bal = mn.PreviousFields.Balance
|
offers_affected += 1
|
||||||
if (prev_xrp_bal === undefined) {
|
|
||||||
console.log(`Total XRP balance unchanged. This usually means the
|
|
||||||
transaction acquired exactly enough XRP to offset the XRP burned
|
|
||||||
as a transaction cost. Balance = ${xrpl.dropsToXrp(final_xrp_bal)} XRP`)
|
|
||||||
} else {
|
|
||||||
const diff_drops = BigNumber(final_xrp_bal) - BigNumber(prev_xrp_bal)
|
|
||||||
console.log(`Changed XRP balance by ${xrpl.dropsToXrp(diff_drops)}
|
|
||||||
to a new value of ${xrpl.dropsToXrp(final_xrp_bal)} XRP. (This
|
|
||||||
includes the net effect of burning XRP as a transaction cost.)`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (mn.LedgerEntryType == "RippleState") {
|
|
||||||
if (mn.FinalFields.HighLimit.issuer == wallet.address ||
|
|
||||||
mn.FinalFields.LowLimit.issuer == wallet.address) {
|
|
||||||
// Modified a trust line we already had
|
|
||||||
const we_are_low = (mn.FinalFields.LowLimit.issuer == wallet.address)
|
|
||||||
const currency = mn.FinalFields.Balance.currency
|
|
||||||
let counterparty
|
|
||||||
if (we_are_low) {
|
|
||||||
counterparty = mn.FinalFields.HighLimit.issuer
|
|
||||||
} else {
|
|
||||||
counterparty = mn.FinalFields.LowLimit.issuer
|
|
||||||
}
|
|
||||||
const final_token_bal = mn.FinalFields.Balance.value
|
|
||||||
const prev_token_bal = mn.PreviousFields.Balance.value
|
|
||||||
if (prev_token_bal === undefined) {
|
|
||||||
console.log(`Balance of ${currency}.${counterparty} unchanged.`)
|
|
||||||
} else {
|
|
||||||
let final_bal = BigNumber(final_token_bal)
|
|
||||||
let diff_tokens = final_bal - BigNumber(prev_token_bal)
|
|
||||||
if (!we_are_low) {
|
|
||||||
// RippleState objects store the balance from the low account's
|
|
||||||
// perspective, so if we are the high account, we negate it to get
|
|
||||||
// the balance from our perspective instead.
|
|
||||||
final_bal = -final_bal
|
|
||||||
diff_tokens = -diff_tokens
|
|
||||||
}
|
|
||||||
console.log(`Balance of ${currency}.${counterparty} changed by
|
|
||||||
${diff_tokens} to a final value of ${final_bal}.`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (affnode.hasOwnProperty("CreatedNode")) {
|
} else if (affnode.hasOwnProperty("CreatedNode")) {
|
||||||
const cn = affnode.CreatedNode
|
if (affnode.CreatedNode.LedgerEntryType == "RippleState") {
|
||||||
if (cn.LedgerEntryType == "Offer") {
|
console.log("Created a trust line.")
|
||||||
console.log(`Created Offer with TakerPays=${cn.NewFields.TakerPays}
|
} else if (affnode.CreatedNode.LedgerEntryType == "Offer") {
|
||||||
and TakerGets=${cn.NewFields.TakerGets}.`)
|
const offer = affnode.CreatedNode.NewFields
|
||||||
} else if (cn.LedgerEntryType == "RippleState") {
|
console.log(`Created an Offer owned by ${offer.Account} with
|
||||||
if (cn.NewFields.HighLimit.issuer == wallet.address ||
|
TakerGets=${amt_str(offer.TakerGets)} and
|
||||||
cn.NewFields.LowLimit.issuer == wallet.address) {
|
TakerPays=${amt_str(offer.TakerPays)}.`)
|
||||||
const we_are_low = (cn.NewFields.LowLimit.issuer == wallet.address)
|
|
||||||
let balance = cn.NewFields.Balance.value
|
|
||||||
if (!we_are_low) {
|
|
||||||
balance = -balance
|
|
||||||
}
|
|
||||||
console.log(`Created ${cn.NewFields.Balance.currency} trust line
|
|
||||||
between ${cn.NewFields.LowLimit.issuer} and
|
|
||||||
${cn.NewFields.HighLimit.issuer} with starting balance
|
|
||||||
${balance}.`)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
console.log(`Modified or removed ${offers_affected} matching Offer(s)`)
|
||||||
|
|
||||||
// Check balances ------------------------------------------------------------
|
// Check balances ------------------------------------------------------------
|
||||||
console.log("Getting address balances...")
|
console.log("Getting address balances as of validated ledger...")
|
||||||
const balances = await client.request({
|
const balances = await client.request({
|
||||||
command: "account_lines",
|
command: "account_lines",
|
||||||
account: wallet.address,
|
account: wallet.address,
|
||||||
ledger_index: "validated"
|
ledger_index: "validated"
|
||||||
})
|
})
|
||||||
console.log(balances.result)
|
console.log(JSON.stringify(balances.result, null, 2))
|
||||||
|
|
||||||
|
// Check Offers --------------------------------------------------------------
|
||||||
|
console.log(`Getting outstanding Offers from ${wallet.address} as of current ledger...`)
|
||||||
|
const acct_offers = await client.request({
|
||||||
|
command: "account_offers",
|
||||||
|
account: wallet.address,
|
||||||
|
ledger_index: "current"
|
||||||
|
})
|
||||||
|
console.log(JSON.stringify(acct_offers.result, null, 2))
|
||||||
|
|
||||||
client.disconnect()
|
client.disconnect()
|
||||||
} // End of main()
|
} // End of main()
|
||||||
|
|||||||
Reference in New Issue
Block a user