@sundaeswap/sprinkles 0.6.0 → 0.7.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.
Files changed (158) hide show
  1. package/dist/cjs/Sprinkle/__tests__/action-integration.test.js +590 -0
  2. package/dist/cjs/Sprinkle/__tests__/action-integration.test.js.map +1 -0
  3. package/dist/cjs/Sprinkle/__tests__/action-registry.test.js +193 -0
  4. package/dist/cjs/Sprinkle/__tests__/action-registry.test.js.map +1 -0
  5. package/dist/cjs/Sprinkle/__tests__/action-runner.test.js +304 -0
  6. package/dist/cjs/Sprinkle/__tests__/action-runner.test.js.map +1 -0
  7. package/dist/cjs/Sprinkle/__tests__/builtin-actions.test.js +1110 -0
  8. package/dist/cjs/Sprinkle/__tests__/builtin-actions.test.js.map +1 -0
  9. package/dist/cjs/Sprinkle/__tests__/cli-adapter.test.js +722 -0
  10. package/dist/cjs/Sprinkle/__tests__/cli-adapter.test.js.map +1 -0
  11. package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js +138 -0
  12. package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -1
  13. package/dist/cjs/Sprinkle/__tests__/mcp-adapter.test.js +713 -0
  14. package/dist/cjs/Sprinkle/__tests__/mcp-adapter.test.js.map +1 -0
  15. package/dist/cjs/Sprinkle/__tests__/tui-helpers.test.js +334 -0
  16. package/dist/cjs/Sprinkle/__tests__/tui-helpers.test.js.map +1 -0
  17. package/dist/cjs/Sprinkle/__tests__/wallet-transaction-actions.test.js +749 -0
  18. package/dist/cjs/Sprinkle/__tests__/wallet-transaction-actions.test.js.map +1 -0
  19. package/dist/cjs/Sprinkle/actions/builtin/blaze-helper.js +61 -0
  20. package/dist/cjs/Sprinkle/actions/builtin/blaze-helper.js.map +1 -0
  21. package/dist/cjs/Sprinkle/actions/builtin/index.js +117 -0
  22. package/dist/cjs/Sprinkle/actions/builtin/index.js.map +1 -0
  23. package/dist/cjs/Sprinkle/actions/builtin/profile-actions.js +202 -0
  24. package/dist/cjs/Sprinkle/actions/builtin/profile-actions.js.map +1 -0
  25. package/dist/cjs/Sprinkle/actions/builtin/settings-actions.js +87 -0
  26. package/dist/cjs/Sprinkle/actions/builtin/settings-actions.js.map +1 -0
  27. package/dist/cjs/Sprinkle/actions/builtin/transaction-actions.js +345 -0
  28. package/dist/cjs/Sprinkle/actions/builtin/transaction-actions.js.map +1 -0
  29. package/dist/cjs/Sprinkle/actions/builtin/wallet-actions.js +212 -0
  30. package/dist/cjs/Sprinkle/actions/builtin/wallet-actions.js.map +1 -0
  31. package/dist/cjs/Sprinkle/actions/cli-adapter.js +372 -0
  32. package/dist/cjs/Sprinkle/actions/cli-adapter.js.map +1 -0
  33. package/dist/cjs/Sprinkle/actions/index.js +127 -0
  34. package/dist/cjs/Sprinkle/actions/index.js.map +1 -0
  35. package/dist/cjs/Sprinkle/actions/mcp-adapter.js +415 -0
  36. package/dist/cjs/Sprinkle/actions/mcp-adapter.js.map +1 -0
  37. package/dist/cjs/Sprinkle/actions/registry.js +92 -0
  38. package/dist/cjs/Sprinkle/actions/registry.js.map +1 -0
  39. package/dist/cjs/Sprinkle/actions/runner.js +190 -0
  40. package/dist/cjs/Sprinkle/actions/runner.js.map +1 -0
  41. package/dist/cjs/Sprinkle/actions/tui-helpers.js +96 -0
  42. package/dist/cjs/Sprinkle/actions/tui-helpers.js.map +1 -0
  43. package/dist/cjs/Sprinkle/actions/types.js +68 -0
  44. package/dist/cjs/Sprinkle/actions/types.js.map +1 -0
  45. package/dist/cjs/Sprinkle/index.js +451 -4
  46. package/dist/cjs/Sprinkle/index.js.map +1 -1
  47. package/dist/cjs/Sprinkle/prompts.js +12 -7
  48. package/dist/cjs/Sprinkle/prompts.js.map +1 -1
  49. package/dist/cjs/Sprinkle/type-guards.js +7 -1
  50. package/dist/cjs/Sprinkle/type-guards.js.map +1 -1
  51. package/dist/esm/Sprinkle/__tests__/action-integration.test.js +588 -0
  52. package/dist/esm/Sprinkle/__tests__/action-integration.test.js.map +1 -0
  53. package/dist/esm/Sprinkle/__tests__/action-registry.test.js +192 -0
  54. package/dist/esm/Sprinkle/__tests__/action-registry.test.js.map +1 -0
  55. package/dist/esm/Sprinkle/__tests__/action-runner.test.js +302 -0
  56. package/dist/esm/Sprinkle/__tests__/action-runner.test.js.map +1 -0
  57. package/dist/esm/Sprinkle/__tests__/builtin-actions.test.js +1107 -0
  58. package/dist/esm/Sprinkle/__tests__/builtin-actions.test.js.map +1 -0
  59. package/dist/esm/Sprinkle/__tests__/cli-adapter.test.js +720 -0
  60. package/dist/esm/Sprinkle/__tests__/cli-adapter.test.js.map +1 -0
  61. package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js +138 -0
  62. package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -1
  63. package/dist/esm/Sprinkle/__tests__/mcp-adapter.test.js +712 -0
  64. package/dist/esm/Sprinkle/__tests__/mcp-adapter.test.js.map +1 -0
  65. package/dist/esm/Sprinkle/__tests__/tui-helpers.test.js +332 -0
  66. package/dist/esm/Sprinkle/__tests__/tui-helpers.test.js.map +1 -0
  67. package/dist/esm/Sprinkle/__tests__/wallet-transaction-actions.test.js +747 -0
  68. package/dist/esm/Sprinkle/__tests__/wallet-transaction-actions.test.js.map +1 -0
  69. package/dist/esm/Sprinkle/actions/builtin/blaze-helper.js +55 -0
  70. package/dist/esm/Sprinkle/actions/builtin/blaze-helper.js.map +1 -0
  71. package/dist/esm/Sprinkle/actions/builtin/index.js +32 -0
  72. package/dist/esm/Sprinkle/actions/builtin/index.js.map +1 -0
  73. package/dist/esm/Sprinkle/actions/builtin/profile-actions.js +197 -0
  74. package/dist/esm/Sprinkle/actions/builtin/profile-actions.js.map +1 -0
  75. package/dist/esm/Sprinkle/actions/builtin/settings-actions.js +81 -0
  76. package/dist/esm/Sprinkle/actions/builtin/settings-actions.js.map +1 -0
  77. package/dist/esm/Sprinkle/actions/builtin/transaction-actions.js +340 -0
  78. package/dist/esm/Sprinkle/actions/builtin/transaction-actions.js.map +1 -0
  79. package/dist/esm/Sprinkle/actions/builtin/wallet-actions.js +207 -0
  80. package/dist/esm/Sprinkle/actions/builtin/wallet-actions.js.map +1 -0
  81. package/dist/esm/Sprinkle/actions/cli-adapter.js +361 -0
  82. package/dist/esm/Sprinkle/actions/cli-adapter.js.map +1 -0
  83. package/dist/esm/Sprinkle/actions/index.js +12 -0
  84. package/dist/esm/Sprinkle/actions/index.js.map +1 -0
  85. package/dist/esm/Sprinkle/actions/mcp-adapter.js +407 -0
  86. package/dist/esm/Sprinkle/actions/mcp-adapter.js.map +1 -0
  87. package/dist/esm/Sprinkle/actions/registry.js +85 -0
  88. package/dist/esm/Sprinkle/actions/registry.js.map +1 -0
  89. package/dist/esm/Sprinkle/actions/runner.js +182 -0
  90. package/dist/esm/Sprinkle/actions/runner.js.map +1 -0
  91. package/dist/esm/Sprinkle/actions/tui-helpers.js +91 -0
  92. package/dist/esm/Sprinkle/actions/tui-helpers.js.map +1 -0
  93. package/dist/esm/Sprinkle/actions/types.js +61 -0
  94. package/dist/esm/Sprinkle/actions/types.js.map +1 -0
  95. package/dist/esm/Sprinkle/index.js +299 -4
  96. package/dist/esm/Sprinkle/index.js.map +1 -1
  97. package/dist/esm/Sprinkle/prompts.js +12 -7
  98. package/dist/esm/Sprinkle/prompts.js.map +1 -1
  99. package/dist/esm/Sprinkle/type-guards.js +3 -0
  100. package/dist/esm/Sprinkle/type-guards.js.map +1 -1
  101. package/dist/types/Sprinkle/actions/builtin/blaze-helper.d.ts +39 -0
  102. package/dist/types/Sprinkle/actions/builtin/blaze-helper.d.ts.map +1 -0
  103. package/dist/types/Sprinkle/actions/builtin/index.d.ts +26 -0
  104. package/dist/types/Sprinkle/actions/builtin/index.d.ts.map +1 -0
  105. package/dist/types/Sprinkle/actions/builtin/profile-actions.d.ts +55 -0
  106. package/dist/types/Sprinkle/actions/builtin/profile-actions.d.ts.map +1 -0
  107. package/dist/types/Sprinkle/actions/builtin/settings-actions.d.ts +32 -0
  108. package/dist/types/Sprinkle/actions/builtin/settings-actions.d.ts.map +1 -0
  109. package/dist/types/Sprinkle/actions/builtin/transaction-actions.d.ts +70 -0
  110. package/dist/types/Sprinkle/actions/builtin/transaction-actions.d.ts.map +1 -0
  111. package/dist/types/Sprinkle/actions/builtin/wallet-actions.d.ts +50 -0
  112. package/dist/types/Sprinkle/actions/builtin/wallet-actions.d.ts.map +1 -0
  113. package/dist/types/Sprinkle/actions/cli-adapter.d.ts +104 -0
  114. package/dist/types/Sprinkle/actions/cli-adapter.d.ts.map +1 -0
  115. package/dist/types/Sprinkle/actions/index.d.ts +12 -0
  116. package/dist/types/Sprinkle/actions/index.d.ts.map +1 -0
  117. package/dist/types/Sprinkle/actions/mcp-adapter.d.ts +92 -0
  118. package/dist/types/Sprinkle/actions/mcp-adapter.d.ts.map +1 -0
  119. package/dist/types/Sprinkle/actions/registry.d.ts +42 -0
  120. package/dist/types/Sprinkle/actions/registry.d.ts.map +1 -0
  121. package/dist/types/Sprinkle/actions/runner.d.ts +45 -0
  122. package/dist/types/Sprinkle/actions/runner.d.ts.map +1 -0
  123. package/dist/types/Sprinkle/actions/tui-helpers.d.ts +53 -0
  124. package/dist/types/Sprinkle/actions/tui-helpers.d.ts.map +1 -0
  125. package/dist/types/Sprinkle/actions/types.d.ts +76 -0
  126. package/dist/types/Sprinkle/actions/types.d.ts.map +1 -0
  127. package/dist/types/Sprinkle/index.d.ts +81 -1
  128. package/dist/types/Sprinkle/index.d.ts.map +1 -1
  129. package/dist/types/Sprinkle/prompts.d.ts.map +1 -1
  130. package/dist/types/Sprinkle/type-guards.d.ts +4 -1
  131. package/dist/types/Sprinkle/type-guards.d.ts.map +1 -1
  132. package/dist/types/tsconfig.build.tsbuildinfo +1 -1
  133. package/package.json +9 -2
  134. package/src/Sprinkle/__tests__/action-integration.test.ts +558 -0
  135. package/src/Sprinkle/__tests__/action-registry.test.ts +187 -0
  136. package/src/Sprinkle/__tests__/action-runner.test.ts +324 -0
  137. package/src/Sprinkle/__tests__/builtin-actions.test.ts +1022 -0
  138. package/src/Sprinkle/__tests__/cli-adapter.test.ts +715 -0
  139. package/src/Sprinkle/__tests__/fill-in-struct.test.ts +144 -0
  140. package/src/Sprinkle/__tests__/mcp-adapter.test.ts +718 -0
  141. package/src/Sprinkle/__tests__/tui-helpers.test.ts +325 -0
  142. package/src/Sprinkle/__tests__/wallet-transaction-actions.test.ts +695 -0
  143. package/src/Sprinkle/actions/builtin/blaze-helper.ts +89 -0
  144. package/src/Sprinkle/actions/builtin/index.ts +86 -0
  145. package/src/Sprinkle/actions/builtin/profile-actions.ts +229 -0
  146. package/src/Sprinkle/actions/builtin/settings-actions.ts +99 -0
  147. package/src/Sprinkle/actions/builtin/transaction-actions.ts +381 -0
  148. package/src/Sprinkle/actions/builtin/wallet-actions.ts +233 -0
  149. package/src/Sprinkle/actions/cli-adapter.ts +430 -0
  150. package/src/Sprinkle/actions/index.ts +32 -0
  151. package/src/Sprinkle/actions/mcp-adapter.ts +463 -0
  152. package/src/Sprinkle/actions/registry.ts +97 -0
  153. package/src/Sprinkle/actions/runner.ts +200 -0
  154. package/src/Sprinkle/actions/tui-helpers.ts +114 -0
  155. package/src/Sprinkle/actions/types.ts +91 -0
  156. package/src/Sprinkle/index.ts +395 -3
  157. package/src/Sprinkle/prompts.ts +118 -72
  158. package/src/Sprinkle/type-guards.ts +9 -0
