bsv-wallet-postgres 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/{CHANGELOG-wallet-postgres.md → CHANGELOG.md} +28 -0
- data/lib/bsv/wallet_postgres/migrations/002_add_output_state.rb +33 -0
- data/lib/bsv/wallet_postgres/migrations/003_add_wallet_settings.rb +20 -0
- data/lib/bsv/wallet_postgres/migrations/004_add_pending_metadata.rb +69 -0
- data/lib/bsv/wallet_postgres/postgres_store.rb +172 -2
- data/lib/bsv/wallet_postgres/version.rb +1 -1
- metadata +9 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cc93b503d2d084ed5b1221f97803f66b171141f2c8a855b7c247b0a54b434fc3
|
|
4
|
+
data.tar.gz: 55b88e4b7a82168df0da8b38ace070fbc50d76249e08e4aa35aaa49bb09a199f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d124ec0511c1ed69ff41a4c9e3a681d794a869a89c1439286b6bac32dc173576e63f22df86f20665a8b5d216fd2057b9245d5b1756581afe4eab6f71deea39e2
|
|
7
|
+
data.tar.gz: 62842664bdd3ad2ba4f065f0e081065baec92c30bb7ad53cfed71dd1f91135f7e8cb3a9dbea73abe9895a4ef691da5b32ccaf744b6dcc0d3a52caa4b075aedc1
|
|
@@ -5,6 +5,34 @@ All notable changes to the `bsv-wallet-postgres` gem are documented here.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
|
|
6
6
|
and this gem adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## 0.2.0 — 2026-04-12
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Migration 004** — adds `satoshis`, `pending_since`, `pending_reference`,
|
|
13
|
+
`no_send` columns and a partial index on `(state, basket)` for spendable
|
|
14
|
+
rows (#353)
|
|
15
|
+
- **`find_spendable_outputs(basket:, min_satoshis:, sort_order:)`** — query
|
|
16
|
+
spendable outputs with backward-compatible COALESCE for legacy rows (#354)
|
|
17
|
+
- **`update_output_state(outpoint, new_state, ...)`** — transition output
|
|
18
|
+
state with JSONB data synchronisation (#354)
|
|
19
|
+
- **`lock_utxos(outpoints, reference:, no_send:)`** — atomic
|
|
20
|
+
`UPDATE ... WHERE state = 'spendable' RETURNING` pattern for concurrent
|
|
21
|
+
safety (#355)
|
|
22
|
+
- **`release_stale_pending!(timeout:)`** — recover stuck pending outputs,
|
|
23
|
+
exempting `no_send` locks (#355)
|
|
24
|
+
- **PostgresStore settings methods** — `store_setting` / `find_setting`
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- **Spendable boolean sync** — `update_output_state`, `lock_utxos`, and
|
|
29
|
+
`release_stale_pending!` now keep the legacy `spendable` column in sync
|
|
30
|
+
with the `state` column; `filter_outputs` uses dual-column WHERE clause
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- Directory restructure — source moved to `gem/bsv-wallet-postgres/`
|
|
35
|
+
|
|
8
36
|
## 0.1.0 — 2026-04-09
|
|
9
37
|
|
|
10
38
|
Initial release of `bsv-wallet-postgres`, a PostgreSQL-backed
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Add output lifecycle state column to wallet_outputs.
|
|
4
|
+
#
|
|
5
|
+
# Introduces a nullable +state+ text column alongside the existing boolean
|
|
6
|
+
# +spendable+ column. The two fields are kept in sync by the application
|
|
7
|
+
# layer (+PostgresStore#update_output_state+).
|
|
8
|
+
#
|
|
9
|
+
# === State values
|
|
10
|
+
#
|
|
11
|
+
# * +spendable+ — the output is available for coin selection
|
|
12
|
+
# * +pending+ — the output has been selected but the spending transaction
|
|
13
|
+
# has not yet been broadcast or confirmed
|
|
14
|
+
# * +spent+ — the output has been consumed by a confirmed transaction
|
|
15
|
+
#
|
|
16
|
+
# === Backward compatibility
|
|
17
|
+
#
|
|
18
|
+
# Rows written before this migration have +state = NULL+. The application
|
|
19
|
+
# treats +state IS NULL AND spendable = TRUE+ as equivalent to
|
|
20
|
+
# +state = 'spendable'+ so that existing data continues to behave
|
|
21
|
+
# correctly without a backfill.
|
|
22
|
+
#
|
|
23
|
+
# The migration is intentionally non-destructive: +state+ is nullable
|
|
24
|
+
# so the migration itself applies instantly on large tables (no rewrite,
|
|
25
|
+
# no default scan). A backfill can be run offline if required.
|
|
26
|
+
Sequel.migration do
|
|
27
|
+
change do
|
|
28
|
+
alter_table(:wallet_outputs) do
|
|
29
|
+
add_column :state, String, null: true
|
|
30
|
+
add_index :state
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Add wallet settings table to BSV::Wallet::PostgresStore.
|
|
4
|
+
#
|
|
5
|
+
# Provides key-value persistence for wallet configuration (e.g. change
|
|
6
|
+
# output parameters). Keys are short strings (e.g. 'change_params');
|
|
7
|
+
# values are JSON-serialised strings so the schema never needs to change
|
|
8
|
+
# when setting shapes evolve.
|
|
9
|
+
#
|
|
10
|
+
# The table uses +key+ as its primary key so +store_setting+ is a simple
|
|
11
|
+
# upsert (insert-or-replace on conflict).
|
|
12
|
+
Sequel.migration do
|
|
13
|
+
change do
|
|
14
|
+
create_table(:wallet_settings) do
|
|
15
|
+
String :key, primary_key: true
|
|
16
|
+
String :value, text: true, null: false
|
|
17
|
+
DateTime :created_at, null: false, default: Sequel::CURRENT_TIMESTAMP
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Add pending lock metadata columns and satoshis to wallet_outputs.
|
|
4
|
+
#
|
|
5
|
+
# Introduces dedicated columns to support the auto-fund UTXO management
|
|
6
|
+
# methods (+find_spendable_outputs+, +lock_utxos+, +update_output_state+,
|
|
7
|
+
# +release_stale_pending!+) without requiring expensive JSONB extraction
|
|
8
|
+
# on every query.
|
|
9
|
+
#
|
|
10
|
+
# === Columns added
|
|
11
|
+
#
|
|
12
|
+
# * +satoshis+ — bigint, nullable. Mirrors the value stored inside
|
|
13
|
+
# the JSONB +data+ blob so that +find_spendable_outputs+
|
|
14
|
+
# can +ORDER BY satoshis+ without casting. New writes
|
|
15
|
+
# populate this column; existing rows leave it NULL
|
|
16
|
+
# and queries fall back to +COALESCE(satoshis, (data->>'satoshis')::bigint, 0)+.
|
|
17
|
+
#
|
|
18
|
+
# * +pending_since+ — timestamp (UTC), nullable. Set to +NOW()+ when a
|
|
19
|
+
# UTXO is locked via +lock_utxos+. Used by
|
|
20
|
+
# +release_stale_pending!+ to identify stale locks.
|
|
21
|
+
#
|
|
22
|
+
# * +pending_reference+ — text, nullable. Caller-supplied label passed to
|
|
23
|
+
# +lock_utxos+. Carried through for observability.
|
|
24
|
+
#
|
|
25
|
+
# * +no_send+ — boolean, default +false+. When +true+ the lock is
|
|
26
|
+
# exempt from automatic stale recovery by
|
|
27
|
+
# +release_stale_pending!+.
|
|
28
|
+
#
|
|
29
|
+
# === Index added
|
|
30
|
+
#
|
|
31
|
+
# A partial index on +(state, basket)+ filtered to rows where
|
|
32
|
+
# +state IS NULL OR state = 'spendable'+ accelerates the hot path of
|
|
33
|
+
# +find_spendable_outputs+: the vast majority of rows in a live wallet
|
|
34
|
+
# are spendable, not pending or spent.
|
|
35
|
+
#
|
|
36
|
+
# === Backward compatibility
|
|
37
|
+
#
|
|
38
|
+
# All new columns are nullable (or carry a safe default). No existing rows
|
|
39
|
+
# are modified. The application layer handles NULL values via +COALESCE+ or
|
|
40
|
+
# explicit IS NULL checks.
|
|
41
|
+
Sequel.migration do
|
|
42
|
+
up do
|
|
43
|
+
alter_table(:wallet_outputs) do
|
|
44
|
+
add_column :satoshis, :bigint, null: true
|
|
45
|
+
add_column :pending_since, :timestamptz, null: true
|
|
46
|
+
add_column :pending_reference, String, null: true
|
|
47
|
+
add_column :no_send, :boolean, null: false, default: false
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Partial index on spendable rows only — keeps the index small and
|
|
51
|
+
# fast for the typical coin-selection scan.
|
|
52
|
+
run <<~SQL
|
|
53
|
+
CREATE INDEX wallet_outputs_spendable_basket_idx
|
|
54
|
+
ON wallet_outputs (state, basket)
|
|
55
|
+
WHERE (state IS NULL OR state = 'spendable');
|
|
56
|
+
SQL
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
down do
|
|
60
|
+
run 'DROP INDEX IF EXISTS wallet_outputs_spendable_basket_idx;'
|
|
61
|
+
|
|
62
|
+
alter_table(:wallet_outputs) do
|
|
63
|
+
drop_column :no_send
|
|
64
|
+
drop_column :pending_reference
|
|
65
|
+
drop_column :pending_since
|
|
66
|
+
drop_column :satoshis
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -109,7 +109,14 @@ module BSV
|
|
|
109
109
|
@db[:wallet_outputs]
|
|
110
110
|
.insert_conflict(
|
|
111
111
|
target: :outpoint,
|
|
112
|
-
update: {
|
|
112
|
+
update: {
|
|
113
|
+
basket: row[:basket],
|
|
114
|
+
tags: row[:tags],
|
|
115
|
+
spendable: row[:spendable],
|
|
116
|
+
state: row[:state],
|
|
117
|
+
satoshis: row[:satoshis],
|
|
118
|
+
data: row[:data]
|
|
119
|
+
}
|
|
113
120
|
)
|
|
114
121
|
.insert(row)
|
|
115
122
|
output_data
|
|
@@ -128,6 +135,154 @@ module BSV
|
|
|
128
135
|
@db[:wallet_outputs].where(outpoint: outpoint).delete.positive?
|
|
129
136
|
end
|
|
130
137
|
|
|
138
|
+
# Returns outputs whose effective state is +:spendable+.
|
|
139
|
+
#
|
|
140
|
+
# Legacy rows with +state = NULL+ are treated as spendable when the
|
|
141
|
+
# +spendable+ boolean is true (or absent), matching MemoryStore's
|
|
142
|
+
# effective_state logic.
|
|
143
|
+
#
|
|
144
|
+
# @param basket [String, nil] restrict to this basket when provided
|
|
145
|
+
# @param min_satoshis [Integer, nil] exclude outputs below this value
|
|
146
|
+
# @param sort_order [Symbol] +:asc+ or +:desc+ (default +:desc+, largest first)
|
|
147
|
+
# @return [Array<Hash>]
|
|
148
|
+
def find_spendable_outputs(basket: nil, min_satoshis: nil, sort_order: :desc)
|
|
149
|
+
ds = @db[:wallet_outputs]
|
|
150
|
+
.where(Sequel.lit('(state = ? OR (state IS NULL AND spendable = TRUE))', 'spendable'))
|
|
151
|
+
ds = ds.where(basket: basket) if basket
|
|
152
|
+
if min_satoshis
|
|
153
|
+
ds = ds.where(
|
|
154
|
+
Sequel.lit('COALESCE(satoshis, (data->>?)::bigint, 0) >= ?', 'satoshis', min_satoshis)
|
|
155
|
+
)
|
|
156
|
+
end
|
|
157
|
+
satoshis_expr = Sequel.lit('COALESCE(satoshis, (data->>?)::bigint, 0)', 'satoshis')
|
|
158
|
+
ds = ds.order(sort_order == :asc ? Sequel.asc(satoshis_expr) : Sequel.desc(satoshis_expr))
|
|
159
|
+
ds.all.map { |r| symbolise_keys(r[:data]) }
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Transitions the state of an existing output.
|
|
163
|
+
#
|
|
164
|
+
# When +new_state+ is +:pending+, sets +pending_since+, +pending_reference+,
|
|
165
|
+
# and +no_send+, and merges those values into the JSONB +data+ blob.
|
|
166
|
+
#
|
|
167
|
+
# When transitioning away from +:pending+, clears the pending metadata
|
|
168
|
+
# columns and removes the corresponding keys from the JSONB blob.
|
|
169
|
+
#
|
|
170
|
+
# @param outpoint [String] the outpoint identifier
|
|
171
|
+
# @param new_state [Symbol] +:spendable+, +:pending+, or +:spent+
|
|
172
|
+
# @param pending_reference [String, nil] caller-supplied label for a pending lock
|
|
173
|
+
# @param no_send [Boolean, nil] true if the lock belongs to a no_send transaction
|
|
174
|
+
# @raise [BSV::Wallet::WalletError] if the outpoint is not found
|
|
175
|
+
# @return [Hash] the updated output hash
|
|
176
|
+
def update_output_state(outpoint, new_state, pending_reference: nil, no_send: nil)
|
|
177
|
+
state_str = new_state.to_s
|
|
178
|
+
|
|
179
|
+
# Keep legacy spendable boolean in sync so filter_outputs and other
|
|
180
|
+
# queries that haven't migrated to the state column still work.
|
|
181
|
+
spendable_bool = new_state == :spendable
|
|
182
|
+
|
|
183
|
+
if new_state == :pending
|
|
184
|
+
updates = {
|
|
185
|
+
state: state_str,
|
|
186
|
+
spendable: spendable_bool,
|
|
187
|
+
pending_since: Sequel.lit('NOW()'),
|
|
188
|
+
pending_reference: pending_reference,
|
|
189
|
+
no_send: no_send ? true : false,
|
|
190
|
+
data: Sequel.lit(
|
|
191
|
+
"data || jsonb_build_object('state', ?, 'pending_since', NOW()::text, 'pending_reference', ?, 'no_send', ?)",
|
|
192
|
+
state_str, pending_reference, no_send ? true : false
|
|
193
|
+
)
|
|
194
|
+
}
|
|
195
|
+
else
|
|
196
|
+
updates = {
|
|
197
|
+
state: state_str,
|
|
198
|
+
spendable: spendable_bool,
|
|
199
|
+
pending_since: nil,
|
|
200
|
+
pending_reference: nil,
|
|
201
|
+
no_send: false
|
|
202
|
+
}
|
|
203
|
+
# Remove pending keys from JSONB blob, update state
|
|
204
|
+
updates[:data] = Sequel.lit(
|
|
205
|
+
"(data - 'pending_since' - 'pending_reference' - 'no_send') || jsonb_build_object('state', ?)",
|
|
206
|
+
state_str
|
|
207
|
+
)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
ds = @db[:wallet_outputs].where(outpoint: outpoint)
|
|
211
|
+
rows_updated = ds.update(updates)
|
|
212
|
+
raise WalletError, "Output not found: #{outpoint}" if rows_updated.zero?
|
|
213
|
+
|
|
214
|
+
row = ds.first
|
|
215
|
+
symbolise_keys(row[:data])
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Atomically marks a set of outpoints as +:pending+.
|
|
219
|
+
#
|
|
220
|
+
# Uses +UPDATE ... WHERE state = 'spendable' ... RETURNING outpoint+ so that
|
|
221
|
+
# the check-and-set is atomic at the database level. A concurrent caller that
|
|
222
|
+
# wins the race will have already changed the state to 'pending', so the
|
|
223
|
+
# second caller's WHERE clause will not match and will return nothing. No
|
|
224
|
+
# explicit row-level locking is needed — the UPDATE itself takes the lock.
|
|
225
|
+
#
|
|
226
|
+
# Legacy rows with +state = NULL AND spendable = TRUE+ are also eligible.
|
|
227
|
+
#
|
|
228
|
+
# @param outpoints [Array<String>] outpoint identifiers to lock
|
|
229
|
+
# @param reference [String] caller-supplied pending reference
|
|
230
|
+
# @param no_send [Boolean] true if this is a no_send lock
|
|
231
|
+
# @return [Array<String>] outpoints that were actually locked
|
|
232
|
+
def lock_utxos(outpoints, reference:, no_send: false)
|
|
233
|
+
return [] if outpoints.empty?
|
|
234
|
+
|
|
235
|
+
rows = @db[:wallet_outputs]
|
|
236
|
+
.where(outpoint: outpoints)
|
|
237
|
+
.where(Sequel.lit('(state = ? OR (state IS NULL AND spendable = TRUE))', 'spendable'))
|
|
238
|
+
.returning(:outpoint)
|
|
239
|
+
.update(
|
|
240
|
+
state: 'pending',
|
|
241
|
+
spendable: false,
|
|
242
|
+
pending_since: Sequel.lit('NOW()'),
|
|
243
|
+
pending_reference: reference,
|
|
244
|
+
no_send: no_send ? true : false,
|
|
245
|
+
data: Sequel.lit(
|
|
246
|
+
"data || jsonb_build_object('state', 'pending', 'pending_since', NOW()::text, " \
|
|
247
|
+
"'pending_reference', ?, 'no_send', ?)",
|
|
248
|
+
reference, no_send ? true : false
|
|
249
|
+
)
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
rows.map { |r| r[:outpoint] }
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# Releases stale pending locks back to +:spendable+.
|
|
256
|
+
#
|
|
257
|
+
# Any output in +:pending+ state whose +pending_since+ is older than
|
|
258
|
+
# +timeout+ seconds is reset to +spendable+ and its pending metadata is
|
|
259
|
+
# cleared. Outputs with +no_send = true+ are exempt and remain pending.
|
|
260
|
+
# Outputs with +pending_since = NULL+ are also skipped — they are treated
|
|
261
|
+
# as freshly locked (NULL means "just acquired but no timestamp yet").
|
|
262
|
+
#
|
|
263
|
+
# @param timeout [Integer] age in seconds before a lock is considered stale (default 300)
|
|
264
|
+
# @return [Integer] number of outputs released
|
|
265
|
+
def release_stale_pending!(timeout: 300)
|
|
266
|
+
rows = @db[:wallet_outputs]
|
|
267
|
+
.where(state: 'pending')
|
|
268
|
+
.where(Sequel.lit('no_send IS NOT TRUE'))
|
|
269
|
+
.where(Sequel.lit('pending_since IS NOT NULL'))
|
|
270
|
+
.where(Sequel.lit('pending_since < (NOW() - INTERVAL ?)', "#{timeout} seconds"))
|
|
271
|
+
.returning(:outpoint)
|
|
272
|
+
.update(
|
|
273
|
+
state: 'spendable',
|
|
274
|
+
spendable: true,
|
|
275
|
+
pending_since: nil,
|
|
276
|
+
pending_reference: nil,
|
|
277
|
+
no_send: false,
|
|
278
|
+
data: Sequel.lit(
|
|
279
|
+
"(data - 'pending_since' - 'pending_reference' - 'no_send') || jsonb_build_object('state', 'spendable')"
|
|
280
|
+
)
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
rows.length
|
|
284
|
+
end
|
|
285
|
+
|
|
131
286
|
# --- Certificates ---
|
|
132
287
|
|
|
133
288
|
def store_certificate(cert_data)
|
|
@@ -181,6 +336,18 @@ module BSV
|
|
|
181
336
|
@db[:wallet_transactions].where(txid: txid).get(:tx_hex)
|
|
182
337
|
end
|
|
183
338
|
|
|
339
|
+
# --- Settings ---
|
|
340
|
+
|
|
341
|
+
def store_setting(key, value)
|
|
342
|
+
@db[:wallet_settings]
|
|
343
|
+
.insert_conflict(target: :key, update: { value: value })
|
|
344
|
+
.insert(key: key, value: value)
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
def find_setting(key)
|
|
348
|
+
@db[:wallet_settings].where(key: key).get(:value)
|
|
349
|
+
end
|
|
350
|
+
|
|
184
351
|
private
|
|
185
352
|
|
|
186
353
|
# --- Row builders ---
|
|
@@ -195,11 +362,14 @@ module BSV
|
|
|
195
362
|
|
|
196
363
|
def output_row(data)
|
|
197
364
|
spendable = data[:spendable] != false # nil treated as spendable, like MemoryStore
|
|
365
|
+
state = data[:state]&.to_s
|
|
198
366
|
{
|
|
199
367
|
outpoint: data[:outpoint],
|
|
200
368
|
basket: data[:basket],
|
|
201
369
|
tags: Sequel.pg_array(Array(data[:tags]), :text),
|
|
202
370
|
spendable: spendable,
|
|
371
|
+
state: state,
|
|
372
|
+
satoshis: data[:satoshis],
|
|
203
373
|
data: Sequel.pg_jsonb(data.to_h)
|
|
204
374
|
}
|
|
205
375
|
end
|
|
@@ -224,7 +394,7 @@ module BSV
|
|
|
224
394
|
ds = ds.where(outpoint: query[:outpoint]) if query[:outpoint]
|
|
225
395
|
ds = ds.where(basket: query[:basket]) if query[:basket]
|
|
226
396
|
ds = apply_array_filter(ds, :tags, query[:tags], query[:tag_query_mode])
|
|
227
|
-
ds = ds.where(spendable
|
|
397
|
+
ds = ds.where(Sequel.lit('(state = ? OR (state IS NULL AND spendable = TRUE))', 'spendable')) unless query[:include_spent]
|
|
228
398
|
ds
|
|
229
399
|
end
|
|
230
400
|
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bsv-wallet-postgres
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Simon Bettison
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-04-
|
|
10
|
+
date: 2026-04-11 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: bsv-wallet
|
|
@@ -15,7 +15,7 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.4.0
|
|
19
19
|
- - "<"
|
|
20
20
|
- !ruby/object:Gem::Version
|
|
21
21
|
version: '1.0'
|
|
@@ -25,7 +25,7 @@ dependencies:
|
|
|
25
25
|
requirements:
|
|
26
26
|
- - ">="
|
|
27
27
|
- !ruby/object:Gem::Version
|
|
28
|
-
version: 0.
|
|
28
|
+
version: 0.4.0
|
|
29
29
|
- - "<"
|
|
30
30
|
- !ruby/object:Gem::Version
|
|
31
31
|
version: '1.0'
|
|
@@ -63,11 +63,14 @@ executables: []
|
|
|
63
63
|
extensions: []
|
|
64
64
|
extra_rdoc_files: []
|
|
65
65
|
files:
|
|
66
|
-
- CHANGELOG
|
|
66
|
+
- CHANGELOG.md
|
|
67
67
|
- LICENSE
|
|
68
68
|
- lib/bsv-wallet-postgres.rb
|
|
69
69
|
- lib/bsv/wallet_postgres.rb
|
|
70
70
|
- lib/bsv/wallet_postgres/migrations/001_create_wallet_tables.rb
|
|
71
|
+
- lib/bsv/wallet_postgres/migrations/002_add_output_state.rb
|
|
72
|
+
- lib/bsv/wallet_postgres/migrations/003_add_wallet_settings.rb
|
|
73
|
+
- lib/bsv/wallet_postgres/migrations/004_add_pending_metadata.rb
|
|
71
74
|
- lib/bsv/wallet_postgres/postgres_store.rb
|
|
72
75
|
- lib/bsv/wallet_postgres/version.rb
|
|
73
76
|
homepage: https://github.com/sgbett/bsv-ruby-sdk
|
|
@@ -76,7 +79,7 @@ licenses:
|
|
|
76
79
|
metadata:
|
|
77
80
|
homepage_uri: https://github.com/sgbett/bsv-ruby-sdk
|
|
78
81
|
source_code_uri: https://github.com/sgbett/bsv-ruby-sdk
|
|
79
|
-
changelog_uri: https://github.com/sgbett/bsv-ruby-sdk/blob/master/
|
|
82
|
+
changelog_uri: https://github.com/sgbett/bsv-ruby-sdk/blob/master/gem/bsv-wallet-postgres/CHANGELOG.md
|
|
80
83
|
rubygems_mfa_required: 'true'
|
|
81
84
|
rdoc_options: []
|
|
82
85
|
require_paths:
|