@@ -764,16 +764,30 @@ var (
764764 SET shares = $4`
765765
766766 RuntimeConsensusAccountDelegationUpsert = `
767- INSERT INTO chain.runtime_accounts_delegations AS old (runtime, delegator, delegatee, shares)
768- VALUES ($1, $2, $3, $4)
769- ON CONFLICT (runtime, delegator, delegatee) DO UPDATE
770- SET shares = old.shares + $4`
767+ -- Update-first pattern to avoid uint_numeric check failure on negative deltas in shares.
768+ -- Regular UPSERT casts shares from VALUES() before conflict check, causing premature failure.
769+ WITH up AS (
770+ UPDATE chain.runtime_accounts_delegations
771+ SET shares = shares + $4::numeric
772+ WHERE runtime = $1 AND delegator = $2 AND delegatee = $3
773+ RETURNING 1
774+ )
775+ INSERT INTO chain.runtime_accounts_delegations (runtime, delegator, delegatee, shares)
776+ SELECT $1, $2, $3, ($4)::uint_numeric
777+ WHERE NOT EXISTS (SELECT 1 FROM up)`
771778
772779 RuntimeConsensusAccountDebondingDelegationUpsert = `
773- INSERT INTO chain.runtime_accounts_debonding_delegations AS old (runtime, delegator, delegatee, debond_end, shares)
774- VALUES ($1, $2, $3, $4, $5)
775- ON CONFLICT (runtime, delegator, delegatee, debond_end) DO UPDATE
776- SET shares = old.shares + $5`
780+ -- Update-first pattern to avoid uint_numeric check failure on negative deltas in shares.
781+ -- Regular UPSERT casts shares from VALUES() before conflict check, causing premature failure.
782+ WITH up AS (
783+ UPDATE chain.runtime_accounts_debonding_delegations
784+ SET shares = shares + $5::numeric
785+ WHERE runtime = $1 AND delegator = $2 AND delegatee = $3 AND debond_end = $4
786+ RETURNING 1
787+ )
788+ INSERT INTO chain.runtime_accounts_debonding_delegations (runtime, delegator, delegatee, debond_end, shares)
789+ SELECT $1, $2, $3, $4, ($5)::uint_numeric
790+ WHERE NOT EXISTS (SELECT 1 FROM up)`
777791
778792 // The NULL check `debond_end IS NULL` is included to handle pre-v0.15.0 events,
779793 // where debond_end may be NULL. This ensures backward compatibility with older data.
0 commit comments