@@ -0,0 +1,749 @@
1
+ "use strict";
2
+
3
+ var _bunTest = require("bun:test");
4
+ var _types = require("../actions/types.js");
5
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
6
+ // ---------------------------------------------------------------------------
7
+ // Mocks
8
+ // ---------------------------------------------------------------------------
9
+
10
+ // Mock wallet/UTxO data factories
11
+ function makeAddress(bech32 = "addr_test1qz...mock") {
12
+ return {
13
+ toBech32: () => bech32
14
+ };
15
+ }
16
+ function makeAssetId(policyId, assetName) {
17
+ return `${policyId}${assetName}`;
18
+ }
19
+ function makeUtxo(opts) {
20
+ const tokenEntries = (opts.tokens ?? []).map(t => [makeAssetId(t.policyId, t.assetName), t.quantity]);
21
+ return {
22
+ input: () => ({
23
+ transactionId: () => ({
24
+ toString: () => opts.txHash
25
+ }),
26
+ index: () => BigInt(opts.index)
27
+ }),
28
+ output: () => ({
29
+ amount: () => ({
30
+ coin: () => opts.lovelace,
31
+ multiasset: () => tokenEntries.length > 0 ? {
32
+ entries: () => tokenEntries
33
+ } : undefined
34
+ })
35
+ })
36
+ };
37
+ }
38
+
39
+ // Controllable mock state
40
+ let mockBlaze = {};
41
+ let mockIsHot = true;
42
+ let mockBlazeError = null;
43
+ _bunTest.mock.module("../actions/builtin/blaze-helper.js", () => ({
44
+ getBlazeFromContext: async () => {
45
+ if (mockBlazeError) throw mockBlazeError;
46
+ return mockBlaze;
47
+ },
48
+ isHotWallet: () => mockIsHot
49
+ }));
50
+
51
+ // Mock Core.AssetId static methods used by wallet/transaction actions
52
+ _bunTest.mock.module("@blaze-cardano/sdk", () => ({
53
+ Core: {
54
+ AssetId: {
55
+ getPolicyId: assetId => assetId.slice(0, 56),
56
+ getAssetName: assetId => assetId.slice(56)
57
+ },
58
+ Transaction: {
59
+ fromCbor: cbor => mockTxFromCbor(cbor)
60
+ },
61
+ TxCBOR: s => s
62
+ },
63
+ Blaze: class {},
64
+ HotWallet: class {}
65
+ }));
66
+
67
+ // Controllable mock transaction from CBOR
68
+ // These mock objects are compatible with the real countSignatures/getRequiredSigners
69
+ // from tx-dialog.ts, so we don't need to mock that module (which would leak globally).
70
+ let mockTxFromCbor = () => ({
71
+ body: () => ({
72
+ hash: () => ({
73
+ toString: () => "abc123txhash"
74
+ }),
75
+ inputs: () => ({
76
+ values: () => [{
77
+ transactionId: () => ({
78
+ toString: () => "input-tx-hash-1"
79
+ }),
80
+ index: () => 0n
81
+ }]
82
+ }),
83
+ outputs: () => [{
84
+ address: () => ({
85
+ toBech32: () => "addr_test1output..."
86
+ }),
87
+ amount: () => ({
88
+ coin: () => 2_000_000n,
89
+ multiasset: () => undefined
90
+ })
91
+ }],
92
+ fee: () => 200_000n,
93
+ requiredSigners: () => null
94
+ }),
95
+ witnessSet: () => ({
96
+ vkeys: () => null
97
+ }),
98
+ toCbor: () => "signed-cbor-hex"
99
+ });
100
+
101
+ // Now import the actions (after mocks are set up)
102
+ const {
103
+ getWalletAddress,
104
+ getWalletBalance,
105
+ getWalletUtxos
106
+ } = await Promise.resolve().then(() => _interopRequireWildcard(require("../actions/builtin/wallet-actions.js")));
107
+ const {
108
+ signTransaction,
109
+ submitTransaction,
110
+ signAndSubmit,
111
+ decodeTransaction
112
+ } = await Promise.resolve().then(() => _interopRequireWildcard(require("../actions/builtin/transaction-actions.js")));
113
+
114
+ // Minimal context factory
115
+ function makeContext(settingsOverrides = {}) {
116
+ return {
117
+ sprinkle: {},
118
+ settings: {
119
+ network: "preview",
120
+ provider: {
121
+ type: "blockfrost",
122
+ apiKey: "test"
123
+ },
124
+ wallet: {
125
+ type: "hot",
126
+ mnemonic: "test words"
127
+ },
128
+ ...settingsOverrides
129
+ }
130
+ };
131
+ }
132
+
133
+ // ---------------------------------------------------------------------------
134
+ // Wallet Actions
135
+ // ---------------------------------------------------------------------------
136
+
137
+ (0, _bunTest.describe)("get-wallet-address", () => {
138
+ (0, _bunTest.beforeEach)(() => {
139
+ mockBlazeError = null;
140
+ mockIsHot = true;
141
+ });
142
+ (0, _bunTest.test)("returns bech32 address and network", async () => {
143
+ mockBlaze = {
144
+ wallet: {
145
+ getChangeAddress: async () => makeAddress("addr_test1qzabc123")
146
+ }
147
+ };
148
+ const ctx = makeContext();
149
+ const result = await getWalletAddress.execute({}, ctx);
150
+ (0, _bunTest.expect)(result.address).toBe("addr_test1qzabc123");
151
+ (0, _bunTest.expect)(result.network).toBe("preview");
152
+ });
153
+ (0, _bunTest.test)("returns 'unknown' network when not in settings", async () => {
154
+ mockBlaze = {
155
+ wallet: {
156
+ getChangeAddress: async () => makeAddress("addr1mainnet")
157
+ }
158
+ };
159
+ const ctx = makeContext({
160
+ network: undefined
161
+ });
162
+ const result = await getWalletAddress.execute({}, ctx);
163
+ (0, _bunTest.expect)(result.network).toBe("unknown");
164
+ });
165
+ (0, _bunTest.test)("throws WALLET_NOT_CONFIGURED when getBlazeFromContext fails", async () => {
166
+ mockBlazeError = new _types.ActionError("Missing settings", "WALLET_NOT_CONFIGURED", {
167
+ missingFields: ["wallet"]
168
+ });
169
+ const ctx = makeContext();
170
+ await (0, _bunTest.expect)(getWalletAddress.execute({}, ctx)).rejects.toMatchObject({
171
+ code: "WALLET_NOT_CONFIGURED"
172
+ });
173
+ });
174
+ (0, _bunTest.test)("throws NO_ADDRESS when wallet returns no address", async () => {
175
+ mockBlaze = {
176
+ wallet: {
177
+ getChangeAddress: async () => {
178
+ throw new Error("no address available");
179
+ }
180
+ }
181
+ };
182
+ const ctx = makeContext();
183
+ await (0, _bunTest.expect)(getWalletAddress.execute({}, ctx)).rejects.toMatchObject({
184
+ code: "NO_ADDRESS"
185
+ });
186
+ });
187
+ (0, _bunTest.test)("has correct metadata", () => {
188
+ (0, _bunTest.expect)(getWalletAddress.name).toBe("get-wallet-address");
189
+ (0, _bunTest.expect)(getWalletAddress.category).toBe("wallet");
190
+ (0, _bunTest.expect)(getWalletAddress.inputSchema).toBeDefined();
191
+ (0, _bunTest.expect)(getWalletAddress.outputSchema).toBeDefined();
192
+ });
193
+ });
194
+ (0, _bunTest.describe)("get-wallet-balance", () => {
195
+ (0, _bunTest.beforeEach)(() => {
196
+ mockBlazeError = null;
197
+ });
198
+ (0, _bunTest.test)("returns lovelace, ada, and empty tokens for ADA-only wallet", async () => {
199
+ mockBlaze = {
200
+ wallet: {
201
+ getUnspentOutputs: async () => [makeUtxo({
202
+ txHash: "tx1",
203
+ index: 0,
204
+ lovelace: 5_000_000n
205
+ }), makeUtxo({
206
+ txHash: "tx2",
207
+ index: 1,
208
+ lovelace: 3_000_000n
209
+ })]
210
+ }
211
+ };
212
+ const result = await getWalletBalance.execute({}, makeContext());
213
+ (0, _bunTest.expect)(result.lovelace).toBe("8000000");
214
+ (0, _bunTest.expect)(result.ada).toBe("8.000000");
215
+ (0, _bunTest.expect)(result.tokens).toEqual([]);
216
+ });
217
+ (0, _bunTest.test)("aggregates tokens across UTxOs", async () => {
218
+ const policyId = "a".repeat(56);
219
+ const assetName = "token1";
220
+ mockBlaze = {
221
+ wallet: {
222
+ getUnspentOutputs: async () => [makeUtxo({
223
+ txHash: "tx1",
224
+ index: 0,
225
+ lovelace: 2_000_000n,
226
+ tokens: [{
227
+ policyId,
228
+ assetName,
229
+ quantity: 100n
230
+ }]
231
+ }), makeUtxo({
232
+ txHash: "tx2",
233
+ index: 0,
234
+ lovelace: 1_000_000n,
235
+ tokens: [{
236
+ policyId,
237
+ assetName,
238
+ quantity: 50n
239
+ }]
240
+ })]
241
+ }
242
+ };
243
+ const result = await getWalletBalance.execute({}, makeContext());
244
+ (0, _bunTest.expect)(result.lovelace).toBe("3000000");
245
+ (0, _bunTest.expect)(result.tokens).toHaveLength(1);
246
+ (0, _bunTest.expect)(result.tokens[0].quantity).toBe("150");
247
+ (0, _bunTest.expect)(result.tokens[0].policyId).toBe(policyId);
248
+ });
249
+ (0, _bunTest.test)("handles fractional ADA correctly", async () => {
250
+ mockBlaze = {
251
+ wallet: {
252
+ getUnspentOutputs: async () => [makeUtxo({
253
+ txHash: "tx1",
254
+ index: 0,
255
+ lovelace: 1_500_123n
256
+ })]
257
+ }
258
+ };
259
+ const result = await getWalletBalance.execute({}, makeContext());
260
+ (0, _bunTest.expect)(result.ada).toBe("1.500123");
261
+ });
262
+ (0, _bunTest.test)("handles zero balance", async () => {
263
+ mockBlaze = {
264
+ wallet: {
265
+ getUnspentOutputs: async () => []
266
+ }
267
+ };
268
+ const result = await getWalletBalance.execute({}, makeContext());
269
+ (0, _bunTest.expect)(result.lovelace).toBe("0");
270
+ (0, _bunTest.expect)(result.ada).toBe("0.000000");
271
+ (0, _bunTest.expect)(result.tokens).toEqual([]);
272
+ });
273
+ (0, _bunTest.test)("throws PROVIDER_ERROR on UTxO fetch failure", async () => {
274
+ mockBlaze = {
275
+ wallet: {
276
+ getUnspentOutputs: async () => {
277
+ throw new Error("connection timeout");
278
+ }
279
+ }
280
+ };
281
+ await (0, _bunTest.expect)(getWalletBalance.execute({}, makeContext())).rejects.toMatchObject({
282
+ code: "PROVIDER_ERROR"
283
+ });
284
+ });
285
+ });
286
+ (0, _bunTest.describe)("get-wallet-utxos", () => {
287
+ (0, _bunTest.beforeEach)(() => {
288
+ mockBlazeError = null;
289
+ });
290
+ (0, _bunTest.test)("returns UTxOs with correct structure", async () => {
291
+ mockBlaze = {
292
+ wallet: {
293
+ getUnspentOutputs: async () => [makeUtxo({
294
+ txHash: "txhash1",
295
+ index: 0,
296
+ lovelace: 5_000_000n
297
+ }), makeUtxo({
298
+ txHash: "txhash2",
299
+ index: 1,
300
+ lovelace: 3_000_000n
301
+ })]
302
+ }
303
+ };
304
+ const result = await getWalletUtxos.execute({}, makeContext());
305
+ (0, _bunTest.expect)(result.total).toBe(2);
306
+ (0, _bunTest.expect)(result.utxos).toHaveLength(2);
307
+ (0, _bunTest.expect)(result.utxos[0].txHash).toBe("txhash1");
308
+ (0, _bunTest.expect)(result.utxos[0].outputIndex).toBe(0);
309
+ (0, _bunTest.expect)(result.utxos[0].lovelace).toBe("5000000");
310
+ (0, _bunTest.expect)(result.utxos[0].tokens).toEqual([]);
311
+ });
312
+ (0, _bunTest.test)("respects limit parameter", async () => {
313
+ mockBlaze = {
314
+ wallet: {
315
+ getUnspentOutputs: async () => Array.from({
316
+ length: 10
317
+ }, (_, i) => makeUtxo({
318
+ txHash: `tx${i}`,
319
+ index: 0,
320
+ lovelace: 1_000_000n
321
+ }))
322
+ }
323
+ };
324
+ const result = await getWalletUtxos.execute({
325
+ limit: 3
326
+ }, makeContext());
327
+ (0, _bunTest.expect)(result.utxos).toHaveLength(3);
328
+ (0, _bunTest.expect)(result.total).toBe(10);
329
+ });
330
+ (0, _bunTest.test)("defaults to limit of 100", async () => {
331
+ mockBlaze = {
332
+ wallet: {
333
+ getUnspentOutputs: async () => Array.from({
334
+ length: 150
335
+ }, (_, i) => makeUtxo({
336
+ txHash: `tx${i}`,
337
+ index: 0,
338
+ lovelace: 1_000_000n
339
+ }))
340
+ }
341
+ };
342
+ const result = await getWalletUtxos.execute({}, makeContext());
343
+ (0, _bunTest.expect)(result.utxos).toHaveLength(100);
344
+ (0, _bunTest.expect)(result.total).toBe(150);
345
+ });
346
+ (0, _bunTest.test)("includes tokens on UTxOs", async () => {
347
+ const policyId = "b".repeat(56);
348
+ mockBlaze = {
349
+ wallet: {
350
+ getUnspentOutputs: async () => [makeUtxo({
351
+ txHash: "tx1",
352
+ index: 0,
353
+ lovelace: 2_000_000n,
354
+ tokens: [{
355
+ policyId,
356
+ assetName: "mytoken",
357
+ quantity: 42n
358
+ }]
359
+ })]
360
+ }
361
+ };
362
+ const result = await getWalletUtxos.execute({}, makeContext());
363
+ (0, _bunTest.expect)(result.utxos[0].tokens).toHaveLength(1);
364
+ (0, _bunTest.expect)(result.utxos[0].tokens[0].quantity).toBe("42");
365
+ });
366
+ (0, _bunTest.test)("throws PROVIDER_ERROR on fetch failure", async () => {
367
+ mockBlaze = {
368
+ wallet: {
369
+ getUnspentOutputs: async () => {
370
+ throw new Error("provider down");
371
+ }
372
+ }
373
+ };
374
+ await (0, _bunTest.expect)(getWalletUtxos.execute({}, makeContext())).rejects.toMatchObject({
375
+ code: "PROVIDER_ERROR"
376
+ });
377
+ });
378
+ });
379
+
380
+ // ---------------------------------------------------------------------------
381
+ // Transaction Actions
382
+ // ---------------------------------------------------------------------------
383
+
384
+ (0, _bunTest.describe)("sign-transaction", () => {
385
+ (0, _bunTest.beforeEach)(() => {
386
+ mockBlazeError = null;
387
+ mockIsHot = true;
388
+ });
389
+ (0, _bunTest.test)("signs a transaction and returns signed CBOR, hash, and signature count", async () => {
390
+ mockBlaze = {
391
+ wallet: {},
392
+ signTransaction: async () => ({
393
+ toCbor: () => "signed-tx-cbor",
394
+ body: () => ({
395
+ hash: () => ({
396
+ toString: () => "signed-tx-hash"
397
+ })
398
+ }),
399
+ witnessSet: () => ({
400
+ vkeys: () => ({
401
+ size: () => 1
402
+ })
403
+ })
404
+ })
405
+ };
406
+ const result = await signTransaction.execute({
407
+ txCbor: "valid-cbor"
408
+ }, makeContext());
409
+ (0, _bunTest.expect)(result.signedTxCbor).toBe("signed-tx-cbor");
410
+ (0, _bunTest.expect)(result.txHash).toBe("signed-tx-hash");
411
+ (0, _bunTest.expect)(result.signatureCount).toBe(1);
412
+ });
413
+ (0, _bunTest.test)("throws COLD_WALLET for cold wallets", async () => {
414
+ mockIsHot = false;
415
+ mockBlaze = {
416
+ wallet: {}
417
+ };
418
+ await (0, _bunTest.expect)(signTransaction.execute({
419
+ txCbor: "some-cbor"
420
+ }, makeContext())).rejects.toMatchObject({
421
+ code: "COLD_WALLET"
422
+ });
423
+ });
424
+ (0, _bunTest.test)("throws INVALID_CBOR for bad CBOR input", async () => {
425
+ mockTxFromCbor = () => {
426
+ throw new Error("invalid cbor");
427
+ };
428
+ mockBlaze = {
429
+ wallet: {}
430
+ };
431
+ await (0, _bunTest.expect)(signTransaction.execute({
432
+ txCbor: "bad-cbor"
433
+ }, makeContext())).rejects.toMatchObject({
434
+ code: "INVALID_CBOR"
435
+ });
436
+
437
+ // Restore default mock
438
+ mockTxFromCbor = () => ({
439
+ body: () => ({
440
+ hash: () => ({
441
+ toString: () => "abc123txhash"
442
+ }),
443
+ inputs: () => ({
444
+ values: () => []
445
+ }),
446
+ outputs: () => [],
447
+ fee: () => 200_000n,
448
+ requiredSigners: () => null
449
+ }),
450
+ witnessSet: () => ({
451
+ vkeys: () => null
452
+ }),
453
+ toCbor: () => "signed-cbor-hex"
454
+ });
455
+ });
456
+ (0, _bunTest.test)("throws SIGN_ERROR when signing fails", async () => {
457
+ mockBlaze = {
458
+ wallet: {},
459
+ signTransaction: async () => {
460
+ throw new Error("hardware wallet disconnected");
461
+ }
462
+ };
463
+ await (0, _bunTest.expect)(signTransaction.execute({
464
+ txCbor: "valid-cbor"
465
+ }, makeContext())).rejects.toMatchObject({
466
+ code: "SIGN_ERROR"
467
+ });
468
+ });
469
+ (0, _bunTest.test)("has correct metadata", () => {
470
+ (0, _bunTest.expect)(signTransaction.name).toBe("sign-transaction");
471
+ (0, _bunTest.expect)(signTransaction.category).toBe("wallet");
472
+ });
473
+ });
474
+ (0, _bunTest.describe)("submit-transaction", () => {
475
+ (0, _bunTest.beforeEach)(() => {
476
+ mockBlazeError = null;
477
+ });
478
+ (0, _bunTest.test)("submits a transaction and returns hash", async () => {
479
+ mockBlaze = {
480
+ wallet: {},
481
+ submitTransaction: async () => ({
482
+ toString: () => "submitted-tx-hash"
483
+ })
484
+ };
485
+ const result = await submitTransaction.execute({
486
+ txCbor: "valid-signed-cbor"
487
+ }, makeContext());
488
+ (0, _bunTest.expect)(result.txHash).toBe("submitted-tx-hash");
489
+ (0, _bunTest.expect)(result.submitted).toBe(true);
490
+ });
491
+ (0, _bunTest.test)("throws SUBMISSION_ERROR on failure", async () => {
492
+ mockBlaze = {
493
+ wallet: {},
494
+ submitTransaction: async () => {
495
+ throw new Error("tx already submitted");
496
+ }
497
+ };
498
+ await (0, _bunTest.expect)(submitTransaction.execute({
499
+ txCbor: "some-cbor"
500
+ }, makeContext())).rejects.toMatchObject({
501
+ code: "SUBMISSION_ERROR"
502
+ });
503
+ });
504
+ (0, _bunTest.test)("has correct metadata", () => {
505
+ (0, _bunTest.expect)(submitTransaction.name).toBe("submit-transaction");
506
+ (0, _bunTest.expect)(submitTransaction.category).toBe("wallet");
507
+ });
508
+ });
509
+ (0, _bunTest.describe)("sign-and-submit", () => {
510
+ (0, _bunTest.beforeEach)(() => {
511
+ mockBlazeError = null;
512
+ mockIsHot = true;
513
+ });
514
+ (0, _bunTest.test)("signs and submits without waiting for confirmation", async () => {
515
+ mockBlaze = {
516
+ wallet: {},
517
+ signTransaction: async () => ({
518
+ toCbor: () => "signed-cbor",
519
+ body: () => ({
520
+ hash: () => ({
521
+ toString: () => "tx-hash"
522
+ })
523
+ }),
524
+ witnessSet: () => ({
525
+ vkeys: () => ({
526
+ size: () => 1
527
+ })
528
+ })
529
+ }),
530
+ submitTransaction: async () => ({
531
+ toString: () => "tx-hash"
532
+ })
533
+ };
534
+ const result = await signAndSubmit.execute({
535
+ txCbor: "valid-cbor",
536
+ waitForConfirmation: false
537
+ }, makeContext());
538
+ (0, _bunTest.expect)(result.txHash).toBe("tx-hash");
539
+ (0, _bunTest.expect)(result.submitted).toBe(true);
540
+ (0, _bunTest.expect)(result.signedTxCbor).toBe("signed-cbor");
541
+ (0, _bunTest.expect)(result.confirmed).toBeUndefined();
542
+ });
543
+ (0, _bunTest.test)("throws COLD_WALLET for cold wallets", async () => {
544
+ mockIsHot = false;
545
+ mockBlaze = {
546
+ wallet: {}
547
+ };
548
+ await (0, _bunTest.expect)(signAndSubmit.execute({
549
+ txCbor: "cbor"
550
+ }, makeContext())).rejects.toMatchObject({
551
+ code: "COLD_WALLET"
552
+ });
553
+ });
554
+ (0, _bunTest.test)("throws SUBMISSION_ERROR when submit fails (includes signedTxCbor in details)", async () => {
555
+ mockBlaze = {
556
+ wallet: {},
557
+ signTransaction: async () => ({
558
+ toCbor: () => "signed-but-failed",
559
+ body: () => ({
560
+ hash: () => ({
561
+ toString: () => "hash"
562
+ })
563
+ }),
564
+ witnessSet: () => ({
565
+ vkeys: () => null
566
+ })
567
+ }),
568
+ submitTransaction: async () => {
569
+ throw new Error("node rejected");
570
+ }
571
+ };
572
+ try {
573
+ await signAndSubmit.execute({
574
+ txCbor: "valid-cbor"
575
+ }, makeContext());
576
+ (0, _bunTest.expect)(true).toBe(false); // should not reach
577
+ } catch (err) {
578
+ (0, _bunTest.expect)(err.code).toBe("SUBMISSION_ERROR");
579
+ (0, _bunTest.expect)(err.details.signedTxCbor).toBe("signed-but-failed");
580
+ }
581
+ });
582
+ (0, _bunTest.test)("has correct metadata", () => {
583
+ (0, _bunTest.expect)(signAndSubmit.name).toBe("sign-and-submit");
584
+ (0, _bunTest.expect)(signAndSubmit.category).toBe("wallet");
585
+ });
586
+ });
587
+ (0, _bunTest.describe)("decode-transaction", () => {
588
+ (0, _bunTest.beforeEach)(() => {
589
+ mockBlazeError = null;
590
+
591
+ // Set up a rich mock transaction for decode tests
592
+ mockTxFromCbor = () => ({
593
+ body: () => ({
594
+ hash: () => ({
595
+ toString: () => "decoded-tx-hash"
596
+ }),
597
+ inputs: () => ({
598
+ values: () => [{
599
+ transactionId: () => ({
600
+ toString: () => "input-hash-1"
601
+ }),
602
+ index: () => 0n
603
+ }, {
604
+ transactionId: () => ({
605
+ toString: () => "input-hash-2"
606
+ }),
607
+ index: () => 1n
608
+ }]
609
+ }),
610
+ outputs: () => [{
611
+ address: () => ({
612
+ toBech32: () => "addr_test1output1"
613
+ }),
614
+ amount: () => ({
615
+ coin: () => 5_000_000n,
616
+ multiasset: () => undefined
617
+ })
618
+ }, {
619
+ address: () => ({
620
+ toBech32: () => "addr_test1output2"
621
+ }),
622
+ amount: () => ({
623
+ coin: () => 2_000_000n,
624
+ multiasset: () => undefined
625
+ })
626
+ }],
627
+ fee: () => 180_000n,
628
+ requiredSigners: () => ({
629
+ values: () => [{
630
+ toString: () => "signer-hash-1"
631
+ }, {
632
+ toString: () => "signer-hash-2"
633
+ }]
634
+ })
635
+ }),
636
+ witnessSet: () => ({
637
+ vkeys: () => ({
638
+ size: () => 2
639
+ })
640
+ })
641
+ });
642
+ });
643
+ (0, _bunTest.test)("decodes a transaction and returns all fields", async () => {
644
+ const result = await decodeTransaction.execute({
645
+ txCbor: "valid-cbor-hex"
646
+ }, makeContext());
647
+ (0, _bunTest.expect)(result.txHash).toBe("decoded-tx-hash");
648
+ (0, _bunTest.expect)(result.inputs).toHaveLength(2);
649
+ (0, _bunTest.expect)(result.inputs[0]).toEqual({
650
+ txHash: "input-hash-1",
651
+ outputIndex: 0
652
+ });
653
+ (0, _bunTest.expect)(result.inputs[1]).toEqual({
654
+ txHash: "input-hash-2",
655
+ outputIndex: 1
656
+ });
657
+ (0, _bunTest.expect)(result.outputs).toHaveLength(2);
658
+ (0, _bunTest.expect)(result.outputs[0].address).toBe("addr_test1output1");
659
+ (0, _bunTest.expect)(result.outputs[0].lovelace).toBe("5000000");
660
+ (0, _bunTest.expect)(result.fee).toBe("180000");
661
+ (0, _bunTest.expect)(result.signatureCount).toBe(2);
662
+ (0, _bunTest.expect)(result.requiredSigners).toEqual(["signer-hash-1", "signer-hash-2"]);
663
+ });
664
+ (0, _bunTest.test)("falls back to hex address when bech32 fails", async () => {
665
+ mockTxFromCbor = () => ({
666
+ body: () => ({
667
+ hash: () => ({
668
+ toString: () => "tx-hash"
669
+ }),
670
+ inputs: () => ({
671
+ values: () => []
672
+ }),
673
+ outputs: () => [{
674
+ address: () => ({
675
+ toBech32: () => {
676
+ throw new Error("cannot convert to bech32");
677
+ },
678
+ toBytes: () => "deadbeef"
679
+ }),
680
+ amount: () => ({
681
+ coin: () => 1_000_000n,
682
+ multiasset: () => undefined
683
+ })
684
+ }],
685
+ fee: () => 100_000n,
686
+ requiredSigners: () => null
687
+ }),
688
+ witnessSet: () => ({
689
+ vkeys: () => null
690
+ })
691
+ });
692
+ const result = await decodeTransaction.execute({
693
+ txCbor: "cbor-with-script-address"
694
+ }, makeContext());
695
+ (0, _bunTest.expect)(result.outputs[0].address).toBe("deadbeef");
696
+ });
697
+ (0, _bunTest.test)("handles transaction with tokens in outputs", async () => {
698
+ const policyId = "c".repeat(56);
699
+ const assetName = "mytoken";
700
+ const assetId = `${policyId}${assetName}`;
701
+ mockTxFromCbor = () => ({
702
+ body: () => ({
703
+ hash: () => ({
704
+ toString: () => "tx-hash"
705
+ }),
706
+ inputs: () => ({
707
+ values: () => []
708
+ }),
709
+ outputs: () => [{
710
+ address: () => ({
711
+ toBech32: () => "addr_test1..."
712
+ }),
713
+ amount: () => ({
714
+ coin: () => 2_000_000n,
715
+ multiasset: () => ({
716
+ entries: () => [[assetId, 500n]]
717
+ })
718
+ })
719
+ }],
720
+ fee: () => 200_000n,
721
+ requiredSigners: () => null
722
+ }),
723
+ witnessSet: () => ({
724
+ vkeys: () => null
725
+ })
726
+ });
727
+ const result = await decodeTransaction.execute({
728
+ txCbor: "cbor-with-tokens"
729
+ }, makeContext());
730
+ (0, _bunTest.expect)(result.outputs[0].tokens).toHaveLength(1);
731
+ (0, _bunTest.expect)(result.outputs[0].tokens[0].policyId).toBe(policyId);
732
+ (0, _bunTest.expect)(result.outputs[0].tokens[0].quantity).toBe("500");
733
+ });
734
+ (0, _bunTest.test)("throws INVALID_CBOR for bad input", async () => {
735
+ mockTxFromCbor = () => {
736
+ throw new Error("bad cbor");
737
+ };
738
+ await (0, _bunTest.expect)(decodeTransaction.execute({
739
+ txCbor: "garbage"
740
+ }, makeContext())).rejects.toMatchObject({
741
+ code: "INVALID_CBOR"
742
+ });
743
+ });
744
+ (0, _bunTest.test)("does not require a wallet (category is 'transaction')", () => {
745
+ (0, _bunTest.expect)(decodeTransaction.name).toBe("decode-transaction");
746
+ (0, _bunTest.expect)(decodeTransaction.category).toBe("transaction");
747
+ });
748
+ });
749
+ //# sourceMappingURL=wallet-transaction-actions.test.js.map