@sundaeswap/sprinkles 0.7.0 → 0.8.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 (95) hide show
  1. package/README.md +178 -181
  2. package/dist/cjs/Sprinkle/__tests__/builtin-actions.test.js +4 -4
  3. package/dist/cjs/Sprinkle/__tests__/builtin-actions.test.js.map +1 -1
  4. package/dist/cjs/Sprinkle/__tests__/cli-adapter.test.js +25 -3
  5. package/dist/cjs/Sprinkle/__tests__/cli-adapter.test.js.map +1 -1
  6. package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js +15 -1
  7. package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -1
  8. package/dist/cjs/Sprinkle/__tests__/mcp-adapter.test.js +7 -9
  9. package/dist/cjs/Sprinkle/__tests__/mcp-adapter.test.js.map +1 -1
  10. package/dist/cjs/Sprinkle/__tests__/native-script.test.js +390 -0
  11. package/dist/cjs/Sprinkle/__tests__/native-script.test.js.map +1 -0
  12. package/dist/cjs/Sprinkle/__tests__/utility-actions.test.js +367 -0
  13. package/dist/cjs/Sprinkle/__tests__/utility-actions.test.js.map +1 -0
  14. package/dist/cjs/Sprinkle/actions/builtin/addressbook-actions.js +164 -0
  15. package/dist/cjs/Sprinkle/actions/builtin/addressbook-actions.js.map +1 -0
  16. package/dist/cjs/Sprinkle/actions/builtin/index.js +60 -3
  17. package/dist/cjs/Sprinkle/actions/builtin/index.js.map +1 -1
  18. package/dist/cjs/Sprinkle/actions/builtin/native-script.js +139 -0
  19. package/dist/cjs/Sprinkle/actions/builtin/native-script.js.map +1 -0
  20. package/dist/cjs/Sprinkle/actions/builtin/utility-actions.js +218 -0
  21. package/dist/cjs/Sprinkle/actions/builtin/utility-actions.js.map +1 -0
  22. package/dist/cjs/Sprinkle/actions/cli-adapter.js +20 -2
  23. package/dist/cjs/Sprinkle/actions/cli-adapter.js.map +1 -1
  24. package/dist/cjs/Sprinkle/actions/index.js +12 -0
  25. package/dist/cjs/Sprinkle/actions/index.js.map +1 -1
  26. package/dist/cjs/Sprinkle/actions/mcp-adapter.js +146 -4
  27. package/dist/cjs/Sprinkle/actions/mcp-adapter.js.map +1 -1
  28. package/dist/cjs/Sprinkle/index.js +267 -5
  29. package/dist/cjs/Sprinkle/index.js.map +1 -1
  30. package/dist/cjs/Sprinkle/schemas.js +17 -1
  31. package/dist/cjs/Sprinkle/schemas.js.map +1 -1
  32. package/dist/esm/Sprinkle/__tests__/builtin-actions.test.js +4 -4
  33. package/dist/esm/Sprinkle/__tests__/builtin-actions.test.js.map +1 -1
  34. package/dist/esm/Sprinkle/__tests__/cli-adapter.test.js +25 -3
  35. package/dist/esm/Sprinkle/__tests__/cli-adapter.test.js.map +1 -1
  36. package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js +15 -1
  37. package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -1
  38. package/dist/esm/Sprinkle/__tests__/mcp-adapter.test.js +7 -9
  39. package/dist/esm/Sprinkle/__tests__/mcp-adapter.test.js.map +1 -1
  40. package/dist/esm/Sprinkle/__tests__/native-script.test.js +388 -0
  41. package/dist/esm/Sprinkle/__tests__/native-script.test.js.map +1 -0
  42. package/dist/esm/Sprinkle/__tests__/utility-actions.test.js +365 -0
  43. package/dist/esm/Sprinkle/__tests__/utility-actions.test.js.map +1 -0
  44. package/dist/esm/Sprinkle/actions/builtin/addressbook-actions.js +159 -0
  45. package/dist/esm/Sprinkle/actions/builtin/addressbook-actions.js.map +1 -0
  46. package/dist/esm/Sprinkle/actions/builtin/index.js +8 -3
  47. package/dist/esm/Sprinkle/actions/builtin/index.js.map +1 -1
  48. package/dist/esm/Sprinkle/actions/builtin/native-script.js +133 -0
  49. package/dist/esm/Sprinkle/actions/builtin/native-script.js.map +1 -0
  50. package/dist/esm/Sprinkle/actions/builtin/utility-actions.js +213 -0
  51. package/dist/esm/Sprinkle/actions/builtin/utility-actions.js.map +1 -0
  52. package/dist/esm/Sprinkle/actions/cli-adapter.js +20 -2
  53. package/dist/esm/Sprinkle/actions/cli-adapter.js.map +1 -1
  54. package/dist/esm/Sprinkle/actions/index.js +1 -1
  55. package/dist/esm/Sprinkle/actions/index.js.map +1 -1
  56. package/dist/esm/Sprinkle/actions/mcp-adapter.js +145 -5
  57. package/dist/esm/Sprinkle/actions/mcp-adapter.js.map +1 -1
  58. package/dist/esm/Sprinkle/index.js +259 -8
  59. package/dist/esm/Sprinkle/index.js.map +1 -1
  60. package/dist/esm/Sprinkle/schemas.js +16 -0
  61. package/dist/esm/Sprinkle/schemas.js.map +1 -1
  62. package/dist/types/Sprinkle/actions/builtin/addressbook-actions.d.ts +50 -0
  63. package/dist/types/Sprinkle/actions/builtin/addressbook-actions.d.ts.map +1 -0
  64. package/dist/types/Sprinkle/actions/builtin/index.d.ts +6 -2
  65. package/dist/types/Sprinkle/actions/builtin/index.d.ts.map +1 -1
  66. package/dist/types/Sprinkle/actions/builtin/native-script.d.ts +27 -0
  67. package/dist/types/Sprinkle/actions/builtin/native-script.d.ts.map +1 -0
  68. package/dist/types/Sprinkle/actions/builtin/utility-actions.d.ts +48 -0
  69. package/dist/types/Sprinkle/actions/builtin/utility-actions.d.ts.map +1 -0
  70. package/dist/types/Sprinkle/actions/cli-adapter.d.ts.map +1 -1
  71. package/dist/types/Sprinkle/actions/index.d.ts +2 -1
  72. package/dist/types/Sprinkle/actions/index.d.ts.map +1 -1
  73. package/dist/types/Sprinkle/actions/mcp-adapter.d.ts +24 -0
  74. package/dist/types/Sprinkle/actions/mcp-adapter.d.ts.map +1 -1
  75. package/dist/types/Sprinkle/index.d.ts +3 -1
  76. package/dist/types/Sprinkle/index.d.ts.map +1 -1
  77. package/dist/types/Sprinkle/schemas.d.ts +72 -0
  78. package/dist/types/Sprinkle/schemas.d.ts.map +1 -1
  79. package/dist/types/tsconfig.build.tsbuildinfo +1 -1
  80. package/package.json +1 -1
  81. package/src/Sprinkle/__tests__/builtin-actions.test.ts +4 -4
  82. package/src/Sprinkle/__tests__/cli-adapter.test.ts +24 -3
  83. package/src/Sprinkle/__tests__/fill-in-struct.test.ts +23 -1
  84. package/src/Sprinkle/__tests__/mcp-adapter.test.ts +7 -5
  85. package/src/Sprinkle/__tests__/native-script.test.ts +341 -0
  86. package/src/Sprinkle/__tests__/utility-actions.test.ts +348 -0
  87. package/src/Sprinkle/actions/builtin/addressbook-actions.ts +168 -0
  88. package/src/Sprinkle/actions/builtin/index.ts +41 -2
  89. package/src/Sprinkle/actions/builtin/native-script.ts +165 -0
  90. package/src/Sprinkle/actions/builtin/utility-actions.ts +285 -0
  91. package/src/Sprinkle/actions/cli-adapter.ts +18 -2
  92. package/src/Sprinkle/actions/index.ts +2 -1
  93. package/src/Sprinkle/actions/mcp-adapter.ts +179 -4
  94. package/src/Sprinkle/index.ts +261 -3
  95. package/src/Sprinkle/schemas.ts +20 -0
