Bridge: auto-refund does not run when BLS signing expires (EXPIRED) #1352
Summary
When an outbound RequestBridgeMint BLS request reaches terminal EXPIRED (threshold not met), the chain emits inference.bls.EventThresholdSigningFailed but does not auto-refund bridge escrow. GNK stays locked until the user calls cancel-bridge-operation with the plaintext request_id from bridge_mint_requested.
Reproduced twice on gonka-testnet-4 (manual test case #18). Unit tests pass in isolation; live integration fails.
Full evidence: docs/bridge-auto-refund-on-expired-bug.md (in working tree).
Expected
finalizeFailedThresholdSigningRequest → BlsHooks.AfterThresholdSigningFailed → ProcessAutoRefundForFailedBridgeOperation → escrow refund + bridge_operation_auto_refunded + BLS → CANCELLED.
Actual (run B @ block 36114)
| Check | Result |
|---|---|
| Mint height | 36114 |
| BLS id | KDTcSiJ3Jrv45kvMOivlDDznH4MT3bKLB1QYQKRpEuA= |
| Terminal block | 36144 — EventThresholdSigningFailed |
bridge_operation_auto_refunded |
Absent |
| Escrow while EXPIRED | 29B ngonka (+1 GNK locked) |
| BLS status | EXPIRED (not CANCELLED) |
Manual cancel tx 9AA0F016… (plaintext req_36114_…) |
Success → escrow 28B |
Earlier run A (mint 8E610948… @ 35726): same pattern — EXPIRED, no auto-refund, manual cancel worked.
Code path
x/bls/keeper/threshold_signing.go:finalizeFailedThresholdSigningRequest/maybeCloseRetryAfterFailedPostProcessx/inference/module/bls_hooks.go:AfterThresholdSigningFailedx/inference/keeper/bridge_pending_refund.go:ProcessAutoRefundForFailedBridgeOperation
Silent (false, nil) if hooks empty or pending not found — no retry queue for failure hooks.
Test gap
TestProcessAutoRefundForFailedBridgeOperation_Mint calls refund logic directly and sets pending after expiry — does not wire BlsHooks on BLS keeper through ProcessThresholdSigningDeadlines.
Workaround
cancel-bridge-operation --request-id <plaintext req_<height>_…> — not BLS base64 id.
Suggested fixes
- Integration test: mint → expire with wired
BlsHooks→ assert auto-refund. - Verify
InvokeSetBlsHookson deployed testnet/mainnet binaries. - Log when failure hook returns
(false, nil). - Optional: failure-hook retry queue (like completed post-process).
Severity
Medium — funds stuck in escrow without user action; manual cancel required (easy to get wrong request_id format). Reduced from High because the expired signature situation will happen during incidents, not normal operation.
💬 Comments (3)
at the moment all filfox servers are down
when they come back, i will need to take back and restore the environment to continue with testing. The data above will be gone. But we can simulate again on request
@maria-mitina @GLiberman Fixed in #1891.
Root cause (as in #1749): InvokeSetBlsHooks asked depinject for *keeper.Keeper while the BLS module provides keeper.Keeper, so the invoker got nil and never installed the hooks. AfterThresholdSigningFailed never ran, so an EXPIRED mint was never refunded. This matches both testnet runs here.
Changes:
- the invoker now takes the keeper by value, so the inference hooks are installed;
- an auto-refund runs only when the signing request is FAILED or EXPIRED;
- a failed request that no hook handles is now logged instead of passing silently.
Tests: the app built through app.New has the hooks installed, and a mint pending before its deadline is refunded through the real deadline sweep, emits bridge_operation_auto_refunded, and ends CANCELLED.
Not included: a retry queue for the failure hook, and cleanup of pending entries left over from operations that completed while the hooks were off. The fix reaches a chain only with an upgrade that ships it; until then the cancel-bridge-operation workaround still applies.
🔄 Auto-synced from Issue #1352 every hour.
Testnet evidence retrieval (
gonka-testnet-4)Run on seed host
702111:Environment
1. Chain height + BLS params
Result
2. Mint block — events + save plaintext
request_idThe result will be
3. Verify
keccak256(plaintext)matches BLSrequest_idResult
4. BLS signing request state
Result - it is Cancelled because i cancelled manually the EXPIRED BLS tx and refunded manually as a test.
5. Failure block —
EventThresholdSigningFailed, no auto-refundResult
6. Escrow + minter balances
Result - the 1 GNK returned after i manually cancelled
7. Manual cancel tx (recovery)
Result - proof of manual cancel and refund
8. Node logs (hook errors)
Result - None in the logs.
9. Pending refund map (export)
Result - Nothing - the refund was not listed in pending...
Run A (earlier attempt @ 35726)
Notes
cancel-bridge-operation --request-idmust be the plaintextreq_<height>_…frombridge_mint_requested(/tmp/bridge_req_id.txt), not the BLS base64 id (KDTcSiJ3…=).finalize_block_events, nottxs_results.--page-limit(not--limit) forquery bls signing-history.