mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2026-04-29 15:37:48 +00:00
175 lines
5.7 KiB
JavaScript
175 lines
5.7 KiB
JavaScript
import { Client, isoTimeToRippleTime, rippleTimeToISOTime, validate, getBalanceChanges } from 'xrpl'
|
|
|
|
const client = new Client('wss://s.altnet.rippletest.net:51233')
|
|
await client.connect()
|
|
|
|
console.log('Funding new wallet from faucet...')
|
|
const { wallet } = await client.fundWallet()
|
|
// const destinationAddress = 'rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe' // Testnet faucet
|
|
// Alternative: Get another account to send the escrow to. Use this if you get
|
|
// a tecDIR_FULL error trying to create escrows to the Testnet faucet.
|
|
const destinationAddress = (await client.fundWallet()).wallet.address
|
|
|
|
// Create an escrow that won't be finished -------------------------------------
|
|
const cancelDelay = 30
|
|
const cancelAfter = new Date()
|
|
cancelAfter.setSeconds(cancelAfter.getSeconds() + cancelDelay)
|
|
console.log('This escrow will expire after:', cancelAfter)
|
|
// Convert cancelAfter to seconds since the Ripple Epoch:
|
|
const cancelAfterRippleTime = isoTimeToRippleTime(cancelAfter.toISOString())
|
|
const conditionHex = 'A02580200000000000000000000000000000000000000000000000000000000000000000810120'
|
|
|
|
const escrowCreate = {
|
|
TransactionType: 'EscrowCreate',
|
|
Account: wallet.address,
|
|
Destination: destinationAddress,
|
|
Amount: '123456',
|
|
Condition: conditionHex,
|
|
CancelAfter: cancelAfterRippleTime
|
|
}
|
|
validate(escrowCreate)
|
|
|
|
console.log('Signing and submitting the EscrowCreate transaction.')
|
|
const response = await client.submitAndWait(escrowCreate, {
|
|
wallet,
|
|
autofill: true // Note: fee is higher based on condition size in bytes
|
|
})
|
|
console.log(JSON.stringify(response.result, null, 2))
|
|
const escrowCreateResultCode = response.result.meta.TransactionResult
|
|
if (escrowCreateResultCode !== 'tesSUCCESS') {
|
|
console.error(`EscrowCreate failed with code ${escrowCreateResultCode}.`)
|
|
client.disconnect()
|
|
process.exit(1)
|
|
}
|
|
|
|
// Wait for the escrow to expire -----------------------------------------------
|
|
// Since ledger close times can be rounded by up to 10 seconds, wait an extra
|
|
// 10 seconds to make sure the escrow has officially expired.
|
|
console.log(`Waiting ${cancelDelay + 10} seconds for the escrow to expire...`)
|
|
await sleep(cancelDelay + 10)
|
|
|
|
/* Sleep function that can be used with await */
|
|
function sleep (delayInSeconds) {
|
|
const delayInMs = delayInSeconds * 1000
|
|
return new Promise((resolve) => setTimeout(resolve, delayInMs))
|
|
}
|
|
|
|
// Look up the official close time of the validated ledger ---------------------
|
|
const ledger = await client.request({
|
|
command: 'ledger',
|
|
ledger_index: 'validated'
|
|
})
|
|
if (ledger.error) {
|
|
console.error(`Error looking up validated ledger: ${ledger.error}`)
|
|
client.disconnect()
|
|
process.exit(1)
|
|
}
|
|
const closeTime = ledger.result.ledger.close_time
|
|
console.log('Latest validated ledger closed at',
|
|
rippleTimeToISOTime(closeTime)
|
|
)
|
|
const ledgerHash = ledger.result.ledger.ledger_hash
|
|
|
|
// Look up escrows connected to the account, handling pagination ---------------
|
|
let marker
|
|
let expiredEscrow
|
|
while (true) {
|
|
console.log(`Requesting page of account_objects with marker ${marker}`)
|
|
const resp = await client.request({
|
|
command: 'account_objects',
|
|
account: wallet.address,
|
|
ledger_hash: ledgerHash,
|
|
type: 'escrow',
|
|
marker
|
|
})
|
|
if (resp.error) {
|
|
console.error('account_objects failed with error', resp)
|
|
client.disconnect()
|
|
process.exit(1)
|
|
}
|
|
|
|
// Add new escrows to the full list
|
|
for (const escrow of resp.result.account_objects) {
|
|
if (!escrow.hasOwnProperty('CancelAfter')) {
|
|
console.log('This escrow does not have an expiration.')
|
|
} else if (escrow.CancelAfter < closeTime) {
|
|
console.log('This escrow has expired.')
|
|
expiredEscrow = escrow
|
|
break
|
|
} else {
|
|
const expirationTime = rippleTimeToISOTime(escrow.CancelAfter)
|
|
console.log('This escrow expires at', expirationTime)
|
|
}
|
|
}
|
|
|
|
if (expiredEscrow) {
|
|
// Found an expired escrow, stop paginating
|
|
break
|
|
}
|
|
|
|
// If there's a marker, loop and fetch the next page of results
|
|
if (resp.result.marker) {
|
|
marker = resp.result.marker
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
|
|
if (!expiredEscrow) {
|
|
console.error('Did not find any expired escrows.')
|
|
process.exit(1)
|
|
}
|
|
|
|
// Find the sequence number of the expired escrow ------------------------------
|
|
let escrow_seq
|
|
const txResp = await client.request({
|
|
command: 'tx',
|
|
transaction: expiredEscrow.PreviousTxnID
|
|
})
|
|
if (txResp.error) {
|
|
console.error("Couldn't get transaction. Maybe this server doesn't have",
|
|
'enough transaction history available?')
|
|
client.disconnect()
|
|
process.exit(1)
|
|
}
|
|
|
|
if (txResp.result.tx_json.TransactionType === 'EscrowCreate') {
|
|
// Save this sequence number for canceling the escrow
|
|
escrow_seq = txResp.result.tx_json.Sequence
|
|
if (escrow_seq === 0) {
|
|
// This transaction used a Ticket, so use TicketSequence instead.
|
|
escrow_seq = response.result.tx_json.TicketSequence
|
|
}
|
|
} else {
|
|
console.error("This escrow's previous transaction wasn't EscrowCreate!")
|
|
client.disconnect()
|
|
process.exit(1)
|
|
}
|
|
|
|
// Send EscrowCancel transaction -----------------------------------------------
|
|
const escrowCancel = {
|
|
TransactionType: 'EscrowCancel',
|
|
Account: wallet.address,
|
|
Owner: expiredEscrow.Account,
|
|
OfferSequence: escrow_seq
|
|
}
|
|
validate(escrowCancel)
|
|
|
|
console.log('Signing and submitting the EscrowCancel transaction.')
|
|
const cancelResponse = await client.submitAndWait(escrowCancel, {
|
|
wallet,
|
|
autofill: true
|
|
})
|
|
console.log(JSON.stringify(cancelResponse.result, null, 2))
|
|
const cancelResultCode = cancelResponse.result.meta.TransactionResult
|
|
if (cancelResultCode !== 'tesSUCCESS') {
|
|
console.error(`EscrowCancel failed with result code ${cancelResultCode}`)
|
|
client.disconnect()
|
|
process.exit(1)
|
|
}
|
|
|
|
console.log('Escrow canceled. Balance changes:')
|
|
console.log(JSON.stringify(getBalanceChanges(cancelResponse.result.meta), null, 2))
|
|
|
|
client.disconnect()
|