mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-19 19:55:51 +00:00
fix: escrow finish and cancel integration (#2382)
* fix: escrow finish and cancel integration * add docs
This commit is contained in:
@@ -8,7 +8,7 @@ import {
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
import {
|
||||
calculateWaitTimeForTransaction,
|
||||
waitForAndForceProgressLedgerTime,
|
||||
generateFundedWallet,
|
||||
getXRPBalance,
|
||||
testTransaction,
|
||||
@@ -40,8 +40,6 @@ describe('EscrowCancel', function () {
|
||||
})
|
||||
).result.ledger.close_time
|
||||
|
||||
const waitTimeInMs = calculateWaitTimeForTransaction(CLOSE_TIME)
|
||||
|
||||
const createTx: EscrowCreate = {
|
||||
Account: testContext.wallet.classicAddress,
|
||||
TransactionType: 'EscrowCreate',
|
||||
@@ -86,14 +84,10 @@ describe('EscrowCancel', function () {
|
||||
OfferSequence: sequence,
|
||||
}
|
||||
|
||||
// We set the CancelAfter timer to be 3 seconds after the last ledger close_time. We need to wait this long
|
||||
// before we can cancel the escrow.
|
||||
const cancelAfterTimerPromise = new Promise((resolve) => {
|
||||
setTimeout(resolve, waitTimeInMs)
|
||||
})
|
||||
|
||||
// Make sure we wait long enough before canceling the escrow.
|
||||
await cancelAfterTimerPromise
|
||||
await waitForAndForceProgressLedgerTime(
|
||||
testContext.client,
|
||||
CLOSE_TIME + 3,
|
||||
)
|
||||
|
||||
// rippled uses the close time of the previous ledger
|
||||
await sendLedgerAccept(testContext.client)
|
||||
|
||||
@@ -8,11 +8,12 @@ import {
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
import {
|
||||
calculateWaitTimeForTransaction,
|
||||
generateFundedWallet,
|
||||
getXRPBalance,
|
||||
sendLedgerAccept,
|
||||
testTransaction,
|
||||
getLedgerCloseTime,
|
||||
waitForAndForceProgressLedgerTime,
|
||||
} from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
@@ -32,14 +33,7 @@ describe('EscrowFinish', function () {
|
||||
const wallet1 = await generateFundedWallet(testContext.client)
|
||||
|
||||
// get the most recent close_time from the standalone container for cancel & finish after.
|
||||
const CLOSE_TIME: number = (
|
||||
await testContext.client.request({
|
||||
command: 'ledger',
|
||||
ledger_index: 'validated',
|
||||
})
|
||||
).result.ledger.close_time
|
||||
|
||||
const waitTimeInMs = calculateWaitTimeForTransaction(CLOSE_TIME)
|
||||
const CLOSE_TIME = await getLedgerCloseTime(testContext.client)
|
||||
|
||||
const AMOUNT = 10000
|
||||
|
||||
@@ -51,10 +45,6 @@ describe('EscrowFinish', function () {
|
||||
FinishAfter: CLOSE_TIME + 2,
|
||||
}
|
||||
|
||||
const finishAfterPromise = new Promise((resolve) => {
|
||||
setTimeout(resolve, waitTimeInMs)
|
||||
})
|
||||
|
||||
await testTransaction(testContext.client, createTx, testContext.wallet)
|
||||
|
||||
const initialBalance = await getXRPBalance(testContext.client, wallet1)
|
||||
@@ -83,7 +73,11 @@ describe('EscrowFinish', function () {
|
||||
OfferSequence: sequence!,
|
||||
}
|
||||
|
||||
await finishAfterPromise
|
||||
// wait for the escrow to be ready to finish
|
||||
await waitForAndForceProgressLedgerTime(
|
||||
testContext.client,
|
||||
CLOSE_TIME + 2,
|
||||
)
|
||||
|
||||
// rippled uses the close time of the previous ledger
|
||||
await sendLedgerAccept(testContext.client)
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
type SubmitResponse,
|
||||
TimeoutError,
|
||||
NotConnectedError,
|
||||
unixTimeToRippleTime,
|
||||
} from '../../src'
|
||||
import { Payment, Transaction } from '../../src/models/transactions'
|
||||
import { hashSignedTx } from '../../src/utils/hashes'
|
||||
@@ -76,34 +75,6 @@ export async function ledgerAccept(
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to get the time after which we can check for the escrow to be finished.
|
||||
* Sometimes the ledger close_time is in the future, so we need to wait for it to catch up.
|
||||
*
|
||||
* @param targetTime - The target wait time, before accounting for current ledger time.
|
||||
* @param minimumWaitTimeMs - The minimum wait time in milliseconds.
|
||||
* @param maximumWaitTimeMs - The maximum wait time in milliseconds.
|
||||
* @returns The wait time in milliseconds.
|
||||
*/
|
||||
export function calculateWaitTimeForTransaction(
|
||||
targetTime: number,
|
||||
minimumWaitTimeMs = 5000,
|
||||
maximumWaitTimeMs = 20000,
|
||||
): number {
|
||||
const currentTimeUnixMs = Math.floor(new Date().getTime())
|
||||
const currentTimeRippleSeconds = unixTimeToRippleTime(currentTimeUnixMs)
|
||||
const closeTimeCurrentTimeDiffSeconds = currentTimeRippleSeconds - targetTime
|
||||
const closeTimeCurrentTimeDiffMs = closeTimeCurrentTimeDiffSeconds * 1000
|
||||
return Math.max(
|
||||
minimumWaitTimeMs,
|
||||
Math.min(
|
||||
Math.abs(closeTimeCurrentTimeDiffMs) + minimumWaitTimeMs,
|
||||
// Maximum wait time of 20 seconds
|
||||
maximumWaitTimeMs,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
export function subscribeDone(client: Client): void {
|
||||
client.removeAllListeners()
|
||||
}
|
||||
@@ -299,3 +270,70 @@ export async function getXRPBalance(
|
||||
}
|
||||
return (await client.request(request)).result.account_data.Balance
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the close time of the ledger.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @returns - A promise that resolves to the close time of the ledger.
|
||||
*
|
||||
* @example
|
||||
* const closeTime = await getLedgerCloseTime(client);
|
||||
* console.log(closeTime); // Output: 1626424978
|
||||
*/
|
||||
export async function getLedgerCloseTime(client: Client): Promise<number> {
|
||||
const CLOSE_TIME: number = (
|
||||
await client.request({
|
||||
command: 'ledger',
|
||||
ledger_index: 'validated',
|
||||
})
|
||||
).result.ledger.close_time
|
||||
|
||||
return CLOSE_TIME
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the ledger time to reach a specific value and forces ledger progress if necessary.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param ledgerTime - The target ledger time.
|
||||
* @param [retries=20] - The number of retries before throwing an error.
|
||||
* @returns - A promise that resolves when the ledger time reaches the target value.
|
||||
*
|
||||
* @example
|
||||
* try {
|
||||
* await waitForAndForceProgressLedgerTime(client, 1626424978, 10);
|
||||
* console.log('Ledger time reached.'); // Output: Ledger time reached.
|
||||
* } catch (error) {
|
||||
* console.error(error);
|
||||
* }
|
||||
*/
|
||||
export async function waitForAndForceProgressLedgerTime(
|
||||
client: Client,
|
||||
ledgerTime: number,
|
||||
retries = 20,
|
||||
): Promise<void> {
|
||||
async function getCloseTime(): Promise<boolean> {
|
||||
const CLOSE_TIME: number = await getLedgerCloseTime(client)
|
||||
if (CLOSE_TIME >= ledgerTime) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
let retryCounter = retries || 0
|
||||
|
||||
while (retryCounter > 0) {
|
||||
// eslint-disable-next-line no-await-in-loop -- Necessary for retries
|
||||
if (await getCloseTime()) {
|
||||
return
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-await-in-loop -- Necessary for retries
|
||||
await ledgerAccept(client)
|
||||
retryCounter -= 1
|
||||
}
|
||||
|
||||
throw new Error(`Ledger time not reached after ${retries} retries.`)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user