@hardkas/toolkit 0.11.1-alpha → 0.11.4-alpha

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.
Files changed (67) hide show
  1. package/dist/fee-estimator.d.ts +9 -0
  2. package/dist/fee-estimator.d.ts.map +1 -0
  3. package/dist/fee-estimator.js +32 -0
  4. package/dist/fee-estimator.js.map +1 -0
  5. package/dist/index.d.ts +4 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +4 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/indexer.d.ts +3 -1
  10. package/dist/indexer.d.ts.map +1 -1
  11. package/dist/indexer.js +13 -2
  12. package/dist/indexer.js.map +1 -1
  13. package/dist/jobs.d.ts +3 -0
  14. package/dist/jobs.d.ts.map +1 -1
  15. package/dist/jobs.js +16 -1
  16. package/dist/jobs.js.map +1 -1
  17. package/dist/payment.d.ts +4 -2
  18. package/dist/payment.d.ts.map +1 -1
  19. package/dist/payment.js +30 -12
  20. package/dist/payment.js.map +1 -1
  21. package/dist/query-api.d.ts +22 -0
  22. package/dist/query-api.d.ts.map +1 -0
  23. package/dist/query-api.js +116 -0
  24. package/dist/query-api.js.map +1 -0
  25. package/dist/snapshot/serialization.d.ts +0 -9
  26. package/dist/snapshot/serialization.d.ts.map +1 -1
  27. package/dist/snapshot/serialization.js +0 -12
  28. package/dist/snapshot/serialization.js.map +1 -1
  29. package/dist/stores/invoice-store.d.ts +15 -1
  30. package/dist/stores/invoice-store.d.ts.map +1 -1
  31. package/dist/stores/invoice-store.js.map +1 -1
  32. package/dist/subscriptions.d.ts +22 -0
  33. package/dist/subscriptions.d.ts.map +1 -0
  34. package/dist/subscriptions.js +91 -0
  35. package/dist/subscriptions.js.map +1 -0
  36. package/dist/wallet.d.ts +81 -2
  37. package/dist/wallet.d.ts.map +1 -1
  38. package/dist/wallet.js +328 -13
  39. package/dist/wallet.js.map +1 -1
  40. package/package.json +27 -11
  41. package/.turbo/turbo-build.log +0 -4
  42. package/src/dag/consensus.ts +0 -150
  43. package/src/dag/index.ts +0 -73
  44. package/src/dag/store.ts +0 -40
  45. package/src/dag/topology.ts +0 -108
  46. package/src/dag/types.ts +0 -20
  47. package/src/index.ts +0 -9
  48. package/src/indexer.ts +0 -128
  49. package/src/jobs.ts +0 -46
  50. package/src/payment.ts +0 -81
  51. package/src/silver/index.ts +0 -102
  52. package/src/silver/templates.ts +0 -27
  53. package/src/silver/types.ts +0 -37
  54. package/src/snapshot/backends/FsSnapshotBackend.ts +0 -100
  55. package/src/snapshot/backends/MemorySnapshotBackend.ts +0 -65
  56. package/src/snapshot/index.ts +0 -102
  57. package/src/snapshot/serialization.ts +0 -35
  58. package/src/snapshot/types.ts +0 -45
  59. package/src/stores/invoice-store.ts +0 -53
  60. package/src/stores/utxo-control-store.ts +0 -78
  61. package/src/utxos.ts +0 -451
  62. package/src/wallet.ts +0 -93
  63. package/test/silver.test.ts +0 -59
  64. package/test/snapshot.test.ts +0 -99
  65. package/test/toolkit.test.ts +0 -109
  66. package/tsconfig.json +0 -9
  67. package/vitest.config.ts +0 -8