@@ -0,0 +1,348 @@
1
+ import { describe, expect, test, mock, beforeEach } from "bun:test";
2
+ import { ActionError } from "../actions/types.js";
3
+
4
+ // ---------------------------------------------------------------------------
5
+ // Mocks
6
+ // ---------------------------------------------------------------------------
7
+
8
+ // Controllable mock state
9
+ let mockBlaze: any = {};
10
+ let mockIsHot = true;
11
+ let mockBlazeError: Error | null = null;
12
+
13
+ mock.module("../actions/builtin/blaze-helper.js", () => ({
14
+ getBlazeFromContext: async () => {
15
+ if (mockBlazeError) throw mockBlazeError;
16
+ return mockBlaze;
17
+ },
18
+ isHotWallet: () => mockIsHot,
19
+ }));
20
+
21
+ // Track calls to blaze transaction builder
22
+ let mintCalls: Array<{ policyId: string; mints: Map<string, bigint> }> = [];
23
+ let provideScriptCalls: any[] = [];
24
+ let payAssetsCalls: Array<{ address: any; value: any }> = [];
25
+ let registerStakeCalls: any[] = [];
26
+
27
+ // Mock transaction returned by complete()
28
+ const mockCompletedTx = {
29
+ toCbor: () => "mock-tx-cbor-hex",
30
+ };
31
+
32
+ // Mock transaction builder chain
33
+ function makeTxBuilder() {
34
+ return {
35
+ addMint: (policyId: string, mints: Map<string, bigint>) => {
36
+ mintCalls.push({ policyId, mints });
37
+ return makeTxBuilder();
38
+ },
39
+ provideScript: (script: any) => {
40
+ provideScriptCalls.push(script);
41
+ return makeTxBuilder();
42
+ },
43
+ payAssets: (address: any, value: any) => {
44
+ payAssetsCalls.push({ address, value });
45
+ return makeTxBuilder();
46
+ },
47
+ addRegisterStake: (credential: any) => {
48
+ registerStakeCalls.push(credential);
49
+ return makeTxBuilder();
50
+ },
51
+ complete: async () => mockCompletedTx,
52
+ };
53
+ }
54
+
55
+ // Mock address with payment credential
56
+ function makeMockAddress(hash = "abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234") {
57
+ return {
58
+ toBech32: () => "addr_test1qzmock",
59
+ asBase: () => ({
60
+ getPaymentCredential: () => ({
61
+ hash: { toString: () => hash },
62
+ }),
63
+ }),
64
+ };
65
+ }
66
+
67
+ mock.module("@blaze-cardano/sdk", () => ({
68
+ Core: {
69
+ Ed25519KeyHashHex: (h: string) => h,
70
+ ScriptPubkey: class {
71
+ hash: string;
72
+ constructor(h: string) { this.hash = h; }
73
+ },
74
+ Script: {
75
+ newNativeScript: (ns: any) => ({
76
+ hash: () => "mock-policy-id-hash",
77
+ }),
78
+ },
79
+ NativeScript: {
80
+ newScriptPubkey: (sp: any) => sp,
81
+ },
82
+ PolicyId: (s: string) => s,
83
+ AssetName: (s: string) => s,
84
+ toHex: (buf: Buffer) => buf.toString("hex"),
85
+ Address: {
86
+ fromBech32: (addr: string) => {
87
+ if (addr === "invalid-address") throw new Error("Invalid bech32");
88
+ return { toBech32: () => addr };
89
+ },
90
+ },
91
+ TxCBOR: (s: string) => s,
92
+ Hash28ByteBase16: (s: string) => s,
93
+ Credential: {
94
+ fromCore: (c: any) => c,
95
+ },
96
+ CredentialType: {
97
+ ScriptHash: 1,
98
+ },
99
+ },
100
+ makeValue: (...args: any[]) => ({ __makeValueArgs: args }),
101
+ Blaze: class {},
102
+ HotWallet: class {},
103
+ }));
104
+
105
+ // Import actions after mocks are set up
106
+ const { mintToken, simpleSend, registerStakeScript } = await import(
107
+ "../actions/builtin/utility-actions.js"
108
+ );
109
+
110
+ // Minimal context factory
111
+ function makeContext(settingsOverrides: Record<string, unknown> = {}) {
112
+ return {
113
+ sprinkle: {} as any,
114
+ settings: {
115
+ network: "preview",
116
+ provider: { type: "blockfrost", apiKey: "test" },
117
+ wallet: { type: "hot", mnemonic: "test words" },
118
+ ...settingsOverrides,
119
+ } as any,
120
+ };
121
+ }
122
+
123
+ // ---------------------------------------------------------------------------
124
+ // mint-token
125
+ // ---------------------------------------------------------------------------
126
+
127
+ describe("mint-token", () => {
128
+ beforeEach(() => {
129
+ mockBlazeError = null;
130
+ mockIsHot = true;
131
+ mintCalls = [];
132
+ provideScriptCalls = [];
133
+ mockBlaze = {
134
+ wallet: {
135
+ getChangeAddress: async () => makeMockAddress(),
136
+ },
137
+ newTransaction: () => makeTxBuilder(),
138
+ };
139
+ });
140
+
141
+ test("has correct metadata", () => {
142
+ expect(mintToken.name).toBe("mint-token");
143
+ expect(mintToken.category).toBe("utility");
144
+ });
145
+
146
+ test("builds a mint transaction and returns policy info", async () => {
147
+ const ctx = makeContext();
148
+ const result = await mintToken.execute(
149
+ { tokenName: "MyToken", amount: "1000" },
150
+ ctx,
151
+ );
152
+ expect(result.policyId).toBe("mock-policy-id-hash");
153
+ expect(result.tokenName).toBe("MyToken");
154
+ expect(result.amount).toBe("1000");
155
+ expect(result.txCbor).toBe("mock-tx-cbor-hex");
156
+ expect(mintCalls).toHaveLength(1);
157
+ expect(provideScriptCalls).toHaveLength(1);
158
+ });
159
+
160
+ test("throws COLD_WALLET when wallet is not hot", async () => {
161
+ mockIsHot = false;
162
+ const ctx = makeContext();
163
+ await expect(
164
+ mintToken.execute({ tokenName: "T", amount: "1" }, ctx),
165
+ ).rejects.toMatchObject({ code: "COLD_WALLET" });
166
+ });
167
+
168
+ test("throws WALLET_NOT_CONFIGURED when blaze init fails", async () => {
169
+ mockBlazeError = new ActionError(
170
+ "Missing settings",
171
+ "WALLET_NOT_CONFIGURED",
172
+ { missingFields: ["wallet"] },
173
+ );
174
+ const ctx = makeContext();
175
+ await expect(
176
+ mintToken.execute({ tokenName: "T", amount: "1" }, ctx),
177
+ ).rejects.toMatchObject({ code: "WALLET_NOT_CONFIGURED" });
178
+ });
179
+
180
+ test("throws NO_ADDRESS when getChangeAddress fails", async () => {
181
+ mockBlaze = {
182
+ wallet: {
183
+ getChangeAddress: async () => {
184
+ throw new Error("no address");
185
+ },
186
+ },
187
+ newTransaction: () => makeTxBuilder(),
188
+ };
189
+ const ctx = makeContext();
190
+ await expect(
191
+ mintToken.execute({ tokenName: "T", amount: "1" }, ctx),
192
+ ).rejects.toMatchObject({ code: "NO_ADDRESS" });
193
+ });
194
+
195
+ test("throws INVALID_ADDRESS when base address is null", async () => {
196
+ mockBlaze = {
197
+ wallet: {
198
+ getChangeAddress: async () => ({
199
+ toBech32: () => "addr_test1...",
200
+ asBase: () => null,
201
+ }),
202
+ },
203
+ newTransaction: () => makeTxBuilder(),
204
+ };
205
+ const ctx = makeContext();
206
+ await expect(
207
+ mintToken.execute({ tokenName: "T", amount: "1" }, ctx),
208
+ ).rejects.toMatchObject({ code: "INVALID_ADDRESS" });
209
+ });
210
+ });
211
+
212
+ // ---------------------------------------------------------------------------
213
+ // simple-send
214
+ // ---------------------------------------------------------------------------
215
+
216
+ describe("simple-send", () => {
217
+ beforeEach(() => {
218
+ mockBlazeError = null;
219
+ mockIsHot = true;
220
+ payAssetsCalls = [];
221
+ mockBlaze = {
222
+ newTransaction: () => makeTxBuilder(),
223
+ };
224
+ });
225
+
226
+ test("has correct metadata", () => {
227
+ expect(simpleSend.name).toBe("simple-send");
228
+ expect(simpleSend.category).toBe("wallet");
229
+ });
230
+
231
+ test("builds a lovelace-only send transaction", async () => {
232
+ const ctx = makeContext();
233
+ const result = await simpleSend.execute(
234
+ { recipientAddress: "addr_test1qzrecipient", lovelace: "5000000" },
235
+ ctx,
236
+ );
237
+ expect(result.txCbor).toBe("mock-tx-cbor-hex");
238
+ expect(payAssetsCalls).toHaveLength(1);
239
+ });
240
+
241
+ test("builds a token send transaction", async () => {
242
+ const ctx = makeContext();
243
+ const result = await simpleSend.execute(
244
+ {
245
+ recipientAddress: "addr_test1qzrecipient",
246
+ policyId: "a".repeat(56),
247
+ assetName: "4d79546f6b656e",
248
+ tokenAmount: "100",
249
+ },
250
+ ctx,
251
+ );
252
+ expect(result.txCbor).toBe("mock-tx-cbor-hex");
253
+ expect(payAssetsCalls).toHaveLength(1);
254
+ });
255
+
256
+ test("throws INVALID_INPUT when neither lovelace nor token provided", async () => {
257
+ const ctx = makeContext();
258
+ await expect(
259
+ simpleSend.execute({ recipientAddress: "addr_test1qzrecipient" }, ctx),
260
+ ).rejects.toMatchObject({ code: "INVALID_INPUT" });
261
+ });
262
+
263
+ test("throws INVALID_ADDRESS for bad recipient", async () => {
264
+ const ctx = makeContext();
265
+ await expect(
266
+ simpleSend.execute(
267
+ { recipientAddress: "invalid-address", lovelace: "1000000" },
268
+ ctx,
269
+ ),
270
+ ).rejects.toMatchObject({ code: "INVALID_ADDRESS" });
271
+ });
272
+
273
+ test("throws WALLET_NOT_CONFIGURED when blaze init fails", async () => {
274
+ mockBlazeError = new ActionError(
275
+ "Missing settings",
276
+ "WALLET_NOT_CONFIGURED",
277
+ { missingFields: ["wallet"] },
278
+ );
279
+ const ctx = makeContext();
280
+ await expect(
281
+ simpleSend.execute(
282
+ { recipientAddress: "addr_test1qz", lovelace: "1000000" },
283
+ ctx,
284
+ ),
285
+ ).rejects.toMatchObject({ code: "WALLET_NOT_CONFIGURED" });
286
+ });
287
+ });
288
+
289
+ // ---------------------------------------------------------------------------
290
+ // register-stake-script
291
+ // ---------------------------------------------------------------------------
292
+
293
+ describe("register-stake-script", () => {
294
+ beforeEach(() => {
295
+ mockBlazeError = null;
296
+ mockIsHot = true;
297
+ registerStakeCalls = [];
298
+ mockBlaze = {
299
+ newTransaction: () => makeTxBuilder(),
300
+ };
301
+ });
302
+
303
+ test("has correct metadata", () => {
304
+ expect(registerStakeScript.name).toBe("register-stake-script");
305
+ expect(registerStakeScript.category).toBe("utility");
306
+ });
307
+
308
+ test("builds a stake registration transaction", async () => {
309
+ const validHash = "a".repeat(56);
310
+ const ctx = makeContext();
311
+ const result = await registerStakeScript.execute(
312
+ { scriptHash: validHash },
313
+ ctx,
314
+ );
315
+ expect(result.txCbor).toBe("mock-tx-cbor-hex");
316
+ expect(registerStakeCalls).toHaveLength(1);
317
+ expect(registerStakeCalls[0]).toMatchObject({
318
+ hash: validHash,
319
+ type: 1, // ScriptHash
320
+ });
321
+ });
322
+
323
+ test("throws INVALID_SCRIPT_HASH for wrong length", async () => {
324
+ const ctx = makeContext();
325
+ await expect(
326
+ registerStakeScript.execute({ scriptHash: "tooshort" }, ctx),
327
+ ).rejects.toMatchObject({ code: "INVALID_SCRIPT_HASH" });
328
+ });
329
+
330
+ test("throws INVALID_SCRIPT_HASH for non-hex characters", async () => {
331
+ const ctx = makeContext();
332
+ await expect(
333
+ registerStakeScript.execute({ scriptHash: "g".repeat(56) }, ctx),
334
+ ).rejects.toMatchObject({ code: "INVALID_SCRIPT_HASH" });
335
+ });
336
+
337
+ test("throws WALLET_NOT_CONFIGURED when blaze init fails", async () => {
338
+ mockBlazeError = new ActionError(
339
+ "Missing settings",
340
+ "WALLET_NOT_CONFIGURED",
341
+ { missingFields: ["provider"] },
342
+ );
343
+ const ctx = makeContext();
344
+ await expect(
345
+ registerStakeScript.execute({ scriptHash: "a".repeat(56) }, ctx),
346
+ ).rejects.toMatchObject({ code: "WALLET_NOT_CONFIGURED" });
347
+ });
348
+ });
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Built-in addressbook actions for managing named native scripts.
3
+ *
4
+ * The addressbook stores MultisigScript entries by name in the profile,
5
+ * allowing them to be reused across actions and automatically resolved
6
+ * by script hash during transaction building.
7
+ */
8
+
9
+ import { Type } from "@sinclair/typebox";
10
+ import type { TSchema } from "@sinclair/typebox";
11
+ import { MultisigScript } from "../../schemas.js";
12
+ import type { TMultisigScript } from "../../schemas.js";
13
+ import { ActionError } from "../types.js";
14
+ import type { IAction } from "../types.js";
15
+ import { toNativeScript } from "./native-script.js";
16
+
17
+ /**
18
+ * `list-addressbook` -- List all entries in the addressbook.
19
+ */
20
+ export const listAddressbook: IAction<
21
+ Record<string, never>,
22
+ { entries: Array<{ name: string; scriptHash: string; script: TMultisigScript }> },
23
+ TSchema
24
+ > = {
25
+ name: "list-addressbook",
26
+ description: "List all named native scripts in the addressbook.",
27
+ category: "addressbook",
28
+ inputSchema: Type.Object({}),
29
+ outputSchema: Type.Object({
30
+ entries: Type.Array(
31
+ Type.Object({
32
+ name: Type.String(),
33
+ scriptHash: Type.String(),
34
+ script: MultisigScript,
35
+ }),
36
+ ),
37
+ }),
38
+ execute: async (_input, context) => {
39
+ const addressbook = context.sprinkle.addressbook ?? {};
40
+ const entries = [];
41
+ for (const [name, ms] of Object.entries(addressbook)) {
42
+ try {
43
+ const script = toNativeScript(ms);
44
+ entries.push({ name, scriptHash: script.hash(), script: ms });
45
+ } catch {
46
+ // Include entries even if hash computation fails
47
+ entries.push({ name, scriptHash: "unknown", script: ms });
48
+ }
49
+ }
50
+ return { entries };
51
+ },
52
+ };
53
+
54
+ /**
55
+ * `set-addressbook-entry` -- Add or update a named native script in the addressbook.
56
+ */
57
+ export const setAddressbookEntry: IAction<
58
+ { name: string; script: TMultisigScript },
59
+ { name: string; scriptHash: string },
60
+ TSchema
61
+ > = {
62
+ name: "set-addressbook-entry",
63
+ description:
64
+ "Add or update a named native script in the addressbook. Accepts a MultisigScript JSON structure.",
65
+ category: "addressbook",
66
+ inputSchema: Type.Object({
67
+ name: Type.String({
68
+ minLength: 1,
69
+ description: "Name for this addressbook entry",
70
+ }),
71
+ script: MultisigScript,
72
+ }),
73
+ outputSchema: Type.Object({
74
+ name: Type.String(),
75
+ scriptHash: Type.String({ description: "Computed script hash" }),
76
+ }),
77
+ execute: async (input, context) => {
78
+ // Validate the script can be converted
79
+ const blazeScript = toNativeScript(input.script);
80
+ const scriptHash = blazeScript.hash();
81
+
82
+ context.sprinkle.addressbook[input.name] = input.script;
83
+ context.sprinkle.saveSettings();
84
+
85
+ return { name: input.name, scriptHash };
86
+ },
87
+ };
88
+
89
+ /**
90
+ * `delete-addressbook-entry` -- Remove a named native script from the addressbook.
91
+ */
92
+ export const deleteAddressbookEntry: IAction<
93
+ { name: string },
94
+ { deleted: boolean; name: string },
95
+ TSchema
96
+ > = {
97
+ name: "delete-addressbook-entry",
98
+ description: "Remove a named native script from the addressbook.",
99
+ category: "addressbook",
100
+ inputSchema: Type.Object({
101
+ name: Type.String({
102
+ minLength: 1,
103
+ description: "Name of the addressbook entry to delete",
104
+ }),
105
+ }),
106
+ outputSchema: Type.Object({
107
+ deleted: Type.Boolean(),
108
+ name: Type.String(),
109
+ }),
110
+ execute: async (input, context) => {
111
+ if (!(input.name in context.sprinkle.addressbook)) {
112
+ throw new ActionError(
113
+ `Addressbook entry "${input.name}" not found.`,
114
+ "NOT_FOUND",
115
+ { name: input.name },
116
+ );
117
+ }
118
+
119
+ delete context.sprinkle.addressbook[input.name];
120
+ context.sprinkle.saveSettings();
121
+
122
+ return { deleted: true, name: input.name };
123
+ },
124
+ };
125
+
126
+ /**
127
+ * `get-addressbook-entry` -- Get a specific named native script from the addressbook.
128
+ */
129
+ export const getAddressbookEntry: IAction<
130
+ { name: string },
131
+ { name: string; scriptHash: string; script: TMultisigScript },
132
+ TSchema
133
+ > = {
134
+ name: "get-addressbook-entry",
135
+ description: "Get a specific named native script from the addressbook.",
136
+ category: "addressbook",
137
+ inputSchema: Type.Object({
138
+ name: Type.String({
139
+ minLength: 1,
140
+ description: "Name of the addressbook entry to retrieve",
141
+ }),
142
+ }),
143
+ outputSchema: Type.Object({
144
+ name: Type.String(),
145
+ scriptHash: Type.String(),
146
+ script: MultisigScript,
147
+ }),
148
+ execute: async (input, context) => {
149
+ const ms = context.sprinkle.addressbook[input.name];
150
+ if (!ms) {
151
+ throw new ActionError(
152
+ `Addressbook entry "${input.name}" not found.`,
153
+ "NOT_FOUND",
154
+ { name: input.name },
155
+ );
156
+ }
157
+
158
+ let scriptHash = "unknown";
159
+ try {
160
+ const blazeScript = toNativeScript(ms);
161
+ scriptHash = blazeScript.hash();
162
+ } catch {
163
+ // Return entry even if hash computation fails
164
+ }
165
+
166
+ return { name: input.name, scriptHash, script: ms };
167
+ },
168
+ };
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Barrel export for built-in Sprinkle actions.
3
3
  *
