LogoLogo
  • Welcome
  • XRPL Basics
    • Getting Started
    • Payments
    • Reading and subscribing to Transactions
    • Writing and reading memos
    • Non Fungible Tokens
    • PathFinding
    • Escrow
    • Price Oracles
    • Tickets
    • Multi-Signature
  • Token Issuance and Liquidity
    • Creating Accounts
    • Issuing Tokens
    • Creating an AMM Pool
  • Cyphered Chat on XRPL
    • Set up
    • Set up Keys
    • Cypher the message
    • Set up the memo & send the tx
    • Get the message and decypher it
  • EVM Sidechain
    • Connecting Metamask
    • Bridging Assets
    • Remix
    • Banking App
    • Banking Contract Key Concepts
  • Tools
    • Xaman Setup
    • Metamask Setup
Powered by GitBook
On this page
  • Start coding
  • Create the escrow
  • Finishing the escrow
  • Extra credits
  • Canceling your escrow
  • Use the escrow as a smart contract
Export as PDF
  1. XRPL Basics

Escrow

In this session, we will create an escrow.

An escrow on the XRP Ledger allows users to lock XRP and release it under specific conditions. This feature enables conditional payments, ensuring funds are only transferred when criteria are met. If conditions aren't fulfilled, the escrow can be canceled, returning the funds to the sender.

Start coding

Create a new file or edit index.ts

import dayjs from 'dayjs';
import { Client, isoTimeToRippleTime, xrpToDrops } from 'xrpl';
import { generateConditionAndFulfillment, escrowTransaction } from './helpers';

const main = async () => {
  console.log('lets get started...');
  // Connect the client to the network
  const client = new Client('wss://s.altnet.rippletest.net:51233');
  await client.connect();

  const { wallet: walletOne } = await client.fundWallet();
  const { wallet: walletTwo } = await client.fundWallet();
  console.log({ walletOne, walletTwo });
};

main();

Create the escrow

In order to create an escrow on the XRP Ledger, you need to specify the amount of XRP to lock, the destination account, and the conditions for release, such as a time-based or cryptographic condition. Additionally, you must ensure the transaction is properly signed and submitted to the network, and verify its success to confirm the escrow is active.

// Time after which the destination user can claim the funds
const WAITING_TIME = 10; // seconds

// Define the time from when the Destination wallet can claim the money in the escrow. So here it would be 10 seconds after the escrow creation.
const finishAfter = dayjs().add(WAITING_TIME, 'seconds').toISOString();

// Generate the condition and fulfillment
const { condition, fulfillment } = generateConditionAndFulfillment();

const escrowCreateResponse = await escrowTransaction({
  txn: {
    Account: walletOne.address,
    TransactionType: 'EscrowCreate',
    Amount: xrpToDrops('1'),
    Destination: walletTwo.address,
    FinishAfter: isoTimeToRippleTime(finishAfter),
    Condition: condition,
  },
  client,
  wallet: walletOne,
});

// We need the sequence to finish an escrow, if it is not there, stop the function
if (!escrowCreateResponse.result.Sequence) {
  await client.disconnect();
  return;
}

Create a helpers.ts file and add the generateConditionAndFulfillment and escrowTransaction function:

import crypto from 'crypto';
import {
  Client,
  EscrowCreate,
  EscrowFinish,
  EscrowCancel,
  Wallet,
  Transaction,
} from 'xrpl';
// @ts-expect-error no types available
import cc from 'five-bells-condition';

export const generateConditionAndFulfillment = () => {
  console.log(
    "******* LET'S GENERATE A CRYPTO CONDITION AND FULFILLMENT *******"
  );
  console.log();

  // use cryptographically secure random bytes generation
  const preimage = crypto.randomBytes(32);

  const fulfillment = new cc.PreimageSha256();
  fulfillment.setPreimage(preimage);

  const condition = fulfillment
    .getConditionBinary()
    .toString('hex')
    .toUpperCase();
  console.log('Condition:', condition);

  // Keep secret until you want to finish the escrow
  const fulfillment_hex = fulfillment
    .serializeBinary()
    .toString('hex')
    .toUpperCase();
  console.log(
    'Fulfillment (keep secret until you want to finish the escrow):',
    fulfillment_hex
  );

  console.log();

  return {
    condition,
    fulfillment: fulfillment_hex,
  };
};

export type TransactionProps<T extends Transaction> = {
  txn: T;
  client: Client;
  wallet: Wallet;
};

export const escrowTransaction = async <T extends Transaction>({
  txn,
  client,
  wallet,
}: TransactionProps<T>) => {
  const escrowResponse = await client.submitAndWait(txn, {
    autofill: true,
    wallet,
  });

  console.log(JSON.stringify(escrowResponse, null, 2));

  return escrowResponse;
};

Finishing the escrow

To finish an escrow on the XRP Ledger, you must wait until the specified conditions are met, such as a time-based or cryptographic condition. Then, submit an "EscrowFinish" transaction, providing the necessary details like the condition, fulfillment, and sequence number, to release the locked funds to the designated recipient.

// Wait "WAITING_TIME" seconds before finishing the escrow
console.log(`Waiting ${WAITING_TIME} seconds`);
const sleep = (ms: number) => {
  return new Promise((resolve) => setTimeout(resolve, ms));
};

await sleep(WAITING_TIME * 1000);

await escrowTransaction({
  txn: {
    Account: walletTwo.address,
    TransactionType: 'EscrowFinish',
    Condition: condition,
    Fulfillment: fulfillment,
    OfferSequence: escrowCreateResponse.result.Sequence,
    Owner: walletOne.address,
  },
  client,
  wallet: walletTwo, // Make sure this is the wallet which was in the "Destination" field during the escrow creation
});
console.log('Escrow transaction sent successfully');
await client.disconnect();

After this step, the escrow transaction has been successfully submitted to the XRP Ledger, signaling the completion of the escrow process. The funds should now be released to the designated recipient, provided all conditions have been met. The client is then disconnected from the network, indicating the end of the transaction session.

Extra credits

Canceling your escrow

If the conditions aren't met, you can cancel the escrow with the EscrowCancel transaction type:

await escrowTransaction({
  txn: {
    Account: walletOne.address, // The account submitting the cancel request
    TransactionType: 'EscrowCancel',
    Owner: walletOne.address, // The account that created the escrow
    OfferSequence: escrowCreateResponse.result.Sequence, // The sequence number of the EscrowCreate transaction
  },
  client,
  wallet: walletOne, // The wallet of the account that created the escrow
});

Use the escrow as a smart contract

You can use XRP Ledger escrows as smart contracts that release XRP after a certain time has passed or after a cryptographic condition has been fulfilled.

PreviousPathFindingNextPrice Oracles

Last updated 2 months ago

The training in video
Learn more about escrow cancel
Learn about escrow as a smart contract