@breeztech/breez-sdk-spark 0.25.0 → 0.26.1

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.
@@ -2935,6 +2935,10 @@ function __wbg_get_imports() {
2935
2935
  const ret = arg0.listTokensOutputs();
2936
2936
  return ret;
2937
2937
  }, arguments); },
2938
+ __wbg_listWatchedDepositAddresses_55fe8af0643e3ea9: function() { return handleError(function (arg0) {
2939
+ const ret = arg0.listWatchedDepositAddresses();
2940
+ return ret;
2941
+ }, arguments); },
2938
2942
  __wbg_log_cf86719f8acabfda: function(arg0, arg1) {
2939
2943
  arg0.log(arg1);
2940
2944
  },
@@ -3634,6 +3638,18 @@ function __wbg_get_imports() {
3634
3638
  const ret = arg0.updateTokenOutputs(arg1, arg2);
3635
3639
  return ret;
3636
3640
  }, arguments); },
3641
+ __wbg_updateWatchedDepositAddress_260322f77dee1443: function() { return handleError(function (arg0, arg1, arg2, arg3) {
3642
+ let deferred0_0;
3643
+ let deferred0_1;
3644
+ try {
3645
+ deferred0_0 = arg1;
3646
+ deferred0_1 = arg2;
3647
+ const ret = arg0.updateWatchedDepositAddress(getStringFromWasm0(arg1, arg2), arg3);
3648
+ return ret;
3649
+ } finally {
3650
+ wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
3651
+ }
3652
+ }, arguments); },
3637
3653
  __wbg_url_68fd9a221360e0db: function(arg0, arg1) {
3638
3654
  const ret = arg1.url;
3639
3655
  const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
@@ -3669,47 +3685,47 @@ function __wbg_get_imports() {
3669
3685
  return ret;
3670
3686
  },
3671
3687
  __wbindgen_cast_0000000000000001: function(arg0, arg1) {
3672
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 22, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
3673
- const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h62bc116e0c266522);
3688
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 21, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
3689
+ const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h0a7e586e9273e375);
3674
3690
  return ret;
3675
3691
  },
3676
3692
  __wbindgen_cast_0000000000000002: function(arg0, arg1) {
3677
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 397, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3693
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 392, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3678
3694
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h3b28fbbc8b451a25);
3679
3695
  return ret;
3680
3696
  },
3681
3697
  __wbindgen_cast_0000000000000003: function(arg0, arg1) {
3682
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("CloseEvent")], shim_idx: 397, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3698
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("CloseEvent")], shim_idx: 392, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3683
3699
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h3b28fbbc8b451a25_2);
3684
3700
  return ret;
3685
3701
  },
3686
3702
  __wbindgen_cast_0000000000000004: function(arg0, arg1) {
3687
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("MessageEvent")], shim_idx: 397, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3703
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("MessageEvent")], shim_idx: 392, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3688
3704
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h3b28fbbc8b451a25_3);
3689
3705
  return ret;
3690
3706
  },
3691
3707
  __wbindgen_cast_0000000000000005: function(arg0, arg1) {
3692
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("SessionStore")], shim_idx: 22, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
3693
- const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h62bc116e0c266522_4);
3708
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("SessionStore")], shim_idx: 21, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
3709
+ const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h0a7e586e9273e375_4);
3694
3710
  return ret;
3695
3711
  },
3696
3712
  __wbindgen_cast_0000000000000006: function(arg0, arg1) {
3697
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Storage")], shim_idx: 22, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
3698
- const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h62bc116e0c266522_5);
3713
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Storage")], shim_idx: 21, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
3714
+ const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h0a7e586e9273e375_5);
3699
3715
  return ret;
3700
3716
  },
3701
3717
  __wbindgen_cast_0000000000000007: function(arg0, arg1) {
3702
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("TokenStore")], shim_idx: 22, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
3703
- const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h62bc116e0c266522_6);
3718
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("TokenStore")], shim_idx: 21, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
3719
+ const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h0a7e586e9273e375_6);
3704
3720
  return ret;
