{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-@l10n/ja/sidebars.yaml","index-page-items":"/ja/docs/tutorials/tokens/mpts/claw-back-confidential-balances_index-page-items"},"props":{"metadata":{"markdoc":{"tagList":["amendment-disclaimer","repo-link","tabs","tab","code-snippet","admonition"]},"type":"markdown","indexPage":true},"seo":{"title":"Claw Back Confidential Balances","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":"Agentic Transactions","description":"XRPL AI Starter Kit to help autonomous agents discover, set up, and execute agentic transactions on the XRP Ledger.","includeFiles":["docs/agents/**/*.*"],"excludeFiles":[]},{"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 xrpld and Clio servers.","includeFiles":["docs/infrastructure/**/*.*"],"excludeFiles":["docs/infrastructure/index.md","docs/infrastructure/*/index.md","docs/infrastructure/installation/build-run-xrpld-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":"Claw back a holder's entire confidential Multi-Purpose Token (MPT) balance as the issuer, then verify the result as the holder, the issuer, and the auditor."},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"claw-back-confidential-balances","__idx":0},"children":["Claw Back Confidential Balances"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This tutorial shows you how to claw back a holder's ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/ja/docs/concepts/tokens/fungible-tokens/confidential-transfers"},"children":["confidential Multi-Purpose Token (MPT)"]}," balance. A confidential clawback takes the holder's total confidential balance (spending + inbox balance), so there is no partial clawback. The clawback amount is publicly visible, so the holder's total confidential balance at that moment can be seen by everyone."]},{"$$mdtype":"Tag","name":"AmendmentDisclaimer","attributes":{"name":"ConfidentialTransfer","compact":false,"statusOnly":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":["Lock an MPT issuance for a holder so that a clawback proof stays valid."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Claw back the holder's entire confidential balance, and verify the result as the holder, the issuer, and the auditor."]}]},{"$$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 and the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/ja/docs/concepts/tokens/fungible-tokens/confidential-transfers"},"children":["Confidential Transfers"]}," concept, in particular ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/ja/docs/concepts/tokens/fungible-tokens/confidential-transfers#confidential-clawback"},"children":["Confidential Clawback"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Have an MPT issued with both the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Can Clawback"]}," and ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Can Lock"]}," flags, the issuer and auditor encryption keys registered on it, and a holder with a confidential balance. See ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/ja/docs/tutorials/tokens/mpts/issue-mpt-for-confidential-transfers"},"children":["Issue an MPT for Confidential Transfers"]},". The setup script for this tutorial creates them for you."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Have an XRP Ledger client library set up in your development environment. 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":"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/confidential-transfers/","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":"TabItemFragment","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["From the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["js/"]}," folder, use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["npm"]}," to install dependencies."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"sh","header":{"controls":{"copy":{}}},"source":"npm install\n","lang":"sh"},"children":[]}]},{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["From the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["py/"]}," 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":"sh","header":{"controls":{"copy":{}}},"source":"python3 -m venv .venv\nsource .venv/bin/activate\npip install -r requirements.txt\n","lang":"sh"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"2-set-up-the-client-and-accounts","__idx":6},"children":["2. Set up the client and accounts"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To get started, import the necessary libraries and instantiate a client to connect to the XRP Ledger. This example imports:"]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["fs"]},": Used to check for and load the tutorial setup data."]},{"$$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":["./confidentialTransfersSetup.js"]},": The tutorial setup script, imported and called directly."]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/confidential-transfers/js/clawbackConfidentialMPT.js","language":"js","header":{"controls":{"copy":{}}},"lang":"js","source":"import fs from 'fs'\nimport {\n  Client,\n  MPTokenIssuanceSetFlags,\n  Wallet,\n  deriveConfidentialKeypair,\n  fetchMPToken,\n  fetchMPTokenIssuance,\n  loadMptCrypto,\n  prepareConfidentialClawback\n} from 'xrpl'\n\nimport { setup } from './confidentialTransfersSetup.js'\n\n// Connect to the network ----------------------\nconst client = new Client('wss://s.devnet.rippletest.net:51233')\nawait client.connect()\n\nconst EXPLORER = 'https://devnet.xrpl.org'"},"children":[]}]},{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["asyncio"]},": Used to run the async tutorial setup function."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["json"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["os"]},": Used to check for and load the tutorial setup data."]},{"$$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":["xrpl.ext.confidential"]},": Used for the confidential clawback builder and decryption."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["confidential_transfers_setup"]},": The tutorial setup script, imported and called directly."]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/confidential-transfers/py/clawback_confidential_mpt.py","language":"py","header":{"controls":{"copy":{}}},"lang":"py","source":"import asyncio\nimport json\nimport os\n\nfrom xrpl.clients import JsonRpcClient\nfrom xrpl.ext.confidential import (\n    decrypt_confidential_balance,\n    prepare_confidential_clawback,\n)\nfrom xrpl.models import LedgerEntry, MPTokenIssuanceSet\nfrom xrpl.models.requests.ledger_entry import MPToken\nfrom xrpl.models.transactions import MPTokenIssuanceSetFlag\nfrom xrpl.transaction import submit_and_wait\nfrom xrpl.wallet import Wallet\n\nfrom confidential_transfers_setup import main as run_setup\n\n# Connect to the network ----------------------\nclient = JsonRpcClient(\"https://s.devnet.rippletest.net:51234\")\n\nEXPLORER = \"https://devnet.xrpl.org\""},"children":[]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Load the issuer, the holder, the auditor, and the issuance the clawback applies to. Only the issuer can claw back, and it needs its own encryption keys to read the holder's balance and build the proof."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/confidential-transfers/js/clawbackConfidentialMPT.js","language":"js","header":{"controls":{"copy":{}}},"lang":"js","source":"// Load setup data ----------------------\n// This step checks for the necessary setup data to run the tutorial.\n// If missing, confidentialTransfersSetup.js will generate it.\nif (!fs.existsSync('confidentialTransfersSetup.json')) {\n  console.log(`\\n=== Setup data doesn't exist. Running setup script... ===\\n`)\n  await setup()\n}\n\nconst setupData = JSON.parse(\n  fs.readFileSync('confidentialTransfersSetup.json', 'utf8')\n)\n\n// Set up accounts ----------------------\nconsole.log(`\\n=== Getting accounts... ===`)\nconst issuer = Wallet.fromSeed(setupData.issuer.seed)\nconst auditor = Wallet.fromSeed(setupData.auditor.seed)\nconst holder = Wallet.fromSeed(setupData.flaggedHolder.seed)\n\nconst issuerKeys = deriveConfidentialKeypair(issuer.seed)\nconst auditorKeys = deriveConfidentialKeypair(auditor.seed)\nconst holderKeys = deriveConfidentialKeypair(holder.seed)\n\nconst { ticker, mptIssuanceID } = setupData.stablecoin\n\nconsole.log(`Issuer address: ${issuer.address}`)\nconsole.log(`Holder address: ${holder.address}`)\nconsole.log(`Auditor address: ${auditor.address}`)"},"children":[]}]},{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/confidential-transfers/py/clawback_confidential_mpt.py","language":"py","header":{"controls":{"copy":{}}},"lang":"py","source":"# Load setup data ----------------------\n# This step checks for the necessary setup data to run the tutorial.\n# If missing, confidential_transfers_setup.py will generate it.\nif not os.path.exists(\"confidential_transfers_setup.json\"):\n    print(\"\\n=== Setup data doesn't exist. Running setup script... ===\\n\")\n    asyncio.run(run_setup())\n\nwith open(\"confidential_transfers_setup.json\") as setup_file:\n    setup_data = json.load(setup_file)\n\n# Set up accounts ----------------------\nprint(\"\\n=== Getting accounts... ===\")\nissuer = Wallet.from_seed(setup_data[\"issuer\"][\"seed\"])\nauditor = Wallet.from_seed(setup_data[\"auditor\"][\"seed\"])\nholder = Wallet.from_seed(setup_data[\"flaggedHolder\"][\"seed\"])\n\nissuer_privkey = setup_data[\"issuer\"][\"privateKey\"]\nissuer_pubkey = setup_data[\"issuer\"][\"publicKey\"]\nauditor_privkey = setup_data[\"auditor\"][\"privateKey\"]\nholder_privkey = setup_data[\"flaggedHolder\"][\"privateKey\"]\n\nticker = setup_data[\"stablecoin\"][\"ticker\"]\nmpt_issuance_id = setup_data[\"stablecoin\"][\"mptIssuanceID\"]\n\nprint(f\"Issuer address: {issuer.address}\")\nprint(f\"Holder address: {holder.address}\")\nprint(f\"Auditor address: {auditor.address}\")"},"children":[]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This example uses pre-configured data from a setup script, including public and private keys, but you can replace these with your own values."]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning","name":"Caution"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For testing purposes, the example's private keys are stored in a JSON file by the setup script. In production, private keys should be stored in a secure, encrypted key store."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"3-lock-the-issuance-for-the-holder","__idx":7},"children":["3. Lock the issuance for the holder"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A clawback proof is built against the balance the issuer reads. If the holder spends or receives anything before the clawback, the balance changes, the proof goes stale, and the clawback fails."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Submit an ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/mptokenissuanceset"},"children":["MPTokenIssuanceSet transaction"]}," with the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["tfMPTLock"]}," flag to ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/ja/docs/concepts/tokens/fungible-tokens/deep-freeze#how-does-mpt-freezelock-behavior-differ-from-iou"},"children":["lock"]}," the MPT issuance for the holder. This requires the issuance to have the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Can Lock"]}," flag enabled."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/confidential-transfers/js/clawbackConfidentialMPT.js","language":"js","header":{"controls":{"copy":{}}},"lang":"js","source":"// Lock the issuance for the holder ----------------------\nconsole.log(`\\n=== Locking ${ticker} for the holder... ===`)\nconst lockTx = {\n  TransactionType: 'MPTokenIssuanceSet',\n  Account: issuer.address,\n  MPTokenIssuanceID: mptIssuanceID,\n  Holder: holder.address,\n  Flags: MPTokenIssuanceSetFlags.tfMPTLock\n}\n\nconst lockResponse = await client.submitAndWait(lockTx, {\n  wallet: issuer,\n  autofill: true\n})\nif (lockResponse.result.meta.TransactionResult !== 'tesSUCCESS') {\n  const resultCode = lockResponse.result.meta.TransactionResult\n  console.error('Error: Unable to lock the issuance:', resultCode)\n  await client.disconnect()\n  process.exit(1)\n}\nconsole.log(`${ticker} is locked for ${holder.address}.`)\nconsole.log(`${EXPLORER}/transactions/${lockResponse.result.hash}`)"},"children":[]}]},{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/confidential-transfers/py/clawback_confidential_mpt.py","language":"py","header":{"controls":{"copy":{}}},"lang":"py","source":"# Lock the issuance for the holder ----------------------\nprint(f\"\\n=== Locking {ticker} for the holder... ===\")\nlock_tx = MPTokenIssuanceSet(\n    account=issuer.address,\n    mptoken_issuance_id=mpt_issuance_id,\n    holder=holder.address,\n    flags=MPTokenIssuanceSetFlag.TF_MPT_LOCK,\n)\n\nlock_response = submit_and_wait(lock_tx, client, issuer, autofill=True)\nif lock_response.result[\"meta\"][\"TransactionResult\"] != \"tesSUCCESS\":\n    result_code = lock_response.result[\"meta\"][\"TransactionResult\"]\n    print(f\"Error: Unable to lock the issuance: {result_code}\")\n    exit(1)\nprint(f\"{ticker} is locked for {holder.address}.\")\nprint(f\"{EXPLORER}/transactions/{lock_response.result['hash']}\")"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"4-read-the-confidential-supply","__idx":8},"children":["4. Read the confidential supply"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The issuance's ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ConfidentialOutstandingAmount"]}," is the total confidential supply and is public, so the issuer can watch the clawback take effect without decrypting anything."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/confidential-transfers/js/clawbackConfidentialMPT.js","language":"js","header":{"controls":{"copy":{}}},"lang":"js","source":"// Read the confidential supply before the clawback ----------------------\nconsole.log(`\\n=== Reading the confidential supply... ===`)\nconst mptIssuance = await fetchMPTokenIssuance(client, mptIssuanceID)\nconst confidentialSupply = BigInt(mptIssuance.ConfidentialOutstandingAmount)\nconsole.log(`Confidential supply before clawback: ${confidentialSupply}`)"},"children":[]}]},{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/confidential-transfers/py/clawback_confidential_mpt.py","language":"py","header":{"controls":{"copy":{}}},"lang":"py","source":"# Read the confidential supply before the clawback ----------------------\nprint(\"\\n=== Reading the confidential supply... ===\")\nmpt_issuance = client.request(\n    LedgerEntry(mpt_issuance=mpt_issuance_id),\n).result[\"node\"]\nconfidential_supply = int(mpt_issuance[\"ConfidentialOutstandingAmount\"])\nprint(f\"Confidential supply before clawback: {confidential_supply}\")"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"5-claw-back-the-confidential-balance","__idx":9},"children":["5. Claw back the confidential balance"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The holder's ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/ledger-data/ledger-entry-types/mptoken"},"children":["MPToken entry"]}," also carries an ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["IssuerEncryptedBalance"]},", which holds the holder's spending and inbox balances added together, encrypted with the issuer's public key. That single total is what makes an unassisted clawback possible, because the issuer can read the exact amount without any cooperation from the holder."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Submit a ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/confidentialmptclawback"},"children":["ConfidentialMPTClawback transaction"]}," to claw back the holder's total confidential balance. The transaction carries the amount in the clear, along with a Zero-Knowledge Proof (ZKP) that the amount matches the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["IssuerEncryptedBalance"]}," it was read from. The two libraries split that work differently."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["prepareConfidentialClawback"]}," needs only the issuer's keypair. It fetches the holder's ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MPToken"]}," entry, decrypts ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["IssuerEncryptedBalance"]},", and sets ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MPTAmount"]}," on the prepared transaction, which is where this example reads the amount from."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/confidential-transfers/js/clawbackConfidentialMPT.js","language":"js","header":{"controls":{"copy":{}}},"lang":"js","source":"// Claw back the confidential balance ----------------------\nconsole.log(`\\n=== Clawing back the holder's confidential balance... ===`)\n// prepareConfidentialClawback attaches the amount the issuer read and a\n// Zero-Knowledge Proof (ZKP) that the amount matches the encrypted balance.\nconst clawbackTx = await prepareConfidentialClawback(client, {\n  account: issuer.address,\n  holder: holder.address,\n  mptIssuanceID,\n  issuerKeypair: issuerKeys\n})\n\n// A clawback takes the whole balance, so there is nothing left to reclaim if\n// this sample has already run against this setup data. The protocol rejects a\n// clawback of zero, so stop before submitting.\nif (clawbackTx.MPTAmount === '0') {\n  console.error(\n    `Error: The confidential balance of ${holder.address} is already zero.`\n  )\n  console.error(\n    'Delete confidentialTransfersSetup.json and run the setup script again.'\n  )\n  await client.disconnect()\n  process.exit(1)\n}\nconsole.log(JSON.stringify(clawbackTx, null, 2))\n\nconst clawbackResponse = await client.submitAndWait(clawbackTx, {\n  wallet: issuer,\n  autofill: true\n})\nif (clawbackResponse.result.meta.TransactionResult !== 'tesSUCCESS') {\n  const resultCode = clawbackResponse.result.meta.TransactionResult\n  console.error('Error: Unable to claw back the balance:', resultCode)\n  await client.disconnect()\n  process.exit(1)\n}\nconsole.log(`Clawed back ${clawbackTx.MPTAmount} ${ticker} from ${holder.address}.`)\nconsole.log(`${EXPLORER}/transactions/${clawbackResponse.result.hash}`)"},"children":[]}]},{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["prepare_confidential_clawback"]}," needs the amount and the ciphertext it was read from, so this example fetches the holder's ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MPToken"]}," entry and decrypts ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["IssuerEncryptedBalance"]}," itself before calling it."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/confidential-transfers/py/clawback_confidential_mpt.py","language":"py","header":{"controls":{"copy":{}}},"lang":"py","source":"# Claw back the confidential balance ----------------------\nprint(\"\\n=== Clawing back the holder's confidential balance... ===\")\nholder_mptoken = client.request(\n    LedgerEntry(\n        mptoken=MPToken(mpt_issuance_id=mpt_issuance_id, account=holder.address),\n    ),\n).result[\"node\"]\n\nissuer_encrypted_balance = holder_mptoken[\"IssuerEncryptedBalance\"]\nclawback_amount = decrypt_confidential_balance(\n    issuer_encrypted_balance,\n    issuer_privkey,\n    range_high=confidential_supply,\n)\n\n# A clawback takes the whole balance, so there is nothing left to reclaim if\n# this sample has already run against this setup data. The protocol rejects a\n# clawback of zero, so stop before submitting.\nif clawback_amount == 0:\n    print(f\"Error: The confidential balance of {holder.address} is already zero.\")\n    print(\"Delete confidential_transfers_setup.json and run the setup script again.\")\n    exit(1)\n\n# prepare_confidential_clawback attaches the amount the issuer read and a\n# Zero-Knowledge Proof (ZKP) that the amount matches the encrypted balance.\nclawback_tx = prepare_confidential_clawback(\n    client,\n    issuer,\n    holder.address,\n    mpt_issuance_id,\n    clawback_amount,\n    issuer_privkey,\n    issuer_pubkey,\n    issuer_encrypted_balance,\n)\nprint(json.dumps(clawback_tx.to_dict(), indent=2))\n\nclawback_response = submit_and_wait(clawback_tx, client, issuer, autofill=True)\nif clawback_response.result[\"meta\"][\"TransactionResult\"] != \"tesSUCCESS\":\n    result_code = clawback_response.result[\"meta\"][\"TransactionResult\"]\n    print(f\"Error: Unable to claw back the balance: {result_code}\")\n    exit(1)\nprint(f\"Clawed back {clawback_amount} {ticker} from {holder.address}.\")\nprint(f\"{EXPLORER}/transactions/{clawback_response.result['hash']}\")"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"6-verify-the-clawback","__idx":10},"children":["6. Verify the clawback"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The clawback sets both the spending balance and the inbox to encrypted zero, so every key that could read the holder's balance now reads zero. Decrypt all four copies to confirm this, one per key that has access."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/confidential-transfers/js/clawbackConfidentialMPT.js","language":"js","header":{"controls":{"copy":{}}},"lang":"js","source":"// Verify the clawback ----------------------\nconsole.log(`\\n=== Verifying the clawback... ===`)\nconst mptoken = await fetchMPToken(client, holder.address, mptIssuanceID)\nconsole.log(`MPToken entry:`)\nconsole.log(JSON.stringify(mptoken, null, 2))\n\nconst crypto = await loadMptCrypto()\nconst [spendingBalance, inboxBalance, issuerView, auditorView] =\n  await Promise.all([\n    crypto.decryptAmount(\n      mptoken.ConfidentialBalanceSpending,\n      holderKeys.privateKey,\n      confidentialSupply\n    ),\n    crypto.decryptAmount(\n      mptoken.ConfidentialBalanceInbox,\n      holderKeys.privateKey,\n      confidentialSupply\n    ),\n    crypto.decryptAmount(\n      mptoken.IssuerEncryptedBalance,\n      issuerKeys.privateKey,\n      confidentialSupply\n    ),\n    crypto.decryptAmount(\n      mptoken.AuditorEncryptedBalance,\n      auditorKeys.privateKey,\n      confidentialSupply\n    )\n  ])\nconsole.log(`\\nHolder reads its spending balance as ${spendingBalance} ${ticker}.`)\nconsole.log(`Holder reads its inbox balance as ${inboxBalance} ${ticker}.\\n`)\nconsole.log(`Issuer reads the holder's balance as ${issuerView} ${ticker}.`)\nconsole.log(`Auditor reads the holder's balance as ${auditorView} ${ticker}.\\n`)\n\nconst issuanceAfter = await fetchMPTokenIssuance(client, mptIssuanceID)\nconst supplyAfter = issuanceAfter.ConfidentialOutstandingAmount\nconsole.log(`Confidential supply after the clawback: ${supplyAfter}`)\nconsole.log(`Total supply in circulation (public + confidential): ${issuanceAfter.OutstandingAmount}`)\n\nawait client.disconnect()\n"},"children":[]}]},{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"/_code-samples/confidential-transfers/py/clawback_confidential_mpt.py","language":"py","header":{"controls":{"copy":{}}},"lang":"py","source":"# Verify the clawback ----------------------\nprint(\"\\n=== Verifying the clawback... ===\")\nholder_mptoken_after = client.request(\n    LedgerEntry(\n        mptoken=MPToken(mpt_issuance_id=mpt_issuance_id, account=holder.address),\n    ),\n).result[\"node\"]\nprint(\"MPToken entry:\")\nprint(json.dumps(holder_mptoken_after, indent=2))\n\nspending = holder_mptoken_after[\"ConfidentialBalanceSpending\"]\ninbox = holder_mptoken_after[\"ConfidentialBalanceInbox\"]\nissuer_balance = holder_mptoken_after[\"IssuerEncryptedBalance\"]\nauditor_balance = holder_mptoken_after[\"AuditorEncryptedBalance\"]\n\nspending_balance = decrypt_confidential_balance(\n    spending, holder_privkey, range_high=confidential_supply\n)\ninbox_balance = decrypt_confidential_balance(\n    inbox, holder_privkey, range_high=confidential_supply\n)\nissuer_view = decrypt_confidential_balance(\n    issuer_balance, issuer_privkey, range_high=confidential_supply\n)\nauditor_view = decrypt_confidential_balance(\n    auditor_balance, auditor_privkey, range_high=confidential_supply\n)\nprint(f\"\\nHolder reads its spending balance as {spending_balance} {ticker}.\")\nprint(f\"Holder reads its inbox balance as {inbox_balance} {ticker}.\\n\")\nprint(f\"Issuer reads the holder's balance as {issuer_view} {ticker}.\")\nprint(f\"Auditor reads the holder's balance as {auditor_view} {ticker}.\\n\")\n\nissuance_after = client.request(\n    LedgerEntry(mpt_issuance=mpt_issuance_id),\n).result[\"node\"]\nsupply_after = issuance_after[\"ConfidentialOutstandingAmount\"]\nprint(f\"Confidential supply after the clawback: {supply_after}\")\nprint(\n    f\"Total supply in circulation (public + confidential): {issuance_after['OutstandingAmount']}\"\n)\n"},"children":[]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The clawed back tokens leave circulation entirely, which the issuance shows in public. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ConfidentialOutstandingAmount"]}," drops by the amount clawed back, and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["OutstandingAmount"]}," drops with it."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"see-also","__idx":11},"children":["See Also"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","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":"/ja/docs/concepts/tokens/fungible-tokens/confidential-transfers"},"children":["Confidential Transfers"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/ja/docs/concepts/tokens/fungible-tokens/multi-purpose-tokens"},"children":["Multi-Purpose Tokens (MPT)"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/ja/docs/concepts/tokens/fungible-tokens/clawing-back-tokens"},"children":["Clawing Back Tokens"]}]}]}]},{"$$mdtype":"Tag","name":"li","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":"/ja/docs/tutorials/tokens/mpts/issue-mpt-for-confidential-transfers"},"children":["Issue an MPT for Confidential Transfers"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/ja/docs/tutorials/payments/send-confidential-payments"},"children":["Send Confidential MPT Payments"]}]}]}]},{"$$mdtype":"Tag","name":"li","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/confidentialmptclawback"},"children":["ConfidentialMPTClawback transaction"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/mptokenissuanceset"},"children":["MPTokenIssuanceSet transaction"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/ledger-data/ledger-entry-types/mptoken"},"children":["MPToken entry"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/ledger-data/ledger-entry-types/mptokenissuance"},"children":["MPTokenIssuance entry"]}]}]}]}]}]},"headings":[{"value":"Claw Back Confidential Balances","id":"claw-back-confidential-balances","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 the client and accounts","id":"2-set-up-the-client-and-accounts","depth":3},{"value":"3. Lock the issuance for the holder","id":"3-lock-the-issuance-for-the-holder","depth":3},{"value":"4. Read the confidential supply","id":"4-read-the-confidential-supply","depth":3},{"value":"5. Claw back the confidential balance","id":"5-claw-back-the-confidential-balance","depth":3},{"value":"6. Verify the clawback","id":"6-verify-the-clawback","depth":3},{"value":"See Also","id":"see-also","depth":2}],"frontmatter":{"seo":{"description":"Claw back a holder's entire confidential Multi-Purpose Token (MPT) balance as the issuer, then verify the result as the holder, the issuer, and the auditor.","title":"Claw Back Confidential Balances"},"metadata":{"indexPage":true},"labels":["Multi-Purpose Token","MPT","Confidential Transfers"],"status":"not_enabled"},"editPage":{"to":"https://github.com/XRPLF/xrpl-dev-portal/tree/master/docs/tutorials/tokens/mpts/claw-back-confidential-balances.md"},"lastModified":"2026-08-26T10:26:57.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/ja/docs/tutorials/tokens/mpts/claw-back-confidential-balances","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}