Decommit from Hydra
Decommit is the process of withdrawing UTxOs from an active Hydra Head back to Cardano Layer 1. This lets you exit the Layer 2 environment and make your assets available on the main chain.
Understanding decommit
What is decommit?
Decommit removes UTxOs from the Hydra Head and returns them to Layer 1 while the head remains open. Think of it as moving funds from the express lane back to the main road.
text
┌─────────────────────────────────────────┐
│ Hydra Head (Layer 2) │
│ │
│ Your UTxOs: [UTxO1, UTxO2, UTxO3] │
│ │
└──────────────┬──────────────────────────┘
│
│ DECOMMIT
│ (Remove from Head, return to L1)
│
┌──────────────▼──────────────────────────┐
│ Cardano Layer 1 │
│ │
│ Available: [UTxO1, UTxO2, UTxO3] │
│ Back on main chain │
│ │
└─────────────────────────────────────────┘
Decommit process
When should you decommit?
You should decommit when you want to withdraw assets from a Hydra Head without closing the Head. For example: moving assets back to your Layer 1 wallet or withdrawing a portion to use on Cardano mainnet.
Steps to decommit
- Connect to the Hydra node via Hydra Bridge.
- Query current UTxOs in the Hydra Head.
- Build a decommit transaction with the UTxOs you want to withdraw.
- Sign the transaction with your wallet.
- Submit the decommit transaction to the Hydra node.
- Monitor the snapshot status and confirm the UTxOs have returned to Layer 1.
ts
// nodejs-playground/src/hydra/decommit.ts
import { TxBuilder } from '@hydra-sdk/transaction'
import { HydraBridge } from '@hydra-sdk/bridge'
import { wallet, walletAddress } from './common'
import { Resolver } from '@hydra-sdk/core'
async function main() {
const bridge = new HydraBridge({
url: 'ws://localhost:4001'
})
const connected = await bridge.connect()
if (!connected) {
throw new Error('Failed to connect to Hydra node')
}
console.log('>>> Connected to Hydra node')
const utxoObj = await bridge.querySnapshotUtxo()
const addrUtxos = await bridge.queryAddressUTxO(walletAddress)
const txBuilder = new TxBuilder({
isHydra: true,
params: {
minFeeA: 0,
minFeeB: 0
}
})
const tx = await txBuilder
.setInputs([
addrUtxos[0] // utxo to decommit
])
.addOutput({
address: walletAddress,
amount: [{ unit: 'lovelace', quantity: String(2_000_000) }]
})
.changeAddress(walletAddress)
.complete()
const signedCbor = await wallet.signTx(tx.to_hex())
const txId = Resolver.resolveTxHash(signedCbor)
const rs = await bridge.decommit({
cborHex: signedCbor,
txId,
timeout: 30000
})
console.log('>>> Submit tx result:', rs)
}
main()
Run
bash
npx tsx src/hydra/decommit.ts
plaintext
>>> Connected to Hydra node
>>> Snapshot UTxO: {
'dee1097738688441b2bcf90d9a20ad8eca859375ffdb8f1fde0f78f461345435#0': {
address: 'addr_test1qpxsf0x8xypuhq5k408f9kh0meyy6jv2lxgqw2fefvjlte0u06dugtmxuhhw8hschdn4q59g64q5s9z42ax6qyg7ewsqt6e548',
datum: null,
datumhash: null,
inlineDatum: null,
inlineDatumRaw: null,
referenceScript: null,
value: { lovelace: 2000000 }
},
'dee1097738688441b2bcf90d9a20ad8eca859375ffdb8f1fde0f78f461345435#1': {
address: 'addr_test1qpxsf0x8xypuhq5k408f9kh0meyy6jv2lxgqw2fefvjlte0u06dugtmxuhhw8hschdn4q59g64q5s9z42ax6qyg7ewsqt6e548',
datum: null,
datumhash: null,
inlineDatum: null,
inlineDatumRaw: null,
referenceScript: null,
value: { lovelace: 16000000 }
}
}
>>> Submit tx result: {
decommitTxId: '7318b97f468ad3dcc91b2fab180995f1bd62b4c49f68d83b3f30b5d8bffc49e4',
headId: '7489fdc412ff71a7831ed508e73b2872482099fd4d97ed73663c70f8',
seq: 227169,
tag: 'DecommitApproved',
timestamp: '2025-11-26T08:22:34.822012138Z',
utxoToDecommit: {
'7318b97f468ad3dcc91b2fab180995f1bd62b4c49f68d83b3f30b5d8bffc49e4#0': {
address: 'addr_test1qpxsf0x8xypuhq5k408f9kh0meyy6jv2lxgqw2fefvjlte0u06dugtmxuhhw8hschdn4q59g64q5s9z42ax6qyg7ewsqt6e548',
datum: null,
datumhash: null,
inlineDatum: null,
inlineDatumRaw: null,
referenceScript: null,
value: [Object]
}
}
}
Decommit message received on Hydra Head WebSocket
json
{
"distributedUTxO": {
"e492f070c2f3449273a1dc6c98391992ea46c88cb2b47c38043926415fe9f8f7#0": {
"address": "addr_test1qpxsf0x8xypuhq5k408f9kh0meyy6jv2lxgqw2fefvjlte0u06dugtmxuhhw8hschdn4q59g64q5s9z42ax6qyg7ewsqt6e548",
"datum": null,
"datumhash": null,
"inlineDatum": null,
"inlineDatumRaw": null,
"referenceScript": null,
"value": {
"lovelace": 2000000
}
}
},
"headId": "7489fdc412ff71a7831ed508e73b2872482099fd4d97ed73663c70f8",
"seq": 227171,
"tag": "DecommitFinalized",
"timestamp": "2025-11-26T08:23:07.390634932Z"
}
Best practices
- Only decommit when necessary to avoid unnecessary Layer 1 fees.
- Carefully check UTxOs before decommitting to avoid asset loss due to mistakes.
- Monitor the snapshot status after decommit to ensure UTxOs have returned to Layer 1.
- If the Head is closed, all UTxOs will be returned to Layer 1 automatically (no manual decommit needed).
