What are you trying to do?
I’m building an escrow-style contract that should be able to both receive and later release coins.
fn send(input: QualifiedCoinInfo, recipient: Either<ZswapCoinPublicKey, ContractAddress>, value: Uint<128>) { ... }
Receiving works fine — the contract correctly accepts assets via receive(coin).
However, when I attempt to release the assets (send them back out), I need to pass a valid QualifiedCoinInfo, which includes the coin’s mt_index (Merkle tree index).
Without the correct mt_index, the contract cannot identify and spend the coin it holds.
What’s not working or unclear?
The documentation explains that:
The runtime or indexer already knows the mt_index of each coin’s commitment when the contract receives it.
DApps are supposed to register this mapping by calling:
queryContext.insertCommitment(commitment, index);
The problem is:
There is no documented or programmatic way for a DApp to obtain that mt_index (or the commitment) from the indexer or runtime after the contract has received the coin.
As a result:
I can receive coins, but cannot later construct the required QualifiedCoinInfo.
Therefore, the contract cannot release or send out the assets it holds.
This effectively prevents implementing escrow or similar holding/spending patterns.
Questions:
How can a DApp obtain the correct mt_index for a coin commitment after it’s received by a contract?
Is there an API (current or planned) in the indexer or runtime to expose this data?
How should insertCommitment() be used in practice if we can’t access the index value?
What have you tried so far?
Used the indexer’s Zswap state to estimate the Merkle index:
const mt_index = zswapState.firstFree - 1;
This works inconsistently — only when no other commitments are inserted in the same block.
Reviewed all available docs (docs.midnight.network/develop) — including Contracts, QueryContext, and Coin Handling Proposal — none describe how to fetch mt_index or register it off-chain.
Contacted support earlier — they confirmed the runtime knows the index, and suggested using queryContext.insertCommitment(commitment, index) — but provided no example or way to retrieve those values.
Verified that the issue is not within contract logic — it’s strictly about obtaining mt_index to build a valid QualifiedCoinInfo.
Example of the blocked step:
// Construct QualifiedCoinInfo for release
const input = {
coin: {
nonce: deposit.nonce,
type: deposit.type,
value: deposit.value
},
mt_index: ??? // this is required but unknown
};
// Attempt to send/release
contract.send(input, depositorPublicKey, deposit.value);
Without access to the mt_index, the transaction can’t be signed or validated, so the contract cannot release assets it holds.
Add any relevant code or error messages.