feat(bifrost): SOL vault keep-alive self-sign to keep signature cursors fresh
Problem
When trading is halted or the chain is quiet, organic SOL outbounds stop and the newest signature for a vault address ages out of a non-archival RPC's history retention. The scanner's getSignaturesForAddress until-cursor then anchors to a signature the RPC can no longer resolve (-32020), wedging observation for that vault — the SOL scanner prune-wedge.
Fix
Land one minimal on-chain tx per stale vault so the cursor re-anchors at a recent slot, instead of forcing every node onto archival RPCs.
- The keep-alive is a TSS-signed vault→self transfer carrying the existing consolidate memo — the same network-sends-to-itself primitive the UTXO clients use for consolidation. Accepted by thornode's
ConsolidateHandlerwithout a scheduledTxOutItem, netting the vault record to exactly minus the tx fee via the generic observation paths. No consensus change. - Trigger: each vault member evaluates the same chain facts every 5 min (current slot vs the vault's newest signature slot) and derives an identical self-send amount from the newest signature's slot, so TSS keysign parties converge without coordination and each refresh round gets a distinct signer-cache hash.
- Threshold: the votable
SignatureRefreshBlocksmimir (THORChain blocks; unset → 14400 ≈ 1 day;0disables). - A self-send must list the vault account exactly once or Solana rejects with
AccountLoadedTwice, soCreateTxroutesToAddress == vaultthrough a new deduplicatedNewSelfTransferTransactionbuilder (account index 0 as both source and destination).
Scope
Bifrost-only (SOL). Part of the 3.19.4 bifrost-only patch. Durable complement to !4905 (merged) (minContextSlot cursor, merged) for the same prune-wedge class.
sol_client.go 35 ++-
sol_keepalive.go 262 +++++
sol_keepalive_test.go 117 +++++
types/transaction.go 36 +++
types/transaction_test.go 41 +++
constants/mimir_strings.go 4 +Testing
Merges as part of the 3.19.4 set (!4932 (merged) · !4934 (merged) · !4936 (merged)) and is validated together on stagenet via v3.19.4-rc1 after all three land — this collective stagenet run satisfies Fable's request for a devnet/stagenet validation. Not gated on a separate pre-merge run. Unit coverage: sol_keepalive_test.go, types/transaction_test.go.