{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-sidebars.yaml","index-page-items":"/docs/tutorials/payments/send-fungible-token-escrows_index-page-items"},"props":{"metadata":{"markdoc":{"tagList":["admonition","amendment-disclaimer","repo-link","tabs","tab","code-snippet"]},"redocly_category":"Documentation","type":"markdown","indexPage":true},"seo":{"title":"Send Fungible Token Escrows","siteUrl":"https://xrpl.org/","llmstxt":{"hide":false,"title":"XRPL Developer Portal & Documentation","description":"Explore XRP Ledger documentation, blogs, and other blockchain developer resources needed to start building and integrating with the ledger.","details":{"content":"XRP Ledger concepts, use cases, tutorials, references, and other blockchain developer resources. Also, stay up to date with release announcements and more through the XRPL Blog."},"sections":[{"title":"Introduction","description":"A high-level introduction to the XRP Ledger.","includeFiles":["docs/introduction/**/*.*","about/faq.md"],"excludeFiles":["docs/introduction/index.md"]},{"title":"Use Cases","description":"Real-world applications and business scenarios for the XRP Ledger.","includeFiles":["docs/use-cases/**/*.*"],"excludeFiles":["docs/use-cases/index.md","docs/use-cases/defi/index.md"]},{"title":"Concepts","description":"Core concepts including accounts, tokens, transactions, consensus, and more.","includeFiles":["docs/concepts/**/*.*"],"excludeFiles":["docs/concepts/index.md","docs/concepts/decentralized-storage/index.md","docs/concepts/payment-types/index.md"]},{"title":"Tutorials","description":"Step-by-step guides for building on the XRP Ledger in JavaScript, Python, Go, and more.","includeFiles":["docs/tutorials/**/*.*"],"excludeFiles":[]},{"title":"References","description":"Protocol specification, transaction types, ledger entries, and API methods.","includeFiles":["docs/references/**/*.*"],"excludeFiles":["docs/references/xrp-api.md","docs/references/data-api.md","docs/references/protocol/index.md","docs/references/protocol/ledger-data/ledger-entry-types/index.md","docs/references/protocol/transactions/index.md","docs/references/protocol/transactions/types/index.md","docs/references/http-websocket-apis/api-conventions/index.md","docs/references/http-websocket-apis/public-api-methods/*/index.md","docs/references/http-websocket-apis/admin-api-methods/*/index.md"]},{"title":"Infrastructure","description":"Install, configure, and troubleshoot rippled and Clio servers.","includeFiles":["docs/infrastructure/**/*.*"],"excludeFiles":["docs/infrastructure/index.md","docs/infrastructure/*/index.md","docs/infrastructure/installation/build-run-rippled-in-reporting-mode.md","docs/infrastructure/configuration/data-retention/index.md","docs/infrastructure/configuration/server-modes/index.md"]},{"title":"Blog (2023+)","description":"Recent XRPL Blog posts (showing 2023 and newer).","includeFiles":["blog/2023/**/*.*","blog/2024/**/*.*","blog/2025/**/*.*","blog/2026/**/*.*"],"excludeFiles":[]},{"title":"Resources","description":"Developer resources and contribution guidelines.","includeFiles":["resources/**/*.*"],"excludeFiles":["resources/index.md"]}],"excludeFiles":[]},"description":"Create and finish escrows that hold fungible tokens (MPTs and trust line tokens) on the XRP Ledger."},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"send-fungible-token-escrows","__idx":0},"children":["Send Fungible Token Escrows"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This tutorial shows you how to create and finish escrows that hold fungible tokens on the XRP Ledger. It covers two types of fungible token escrows:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Conditional MPT escrow"]},": An escrow holding ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/fungible-tokens/multi-purpose-tokens"},"children":["Multi-Purpose Tokens"]}," that is released when a crypto-condition is fulfilled."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Timed trust line token escrow"]},": An escrow holding ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/fungible-tokens/trust-line-tokens"},"children":["trust line tokens"]}," that is released after a specified time."]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info","name":"Note"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Though this tutorial covers these two specific scenarios, both fungible token types can be used in either conditional or timed escrows."]}]},{"$$mdtype":"Tag","name":"AmendmentDisclaimer","attributes":{"name":"TokenEscrow","compact":false,"mode":""},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"goals","__idx":1},"children":["Goals"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["By the end of this tutorial, you will be able to:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Issue an MPT with escrow support enabled."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Create and finish a conditional escrow that holds MPTs."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Enable trust line token escrows on an issuer account."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Create and finish a timed escrow that holds trust line tokens."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"prerequisites","__idx":2},"children":["Prerequisites"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To complete this tutorial, you should:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Have a basic understanding of the XRP Ledger."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Have an XRP Ledger client library installed. This page provides examples for the following:",{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["JavaScript"]}," with the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://github.com/XRPLF/xrpl.js"},"children":["xrpl.js library"]},". See ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/tutorials/get-started/get-started-javascript"},"children":["Get Started Using JavaScript"]}," for setup steps."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Python"]}," with the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://github.com/XRPLF/xrpl-py"},"children":["xrpl-py library"]},". See ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/tutorials/get-started/get-started-python"},"children":["Get Started Using Python"]}," for setup steps."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Go"]}," with the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://github.com/XRPLF/xrpl-go"},"children":["xrpl-go library"]},". See ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/tutorials/get-started/get-started-go"},"children":["Get Started Using Go"]}," for setup steps."]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"source-code","__idx":3},"children":["Source Code"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can find the complete source code for this tutorial's examples in the ",{"$$mdtype":"Tag","name":"RepoLink","attributes":{"path":"_code-samples/escrow/","github_fork":"https://github.com/XRPLF/xrpl-dev-portal","github_branch":"master"},"children":["code samples section of this website's repository"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"steps","__idx":4},"children":["Steps"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"1-install-dependencies","__idx":5},"children":["1. Install dependencies"]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["From the code sample folder, use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["npm"]}," to install dependencies."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"npm install\n","lang":"bash"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["From the code sample folder, set up a virtual environment and use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["pip"]}," to install dependencies."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"python3 -m venv .venv\nsource .venv/bin/activate\npip install -r requirements.txt\n","lang":"bash"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Go","disable":false},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["From the code sample folder, use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["go"]}," to install dependencies."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"go mod tidy\n","lang":"bash"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"2-set-up-client-and-fund-accounts","__idx":6},"children":["2. Set up client and fund accounts"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Import the necessary libraries, instantiate a client to connect to the XRPL, and fund two new accounts (",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Issuer"]}," and ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Escrow Creator"]},"). This example imports:"]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["xrpl"]},": Used for XRPL client connection, transaction submission, and wallet handling."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["five-bells-condition"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["crypto"]},": Used to generate a crypto-condition."]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/js/sendFungibleTokenEscrow.js","language":"js","header":{"controls":{"copy":{}}},"lang":"js","source":"// This example demonstrates how to create escrows that hold fungible tokens.\n// It covers MPTs and Trust Line Tokens, and uses conditional and timed escrows.\n\nimport xrpl from 'xrpl'\nimport { PreimageSha256 } from 'five-bells-condition'\nimport { randomBytes } from 'crypto'\n\nconst client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')\nawait client.connect()\n\n// Fund an issuer account and an escrow creator account ----------------------\nconsole.log(`\\n=== Funding Accounts ===\\n`)\nconst [\n  { wallet: issuer },\n  { wallet: creator }\n] = await Promise.all([\n  client.fundWallet(),\n  client.fundWallet()\n])\nconsole.log(`Issuer: ${issuer.address}`)\nconsole.log(`Escrow Creator: ${creator.address}`)"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["xrpl"]},": Used for XRPL client connection, transaction submission, and wallet handling."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["json"]},": Used for loading and formatting JSON data."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["os"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cryptoconditions"]},": Used to generate a crypto-condition."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["datetime"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["time"]},": Used for time calculations."]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/py/send_fungible_token_escrow.py","language":"py","header":{"controls":{"copy":{}}},"lang":"py","source":"# This example demonstrates how to create escrows that hold fungible tokens.\n# It covers MPTs and Trust Line Tokens, and uses conditional and timed escrows.\n\nimport json\nfrom datetime import datetime, timedelta, UTC\nfrom os import urandom\nfrom time import sleep\n\nfrom cryptoconditions import PreimageSha256\nfrom xrpl.clients import JsonRpcClient\nfrom xrpl.models import (\n    AccountSet,\n    EscrowCreate,\n    EscrowFinish,\n    MPTokenAuthorize,\n    MPTokenIssuanceCreate,\n    Payment,\n    TrustSet,\n)\nfrom xrpl.models.amounts import IssuedCurrencyAmount, MPTAmount\nfrom xrpl.models.requests import Ledger\nfrom xrpl.models.transactions.account_set import AccountSetAsfFlag\nfrom xrpl.models.transactions.mptoken_issuance_create import MPTokenIssuanceCreateFlag\nfrom xrpl.transaction import submit_and_wait\nfrom xrpl.utils import datetime_to_ripple_time, ripple_time_to_datetime\nfrom xrpl.wallet import generate_faucet_wallet\n\nclient = JsonRpcClient(\"https://s.altnet.rippletest.net:51234\")\n\n# Fund an issuer account and an escrow creator account ----------------------\nprint(\"\\n=== Funding Accounts ===\\n\")\nissuer = generate_faucet_wallet(client, debug=True)\ncreator = generate_faucet_wallet(client, debug=True)\nprint(f\"Issuer: {issuer.address}\")\nprint(f\"Escrow Creator: {creator.address}\")"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Go","disable":false},"children":[{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["xrpl-go"]},": Used for XRPL client connection, transaction submission, and wallet handling."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["encoding/json"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["strings"]},", and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["fmt"]},": Used for formatting and printing results to the console."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cryptoconditions"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["crypto/rand"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["encoding/hex"]},": Used to generate a crypto-condition."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["time"]},": Used for time calculations."]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/go/send-fungible-token-escrow/main.go","language":"go","header":{"controls":{"copy":{}}},"lang":"go","source":"// This example demonstrates how to create escrows that hold fungible tokens.\n// It covers MPTs and Trust Line Tokens, and uses conditional and timed escrows.\n\npackage main\n\nimport (\n\t\"crypto/rand\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/Peersyst/xrpl-go/pkg/crypto\"\n\t\"github.com/Peersyst/xrpl-go/xrpl/faucet\"\n\t\"github.com/Peersyst/xrpl-go/xrpl/queries/account\"\n\t\"github.com/Peersyst/xrpl-go/xrpl/queries/common\"\n\tledgerreq \"github.com/Peersyst/xrpl-go/xrpl/queries/ledger\"\n\txrpltime \"github.com/Peersyst/xrpl-go/xrpl/time\"\n\t\"github.com/Peersyst/xrpl-go/xrpl/transaction\"\n\t\"github.com/Peersyst/xrpl-go/xrpl/transaction/types\"\n\t\"github.com/Peersyst/xrpl-go/xrpl/wallet\"\n\t\"github.com/Peersyst/xrpl-go/xrpl/websocket\"\n\twstypes \"github.com/Peersyst/xrpl-go/xrpl/websocket/types\"\n\t\"github.com/go-interledger/cryptoconditions\"\n)\n\nfunc main() {\n\tclient := websocket.NewClient(\n\t\twebsocket.NewClientConfig().\n\t\t\tWithHost(\"wss://s.altnet.rippletest.net:51233\").\n\t\t\tWithFaucetProvider(faucet.NewTestnetFaucetProvider()),\n\t)\n\tdefer client.Disconnect()\n\n\tif err := client.Connect(); err != nil {\n\t\tpanic(err)\n\t}\n\n\t// Fund an issuer account and an escrow creator account ----------------------\n\tfmt.Printf(\"\\n=== Funding Accounts ===\\n\\n\")\n\n\tcreateAndFund := func(label string) wallet.Wallet {\n\t\tfmt.Printf(\"Funding %s account...\\n\", label)\n\t\tw, err := wallet.New(crypto.ED25519())\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tif err := client.FundWallet(&w); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\t// Poll until account is validated on ledger\n\t\tfunded := false\n\t\tfor range 20 {\n\t\t\t_, err := client.Request(&account.InfoRequest{\n\t\t\t\tAccount:     w.GetAddress(),\n\t\t\t\tLedgerIndex: common.Validated,\n\t\t\t})\n\t\t\tif err == nil {\n\t\t\t\tfunded = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ttime.Sleep(time.Second)\n\t\t}\n\t\tif !funded {\n\t\t\tpanic(\"Issue funding account: \" + w.GetAddress().String())\n\t\t}\n\t\treturn w\n\t}\n\n\tissuer := createAndFund(\"Issuer\")\n\tcreator := createAndFund(\"Escrow Creator\")\n\tfmt.Printf(\"Issuer: %s\\n\", issuer.ClassicAddress)\n\tfmt.Printf(\"Escrow Creator: %s\\n\", creator.ClassicAddress)\n\n\t"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"3-issue-an-mpt-with-escrow-support","__idx":7},"children":["3. Issue an MPT with escrow support"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Construct an ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/mptokenissuancecreate"},"children":["MPTokenIssuanceCreate transaction"]}," with the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["tfMPTCanEscrow"]}," flag, which enables the token to be held in escrows. Then, retrieve the MPT issuance ID from the transaction result. This example creates an escrow that sends MPTs back to the original issuer. If you wanted to create an escrow for another account, the issuer would also have to set the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["tfMPTCanTransfer"]}," flag."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/js/sendFungibleTokenEscrow.js","language":"js","header":{"controls":{"copy":{}}},"lang":"js","source":"// ====== Conditional MPT Escrow ======\n\n// Issuer creates an MPT ----------------------\nconsole.log('\\n=== Creating MPT ===\\n')\nconst mptCreateTx = {\n  TransactionType: 'MPTokenIssuanceCreate',\n  Account: issuer.address,\n  MaximumAmount: '1000000',\n  Flags: xrpl.MPTokenIssuanceCreateFlags.tfMPTCanEscrow\n}\n\n// Validate the transaction structure before submitting\nxrpl.validate(mptCreateTx)\nconsole.log(JSON.stringify(mptCreateTx, null, 2))\n\n// Submit, sign, and wait for validation\nconsole.log(`\\nSubmitting MPTokenIssuanceCreate transaction...`)\nconst mptCreateResponse = await client.submitAndWait(mptCreateTx, {\n  wallet: issuer,\n  autofill: true\n})\nif (mptCreateResponse.result.meta.TransactionResult !== 'tesSUCCESS') {\n  console.error(`MPTokenIssuanceCreate failed: ${mptCreateResponse.result.meta.TransactionResult}`)\n  await client.disconnect()\n  process.exit(1)\n}\n\n// Extract the MPT issuance ID from the transaction result\nconst mptIssuanceId = mptCreateResponse.result.meta.mpt_issuance_id\nconsole.log(`MPT created: ${mptIssuanceId}`)"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/py/send_fungible_token_escrow.py","language":"py","header":{"controls":{"copy":{}}},"lang":"py","source":"# ====== Conditional MPT Escrow ======\n\n# Issuer creates an MPT ----------------------\nprint(\"\\n=== Creating MPT ===\\n\")\nmpt_create_tx = MPTokenIssuanceCreate(\n    account=issuer.address,\n    maximum_amount=\"1000000\",\n    flags=MPTokenIssuanceCreateFlag.TF_MPT_CAN_ESCROW,\n)\n\nprint(json.dumps(mpt_create_tx.to_xrpl(), indent=2))\n\n# Submit, sign, and wait for validation\nprint(\"\\nSubmitting MPTokenIssuanceCreate transaction...\")\nmpt_create_response = submit_and_wait(mpt_create_tx, client, issuer)\n\nif mpt_create_response.result[\"meta\"][\"TransactionResult\"] != \"tesSUCCESS\":\n    print(f\"MPTokenIssuanceCreate failed: {mpt_create_response.result['meta']['TransactionResult']}\")\n    exit(1)\n\n# Extract the MPT issuance ID from the transaction result\nmpt_issuance_id = mpt_create_response.result[\"meta\"][\"mpt_issuance_id\"]\nprint(f\"MPT created: {mpt_issuance_id}\")"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Go","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/go/send-fungible-token-escrow/main.go","language":"go","header":{"controls":{"copy":{}}},"lang":"go","source":"\t// ====== Conditional MPT Escrow ======\n\n\t// Issuer creates an MPT ----------------------\n\tfmt.Printf(\"\\n=== Creating MPT ===\\n\\n\")\n\tmaxAmount := types.XRPCurrencyAmount(1000000)\n\tmptCreateTx := transaction.MPTokenIssuanceCreate{\n\t\tBaseTx: transaction.BaseTx{\n\t\t\tAccount: issuer.ClassicAddress,\n\t\t\tFlags:   transaction.TfMPTCanEscrow,\n\t\t},\n\t\tMaximumAmount: &maxAmount,\n\t}\n\n\t// Flatten() converts the struct to a map and adds the TransactionType field\n\tflatMptCreateTx := mptCreateTx.Flatten()\n\tmptCreateTxJSON, _ := json.MarshalIndent(flatMptCreateTx, \"\", \"  \")\n\tfmt.Printf(\"%s\\n\", string(mptCreateTxJSON))\n\n\t// Submit, sign, and wait for validation\n\tfmt.Printf(\"\\nSubmitting MPTokenIssuanceCreate transaction...\\n\")\n\tmptCreateResponse, err := client.SubmitTxAndWait(flatMptCreateTx, &wstypes.SubmitOptions{\n\t\tAutofill: true,\n\t\tWallet:   &issuer,\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tif mptCreateResponse.Meta.TransactionResult != \"tesSUCCESS\" {\n\t\tfmt.Printf(\"MPTokenIssuanceCreate failed: %s\\n\", mptCreateResponse.Meta.TransactionResult)\n\t\tos.Exit(1)\n\t}\n\n\t// Extract the MPT issuance ID from the transaction result\n\tmptIssuanceID := string(*mptCreateResponse.Meta.MPTIssuanceID)\n\tfmt.Printf(\"MPT created: %s\\n\", mptIssuanceID)\n\n\t"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"4-authorize-the-mpt","__idx":8},"children":["4. Authorize the MPT"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Before the escrow creator can hold the MPT, they must indicate their willingness to hold it with the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/mptokenauthorize"},"children":["MPTokenAuthorize transaction"]},"."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/js/sendFungibleTokenEscrow.js","language":"js","header":{"controls":{"copy":{}}},"lang":"js","source":"// Escrow Creator authorizes the MPT ----------------------\nconsole.log('\\n=== Escrow Creator Authorizing MPT ===\\n')\nconst mptAuthTx = {\n  TransactionType: 'MPTokenAuthorize',\n  Account: creator.address,\n  MPTokenIssuanceID: mptIssuanceId\n}\n\nxrpl.validate(mptAuthTx)\nconsole.log(JSON.stringify(mptAuthTx, null, 2))\n\nconsole.log(`\\nSubmitting MPTokenAuthorize transaction...`)\nconst mptAuthResponse = await client.submitAndWait(mptAuthTx, {\n  wallet: creator,\n  autofill: true\n})\nif (mptAuthResponse.result.meta.TransactionResult !== 'tesSUCCESS') {\n  console.error(`MPTokenAuthorize failed: ${mptAuthResponse.result.meta.TransactionResult}`)\n  await client.disconnect()\n  process.exit(1)\n}\nconsole.log('Escrow Creator authorized for MPT.')"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/py/send_fungible_token_escrow.py","language":"py","header":{"controls":{"copy":{}}},"lang":"py","source":"# Escrow Creator authorizes the MPT ----------------------\nprint(\"\\n=== Escrow Creator Authorizing MPT ===\\n\")\nmpt_auth_tx = MPTokenAuthorize(\n    account=creator.address,\n    mptoken_issuance_id=mpt_issuance_id,\n)\n\nprint(json.dumps(mpt_auth_tx.to_xrpl(), indent=2))\n\nprint(\"\\nSubmitting MPTokenAuthorize transaction...\")\nmpt_auth_response = submit_and_wait(mpt_auth_tx, client, creator)\n\nif mpt_auth_response.result[\"meta\"][\"TransactionResult\"] != \"tesSUCCESS\":\n    print(f\"MPTokenAuthorize failed: {mpt_auth_response.result['meta']['TransactionResult']}\")\n    exit(1)\nprint(\"Escrow Creator authorized for MPT.\")"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Go","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/go/send-fungible-token-escrow/main.go","language":"go","header":{"controls":{"copy":{}}},"lang":"go","source":"\t// Escrow Creator authorizes the MPT ----------------------\n\tfmt.Printf(\"\\n=== Escrow Creator Authorizing MPT ===\\n\\n\")\n\tmptAuthTx := transaction.MPTokenAuthorize{\n\t\tBaseTx: transaction.BaseTx{\n\t\t\tAccount: creator.ClassicAddress,\n\t\t},\n\t\tMPTokenIssuanceID: mptIssuanceID,\n\t}\n\n\tflatMptAuthTx := mptAuthTx.Flatten()\n\tmptAuthTxJSON, _ := json.MarshalIndent(flatMptAuthTx, \"\", \"  \")\n\tfmt.Printf(\"%s\\n\", string(mptAuthTxJSON))\n\n\tfmt.Printf(\"\\nSubmitting MPTokenAuthorize transaction...\\n\")\n\tmptAuthResponse, err := client.SubmitTxAndWait(flatMptAuthTx, &wstypes.SubmitOptions{\n\t\tAutofill: true,\n\t\tWallet:   &creator,\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tif mptAuthResponse.Meta.TransactionResult != \"tesSUCCESS\" {\n\t\tfmt.Printf(\"MPTokenAuthorize failed: %s\\n\", mptAuthResponse.Meta.TransactionResult)\n\t\tos.Exit(1)\n\t}\n\tfmt.Printf(\"Escrow Creator authorized for MPT.\\n\")\n\n\t"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"5-send-mpts-to-the-escrow-creator","__idx":9},"children":["5. Send MPTs to the escrow creator"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Send MPTs from the issuer to the escrow creator using a ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/payment"},"children":["Payment transaction"]},"."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/js/sendFungibleTokenEscrow.js","language":"js","header":{"controls":{"copy":{}}},"lang":"js","source":"// Issuer sends MPTs to escrow creator ----------------------\nconsole.log('\\n=== Issuer Sending MPTs to Escrow Creator ===\\n')\nconst mptPaymentTx = {\n  TransactionType: 'Payment',\n  Account: issuer.address,\n  Destination: creator.address,\n  Amount: {\n    mpt_issuance_id: mptIssuanceId,\n    value: '5000'\n  }\n}\n\nxrpl.validate(mptPaymentTx)\nconsole.log(JSON.stringify(mptPaymentTx, null, 2))\n\nconsole.log(`\\nSubmitting MPT Payment transaction...`)\nconst mptPaymentResponse = await client.submitAndWait(mptPaymentTx, {\n  wallet: issuer,\n  autofill: true\n})\nif (mptPaymentResponse.result.meta.TransactionResult !== 'tesSUCCESS') {\n  console.error(`MPT Payment failed: ${mptPaymentResponse.result.meta.TransactionResult}`)\n  await client.disconnect()\n  process.exit(1)\n}\nconsole.log('Successfully sent 5000 MPTs to Escrow Creator.')"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/py/send_fungible_token_escrow.py","language":"py","header":{"controls":{"copy":{}}},"lang":"py","source":"# Issuer sends MPTs to escrow creator ----------------------\nprint(\"\\n=== Issuer Sending MPTs to Escrow Creator ===\\n\")\nmpt_payment_tx = Payment(\n    account=issuer.address,\n    destination=creator.address,\n    amount=MPTAmount(\n        mpt_issuance_id=mpt_issuance_id,\n        value=\"5000\",\n    ),\n)\n\nprint(json.dumps(mpt_payment_tx.to_xrpl(), indent=2))\n\nprint(\"\\nSubmitting MPT Payment transaction...\")\nmpt_payment_response = submit_and_wait(mpt_payment_tx, client, issuer)\n\nif mpt_payment_response.result[\"meta\"][\"TransactionResult\"] != \"tesSUCCESS\":\n    print(f\"MPT Payment failed: {mpt_payment_response.result['meta']['TransactionResult']}\")\n    exit(1)\nprint(\"Successfully sent 5000 MPTs to Escrow Creator.\")"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Go","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/go/send-fungible-token-escrow/main.go","language":"go","header":{"controls":{"copy":{}}},"lang":"go","source":"\t// Issuer sends MPTs to escrow creator ----------------------\n\tfmt.Printf(\"\\n=== Issuer Sending MPTs to Escrow Creator ===\\n\\n\")\n\tmptPaymentTx := transaction.Payment{\n\t\tBaseTx: transaction.BaseTx{\n\t\t\tAccount: issuer.ClassicAddress,\n\t\t},\n\t\tDestination: creator.ClassicAddress,\n\t\tAmount: types.MPTCurrencyAmount{\n\t\t\tMPTIssuanceID: mptIssuanceID,\n\t\t\tValue:         \"5000\",\n\t\t},\n\t}\n\n\tflatMptPaymentTx := mptPaymentTx.Flatten()\n\tmptPaymentTxJSON, _ := json.MarshalIndent(flatMptPaymentTx, \"\", \"  \")\n\tfmt.Printf(\"%s\\n\", string(mptPaymentTxJSON))\n\n\tfmt.Printf(\"\\nSubmitting MPT Payment transaction...\\n\")\n\tmptPaymentResponse, err := client.SubmitTxAndWait(flatMptPaymentTx, &wstypes.SubmitOptions{\n\t\tAutofill: true,\n\t\tWallet:   &issuer,\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tif mptPaymentResponse.Meta.TransactionResult != \"tesSUCCESS\" {\n\t\tfmt.Printf(\"MPT Payment failed: %s\\n\", mptPaymentResponse.Meta.TransactionResult)\n\t\tos.Exit(1)\n\t}\n\tfmt.Printf(\"Successfully sent 5000 MPTs to Escrow Creator.\\n\")\n\n\t"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"6-create-a-condition-and-fulfillment","__idx":10},"children":["6. Create a condition and fulfillment"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Conditional escrows require a fulfillment and its corresponding condition in the format of a PREIMAGE-SHA-256 ",{"$$mdtype":"Tag","name":"em","attributes":{},"children":["crypto-condition"]},", represented as hexadecimal. To calculate these in the correct format, use a crypto-conditions library. Generally, you want to generate the fulfillment using at least 32 random bytes from a cryptographically secure source of randomness."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/js/sendFungibleTokenEscrow.js","language":"js","header":{"controls":{"copy":{}}},"lang":"js","source":"// Escrow Creator creates a conditional MPT escrow ----------------------\nconsole.log('\\n=== Creating Conditional MPT Escrow ===\\n')\n\n// Generate crypto-condition\nconst preimage = randomBytes(32)\nconst fulfillment = new PreimageSha256()\nfulfillment.setPreimage(preimage)\nconst fulfillmentHex = fulfillment.serializeBinary().toString('hex').toUpperCase()\nconst conditionHex = fulfillment.getConditionBinary().toString('hex').toUpperCase()\nconsole.log(`Condition: ${conditionHex}`)\nconsole.log(`Fulfillment: ${fulfillmentHex}\\n`)"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/py/send_fungible_token_escrow.py","language":"py","header":{"controls":{"copy":{}}},"lang":"py","source":"# Escrow Creator creates a conditional MPT escrow ----------------------\nprint(\"\\n=== Creating Conditional MPT Escrow ===\\n\")\n\n# Generate crypto-condition\npreimage = urandom(32)\nfulfillment = PreimageSha256(preimage=preimage)\nfulfillment_hex = fulfillment.serialize_binary().hex().upper()\ncondition_hex = fulfillment.condition_binary.hex().upper()\nprint(f\"Condition: {condition_hex}\")\nprint(f\"Fulfillment: {fulfillment_hex}\\n\")"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Go","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/go/send-fungible-token-escrow/main.go","language":"go","header":{"controls":{"copy":{}}},"lang":"go","source":"\t// Escrow Creator creates a conditional MPT escrow ----------------------\n\tfmt.Printf(\"\\n=== Creating Conditional MPT Escrow ===\\n\\n\")\n\n\t// Generate crypto-condition\n\tpreimage := make([]byte, 32)\n\tif _, err := rand.Read(preimage); err != nil {\n\t\tpanic(err)\n\t}\n\tfulfillment := cryptoconditions.NewPreimageSha256(preimage)\n\tfulfillmentBinary, err := fulfillment.Encode()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tconditionBinary, err := fulfillment.Condition().Encode()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfulfillmentHex := strings.ToUpper(hex.EncodeToString(fulfillmentBinary))\n\tconditionHex := strings.ToUpper(hex.EncodeToString(conditionBinary))\n\tfmt.Printf(\"Condition: %s\\n\", conditionHex)\n\tfmt.Printf(\"Fulfillment: %s\\n\\n\", fulfillmentHex)\n\n\t"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"7-create-the-conditional-mpt-escrow","__idx":11},"children":["7. Create the conditional MPT escrow"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Create a conditional escrow using the generated crypto-condition. Fungible token escrows require an expiration date. This example sets an expiration time of five minutes. After creating the escrow, save the sequence number to reference it later."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/js/sendFungibleTokenEscrow.js","language":"js","header":{"controls":{"copy":{}}},"lang":"js","source":"// Set expiration (300 seconds from now)\nconst cancelAfter = new Date()\ncancelAfter.setSeconds(cancelAfter.getSeconds() + 300)\nconst cancelAfterRippleTime = xrpl.isoTimeToRippleTime(cancelAfter.toISOString())\n\nconst mptEscrowCreateTx = {\n  TransactionType: 'EscrowCreate',\n  Account: creator.address,\n  Destination: issuer.address,\n  Amount: {\n    mpt_issuance_id: mptIssuanceId,\n    value: '1000'\n  },\n  Condition: conditionHex,\n  CancelAfter: cancelAfterRippleTime // Fungible token escrows require a CancelAfter time\n}\n\nxrpl.validate(mptEscrowCreateTx)\nconsole.log(JSON.stringify(mptEscrowCreateTx, null, 2))\n\nconsole.log(`\\nSubmitting MPT EscrowCreate transaction...`)\nconst mptEscrowResponse = await client.submitAndWait(mptEscrowCreateTx, {\n  wallet: creator,\n  autofill: true\n})\nif (mptEscrowResponse.result.meta.TransactionResult !== 'tesSUCCESS') {\n  console.error(`MPT EscrowCreate failed: ${mptEscrowResponse.result.meta.TransactionResult}`)\n  await client.disconnect()\n  process.exit(1)\n}\n\n// Save the sequence number to identify the escrow later\nconst mptEscrowSeq = mptEscrowResponse.result.tx_json.Sequence\nconsole.log(`Conditional MPT escrow created. Sequence: ${mptEscrowSeq}`)"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/py/send_fungible_token_escrow.py","language":"py","header":{"controls":{"copy":{}}},"lang":"py","source":"# Set expiration (300 seconds from now)\ncancel_after = datetime.now(tz=UTC) + timedelta(seconds=300)\ncancel_after_ripple_time = datetime_to_ripple_time(cancel_after)\n\nmpt_escrow_create_tx = EscrowCreate(\n    account=creator.address,\n    destination=issuer.address,\n    amount=MPTAmount(\n        mpt_issuance_id=mpt_issuance_id,\n        value=\"1000\",\n    ),\n    condition=condition_hex,\n    cancel_after=cancel_after_ripple_time,  # Fungible token escrows require a cancel_after time\n)\n\nprint(json.dumps(mpt_escrow_create_tx.to_xrpl(), indent=2))\n\nprint(\"\\nSubmitting MPT EscrowCreate transaction...\")\nmpt_escrow_response = submit_and_wait(mpt_escrow_create_tx, client, creator)\n\nif mpt_escrow_response.result[\"meta\"][\"TransactionResult\"] != \"tesSUCCESS\":\n    print(f\"MPT EscrowCreate failed: {mpt_escrow_response.result['meta']['TransactionResult']}\")\n    exit(1)\n\n# Save the sequence number to identify the escrow later\nmpt_escrow_seq = mpt_escrow_response.result[\"tx_json\"][\"Sequence\"]\nprint(f\"Conditional MPT escrow created. Sequence: {mpt_escrow_seq}\")"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Go","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/go/send-fungible-token-escrow/main.go","language":"go","header":{"controls":{"copy":{}}},"lang":"go","source":"\t// Set expiration (300 seconds from now)\n\tcancelAfterRippleTime := xrpltime.UnixTimeToRippleTime(time.Now().Unix()) + 300\n\n\tmptEscrowCreateTx := transaction.EscrowCreate{\n\t\tBaseTx: transaction.BaseTx{\n\t\t\tAccount: creator.ClassicAddress,\n\t\t},\n\t\tDestination: issuer.ClassicAddress,\n\t\tAmount: types.MPTCurrencyAmount{\n\t\t\tMPTIssuanceID: mptIssuanceID,\n\t\t\tValue:         \"1000\",\n\t\t},\n\t\tCondition:   conditionHex,\n\t\tCancelAfter: uint32(cancelAfterRippleTime), // Fungible token escrows require a CancelAfter time\n\t}\n\n\tflatMptEscrowCreateTx := mptEscrowCreateTx.Flatten()\n\tmptEscrowCreateTxJSON, _ := json.MarshalIndent(flatMptEscrowCreateTx, \"\", \"  \")\n\tfmt.Printf(\"%s\\n\", string(mptEscrowCreateTxJSON))\n\n\tfmt.Printf(\"\\nSubmitting MPT EscrowCreate transaction...\\n\")\n\tmptEscrowResponse, err := client.SubmitTxAndWait(flatMptEscrowCreateTx, &wstypes.SubmitOptions{\n\t\tAutofill: true,\n\t\tWallet:   &creator,\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tif mptEscrowResponse.Meta.TransactionResult != \"tesSUCCESS\" {\n\t\tfmt.Printf(\"MPT EscrowCreate failed: %s\\n\", mptEscrowResponse.Meta.TransactionResult)\n\t\tos.Exit(1)\n\t}\n\n\t// Save the sequence number to identify the escrow later\n\tmptEscrowSeq := mptEscrowResponse.TxJSON.Sequence()\n\tfmt.Printf(\"Conditional MPT escrow created. Sequence: %d\\n\", mptEscrowSeq)\n\n\t"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"8-finish-the-conditional-mpt-escrow","__idx":12},"children":["8. Finish the conditional MPT escrow"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Finish the escrow by providing the original condition and its matching fulfillment."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/js/sendFungibleTokenEscrow.js","language":"js","header":{"controls":{"copy":{}}},"lang":"js","source":"// Finish the conditional MPT escrow with the fulfillment ----------------------\nconsole.log('\\n=== Finishing Conditional MPT Escrow ===\\n')\nconst mptEscrowFinishTx = {\n  TransactionType: 'EscrowFinish',\n  Account: creator.address,\n  Owner: creator.address,\n  OfferSequence: mptEscrowSeq,\n  Condition: conditionHex,\n  Fulfillment: fulfillmentHex\n}\n\nxrpl.validate(mptEscrowFinishTx)\nconsole.log(JSON.stringify(mptEscrowFinishTx, null, 2))\n\nconsole.log(`\\nSubmitting EscrowFinish transaction...`)\nconst mptFinishResponse = await client.submitAndWait(mptEscrowFinishTx, {\n  wallet: creator,\n  autofill: true\n})\nif (mptFinishResponse.result.meta.TransactionResult !== 'tesSUCCESS') {\n  console.error(`MPT EscrowFinish failed: ${mptFinishResponse.result.meta.TransactionResult}`)\n  await client.disconnect()\n  process.exit(1)\n}\nconsole.log(`Conditional MPT escrow finished successfully: https://testnet.xrpl.org/transactions/${mptFinishResponse.result.hash}`)"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/py/send_fungible_token_escrow.py","language":"py","header":{"controls":{"copy":{}}},"lang":"py","source":"# Finish the conditional MPT escrow with the fulfillment ----------------------\nprint(\"\\n=== Finishing Conditional MPT Escrow ===\\n\")\nmpt_escrow_finish_tx = EscrowFinish(\n    account=creator.address,\n    owner=creator.address,\n    offer_sequence=mpt_escrow_seq,\n    condition=condition_hex,\n    fulfillment=fulfillment_hex,\n)\n\nprint(json.dumps(mpt_escrow_finish_tx.to_xrpl(), indent=2))\n\nprint(\"\\nSubmitting EscrowFinish transaction...\")\nmpt_finish_response = submit_and_wait(mpt_escrow_finish_tx, client, creator)\n\nif mpt_finish_response.result[\"meta\"][\"TransactionResult\"] != \"tesSUCCESS\":\n    print(f\"MPT EscrowFinish failed: {mpt_finish_response.result['meta']['TransactionResult']}\")\n    exit(1)\nprint(f\"Conditional MPT escrow finished successfully: https://testnet.xrpl.org/transactions/{mpt_finish_response.result['hash']}\")"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Go","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/go/send-fungible-token-escrow/main.go","language":"go","header":{"controls":{"copy":{}}},"lang":"go","source":"\t// Finish the conditional MPT escrow with the fulfillment ----------------------\n\tfmt.Printf(\"\\n=== Finishing Conditional MPT Escrow ===\\n\\n\")\n\tmptEscrowFinishTx := transaction.EscrowFinish{\n\t\tBaseTx: transaction.BaseTx{\n\t\t\tAccount: creator.ClassicAddress,\n\t\t},\n\t\tOwner:         creator.ClassicAddress,\n\t\tOfferSequence: mptEscrowSeq,\n\t\tCondition:     conditionHex,\n\t\tFulfillment:   fulfillmentHex,\n\t}\n\n\tflatMptEscrowFinishTx := mptEscrowFinishTx.Flatten()\n\tmptEscrowFinishTxJSON, _ := json.MarshalIndent(flatMptEscrowFinishTx, \"\", \"  \")\n\tfmt.Printf(\"%s\\n\", string(mptEscrowFinishTxJSON))\n\n\tfmt.Printf(\"\\nSubmitting EscrowFinish transaction...\\n\")\n\tmptFinishResponse, err := client.SubmitTxAndWait(flatMptEscrowFinishTx, &wstypes.SubmitOptions{\n\t\tAutofill: true,\n\t\tWallet:   &creator,\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tif mptFinishResponse.Meta.TransactionResult != \"tesSUCCESS\" {\n\t\tfmt.Printf(\"MPT EscrowFinish failed: %s\\n\", mptFinishResponse.Meta.TransactionResult)\n\t\tos.Exit(1)\n\t}\n\tfmt.Printf(\"Conditional MPT escrow finished successfully: https://testnet.xrpl.org/transactions/%s\\n\", mptFinishResponse.Hash)\n\n\t"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"9-enable-trust-line-token-escrows","__idx":13},"children":["9. Enable trust line token escrows"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Token issuers enable trust line token escrows differently from MPTs. Unlike MPTs, which are escrowable at the token level, trust line tokens are escrowable at the account level. When an issuer enables the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["asfAllowTrustLineLocking"]}," flag on their account, ",{"$$mdtype":"Tag","name":"em","attributes":{},"children":["all"]}," trust line tokens issued from that account are escrowable."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/js/sendFungibleTokenEscrow.js","language":"js","header":{"controls":{"copy":{}}},"lang":"js","source":"// ====== Timed Trust Line Token Escrow ======\n\n// Enable trust line token escrows on the issuer ----------------------\nconsole.log('\\n=== Enabling Trust Line Token Escrows on Issuer ===\\n')\nconst accountSetTx = {\n  TransactionType: 'AccountSet',\n  Account: issuer.address,\n  SetFlag: xrpl.AccountSetAsfFlags.asfAllowTrustLineLocking\n}\n\nxrpl.validate(accountSetTx)\nconsole.log(JSON.stringify(accountSetTx, null, 2))\n\nconsole.log(`\\nSubmitting AccountSet transaction...`)\nconst accountSetResponse = await client.submitAndWait(accountSetTx, {\n  wallet: issuer,\n  autofill: true\n})\nif (accountSetResponse.result.meta.TransactionResult !== 'tesSUCCESS') {\n  console.error(`AccountSet failed: ${accountSetResponse.result.meta.TransactionResult}`)\n  await client.disconnect()\n  process.exit(1)\n}\nconsole.log('Trust line token escrows enabled by issuer.')"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/py/send_fungible_token_escrow.py","language":"py","header":{"controls":{"copy":{}}},"lang":"py","source":"# ====== Timed Trust Line Token Escrow ======\n\n# Enable trust line token escrows on the issuer ----------------------\nprint(\"\\n=== Enabling Trust Line Token Escrows on Issuer ===\\n\")\naccount_set_tx = AccountSet(\n    account=issuer.address,\n    set_flag=AccountSetAsfFlag.ASF_ALLOW_TRUSTLINE_LOCKING,\n)\n\nprint(json.dumps(account_set_tx.to_xrpl(), indent=2))\n\nprint(\"\\nSubmitting AccountSet transaction...\")\naccount_set_response = submit_and_wait(account_set_tx, client, issuer)\n\nif account_set_response.result[\"meta\"][\"TransactionResult\"] != \"tesSUCCESS\":\n    print(f\"AccountSet failed: {account_set_response.result['meta']['TransactionResult']}\")\n    exit(1)\nprint(\"Trust line token escrows enabled by issuer.\")"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Go","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/go/send-fungible-token-escrow/main.go","language":"go","header":{"controls":{"copy":{}}},"lang":"go","source":"\t// ====== Timed Trust Line Token Escrow ======\n\n\t// Enable trust line token escrows on the issuer ----------------------\n\tfmt.Printf(\"\\n=== Enabling Trust Line Token Escrows on Issuer ===\\n\\n\")\n\taccountSetTx := transaction.AccountSet{\n\t\tBaseTx: transaction.BaseTx{\n\t\t\tAccount: issuer.ClassicAddress,\n\t\t},\n\t\tSetFlag: transaction.AsfAllowTrustLineLocking,\n\t}\n\n\tflatAccountSetTx := accountSetTx.Flatten()\n\taccountSetTxJSON, _ := json.MarshalIndent(flatAccountSetTx, \"\", \"  \")\n\tfmt.Printf(\"%s\\n\", string(accountSetTxJSON))\n\n\tfmt.Printf(\"\\nSubmitting AccountSet transaction...\\n\")\n\taccountSetResponse, err := client.SubmitTxAndWait(flatAccountSetTx, &wstypes.SubmitOptions{\n\t\tAutofill: true,\n\t\tWallet:   &issuer,\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tif accountSetResponse.Meta.TransactionResult != \"tesSUCCESS\" {\n\t\tfmt.Printf(\"AccountSet failed: %s\\n\", accountSetResponse.Meta.TransactionResult)\n\t\tos.Exit(1)\n\t}\n\tfmt.Printf(\"Trust line token escrows enabled by issuer.\\n\")\n\n\t"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"10-set-up-a-trust-line","__idx":14},"children":["10. Set up a trust line"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Establish a trust line between the escrow creator and issuer using the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/trustset"},"children":["TrustSet transaction"]},". The escrow creator submits this transaction to indicate their willingness to receive the token, defining the currency and maximum amount they're willing to hold."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/js/sendFungibleTokenEscrow.js","language":"js","header":{"controls":{"copy":{}}},"lang":"js","source":"// Escrow Creator sets up a trust line to the issuer ----------------------\nconsole.log('\\n=== Setting Up Trust Line ===\\n')\nconst currencyCode = 'IOU'\n\nconst trustSetTx = {\n  TransactionType: 'TrustSet',\n  Account: creator.address,\n  LimitAmount: {\n    currency: currencyCode,\n    issuer: issuer.address,\n    value: '10000000'\n  }\n}\n\nxrpl.validate(trustSetTx)\nconsole.log(JSON.stringify(trustSetTx, null, 2))\n\nconsole.log(`\\nSubmitting TrustSet transaction...`)\nconst trustResponse = await client.submitAndWait(trustSetTx, {\n  wallet: creator,\n  autofill: true\n})\nif (trustResponse.result.meta.TransactionResult !== 'tesSUCCESS') {\n  console.error(`TrustSet failed: ${trustResponse.result.meta.TransactionResult}`)\n  await client.disconnect()\n  process.exit(1)\n}\nconsole.log(`Trust line successfully created for \"${currencyCode}\" tokens.`)"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/py/send_fungible_token_escrow.py","language":"py","header":{"controls":{"copy":{}}},"lang":"py","source":"# Escrow Creator sets up a trust line to the issuer ----------------------\nprint(\"\\n=== Setting Up Trust Line ===\\n\")\ncurrency_code = \"IOU\"\n\ntrust_set_tx = TrustSet(\n    account=creator.address,\n    limit_amount=IssuedCurrencyAmount(\n        currency=currency_code,\n        issuer=issuer.address,\n        value=\"10000000\",\n    ),\n)\n\nprint(json.dumps(trust_set_tx.to_xrpl(), indent=2))\n\nprint(\"\\nSubmitting TrustSet transaction...\")\ntrust_response = submit_and_wait(trust_set_tx, client, creator)\n\nif trust_response.result[\"meta\"][\"TransactionResult\"] != \"tesSUCCESS\":\n    print(f\"TrustSet failed: {trust_response.result['meta']['TransactionResult']}\")\n    exit(1)\nprint(f'Trust line successfully created for \"{currency_code}\" tokens.')"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Go","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/go/send-fungible-token-escrow/main.go","language":"go","header":{"controls":{"copy":{}}},"lang":"go","source":"\t// Escrow Creator sets up a trust line to the issuer ----------------------\n\tfmt.Printf(\"\\n=== Setting Up Trust Line ===\\n\\n\")\n\tcurrencyCode := \"IOU\"\n\n\ttrustSetTx := transaction.TrustSet{\n\t\tBaseTx: transaction.BaseTx{\n\t\t\tAccount: creator.ClassicAddress,\n\t\t},\n\t\tLimitAmount: types.IssuedCurrencyAmount{\n\t\t\tCurrency: currencyCode,\n\t\t\tIssuer:   issuer.ClassicAddress,\n\t\t\tValue:    \"10000000\",\n\t\t},\n\t}\n\n\tflatTrustSetTx := trustSetTx.Flatten()\n\ttrustSetTxJSON, _ := json.MarshalIndent(flatTrustSetTx, \"\", \"  \")\n\tfmt.Printf(\"%s\\n\", string(trustSetTxJSON))\n\n\tfmt.Printf(\"\\nSubmitting TrustSet transaction...\\n\")\n\ttrustResponse, err := client.SubmitTxAndWait(flatTrustSetTx, &wstypes.SubmitOptions{\n\t\tAutofill: true,\n\t\tWallet:   &creator,\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tif trustResponse.Meta.TransactionResult != \"tesSUCCESS\" {\n\t\tfmt.Printf(\"TrustSet failed: %s\\n\", trustResponse.Meta.TransactionResult)\n\t\tos.Exit(1)\n\t}\n\tfmt.Printf(\"Trust line successfully created for \\\"%s\\\" tokens.\\n\", currencyCode)\n\n\t"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"11-send-iou-tokens-to-the-escrow-creator","__idx":15},"children":["11. Send IOU tokens to the escrow creator"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Send IOU tokens from the issuer to the escrow creator using a ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/payment"},"children":["Payment transaction"]},"."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/js/sendFungibleTokenEscrow.js","language":"js","header":{"controls":{"copy":{}}},"lang":"js","source":"// Issuer sends IOU tokens to creator ----------------------\nconsole.log('\\n=== Issuer Sending IOU Tokens to Escrow Creator ===\\n')\nconst iouPaymentTx = {\n  TransactionType: 'Payment',\n  Account: issuer.address,\n  Destination: creator.address,\n  Amount: {\n    currency: currencyCode,\n    value: '5000',\n    issuer: issuer.address\n  }\n}\n\nxrpl.validate(iouPaymentTx)\nconsole.log(JSON.stringify(iouPaymentTx, null, 2))\n\nconsole.log(`\\nSubmitting Trust Line Token payment transaction...`)\nconst iouPayResponse = await client.submitAndWait(iouPaymentTx, {\n  wallet: issuer,\n  autofill: true\n})\nif (iouPayResponse.result.meta.TransactionResult !== 'tesSUCCESS') {\n  console.error(`Trust Line Token payment failed: ${iouPayResponse.result.meta.TransactionResult}`)\n  await client.disconnect()\n  process.exit(1)\n}\nconsole.log(`Successfully sent 5000 ${currencyCode} tokens.`)"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/py/send_fungible_token_escrow.py","language":"py","header":{"controls":{"copy":{}}},"lang":"py","source":"# Issuer sends IOU tokens to creator ----------------------\nprint(\"\\n=== Issuer Sending IOU Tokens to Escrow Creator ===\\n\")\niou_payment_tx = Payment(\n    account=issuer.address,\n    destination=creator.address,\n    amount=IssuedCurrencyAmount(\n        currency=currency_code,\n        value=\"5000\",\n        issuer=issuer.address,\n    ),\n)\n\nprint(json.dumps(iou_payment_tx.to_xrpl(), indent=2))\n\nprint(\"\\nSubmitting Trust Line Token payment transaction...\")\niou_pay_response = submit_and_wait(iou_payment_tx, client, issuer)\n\nif iou_pay_response.result[\"meta\"][\"TransactionResult\"] != \"tesSUCCESS\":\n    print(f\"Trust Line Token payment failed: {iou_pay_response.result['meta']['TransactionResult']}\")\n    exit(1)\nprint(f\"Successfully sent 5000 {currency_code} tokens.\")"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Go","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/go/send-fungible-token-escrow/main.go","language":"go","header":{"controls":{"copy":{}}},"lang":"go","source":"\t// Issuer sends IOU tokens to creator ----------------------\n\tfmt.Printf(\"\\n=== Issuer Sending IOU Tokens to Escrow Creator ===\\n\\n\")\n\tiouPaymentTx := transaction.Payment{\n\t\tBaseTx: transaction.BaseTx{\n\t\t\tAccount: issuer.ClassicAddress,\n\t\t},\n\t\tDestination: creator.ClassicAddress,\n\t\tAmount: types.IssuedCurrencyAmount{\n\t\t\tCurrency: currencyCode,\n\t\t\tValue:    \"5000\",\n\t\t\tIssuer:   issuer.ClassicAddress,\n\t\t},\n\t}\n\n\tflatIouPaymentTx := iouPaymentTx.Flatten()\n\tiouPaymentTxJSON, _ := json.MarshalIndent(flatIouPaymentTx, \"\", \"  \")\n\tfmt.Printf(\"%s\\n\", string(iouPaymentTxJSON))\n\n\tfmt.Printf(\"\\nSubmitting Trust Line Token payment transaction...\\n\")\n\tiouPayResponse, err := client.SubmitTxAndWait(flatIouPaymentTx, &wstypes.SubmitOptions{\n\t\tAutofill: true,\n\t\tWallet:   &issuer,\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tif iouPayResponse.Meta.TransactionResult != \"tesSUCCESS\" {\n\t\tfmt.Printf(\"Trust Line Token payment failed: %s\\n\", iouPayResponse.Meta.TransactionResult)\n\t\tos.Exit(1)\n\t}\n\tfmt.Printf(\"Successfully sent 5000 %s tokens.\\n\", currencyCode)\n\n\t"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"12-create-a-timed-trust-line-token-escrow","__idx":16},"children":["12. Create a timed trust line token escrow"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To make a timed escrow, set the maturity time of the escrow, which is a timestamp formatted as ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/data-types/basic-data-types#specifying-time"},"children":["seconds since the Ripple Epoch"]},". This example sets a maturity time of ten seconds from the time the code executes. Since it is a fungible token escrow, it also sets an expiration time of five minutes. After submitting the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/escrowcreate"},"children":["EscrowCreate transaction"]},", save the sequence number from the transaction result."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/js/sendFungibleTokenEscrow.js","language":"js","header":{"controls":{"copy":{}}},"lang":"js","source":"// Escrow Creator creates a timed trust line token escrow ----------------------\nconsole.log('\\n=== Creating Timed Trust Line Token Escrow ===\\n')\nconst delay = 10 // seconds\nconst now = new Date()\nconst finishAfter = new Date(now.getTime() + delay * 1000)\nconst finishAfterRippleTime = xrpl.isoTimeToRippleTime(finishAfter.toISOString())\nconsole.log(`Escrow will mature after: ${finishAfter.toLocaleString()}\\n`)\n\nconst iouCancelAfter = new Date(now.getTime() + 300 * 1000)\nconst iouCancelAfterRippleTime = xrpl.isoTimeToRippleTime(iouCancelAfter.toISOString())\n\nconst iouEscrowCreateTx = {\n  TransactionType: 'EscrowCreate',\n  Account: creator.address,\n  Destination: issuer.address,\n  Amount: {\n    currency: currencyCode,\n    value: '1000',\n    issuer: issuer.address\n  },\n  FinishAfter: finishAfterRippleTime,\n  CancelAfter: iouCancelAfterRippleTime\n}\n\nxrpl.validate(iouEscrowCreateTx)\nconsole.log(JSON.stringify(iouEscrowCreateTx, null, 2))\n\nconsole.log(`\\nSubmitting Trust Line Token EscrowCreate transaction...`)\nconst iouEscrowResponse = await client.submitAndWait(iouEscrowCreateTx, {\n  wallet: creator,\n  autofill: true\n})\nif (iouEscrowResponse.result.meta.TransactionResult !== 'tesSUCCESS') {\n  console.error(`Trust Line Token EscrowCreate failed: ${iouEscrowResponse.result.meta.TransactionResult}`)\n  await client.disconnect()\n  process.exit(1)\n}\n\n// Save the sequence number to identify the escrow later\nconst iouEscrowSeq = iouEscrowResponse.result.tx_json.Sequence\nconsole.log(`Trust Line Token escrow created. Sequence: ${iouEscrowSeq}`)"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/py/send_fungible_token_escrow.py","language":"py","header":{"controls":{"copy":{}}},"lang":"py","source":"# Escrow Creator creates a timed trust line token escrow ----------------------\nprint(\"\\n=== Creating Timed Trust Line Token Escrow ===\\n\")\ndelay = 10  # seconds\nnow = datetime.now(tz=UTC)\nfinish_after = now + timedelta(seconds=delay)\nfinish_after_ripple_time = datetime_to_ripple_time(finish_after)\nmature_time = finish_after.astimezone().strftime(\"%m/%d/%Y, %I:%M:%S %p\")\nprint(f\"Escrow will mature after: {mature_time}\\n\")\n\niou_cancel_after = now + timedelta(seconds=300)\niou_cancel_after_ripple_time = datetime_to_ripple_time(iou_cancel_after)\n\niou_escrow_create_tx = EscrowCreate(\n    account=creator.address,\n    destination=issuer.address,\n    amount=IssuedCurrencyAmount(\n        currency=currency_code,\n        value=\"1000\",\n        issuer=issuer.address,\n    ),\n    finish_after=finish_after_ripple_time,\n    cancel_after=iou_cancel_after_ripple_time,\n)\n\nprint(json.dumps(iou_escrow_create_tx.to_xrpl(), indent=2))\n\nprint(\"\\nSubmitting Trust Line Token EscrowCreate transaction...\")\niou_escrow_response = submit_and_wait(iou_escrow_create_tx, client, creator)\n\nif iou_escrow_response.result[\"meta\"][\"TransactionResult\"] != \"tesSUCCESS\":\n    print(f\"Trust Line Token EscrowCreate failed: {iou_escrow_response.result['meta']['TransactionResult']}\")\n    exit(1)\n\n# Save the sequence number to identify the escrow later\niou_escrow_seq = iou_escrow_response.result[\"tx_json\"][\"Sequence\"]\nprint(f\"Trust Line Token escrow created. Sequence: {iou_escrow_seq}\")"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Go","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/go/send-fungible-token-escrow/main.go","language":"go","header":{"controls":{"copy":{}}},"lang":"go","source":"\t// Escrow Creator creates a timed trust line token escrow ----------------------\n\tfmt.Printf(\"\\n=== Creating Timed Trust Line Token Escrow ===\\n\\n\")\n\tdelay := 10 // seconds\n\tnow := time.Now()\n\tfinishAfterRippleTime := xrpltime.UnixTimeToRippleTime(now.Unix()) + int64(delay)\n\tmatureTime := now.Add(time.Duration(delay) * time.Second).Format(\"01/02/2006, 03:04:05 PM\")\n\tfmt.Printf(\"Escrow will mature after: %s\\n\\n\", matureTime)\n\n\tiouCancelAfterRippleTime := xrpltime.UnixTimeToRippleTime(now.Unix()) + 300\n\n\tiouEscrowCreateTx := transaction.EscrowCreate{\n\t\tBaseTx: transaction.BaseTx{\n\t\t\tAccount: creator.ClassicAddress,\n\t\t},\n\t\tDestination: issuer.ClassicAddress,\n\t\tAmount: types.IssuedCurrencyAmount{\n\t\t\tCurrency: currencyCode,\n\t\t\tValue:    \"1000\",\n\t\t\tIssuer:   issuer.ClassicAddress,\n\t\t},\n\t\tFinishAfter: uint32(finishAfterRippleTime),\n\t\tCancelAfter: uint32(iouCancelAfterRippleTime),\n\t}\n\n\tflatIouEscrowCreateTx := iouEscrowCreateTx.Flatten()\n\tiouEscrowCreateTxJSON, _ := json.MarshalIndent(flatIouEscrowCreateTx, \"\", \"  \")\n\tfmt.Printf(\"%s\\n\", string(iouEscrowCreateTxJSON))\n\n\tfmt.Printf(\"\\nSubmitting Trust Line Token EscrowCreate transaction...\\n\")\n\tiouEscrowResponse, err := client.SubmitTxAndWait(flatIouEscrowCreateTx, &wstypes.SubmitOptions{\n\t\tAutofill: true,\n\t\tWallet:   &creator,\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tif iouEscrowResponse.Meta.TransactionResult != \"tesSUCCESS\" {\n\t\tfmt.Printf(\"Trust Line Token EscrowCreate failed: %s\\n\", iouEscrowResponse.Meta.TransactionResult)\n\t\tos.Exit(1)\n\t}\n\n\t// Save the sequence number to identify the escrow later\n\tiouEscrowSeq := iouEscrowResponse.TxJSON.Sequence()\n\tfmt.Printf(\"Trust Line Token escrow created. Sequence: %d\\n\", iouEscrowSeq)\n\n\t"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"13-wait-for-escrow-to-mature-and-finish","__idx":17},"children":["13. Wait for escrow to mature and finish"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Wait for the escrow to mature. Before submitting the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/escrowfinish"},"children":["EscrowFinish"]}," transaction, the code checks the current validated ledger to confirm the close time is after the escrow maturation time. This check ensures the escrow is matured on a validated ledger before trying to finish it."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/js/sendFungibleTokenEscrow.js","language":"js","header":{"controls":{"copy":{}}},"lang":"js","source":"// Wait for the escrow to mature, then finish it --------------------\nconsole.log(`\\n=== Waiting For Timed Trust Line Token Escrow to Mature ===\\n`)\n\n// Sleep function to countdown delay until escrow matures\nfunction sleep (delayInSeconds) {\n  return new Promise((resolve) => setTimeout(resolve, delayInSeconds * 1000))\n}\nfor (let i = delay; i >= 0; i--) {\n  process.stdout.write(`\\rWaiting for escrow to mature... ${i}s remaining...`)\n  await sleep(1)\n}\nconsole.log('\\rWaiting for escrow to mature... done.           ')\n\n// Confirm latest validated ledger close time is after the FinishAfter time\nlet escrowReady = false\nwhile (!escrowReady) {\n  const validatedLedger = await client.request({\n    command: 'ledger',\n    ledger_index: 'validated'\n  })\n  const ledgerCloseTime = validatedLedger.result.ledger.close_time\n  console.log(`Latest validated ledger closed at: ${new Date(xrpl.rippleTimeToISOTime(ledgerCloseTime)).toLocaleString()}`)\n  if (ledgerCloseTime > finishAfterRippleTime) {\n    escrowReady = true\n    console.log('Escrow confirmed ready to finish.')\n  } else {\n    let timeDifference = finishAfterRippleTime - ledgerCloseTime\n    if (timeDifference === 0) { timeDifference = 1 }\n    console.log(`Escrow needs to wait another ${timeDifference}s.`)\n    await sleep(timeDifference)\n  }\n}\n\n// Finish the timed trust line token escrow --------------------\nconsole.log('\\n=== Finishing Timed Trust Line Token Escrow ===\\n')\nconst iouEscrowFinishTx = {\n  TransactionType: 'EscrowFinish',\n  Account: creator.address,\n  Owner: creator.address,\n  OfferSequence: iouEscrowSeq\n}\n\nxrpl.validate(iouEscrowFinishTx)\nconsole.log(JSON.stringify(iouEscrowFinishTx, null, 2))\n\nconsole.log(`\\nSubmitting EscrowFinish transaction...`)\nconst iouFinishResponse = await client.submitAndWait(iouEscrowFinishTx, {\n  wallet: creator,\n  autofill: true\n})\nif (iouFinishResponse.result.meta.TransactionResult !== 'tesSUCCESS') {\n  console.error(`Trust Line Token EscrowFinish failed: ${iouFinishResponse.result.meta.TransactionResult}`)\n  await client.disconnect()\n  process.exit(1)\n}\nconsole.log(`Timed Trust Line Token escrow finished successfully: https://testnet.xrpl.org/transactions/${iouFinishResponse.result.hash}`)\n\nawait client.disconnect()\n"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/py/send_fungible_token_escrow.py","language":"py","header":{"controls":{"copy":{}}},"lang":"py","source":"# Wait for the escrow to mature, then finish it --------------------\nprint(\"\\n=== Waiting For Timed Trust Line Token Escrow to Mature ===\\n\")\n\n# Countdown delay until escrow matures\nfor i in range(delay, -1, -1):\n    print(f\"Waiting for escrow to mature... {i}s remaining...\", end=\"\\r\", flush=True)\n    sleep(1)\nprint(\"Waiting for escrow to mature... done.           \")\n\n# Confirm latest validated ledger close time is after the finish_after time\nescrow_ready = False\nwhile not escrow_ready:\n    validated_ledger = client.request(Ledger(ledger_index=\"validated\"))\n    ledger_close_time = validated_ledger.result[\"ledger\"][\"close_time\"]\n    ledger_close_local = ripple_time_to_datetime(ledger_close_time).astimezone().strftime(\"%m/%d/%Y, %I:%M:%S %p\")\n    print(f\"Latest validated ledger closed at: {ledger_close_local}\")\n    if ledger_close_time > finish_after_ripple_time:\n        escrow_ready = True\n        print(\"Escrow confirmed ready to finish.\")\n    else:\n        time_difference = finish_after_ripple_time - ledger_close_time\n        if time_difference == 0:\n            time_difference = 1\n        print(f\"Escrow needs to wait another {time_difference}s.\")\n        sleep(time_difference)\n\n# Finish the timed trust line token escrow --------------------\nprint(\"\\n=== Finishing Timed Trust Line Token Escrow ===\\n\")\niou_escrow_finish_tx = EscrowFinish(\n    account=creator.address,\n    owner=creator.address,\n    offer_sequence=iou_escrow_seq,\n)\n\nprint(json.dumps(iou_escrow_finish_tx.to_xrpl(), indent=2))\n\nprint(\"\\nSubmitting EscrowFinish transaction...\")\niou_finish_response = submit_and_wait(iou_escrow_finish_tx, client, creator)\n\nif iou_finish_response.result[\"meta\"][\"TransactionResult\"] != \"tesSUCCESS\":\n    print(f\"Trust Line Token EscrowFinish failed: {iou_finish_response.result['meta']['TransactionResult']}\")\n    exit(1)\nprint(f\"Timed Trust Line Token escrow finished successfully: https://testnet.xrpl.org/transactions/{iou_finish_response.result['hash']}\")\n"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Go","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/escrow/go/send-fungible-token-escrow/main.go","language":"go","header":{"controls":{"copy":{}}},"lang":"go","source":"\t// Wait for the escrow to mature, then finish it --------------------\n\tfmt.Printf(\"\\n=== Waiting For Timed Trust Line Token Escrow to Mature ===\\n\\n\")\n\n\t// Countdown delay until escrow matures\n\tfor i := delay; i >= 0; i-- {\n\t\tfmt.Printf(\"Waiting for escrow to mature... %ds remaining...\\r\", i)\n\t\ttime.Sleep(time.Second)\n\t}\n\tfmt.Printf(\"Waiting for escrow to mature... done.           \\n\")\n\n\t// Confirm latest validated ledger close time is after the FinishAfter time\n\tescrowReady := false\n\tfor !escrowReady {\n\t\tledgerResp, err := client.GetLedger(&ledgerreq.Request{\n\t\t\tLedgerIndex: common.Validated,\n\t\t})\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tledgerCloseTime := int64(ledgerResp.Ledger.CloseTime)\n\t\tledgerCloseLocal := time.Unix(xrpltime.RippleTimeToUnixTime(ledgerCloseTime)/1000, 0).Format(\"01/02/2006, 03:04:05 PM\")\n\t\tfmt.Printf(\"Latest validated ledger closed at: %s\\n\", ledgerCloseLocal)\n\t\tif ledgerCloseTime > finishAfterRippleTime {\n\t\t\tescrowReady = true\n\t\t\tfmt.Printf(\"Escrow confirmed ready to finish.\\n\")\n\t\t} else {\n\t\t\ttimeDifference := finishAfterRippleTime - ledgerCloseTime\n\t\t\tif timeDifference == 0 {\n\t\t\t\ttimeDifference = 1\n\t\t\t}\n\t\t\tfmt.Printf(\"Escrow needs to wait another %ds.\\n\", timeDifference)\n\t\t\ttime.Sleep(time.Duration(timeDifference) * time.Second)\n\t\t}\n\t}\n\n\t// Finish the timed trust line token escrow --------------------\n\tfmt.Printf(\"\\n=== Finishing Timed Trust Line Token Escrow ===\\n\\n\")\n\tiouEscrowFinishTx := transaction.EscrowFinish{\n\t\tBaseTx: transaction.BaseTx{\n\t\t\tAccount: creator.ClassicAddress,\n\t\t},\n\t\tOwner:         creator.ClassicAddress,\n\t\tOfferSequence: iouEscrowSeq,\n\t}\n\n\tflatIouEscrowFinishTx := iouEscrowFinishTx.Flatten()\n\tiouEscrowFinishTxJSON, _ := json.MarshalIndent(flatIouEscrowFinishTx, \"\", \"  \")\n\tfmt.Printf(\"%s\\n\", string(iouEscrowFinishTxJSON))\n\n\tfmt.Printf(\"\\nSubmitting EscrowFinish transaction...\\n\")\n\tiouFinishResponse, err := client.SubmitTxAndWait(flatIouEscrowFinishTx, &wstypes.SubmitOptions{\n\t\tAutofill: true,\n\t\tWallet:   &creator,\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tif iouFinishResponse.Meta.TransactionResult != \"tesSUCCESS\" {\n\t\tfmt.Printf(\"Trust Line Token EscrowFinish failed: %s\\n\", iouFinishResponse.Meta.TransactionResult)\n\t\tos.Exit(1)\n\t}\n\tfmt.Printf(\"Timed Trust Line Token escrow finished successfully: https://testnet.xrpl.org/transactions/%s\\n\", iouFinishResponse.Hash)\n}\n"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"see-also","__idx":18},"children":["See Also"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Concepts"]},":"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/payment-types/escrow"},"children":["Escrow"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/fungible-tokens/multi-purpose-tokens"},"children":["Multi-Purpose Tokens"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/fungible-tokens/trust-line-tokens"},"children":["Trust Line Tokens"]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Tutorials"]},":"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/tutorials/payments/look-up-escrows"},"children":["Look up Escrows"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/tutorials/payments/cancel-an-expired-escrow"},"children":["Cancel an Expired Escrow"]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["References"]},":"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/escrowcreate"},"children":["EscrowCreate transaction"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/escrowfinish"},"children":["EscrowFinish transaction"]}]}]}]},"headings":[{"value":"Send Fungible Token Escrows","id":"send-fungible-token-escrows","depth":1},{"value":"Goals","id":"goals","depth":2},{"value":"Prerequisites","id":"prerequisites","depth":2},{"value":"Source Code","id":"source-code","depth":2},{"value":"Steps","id":"steps","depth":2},{"value":"1. Install dependencies","id":"1-install-dependencies","depth":3},{"value":"2. Set up client and fund accounts","id":"2-set-up-client-and-fund-accounts","depth":3},{"value":"3. Issue an MPT with escrow support","id":"3-issue-an-mpt-with-escrow-support","depth":3},{"value":"4. Authorize the MPT","id":"4-authorize-the-mpt","depth":3},{"value":"5. Send MPTs to the escrow creator","id":"5-send-mpts-to-the-escrow-creator","depth":3},{"value":"6. Create a condition and fulfillment","id":"6-create-a-condition-and-fulfillment","depth":3},{"value":"7. Create the conditional MPT escrow","id":"7-create-the-conditional-mpt-escrow","depth":3},{"value":"8. Finish the conditional MPT escrow","id":"8-finish-the-conditional-mpt-escrow","depth":3},{"value":"9. Enable trust line token escrows","id":"9-enable-trust-line-token-escrows","depth":3},{"value":"10. Set up a trust line","id":"10-set-up-a-trust-line","depth":3},{"value":"11. Send IOU tokens to the escrow creator","id":"11-send-iou-tokens-to-the-escrow-creator","depth":3},{"value":"12. Create a timed trust line token escrow","id":"12-create-a-timed-trust-line-token-escrow","depth":3},{"value":"13. Wait for escrow to mature and finish","id":"13-wait-for-escrow-to-mature-and-finish","depth":3},{"value":"See Also","id":"see-also","depth":2}],"frontmatter":{"seo":{"description":"Create and finish escrows that hold fungible tokens (MPTs and trust line tokens) on the XRP Ledger.","title":"Send Fungible Token Escrows"},"metadata":{"indexPage":true},"labels":["Escrow"]},"editPage":{"to":"https://github.com/XRPLF/xrpl-dev-portal/tree/master/docs/tutorials/payments/send-fungible-token-escrows.md"},"lastModified":"2026-04-03T23:51:50.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/docs/tutorials/payments/send-fungible-token-escrows","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}