Resource Token Mint Event Deduplication Failure in Concurrent Settlement Finalization
Problem Statement
The src/settlement/finalizer.ts module finalizes resource token mint events after tariff evaluation completes. The finalizeMint() function at line 80 checks pending_mints for unprocessed events and submits them to the Soroban contract. When tariff evaluation completes for two resource types simultaneously (water and energy), both trigger finalizeMint() for the same batch. Both read pending_mints and see the same unprocessed events, and both submit identical mint transactions. The Soroban contract receives duplicate mint requests for the same resource token, minting twice the intended amount. The settlement balance sheet shows double the expected token supply.
State Invariants & Parameters
- Resource types: water, energy, bandwidth (independent evaluation paths)
- Mint submission: POST to Soroban RPC (idempotent if properly keyed)
- Settlement batch: processed every 60s
- Duplicate mint risk: 2× intended supply
Affected Code Paths
src/settlement/finalizer.ts:75-120 — Mint submission without dedup check
src/settlement/mintQueue.ts:40-65 — Pending mint queue management
src/billing/tariffFinalizer.ts:55-80 — Tariff completion triggers mint
Resolution Blueprint
- Add a
processed_mints unique constraint on (batch_id, resource_type): INSERT INTO processed_mints (...) VALUES (...) ON CONFLICT DO NOTHING RETURNING id. If no row returned, mint was already processed — skip.
- Implement idempotency keys in Soroban mint:
SHA256(batch_id || resource_type || 'mint') as the idempotency key. The contract checks the key before minting.
- Route all finalization through a single queue worker (BullMQ with resource-type concurrency limit of 1 per batch).
- Add a concurrent finalization test with both water and energy finalization triggering simultaneously and verify exactly one mint per resource type.
Labels
Complexity: Hardcore
Layer: Core-Engine
Type: Race-Condition
Resource Token Mint Event Deduplication Failure in Concurrent Settlement Finalization
Problem Statement
The
src/settlement/finalizer.tsmodule finalizes resource token mint events after tariff evaluation completes. ThefinalizeMint()function at line 80 checkspending_mintsfor unprocessed events and submits them to the Soroban contract. When tariff evaluation completes for two resource types simultaneously (water and energy), both triggerfinalizeMint()for the same batch. Both readpending_mintsand see the same unprocessed events, and both submit identical mint transactions. The Soroban contract receives duplicate mint requests for the same resource token, minting twice the intended amount. The settlement balance sheet shows double the expected token supply.State Invariants & Parameters
Affected Code Paths
src/settlement/finalizer.ts:75-120— Mint submission without dedup checksrc/settlement/mintQueue.ts:40-65— Pending mint queue managementsrc/billing/tariffFinalizer.ts:55-80— Tariff completion triggers mintResolution Blueprint
processed_mintsunique constraint on(batch_id, resource_type):INSERT INTO processed_mints (...) VALUES (...) ON CONFLICT DO NOTHING RETURNING id. If no row returned, mint was already processed — skip.SHA256(batch_id || resource_type || 'mint')as the idempotency key. The contract checks the key before minting.Labels
Complexity: HardcoreLayer: Core-EngineType: Race-Condition