From 847b0f71b94db31424fdf8b22e683c25e56a20a6 Mon Sep 17 00:00:00 2001 From: mDuo13 Date: Fri, 14 Nov 2025 16:24:46 -0800 Subject: [PATCH] Escrow tutorials: Add conditional example & workaround for faucet tecDIR_FULL --- .../escrow/js/send-conditional-escrow.js | 89 +++++++++++++++++++ _code-samples/escrow/js/send-timed-escrow.js | 13 ++- 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 _code-samples/escrow/js/send-conditional-escrow.js diff --git a/_code-samples/escrow/js/send-conditional-escrow.js b/_code-samples/escrow/js/send-conditional-escrow.js new file mode 100644 index 0000000000..594b4d303b --- /dev/null +++ b/_code-samples/escrow/js/send-conditional-escrow.js @@ -0,0 +1,89 @@ +import xrpl from 'xrpl' +import { PreimageSha256 } from 'five-bells-condition' +import { randomBytes } from 'crypto' + +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 destination_address = '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 destination_address = (await client.fundWallet()).wallet.address + +// Create the crypto-condition for release ---------------------------------- +const preimage = randomBytes(32) +const fulfillment = new PreimageSha256() +fulfillment.setPreimage(preimage) +const fulfillmentHex = fulfillment.serializeBinary().toString('hex').toUpperCase() +const conditionHex = fulfillment.getConditionBinary().toString('hex').toUpperCase() +console.log('Condition:', conditionHex) +console.log('Fulfillment:', fulfillmentHex) + +// Set the escrow expiration ------------------------------------------------ +const cancelDelay = 300 // Seconds in the future when the escrow should expire +const cancelAfter = new Date() // Current time +cancelAfter.setSeconds(cancelAfter.getSeconds() + cancelDelay) +console.log('This escrow will expire after:', cancelAfter) +// Convert cancelAfter to seconds since the Ripple Epoch: +const cancelAfterRippleTime = xrpl.isoTimeToRippleTime(cancelAfter.toISOString()) + +// Send EscrowCreate transaction -------------------------------------------- +const escrowCreate = { + TransactionType: 'EscrowCreate', + Account: wallet.address, + Destination: destination_address, + Amount: '123456', // drops of XRP + Condition: conditionHex, + CancelAfter: cancelAfterRippleTime +} +xrpl.validate(escrowCreate) + +console.log('Signing and submitting the transaction:', + JSON.stringify(escrowCreate, null, 2)) +const response = await client.submitAndWait(escrowCreate, { + wallet, + autofill: true // Note: fee is higher based on condition size in bytes +}) + +// Check result of submitting ----------------------------------------------- +console.log(JSON.stringify(response.result, null, 2)) +const escrowCreateResultCode = response.result.meta.TransactionResult +if (escrowCreateResultCode === 'tesSUCCESS') { + console.log('Escrow created successfully.') +} else { + console.error(`EscrowCreate failed with code ${escrowCreateResultCode}.`) + process.exit(1) +} + +// Save the sequence number so you can identify the escrow later. +const escrowSeq = response.result.tx_json.Sequence +console.log(`Escrow sequence is ${escrowSeq}.`) + + +// Send EscrowFinish transaction -------------------------------------------- +const escrowFinish = { + TransactionType: 'EscrowFinish', + Account: wallet.address, + Owner: wallet.address, + OfferSequence: escrowSeq, + Condition: conditionHex, + Fulfillment: fulfillmentHex +} +xrpl.validate(escrowFinish) + +console.log('Signing and submitting the transaction:', + JSON.stringify(escrowFinish, null, 2)) +const response2 = await client.submitAndWait(escrowFinish, { + wallet, + autofill: true // Note: fee is higher based on fulfillment size in bytes +}) +console.log(JSON.stringify(response2.result, null, 2)) +if (response2.result.meta.TransactionResult === 'tesSUCCESS') { + console.log('Escrow finished successfully.') +} else { + console.log(`Failed with result code ${response2.result.meta.TransactionResult}`) +} + +client.disconnect() diff --git a/_code-samples/escrow/js/send-timed-escrow.js b/_code-samples/escrow/js/send-timed-escrow.js index 5b0b98c892..723d026741 100644 --- a/_code-samples/escrow/js/send-timed-escrow.js +++ b/_code-samples/escrow/js/send-timed-escrow.js @@ -5,6 +5,10 @@ await client.connect() console.log('Funding new wallet from faucet...') const { wallet } = await client.fundWallet() +const destination_address = '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 destination_address = (await client.fundWallet()).wallet.address // Set the escrow finish time ----------------------------------------------- const delay = 30 // Seconds in the future when the escrow should mature @@ -18,7 +22,7 @@ const finishAfterRippleTime = xrpl.isoTimeToRippleTime(finishAfter.toISOString() const escrowCreate = { TransactionType: 'EscrowCreate', Account: wallet.address, - Destination: 'rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe', // Testnet faucet + Destination: destination_address, Amount: '123456', // drops of XRP FinishAfter: finishAfterRippleTime } @@ -31,6 +35,13 @@ const response = await client.submitAndWait(escrowCreate, { autofill: true }) console.log(JSON.stringify(response.result, null, 2)) +const escrowCreateResultCode = response.result.meta.TransactionResult +if (escrowCreateResultCode === 'tesSUCCESS') { + console.log('Escrow created successfully.') +} else { + console.error(`EscrowCreate failed with code ${escrowCreateResultCode}.`) + process.exit(1) +} // Save the sequence number so you can identify the escrow later. const escrowSeq = response.result.tx_json.Sequence