# Create Conditional Escrows Using JavaScript This example shows how to: 1. Create escrow payments that become available when any account enters a fulfillment code. 2. Complete a conditional escrow transaction. 3. Cancel a conditional escrow transaction. [](/assets/mt-conditional-escrow-1-empty-form.d5b26c4d2f5e1ab7b6672e1d12f0af0f1d1ff43ef252554518d8f3824710a32a.ac57e6ef.png) ## Prerequisites Download and expand the [Modular Tutorials](../../../../_code-samples/modular-tutorials/payment-modular-tutorials.zip) archive. ## Usage ### Create Escrow You create a condition-based escrow using a fulfillment code associated with a condition code. Create the condition/fulfillment pair using the `five-bells-condition` application. Install `five-bells-condition`: 1. In a terminal window, navigate to your chosen local directory. 2. Enter the command `npm install five-bells-condition`. To create a condition/fulfillment pair: 1. In a terminal window, navigate to your chosen local directory. 2. Enter the command `node getConditionAndFulfillment.js`. 3. Copy and save the generated Condition and Fulfillment pair. [](/assets/mt-conditional-escrow-2-getconditionandfulfillment.cce6120b882a651d04be05b45f9c7d3e14902100f6cd735ae060179730218ae9.ac57e6ef.png) To get test accounts: 1. Open `create-conditional-escrow.html` in a browser 2. Get test accounts. 1. If you copied the gathered information from another tutorial: 1. Paste the gathered information to the **Result** field. 2. Click **Distribute Account Info**. 2. If you have an existing account seed: 1. Paste the account seed to the **Account 1 Seed** or **Account 2 Seed** field. 2. Click **Get Account 1 from Seed** or **Get Account 2 from Seed**. 3. If you do not have existing accounts: 1. Click **Get New Account 1**. 2. Click **Get New Account 2**. [](/assets/mt-conditional-escrow-3-form-with-accounts.ad9dcf519815cb426a55dbc69dc47b522b77241cfb254d2145c5498117ace9f2.ac57e6ef.png) ### Create Conditional Escrow When you create a conditional escrow, you need to specify the amount you want to reserve and the `Condition` value you generated above. You can also set a cancel date and time, after which the escrow is no longer available. For testing, the **Cancel** time is in seconds: in practice, you might set a **Cancel** time in days, weeks, months, or years. To create a conditional escrow: 1. Enter an **Amount** to transfer. 2. Enter the **Destination** field (for example, use Account 2 Address). 3. Enter the **Escrow Condition** value. 4. Enter the **Escrow Cancel (seconds)** value. 5. Click **Create Escrow**. 6. Copy and save the *Sequence Number* of the escrow called out in the **Results** field. The escrow is created on the XRP Ledger instance, reserving your requested XRP amount plus the transaction cost. When you create an escrow, capture and save the *Sequence Number* so that you can use it to finish the escrow transaction. [](/assets/mt-conditional-escrow-4-escrow-create.fd4c8606dc5bda9ddb176d451e77f44ce991ba0842fca424b8e7c6b88e950548.ac57e6ef.png) ## Finish Conditional Escrow Any account can finish the conditional escrow any time before the *Escrow Cancel* time. Following on the example above, you can use the *Sequence Number* to finish the transaction once the Escrow Cancel time has passed. To finish a conditional escrow: 1. Enter the **Escrow Condition** code for the escrow. 2. Enter the corresponding **Escrow Fulfillment** code. 3. Enter the **Escrow Owner** (the account address of the account that created the escrow). 4. Enter the sequence number in the **Escrow Sequence Number** field. 5. Click **Finish Escrow**. The transaction is completed and balances adjusted for both accounts. [](/assets/mt-conditional-escrow-5-escrow-fulfill.be11ceb47fab17bfb1ca760ffa47f369015c43bee0d6709a4b457aa2e4a6765f.ac57e6ef.png) ## Get Escrows Click **Get Escrows** to see the current list of escrows generated by or destined for the current account. ## Cancel Escrow When the Escrow Cancel time passes, the escrow is no longer available to the recipient. The initiator of the escrow can reclaim the XRP, less the transaction fees. Any account can cancel an escrow once the cancel time has elapsed. Accounts that try to cancel the transaction prior to the **Escrow Cancel** time are charged the nominal transaction cost (typically 12 drops), but the actual escrow cannot be cancelled until after the Escrow Cancel time. To cancel an expired escrow: 1. Enter the sequence number in the **Escrow Sequence Number** field. 2. Click **Cancel Escrow**. ## Oh No! I Forgot to Save the Sequence Number! If you forget to save the sequence number, you can find it in the escrow transaction record. 1. If needed, create a new escrow as described in [Create Escrow](#create-escrow), above. 2. Click **Get Escrows** to get the escrow information. 3. Copy the *PreviousTxnID* value from the results. [](/assets/mt-conditional-escrow-6-get-escrows.283f68d80dac082ab69c6432a675ccaf153508853afaaa5ea219903655e3a086.ac57e6ef.png) 4. Paste the *PreviousTxnID* in the **Transaction** field. 5. Click **Get Transaction**. 6. Locate the *ModifiedNode.PreviousFields.Sequence* value in the results. [](/assets/mt-conditional-escrow-7-sequence-value.e3ca1e1f9888c9bfd75f50a149fc02f76e4ac630eaa9c3af17275339db198d68.ac57e6ef.png) # Code Walkthrough Download the [Modular Tutorials](../../../../_code-samples/modular-tutorials/payment-modular-tutorials.zip) archive. ## five-bells.cjs To generate a condition/fulfillment pair, use Node.js to run the `five-bells.js` script. ```javascript const cc = require('five-bells-condition') const crypto = require('crypto') // 1. Generate a random 32-byte seed const preimageData = crypto.randomBytes(32) // 2. Create a PreimageSha256 fulfillment object const fulfillment = new cc.PreimageSha256() // 3. Set the preimage fulfillment.setPreimage(preimageData) // 4. Generate the condition (binary) const conditionBinary = fulfillment.getConditionBinary() // 5. Generate the fulfillment (binary) const fulfillmentBinary = fulfillment.serializeBinary() // Convert to hex for easier use const conditionHex = conditionBinary.toString('hex').toUpperCase() const fulfillmentHex = fulfillmentBinary.toString('hex').toUpperCase() console.log('Condition (hex):', conditionHex) console.log('Fulfillment (hex):', fulfillmentHex) ``` ## create-conditional-escrow.js ### createConditionalEscrow() Connect to the ledger and get the account wallet. ```javascript async function createConditionalEscrow() { let net = getNet() const client = new xrpl.Client(net) await client.connect() const wallet = xrpl.Wallet.fromSeed(accountSeedField.value) const sendAmount = amountField.value let results = `===Connected to ${net}===\n===Creating conditional escrow.===\n\n` resultField.value = results ``` Prepare the cancel date by adding the number of seconds in the **Escrow Cancel Date** field to the current date and time. In practice, the cancel date might be in days, weeks, months, or years. Using seconds allows you to test scenarios with expired escrows. ```javascript let escrow_cancel_date = new Date() escrow_cancel_date = addSeconds(parseInt(escrowCancelDateField.value)) ``` Prepare the transaction object. ```javascript const escrowTx = await client.autofill({ "TransactionType": "EscrowCreate", "Account": wallet.address, "Amount": xrpl.xrpToDrops(sendAmount), "Destination": destinationField.value, "CancelAfter": escrow_cancel_date, "Condition": escrowConditionField.value }) ``` Sign the prepared transaction object. ```javascript const signed = wallet.sign(escrowTx) ``` Submit the signed object and wait for the results. ```javascript const tx = await client.submitAndWait(signed.tx_blob) ``` Report the results, parsing the *Sequence Number* for later use. ```javascript results = "\n=== *** Sequence Number (Save!): " + tx.result.tx_json.Sequence results += "\n\n===Balance changes===\n" + JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2) xrpBalanceField.value = (await client.getXrpBalance(wallet.address)) resultField.value += results ``` Catch and report any errors, then disconnect from the XRP Ledger. ```javascript catch (error) { results += "\n===Error: " + error.message resultField.value = results } finally { // -------------------------------------------------------- Disconnect client.disconnect() }// End of createTimeEscrow() ``` ### finishConditionalEscrow() Connect to the ledger and get the account wallet from the account seed. ```javascript async function finishConditionalEscrow() { let net = getNet() const client = new xrpl.Client(net) await client.connect() let results = `===Connected to ${net}===\n===Fulfilling conditional escrow.===\n` resultField.value = results const wallet = xrpl.Wallet.fromSeed(accountSeedField.value) ``` Prepare the transaction object. ```javascript const prepared = await client.autofill({ "TransactionType": "EscrowFinish", "Account": accountAddressField.value, "Owner": escrowOwnerField.value, "OfferSequence": parseInt(escrowSequenceNumberField.value), "Condition": escrowConditionField.value, "Fulfillment": escrowFulfillmentField.value }) ``` Sign the prepared transaction object. ```javascript const signed = wallet.sign(prepared) ``` Submit the signed transaction and wait for the results. ```javascript const tx = await client.submitAndWait(signed.tx_blob) ``` Report the results ```javascript results = "\n===Balance changes===" + JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2) resultField.value += results ``` Catch and report any errors, then disconnect from the XRP Ledger. ```javascript catch (error) { results += "\n===Error: " + error.message + ".===\n" resultField.value = results } finally { // -------------------------------------------------------- Disconnect client.disconnect() } ``` ## create-conditional-escrow.html ```html