Summary
When building transactions via the /hydra/tx?submit=false endpoint using the official kuber-client npm package (against the devnet provided in this repository), the backend requires clients to explicitly set fee: 0 in transaction requests. Without this explicit parameter, transactions fail with a balance error—even though the devnet protocol parameters define zero transaction fees (txFeeFixed: 0, txFeePerByte: 0).
Environment
- Package:
kuber-client (npm)
- Endpoint:
/hydra/tx?submit=false
- Providers:
hydra0 = new KuberHydraApiProvider("http://localhost:8082");
hydra1 = new KuberHydraApiProvider("http://localhost:8083");
hydra2 = new KuberHydraApiProvider("http://localhost:8084");
providers = [hydra0, hydra1, hydra2];
- Devnet Protocol Parameters:
txFeeFixed: 0
txFeePerByte: 0
executionUnitPrices.priceMemory: 0
executionUnitPrices.priceSteps: 0
- Devnet Setup:
- Using
/kuber-hydra/devnet/runtime/protocol-parameters.json as protocol parameters
- Hydra node started via provided devnet scripts
Steps to Reproduce
- Start a Hydra Head node using the devnet setup and protocol parameters with zero fees:
{
"txFeeFixed": 0,
"txFeePerByte": 0,
"executionUnitPrices": {
"priceMemory": 0,
"priceSteps": 0
}
}
- Query protocol parameters to verify zero fees:
curl http://localhost:8082/hydra/query/protocol-parameters
- Attempt to build a transaction without explicitly setting
fee: 0:
const tx = await provider.buildTx({
inputs: ["<txHash>#<index>"],
outputs: [{
address: "addr_test1...",
value: { lovelace: 5000000 }
}],
changeAddress: "addr_test1..."
// Note: fee parameter is omitted
});
- Observe the error:
APIError: Api Error response [500] : {
"message": "Missing Balance :[(AdaAssetId,400000)]",
"type": "InsufficientInput"
}
- Add explicit
fee: 0 to the request:
const tx = await provider.buildTx({
inputs: ["<txHash>#<index>"],
outputs: [{
address: "addr_test1...",
value: { lovelace: 5000000 }
}],
changeAddress: "addr_test1...",
fee: 0 // ← Explicitly set to zero
});
- Transaction now builds successfully.
Expected Behavior
The transaction builder should automatically derive the fee from the active protocol parameters when the fee field is omitted from the request. Since the Hydra Head protocol parameters explicitly define txFeeFixed: 0 and txFeePerByte: 0, the builder should:
- Query the protocol parameters if not already cached
- Apply the zero-fee policy from those parameters
- Balance the transaction accordingly without requiring client intervention
This behavior would be consistent with standard Cardano transaction building semantics, where protocol parameters govern fee calculation by default.
Actual Behavior
When the fee field is omitted, the backend appears to calculate or assume a non-zero fee (approximately 400,000 lovelace based on the error message), leading to:
- Transaction imbalance errors
- Failed transaction construction
- Requirement for clients to manually specify
fee: 0
This behavior is problematic because:
- It contradicts the protocol parameter configuration
- It breaks the abstraction layer that protocol parameters are supposed to provide
- It forces all clients to have explicit knowledge of Hydra's zero-fee model
- It creates inconsistent behavior between Hydra and mainnet transaction builders
Impact
Developer Experience:
- Requires workarounds in client code that shouldn't be necessary
- Creates confusion about whether fees apply in Hydra Heads
- Breaks intuitive API usage patterns
Code Maintenance:
- Forces boilerplate
fee: 0 in every transaction request
- Makes code less portable between Hydra and mainnet contexts
- Complicates automated testing and CI/CD pipelines
Example of Required Workaround:
// Current workaround needed in every transaction
function buildHydraTx(provider, inputs, outputs, changeAddress) {
return provider.buildTx({
inputs,
outputs,
fee: 0, // Must explicitly set despite protocol params
changeAddress
});
}
Proposed Solution
Modify the transaction builder backend logic to:
-
Default to protocol parameters: When fee is not provided in the request, query the current protocol parameters and calculate the fee accordingly
-
Respect zero-fee protocols: If txFeeFixed and txFeePerByte are both zero, automatically set transaction fee to zero
-
Maintain backward compatibility: Continue to respect explicitly provided fee values to allow manual overrides when necessary

Summary
When building transactions via the
/hydra/tx?submit=falseendpoint using the officialkuber-clientnpm package (against the devnet provided in this repository), the backend requires clients to explicitly setfee: 0in transaction requests. Without this explicit parameter, transactions fail with a balance error—even though the devnet protocol parameters define zero transaction fees (txFeeFixed: 0,txFeePerByte: 0).Environment
kuber-client(npm)/hydra/tx?submit=falsetxFeeFixed: 0txFeePerByte: 0executionUnitPrices.priceMemory: 0executionUnitPrices.priceSteps: 0/kuber-hydra/devnet/runtime/protocol-parameters.jsonas protocol parametersSteps to Reproduce
{ "txFeeFixed": 0, "txFeePerByte": 0, "executionUnitPrices": { "priceMemory": 0, "priceSteps": 0 } }fee: 0:fee: 0to the request:Expected Behavior
The transaction builder should automatically derive the fee from the active protocol parameters when the
feefield is omitted from the request. Since the Hydra Head protocol parameters explicitly definetxFeeFixed: 0andtxFeePerByte: 0, the builder should:This behavior would be consistent with standard Cardano transaction building semantics, where protocol parameters govern fee calculation by default.
Actual Behavior
When the
feefield is omitted, the backend appears to calculate or assume a non-zero fee (approximately 400,000 lovelace based on the error message), leading to:fee: 0This behavior is problematic because:
Impact
Developer Experience:
Code Maintenance:
fee: 0in every transaction requestExample of Required Workaround:
Proposed Solution
Modify the transaction builder backend logic to:
Default to protocol parameters: When
feeis not provided in the request, query the current protocol parameters and calculate the fee accordinglyRespect zero-fee protocols: If
txFeeFixedandtxFeePerByteare both zero, automatically set transaction fee to zeroMaintain backward compatibility: Continue to respect explicitly provided
feevalues to allow manual overrides when necessary