4
- * Provides a `getBuiltinActions()` factory that returns all 14 built-in actions
4
+ * Provides a `getBuiltinActions()` factory that returns all 17 built-in actions
5
5
  * ready for registration on an ActionRegistry.
6
6
  */
7
7
 
@@ -31,6 +31,25 @@ export {
31
31
  decodeTransaction,
32
32
  } from "./transaction-actions.js";
33
33
 
34
+ export {
35
+ mintToken,
36
+ simpleSend,
37
+ registerStakeScript,
38
+ } from "./utility-actions.js";
39
+
40
+ export {
41
+ toNativeScript,
42
+ completeWithScripts,
43
+ } from "./native-script.js";
44
+ export type { NativeScriptInput } from "./native-script.js";
45
+
46
+ export {
47
+ listAddressbook,
48
+ getAddressbookEntry,
49
+ setAddressbookEntry,
50
+ deleteAddressbookEntry,
51
+ } from "./addressbook-actions.js";
52
+
34
53
  import {
35
54
  listProfiles,
36
55
  getProfile,
@@ -54,8 +73,21 @@ import {
54
73
  decodeTransaction,
55
74
  } from "./transaction-actions.js";
56
75
 
76
+ import {
77
+ mintToken,
78
+ simpleSend,
79
+ registerStakeScript,
80
+ } from "./utility-actions.js";
81
+
82
+ import {
83
+ listAddressbook,
84
+ getAddressbookEntry,
85
+ setAddressbookEntry,
86
+ deleteAddressbookEntry,
87
+ } from "./addressbook-actions.js";
88
+
57
89
  /**
58
- * Returns an array of all 14 built-in Sprinkle actions.
90
+ * Returns all built-in Sprinkle actions.
59
91
  * Register them on your ActionRegistry or pass them to `Sprinkle.run()`.
60
92
  *
61
93
  * @example
@@ -82,5 +114,12 @@ export function getBuiltinActions<S extends TSchema>(): AnyAction<S>[] {
82
114
  submitTransaction,
83
115
  signAndSubmit,
84
116
  decodeTransaction,
117
+ mintToken,
118
+ simpleSend,
119
+ registerStakeScript,
120
+ listAddressbook,
121
+ getAddressbookEntry,
122
+ setAddressbookEntry,
123
+ deleteAddressbookEntry,
85
124
  ] as unknown as AnyAction<S>[];
86
125
  }