diff --git a/_code-samples/escrow/js/create-escrow.js b/_code-samples/escrow/js/create-escrow.js deleted file mode 100644 index 6d557475b69..00000000000 --- a/_code-samples/escrow/js/create-escrow.js +++ /dev/null @@ -1,69 +0,0 @@ -'use strict' -const xrpl = require('xrpl'); -const cc = require('five-bells-condition'); -const crypto = require('crypto'); - -// Useful Documentation:- -// 1. five-bells-condition: https://www.npmjs.com/package/five-bells-condition -// 2. Crypto module: https://nodejs.org/api/crypto.html - -// Your seed value, for testing purposes you can make one with the faucet: -// https://xrpl.org/resources/dev-tools/xrp-faucets -const seed = "sEd7jfWyNG6J71dEojB3W9YdHp2KCjy"; - -async function main() { - try { - - // Connect ---------------------------------------------------------------- - const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233'); - await client.connect(); - - // Prepare wallet to sign the transaction --------------------------------- - const wallet = await xrpl.Wallet.fromSeed(seed); - console.log("Wallet Address: ", wallet.address); - console.log("Seed: ", seed); - - // Set the escrow finish time --------------------------------------------- - let finishAfter = new Date((new Date().getTime() / 1000) + 120); // 2 minutes from now - finishAfter = new Date(finishAfter * 1000); - console.log("This escrow will finish after: ", finishAfter); - - // Construct condition and fulfillment ------------------------------------ - const preimageData = crypto.randomBytes(32); - const myFulfillment = new cc.PreimageSha256(); - myFulfillment.setPreimage(preimageData); - const conditionHex = myFulfillment.getConditionBinary().toString('hex').toUpperCase(); - - console.log('Condition:', conditionHex); - console.log('Fulfillment:', myFulfillment.serializeBinary().toString('hex').toUpperCase()); - - // Prepare EscrowCreate transaction ------------------------------------ - const escrowCreateTransaction = { - "TransactionType": "EscrowCreate", - "Account": wallet.address, - "Destination": wallet.address, - "Amount": "6000000", //drops XRP - "DestinationTag": 2023, - "Condition": conditionHex, // Omit this for time-held escrows - "Fee": "12", - "FinishAfter": xrpl.isoTimeToRippleTime(finishAfter.toISOString()), - }; - - xrpl.validate(escrowCreateTransaction); - - // Sign and submit the transaction ---------------------------------------- - console.log('Signing and submitting the transaction:', - JSON.stringify(escrowCreateTransaction, null, "\t"), "\n" - ); - const response = await client.submitAndWait(escrowCreateTransaction, { wallet }); - console.log(`Sequence number: ${response.result.tx_json.Sequence}`); - console.log(`Finished submitting! ${JSON.stringify(response.result, null, "\t")}`); - - await client.disconnect(); - - } catch (error) { - console.log(error); - } -} - -main() diff --git a/_code-samples/escrow/js/package.json b/_code-samples/escrow/js/package.json index f10d9adf373..7b7cf3a9472 100644 --- a/_code-samples/escrow/js/package.json +++ b/_code-samples/escrow/js/package.json @@ -1,9 +1,10 @@ { "name": "escrow-examples", - "version": "0.0.3", + "version": "2.0.0", "license": "MIT", "dependencies": { "five-bells-condition": "*", - "xrpl": "^4.0.0" - } + "xrpl": "^4.4.0" + }, + "type": "module" } diff --git a/_code-samples/escrow/js/send-timed-escrow-functions.js b/_code-samples/escrow/js/send-timed-escrow-functions.js new file mode 100644 index 00000000000..980c53f2005 --- /dev/null +++ b/_code-samples/escrow/js/send-timed-escrow-functions.js @@ -0,0 +1,146 @@ +import xrpl from 'xrpl' + +/* Sleep function that can be used with await */ +function sleep (delayInSeconds) { + const delayInMs = delayInSeconds * 1000 + return new Promise((resolve) => setTimeout(resolve, delayInMs)) +} + +/* Main function when called as a commandline script */ +async function main () { + const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233') + await client.connect() + + console.log('Funding new wallet from faucet...') + const { wallet } = await client.fundWallet() + const dest_address = 'rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe' // Testnet faucet + const delay = 30 + + const { escrowSeq, finishAfterRippleTime } = await send_timed_escrow( + client, + wallet, + dest_address, + delay + ) + + await wait_for_escrow(client, finishAfterRippleTime) + + await finish_escrow(client, wallet, escrowSeq) + + client.disconnect() +} + +/* + * Create a time-based escrow. + * Parameters: + * client (xrpl.Client): network-connected client + * wallet (xrpl.Wallet): sender wallet + * dest_address (string): receiver address in base58 + * delay (int): number of seconds until the escrow is mature + * Returns: object with the following keys + * response (xrpl.TxResponse): transaction result from submitAndWait + * escrowSeq (int): sequence number of the created escrow (int) + * finishAfterRippleTime (int): the FinishAfter time of the created escrow, + * in seconds since the Ripple Epoch + */ +async function send_timed_escrow (client, wallet, dest_address, delay) { + // Set the escrow finish time ----------------------------------------------- + const finishAfter = new Date() + finishAfter.setSeconds(finishAfter.getSeconds() + delay) + console.log('This escrow will finish after:', finishAfter) + // Convert finishAfter to seconds since the Ripple Epoch: + const finishAfterRippleTime = xrpl.isoTimeToRippleTime(finishAfter.toISOString()) + + // Send EscrowCreate transaction -------------------------------------------- + const escrowCreate = { + TransactionType: 'EscrowCreate', + Account: wallet.address, + Destination: dest_address, + Amount: '12345', // drops of XRP + FinishAfter: finishAfterRippleTime + } + xrpl.validate(escrowCreate) + + console.log('Signing and submitting the transaction:', + JSON.stringify(escrowCreate, null, 2)) + const response = await client.submitAndWait(escrowCreate, { + wallet, + autofill: true + }) + console.log(JSON.stringify(response.result, null, 2)) + const escrowSeq = response.result.tx_json.Sequence + console.log(`Escrow sequence is ${escrowSeq}.`) + return { + response, + escrowSeq, + finishAfterRippleTime + } +} + +/* + * Check the ledger close time to see if an escrow can be finished. + * If it's not ready yet, wait a number of seconds equal to the difference + * from the latest ledger close time to the escrow's FinishAfter time. + * Parameters: + * client (xrpl.Client): network-connected client + * finishAfterRippleTime (int): the FinishAfter time of the escrow, + * in seconds since the Ripple Epoch + * Returns: null + */ +async function wait_for_escrow (client, finishAfterRippleTime) { + // Check if escrow can be finished ------------------------------------------- + let escrowReady = false + while (!escrowReady) { + // Check the close time of the latest validated ledger. + // Close times are rounded by about 10 seconds, so the exact time the escrow + // is ready to finish may vary by +/- 10 seconds. + const validatedLedger = await client.request({ + command: 'ledger', + ledger_index: 'validated' + }) + const ledgerCloseTime = validatedLedger.result.ledger.close_time + console.log('Latest validated ledger closed at', + xrpl.rippleTimeToISOTime(ledgerCloseTime)) + if (ledgerCloseTime > finishAfterRippleTime) { + escrowReady = true + console.log('Escrow is ready to be finished.') + } else { + let timeDifference = finishAfterRippleTime - ledgerCloseTime + if (timeDifference === 0) { timeDifference = 1 } + console.log(`Waiting another ${timeDifference} second(s).`) + await sleep(timeDifference) + } + } +} + +/* + * Finish an escrow that your account owns. + * Parameters: + * client (xrpl.Client): network-connected client + * wallet (xrpl.Wallet): escrow owner and transaction sender's wallet + * escrowSeq (int): the Sequence number of the escrow to finish + * Returns: null + */ +async function finish_escrow (client, wallet, escrowSeq) { + // Send EscrowFinish transaction -------------------------------------------- + const escrowFinish = { + TransactionType: 'EscrowFinish', + Account: wallet.address, + Owner: wallet.address, + OfferSequence: escrowSeq + } + xrpl.validate(escrowFinish) + + console.log('Signing and submitting the transaction:', + JSON.stringify(escrowFinish, null, 2)) + const response2 = await client.submitAndWait(escrowFinish, { + wallet, + autofill: true + }) + console.log(JSON.stringify(response2.result, null, 2)) + if (response2.result.meta.TransactionResult === 'tesSUCCESS') { + console.log('Escrow finished successfully.') + } +} + +main() diff --git a/_code-samples/escrow/js/send-timed-escrow-linear.js b/_code-samples/escrow/js/send-timed-escrow-linear.js new file mode 100644 index 00000000000..c8079fd37ce --- /dev/null +++ b/_code-samples/escrow/js/send-timed-escrow-linear.js @@ -0,0 +1,92 @@ +import xrpl from 'xrpl' + +/* Sleep function that can be used with await */ +function sleep (delayInSeconds) { + const delayInMs = delayInSeconds * 1000 + return new Promise((resolve) => setTimeout(resolve, delayInMs)) +} + +const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233') +await client.connect() + +console.log('Funding new wallet from faucet...') +const { wallet } = await client.fundWallet() +const dest_address = 'rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe' // Testnet faucet +const delay = 30 + +// Set the escrow finish time ----------------------------------------------- +const finishAfter = new Date() +finishAfter.setSeconds(finishAfter.getSeconds() + delay) +console.log('This escrow will finish after:', finishAfter) +// Convert finishAfter to seconds since the Ripple Epoch: +const finishAfterRippleTime = xrpl.isoTimeToRippleTime(finishAfter.toISOString()) + +// Send EscrowCreate transaction -------------------------------------------- +const escrowCreate = { + TransactionType: 'EscrowCreate', + Account: wallet.address, + Destination: dest_address, + Amount: '12345', // drops of XRP + FinishAfter: finishAfterRippleTime +} +xrpl.validate(escrowCreate) + +console.log('Signing and submitting the transaction:', + JSON.stringify(escrowCreate, null, 2)) +const response = await client.submitAndWait(escrowCreate, { + wallet, + autofill: true +}) +console.log(JSON.stringify(response.result, null, 2)) +const escrowSeq = response.result.tx_json.Sequence +console.log(`Escrow sequence is ${escrowSeq}.`) + +// Wait for the escrow to be finishable ------------------------------------- +console.log(`Waiting ${delay} seconds for the escrow to mature...`) +await sleep(delay) + +// Check if escrow can be finished ------------------------------------------- +let escrowReady = false +while (!escrowReady) { + // Check the close time of the latest validated ledger. + // Close times are rounded by about 10 seconds, so the exact time the escrow + // is ready to finish may vary by +/- 10 seconds. + const validatedLedger = await client.request({ + command: 'ledger', + ledger_index: 'validated' + }) + const ledgerCloseTime = validatedLedger.result.ledger.close_time + console.log('Latest validated ledger closed at', + xrpl.rippleTimeToISOTime(ledgerCloseTime)) + if (ledgerCloseTime > finishAfterRippleTime) { + escrowReady = true + console.log('Escrow is ready to be finished.') + } else { + let timeDifference = finishAfterRippleTime - ledgerCloseTime + if (timeDifference === 0) { timeDifference = 1 } + console.log(`Waiting another ${timeDifference} second(s).`) + await sleep(timeDifference) + } +} + +// Send EscrowFinish transaction -------------------------------------------- +const escrowFinish = { + TransactionType: 'EscrowFinish', + Account: wallet.address, + Owner: wallet.address, + OfferSequence: escrowSeq +} +xrpl.validate(escrowFinish) + +console.log('Signing and submitting the transaction:', + JSON.stringify(escrowFinish, null, 2)) +const response2 = await client.submitAndWait(escrowFinish, { + wallet, + autofill: true +}) +console.log(JSON.stringify(response2.result, null, 2)) +if (response2.result.meta.TransactionResult === 'tesSUCCESS') { + console.log('Escrow finished successfully.') +} + +client.disconnect()