@@ -1 +1 @@
1
- {"version":3,"file":"invoice-store.js","sourceRoot":"","sources":["../../src/stores/invoice-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAavD,MAAM,OAAO,gBAAgB;IACjB,KAAK,CAAiC;IAE9C,YAAY,OAA6B;QACrC,IAAI,CAAC,KAAK,GAAG,IAAI,eAAe,CAAgB,OAAO,CAAC,CAAC;IAC7D,CAAC;IAEM,IAAI,CAAC,OAAsB;QAC9B,OAAO,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC7C,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;IAEM,GAAG,CAAC,EAAU;QACjB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC;IAEM,IAAI;QACP,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,CAAC;IAEM,cAAc,CAAC,UAAkB;QACpC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC;IACtE,CAAC;IAEM,QAAQ;QACX,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;IAC9D,CAAC;IAEM,KAAK,CAAC,UAAmB;QAC5B,IAAI,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACjC,IAAI,UAAU,EAAE,CAAC;YACb,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC;QACjE,CAAC;QAED,OAAO;YACH,aAAa,EAAE,QAAQ,CAAC,MAAM;YAC9B,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,MAAM;SACjE,CAAC;IACN,CAAC;CACJ"}
1
+ {"version":3,"file":"invoice-store.js","sourceRoot":"","sources":["../../src/stores/invoice-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAsBvD,MAAM,OAAO,gBAAgB;IACjB,KAAK,CAAiC;IAE9C,YAAY,OAA6B;QACrC,IAAI,CAAC,KAAK,GAAG,IAAI,eAAe,CAAgB,OAAO,CAAC,CAAC;IAC7D,CAAC;IAEM,IAAI,CAAC,OAAsB;QAC9B,OAAO,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC7C,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;IAEM,GAAG,CAAC,EAAU;QACjB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC;IAEM,IAAI;QACP,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,CAAC;IAEM,cAAc,CAAC,UAAkB;QACpC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC;IACtE,CAAC;IAEM,QAAQ;QACX,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;IAC9D,CAAC;IAEM,KAAK,CAAC,UAAmB;QAC5B,IAAI,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACjC,IAAI,UAAU,EAAE,CAAC;YACb,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC;QACjE,CAAC;QAED,OAAO;YACH,aAAa,EAAE,QAAQ,CAAC,MAAM;YAC9B,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,MAAM;SACjE,CAAC;IACN,CAAC;CACJ"}
@@ -0,0 +1,22 @@
1
+ import { KaspaRpcClient } from "@hardkas/kaspa-rpc";
2
+ export interface WalletSubscriptionEvent {
3
+ type: "transaction";
4
+ txid: string;
5
+ details?: any;
6
+ }
7
+ export type WalletWatchHandler = (event: WalletSubscriptionEvent) => void | Promise<void>;
8
+ export declare class WalletSubscriptionManager {
9
+ private rpc;
10
+ private getAddress;
11
+ private seenTxIds;
12
+ private txIdQueue;
13
+ private readonly MAX_DEDUPE_CACHE;
14
+ private handlers;
15
+ private activeRpcSubscription?;
16
+ constructor(rpc: KaspaRpcClient, getAddress: () => Promise<string>);
17
+ watch(handler: WalletWatchHandler): Promise<{
18
+ unwatch: () => Promise<void>;
19
+ }>;
20
+ private handleRawUtxosChanged;
21
+ }
22
+ //# sourceMappingURL=subscriptions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscriptions.d.ts","sourceRoot":"","sources":["../src/subscriptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGpD,MAAM,WAAW,uBAAuB;IACpC,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,GAAG,CAAC;CACjB;AAED,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,uBAAuB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1F,qBAAa,yBAAyB;IAStB,OAAO,CAAC,GAAG;IAAkB,OAAO,CAAC,UAAU;IAR3D,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAQ;IAGzC,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,qBAAqB,CAAC,CAAmD;gBAE7D,GAAG,EAAE,cAAc,EAAU,UAAU,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC;IAErE,KAAK,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC;IA6B1F,OAAO,CAAC,qBAAqB;CAwDhC"}
@@ -0,0 +1,91 @@
1
+ import { logger } from "@hardkas/observability";
2
+ export class WalletSubscriptionManager {
3
+ rpc;
4
+ getAddress;
5
+ seenTxIds = new Set();
6
+ txIdQueue = []; // Simple LRU tracking
7
+ MAX_DEDUPE_CACHE = 1000;
8
+ // Maintain a list of handlers per address
9
+ handlers = new Set();
10
+ activeRpcSubscription;
11
+ constructor(rpc, getAddress) {
12
+ this.rpc = rpc;
13
+ this.getAddress = getAddress;
14
+ }
15
+ async watch(handler) {
16
+ this.handlers.add(handler);
17
+ // If this is the first handler, spin up the underlying RPC subscription
18
+ if (this.handlers.size === 1 && !this.activeRpcSubscription) {
19
+ const addr = await this.getAddress();
20
+ const subscription = await this.rpc.subscribeToUtxosChanged([addr], (data) => {
21
+ this.handleRawUtxosChanged(data);
22
+ });
23
+ this.activeRpcSubscription = {
24
+ unsubscribe: async () => {
25
+ await subscription.unsubscribe();
26
+ }
27
+ };
28
+ }
29
+ return {
30
+ unwatch: async () => {
31
+ this.handlers.delete(handler);
32
+ if (this.handlers.size === 0 && this.activeRpcSubscription) {
33
+ await this.activeRpcSubscription.unsubscribe().catch(() => { });
34
+ this.activeRpcSubscription = undefined;
35
+ }
36
+ }
37
+ };
38
+ }
39
+ handleRawUtxosChanged(data) {
40
+ // Data usually has 'added' and 'removed' arrays containing KaspaRpcUtxo
41
+ const added = data?.added || data?.utxosAdded || [];
42
+ const removed = data?.removed || data?.utxosRemoved || [];
43
+ // Extract all unique txids from this event
44
+ const incomingTxids = new Set();
45
+ const extractTxid = (utxos) => {
46
+ for (const u of utxos) {
47
+ const txid = u?.outpoint?.transactionId || u?.outpoint?.transaction_id || u?.outpoint?.txId;
48
+ if (txid) {
49
+ incomingTxids.add(txid);
50
+ }
51
+ }
52
+ };
53
+ extractTxid(added);
54
+ extractTxid(removed);
55
+ for (const txid of incomingTxids) {
56
+ if (this.seenTxIds.has(txid)) {
57
+ logger.debug("WalletSubscriptionManager deduplicated event", { txid });
58
+ continue;
59
+ }
60
+ // Mark as seen
61
+ this.seenTxIds.add(txid);
62
+ this.txIdQueue.push(txid);
63
+ if (this.txIdQueue.length > this.MAX_DEDUPE_CACHE) {
64
+ const oldest = this.txIdQueue.shift();
65
+ if (oldest)
66
+ this.seenTxIds.delete(oldest);
67
+ }
68
+ // Dispatch to all wallet-level handlers
69
+ const event = {
70
+ type: "transaction",
71
+ txid,
72
+ details: data
73
+ };
74
+ for (const handler of this.handlers) {
75
+ try {
76
+ // Safe execution
77
+ const res = handler(event);
78
+ if (res instanceof Promise) {
79
+ res.catch(err => {
80
+ logger.error("Wallet watch async handler threw error", { error: err });
81
+ });
82
+ }
83
+ }
84
+ catch (err) {
85
+ logger.error("Wallet watch sync handler threw error", { error: err });
86
+ }
87
+ }
88
+ }
89
+ }
90
+ }
91
+ //# sourceMappingURL=subscriptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscriptions.js","sourceRoot":"","sources":["../src/subscriptions.ts"],"names":[],"mappings":"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"}
package/dist/wallet.d.ts CHANGED
@@ -1,7 +1,14 @@
1
+ import { WalletQueryProvider } from '@hardkas/query';
1
2
  import { WalletUtxoApi } from './utxos.js';
3
+ import { WalletWatchHandler } from './subscriptions.js';
4
+ import { FeePriority } from './fee-estimator.js';
2
5
  export interface WalletToolkitOptions {
3
6
  storePath?: string;
4
7
  network?: "simnet" | "testnet" | "mainnet";
8
+ provider?: WalletQueryProvider;
9
+ rpc?: any;
10
+ signer?: any;
11
+ coinbaseMaturity?: bigint;
5
12
  }
6
13
  export declare class WalletToolkit {
7
14
  readonly name: string;
@@ -11,24 +18,96 @@ export declare class WalletToolkit {
11
18
  private addressManager;
12
19
  private walletQuery;
13
20
  private _utxosApi;
21
+ private _subscriptionManager?;
14
22
  private constructor();
15
23
  static open(name: string, options?: WalletToolkitOptions): WalletToolkit;
16
24
  create(): Promise<void>;
17
- address(): Promise<string>;
25
+ receive(): Promise<string>;
18
26
  balance(): Promise<bigint>;
19
27
  get utxos(): WalletUtxoApi;
20
28
  history(): Promise<any[]>;
29
+ watch(cb: WalletWatchHandler): Promise<{
30
+ unwatch: () => void;
31
+ }>;
21
32
  estimateFee(opts: {
22
33
  to: string;
23
34
  amount: bigint;
24
- }): Promise<any>;
35
+ priority?: FeePriority;
36
+ feeRate?: bigint;
37
+ }): Promise<{
38
+ fee: bigint;
39
+ feeRate: bigint;
40
+ estimatedMass: bigint;
41
+ estimatedFee: bigint;
42
+ totalOut: bigint;
43
+ plan: any;
44
+ evidence: "dynamic" | "heuristic";
45
+ mempoolSize?: number;
46
+ }>;
47
+ /**
48
+ * @deprecated Use hardkas.tx.plan directly or the specific operation helpers like send() or consolidate()
49
+ */
25
50
  planSend(opts: {
26
51
  to: string;
27
52
  amount: bigint;
53
+ priority?: FeePriority;
54
+ feeRate?: bigint;
28
55
  }): Promise<any>;
56
+ /**
57
+ * @deprecated sendSimulated is moved to testing patterns. Use hardkas.localnet.mine() and standard send() flows.
58
+ */
29
59
  sendSimulated(opts: {
30
60
  to: string;
31
61
  amount: bigint;
62
+ priority?: FeePriority;
63
+ feeRate?: bigint;
32
64
  }): Promise<string>;
65
+ private signAndBroadcast;
66
+ send(opts: {
67
+ to: string;
68
+ amount: bigint;
69
+ priority?: FeePriority;
70
+ feeRate?: bigint;
71
+ }): Promise<{
72
+ txId: string;
73
+ plan: any;
74
+ }>;
75
+ payMany(opts: {
76
+ outputs: {
77
+ address: string;
78
+ amount: bigint;
79
+ }[];
80
+ priority?: FeePriority;
81
+ feeRate?: bigint;
82
+ }): Promise<{
83
+ txId: string;
84
+ plan: any;
85
+ }>;
86
+ sweep(opts: {
87
+ to: string;
88
+ priority?: FeePriority;
89
+ feeRate?: bigint;
90
+ }): Promise<{
91
+ txId: string;
92
+ plan: any;
93
+ }>;
94
+ consolidate(opts: {
95
+ to?: string;
96
+ priority?: FeePriority;
97
+ feeRate?: bigint;
98
+ maxUtxos?: number;
99
+ }): Promise<{
100
+ txId: string;
101
+ plan: any;
102
+ }>;
103
+ split(opts: {
104
+ outputsCount: number;
105
+ amountPerOutput: bigint;
106
+ priority?: FeePriority;
107
+ feeRate?: bigint;
108
+ }): Promise<{
109
+ txId: string;
110
+ plan: any;
111
+ }>;
33
112
  }
34
113
  //# sourceMappingURL=wallet.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"wallet.d.ts","sourceRoot":"","sources":["../src/wallet.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG3C,MAAM,WAAW,oBAAoB;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;CAC9C;AAED,qBAAa,aAAa;aAQF,IAAI,EAAE,MAAM;IAC5B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAT5B,OAAO,CAAC,aAAa,CAAoB;IACzC,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,WAAW,CAAc;IAEjC,OAAO,CAAC,SAAS,CAAgB;IAEjC,OAAO;WAsBO,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,oBAAyB,GAAG,aAAa;IAKtE,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAIvB,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;IAY1B,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;IAKvC,IAAW,KAAK,IAAI,aAAa,CAEhC;IAEY,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAKzB,WAAW,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,GAAG,CAAC;IAU/D,QAAQ,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,GAAG,CAAC;IAI5D,aAAa,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC;CAGpF"}
1
+ {"version":3,"file":"wallet.d.ts","sourceRoot":"","sources":["../src/wallet.ts"],"names":[],"mappings":"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"}
package/dist/wallet.js CHANGED
@@ -1,7 +1,26 @@
1
1
  import { WalletManagerImpl, WalletStateStoreJson, AddressManager } from '@hardkas/accounts';
2
2
  import { WalletQuery } from '@hardkas/query';
3
+ import { buildPaymentPlan, toTxBuilderUtxo } from '@hardkas/tx-builder';
3
4
  import { WalletUtxoApi } from './utxos.js';
4
5
  import { UtxoControlStore } from './stores/utxo-control-store.js';
6
+ import { logger, metrics } from '@hardkas/observability';
7
+ import { WalletSubscriptionManager } from './subscriptions.js';
8
+ import { calculateDynamicFeeRate } from './fee-estimator.js';
9
+ metrics.register({
10
+ name: "wallet_tx_generated_total",
11
+ help: "Total tx generated by wallet",
12
+ type: "counter"
13
+ });
14
+ metrics.register({
15
+ name: "wallet_tx_submitted_total",
16
+ help: "Total tx submitted by wallet",
17
+ type: "counter"
18
+ });
19
+ metrics.register({
20
+ name: "wallet_tx_failed_total",
21
+ help: "Total tx failed by wallet",
22
+ type: "counter"
23
+ });
5
24
  export class WalletToolkit {
6
25
  name;
7
26
  store;
@@ -10,18 +29,66 @@ export class WalletToolkit {
10
29
  addressManager;
11
30
  walletQuery;
12
31
  _utxosApi;
32
+ _subscriptionManager;
13
33
  constructor(name, store, options) {
14
34
  this.name = name;
15
35
  this.store = store;
16
36
  this.options = options;
17
37
  this.walletManager = new WalletManagerImpl();
18
38
  this.addressManager = AddressManager;
19
- this.walletQuery = new WalletQuery({});
39
+ let provider = options.provider;
40
+ if (!provider && options.rpc) {
41
+ provider = {
42
+ source: "rpc",
43
+ async getBalances(addresses) {
44
+ const res = {};
45
+ for (const addr of addresses) {
46
+ const bal = await options.rpc.getBalanceByAddress(addr);
47
+ res[addr] = bal.balanceSompi;
48
+ }
49
+ return res;
50
+ },
51
+ async getUtxos(addresses) {
52
+ const res = {};
53
+ for (const addr of addresses) {
54
+ const utxos = await options.rpc.getUtxosByAddress(addr);
55
+ res[addr] = utxos.map((u) => ({
56
+ transactionId: u.outpoint.transactionId,
57
+ outputIndex: u.outpoint.index,
58
+ amountSompi: u.amountSompi,
59
+ scriptPublicKey: u.scriptPublicKey,
60
+ address: u.address,
61
+ blockDaaScore: u.blockDaaScore,
62
+ isCoinbase: u.isCoinbase
63
+ }));
64
+ }
65
+ return res;
66
+ },
67
+ async getHistory() {
68
+ return { items: [] };
69
+ }
70
+ };
71
+ }
72
+ else if (!provider) {
73
+ provider = {
74
+ source: "dummy",
75
+ async getBalances() { return {}; },
76
+ async getUtxos() { return {}; },
77
+ async getHistory() { return { items: [] }; }
78
+ };
79
+ }
80
+ this.walletQuery = new WalletQuery({ provider, network: options.network || "simnet" });
20
81
  const utxoControlPath = options.storePath
21
82
  ? options.storePath.replace('.json', '-utxo-control.json')
22
83
  : 'default-utxo-control.json';
23
84
  const utxoStore = new UtxoControlStore(utxoControlPath);
24
- this._utxosApi = new WalletUtxoApi(async () => (await this.walletQuery.getUtxos([await this.address()])), async () => this.address(), async (inputs, outputs) => BigInt(inputs * 1000 + outputs * 1000), // Dummy fee estimation
85
+ this._utxosApi = new WalletUtxoApi(async () => {
86
+ const addr = await this.receive();
87
+ const res = await this.walletQuery.getUtxos([addr]);
88
+ if (!res.ok)
89
+ throw new Error(res.error || "Degraded query result");
90
+ return res.utxos[addr] || [];
91
+ }, async () => this.receive(), async (inputs, outputs) => BigInt(inputs * 1000 + outputs * 1000), // Dummy fee estimation
25
92
  utxoStore);
26
93
  }
27
94
  static open(name, options = {}) {
@@ -31,7 +98,7 @@ export class WalletToolkit {
31
98
  async create() {
32
99
  this.walletManager.create({ walletId: this.name });
33
100
  }
34
- async address() {
101
+ async receive() {
35
102
  // High level facade: gets receive address
36
103
  const seedRef = this.walletManager.getSeedRef(this.name);
37
104
  return this.addressManager.derive({
@@ -43,30 +110,278 @@ export class WalletToolkit {
43
110
  }).address;
44
111
  }
45
112
  async balance() {
46
- const addr = await this.address();
113
+ const addr = await this.receive();
47
114
  return (await this.walletQuery.getBalance([addr]));
48
115
  }
49
116
  get utxos() {
50
117
  return this._utxosApi;
51
118
  }
52
119
  async history() {
53
- const addr = await this.address();
54
- return (await this.walletQuery.getHistory({ addresses: [addr] }));
120
+ const addr = await this.receive();
121
+ // Return local observed history (best-effort locally + remote if available)
122
+ const remoteHistory = await this.walletQuery.getHistory({ addresses: [addr] });
123
+ // Enhance with local mock/artifacts if needed, but per specs:
124
+ // "txs enviadas por HardKAS, UTXO changes observados, receipts locales"
125
+ // For now, we return remoteHistory items + potentially local state from utxos store
126
+ const items = remoteHistory?.items || remoteHistory || [];
127
+ return items;
128
+ }
129
+ async watch(cb) {
130
+ if (!this.options.rpc || !this.options.rpc.subscribeToUtxosChanged) {
131
+ throw new Error("RPC client with subscription support is required for watch()");
132
+ }
133
+ if (!this._subscriptionManager) {
134
+ this._subscriptionManager = new WalletSubscriptionManager(this.options.rpc, async () => this.receive());
135
+ }
136
+ return this._subscriptionManager.watch(cb);
55
137
  }
56
138
  async estimateFee(opts) {
57
- const u = await this.utxos.list();
58
- // Since we are mocking the facade, just return a fake fee
139
+ const addr = await this.receive();
140
+ const availableUtxos = await this.utxos.list();
141
+ let finalFeeRate = opts.feeRate;
142
+ let evidence = "heuristic";
143
+ let mempoolSize;
144
+ if (!finalFeeRate) {
145
+ const dynamic = await calculateDynamicFeeRate(this.options.rpc, opts.priority || "normal");
146
+ finalFeeRate = dynamic.feeRate;
147
+ evidence = dynamic.evidence;
148
+ mempoolSize = dynamic.mempoolSize;
149
+ }
150
+ // Fetch current DAA score for coinbase maturity filtering
151
+ let virtualDaaScore;
152
+ let networkId;
153
+ if (this.options.rpc?.getBlockDagInfo) {
154
+ try {
155
+ const dagInfo = await this.options.rpc.getBlockDagInfo();
156
+ virtualDaaScore = dagInfo.virtualDaaScore;
157
+ networkId = dagInfo.networkId;
158
+ }
159
+ catch {
160
+ // If DAG info unavailable, proceed without maturity filtering
161
+ }
162
+ }
163
+ const plan = buildPaymentPlan({
164
+ fromAddress: addr,
165
+ outputs: [{ address: opts.to, amountSompi: opts.amount }],
166
+ availableUtxos: availableUtxos,
167
+ feeRateSompiPerMass: finalFeeRate || 1n,
168
+ changeAddress: addr,
169
+ coinbaseMaturity: networkId === "mainnet" ? 1000n : 100n,
170
+ ...(virtualDaaScore !== undefined ? { virtualDaaScore } : {}),
171
+ ...(networkId !== undefined ? { networkId } : {})
172
+ });
173
+ const exactMass = BigInt(plan.estimatedMass);
59
174
  return {
60
- selectedUtxos: [],
61
- fee: 1000n,
62
- totalOut: BigInt(opts.amount) + 1000n
175
+ fee: plan.estimatedFeeSompi,
176
+ feeRate: finalFeeRate || 1n,
177
+ estimatedMass: exactMass,
178
+ estimatedFee: plan.estimatedFeeSompi,
179
+ totalOut: opts.amount + plan.estimatedFeeSompi,
180
+ plan,
181
+ evidence,
182
+ ...(mempoolSize !== undefined ? { mempoolSize } : {})
63
183
  };
64
184
  }
185
+ /**
186
+ * @deprecated Use hardkas.tx.plan directly or the specific operation helpers like send() or consolidate()
187
+ */
65
188
  async planSend(opts) {
66
- return {};
189
+ return {
190
+ message: "This is a stub, as requested by P61 audit. Real planning requires UTXO orchestration."
191
+ };
67
192
  }
193
+ /**
194
+ * @deprecated sendSimulated is moved to testing patterns. Use hardkas.localnet.mine() and standard send() flows.
195
+ */
68
196
  async sendSimulated(opts) {
69
- return `simulated_tx_${Date.now()}`;
197
+ return `sim_tx_${Date.now()}`;
198
+ }
199
+ async signAndBroadcast(plan) {
200
+ if (!this.options.signer) {
201
+ const err = new Error("MISSING_SIGNER: WalletToolkit requires an explicit signer to sign transactions.");
202
+ err.code = "MISSING_SIGNER";
203
+ throw err;
204
+ }
205
+ if (!this.options.rpc) {
206
+ throw new Error("RPC client is required for broadcast.");
207
+ }
208
+ const addr = await this.receive();
209
+ const fakeArtifact = {
210
+ schema: "hardkas.txPlan",
211
+ planId: "wallet-toolkit-inline",
212
+ networkId: this.options.network || "simnet",
213
+ mode: "real",
214
+ from: { address: addr },
215
+ to: { address: plan.outputs[0]?.address || addr },
216
+ amountSompi: plan.outputs.reduce((acc, out) => acc + BigInt(out.amountSompi), 0n).toString(),
217
+ estimatedFeeSompi: plan.estimatedFeeSompi.toString(),
218
+ inputs: plan.inputs,
219
+ outputs: plan.outputs,
220
+ change: plan.change,
221
+ };
222
+ const result = await (this.options.signer.signTxPlan
223
+ ? this.options.signer.signTxPlan({ planArtifact: fakeArtifact })
224
+ : this.options.signer.signTransaction(fakeArtifact));
225
+ const rawTx = JSON.parse(result.signedTransaction.payload);
226
+ const submitRes = await this.options.rpc.submitTransaction(rawTx);
227
+ metrics.inc("wallet_tx_submitted_total");
228
+ logger.info("Wallet tx submitted successfully", { txId: submitRes.transactionId || result.txId });
229
+ // Return full artifact/evidence format
230
+ return {
231
+ txId: submitRes.transactionId || result.txId,
232
+ plan
233
+ };
234
+ }
235
+ async send(opts) {
236
+ return this.payMany({
237
+ outputs: [{ address: opts.to, amount: opts.amount }],
238
+ ...(opts.priority !== undefined ? { priority: opts.priority } : {}),
239
+ ...(opts.feeRate !== undefined ? { feeRate: opts.feeRate } : {})
240
+ });
241
+ }
242
+ async payMany(opts) {
243
+ const addr = await this.receive();
244
+ const availableUtxos = await this.utxos.list();
245
+ let finalFeeRate = opts.feeRate;
246
+ if (!finalFeeRate) {
247
+ const dynamic = await calculateDynamicFeeRate(this.options.rpc, opts.priority || "normal");
248
+ finalFeeRate = dynamic.feeRate;
249
+ }
250
+ // Fetch current DAA score for coinbase maturity filtering
251
+ let virtualDaaScore;
252
+ let networkId;
253
+ if (this.options.rpc?.getBlockDagInfo) {
254
+ try {
255
+ const dagInfo = await this.options.rpc.getBlockDagInfo();
256
+ virtualDaaScore = dagInfo.virtualDaaScore;
257
+ networkId = dagInfo.networkId;
258
+ }
259
+ catch {
260
+ // If DAG info unavailable, proceed without maturity filtering
261
+ }
262
+ }
263
+ const builderOutputs = opts.outputs.map(o => ({ address: o.address, amountSompi: o.amount }));
264
+ const mappedUtxos = availableUtxos.map(u => toTxBuilderUtxo(u));
265
+ const plan = buildPaymentPlan({
266
+ fromAddress: addr,
267
+ outputs: builderOutputs,
268
+ availableUtxos: mappedUtxos,
269
+ feeRateSompiPerMass: finalFeeRate || 1n,
270
+ changeAddress: addr,
271
+ coinbaseMaturity: networkId === "mainnet" ? 1000n : 100n,
272
+ ...(virtualDaaScore !== undefined ? { virtualDaaScore } : {}),
273
+ ...(networkId !== undefined ? { networkId } : {})
274
+ });
275
+ return this.signAndBroadcast(plan);
276
+ }
277
+ async sweep(opts) {
278
+ const addr = await this.receive();
279
+ let availableUtxos = await this.utxos.list();
280
+ if (availableUtxos.length === 0)
281
+ throw new Error("No UTXOs to sweep");
282
+ let finalFeeRate = opts.feeRate;
283
+ if (!finalFeeRate) {
284
+ const dynamic = await calculateDynamicFeeRate(this.options.rpc, opts.priority || "normal");
285
+ finalFeeRate = dynamic.feeRate;
286
+ }
287
+ // Filter immature coinbase UTXOs
288
+ if (this.options.rpc?.getBlockDagInfo) {
289
+ try {
290
+ const dagInfo = await this.options.rpc.getBlockDagInfo();
291
+ const virtualDaaScore = dagInfo.virtualDaaScore;
292
+ if (virtualDaaScore !== undefined) {
293
+ if (this.options.coinbaseMaturity === undefined) {
294
+ throw new Error("COINBASE_MATURITY_UNRESOLVED: WalletToolkit requires coinbaseMaturity to be explicitly provided");
295
+ }
296
+ const COINBASE_MATURITY = this.options.coinbaseMaturity;
297
+ availableUtxos = availableUtxos.filter((u) => {
298
+ if (u.isCoinbase && u.blockDaaScore !== undefined &&
299
+ (virtualDaaScore - BigInt(u.blockDaaScore)) < COINBASE_MATURITY) {
300
+ return false;
301
+ }
302
+ return true;
303
+ });
304
+ if (availableUtxos.length === 0)
305
+ throw new Error("No mature UTXOs to sweep");
306
+ }
307
+ }
308
+ catch (e) {
309
+ if (e.message?.includes("No mature UTXOs"))
310
+ throw e;
311
+ // If DAG info unavailable, proceed without maturity filtering
312
+ }
313
+ }
314
+ const { estimateTransactionMass } = await import("@hardkas/tx-builder");
315
+ const massRes = estimateTransactionMass({
316
+ inputCount: availableUtxos.length,
317
+ outputs: [{ address: opts.to }],
318
+ payloadBytes: 0,
319
+ hasChange: false
320
+ });
321
+ const fee = massRes.mass * (finalFeeRate || 1n);
322
+ const totalValue = availableUtxos.reduce((acc, u) => acc + BigInt(u.amountSompi), 0n);
323
+ const sendValue = totalValue - fee;
324
+ if (sendValue <= 0n) {
325
+ throw new Error("Insufficient funds to cover sweep fee");
326
+ }
327
+ const plan = {
328
+ inputs: availableUtxos,
329
+ outputs: [{ address: opts.to, amountSompi: sendValue }],
330
+ estimatedMass: massRes.mass,
331
+ estimatedFeeSompi: fee
332
+ };
333
+ return this.signAndBroadcast(plan);
334
+ }
335
+ async consolidate(opts) {
336
+ const addr = await this.receive();
337
+ const availableUtxos = await this.utxos.list();
338
+ const maxUtxos = opts.maxUtxos || 100;
339
+ if (availableUtxos.length <= 1) {
340
+ throw new Error("Not enough UTXOs to consolidate");
341
+ }
342
+ // Sort by smallest first to consolidate dust
343
+ const sortedUtxos = [...availableUtxos].sort((a, b) => {
344
+ const diff = BigInt(a.amountSompi) - BigInt(b.amountSompi);
345
+ return diff < 0n ? -1 : diff > 0n ? 1 : 0;
346
+ });
347
+ const selectedUtxos = sortedUtxos.slice(0, maxUtxos);
348
+ const toAddress = opts.to || addr;
349
+ let finalFeeRate = opts.feeRate;
350
+ if (!finalFeeRate) {
351
+ const dynamic = await calculateDynamicFeeRate(this.options.rpc, opts.priority || "normal");
352
+ finalFeeRate = dynamic.feeRate;
353
+ }
354
+ const { estimateTransactionMass } = await import("@hardkas/tx-builder");
355
+ const massRes = estimateTransactionMass({
356
+ inputCount: selectedUtxos.length,
357
+ outputs: [{ address: toAddress }],
358
+ payloadBytes: 0,
359
+ hasChange: false
360
+ });
361
+ const fee = massRes.mass * (finalFeeRate || 1n);
362
+ const totalValue = selectedUtxos.reduce((acc, u) => acc + BigInt(u.amountSompi), 0n);
363
+ const sendValue = totalValue - fee;
364
+ if (sendValue <= 0n) {
365
+ throw new Error("Insufficient funds to cover consolidate fee");
366
+ }
367
+ const plan = {
368
+ inputs: selectedUtxos,
369
+ outputs: [{ address: toAddress, amountSompi: sendValue }],
370
+ estimatedMass: massRes.mass,
371
+ estimatedFeeSompi: fee
372
+ };
373
+ return this.signAndBroadcast(plan);
374
+ }
375
+ async split(opts) {
376
+ if (opts.outputsCount <= 0)
377
+ throw new Error("outputsCount must be greater than 0");
378
+ const addr = await this.receive();
379
+ const outputs = Array(opts.outputsCount).fill({ address: addr, amount: opts.amountPerOutput });
380
+ return this.payMany({
381
+ outputs,
382
+ ...(opts.priority !== undefined ? { priority: opts.priority } : {}),
383
+ ...(opts.feeRate !== undefined ? { feeRate: opts.feeRate } : {})
384
+ });
70
385
  }
71
386
  }
72
387
  //# sourceMappingURL=wallet.js.map