3705
3721
  },
3706
3722
  __wbindgen_cast_0000000000000008: function(arg0, arg1) {
3707
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("TreeStore")], shim_idx: 22, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
3708
- const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h62bc116e0c266522_7);
3723
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("TreeStore")], shim_idx: 21, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
3724
+ const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h0a7e586e9273e375_7);
3709
3725
  return ret;
3710
3726
  },
3711
3727
  __wbindgen_cast_0000000000000009: function(arg0, arg1) {
3712
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 402, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3728
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 396, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3713
3729
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h484cd36e13f37bd7);
3714
3730
  return ret;
3715
3731
  },
@@ -3817,36 +3833,36 @@ function wasm_bindgen__convert__closures_____invoke__h3b28fbbc8b451a25_3(arg0, a
3817
3833
  wasm.wasm_bindgen__convert__closures_____invoke__h3b28fbbc8b451a25_3(arg0, arg1, arg2);
3818
3834
  }
3819
3835
 
3820
- function wasm_bindgen__convert__closures_____invoke__h62bc116e0c266522(arg0, arg1, arg2) {
3821
- const ret = wasm.wasm_bindgen__convert__closures_____invoke__h62bc116e0c266522(arg0, arg1, arg2);
3836
+ function wasm_bindgen__convert__closures_____invoke__h0a7e586e9273e375(arg0, arg1, arg2) {
3837
+ const ret = wasm.wasm_bindgen__convert__closures_____invoke__h0a7e586e9273e375(arg0, arg1, arg2);
3822
3838
  if (ret[1]) {
3823
3839
  throw takeFromExternrefTable0(ret[0]);
3824
3840
  }
3825
3841
  }
3826
3842
 
3827
- function wasm_bindgen__convert__closures_____invoke__h62bc116e0c266522_4(arg0, arg1, arg2) {
3828
- const ret = wasm.wasm_bindgen__convert__closures_____invoke__h62bc116e0c266522_4(arg0, arg1, arg2);
3843
+ function wasm_bindgen__convert__closures_____invoke__h0a7e586e9273e375_4(arg0, arg1, arg2) {
3844
+ const ret = wasm.wasm_bindgen__convert__closures_____invoke__h0a7e586e9273e375_4(arg0, arg1, arg2);
3829
3845
  if (ret[1]) {
3830
3846
  throw takeFromExternrefTable0(ret[0]);
3831
3847
  }
3832
3848
  }
3833
3849
 
3834
- function wasm_bindgen__convert__closures_____invoke__h62bc116e0c266522_5(arg0, arg1, arg2) {
3835
- const ret = wasm.wasm_bindgen__convert__closures_____invoke__h62bc116e0c266522_5(arg0, arg1, arg2);
3850
+ function wasm_bindgen__convert__closures_____invoke__h0a7e586e9273e375_5(arg0, arg1, arg2) {
3851
+ const ret = wasm.wasm_bindgen__convert__closures_____invoke__h0a7e586e9273e375_5(arg0, arg1, arg2);
3836
3852
  if (ret[1]) {
3837
3853
  throw takeFromExternrefTable0(ret[0]);
3838
3854
  }
3839
3855
  }
3840
3856
 
3841
- function wasm_bindgen__convert__closures_____invoke__h62bc116e0c266522_6(arg0, arg1, arg2) {
3842
- const ret = wasm.wasm_bindgen__convert__closures_____invoke__h62bc116e0c266522_6(arg0, arg1, arg2);
3857
+ function wasm_bindgen__convert__closures_____invoke__h0a7e586e9273e375_6(arg0, arg1, arg2) {
3858
+ const ret = wasm.wasm_bindgen__convert__closures_____invoke__h0a7e586e9273e375_6(arg0, arg1, arg2);
3843
3859
  if (ret[1]) {
3844
3860
  throw takeFromExternrefTable0(ret[0]);
3845
3861
  }
3846
3862
  }
3847
3863
 
3848
- function wasm_bindgen__convert__closures_____invoke__h62bc116e0c266522_7(arg0, arg1, arg2) {
3849
- const ret = wasm.wasm_bindgen__convert__closures_____invoke__h62bc116e0c266522_7(arg0, arg1, arg2);
3864
+ function wasm_bindgen__convert__closures_____invoke__h0a7e586e9273e375_7(arg0, arg1, arg2) {
3865
+ const ret = wasm.wasm_bindgen__convert__closures_____invoke__h0a7e586e9273e375_7(arg0, arg1, arg2);
3850
3866
  if (ret[1]) {
3851
3867
  throw takeFromExternrefTable0(ret[0]);
3852
3868
  }
Binary file
@@ -189,11 +189,11 @@ export const __wbg_externalsparksignerhandle_free: (a: number, b: number) => voi
189
189
  export const __wbg_signingonlyexternalsigners_free: (a: number, b: number) => void;
190
190
  export const signingonlyexternalsigners_breezSigner: (a: number) => number;
191
191
  export const signingonlyexternalsigners_sparkSigner: (a: number) => number;
192
- export const wasm_bindgen__convert__closures_____invoke__h62bc116e0c266522: (a: number, b: number, c: any) => [number, number];
193
- export const wasm_bindgen__convert__closures_____invoke__h62bc116e0c266522_4: (a: number, b: number, c: any) => [number, number];
194
- export const wasm_bindgen__convert__closures_____invoke__h62bc116e0c266522_5: (a: number, b: number, c: any) => [number, number];
195
- export const wasm_bindgen__convert__closures_____invoke__h62bc116e0c266522_6: (a: number, b: number, c: any) => [number, number];
196
- export const wasm_bindgen__convert__closures_____invoke__h62bc116e0c266522_7: (a: number, b: number, c: any) => [number, number];
192
+ export const wasm_bindgen__convert__closures_____invoke__h0a7e586e9273e375: (a: number, b: number, c: any) => [number, number];
193
+ export const wasm_bindgen__convert__closures_____invoke__h0a7e586e9273e375_4: (a: number, b: number, c: any) => [number, number];
194
+ export const wasm_bindgen__convert__closures_____invoke__h0a7e586e9273e375_5: (a: number, b: number, c: any) => [number, number];
195
+ export const wasm_bindgen__convert__closures_____invoke__h0a7e586e9273e375_6: (a: number, b: number, c: any) => [number, number];
196
+ export const wasm_bindgen__convert__closures_____invoke__h0a7e586e9273e375_7: (a: number, b: number, c: any) => [number, number];
197
197
  export const wasm_bindgen__convert__closures_____invoke__h41057d61edf43a32: (a: number, b: number, c: any, d: any) => void;
198
198
  export const wasm_bindgen__convert__closures_____invoke__h3b28fbbc8b451a25: (a: number, b: number, c: any) => void;
199
199
  export const wasm_bindgen__convert__closures_____invoke__h3b28fbbc8b451a25_2: (a: number, b: number, c: any) => void;
@@ -801,7 +801,7 @@ class MysqlStorage {
801
801
  async listDeposits() {
802
802
  try {
803
803
  const [rows] = await this.pool.query(
804
- "SELECT txid, vout, amount_sats, is_mature, claim_error, refund_tx, refund_tx_id, instant_claim_status, refund_state FROM brz_unclaimed_deposits WHERE user_id = ?",
804
+ "SELECT txid, vout, amount_sats, is_mature, claim_error, refund_tx, refund_tx_id, instant_claim_status, refund_state, max_claim_fee FROM brz_unclaimed_deposits WHERE user_id = ?",
805
805
  [this.identity]
806
806
  );
807
807
 
@@ -816,6 +816,7 @@ class MysqlStorage {
816
816
  refundTxId: row.refund_tx_id,
817
817
  instantClaimStatus: parseJson(row.instant_claim_status),
818
818
  refundState: parseJson(row.refund_state),
819
+ maxClaimFee: parseJson(row.max_claim_fee),
819
820
  }));
820
821
  } catch (error) {
821
822
  throw new StorageError(
@@ -868,6 +869,18 @@ class MysqlStorage {
868
869
  payload.refundTxid,
869
870
  ]
870
871
  );
872
+ } else if (payload.type === "maxClaimFee") {
873
+ await this.pool.query(
874
+ `UPDATE brz_unclaimed_deposits
875
+ SET max_claim_fee = ?
876
+ WHERE user_id = ? AND txid = ? AND vout = ?`,
877
+ [
878
+ payload.maxFee ? JSON.stringify(payload.maxFee) : null,
879
+ this.identity,
880
+ txid,
881
+ vout,
882
+ ]
883
+ );
871
884
  } else {
872
885
  throw new StorageError(`Unknown payload type: ${payload.type}`);
873
886
  }
@@ -880,6 +893,59 @@ class MysqlStorage {
880
893
  }
881
894
  }
882
895
 
896
+ async listWatchedDepositAddresses() {
897
+ try {
898
+ const [rows] = await this.pool.query(
899
+ `SELECT address, issued_at, seen FROM brz_watched_deposit_addresses
900
+ WHERE user_id = ? ORDER BY issued_at DESC`,
901
+ [this.identity]
902
+ );
903
+ return rows.map((row) => ({
904
+ address: row.address,
905
+ issuedAt: BigInt(row.issued_at),
906
+ seen: toBool(row.seen) ?? false,
907
+ }));
908
+ } catch (error) {
909
+ throw new StorageError(
910
+ `Failed to list watched deposit addresses: ${error.message}`,
911
+ error
912
+ );
913
+ }
914
+ }
915
+
916
+ async updateWatchedDepositAddress(address, payload) {
917
+ try {
918
+ if (payload.type === "watch") {
919
+ await this.pool.query(
920
+ `INSERT INTO brz_watched_deposit_addresses (user_id, address, issued_at, seen)
921
+ VALUES (?, ?, ?, FALSE)
922
+ ON DUPLICATE KEY UPDATE issued_at = VALUES(issued_at), seen = FALSE`,
923
+ [this.identity, address, String(payload.issuedAt)]
924
+ );
925
+ } else if (payload.type === "seen") {
926
+ await this.pool.query(
927
+ `UPDATE brz_watched_deposit_addresses SET seen = TRUE
928
+ WHERE user_id = ? AND address = ?`,
929
+ [this.identity, address]
930
+ );
931
+ } else if (payload.type === "unwatch") {
932
+ await this.pool.query(
933
+ `DELETE FROM brz_watched_deposit_addresses
934
+ WHERE user_id = ? AND address = ? AND issued_at = ?`,
935
+ [this.identity, address, String(payload.issuedAt)]
936
+ );
937
+ } else {
938
+ throw new StorageError(`Unknown payload type: ${payload.type}`);
939
+ }
940
+ } catch (error) {
941
+ if (error instanceof StorageError) throw error;
942
+ throw new StorageError(
943
+ `Failed to update watched deposit address '${address}': ${error.message}`,
944
+ error
945
+ );
946
+ }
947
+ }
948
+
883
949
  async setLnurlMetadata(metadata) {
884
950
  try {
885
951
  await this._withTransaction(async (conn) => {
@@ -584,6 +584,29 @@ class MysqlMigrationManager {
584
584
  `ALTER TABLE brz_unclaimed_deposits ADD COLUMN refund_state JSON NULL`,
585
585
  ],
586
586
  },
587
+ {
588
+ // Deposit addresses polled on-chain for deposits still in the mempool.
589
+ // Rows are removed once watching them can no longer lead to an early
590
+ // claim, so the table holds only the live watch set.
591
+ name: "Add brz_watched_deposit_addresses",
592
+ sql: [
593
+ `CREATE TABLE IF NOT EXISTS brz_watched_deposit_addresses (
594
+ user_id VARBINARY(33) NOT NULL,
595
+ address VARCHAR(255) NOT NULL,
596
+ issued_at BIGINT NOT NULL,
597
+ seen BOOLEAN NOT NULL DEFAULT FALSE,
598
+ PRIMARY KEY (user_id, address)
599
+ )`,
600
+ ],
601
+ },
602
+ {
603
+ // The fee ceiling standing for one deposit as a JSON-encoded MaxFee,
604
+ // overriding the configured one. NULL when the configured one applies.
605
+ name: "Add max claim fee to brz_unclaimed_deposits",
606
+ sql: [
607
+ `ALTER TABLE brz_unclaimed_deposits ADD COLUMN max_claim_fee JSON NULL`,
608
+ ],
609
+ },
587
610
  ];
588
611
  }
589
612
  }
@@ -730,7 +730,7 @@ class PostgresStorage {
730
730
  async listDeposits() {
731
731
  try {
732
732
  const result = await this.pool.query(
733
- "SELECT txid, vout, amount_sats, is_mature, claim_error, refund_tx, refund_tx_id, instant_claim_status, refund_state FROM brz_unclaimed_deposits WHERE user_id = $1",
733
+ "SELECT txid, vout, amount_sats, is_mature, claim_error, refund_tx, refund_tx_id, instant_claim_status, refund_state, max_claim_fee FROM brz_unclaimed_deposits WHERE user_id = $1",
734
734
  [this.identity]
735
735
  );
736
736
 
@@ -744,6 +744,7 @@ class PostgresStorage {
744
744
  refundTxId: row.refund_tx_id,
745
745
  instantClaimStatus: row.instant_claim_status || null,
746
746
  refundState: row.refund_state || null,
747
+ maxClaimFee: row.max_claim_fee || null,
747
748
  }));
748
749
  } catch (error) {
749
750
  throw new StorageError(
@@ -796,6 +797,18 @@ class PostgresStorage {
796
797
  payload.refundTxid,
797
798
  ]
798
799
  );
800
+ } else if (payload.type === "maxClaimFee") {
801
+ await this.pool.query(
802
+ `UPDATE brz_unclaimed_deposits
803
+ SET max_claim_fee = $1
804
+ WHERE user_id = $2 AND txid = $3 AND vout = $4`,
805
+ [
806
+ payload.maxFee ? JSON.stringify(payload.maxFee) : null,
807
+ this.identity,
808
+ txid,
809
+ vout,
810
+ ]
811
+ );
799
812
  } else {
800
813
  throw new StorageError(`Unknown payload type: ${payload.type}`);
801
814
  }
@@ -808,6 +821,59 @@ class PostgresStorage {
808
821
  }
809
822
  }
810
823
 
824
+ async listWatchedDepositAddresses() {
825
+ try {
826
+ const result = await this.pool.query(
827
+ `SELECT address, issued_at, seen FROM brz_watched_deposit_addresses
828
+ WHERE user_id = $1 ORDER BY issued_at DESC`,
829
+ [this.identity]
830
+ );
831
+ return result.rows.map((row) => ({
832
+ address: row.address,
833
+ issuedAt: BigInt(row.issued_at),
834
+ seen: row.seen ?? false,
835
+ }));
836
+ } catch (error) {
837
+ throw new StorageError(
838
+ `Failed to list watched deposit addresses: ${error.message}`,
839
+ error
840
+ );
841
+ }
842
+ }
843
+
844
+ async updateWatchedDepositAddress(address, payload) {
845
+ try {
846
+ if (payload.type === "watch") {
847
+ await this.pool.query(
848
+ `INSERT INTO brz_watched_deposit_addresses (user_id, address, issued_at, seen)
849
+ VALUES ($1, $2, $3, FALSE)
850
+ ON CONFLICT(user_id, address) DO UPDATE SET issued_at = EXCLUDED.issued_at, seen = FALSE`,
851
+ [this.identity, address, String(payload.issuedAt)]
852
+ );
853
+ } else if (payload.type === "seen") {
854
+ await this.pool.query(
855
+ `UPDATE brz_watched_deposit_addresses SET seen = TRUE
856
+ WHERE user_id = $1 AND address = $2`,
857
+ [this.identity, address]
858
+ );
859
+ } else if (payload.type === "unwatch") {
860
+ await this.pool.query(
861
+ `DELETE FROM brz_watched_deposit_addresses
862
+ WHERE user_id = $1 AND address = $2 AND issued_at = $3`,
863
+ [this.identity, address, String(payload.issuedAt)]
864
+ );
865
+ } else {
866
+ throw new StorageError(`Unknown payload type: ${payload.type}`);
867
+ }
868
+ } catch (error) {
869
+ if (error instanceof StorageError) throw error;
870
+ throw new StorageError(
871
+ `Failed to update watched deposit address '${address}': ${error.message}`,
872
+ error
873
+ );
874
+ }
875
+ }
876
+
811
877
  async setLnurlMetadata(metadata) {
812
878
  try {
813
879
  await this._withTransaction(async (client) => {
@@ -540,6 +540,29 @@ class PostgresMigrationManager {
540
540
  `ALTER TABLE brz_unclaimed_deposits ADD COLUMN refund_state JSONB`,
541
541
  ],
542
542
  },
543
+ {
544
+ // Deposit addresses polled on-chain for deposits still in the mempool.
545
+ // Rows are removed once watching them can no longer lead to an early
546
+ // claim, so the table holds only the live watch set.
547
+ name: "Add brz_watched_deposit_addresses",
548
+ sql: [
549
+ `CREATE TABLE IF NOT EXISTS brz_watched_deposit_addresses (
550
+ user_id BYTEA NOT NULL,
551
+ address TEXT NOT NULL,
552
+ issued_at BIGINT NOT NULL,
553
+ seen BOOLEAN NOT NULL DEFAULT FALSE,
554
+ PRIMARY KEY (user_id, address)
555
+ )`,
556
+ ],
557
+ },
558
+ {
559
+ // The fee ceiling standing for one deposit as a JSON-encoded MaxFee,
560
+ // overriding the configured one. NULL when the configured one applies.
561
+ name: "Add max claim fee to brz_unclaimed_deposits",
562
+ sql: [
563
+ `ALTER TABLE brz_unclaimed_deposits ADD COLUMN max_claim_fee JSONB`,
564
+ ],
565
+ },
543
566
  ];
544
567
  }
545
568
  }
@@ -700,7 +700,7 @@ class SqliteStorage {
700
700
  listDeposits() {
701
701
  try {
702
702
  const stmt = this.db.prepare(`
703
- SELECT txid, vout, amount_sats, is_mature, claim_error, refund_tx, refund_tx_id, instant_claim_status, refund_state
703
+ SELECT txid, vout, amount_sats, is_mature, claim_error, refund_tx, refund_tx_id, instant_claim_status, refund_state, max_claim_fee
704
704
  FROM unclaimed_deposits
705
705
  `);
706
706
 
@@ -718,6 +718,9 @@ class SqliteStorage {
718
718
  ? JSON.parse(row.instant_claim_status)
719
719
  : null,
720
720
  refundState: row.refund_state ? JSON.parse(row.refund_state) : null,
721
+ maxClaimFee: row.max_claim_fee
722
+ ? JSON.parse(row.max_claim_fee)
723
+ : null,
721
724
  }))
722
725
  );
723
726
  } catch (error) {
@@ -767,6 +770,18 @@ class SqliteStorage {
767
770
  `);
768
771
 
769
772
  stmt.run(JSON.stringify(payload.state), txid, vout, payload.refundTxid);
773
+ } else if (payload.type === "maxClaimFee") {
774
+ const stmt = this.db.prepare(`
775
+ UPDATE unclaimed_deposits
776
+ SET max_claim_fee = ?
777
+ WHERE txid = ? AND vout = ?
778
+ `);
779
+
780
+ stmt.run(
781
+ payload.maxFee ? JSON.stringify(payload.maxFee) : null,
782
+ txid,
783
+ vout
784
+ );
770
785
  } else {
771
786
  return Promise.reject(
772
787
  new StorageError(`Unknown payload type: ${payload.type}`)
@@ -784,6 +799,71 @@ class SqliteStorage {
784
799
  }
785
800
  }
786
801
 
802
+ listWatchedDepositAddresses() {
803
+ try {
804
+ const rows = this.db
805
+ .prepare(
806
+ `SELECT address, issued_at, seen FROM watched_deposit_addresses
807
+ ORDER BY issued_at DESC`
808
+ )
809
+ .all();
810
+ return Promise.resolve(
811
+ rows.map((row) => ({
812
+ address: row.address,
813
+ issuedAt: row.issued_at,
814
+ seen: Boolean(row.seen),
815
+ }))
816
+ );
817
+ } catch (error) {
818
+ return Promise.reject(
819
+ new StorageError(
820
+ `Failed to list watched deposit addresses: ${error.message}`,
821
+ error
822
+ )
823
+ );
824
+ }
825
+ }
826
+
827
+ updateWatchedDepositAddress(address, payload) {
828
+ try {
829
+ if (payload.type === "watch") {
830
+ this.db
831
+ .prepare(
832
+ `INSERT INTO watched_deposit_addresses (address, issued_at, seen)
833
+ VALUES (?, ?, 0)
834
+ ON CONFLICT(address) DO UPDATE SET issued_at = excluded.issued_at, seen = 0`
835
+ )
836
+ .run(address, payload.issuedAt);
837
+ } else if (payload.type === "seen") {
838
+ this.db
839
+ .prepare(
840
+ "UPDATE watched_deposit_addresses SET seen = 1 WHERE address = ?"
841
+ )
842
+ .run(address);
843
+ } else if (payload.type === "unwatch") {
844
+ this.db
845
+ .prepare(
846
+ `DELETE FROM watched_deposit_addresses
847
+ WHERE address = ? AND issued_at = ?`
848
+ )
849
+ .run(address, payload.issuedAt);
850
+ } else {
851
+ return Promise.reject(
852
+ new StorageError(`Unknown payload type: ${payload.type}`)
853
+ );
854
+ }
855
+ return Promise.resolve();
856
+ } catch (error) {
857
+ if (error instanceof StorageError) return Promise.reject(error);
858
+ return Promise.reject(
859
+ new StorageError(
860
+ `Failed to update watched deposit address '${address}': ${error.message}`,
861
+ error
862
+ )
863
+ );
864
+ }
865
+ }
866
+
787
867
  setLnurlMetadata(metadata) {
788
868
  try {
789
869
  const stmt = this.db.prepare(
@@ -500,6 +500,27 @@ class MigrationManager {
500
500
  name: "Add refund state to unclaimed_deposits",
501
501
  sql: [`ALTER TABLE unclaimed_deposits ADD COLUMN refund_state TEXT`],
502
502
  },
503
+ {
504
+ // Deposit addresses polled on-chain for deposits still in the mempool.
505
+ // Rows are removed once watching them can no longer lead to an early
506
+ // claim, so the table holds only the live watch set.
507
+ name: "Add watched_deposit_addresses",
508
+ sql: [
509
+ `CREATE TABLE IF NOT EXISTS watched_deposit_addresses (
510
+ address TEXT PRIMARY KEY,
511
+ issued_at INTEGER NOT NULL,
512
+ seen INTEGER NOT NULL DEFAULT 0
513
+ )`,
514
+ ],
515
+ },
516
+ {
517
+ // The fee ceiling standing for one deposit as a JSON-encoded MaxFee,
518
+ // overriding the configured one. NULL when the configured one applies.
519
+ name: "Add max claim fee to unclaimed_deposits",
520
+ sql: [
521
+ `ALTER TABLE unclaimed_deposits ADD COLUMN max_claim_fee TEXT`,
522
+ ],
523
+ },
503
524
  ];
504
525
  }
505
526
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@breeztech/breez-sdk-spark",
3
- "version": "0.25.0",
3
+ "version": "0.26.1",
4
4
  "description": "Breez Spark SDK",
5
5
  "repository": "https://github.com/breez/spark-sdk",
6
6
  "author": "Breez <contact@breez.technology> (https://github.com/breez)",