Class: BSV::Wallet::Postgres::UTXOPool

Inherits:
Object
  • Object
show all
Includes:
Interface::UTXOPool
Defined in:
lib/bsv/wallet/postgres/utxo_pool.rb

Overview

Tier 1 UTXO selection — delegates to Store#find_spendable.

No reservation at this tier. Locking happens in Store#create_action via the input row INSERT ON CONFLICT.

Constant Summary collapse

MAX_UTXO_COUNT =
500
MIN_UTXO_SATS =
1000
MAX_CHANGE_PER_TX =
8

Instance Method Summary collapse

Constructor Details

#initialize(store:, max_utxo_count: MAX_UTXO_COUNT, min_utxo_sats: MIN_UTXO_SATS, max_change_per_tx: MAX_CHANGE_PER_TX) ⇒ UTXOPool

Returns a new instance of UTXOPool.

Raises:

  • (ArgumentError)


17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/bsv/wallet/postgres/utxo_pool.rb', line 17

def initialize(store:, max_utxo_count: MAX_UTXO_COUNT,
               min_utxo_sats: MIN_UTXO_SATS,
               max_change_per_tx: MAX_CHANGE_PER_TX)
  raise ArgumentError, 'max_utxo_count must be >= 1' unless max_utxo_count >= 1
  raise ArgumentError, 'min_utxo_sats must be positive' unless min_utxo_sats.positive?
  raise ArgumentError, 'max_change_per_tx must be >= 1' unless max_change_per_tx >= 1

  @store = store
  @max_utxo_count    = max_utxo_count
  @min_utxo_sats     = min_utxo_sats
  @max_change_per_tx = max_change_per_tx
end

Instance Method Details

#balanceObject



42
43
44
# File 'lib/bsv/wallet/postgres/utxo_pool.rb', line 42

def balance
  (Output.spendable.sum(:satoshis) || 0).to_i
end

#change_output_countObject



50
51
52
53
54
# File 'lib/bsv/wallet/postgres/utxo_pool.rb', line 50

def change_output_count
  target = [@max_utxo_count, balance / @min_utxo_sats].min
  deficit = target - spendable_count
  deficit.clamp(1, @max_change_per_tx)
end

#release(outputs:) ⇒ Object



38
39
40
# File 'lib/bsv/wallet/postgres/utxo_pool.rb', line 38

def release(outputs:)
  # No-op for tier 1 — CASCADE handles it
end

#select(satoshis:, exclude: []) ⇒ Object

Raises:

  • (BSV::Wallet::PoolDepletedError)


30
31
32
33
34
35
36
# File 'lib/bsv/wallet/postgres/utxo_pool.rb', line 30

def select(satoshis:, exclude: [])
  candidates = @store.find_spendable(satoshis: satoshis, exclude: exclude)
  total = candidates.sum { |c| c[:satoshis] }
  raise BSV::Wallet::PoolDepletedError, 'default' if total < satoshis

  candidates
end

#spendable_countObject



46
47
48
# File 'lib/bsv/wallet/postgres/utxo_pool.rb', line 46

def spendable_count
  Output.spendable.count
end